为什么 xpath.each return 是元素而不是节点?
Why does xpath.each return an element instead of a node?
我想迭代 xpath
搜索的结果,这样我就可以对节点进行操作。 Nokogiri 的文档和示例说 xpath
returns 一个 NodeSet 和 NodeSet.each
returns 一个节点,这是我想要的,但是我得到了一个元素。我做错了什么?
这个简化的代码突出了这个问题。 Whosebug 上有很多相关的问题,虽然它们是特定领域的,模糊了问题,并且与这个问题没有完全匹配。
<?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
根据请求从评论中转换:
一个Element
是一个Node
。 (并非每个 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"]
这可能有助于阐明正在发生的事情:
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 bar\n"
这可能有助于“解释您所看到的内容并激起您对引擎盖下的其他内容的好奇心。
我想迭代 xpath
搜索的结果,这样我就可以对节点进行操作。 Nokogiri 的文档和示例说 xpath
returns 一个 NodeSet 和 NodeSet.each
returns 一个节点,这是我想要的,但是我得到了一个元素。我做错了什么?
这个简化的代码突出了这个问题。 Whosebug 上有很多相关的问题,虽然它们是特定领域的,模糊了问题,并且与这个问题没有完全匹配。
<?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
根据请求从评论中转换:
一个Element
是一个Node
。 (并非每个 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"]
这可能有助于阐明正在发生的事情:
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 bar\n"
这可能有助于“解释您所看到的内容并激起您对引擎盖下的其他内容的好奇心。