del.icio.usのRSSをXML::RSSでparseする前に
del.icio.usで日本の記事をブックマークする際に、extended欄に記事から長い文章を貼り付けると、たまに文字化けすることがあります。
feedburnerでdel.icio.usが文字化けする問題 -huixingの日記-
普通に使うだけなら、あーなんか最後が?になってるけどまぁいいか、で済ませられるんですが、このRSSをperlのXML::RSSでparse使用とすると、
not well-formed (invalid token) at line 31, column 92, byte 2258 at /usr/local/lib/perl5/site_perl/5.8.6/ppc-linux/XML/Parser.pm line 187
と言われてしまいます(上記は実験用RSSをparseした場合の出力)。
このエラーメッセージを元に検索すると次のページが見つかりました。
not well-formed (invalid token) at line 1, column 34922, byte 50440 at /usr/lib/perl5/5.8.0/i386-linux-thread-multi/XML/Parser.pm line 185
調べてみると,SOAPレスポンスメッセージの中の「レビュー」部分に機種依存の文字が含まれているため,うまくparseできないようだ.
XML::Parserのエラー -test::blog-
上記はAmazonのSOAPレスポンスの問題ですが、del.icio.usのRSSもencoding=utf-8なので、同じ問題のようです。
いろいろ試してみて、getしたRSSをutf-8 -> euc-jp -> utf-8とすることで解決しました。eucに変換することで、utf-8の場合に人間には?で見えていたu+fffdの文字を本来の?に変換し、文字としての?をまたutf-8に戻しています(機種依存文字の解決だけなら最後のutf-8に戻す処理は要らないです)。
#!/usr/local/bin/perl -w use strict; use warnings; use LWP::Simple; use XML::RSS; use Encode; use encoding "euc-jp"; my $url = 'http://del.icio.us/rss/rtk2106/_tmp+perl'; my $content = get($url); my $rss = XML::RSS->new; $content = _convert_encode($content); $rss->parse($content); my $output; foreach my $item (@{$rss->{items}}) { $output .= "--------------------\n"; $output .= "title : $item->{title}\n"; $output .= "link : $item->{link}\n"; $output .= "description : $item->{description}\n"; } print $output; sub _convert_encode { my ($content) = shift; my ($enc_src) = ($content =~ /<\?xml .*? encoding="(.*?)"\s*\?>/); my $enc_dst = 'euc-jp'; Encode::from_to($content, $enc_src, $enc_dst); Encode::from_to($content, $enc_dst, $enc_src); return $content; }