たけまる / フィードから JSON への変換方法を統一して JavaScript でラクする
2007-04-02
_
フィードから JSON への変換方法を統一して JavaScript でラクする [atom][perl]



以前のエントリ [2007-03-31] で XML::FeedPP を使ったのは,まえにJSONP 変換を作ったからです.
ところが,JSONP 変換サービスはあちこちにあります.たとえば,↓など
は老舗です.
XML を JSON に変換するサービス - ベータ版を公開 :: Drk7jp
では,どうして新たに JSONP 変換スクリプトを書いたかというと,変換
後の JSON のデータ構造を揃えたかったからです.
たとえば,RSS と Atom が混ざっていると,JavaScript でエントリを取
得するときにハッシュキーを使い分けなければなりません.また,XML か
ら JSON への変換方法が統一されていないと,ある要素が配列なのかハッ
シュなのかわからなかったりします.
というわけで,次のような特徴を持つ JSONP 変換スクリプトを作ってみ
ました.公開しますので自由に使ってください.
■ 特徴
- データ形式を指定したフィード (たとえば Atom 1.0) に変換してから JSON にする.フィードの種類がなんであっても,JavaScript で同じよ うに処理できる. - XML から JSON への変換は,GData 準拠とする.たとえば,要素数がひ とつであればハッシュ,複数であれば配列となる.また,テキスト要素 へのアクセスキーは '$t' である. - 複数フィードをひとつにまとめられる.時刻順のソートもできる. - ついでに,XML 間の変換もサポートした ([2007-03-31] に書いたよう に,Atom 0.3 <-> Atom 1.0 とか).
JSON への変換には,[2007-02-22] で紹介した Google::Data::JSON を使っ
ています.
まぁ,いまとなっては Yahoo PIPES でできることなんでしょうが,ビジ
ネス上の理由で使えなかったりすることもあるので,そういう方はこちら
を参考にしてください.下のほうでソースも公開しています.
■ ベースURI
http://teahut.sakura.ne.jp/t/feed.cgi
■ パラメータ
| パラメータ | 値 | 説明 |
| uri | フィードURI | 複数指定するとひとつのフィードにまとめます |
| alt | rdf, rss, atom03, atom10 | 変換後のデータ形式を指定します |
| jsonp | JavaScript 関数名 | この関数名で JSON を格納します |
| sort | feed, date | エントリをソートします |
jsonp を指定しなければ,単なる XML 変換を行います.
■ 例
このブログのフィード (RDF) を Atom に変換して,JSON に変換し,
myfunc という JavaScript 関数 に渡します.
feed.cgi?alt=atom10&jsonp=myfunc&uri=http://teahut.sakura.ne.jp/b/cl.rdf
■ ソースコード
自由に使っていただいてかまいません.なお,XML::FeedPP には
[2007-03-31] のパッチを当ててください.
use strict;
use warnings;
use CGI;
use CGI::Carp qw( fatalsToBrowser );
use Google::Data::JSON qw( gdata add_elements );
use XML::FeedPP;
my @RDF_ELEMENTS = qw( channel description image item items link rdf:li rdf:RDF
rdf:Seq title url );
my @RSS_ELEMENTS = qw( author category channel cloud comments copyright
description docs enclosure generator guid height image
language lastBuildDate link managingEditor name pubDate
rating rss skipDays skipHours source textInput title ttl
url webMaster width );
add_elements( @RDF_ELEMENTS, @RSS_ELEMENTS );
my $PROXY = undef;
my $q = CGI->new;
$ENV{http_proxy} = $q->param('noproxy') ? undef : $PROXY;
my @uri = $q->param('uri');
my $alt = $q->param('alt') || 'rss';
my $feed = $alt eq 'rdf' ? XML::FeedPP::RDF->new
: $alt eq 'rss' ? XML::FeedPP::RSS->new
: $alt =~ /atom0\.?3/ ? XML::FeedPP::Atom->new
: XML::FeedPP::Atom1_0->new ;
$feed->title( join ' - ', map { XML::FeedPP->new($_)->title } @uri );
$feed->merge($_) for @uri;
$feed->sort_item if $q->param('sort') && $q->param('sort') =~ /date/i;
$feed->pubDate(time);
$_->title( $_->title . ' (' . $_->author . ')' ) for $feed->get_item;
if ( my $jsonp = $q->param('jsonp') ) {
print $q->header( -charset => 'utf-8', -type => 'application/json' ),
"$jsonp(" . gdata( $feed->to_string )->as_json . ')';
}
elsif ( $alt eq 'json' ) {
print $q->header( -charset => 'utf-8', -type => 'application/json' ),
gdata( $feed->to_string )->as_json;
}
elsif ( $alt eq 'rdf' ) {
print $q->header( -charset => 'utf-8', -type => 'application/rdf+xml' ),
$feed->to_string;
}
elsif ( $alt eq 'rss' ) {
print $q->header( -charset => 'utf-8', -type => 'application/rss+xml' ),
$feed->to_string;
}
elsif ( $alt =~ /atom0\.?3/ ) {
print $q->header( -charset => 'utf-8', -type => 'application/x.atom+xml' ),
$feed->to_string;
}
else {
print $q->header( -charset => 'utf-8', -type => 'application/atom+xml' ),
$feed->to_string;
}
