なぜ空(無名)ハッシュを返すのか

| | トラックバック(0)

カテゴリ:

XML::Simpleの扱いではまる。

例えばこういうXMLの場合、

<entry>
<string>ほげほげ</string>
<string>ほげーほげー</string>
<string>捕鯨捕鯨</string>
</entry>

そしてこういう場合、

<entry>
<string>ほげほげ</string>
</entry>

さらにこういう場合、

<entry>
</entry>

これら3パターンではXML::Simpleをデフォルトで使った場合、
返ってくるハッシュ構造が異なってしまう。
手早くコードを書こうとすると、手元にあるサンプルのXML構造だけを想定して、
変数の取り出しなどの手順を書くので、
別のXMLがきた場合、変数が取り出せなくなったりする。

それを回避するために、オプションがあるのだが、
それですべての問題を回避できるかというと、
多分できないと思う。
XML::Simpleを使うことで開発スピードはあがるが、
パースの汎用性は当然落ちるし、それによってプログラムが止まる可能性も高まる。
止まらないプログラムを書くには、
いろいろな状況を想定して条件分岐を書くしかないが、
それだと結局開発スピードが落ちて、
自分でパーサを書いた方が早かったということになるかもしれない。

今回はまあ、XML::Simpleですませてしまった。
このページを参考にさせていただいた。
Perl モジュール XML::Simple の使い方 - ミヤビッチの穴

今回はこんな感じでオプション指定した。

my $xp = XML::Simple->new(
   SuppressEmpty => undef,
   keyattr => [ 'name', 'key'],
   forcearray => 0
)

「SuppressEmpty => undef」は要素がなかったときに、空のハッシュを返すのではなく
undefを返せという意味。

「keyattr => [ 'name', 'key']」はnameとkeyがあったらそれはハッシュのkeyにしろという意味。
デフォルトだとこれに ' id ' も含まれているので、
それを除外した感じ。

「forcearray => 0」は要素の数に関わらず毎回必ず無名配列を作ってその要素として
ハッシュを格納する というのを"しない"という処理。
これはデフォルトで0なのであえて指定する必要はなかったと言える。

それで、まあうまくいっていそうなんだけれども、
疑問に思ったのが、なんでデフォルトだと要素が空だった場合に空(無名)ハッシュ( {} )を
返す仕様になっているのかという点。

返ってきた値が空だったらこれこれの挙動をせよ、とプログラムを書こうとしても

if( !$xml_ref->{'value'} )

とやるだけでは値が空でも空ハッシュが返ってきてしまうせいで真と判定されてしまう。
わざわざ

if( !%{ $xml_ref->{'value'} })

と書かないといけない。
手間としてはちょっとしたものだけれども、
どことなく直感的ではないので、ついついミスしてしまう。

まあそれはそれで、やりずらいなあと思いながらコードを書いていたのだが、
あるとき、なぜ空ハッシュになっているのかがわかった。

基本的に、XML::Simpleにパースさせたら、
返ってくるのはハッシュの配列のハッシュのハッシュの配列のハッシュの・・・・という具合に、
気の遠くなるほど複雑な無名ハッシュと無名配列と変数の入り乱れる構造が
返ってくる。

深い深いハッシュ・配列構造をしているので、
その構造を操作するさいは、常に変数(スカラー値)を取得したりセットしたりするだけでなく、
その複雑ハッシュ構造の一部のハッシュ構造を取ってきてどうのこうのという
操作をすることが頻繁に起こる。

そうすると、コードの中ではハッシュのリファレンスがあっちにいったり
こっちにいったりするようになる。
飛んできた部分ハッシュから変数を取り出したり、
そこからまた部分ハッシュを取り出したり。

送られてくるのはハッシュのリファレンスであることを想定しているので、
来た変数がハッシュどうか、リファレンスかどうかのチェックなどすることなしに、
それを操作しようとする。

それこそが、XMLの要素が空だった場合にundefとか文字のない文字列とかを返すのではなく、
無名ハッシュを返す理由なのである。

いつもハッシュが来ると思っているので
「undef」とか「0」とか「''」(文字のない文字列)が来たりすると
それにたいしてハッシュ値を取り出そうという操作をした結果、

Can't use string ("0") as a HASH ref while "strict refs" in use at sample.pl line 45.

というエラーが起こることになる。
ここで問題なのはこれはプログラムが止まってしまうエラーだということ。

もし、例え空っぽであってもハッシュが返ってくれば、
それはundefを返すだけなのでプログラムは止まらない。

ややこしいかもしれないので、くどいけど繰り返すと、

・スカラーに対してハッシュの値を取り出す操作をするとプログラムは止まる
・空っぽでもそれが(無名)ハッシュならundefを返すだけでプログラムは止まらずに済む

ということ。

プログラムが止まるか止まらないかというのは大きな差で、
止まらない方が当然ロバストなシステムとなり
使い勝手が雲泥の差となる。

だから、XML::Simpleは空の無名ハッシュを返すのだろう、
ということを考えた。

comments powered by Disqus

トラックバック(0)

このブログ記事を参照しているブログ一覧: なぜ空(無名)ハッシュを返すのか

このブログ記事に対するトラックバックURL: http://nozawashinichi.sakura.ne.jp/MT-4.25/mt-tb.cgi/663

comments powered by Disqus

このブログ記事について

このページは、Shinichi Nozawaが2009年11月19日 17:27に書いたブログ記事です。

ひとつ前のブログ記事は「いともあっさりMT::Mailが使えた」です。

次のブログ記事は「メモ about 192.168.0.0」です。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。