XML::RSS

RSSフィードを生成する(デコードもできる)
お手軽にRSSを生成できるが、諸々の問題点があって素直には使えない。

問題点1:
ワイドキャラクタをHTMLエンコード(&#xx)してしまう。ワイドキャラクタをHTMLエンコードされると、大抵のRSSリーダは(ブラウザも)、”意味不明の1バイト文字"と認識し、ワイドキャラクタと認識してくれないので、漢字は全て文字化けする。
回避するには、< > & ' "  だけをHTMLエンコードしたコンテンツを渡して、二重エンコードさせ、一度デコードしたものを最終出力にする。

問題点2:
XML::RSSの問題点というより、RSSの使われ方の方が問題かもしれないが…RSS解釈が厳格で実情に合わない部分がある。
<content:encoded>フィールドにエンコードされたHTML(つまり、タグを含んだ生HTML)を埋め込むフォーマットが流通しているが、このフィールドはRSS1.0の正式規格にはないので対応してくれない。
使いたければ、RSS生成後に強引に文字列置換で埋め込むしかない。

使い方の例:

use strict;
use XML::RSS;
use HTML::Entities;  # HTMLエンコード/デコードにHTML::Entitiesを使う

my $rss = XML::RSS->new(version => '1.0', encoding=> 'utf-8');
$rss->channel(
	title        => encode_entities($site_title,qq/><&'"/),
	link         => $site_url,
	description  => encode_entities($site_description,qq/><&'"/),
	dc           => {language   => 'ja'}
);
#
# @contentsにRSS出力するコンテンツのハッシュリファレンスの配列が入っている場合の例
# 後でencoded_contentを出力する位置に "+++$n" を出力しておく
my $n = 0;
foreach (@contents) {
	$rss->add_item(
		title       => encode_entities($_->{'subject'},qq/><&'"/),
		link        => $_->{'content_url'};
		description => encode_entities("$_->{'decoded_content'}+++$n",qq/><&'"/),
		dc => {
			date    => "$_->{'date'}+09:00",
			subject => encode_entities($_->{'content_subject'},qq/><&'"/),
			creator => encode_entities($_->{'content_creator'},qq/><&'"/),
			rights  => encode_entities($_->{'content_copyrights'},qq/><&'"/)
		}
	);
	++$n;
}
my $out = $rss->as_string;
#
# "+++$n"をencoded_contentに置換する
$n = 0;
foreach (@contents) {
	$out =~ s|\+\+\+$n(</description>)|$1\n<content:encoded><![CDATA[$_->{'encoded_content'}]]></content:encoded>|;
	++$n;
}
print decode_entities($out);