【问题标题】:Keeping attributes when converting XML to Ruby hash将 XML 转换为 Ruby 哈希时保留属性
【发布时间】:2013-10-11 02:48:29
【问题描述】:

我有一个要解析的大型 XML 文档。在本文档中,许多标签具有不同的属性。例如:

<album>
 <song-name type="published">Do Re Mi</song-name>
</album>

目前,我通过要求 'active_support/core_ext/hash' 来使用 Rail 的哈希解析库。

当我将其转换为哈希时,它会删除属性。它返回:

{"album"=>{"song-name"=>"Do Re Mi"}}

我如何维护这些属性,在本例中是 type="published" 属性?

这似乎以前在“How can I use XML attributes when converting into a hash with from_xml?”中被问过,没有确定的答案,但那是从 2010 年开始的,我很好奇从那以后情况是否发生了变化。或者,我想知道您是否知道解析此 XML 的另一种方法,以便我仍然可以包含属性信息。

【问题讨论】:

    标签: ruby-on-rails ruby hash xml-parsing


    【解决方案1】:

    将 XML 转换为哈希并不是一个好的解决方案。剩下的哈希值比原始 XML 更难解析。另外,如果 XML 太大,您将得到一个不适合内存且无法处理的哈希,而原始 XML 可以使用 SAX 解析器进行解析。

    假设文件在加载时不会占用你的内存,我建议使用Nokogiri 来解析它,执行以下操作:

    require 'nokogiri'
    
    class Album
    
      attr_reader :song_name, :song_type
      def initialize(song_name, song_type)
        @song_name = song_name
        @song_type = song_type
      end
    end
    
    xml = <<EOT
    <xml>
      <album>
       <song-name type="published">Do Re Mi</song-name>
      </album>
      <album>
        <song-name type="unpublished">Blah blah blah</song-name>
      </album>
    </xml>
    EOT
    
    albums = []
    doc = Nokogiri::XML(xml)
    doc.search('album').each do |album|
      song_name = album.at('song-name')
      albums << Album.new(
          song_name.text,
          song_name['type']
        )
    end
    
    puts albums.first.song_name
    puts albums.last.song_type
    

    哪些输出:

    Do Re Mi
    unpublished
    

    代码首先定义了一个合适的对象,用于保存您想要的数据。当 XML 被解析成 DOM 时,代码会循环遍历所有 &lt;album&gt; 节点,提取信息,定义类的实例,并将其附加到 albums 数组中。

    运行后,您将拥有一个数组,您可以遍历并处理每个项目,将其存储到数据库中,或者根据需要进行操作。不过,如果您的目标是将这些信息插入数据库,那么让 DBM 读取 XML 并直接导入它会更聪明。

    【讨论】:

    • 太棒了,铁皮人。我很高兴你早早阻止了我。这非常有用。
    • 我没有声称它很棒,我就是这样做的。如果您遇到任何其他问题,请告诉我们。解析 XML/HTML 有时会非常令人沮丧。
    【解决方案2】:

    主动支持 XMLConverter 类的问题 请将以下代码添加到您的任何初始化程序文件中。

    module ActiveSupport
        class XMLConverter
            private
                def become_content?(value)
                    value['type'] == 'file' || (value['__content__'] && (value.keys.size == 1 && value['__content__'].present?))
                end
        end
    end
    

    它会给你如下输出。

    Ex 输入 XML

    xml = '<album>
       <song-name type="published">Do Re Mi</song-name>
    </album>'
    
    Hash.from_xml(xml)
    

    输出将是

    {"album"=>{"song_name"=>{"type"=>"published", "__content__"=>"Do Re Mi"}}}
    

    【讨论】:

    • 是的,但这也不理想,因为如果从这样的哈希中我们尝试再次构造 xml {"album"=&gt;{"song_name"=&gt;{"type"=&gt;"published", "__content__"=&gt;"Do Re Mi"}}}.to_xml 我们会得到 &lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;\n&lt;hash&gt;\n &lt;album&gt;\n &lt;song-name&gt;\n &lt;type&gt;published&lt;/type&gt;\n &lt;__content__&gt;Do Re Mi&lt;/__content__&gt;\n &lt;/song-name&gt;\n &lt;/album&gt; 这不是原始的。
    【解决方案3】:

    我实际上认为它是垃圾方法,它正在检查类型属性,如果它不返回哈希,它将返回 true,在方法 become_hash 中哪个?返回假。这是 process_hash 方法中的最后一次检查。所以它会为类型属性返回 nil 并且不会为它构建散列。

    对于那些感兴趣的人,我正在谈论的是主动支持 gem active_support/core_ext/hash/conversions.rb

    module ActiveSupport class XMLConverter private def garbage?(value) false end end end

    我只是将其默认为 false,它对我有用,但可能并不适合所有人。

    【讨论】:

      【解决方案4】:

      正如您在上面链接的问题,Nokogiri 是(简短的)答案。

      如果你能提供一些示例代码,有人可能会想出更好的答案。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-08-26
        • 2014-07-02
        • 2010-12-16
        • 2018-07-23
        • 2016-10-26
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多