Nokogiri::XML::Reader跳过命名空间



我有多个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
  • 为什么Nokogiri在第一项中包含名称空间,而在第二项中不包含?只是因为第一个使用了名称空间,而第二个没有
  • 即使当前节点中没有出现此名称空间,搜索具有名称空间的标记的解决方法是什么
  1. 为什么Nokogiri在第一项中包含名称空间,而在第二项中不包含?只是因为第一个使用了名称空间,而第二个没有

要了解差异,请查看第一个<item>:的node.outer_xml返回的内容

<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在父元素上包含了任何子元素的命名空间声明,这很有帮助。在第二种情况下,没有任何元素具有任何名称空间,因此Nokogiri不包含任何名称空间声明。

  1. 即使当前节点中没有出现此名称空间,搜索具有名称空间的标记的解决方法是什么

一个简单的解决方案是使用条件跳过不包括名称空间的元素:

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返回的是Nokogiri::XML::Document,而不是Node,而且命名非常混乱。

一个更简单的解决方案是使用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文档很大,但除非您遇到实际的内存或性能问题,否则我建议您改用这种方法。

相关内容

  • 没有找到相关文章