- 2005-11-29 (火)
- Perl
前回の記事に引き続き、XML::Simple モジュールとその背後で利用されるパーサーにおける、ややおまけ的な内容について記述してみました。
背後で利用している XML::SAXパーサーの確実な確認方法
基本的な確認方法は前回記事にて記述しましたが、より確実に、コード実行時に利用しているパーサーが何なのかを確かめたい場合は、ちと泥臭いですが、以下のように XML::Simple のソースコードに直接追記する事で確認できます。
XML::Simple (Simple.pm) の build_tree 関数の以下の箇所(v2.14ならば281-283行目)に
$XML::SAX::ParserPackage = $preferred_parser if($preferred_parser);
my $sp = XML::SAX::ParserFactory->parser(Handler => $self);
こんな感じに一行 warn 文を追加:
$XML::SAX::ParserPackage = $preferred_parser if($preferred_parser);
my $sp = XML::SAX::ParserFactory->parser(Handler => $self); warn $sp."\n"; # 追記箇所
これで XML::Simple 実行の際に use warnings を宣言しておけば、
XML::SAX::PurePerl=HASH(0x83a39e4)
のような文字列がSTDERRに出力されるようになります(微妙^^;)。
$/ 変数の状態によって利用パーサーが変わる妙について
上記の「背後で利用している XML::SAXパーサーの確実な確認方法」を用いて XML::Simple 実行時に裏で利用されているパーサーが何なのかを確実に判別できる状態にして、さらに XML::LibXML 等オプショナルなSAXパーサーが追加インストールされている状態にした上で、以下のようなコードを実行します:
why.pl
#!/usr/bin/perl
use strict;
use warnings;
use encoding 'utf8';
use XML::Simple;
die "Usage: ./why.pl xmlfile\n" if(!@ARGV);
my $xml;
{
open(IN,$ARGV[0]) or die;
local $/ = undef;
$xml = <IN>;
close(IN);
}
my $p = XML::Simple->new();
my $r = $p->XMLin($xml) or die;
以下適当なXMLデータを用いての実行結果:
$ ./why.pl sampleSmall.xml
XML::LibXML::SAX=HASH(0x82ccfdc)
最後にインストールしたSAXパーサー = XML::LibXML::SAX が利用されていることがわかります。では次に why.pl のファイルオープン処理を囲っているブロック記述を省いてみます。
why.pl (修正後)
#!/usr/bin/perl
use strict;
use warnings;
use encoding 'utf8';
use XML::Simple;
die "Usage: ./why.pl xmlfile\n" if(!@ARGV);
my $xml;
open(IN,$ARGV[0]) or die;
local $/ = undef;
$xml = <IN>;
close(IN);
my $p = XML::Simple->new();
my $r = $p->XMLin($xml) or die;
これを実行してみると...
$ ./why.pl sampleSmall.xml XML::SAX::PurePerl=HASH(0x82cce00)
あら不思議。ファイルオープン処理、特に local $/=undef; 部分をブロック枠からはずした事で、暗黙的に利用されるSAXパーサーが変わってしまいました。
XML::Simple のソースコードを追ってみると、XMLin メソッド実行時にて(v2.14の場合 273行目)、
eval { require XML::SAX; };
なんてやっていたりしますので、先の local $/=undef 記述が XML::SAX のスコープ内でも有効になり、その結果なんらかの影響を与えているように見えます。結果、どうして利用するSAXパーサーが変化するかまでは追いませんでしたが(面倒くさくなった^^;)、
$/ 変数に対する操作は、きちんと {} ブロックで囲まないと、XML::Simple の暗黙的なパーサーの選択に影響を与えるので注意すべし
という事は言えるかと思われます。「妙」というよりかは、きちんとしたソースコードを書けなかったオマエがヘッポコってだけの事ですが(汗)。皆様ご注意くださいませ。