2013-10-11 2 views
2

У меня есть большой XML-документ, который я ищу для синтаксического анализа. В этом документе многие теги имеют в них разные атрибуты. Например:Сохранение атрибутов при преобразовании XML в Ruby hash

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

В настоящее время я использую хэш-разборе библиотеки рейл, требуя '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

Преобразование 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 и импортировать его напрямую.

+0

Friggin блестящий, олово. Я рад, что ты рано меня задержал. Это невероятно полезно. – CodeBiker

+0

Я не претендую на то, что он блестящий, это как раз то, как я это сделаю. Сообщите нам, если у вас возникнут другие проблемы. Разбор XML/HTML может быть довольно неприятным. –

-1

Как и в указанном выше вопросе, Nokogiri является (коротким) ответом.

Если вы можете предоставить примерный код, кто-то может найти лучшие ответы.

2

Это проблема с активной поддержкой. XMLConverter class . Пожалуйста, добавьте следующий код в любой из файлов инициализаторов.

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"}}} 
0

Я на самом деле думаю, что его метод мусора, это проверка атрибута типа, и если он не возвращает хэш он вернется true, которое в методе get_hash? возвращает false. Последняя проверка в методе process_hash. Поэтому он будет возвращать nil для атрибута type и не будет создавать хэш для него.

Для тех, кто интересуется, что я говорю о том, в активной поддержки жемчужину active_support/core_ext/хэш/conversions.rb

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

Я просто по умолчанию это ложь, и она работала для меня, но это возможно, не для всех.

Смежные вопросы