8
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

RubyでXMLファイルをHashとしてパースする方法の比較

Last updated at Posted at 2016-05-20

XMLファイルを使う必要にかられて、ちょっと調べてみました。

実際のプログラムを作る際には、XPashやCSSでの検索に対応したGem1のオブジェクトを使った方がいいとは思いますが、それでも軽く中身を確認するためにはHashで取り込めると便利なので。

具体的には、ActiveSupportを使った方法とXmlSimpleというgemを使った方法が見つかったので、それらの比較になります。

インストール方法

ActiveSupport
$ gem install activesupport
XmlSimple
$ gem install xml-simple

gemなので、特筆することはなく。

使い方

ActiveSupport
require 'active_support'
require 'active_support/core_ext'

hash = Hash.from_xml(open('path/to/file.xml'))
XmlSimple
require 'xmlsimple'

hash = XmlSimple.xml_in(open("path/to/file.xml"))

使い方もほぼ同じですね。
なお、今回の例ではそれぞれの引数にopenメソッドで開いたFileオブジェクトを渡していますが、XMLのデータ自体を文字列で渡すことも出来るようです。

出力結果

以下のXMLデータを読み込ませた結果で比較します。

テストデータ
<package>
  <track is_inst="true">
    <track_no>1</track_no>
    <title>タイトル1</title>
  </track>
  <track>
    <track_no>2</track_no>
    <title code="12345">タイトル2</title>
    <single />
  </track>
</package>
ActiveSupport
{
    "package" => {
        "track" => [
            [0] {
                 "is_inst" => "true",
                "track_no" => "1",
                   "title" => "タイトル1"
            },
            [1] {
                "track_no" => "2",
                   "title" => "タイトル2",
                  "single" => nil
            }
        ]
    }
}
XmlSimple
{
    "track" => [
        [0] {
             "is_inst" => "true",
            "track_no" => [
                [0] "1"
            ],
               "title" => [
                [0] "タイトル1"
            ]
        },
        [1] {
            "track_no" => [
                [0] "2"
            ],
               "title" => [
                [0] {
                       "code" => "12345",
                    "content" => "タイトル2"
                }
            ],
              "single" => [
                [0] {}
            ]
        }
    ]
}

ActiveSupportは、codeというattributeが欠損してますね(is_instは残っていますが、その差の違いは不明です・・・)。なので、attributeが重要なシーンでは使えなさそうです。
逆に、XmlSimpleはすべてのデータが反映されていますが、attributeはString型、elementはArray型で格納されるようです。確かにわかりやすいですが、elementしか使わない場合などに一気にeach句で回したりするのには不便ですね・・・
結論: 適材適所。

処理時間

最後に処理時間を計測しました。

  • 実行コマンド
    • 使い方の部分のコマンドをそのまま。
  • 対象データ
    • 少し大きめの某XMLファイル(5.2MB/144747行)
  • 計測方法
    • 計測マシンは、自分のMacbookPro(Core i7 3GHz/16GB)
    • rubyのバージョン2.2.0p0
    • ruby標準のbenchmarkライブラリを使いました。
ActiveSupport
      user     system      total        real
  9.870000   0.170000  10.040000 ( 10.047934)
XmlSimple
      user     system      total        real
 10.600000   0.180000  10.780000 ( 10.855242)

結論: 性能は考慮材料にならなさそう。

注意点

どこに書いたらいいのかわからなかったので、ハマった点を最後に書いておきます。

rubyのopenメソッドでは文字コードを指定してファイルを開く事が可能ですが、今回の両gemはそれよりもXMLデータ内のXML宣言(<?xml version="1.0" encoding="Shift_Jis"?>みたいなの)の方が優先されるようです。
そのため、ShiftJISのデータをパースしようとすると、文字化けが起きるばかりではなく、いわゆるダメ文字のせいで失敗する事さえあります。

これを回避するためには、XMLデータ内のXML宣言を消した上で処理するしかなさそうです。やっぱり、この方法で本番利用するのは現実味がないです。

  1. Nokogiriが有名ですね。詳しくはこのページがよくまとまっていて参考になります。

8
10
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?