Nokogiri::XML::Reader 跳过命名空间
Nokogiri::XML::Reader skips namespaces
我有多个 XML(如下所示),其中出现了一个可选标记。此标记位于命名空间 mynamespace
中
xml = %{<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0" xmlns:mynamespace="http://example.com/ns/1.0">
<channel>
<item>
<title>bar</title>
<mynamespace:custom_tag>some text</mynamespace:custom_tag>
</item>
<item>
<title>foo</title>
</item>
</channel>
</rss>}
Nokogiri::XML::Reader(xml).each do |node|
next if node.name!='item' || node.node_type != Nokogiri::XML::Reader::TYPE_ELEMENT
node = Nokogiri::XML.parse(node.outer_xml)
puts "-> node"
puts node.namespaces
puts node.xpath("//mynamespace:custom_tag").text
end
当 Nokogiri::XML::Reader(xml)
迭代每个 <item>
时,第一个 运行 输出 some text
。但是当第二项不包含我的 mynamespace
命名空间的元素被解析时,它会抛出错误。
输出为:
-> node
{"xmlns:mynamespace"=>"http://example.com/ns/1.0"}
some text
-> node
{}
Nokogiri::XML::XPath::SyntaxError: Undefined namespace prefix: //mynamespace:custom_tag
- Why does Nokogiri include the namespace in the first item but not in the second item? Only because the first uses the namespace, and the second doesn't?
- What would be a workaround to search for tags with namespaces, even when this namespace doesn't occur in the current node?
- Why does Nokogiri include the namespace in the first item but not in the second item? Only because the first uses the namespace, and the second doesn't?
要了解区别,请看第一个 node.outer_xml
returns <item>
:
<item xmlns:mynamespace="http://example.com/ns/1.0">
<title>bar</title>
<mynamespace:custom_tag>some text</mynamespace:custom_tag>
</item>
...相对于第二个:
<item>
<title>foo</title>
</item>
您会注意到在第一种情况下 outer_xml
与输入 XML 不同:Nokogiri 有助于在父元素上包含任何子元素的命名空间声明。在第二种情况下,none 个元素具有任何名称空间,因此 Nokogiri 不包含任何名称空间声明。
- What would be a workaround to search for tags with namespaces, even when this namespace doesn't occur in the current node?
一个简单的解决方案是使用条件来跳过不包含命名空间的元素:
Nokogiri::XML::Reader(xml).each do |node|
next unless node.name == 'item' && node.node_type == Nokogiri::XML::Reader::TYPE_ELEMENT
item_doc = Nokogiri::XML.parse(node.outer_xml)
puts "-> node"
unless item_doc.namespaces.key?("xmlns:mynamespace")
puts "Does not include namespace; skipping"
next
end
puts item_doc.xpath("//mynamespace:custom_tag").text
end
# => -> node
# some text
# -> node
# Element doesn't include namespace; skipping
你会注意到,我还用 item_doc
更改了块内的变量名称 node
,因为 Nokogiri::XML.parse
returns 是 Nokogiri::XML::Document,而不是节点,命名很混乱。
一个更简单的解决方案是使用 Nokogiri 的内存解析器而不是 XML::Reader:
doc = Nokogiri::XML(xml)
doc.xpath("//rss/channel/item/mynamespace:custom_tag").each do |node|
puts node.text
end
# => some_text
您可能正在使用 XML::Reader,因为 XML 文档很大,但除非您遇到实际内存或性能问题,否则我建议改用此方法。
我有多个 XML(如下所示),其中出现了一个可选标记。此标记位于命名空间 mynamespace
xml = %{<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0" xmlns:mynamespace="http://example.com/ns/1.0">
<channel>
<item>
<title>bar</title>
<mynamespace:custom_tag>some text</mynamespace:custom_tag>
</item>
<item>
<title>foo</title>
</item>
</channel>
</rss>}
Nokogiri::XML::Reader(xml).each do |node|
next if node.name!='item' || node.node_type != Nokogiri::XML::Reader::TYPE_ELEMENT
node = Nokogiri::XML.parse(node.outer_xml)
puts "-> node"
puts node.namespaces
puts node.xpath("//mynamespace:custom_tag").text
end
当 Nokogiri::XML::Reader(xml)
迭代每个 <item>
时,第一个 运行 输出 some text
。但是当第二项不包含我的 mynamespace
命名空间的元素被解析时,它会抛出错误。
输出为:
-> node
{"xmlns:mynamespace"=>"http://example.com/ns/1.0"}
some text
-> node
{}
Nokogiri::XML::XPath::SyntaxError: Undefined namespace prefix: //mynamespace:custom_tag
- Why does Nokogiri include the namespace in the first item but not in the second item? Only because the first uses the namespace, and the second doesn't?
- What would be a workaround to search for tags with namespaces, even when this namespace doesn't occur in the current node?
- Why does Nokogiri include the namespace in the first item but not in the second item? Only because the first uses the namespace, and the second doesn't?
要了解区别,请看第一个 node.outer_xml
returns <item>
:
<item xmlns:mynamespace="http://example.com/ns/1.0">
<title>bar</title>
<mynamespace:custom_tag>some text</mynamespace:custom_tag>
</item>
...相对于第二个:
<item>
<title>foo</title>
</item>
您会注意到在第一种情况下 outer_xml
与输入 XML 不同:Nokogiri 有助于在父元素上包含任何子元素的命名空间声明。在第二种情况下,none 个元素具有任何名称空间,因此 Nokogiri 不包含任何名称空间声明。
- What would be a workaround to search for tags with namespaces, even when this namespace doesn't occur in the current node?
一个简单的解决方案是使用条件来跳过不包含命名空间的元素:
Nokogiri::XML::Reader(xml).each do |node|
next unless node.name == 'item' && node.node_type == Nokogiri::XML::Reader::TYPE_ELEMENT
item_doc = Nokogiri::XML.parse(node.outer_xml)
puts "-> node"
unless item_doc.namespaces.key?("xmlns:mynamespace")
puts "Does not include namespace; skipping"
next
end
puts item_doc.xpath("//mynamespace:custom_tag").text
end
# => -> node
# some text
# -> node
# Element doesn't include namespace; skipping
你会注意到,我还用 item_doc
更改了块内的变量名称 node
,因为 Nokogiri::XML.parse
returns 是 Nokogiri::XML::Document,而不是节点,命名很混乱。
一个更简单的解决方案是使用 Nokogiri 的内存解析器而不是 XML::Reader:
doc = Nokogiri::XML(xml)
doc.xpath("//rss/channel/item/mynamespace:custom_tag").each do |node|
puts node.text
end
# => some_text
您可能正在使用 XML::Reader,因为 XML 文档很大,但除非您遇到实际内存或性能问题,否则我建议改用此方法。