【问题标题】:Nokogiri::XML::Reader skips namespacesNokogiri::XML::Reader 跳过命名空间
【发布时间】:2015-12-10 17:04:32
【问题描述】:

我有多个 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) 迭代每个&lt;item&gt; 时,第一次运行输出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 将命名空间包含在第一项中而不包含在第二项中?只是因为第一个使用命名空间,而第二个没有?
  • 即使当前节点中不存在此命名空间,搜索带有命名空间的标签的解决方法是什么?

【问题讨论】:

    标签: ruby xml nokogiri xml-namespaces


    【解决方案1】:
    1. 为什么 Nokogiri 将命名空间包含在第一项中而不包含在第二项中?只是因为第一个使用命名空间,而第二个没有?

    要了解区别,请查看node.outer_xml 为第一个&lt;item&gt; 返回的内容:

    <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
    

    您会注意到,我还将块内的变量名称 node 更改为 item_doc,因为 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 文档很大,但除非您遇到实际的内存或性能问题,否则我建议您改用这种方法。

    【讨论】:

      猜你喜欢
      • 2022-01-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-26
      相关资源
      最近更新 更多