Ruby で XML⇒Hash変換 ActiveSupport+REXML vs. Nokogiri

シェアする

Ruby で XML のデータを Hash に変換して使う必要があったが、要素数がおよそ65万もあり、Hash.from_xml でやるとものすごく時間がかかってしまったので、Nokogiri を使用した場合との比較メモ。


XMLファイル(ファイルサイズ:31.5MB)

<?xml version="1.0" encoding="UTF-8"?>
<IdNameList>
<Record id="12345" name="abcd" />
<Record id="67890" name="efgh" />
<Record id="13467" name="ijkl" />
・・・
  (約65万行)
・・・
</IdNameList>

出力するHash

hash = {
"12345" => "abcd",
"67890" => "efgh",
"13467" => "ijkl",
・・・
}

REXML(Ruby標準ライブラリ)+ ActiveSupport

内部的に ActiveSupport::XmlMini.parse の処理が行われる。

require 'active_support'
require 'active_support/core_ext'

hash = Hash.new
xml = Hash.from_xml(File.open('userlist.xml'))
xml['IdNameList']['Record'].each { |data|
  hash.store(data[id], data[name])
}

処理時間:316.669600947 sec.

Nokogiri

require 'nokogiri'

hash = Hash.new
xml = Nokogiri::XML(File.open('userlist.xml'))
xml.path('/IdNameList/Record').each { |data|
  hash.store(data.attributes['id'].value, data.attributes['name'].value)
}

処理時間:5.729888423 sec.

結果

Nokogiri を使うことで圧倒的に速くなりました。

今回は試していませんが、LibXML というライブラリもあるそうです。

また、ActiveSupport を使う場合でも、

ActiveSupport::backend = 'LibXML'
ActiveSupport::XmlMini.parse(xml)
ActiveSupport::backend = 'Nokogiri'
ActiveSupport::XmlMini.parse(xml)

などとすることで、内部処理に LibXML や Nokogiri を使用することができ高速に処理できるようです。

【参考サイト】