- 2004-05-13 (木)
- Perl
CNET Japan の最新ニュースヘッドラインを自分のBLOGのサイドバーに表示させる といった、RSS(*.rdf)を公開している任意のサイトの情報を自分のページに設置できる、RSS FeedをJavaScriptとしてHTMLに埋め込む方法をご紹介。以前、2回に渡って XML::Simple を使った PERL でのXML処理手法を書きましたが(コレとコレ)、今回はその手法を使っての実例紹介です。また、Googleにて "RSS javascript" と検索すると、
miyagawa氏のBlog Developer's Cookbook
→ RSS feed を JavaScript で HTML に埋め込む
naoya氏のNDO::Weblog
→RSS を整形して SSI で表示してみました
等のページにて同様の機能を実現する方法が紹介されていましたが、ここで紹介するのはそれらとはまた違った、「簡単なソースコード」「更新に手間がかからない」といった点を重視した実装方法を述べてみます。
作るもの
呼び出される度に、指定したRSS Feedの最新版を取得して、
<!--
document.write('<a href="リンク先1">最新記事1</a><br>');
document.write('<a href="リンク先2">最新記事2</a><br>');
document.write('<a href="リンク先3">最新記事3</a><br>');
//-->
といったJavaScriptを動的に出力するCGIスクリプト。ここでは名前を
rss2js.cgi
としておきます。
作成したCGIの使い方
HTMLにて外部のjsファイル(JavaScriptファイル)を呼び出すには、
<script language="javascript" type="text/javascript" src="/path/to/file.js"></script>
と書くことで出来ますが、この src 部分は静的な *.js ファイルである必要はありません。今回作成する rss2js.cgi は呼び出されると「作るもの」項に書いてあるような Javascriptコード を出力するので、これを
<script language="javascript" type="text/javascript" src="/path/to/rss2js.cgi"></script>
と書くことで、CGIにて動的に作成した最新記事一覧を任意の静的HTML上で表示させる事ができる、といった仕組みになります。
rss2js.cgiのソースコード
で、このCGIのソースコードですが、記述する処理は大体こんな感じになります:
(1)RSS Feed を取得して Perl構造体に変換する
(2)JavaScriptで出力する際に必要な文字エスケープ処理を行う
(3)JavaScriptの document.write 文として出力する
(1)の部分にて、以前に書いた「XML::Simple の使い方」と「その2」で書いた手法を用いています。取り込むRSSは CNET JapanのHEADLINE NEWS RSS にしてみました。(2)は作ってる途中で気づいた事です。JavaScriptで出力する文字列の中に ' (apostrophi) や 改行文字が含まれていると document.write(' hogehoge ' ) の処理が正しく実行されませんので、PERL側で事前にエスケープさせます。(3)でのポイントはPERLからの出力文字列が JavaScript であることをブラウザに認識させる為に HTTP HEADER を頭で出力している点です。で、実際のソースコードは以下の様になります:
#!/usr/bin/perl
use LWP::Simple;
use XML::Simple;
use Jcode;
### RSS取得&解析 ###
my $url = "http://japan.cnet.com/rss/index.rdf";
my $xml = LWP::Simple::get($url);
my $x = new XML::Simple;
my $obj = $x->XMLin($xml);
$obj = &ConvertEncoding($obj,'utf8','euc');
### 文字エスケープ ###
my ($v);
foreach $v (@{$obj->{item}}){
$v->{title} =~ s/'/\\'/g;
$v->{title} =~ s/[\r\n]//g;
}
### JavaScript出力 ###
my $v;
print qq(Content-type: text/javascript\n\n);
print qq(<!--\n);
foreach $v (@{$obj->{item}}){
print qq(document.write\('<a href="$v->{link}" );
print qq(target="_blank">- $v->{title}</a><BR>'\);\n);
}
print qq(//-->\n);
# _____ Subroutine : 構造体の文字コード置換 _____________________
sub ConvertEncoding($$$){
my($p,$from,$to) = @_;
die qq(ConvertEncoding : need to specify character encoding
you'd want to convert to) if(!$to);
my $r = ref($p);
### if [BLESSED] HASH REFERENCE ###
if($r eq 'HASH' || ( !$r && $p =~ /=HASH\(.+\)/ )){
my $v;
foreach $v (keys %{$p}){
$p->{$v} = &ConvertEncoding($p->{$v},$from,$to);
}
}
### if [BLESSED] ARRAY REFERENCE ###
elsif($r eq 'ARRAY' || ( !$r && $p =~ /=ARRAY\(.+\)/ )){
my $i=0;
for ($i;$i <= $#{$p};$i++){
$p->[$i] = &ConvertEncoding($p->[$i],$from,$to);
}
}
### if [BLESSED] CODE REFERENCE ###
elsif($r eq 'CODE' || ( !$r && $p =~ /=CODE\(.+\)/ )){
}
### if SCALAR ###
else{
$p = Jcode->new($p,$from)->$to;
}
return $p;
}
完成
作成した rss2js.cgi をサーバに設置したうえで、任意のHTMLの一覧を表示させたい場所に以下のScriptタグを記述すれば完成です:
<script language="javascript" type="text/javascript" src="/path/to/rss2js.cgi"></script>
今回は最低限のコードで、最低限の機能のみを実装しましたが、さらに拡張機能として、
任意のRSSをGETパラメータにて指定できる
一覧表示件数をGETパラメータにて指定できる
出力する一覧の文字コードをGETパラメータにて指定できる
等があったら便利ですよね。その辺のカスタマイズもPERL CGIですので容易に実現できるかと思います。今回紹介した方法+上記のカスタマイズを実装させた上で、iandeth. では MyClip の Clip Ranking RSS をサイドメニューの「注目ニュース」として表示させています。bashiの注目するニュースではなくて、他の皆が注目しているニュースを自分のBLOGに表示させてるという横着っぷり /w。
追記
後日Googleで似たような記事/サービスについて調べてみたら... 速攻で幾つか有名っぽいページを見つけてしまいました^^;
B.B.氏のB.B.'sWebSpace : ページ埋め込み型RSSリーダ jsRSS.cgi
rss-jp.netの read_rss.cgi
最初にもっと調べてから書けよ俺...。