- 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
最初にもっと調べてから書けよ俺...。