为什么 xpath.each 返回一个元素而不是一个节点



我想迭代xpath搜索的结果,这样我就可以对节点做一些事情了。Nokogiri 的文档和示例说xpath返回一个 NodeSet,NodeSet.each返回一个 Node,这就是我想要的,但是我得到了一个元素。我做错了什么?

此简化的代码突出显示了该问题。StackOverflow上有许多相关的问题,尽管它们是特定于领域的,掩盖了问题,并且与这个问题不完全匹配。

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<root xmlns="http://example.org/1">
  <item>
    <value>One</value>
  </item>
  <item>
    <value>Two</value>
  </item>
</root>
#!/usr/bin/ruby -w
require 'nokogiri'
xmlfile = File.open("testfile.xml")
xmldoc = Nokogiri::XML(xmlfile)
xmldoc.xpath("//xmlns:value").each do |node|
    if (node.nil?) then
        next
    end
    puts "node is a #{node.class}"
end
node is a Nokogiri::XML::Element
node is a Nokogiri::XML::Element

这可能有助于澄清正在发生的事情:

require 'nokogiri'
types = {
  1 => 'ELEMENT_NODE',
  2 => 'ATTRIBUTE_NODE',
  3 => 'TEXT_NODE',
  4 => 'CDATA_SECTION_NODE',
  5 => 'ENTITY_REF_NODE',
  6 => 'ENTITY_NODE',
  7 => 'PI_NODE',
  8 => 'COMMENT_NODE',
  9 => 'DOCUMENT_NODE',
  10 => 'DOCUMENT_TYPE_NODE',
  11 => 'DOCUMENT_FRAG_NODE',
  12 => 'NOTATION_NODE',
  13 => 'HTML_DOCUMENT_NODE',
  14 => 'DTD_NODE',
  15 => 'ELEMENT_DECL',
  16 => 'ATTRIBUTE_DECL',
  17 => 'ENTITY_DECL',
  18 => 'NAMESPACE_DECL',
  19 => 'XINCLUDE_START',
  20 => 'XINCLUDE_END',
  21 => 'DOCB_DOCUMENT_NODE',
}
doc = Nokogiri::XML.parse(<<EOT)
<xml>
  <t1>foo</t1>
  bar
</xml>
EOT
doc.xpath('//.').each do |n|
  puts "'%s' is a %s containing "%s"" % [n.name, types[n.type], n.content]
end

这导致:

# >> 'document' is a DOCUMENT_NODE containing "
# >>   foo
# >>   bar
# >> "
# >> 'xml' is a ELEMENT_NODE containing "
# >>   foo
# >>   bar
# >> "
# >> 'text' is a TEXT_NODE containing "
# >>   "
# >> 't1' is a ELEMENT_NODE containing "foo"
# >> 'text' is a TEXT_NODE containing "foo"
# >> 'text' is a TEXT_NODE containing "
# >>   bar
# >> "

像libxml2这样的解析器,位于Nokogiri下,将XML或HTML分解为各种不同类型的节点,然后将其传递回Nokogiri。

根据搜索访问器的不同,您可以获得各种类型中的任何一种,但通常最有用的是文档中的标签:

doc.xpath('//t1').each do |n|
  puts "'%s' is a %s containing "%s"" % [n.name, types[n.type], n.content]
end
# >> 't1' is a ELEMENT_NODE containing "foo"

有了这些,我们可以搜索或导航文档查找感兴趣的节点,查找和提取其内容或隔离部分并移动,更改或删除它们,或插入新内容。

有时我们关心文本节点,因为我们想要干预文本或破坏格式:

doc.xpath('//text()').each do |n|
  puts "'%s' is a %s containing %s" % [n.name, types[n.type], n.content.inspect]
end
# >> 'text' is a TEXT_NODE containing "n  "
# >> 'text' is a TEXT_NODE containing "foo"
# >> 'text' is a TEXT_NODE containing "n  barn"

这可能有助于"解释你所看到的东西,并激起你对引擎盖下还有什么的好奇心。

根据每个请求的注释转换:

ElementNode。(并非每个Node都是Element

# is Element a kind of a Node?
Nokogiri::XML::Element < Nokogiri::XML::Node
# => true
# is every node I get from xpath a Node?
xmldoc.xpath("//xmlns:value").all? { |node| node.is_a?(Nokogiri::XML::Node) }
# => true
# can I get a parent from each node I get from xpath?
xmldoc.xpath("//xmlns:value").map { |node| node.parent.name }
# => ["item", "item"]

相关内容

  • 没有找到相关文章

最新更新