JSONP によるクロスドメインの通信: 第 2 回 JSONP、jQuery、Yahoo! Query Language を使ってマッシュアップを作成する

このシリーズの前回の記事では、ブラウザーの同一生成元ポリシーによる制約を回避し、サードパーティーのソースからのデータを組み合わせて表示するための方法として JSONP (JSON with Padding) を紹介しました。今回の記事は前回の続きとして、Yahoo! が提供する JSONP サービスである YQL (Yahoo! Query Language) と jQuery を使用して、マッシュアップによる Web ページを作成する方法について説明します。

Seda Özses, IT Specialist, IBM

Photo of Seda OzsesSeda Özses は ibm.com 全体を統括するウェブマスター・チームのメンバーです。彼女は主に ibm.com 全体としての Web ポータルを担当しており、XSL に関する作業と、彼女のチームに必要なさまざまな要件を管理しています。



Salih Ergül, IT Architect, Independent Consultant

Photo of Salih ErgulSalih Ergül は自営の IT アーキテクトであり、電話業界や銀行業界における大規模でミッション・クリティカルなエンタープライズ・アプリケーション統合プロジェクトを専門としています。彼はこれまで Java プログラミングに関して何本かの記事を書いており、現在は銀行業界で業務を行っています。



2009年 3月 03日

はじめに

このシリーズの第 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 には大量の構造化データがあり、それらのデータをさまざまな 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

この記事で既に触れたように、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 コンソール
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 コンソールを使用するとクエリーに対するレスポンスを表示することができ、レスポンスの正確な構造を判断することができます。

第 1 のウィジェット

リスト 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>

第 2 のウィジェット

第 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 のウィジェット

第 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 項目の説明も表示するようにする。

参考文献

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Web development
ArticleID=379509
ArticleTitle=JSONP によるクロスドメインの通信: 第 2 回 JSONP、jQuery、Yahoo! Query Language を使ってマッシュアップを作成する
publish-date=03032009