NDO::WeblogさんのPerl で XML
の処理はどれが速いかベンチで、正規表現、XML::Simple、XML::RSS、XML::LibXMLの4つで、RSSの中から、linkを抜き出すベンチの記事が公開されていますが、
もうすこし、RSSの中から情報を抜き出して、Perlで使いやすいようにしていったらどうなるか試してみた。
ちょっとさぼって、XML::RSSとXML::LibXMLだけ
まず結果から
# perl libxmlrss.pl index.rdf
Benchmark: timing 100 iterations of XML::LibXML, XML::RSS...
XML::LibXML: 5 wallclock secs ( 4.49 usr + 0.02 sys = 4.51 CPU) @ 22.17/s (n=100)
XML::RSS: 24 wallclock secs (24.40 usr + 0.01 sys = 24.41 CPU) @ 4.10/s (n=100)
やはり、XML::RSSはXML::LibXMLに比べて遅いです。
XPathの書き方がこれでいいのかどうかわからないのでもうすこし改善できるところなどありそうです。
スクリプトはNDO::Weblogさんのを参考にして書きました
XML::LibXMLを使った方は、RSS1.0でencodeモジュールを使用している時のみ対応です。
実際XML::LibXMLを使うには処理を分ける必要があると思います。
#!/usr/bin/perl
use strict;
use XML::LibXML;
use XML::RSS;
use IO::File;
use Benchmark;
my $rss_file = shift or die "usage $0";
my $fh = IO::File->new($rss_file) or die "cannot open $rss_file: $!";
my $content = join("",$fh->getlines);
$fh->close;
Benchmark::timethese(100, {
'XML::RSS' =>\&with_xml_rss,
'XML::LibXML' => \&with_xml_libxml,
});
sub with_xml_rss{
my %rss;
my $rss = XML::RSS->new;
$rss->add_module(
prefix=>"content",
uri=>"http://purl.org/rss/1.0/modules/content/"
);
$rss->parse($content);
my $channel = $rss->channel;
$rss{title} = $channel->{title};
$rss{link} = $channel->{link};
$rss{date} = $channel->{dc}->{date};
my @items;
foreach my $item (@{$rss->{items}}){
my %item;
$item{title}=$item->{title};
$item{link}=$item->{link};
$item{description}=$item->{description};
$item{encoded}=$item->{content}->{encoded};
$item{subject}=$item->{dc}->{subject};
$item{creator}=$item->{dc}->{creator};
$item{date}=$item->{dc}->{date};
push(@items,\%item);
}
$rss{items}=\@items;
}
sub with_xml_libxml{
my %rss;
my $parser = XML::LibXML->new;
my $doc = $parser->parse_string($content);
$rss{title} = $doc->findvalue("//*[local-name()='channel']/*[local-name()='title']/text()");
$rss{link} = $doc->findvalue("//*[local-name()='channel']/*[local-name()='link']/text()");
$rss{date} = $doc->findvalue("//*[local-name()='channel']/dc:date/text()");
my @nodes = $doc->findnodes(
"//*[local-name()='item']"
);
my @items;
for my $node (@nodes){
my %item;
$item{title}=$node->findvalue("*[local-name()='title']/text()");
$item{link}=$node->findvalue("*[local-name()='link']/text()");
$item{description}=$node->findvalue("*[local-name()='description']/text()");
$item{encoded}=$node->findvalue("./content:encoded/text()");
$item{subject}=$node->findvalue("./dc:subject/text()");
$item{creator}=$node->findvalue("./dc:creator/text()");
$item{date}=$node->findvalue("./dc:date/text()");
push(@items,\%item);
}
$rss{items}=\@items;
}