[自分メモ] PerlでXML::LibXMLの使いかた。
このページはPerlのxml-libxmlに関する自分用メモです。最低限のことのみ。適当に作成した商品データ(10件分)を読み込んで1件づつ出力するという簡単なサンプルコード。今回はXMLデータの読み込みのみでXMLにデータを追加するといったことなどは書いてません。
sample xml(test.xml)を読み込んで、商品IDとタイトル、価格のデータを
[ID:xxxxxx] タイトル 価格
ってな感じで出力したい。コードはこんな感じ。
use strict;
use Encode;
use XML::LibXML;
use utf8;
my $parser = XML::LibXML->new();
my $doc = $parser->parse_file('./xml/test.xml');
my @nodes = $doc->findnodes('SearchResults/Items/Item');
my ($id, $title, $price);
my @itemdata = ();
foreach my $node (@nodes) {
$id = $node->find('ItemId');
$title = $node->find('Title');
$price = $node->find('Price');
if ($node->findvalue('Price/@Code') eq 'JP' ) {
$price .= ' 円';
}
# print encode('sjis', "[ID:$id] $title $price\n");
push @itemdata, encode('sjis', "[ID:$id] $title $price\n");
}
このコードを実行すると
[ID:00001] もみじ 100 円
ってな感じで出力されます。とりあえずこれでクリアと思ったんだけどnamespaceの付いたXMLデータだと上記の例では読み込むことが出来ません。たとえば先ほどのtest.xmlにnamespaceを追加してみます(sample:test2.xml)。
<SearchResults xmlns="http://example.com/hoge/">
上記のようにnamespace情報を付加してみました。これは凄いTry&Errorを繰り返したんですよね。いろいろと苦労しました。
まずはその1。XPathにlocal-nameと指定してやるやり方。これだと長いXPathを使うときにちょっと疲れるかも・・・。
my $parser = XML::LibXML->new();
my $doc = $parser->parse_file('./xml/test2.xml');
my @nodes = $doc->findnodes("/*[local-name()='SearchResults']/*[local-name()='Items']/*[local-name()='Item']");
my ($id, $title, $price);
my @itemdata = ();
foreach my $node (@nodes) {
$id = $node->findvalue("*[local-name()='ItemId']");
$title = $node->find("*[local-name()='Title']");
$price = $node->find("*[local-name()='Price']");
if ($node->findvalue("*[local-name()='Price']/\@Code") eq 'JP') {
$price .= ' 円';
}
# print encode('sjis', "[ID:$id] $title $price\n");
push @itemdata, encode('sjis', "[ID:$id] $title $price\n");
}
続いてその2。XPathContextを使ってnamespace情報を渡してやってそれを元にxmlをパースするって感じ。
my $parser = XML::LibXML->new();
my $doc = $parser->parse_file('./xml/test2.xml');
my $xc = XML::LibXML::XPathContext->new;
$xc->registerNs('xmlns', 'http://example.com/hoge/');
my @nodes = $xc->findnodes('xmlns:SearchResults/xmlns:Items/xmlns:Item', $doc);
my ($id, $title, $price);
my @itemdata = ();
foreach my $node (@nodes) {
$id = $xc->find('xmlns:ItemId', $node);
$title = $xc->find('xmlns:Title', $node);
$price = $xc->find('xmlns:Price', $node);
if ($xc->findvalue('xmlns:Price/@Code', $node) eq 'JP' ) {
$price .= ' 円';
}
# print encode('sjis', "[ID:$id] $title $price\n");
push @itemdata, encode('sjis', "[ID:$id] $title $price\n");
}
上記3種のコードのベンチを取ってみました。PC: CPU Pen4-2.66、メモリ 512M。ソフト Win XP Pro、AN HTTPD、Active Perl 5.8.8-822です。
Benchmark: timing 1000 iterations of nons, ns-type01, ns-type02... nons: 11 wallclock secs ( 8.44 usr + 1.59 sys = 10.03 CPU) @ 99.69/s (n=1000) ns-type01: 11 wallclock secs ( 9.59 usr + 1.44 sys = 11.03 CPU) @ 90.65/s (n=1000) ns-type02: 11 wallclock secs ( 8.38 usr + 1.67 sys = 10.05 CPU) @ 99.53/s (n=1000)
コメント