このシリーズの第 1 回ではクロスドメインの通信のための効果的な手法として JSONP を紹介しました。JSONP を利用すると、現在のブラウザーによって強制される同一生成元ポリシーの制約を回避することができます。第 1 回では、jQuery がネイティブで JSONP をサポートしていることを利用して、サードパーティーのサービス (いわゆる JSONP サービス) から JSON フォーマットのコンテンツを収集する方法を説明しました。今回の記事では、単一エンドポイントの JSONP サービスとして YQL (Yahoo! Query Language) を紹介します。YQL を利用すると、さまざまなデータ・ソースのデータを照会し、取得したデータをフィルタリングしたり、組み合わせたりすることができます。
また、今回の記事ではマッシュアップ・アプリケーションを jQuery で実装する方法も説明します。このアプリケーションは、株価情報、The New York Times (NYT) の RSS フィード、天気予報のデータを収集し、1 つの Web ページに表示します。
Web には大量の構造化データがあり、それらのデータをさまざまな Web サービスや API を通じて利用することができます。そうしたサービスを利用するためには、それらにアクセスしてクエリーを実行し、その結果を標準化されていない方法で解析する必要があります。それぞれのサービスには、サービスにアクセスするための独自の URL があるとともに、クエリーを実行する方法やクエリーの結果の解釈の仕方を記述したドキュメントがあります。YQL を利用すると、さまざまな URL にある、さまざまなサービスが提供するデータを、統一された方法で照会することができます。YQL によって単一エンドポイントのサービスが提供され、Web 全体にわたってのデータの照会、フィルタリング、組み合わせを行うことができるため、それぞれのサービスに特有の処理をする必要がなくなります。
YQL は基本的に SQL をベースとする問い合わせ言語であり、さまざまなサービスからの構造化データを標準化された方法で照会したり取得したりすることができます。一方で YQL は Yahoo! がホストするクエリー・エンジンでもあり、REST エンドポイントに公開されています。YQL は、テーブルや行に対しておなじみのリレーショナル・データベース・モデルを使用しますが、データは内部で XML として解釈され、構造化されます。照会先のデータ・ソースが XML データを提供しない場合には、YQL がデータを変換します。YQL はレスポンスを XML または JSON で返します (どちらを返すかの指定はサービスを呼び出す際に行います)。さらに、サービスからのデータとして JSON を要求する場合にはコールバック関数を指定することができます。これにより YQL サービスは JSONP サービスとなりますが、これは非常に重要な点です。これによって多くの Web サービスが自動的に JSONP をサポートすることになるからです。
YQL が解釈し、サポートするデータ・ソースには、RSS、Atom、JSON、XML、CSV、HTML、Flickr、Yahoo! ファイナンス、天気情報などがあります。また YQL は外部の (Yahoo! 外の) データ・ソースもサポートしているため、マッシュアップ・アプリケーションの構築に無限の可能性が生まれます。YQL はアプリケーションを Web に接続するための単一のインターフェースと言うことができます。
図 1. 仲介サービスとしての YQL
この記事で既に触れたように、YQL は SQL に似た言語であり、Web にある構造化データを照会することができます。従って YQL 文で中心として使われる動詞は SELECT
です。構文も SQL と非常によく似ています。
SELECT fields FROM source_table WHERE filter .. |
下記のリストは The New York Times の RSS フィードの見出しを取得する簡単なクエリーを示しています。
select title from rss where url="http://www.nytimes.com/services/xml/rss/nyt/HomePage.xml" |
もっと複雑な YQL クエリーの例として、ニューヨークにあるベジタリアン向けのレストランを最大 3 軒に制限して取得する場合には下記のようになります。
select Title, Address, City, Rating.AverageRating from local.search where query="vegetarian" and location="New York, NY" limit 3 |
上記のクエリーを実行すると、リスト 1 のような JSON によるレスポンスが返されます (クエリーに関して返されたメタデータは省略してあります)。
リスト 1. クエリーに対する JSON でのレスポンス
"results": { "Result": [ { "Title": "World of Vegetarian Incorporated", "Address": "24 Pell St", "City": "New York", "Rating": { "AverageRating": "5" } }, { "Title": "Counter", "Address": "105 1st Ave", "City": "New York", "Rating": { "AverageRating": "4" } }, { "Title": "Red Bamboo", "Address": "140 W 4th St", "City": "New York", "Rating": { "AverageRating": "4.5" } } ] } |
さらには YQL を使って下記のように Web にクエリーを実行することもできます。
select title,abstract,url from search.web where query="Bart Simpson" |
YQL を学び、理解を深めるための早道は YQL コンソールを使うことです。YQL コンソールは Yahoo! のサイト (http://developer.yahoo.com/yql/console/) に提供されています (図 2 のスクリーン・キャプチャーを参照)。
この記事の中にある YQL 文をコピーして YQL コンソールに貼り付けると、その YQL 文に対する JSONP レスポンスを調べることができます (XML フォーマットではなく JSON フォーマットで出力を得るためのラジオ・ボタンにチェックを入れることを忘れないでください)。
図 2. YQL コンソール
jQuery を使って YQL サービスにクエリーを実行する
典型的な YQL GET
リクエストは下記のようなものです。
http://query.yahooapis.com/v1/public?q=[command]&[query parameter] |
ここで command
は YQL コマンドであり、query parameter
は YQL サービスに対するオプション・パラメーターを表します。ここでは YQL が JSONP をサポートしていることに関心があるため、リクエストには必ず 2 つのオプション・パラメーターを含め、YQL サービスから JSONP レスポンスを取得する必要があります。そこでリクエストには下記のようなフォーマットを使います。
http://query.yahooapis.com/v1/public?q=[command]&format=json&callback=? |
ここで format
はレスポンス・フォーマットとして何を要求するのかを指定するリクエスト・パラメーターであり、callback
は Web アプリケーションの中にあるコールバック関数の名前です (この場合には jQuery によって関数名が提供されます)。ここではコールバック関数の名前として実際の関数名ではなく ?
を使用していることに注目してください。こうすることで、関数を生成するように jQuery に命令しています。
YQL サービスへの呼び出しを jQuery で行うための典型的なコードはリスト 2 のようなコードになります。
リスト 2. jQuery で YQL を呼び出す場合の典型的な例
jQuery.getJSON(yqlUrl, function(data) { // data is the JSON response // process the response here }); |
YQL に対してクエリーを実行する方法と YQL から JSONP レスポンスを取得する方法を理解できたので、マッシュアップによる Web ページの作成を開始することができます。ここでは 3 つのウィジェットを持つ Web ページを作成します。それぞれのウィジェットは Web のさまざまな場所からコンテンツを取得しますが、コンテンツを取得する際には YQL という統一された同じサービスを使用します。
第 1 のウィジェットは株価用のウィジェットであり、IBM®、Yahoo!、Google、Microsoft® の最新の株価を照会して取得します。このクエリーのためのデータ・ソースは Yahoo! Finance の CSV ファイルです。リスト 3 は第 1 のウィジェットの YQL を示しています。
リスト 3. 第 1 のウィジェット (株価用) の YQL
select symbol, price from csv where url='http://download.finance.yahoo.com/d/quotes.csv? s=IBM,YHOO,GOOG,MSFT&f=sl1d1t1c1ohgv&e=.csv' and columns='symbol,price,date,time,change,col1,high,low,col2' |
第 2 のウィジェットは The New York Times の RSS フィードの見出しを表示します。このウィジェットは YQL を使ってリスト 4 のようにデータを取得します。
リスト 4. 第 2 のウィジェット (RSS フィード用) の YQL コード
select title, link from rss where url="http://www.nytimes.com/services/xml/rss/nyt/HomePage.xml" |
第 3 の、そして最後のウィジェット (リスト 5) は、天気予報のウィジェットです。このウィジェットは郵便番号が 10504 の場所 (ニューヨーク州 Armonk) の予報を表示します。
リスト 5. 第 3 の、そして最後のウィジェット (天気予報用)
select * from weather.forecast where location=10504 |
各ウィジェットはリスト 6 に示すスケルトン・コードを Web ページの中に持っています。
リスト 6. 各ウィジェットのスケルトン・コード
<div class="widget"> <div class="widget-head">[WIDGET HEADER]</div> <div class="widget-content" id="[CONTENT ID]">[WIDGET CONTENT]</div> </div> |
各ウィジェットは widget
というクラス型の div
要素であり、ヘッダー (widget-head
) とコンテンツ・エリア (widget-content
) を持っています。ウィジェットのコンテンツ・エリアには JavaScript コードによってデータが追加されます (JavaScript コードは JSONP データを取得してウィジェットのコンテンツ・セクションに追加します)。
マッシュアップによる Web ページを作成するためには、まず 3 つのウィジェットのためのプレースホルダーを定義します (株価用、NYT ニュース用、そして天気予報用)。これをリスト 7 に示します。
リスト 7. ウィジェット用のプレースホルダー
<div class="widget"> <div class="widget-head">Lastest stock quotes</div> <div class="widget-content" id="quotes"></div> </div> <div class="widget"> <div class="widget-head">NYT news headlines</div> <div class="widget-content" id="headlines"></div> </div> <div class="widget"> <div class="widget-head">Weather for Armonk NY</div> <div class="widget-content" id="weather"> </div> </div> |
コンテンツ・エリアが空のままであることに注目してください。こうする理由は、JSONP を使ってコンテンツ・エリアに動的にデータを追加しようとしているからです。このすぐ後に説明しますが、jQuery を利用すると非常に容易にオン・ザ・フライで HTML フラグメントを生成することができます。各ウィジェットのコンテンツ・エリアには、リスト 8 のスケルトン・コードによってデータが追加されます。
リスト 8. jQuery のスケルトン・コード
$.getJSON(yqlUrl, function(data){ // loop through the items $.each(data.query.results.[ITEM NAME], function(index, item){ // process each item here // generate HTML to append to the widget's content area }); }); |
リスト 8 のコードは yqlUrl
に対して GET
リクエストを発行し、JSONP レスポンスを取得します (必ず yqlUrl を提供する必要があります)。JSONP レスポンス (ここでは data
という名前です) が受信されると、クエリー結果の項目群に対してループ操作を行い、項目を 1 つずつ処理することができます。[ITEM NAME]
は項目の配列に対するプレースホルダーであり、この名前の付け方はデータ・ソースに応じて変更する必要があるかもしれません。先ほど説明した YQL コンソールを使用するとクエリーに対するレスポンスを表示することができ、レスポンスの正確な構造を判断することができます。
リスト 9 は第 1 の jQuery のフラグメントを示しています (株価用のウィジェットのコンテンツにデータを追加します)。
リスト 9. 第 1 のウィジェットの JavaScript コード
var yqlUrl1= "http://query.yahooapis.com/v1/public/yql?q= select%20symbol%2C%20price%20from%20csv%20 where%20url%3D'http%3A%2F%2Fdownload.finance.yahoo.com%2Fd%2Fquotes.csv%3F s%3DIBM%2CYHOO%2CGOOG%2CMSFT%26f%3Dsl1d1t1c1ohgv%26e%3D.csv'%20and%20 columns%3D'symbol%2Cprice%2Cdate%2Ctime%2Cchange%2Ccol1%2Chigh%2Clow%2Ccol2' &format=json&callback=?"; $.getJSON(yqlUrl1, function(data){ $.each(data.query.results.row, function(index, item){ $('#quotes') .append( $('<p/>') .append($('<span class="left"/>').text(item.symbol)) .append($('<span class="right"/>').text('$'+item.price)) ); }); }); |
第 1 のウィジェットに対する適切にエスケープされた URL はどのようにして得られたのでしょう。YQL コンソールを見てみると、画面の右上の隅に「The Rest query」というタイトルのセクションがあります。YQL 文のテストに成功したら、そのセクションからクエリー・ストリングをコピーし、それを getJSON()
関数の第 1 のパラメーターとして使う必要があります。
株価用のウィジェットは各項目をループし、2 つの span
要素を含む p
要素を #quotes
という ID の div
要素に追加します。すると、コンテンツ・エリア用の HTML コードはリスト 10 のようなものになります。
リスト 10. 第 1 のウィジェット用の HTML コード
<div id="quotes" class="widget-content"> <p> <span class="left">"IBM"</span> <span class="right">$91.51</span> </p> <p> <span class="left">"YHOO"</span> <span class="right">$12.22</span> </p> <p> <span class="left">"GOOG"</span> <span class="right">$353.11</span> </p> <p> <span class="left">"MSFT"</span> <span class="right">$18.12</span> </p> </div> |
第 1 のウィジェットが作成できたら、第 2 のウィジェットに進みます。
リスト 11. 第 2 のウィジェットの JavaScript コード
var yqlUrl2= "http://query.yahooapis.com/v1/public/yql?q= select%20title%2C%20link%20from%20rss%20 where%20url%3D%22http%3A%2F%2Fwww.nytimes.com%2Fservices%2Fxml%2Frss%2Fnyt%2F HomePage.xml%22&format=json&callback=?"; $.getJSON(yqlUrl2, function(data){ $.each(data.query.results.item, function(index, item){ $("<a href='" + item.link + "' target="_blank\"/>") .html(item.title) .appendTo($('#headlines')) .wrap('<p/>'); }); }); |
リスト 11 のコードは最初に The New York Times の RSS フィードの title
要素と link
要素を取得します。次に、メインの記事へのリンクを含む p
要素を、このウィジェットのコンテンツ・エリアに追加します。すると、コンテンツ・エリア用の HTML コードはリスト 12 のようなものになります。
リスト 12. 第 2 のウィジェットの HTML コード
<div id="headlines" class="widget-content"> <p> <a target="_blank" href="http://www.nytimes.com/2009/02/19/business/19housing.html ?partner=rss&emc=rss">Obama Unveils $75 Billion Plan to Fight Home Foreclosures</a> </p> <p> <a target="_blank" href="http://www.nytimes.com/2009/02/19/business/economy/19fed.html ?partner=rss&emc=rss">Fed Offers Bleak Economic Outlook</a> </p> ... </div> |
第 3 のウィジェットの動作は上記の 2 つのウィジェットの動作と非常によく似ています。しかし第 3 のウィジェットの場合には item.description
をコンテンツ・エリアに直接追加します。コンテンツ・エリアには HTML フォーマットのデータが既に含まれているからです。
リスト 13. 第 3 のウィジェットの JavaScript コード
var yqlUrl3= "http://query.yahooapis.com/v1/public/yql?q= select%20*%20from%20weather.forecast%20where%20location%3D10504& format=json&callback=?"; $.getJSON(yqlUrl3, function(data){ $.each(data.query.results.channel, function(index, item){ $('#weather') .append($('<p/>').html(item.description)); }); }); |
完全なものにするために、リスト 14 ではすべてのものを 1 ヶ所にまとめています (ただしウィジェットのスタイリングに使用した CSS は除いています)。
リスト 14. サンプルのマッシュアップ・ページの HTML コード
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <script type="text/javascript" src="jquery-1.3.1.min.js"/> <style type="text/css"> ... </style> <title>JSONP Mashup</title> </head> <body> <div class="widget"> <div class="widget-head">Latest stock quotes</div> <div class="widget-content" id="quotes"/> </div> <div class="widget"> <div class="widget-head">NYT news headlines</div> <div class="widget-content" id="headlines"/> </div> <div class="widget"> <div class="widget-head">Weather for Armonk, NY</div> <div class="widget-content" id="weather"> </div> </div> <script type="text/javascript"> var yqlUrl1="http://query.yahooapis.com/v1/public/yql?q= select%20symbol%2C%20price%20from%20csv%20 where%20url%3D'http%3A%2F%2Fdownload.finance.yahoo.com%2Fd%2Fquotes.csv%3F s%3DIBM%2CYHOO%2CGOOG%2CMSFT%26f%3Dsl1d1t1c1ohgv%26e%3D.csv'%20and%20 columns%3D'symbol%2Cprice%2Cdate%2Ctime%2Cchange%2Ccol1%2Chigh%2Clow%2Ccol2' &format=json&callback=?"; $.getJSON(yqlUrl1, function(data){ $.each(data.query.results.row, function(index, item){ $('#quotes') .append( $('<p/>') .append($('<span class="left"/>').text(item.symbol)) .append($('<span class="right"/>').text('$'+item.price)) ); }); }); var yqlUrl2="http://query.yahooapis.com/v1/public/yql?q= select%20title%2C%20link%20from%20rss%20 where%20url%3D%22http%3A%2F%2Fwww.nytimes.com%2Fservices%2Fxml%2Frss%2Fnyt%2F HomePage.xml%22&format=json&callback=?"; $.getJSON(yqlUrl2, function(data){ $.each(data.query.results.item, function(index, item){ $("<a href='" + item.link + "' target="_blank\"/>") .html(item.title) .appendTo($('#headlines')) .wrap('<p/>'); }); }); var yqlUrl3= "http://query.yahooapis.com/v1/public/yql?q= select%20*%20from%20weather.forecast%20where%20location%3D10504& format=json&callback=?"; $.getJSON(yqlUrl3, function(data){ $.each(data.query.results.channel, function(index, item){ $('#weather') .append($('<p/>').html(item.description)); }); }); </script> </body> </html> |
図 3 は、この記事の執筆時点での完成した Web ページのスクリーンショットを示しています。
図 3. サンプルのマッシュアップ・ページ
YQL はサーバー・サイドのプロキシーを使わずにクライアント・サイドでマッシュアップを実現できる強力なサービスです。YQL は JSONP をサポートしているため、jQuery と組み合わせることによって、YQL による 1 つの統一されたインターフェースをとおして Web 全体の構造データにアクセスすることができます。この記事では、jQuery と YQL を使うことによって、ほんの数行のコードでマッシュアップによる Web ページを作成する方法を学びました。この記事で紹介した内容を出発点としてコードを改善すれば、より洗練された Web ページにすることができます。そのためのヒントをいくつか挙げておきます。
- ウィジェットのヘッダーに画像へのリンクを配置し、クリックされるとコンテンツ・エリアが更新されるようにする。
- 入力フィールドを用意し、ユーザーが株式コードを入力するとその株式コードの株価のみを取得するようにする。
- RSS 項目の表題とリンクのみではなく、RSS 項目の説明も表示するようにする。
- JSONP を紹介する、この記事シリーズの第 1 回、「JSONP によるクロスドメイン通信: 第 1 回 JSONP と jQuery を組み合わせ、強力なマッシュアップを迅速に作成する」を読んでください。
- Yahoo! Query Language について、その発明者たちによる説明を読んでください。
- YQL コンソールを試しながら YQL について学び、また YQL の使い方を練習してください。
- 「jQuery を扱う: 第 1 回 ブラウザーでデスクトップ・アプリケーションを実現する」(developerWorks、2008年9月) をはじめとする 3 回シリーズの記事を読んで、jQuery について学んでください。