Movatterモバイル変換


[0]ホーム

URL:


てっく煮" src="/images/logo-ja.png">

2006年01月13日

xml2json.cgi - ドメインを超えてXMLを読みこむ

このエントリーをはてなブックマークに追加Tweet

Ajax の弱点は別ドメインのページを取得できないこと。そんな制限を取っ払って、別ドメインの XML を取得できる CGI を作ってみました。

使い方

XMLファイルの例:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?><items><item><jcity>千代田区</jcity><jlocal>千代田</jlocal><jpref>東京都</jpref><pref_cd>13</pref_cd><zip_cd>1000001</zip_cd></item></items>

XMLファイルへのアクセス方法1(同期)

XML の URL はhttp://www.example.com/sample.xml だと仮定します。XML を読み込むには次のようなタグを HTML に記述します。

<scriptcharset="utf-8"type="text/javascript"src="xml2json.cgi?url=http%3A%2F%2Fwww.example.com%2Fsample.xml"></script>

xml2json.cgi は自分のサーバーに設置します。

上記の JavaScript は次のように展開されてインポートされます。

if(typeof(xml)=='undefined')xml={};xml.data={items:{item:{jcity:"千代田区",jlocal:"千代田",jpref:"東京都",pref_cd:"13",zip_cd:"1000001"}}}if(typeof(xml.onload)=='function')xml.onload(xml.data);

たとえば、HTML からは次のようにして XML の情報を利用します。

<scriptcharset="utf-8"type="text/javascript"src="xml2json.cgi?url=http%3A%2F%2Fwww.example.com%2Fsample.xml"></script><script>alert(xml.data["items"]["item"]["jcity"];</script>

XMLファイルへのアクセス方法2(非同期)

script タグでインポートしてしまうと、スクリプトのダウンロードが完了するまで、script タグ以降の HTML の表示がとまってしまいます。

そこで、非同期に xml2json を呼び出す方法を示します。ここでは、window.onload イベントで読み込みを行っています。

window.onload=function(){vars=document.getElementsByTagName("head")[0].appendChild(document.createElement("script"));s.type="text/javascript";s.charset="utf-8";s.src="xml2json.cgi?url=http%3A%2F%2Fwww.example.com%2Fsample.xml";}varxml={};xml.onload=function(data){// 読み込み後の処理}

XML2JSON のソースコード

分かりやすくするために、複雑なエラー処理がない単純なソースコードを示します。サーバー側で CGI として動作します。

LWP::UserAgent でダウンロードしてXML::Simple で XML 解析して、Data::Dumper でダンプしています。Perl の Dump と JavaScript の JSON 形式が酷似しているため、処理はこれだけです(ダンプデータの=>: に置換するだけ・・・)。

#!/usr/local/bin/perluseCGI;useLWP::UserAgent;useXML::Simple;useData::Dumper;my$q=newCGI;# parammy$var=$q->param('var');$var="xml"if!defined$varor$var!~/^[a-zA-Z_]+$/;my$url=$q->param('url');dieif!defined$urlor$url!~m!^http://!;# requestmy$ua=LWP::UserAgent->new;$ua->agent("XML2JSON/0.1");my$req=HTTP::Request->new(GET=>$url);my$res=$ua->request($req);dieif!$res->is_success;dieif$res->headers->header("Content-Type")!~m!/xml!;# XML Dump$XML::Simple::PREFERRED_PARSER='XML::Parser';my$xmlobj=XMLin($res->content);$Data::Dumper::Indent=1;$Data::Dumper::Useqq="utf8";$json=Dumper($xmlobj);$json=~s/^\$VAR1/$var.data/;$json=~s/([^\\])" => ("|{|\[)/$1" : $2/g;# outputprint$q->header(-type=>"text/plain",-charset=>"utf-8");print"if (typeof($var) == 'undefined')$var = {};\n";print$json."\n";print"if (typeof($var.onload) == 'function')$var.onload($var.data);";

毎回サーバーに取りに行くのは負荷が高いので、こんな風にキャッシュ機能をつけるとよいかもしれません。

#!/usr/local/bin/perluseCGI;useJcode;useLWP::UserAgent;useXML::Simple;useDigest::MD5qw(md5_hex);useData::Dumper;my$cache_dir="../cache/";my$cache_lifetime=600;# 10minmy$q=newCGI;# parammy$var=$q->param('var');$var="xml"if!defined$varor$var!~/^[a-zA-Z_]+$/;my$url=$q->param('url');&error("url is not set")if!defined$urlor$url!~m!^http://!;my$json;my$cache=$cache_dir.md5_hex($url);if(-f$cache&&(stat($cache))[9]+$cache_lifetime>time){open(CACHE,$cache);$json=join("",<CACHE>);close(CACHE);}else{# requestmy$ua=LWP::UserAgent->new;$ua->agent("XML2JSON/0.1");my$req=HTTP::Request->new(GET=>$url);my$res=$ua->request($req);&error("cannot get url")if!$res->is_success;&error("cotnent is not xml (".$res->headers->header("Content-Type").")")if$res->headers->header("Content-Type")!~m!/xml!;# XML Dump$XML::Simple::PREFERRED_PARSER='XML::Parser';my$xmlobj=XMLin($res->content);$Data::Dumper::Indent=1;$Data::Dumper::Useqq="utf8";$json=Dumper($xmlobj);# Write cachemy$cache=$cache_dir.md5_hex($url);if(open(CACHE,">$cache")){printCACHE$json;close(CACHE);}}$json=~s/^\$VAR1/$var.data/;$json=~s/([^\\])" => ("|{|\[)/$1" : $2/g;# outputprint$q->header(-type=>"text/plain",-charset=>"utf-8");print"if (typeof($var) == 'undefined')$var = {};\n";print$json."\n";print"if (typeof($var.onload) == 'function')$var.onload($var.data);";suberror{print$q->header(-type=>"text/plain",-charset=>"utf-8");print"var$var =\"$_[0]\";";exit;}

思うこと

開発者的には RSS を XML で吐き出すのと同時に JSON で吐き出してくれるページが増えてくれたらうれしいなぁ。

ただ、悪意のある JavaScript をインポートしてしまうと、訪問者の Cookie が漏れてしまうので、Cookie で個人情報を管理している場合は注意が必要です。信頼できる会社に XML2JSON なサービスをやってほしいところです。

(追記) Yahoo! Pipes を使えば、外部サイトの内容を JSONP で取得できるようになりました。詳しくはYahoo! Pipes の Page Fetch モジュールでスクレイピングし放題 を見てください。


[8]ページ先頭

©2009-2025 Movatter.jp