在将XML转换为Ruby哈希时保持属性

时间:2013-10-11 02:48:30

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

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

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

目前,我正在使用Rail的哈希解析库,需要'active_support/core_ext/hash'

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

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

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

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

4 个答案:

答案 0 :(得分:4)

将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时,代码将循环遍历所有<album>个节点,并提取信息,定义类的实例,并将其附加到albums数组。

运行之后,您将拥有一个阵列,您可以走路,处理每个项目,将其存储到数据库中,或根据需要进行操作。但是,如果您的目标是将该信息插入数据库,那么让DBM读取XML并直接导入它会更聪明。

答案 1 :(得分:3)

主动支持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"}}}

答案 2 :(得分:0)

我实际上认为它是垃圾方法,它正在检查type属性,如果它没有返回一个哈希值,它将返回true,这在方法become_hash中?返回false。这是process_hash方法中的最后一次检查。因此它将为type属性返回nil,并且不会为它构建哈希。

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

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

我只是默认它是假的,它对我有用,但它可能并不适合所有人。

答案 3 :(得分:-2)

与上面提到的问题一样,Nokogiri是(简短)答案。

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