zerosp.blog > Web Programming > 2007/12/11 11:03 >

[自分メモ] 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)

投稿日 2007-12-11 11:03

当サイトのコメントとトラックバックの扱いについて。

スパム対策のため認証制となっています。受け取ったコメント、トラックバックは一旦保留扱いとなり管理人が許可したものだけ表示されます。

トラックバック

  • [自分メモ] PerlでXML::LibXMLの使いかた。のトラックバックURL

コメント

コメントフォーム