
perlで動く軽めのXMLパーサとしてXML::TreePPがある。これを用いてXMLのサイトマップを生成するcgiを作ってみよう。XMLパーサを使ってXMLサイトマップを作るなんてのは何番煎じになるのかわからないけれど、XML::TreePPを使ってサイズの大きくならないXMLファイルの生成について記事を書こうと思ったらこうなった。
#!/usr/local/bin/perl -wT
use strict;
use warnings;
use DateTime;
use DateTime::Format::W3CDTF;
use XML::TreePP;
my @target = &set_target();
&make_sitemap(@target);
exit;
sub set_target
{
opendir DIR, "./";
my @target = grep{m/^\w+\.html$/} readdir DIR;
closedir DIR;
return @target;
}
sub set_priority
{
my $mtime = shift;
return sprintf("%2.1f", $_ eq 'index.html' ? 1.0 : 0.5);
}
sub set_lastmod
{
my $mtime = shift;
my $dt = DateTime->from_epoch( time_zone => 'Asia/Tokyo', epoch => $mtime );
return DateTime::Format::W3CDTF->format_datetime($dt);
}
sub set_changefreq
{
my $mtime = shift;
my $changefreq = '';
my $sub = time - $mtime;
my $diff = 60;
if ($sub < $diff ) {
$changefreq = 'always';
} elsif ($sub < ($diff *= 60)) {
$changefreq = 'hourly';
} elsif ($sub < ($diff *= 24)) {
$changefreq = 'daily';
} elsif ($sub < ($diff *= 7)) {
$changefreq = 'weekly';
} elsif ($sub < ($diff *= 30)) {
$changefreq = 'monthly';
} elsif ($sub < ($diff *= 12)) {
$changefreq = 'yearly';
} else {
$changefreq = 'never';
}
return $changefreq;
}
sub set_url
{
my $file = shift;
my $mtime = (stat($file))[9];
my $url = {
changefreq => &set_changefreq($mtime),
lastmod => &set_lastmod($mtime),
loc => $file,
priority => &set_priority($mtime),
};
return $url;
}
sub make_sitemap
{
my $tpp = XML::TreePP->new();
my $tree = {
'urlset' => {
'-xmlns' => 'http://www.google.com/schemas/sitemap/0.84',
url => [
],
},
};
@{$tree->{urlset}->{url}} = map{&set_url($_)}@_;
$tpp->writefile("./sitemap.xml", $tree);
return;
}
__END__
サイトマップを生成したいファイルの配列を返す。
ファイルが書かれた配列引数を受け取って、それぞれのファイルについてurlタグの内容を生成するサブルーチンを呼び出す。生成されたハッシュをTreePPのwritefileでXMLに変換して書き込み
サイトマップを生成したいファイルを引数としてurlタグと対応した連想配列を返す。更新時間を元にurlタグの内容(loc, lastmod, changefreq, priorityタグ)を生成する。
ファイルの最終更新時間を引数として、priorityタグの内容を返す。このスクリプトでは最終更新時間を受け取っているがそれに関連した処理は行っていない。単純にindex.htmlはゲートページなのでこのプライオリティを1.0としてそれ以外は0.5にしている。もっと複雑なルールが必要ならばこのサブルーチンの中に書く。
ファイルの最終更新時刻を引数として、lastmodタグの内容を返す。DataTimeと出力フォーマットのDateTime::Format::W3CDTFを使って、ファイルの最終更新時刻を適当な時刻フォーマット(W3C Datetime)に変換しているだけ。W3C DatetimeはISO8601で定義されているのでDateTime::Format::ISO8601を使うのが正攻法だが、このサブセットであるW3CDTFのほうが単純なのでDateTime::Format::W3CDTFを使っている。
ファイルの最終更新時刻を引数として、changefreqタグの内容を返す。ファイルの最終更新時刻を元に、cgiが呼び出された時刻と比較して60秒以内に更新があったらalways、60*60秒以内なら'hourly'等の文字列を返す。更新頻度というよりも更新したタイミングからどのくらい経過したかという意味になっているのであまりよろしくないと思うけれど。