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

时间:2015-12-10 17:04:32

标签: ruby xml nokogiri xml-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
  
      
  • 为什么Nokogiri在第一项中包含命名空间而在第二项中没有?只是因为第一个使用命名空间,第二个不使用命名空间
  •   
  • 搜索带有命名空间的标记的解决方法是什么,即使此命名空间不在当前节点中发生?
  •   

1 个答案:

答案 0 :(得分:1)

  
      
  1. 为什么Nokogiri在第一项中包含命名空间而在第二项中没有?只是因为第一个使用命名空间,第二个不使用命名空间
  2.   

要了解差异,请查看第一个node.outer_xml的{​​{1}}返回内容:

<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> 与输入XML不同:Nokogiri有用地包含父元素上任何子元素的名称空间声明。在第二种情况下,没有任何元素具有任何名称空间,因此Nokogiri不包含任何名称空间声明。

  
      
  1. 搜索带有命名空间的标记的解决方法是什么,即使此命名空间不在当前节点中发生?
  2.   

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

outer_xml

您注意到我还使用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 更改了块内的变量名node,因为item_doc返回Nokogiri :: XML :: Document,而不是Node,命名很混乱。

更简单的解决方案是使用Nokogiri的内存解析器而不是XML :: Reader:

Nokogiri::XML.parse

您可能正在使用XML :: Reader,因为XML文档很大,但除非您遇到实际内存或性能问题,否则我建议您使用此方法。