2010-12-19 44 views
1

我想根据运行引入nokogiri :: XML ::节点集的搜索方法上的一个节点集称为节点集对于一些XPath的规则如下图所示:如何保持空白结果为引入nokogiri的NodeSet.search方法

nodeset.search(rule) 

的上面的代码返回一个NodeSet,但不包含那些不符合规则的。我的意图是:如果nodeset中的元素匹配规则,那么请返回匹配的结果;如果不匹配,请在结果中返回一个空白字符串,以便我可以知道调用者nodeset中的哪个元素匹配,调用者nodeset中的哪个元素不匹配。

有人能告诉我该怎么做吗?我会非常感谢你的帮助。

+0

非常感谢您的回复,我知道您的意思。我可以将调用者“nodeset”当作一个数组并循环遍历一个一个元素来搜索xpath“规则”,但是搜索每个元素的结果是NodeSet,在遍历所有节点集之后,我有一个新的列表节点集,但最后我期望最终的结果只是一个节点集,就像Nokogiri搜索方法的返回结果一样,对于那些无法与规则匹配的节点,而不是节点集列表,即使包含匹配和不匹配的节点集也是如此。 – ywenbo 2010-12-20 00:33:38

+0

什么是“空节点”?你几乎肯定会根据下面的答案使用'select'或'map'来创建一个数组,然后自己手动创建一个新的'NodeSet'。如果您需要此方面的帮助,请说明您真正期望在NodeSet中呈现的内容,以反映您的不匹配情况。到目前为止,您已经说过“空白字符串”和“空白节点”。 – Phrogz 2010-12-20 22:59:03

+0

@Progrog谢谢你的回复。是的,你没事。我可以创建新的NodeSet,然后根据特定的搜索结果来填充NodeSet,这很酷。真的很感谢你的帮助。 – ywenbo 2010-12-21 01:22:51

回答

1

引入nokogiri NodeSet支持组操作。相反,保持空白在你的组匹配的,找出遗漏的物品事后:

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而不是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

我不知道nokogiri足够好知道这将工作如何,但我怀疑下面的例子可能会提出一个前进的方向。下面假设NODESET就像一个红宝石阵列,它会按它的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]类似的Ruby阵列http://nokogiri.rubyforge.org/nokogiri/Nokogiri/XML/NodeSet.html#M000448

+0

谢谢你的回复,你指出的方向也是对的,但我只能选择一个,反正谢谢。 – ywenbo 2010-12-21 01:25:14

+0

虽然你可以upvote ;-)其实我同意,Phrogz的解决方案是一样的,但更好地解释。 – noodl 2010-12-21 10:59:49

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"] 
+0

你是对的,但我只能选择一个答案,对不起。 – ywenbo 2010-12-21 01:24:05