XML::Simpleが文字化けする件【解決】
エックスサーバー上で作成したプログラムが文字化けするので調べてみた。結論から言うと文字コードやutf8フラグ云々の話ではなかった。
下の画像を見ていただきたい。楽天からAPIでジャンルリストを取得してみたところであるがXML::Simpleでパースして表示しているだけであるが、何故かリストの後半が文字化けしている。通常文字コード絡みで文字化けする場合は全部文字化けするか文字化けしないかの二択なのでこのように一定の場所からいきなり文字化けを始めるという現象は普通ない。
不可解な現象で、原因の究明には困難を極めたがなんとか解決できたのでメモとして残しておく。
XM::Simpleでパースを行った後に文字化けすることはデバッグログに出力することで確認できたので原因はXMl::Simpleにあることは割とすぐに分かった。
バージョンが原因ではないかと思って自分が普段利用しているコアサーバーのモジュールとバージョンの比較を行ってみたがXML::Simpleのバージョンは
エックスサーバー:2.18
コアサーバー:2.14
とエックスサーバーの方が新しかった。
バージョンの確認には下記のように単純にVERSION変数の出力で行った。
$XML::Simple::VERSION
$XML::Parser::VERSION
$XML::SAX::VERSION
コアサーバーの各モジュールのバージョンは下記のようになっていた。
XML::Simple 2.14
XML::Parser 2.34
XML::SAX 0.14
エックスサーバーの方はどれも最新バージョンだった。
それで、最初は最新バージョンに不具合があるのではないかと思ったが、どれも公開されてから日にちが経っており不具合がればずっと放置されているはずもないと考えた。
utf8 flagの問題も考えてフラグが立ってるかフラグを立てたり落としたりしてみたが事態はよくならなかった。
XML::Simpleの内部で何か外部モジュールを使っていたそのバージョンが古いのではないかと考えたがXML::Simpleのソースの頭のほうを覗いてもuse ◯◯しているところがないので全て自前でやっているのかと最初は思った、が、結果的にこの考えは割と間違ってなかったことが後から分かる。まあ、英語が普通に読める人ならドキュメントを見れば分かることなので全ては英語が読めない私がだめなのだが・・・。
結果的に、XML::SimpleはパーサーとしてXML::ParserかXML::SAXを使うようになっている。XML::Simpleのソースを斜め読みした限りではデフォルトはXML::SAXを使うようになっていて明示的にXML::Parserを使うように指定しないとXML::Parserは使われないように見えた。
実際XML::Simpleのドキュメントを見るとデフォルトはXML::SAXを使うようになっているというのはなんとなく読み取れる。
$XML::Simple::PREFERRED_PARSER = ‘XML::Parser’;
と明示的に指定すればXML::parserが使われるのはXML::Simpleのソースを見ると分かる。
で、実際に下の一行をソースに入れてみたところ文字化けが解決した。
$XML::Simple::PREFERRED_PARSER = ‘XML::Parser’;
以下の画像を見ると実際に文字化けが直ったことが確認できる。
Befor | After |
XML::SAXの問題らしいということはわかったので、ではXML::SAXの何が問題なのかとちょっと調べてみた。
XML::SAX[http://cpan.uwinnipeg.ca/htdocs/XML-SAX/XML/SAX.html]
ドキュメントによるとXML::SAX->parsers()で利用するパーサーのリストを取得できるようなので下のようなコードを書いて確認してみた。
use XML::SAX;
my $parsers = XML::SAX->parsers();
foreach my $x (@{$parsers}){
print "[$x]\n";
foreach my $h (keys %{$x}){
print "[$h]=$$x{$h}\n";
}
}
コアサーバーでは以下のように情報を取得できた。
[HASH(0x81da304)]
[Features]=HASH(0x81c8798)
[Name]=XML::LibXML::SAX::Parser
[HASH(0x81c89a8)]
[Features]=HASH(0x81c86f0)
[Name]=XML::LibXML::SAX
が、エックスサーバーでは取得できなかった。
結論としてエックスサーバーは何かがおかしいということしか分からなかったがそう結論づけた。
そいううわけでXML::Simpleで不可解な文字化けに悩まされている場合は、
$XML::Simple::PREFERRED_PARSER = ‘XML::Parser’;
とすると幸せになれるかも知れない。
というか常にそうしたほうがいいのかも知れない。