как сохранить пустой результат для метода NodeSet.search Nokogiri - PullRequest
1 голос
/ 19 декабря 2010

Я хочу запустить метод поиска Nokogiri :: XML :: NodeSet на основе одного NodeSet, называемого набором узлов, для некоторого правила xpath, как показано ниже:

nodeset.search(rule)

приведенный выше код возвращает NodeSet, но этоне содержит те, которые не могут соответствовать правилу.Я хочу, чтобы: если элемент в наборе узлов соответствовал правилу, пожалуйста, верните соответствующий результат;если не совпадает, пожалуйста, верните пустую строку в результате, чтобы я мог знать, какой элемент в наборе узлов вызывающей стороны соответствует, какой элемент в наборе узлов вызывающей стороны не совпадает.

Может кто-нибудь сказать мне, как это сделать?Я буду очень признателен за вашу помощь.

Ответы [ 3 ]

1 голос
/ 19 декабря 2010

Nokogiri NodeSet поддерживает операции над множествами, аналогичные Ruby-массивам.Вместо того, чтобы оставлять пропуски в вашем подходящем наборе, выясните пропущенные элементы по факту:

require 'nokogiri'

doc = Nokogiri::XML <<-ENDXML
<root>
  <a id="a1" class="foo">
    <a id="a1a" class="foo" />
    <a id="a1b" class="foo" andalso="this" />
  </a>
  <a id="a2" class="foo" andalso="this">
    <a id="a2a" class="bar" />
    <a id="a2b" class="bar" andalso="this" />
  </a>
  <a id="a3" class="foo" andalso="this" />
</root>
ENDXML

foos = doc.xpath('//a[@class="foo"]')
p foos.map{ |e| e['id'] }
#=> ["a1", "a1a", "a1b", "a2"]

subselect = foos.xpath('self::*[@andalso="this"]')
p subselect.map{ |e| e['id'] }
#=> ["a1b", "a2", "a3"]

missed = foos - subselect
p missed.map{ |e| e['id'] }
#=> ["a1", "a1a"]

Если вы действительно хотите, чтобы в результате не было узлов, вам придется использовать #map вместо #search или другие методы Нокогири и получите Array вместо NodeSet:

subselect = foos.map do |el|
  if el['andalso']=='this'
    el
  else
    ""
  end
end
p subselect.map{ |e| e=="" ? "" : e['id'] }
#=> ["", "", "a1b", "a2", "a3"]
0 голосов
/ 20 декабря 2010

Вот как я бы это сделал:

require 'nokogiri'

xml = <<EOT
<xml>
  <find_node>foo</find_node>
  <ignore_node>bar</ignore_node>
  <find_node>foo</find_node>
  <ignore_node>bar</ignore_node>
</xml>
EOT

# parse the document...
doc = Nokogiri::XML(xml)

# find the nodes we want...
desired_nodes = doc.search('//find_node')

# see if it's working...
desired_nodes.map{ |n| n.to_xml } # => ["<find_node>foo</find_node>", "<find_node>foo</find_node>"]

# walk the tree, grabbing the text or '' depending on whether the node is a hit or a miss...
node_result = doc.search('/xml/*').map{ |n| desired_nodes.include?(n) ? n.text : '' }

# ** here's the result **
node_result # => ["foo", "", "foo", ""]

# if we wanted to we could grab the desired_nodes' text...
desired_nodes.map{ |n| n.text } # => ["foo", "foo"]

# or find the ignored nodes...
ignored_nodes = doc.search('/xml/*') - desired_nodes
ignored_nodes.map{ |n| n.to_xml } # => ["<ignore_node>bar</ignore_node>", "<ignore_node>bar</ignore_node>"]

# ...and grab the ignored_nodes' text...
ignored_nodes.map{ |n| n.text } # => ["bar", "bar"]
0 голосов
/ 19 декабря 2010

Я не знаю нокогири достаточно хорошо, чтобы знать, насколько хорошо это будет работать, но я подозреваю, что следующий пример может предложить путь вперед.Далее предполагается, что NodeSet ведет себя как массив ruby, который он выполняет в соответствии со своими документами API [1]

a = (0..9).to_a
 => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
evens = a.select { |i| i % 2 == 0 }
 => [0, 2, 4, 6, 8]
odds = a - evens
 => [1, 3, 5, 7, 9]

Я считаю, что вы должны иметь возможность сделать что-то похожее с вашим набором узлов, чтобы, когда ваш поиск былвыполнив, вы можете найти несопоставленные узлы, вычитая новый набор узлов из исходного.

[1] http://nokogiri.rubyforge.org/nokogiri/Nokogiri/XML/NodeSet.html#M000448

...