我想基于一个名为nodeset的NodeSet运行Nokogiri :: XML :: NodeSet的搜索方法,用于某些xpath规则,如下所示:
nodeset.search(rule)
上面的代码返回一个NodeSet,但不包含那些与规则不匹配的NodeSet。我的意图是:如果节点集中的元素与规则匹配,那么请返回匹配的结果;如果不匹配,请在结果中返回一个空字符串,以便我可以知道调用者节点集中的哪个元素匹配,调用者节点集中的哪个元素不匹配。
有人可以告诉我该怎么做吗?我非常感谢你的帮助。
答案 0 :(得分:1)
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
或其他Nokogiri方法,并获得Array
而不是{{1 }}:
NodeSet
答案 1 :(得分:0)
我不太了解nokogiri,知道这有多好,但我怀疑下面的例子可能会提出一个前进的方向。以下假设NodeSet的行为类似于根据其API文档[1]
执行的ruby数组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
答案 2 :(得分:0)
以下是我如何去做的事情:
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"]