XmlSimpleを試してみる

先日Google Codeに掲載されていたUsing Ruby with Goole Data APISを読んだ時に、XMLの処理でXmlSimpleというライブラリを使っていたのが気になったので試してみる。

もとはPerlXML::Simpleを模したものらしい。実装としてはREXML(2.7.1以後)のラッパーとして動作してるっぽいのでREXMLの制限がなにかあればそれはそのまま引き継ぐということかな。

インストールは例によってgemで一発で解決。

gem install xml-simple

そこそこ大きいデータを処理したときどうなるか知りたいので大きめのデータがいいので、BoardGameGeekのXMLスナップショットを利用してみる。これはこのサイトの登録データを不定期にXMLにはき出しているものでテキストで7M近いサイズのXMLになってる。

ちょうど4/29があったのでこれを使ってみる。試しにWindows端末のirbでテスト

require "rubygems"
require "xmlsimple"
doc = XmlSimple.xml_in("./bgg-snapshot-20080429.xml")

docの中身がはき出されるまでに約50秒。Core Duo2 3.0GHzの端末でこのぐらい。まあ、バッチでしか処理しないのでいいと言えばいいかな。

使い方は簡単だが難しい。XMLデータをHash化してしまう構造なんだが、繰り返しありと無しでが混ざってるや属性値ありと無しが混ざっているときの処理が面倒な雰囲気。

今回のXMLデータを抜粋してみると以下のようになる


 
  2002 
  3 
  5 
  90 
  Puerto Rico 
 
 
  2004 
  2 
  6 
  120 
  Power Grid 
  Funkenschlag (Second Edition) 
 

先ほど読み込ませたものでアプローチすると、以下のようになる

doc["game"][0]["name"] #=>[{"primary"=>"true", "content"=>"Puerto Rico"}]

トップのgamesタグは格納されていないので、その次の要素からがキーになる。gameの要素の0番目(読み込んだ順)で、その要素のHashにアクセスできる。で、nameにアクセスするとPuerto Rico部分にアクセスできるわけなんだが、属性値がある場合は、勝手にHash構造に変換されて入ってしまうのがミソ。

しかもディフォルトだと配列になっている。

これは、2つ目の要素にアプローチしたときその差がわかる。

doc["game"][1]["name"] 
 #=>[{"primary"=>"true", "content"=>"Power Grid"}, "Funkenschlag (Second Edition)"]

名前のデータは2個あるのだが、属性値が無いほうはただのStringとして格納されている。Hashになったり文字列になったりすることを予想しながら使わないといけないので、この辺結構面倒かも。

オプションとして特定の属性値をHashのキーとして認識させることとかもできるにはできる

doc = XmlSimple.xml_in("./bgg-snapshot-20080423.xml","KeyAttr"=>"gameid")

こうなるとの3076がキーになってアプローチできる。

doc["game"]["3076"]["name"] 
 #=>[{"primary"=>"true", "content"=>"Puerto Rico"}]

配列に強制的にするかどうかも決めれるみたいなんだけど、属性値の有無でHashにするかどうかの挙動を変えるのは、ぱっと見た感じ見あたらない。

その辺がわかればもうちょっと使いやすくなりそうなんだけど、個人的には微妙なライブラリかなあ。