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

  • XMLファイル(ファイルサイズ:31.5MB)
    1
    2
    3
    4
    5
    6
    7
    8
    
    <IdNameList>
        <Record id="12345" name="abcd" />
        <Record id="67890" name="efgh" />
        <Record id="13467" name="ijkl" />
        #  ・・・
        # (約65万行)
        #  ・・・
    </IdNameList>
    
  • 出力するHash
    1
    2
    3
    4
    5
    6
    
    hash = {
      "12345" => "abcd",
      "67890" => "efgh",
      "13467" => "ijkl",
        ・・・
    }
    

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

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

1
2
3
4
5
6
7
8
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

1
2
3
4
5
6
7
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 を使う場合でも、

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

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

参考