YQL と PHP を使用して Web アプリケーションを構築する: 第 1 回

PHP と YQL を使用して複数の Web サービスからデータを取得し、結合する

複数のサード・パーティー Web サービスに対する共通のインターフェースとなる YQL (Yahoo! Query Language) では、単純で SQL ライクな構文を使ってデータを検索、追加、更新、削除できるようになっています。この YQL に PHP の強力な XML 処理ツールを組み合わせれば、さまざまなオンライン・サービスのデータを簡単かつ効率的に Web サービスに追加することができます。しかも、それぞれのサービスの API ドキュメントをくまなく調べる必要もありません。

Vikram Vaswani, Founder, Melonfire

Photo of Vikram VaswaniVikram Vaswani は、オープンソースのツールと技術を専門とするコンサルティング・サービス会社、Melonfire の創業者で、現在 CEO を務めています。彼は、『Zend Framework: A Beginners Guide』および『PHP: A Beginners Guide』の著者でもあります。



2010年 11月 30日 (初版 2010年 11月 16日)

2010年 11月 30日 - 連載第 1 回の「はじめに」および「まとめ」セクションにリンクを追加しました。また「参考文献」セクションの「学ぶために」に連載第 2 回の記事の項目を追加しました。

はじめに

最近の人気の高い Web サイトには必ずと言ってよいほど、開発者用の API があります。そのため、Web アプリケーションのプログラマーは REST や SOAP などの標準フレームワークを使ってサイトのデータにアクセスしたり、操作したりできるようになっています。その一例は、Google バズ、Google ドキュメント、Google カレンダーなどの Google サービスにアクセスできるように Google で用意している Google Data API です。また、Twitter にもユーザーがツイートを検索、投稿するために使用できる REST API があり、Facebook では Graph API を使ってユーザーのプロフィールと接続を管理することができます。

よく使われる頭文字語

  • API: Application Program Interface
  • DOM: Document Object Model
  • ECS: E-Commerce Service
  • HTML: HyperText Markup Language
  • ISBN: International Standard Book Number
  • JSON: JavaScript Object Notation
  • RDBMS: Relational Database Management System
  • REST: REpresentational State Transfer
  • RSS: Really Simple Syndication
  • SOAP: Simple Object Access Protocol
  • SQL: Structured Query Language
  • URL: Uniform Resource Locator
  • XML: Extensible Markup Language

これらの API が開発者の人生に刺激を与え、新しい独創的なアプリケーションを生み出す可能性を広げることは確かですが、そこにはいくつかの問題もあります。そのうち、実装に関して大きな問題となるのは、サイトの間で API の統一がとれていないことです。REST を使用するサイトもあれば、SOAP を使用するサイトもあります。一部のサイトでは、レスポンス・データを Atom でエンコードする一方、他のサイトでは RSS を使っていたり、さらに別のサイトでは XML や JSON を使用したりしています。その結果、新しい Web サービスをアプリケーションに統合することに決めるたびに、まずは大量の資料を読み、次にかなりのテストを行ってサービス API の構造を完全に把握してからでないと、統合に取り掛かることができません。

まさにこの問題を解決するために Yahoo! の開発者たちが考案することに決めたのが、Yahoo! Query Language です。頭文字の YQL でお馴染みのこの言語は、さまざまな Web サービス API に対して統一された SQL ライクなインターフェースを提供することによって、サード・パーティーのデータを Web アプリケーションに統合する際のタスクを大幅に単純化します。この 2 回の連載では YQL を紹介し、YQLを私のお気に入りの言語、PHP と一緒に使用して高度な Web アプリケーションを構築する方法を説明します。


YQL の概要

SQL を使い慣れていれば、YQL にはすぐに親近感を覚えることでしょう。簡単に言うと、YQL は個々の Web サービスをあたかもデータ・テーブルであるかのように扱うことで、開発者がデータベースのテーブルから情報を抽出するかのように、SQL ライクなクエリーを作成して Web サービスから情報を抽出できるようにします。YQL サービスは、このようなクエリー・ストリングを構文解析して、リモート・サービスでクエリーを実行し、結果を標準的な XML または JSON フォーマットで返します。クエリー・ストリング自体は、REST を使用する YQL サービスに GET リクエストとして渡されます。

この手法をよりよく理解するための単純な例として、Twitter で “master chief” という言葉が含まれるすべての投稿を検索するとします。YQL を使用しない場合、Twitter Search API を使って検索するために、通常は以下のようなリクエストを作成することになります。

http://search.twitter.com/search.atom?q=master%20chief&lang=en

このリクエストに対し、Twitter Search API は図 1 のような Atom フィードによる結果を返します。

図 1. Twitter Search API から返された検索結果の Atom フィード
Twitter Search API から返された、”master chief” の検索結果の Atom フィードを示す画面のスクリーン・キャプチャー

一方、YQL では、以下のように YQL クエリーを使って Twitter データ・テーブルにアクセスすることで簡単に情報を抽出します。

SELECT * FROM twitter.search WHERE q='master chief'

上記のクエリーは標準的な SQL クエリーとほとんど同じであることに注目してください。SELECT キーワードは、これがデータを取得する操作であることを示します。そして FROM キーワードがデータ・ソースを指定し、WHERE 節がフィルターを指定します。このクエリーを実行依頼すると、YQL はそれに対する Twitter からの結果を標準的な XML または JSON 文書で返します。図 2 に、その一例を示します。

図 2. Twitter データ・テーブルに対して実行した YQL クエリーの実行結果
Twitter データ・テーブルに対して YQL クエリーを実行した結果として返される XML を示す画面のスクリーン・キャプチャー

数日後、この Web アプリケーションにさらにデータを追加することにしたとします。具体的には、Twitter の検索結果に伴うジオコード情報を使用して、それぞれの投稿が送信された地域の地図を表示します。さらに、検索語「master chief」に関するニュースのヘッドラインの一覧も Twitter 検索結果と併せて表示します。

YQL を使用しないでこのタスクを実現するとなると、まずは Yahoo! 地図と Google ニュースの API ドキュメントを読む作業にある程度の時間を費やすことになるでしょう。一方、YQL では以下の 2 つのクエリーを追加するだけで、簡単にこのタスクを実現することができます。

SELECT * FROM google.news WHERE q="master chief"

SELECT * FROM maps.map WHERE latitude="XX" AND longitude="YY"

図 3図 4 に、クエリーに対する結果のスナップショットを示します。

図 3. Google ニュース・データ・テーブルに対する YQL クエリーの実行結果
Google ニュース・データ・テーブルに対する YQL クエリーの実行結果を示す画面のスクリーン・キャプチャー
図 4. Yahoo マップ・データ・テーブルに対する YQL クエリーの実行結果
Yahoo マップ・データ・テーブルに対する YQL クエリーの実行結果を示す画面のスクリーン・キャプチャー

図 3図 4 のクエリーの結果から明らかなように、YQL の最大のメリットは、サード・パーティーの Web サービスに対する統一したインターフェースを提供するところにあります。一般に理解されている SQL の構文を使用してサード・パーティーのサービスをクエリーできる YQL では、時間と手間が省かれ、さまざまに異なるソースからのデータを簡単に Web アプリケーションに統合することができます。さらに、出力フォーマットとして XML または JSON のいずれかを選択できるため、結果のデータにアクセスして操作する方法にある程度の柔軟性がもたらされ、サーバー・サイドのプログラミング (例えば PHP や Perl など) を使用することも、クライアント・サイドのツール (例えば jQuery や mooTools など) を使用することもできて便利です。


YQL Console の使用

YQL を使い始めるには、YQL Console を利用するのが最も簡単です。このインタラクティブなオンライン・ツールでは、YQL クエリーをオンザフライで作成してテストすることができます。YQL Console は Yahoo! Developer Network 上にホストされており、診断ツール、サンプル・クエリー、使用可能なテーブルのリストなどが付属しています。

YQL Console がどのような動作をするか確かめるには、YQL Console にアクセスして、以下のクエリーを入力してください。このクエリーは、現在人気のある音楽アルバムのリストを取得するためのものです。

SELECT * FROM music.release.popular

フォームを送信すると、クエリー・ストリングは URL エンコードされたクエリー・ストリングとして YQL サービスに送信されます。クエリー・ストリングを受け取った YQL サービスはテーブルの定義を調べ、クエリーを実行して、その結果を返します。YQL Console には図 5 のような出力が表示されます。

図 5. YQL 対話型コンソールに表示されるクエリー出力
YQL 対話型コンソールに表示されるクエリー出力を示す画面のスクリーン・キャプチャー

YQL を PHP で使用する方法

図 5 に示されているように、YQL は XML または JSON のいずれかを使ってデータを返すことができますが、通常、PHP Web アプリケーションを構築する場合には XML のほうが重宝します。PHP には XML を処理するための組み込み拡張機能 (SimpleXML、DOM、または XMLReader) が付属しているため、XML 文書であれば、結果を簡単に構文解析することができるからです。この点を念頭に置いて、リスト 1 では上記と同じクエリーを、今度は PHP と SimpleXML を使用して実行してみます。

リスト 1. SimpleXML による YQL クエリーの実行結果の処理
<?php
// execute query
// get list of 15 most popular music releases
// retrieve result as SimpleXML object
$xml = simplexml_load_file('
  http://query.yahooapis.com/v1/public/yql?q=
  SELECT * FROM music.release.popular
');

// iterate over query result set
echo '<h2>Popular Music</h2>';
$results = $xml->results;
foreach ($results->Release as $r) {
  echo '<p>';
  echo '<a href="' . $r['url'] . '">' . $r['title'] . 
    '</a> (' . $r['releaseYear'] . ') - ';  
  echo '<a href="' . $r->Artist['url'] . '">' . $r->Artist['name'] . 
    '</a> <br/>'; 
  echo 'Current chart position: ' . $r->ItemInfo->ChartPosition['this'] . 
    ' / Last chart position: ' . $r->ItemInfo->ChartPosition['last']; 
  echo '</p>';
}  
?>

リスト 1 ではまず、YQL Web サービスに対するクエリーを作成し、URL エンコードされたクエリー・ストリングを渡しています。このクエリー・ストリングは前の例で使用したものと同じですが、今回は simplexml_load_file() 関数でリクエストを実行しているため、結果の XML 文書は自動的に構文解析されて SimpleXML オブジェクトに変換されることになります。そしてスクリプトの残りの部分で、XML 文書の <results> ノードを繰り返し処理し、各アルバムのタイトル、リンク、アーティスト、現在のチャートでの順位を出力します。

図 6 に、このコードの結果を示します。

図 6. YQL クエリーによって取得した、人気の高い音楽アルバムのリスト
YQL クエリーによって取得した、人気の高い音楽アルバムのリストを示す画面のスクリーン・キャプチャー

Zend Framework を使用する場合には、代わりに Zend_Rest_Client コンポーネントを使って YQL Web サービスにアクセスすることができます。その場合のコードをリスト 2 に記載します。このコードでも、リスト 1 と同じ出力が生成されます。

リスト 2. Zend Framework による YQL クエリーの実行結果の処理
<?php
// set up Zend auto-loader
// load Zend REST client classes
require_once 'Zend/Loader.php';
Zend_Loader::loadClass('Zend_Rest_Client');

// execute YQL query
// get list of most popular music releases
try {
  $client = new Zend_Rest_Client('http://query.yahooapis.com/v1/public/yql');
  $client->q('SELECT * FROM music.release.popular');
  $result = $client->get();
} catch (Zend_Rest_Client_Exception $e) {
    echo "Client error: " . $e->getResponse();
} catch (Exception $e) {
    echo "Error: " . $e->getMessage();
}

// iterate over query result set
echo '<h2>Popular Music</h2>';
foreach ($result->Release as $r) {
  echo '<p>';
  echo '<a href="' . $r['url'] . '">' . $r['title'] . 
    '</a> (' . $r['releaseYear'] . ') - ';  
  echo '<a href="' . $r->Artist['url'] . '">' . $r->Artist['name'] . 
    '</a> <br/>'; 
  echo 'Current chart position: ' . $r->ItemInfo->ChartPosition['this'] . 
    ' / Last chart position: ' . $r->ItemInfo->ChartPosition['last']; 
  echo '</p>';
} 
?>

Zend Framework の Zend_Rest_Client コンポーネントは、PHP アプリケーションと REST ベースの Web サービスの統合に取り組む開発者のために設計されています。このクライアントを使用することで、REST サービス・エンドポイントに GET、POST、PUT、および DELETE レスポンスを返すことができます。REST レスポンスは Zend_Rest_Client_Response オブジェクトのインスタンスとして返されるため、個々のレスポンス・プロパティーに容易にアクセスすることができます。

リスト 2 では、まず Zend クラス・ライブラリーをロードし、それから Zend_Rest_Client クラスのインスタンスを初期化しています。このクライアントを使用して、リスト 1 で行ったように YQL Web サービス・エンドポイントへの非認証 GET リクエストを初期化します。リクエストに対して返された XML ファイルは構文解析されて、Zend_Rest_Client_Response オブジェクトに変換されます。その後は、オブジェクトを標準的な foreach() ループで処理することができます。Zend_Rest_Client オブジェクトを使用する場合、YQL クエリーを URL エンコードする必要はありません。このステップは、コンポーネントが内部で処理してくれます。


フィルタリングやソートを行うクエリーの実行結果

通常の SELECT クエリーと同じく、YQL では WHERE 節を使って結果をフィルタリングするクエリーを実行することも、必須フィールドを指定してクエリーを実行することも、1 つ以上のフィールドを基準に結果をソートするクエリーを実行することもできます。その一例として、以下のクエリーを見てください。これは Flickr API に対するクエリーで、検索語 “england” と一致する場所の一覧を取得するためのものです。

SELECT * FROM flickr.places WHERE query="england"

このクエリーに対する YQL のレスポンスは図 7 のようになります。

図 7. YQL クエリーによって Flickr から取得した “england” の検索結果のリスト
YQL クエリーによって Flickr から取得した “england” の検索結果のリストを示す画面のスクリーン・キャプチャー

リスト 3 に、このクエリーを実際に使用する方法を示します。

リスト 3. WHERE 節によってフィルタリングを行う YQL クエリーの実行結果
<?php
// set up Zend auto-loader
// load Zend REST client classes
require_once 'Zend/Loader.php';
Zend_Loader::loadClass('Zend_Rest_Client');

// execute YQL query
// get list of Flickr places matching search term
try {
  $client = new Zend_Rest_Client('http://query.yahooapis.com/v1/public/yql');
  $client->q('SELECT * FROM flickr.places WHERE query="england"');
  $result = $client->get();
} catch (Zend_Rest_Client_Exception $e) {
    echo "Client error: " . $e->getResponse();
} catch (Exception $e) {
    echo "Error: " . $e->getMessage();
}

// iterate over query result set
echo '<h2>Search Results</h2>';
echo '<table border=1>';
echo '<tr><th>Name</th><th>Latitude</th><th>
Longitude</th></tr>';
foreach ($result->place as $p) {
  echo '<tr>';
  echo '<td>' . $p . '</td>';  
  echo '<td>' . $p['latitude'] . '</td>';  
  echo '<td>' . $p['longitude'] . '</td>';  
  echo '</tr>';
}  
echo '</table>';
?>

図 8 に、リスト 3 を実行して得られる出力を整形した結果を表示します。

図 8. YQL クエリーによって Flickr から取得した “england” の検索結果を整形したリスト
YQL クエリーによって Flickr から取得した “england” の検索結果を整形したリストを示す画面のスクリーン・キャプチャー

フィルター基準は、AND 演算子と OR 演算子を使用することで、さらに追加することができます。以下は、上記のクエリーに変更を加え、timezone を基準に結果を絞り込む例です。

SELECT * FROM flickr.places WHERE query="england" AND timezone LIKE "%europe%"

クエリーの出力は、特定のフィールドに絞り込むことができます。この手法は、Web サービスから返されるデータのうちの一部だけが必要な場合に役立つだけでなく、レスポンス・パケットのサイズを縮小することにもなります。以下は上記の例を変更し、各レコードの緯度、経度、名前だけを取得する場合のクエリーです。

SELECT latitude, longitude, content FROM flickr.places WHERE query="england"

YQL は、結果セットのソート、カウント、重複の排除に使用できる各種のユーティリティー関数もサポートします。一般に、これらの関数はYQL クエリー・ストリングの後にパイプ (|) 文字で区切って配置します。以下のクエリーは、緯度を基準に結果をソートする例です。

SELECT latitude, longitude, content FROM flickr.places 
  WHERE query="england" | sort (field="latitude")

また以下のように unique フィルターを適用してチェック対象とするフィールドを指定することで、フィールドの値が同じになる行を 1 つだけしか結果に含めないようにすることもできます。

SELECT * FROM flickr.places 
  WHERE query="england" | unique (field="timezone")

リスト 4 に以上の例を 1 つにまとめ、ユーザーに地名を入力するように求めて、ソート可能な結果リストを返すインタラクティブなクエリー・ツールを組み立てます。

リスト 4. 地名の検索
<html>
  <head></head>
  <body>  
    <form method="post" action="<?php echo htmlentities
    ($_SERVER['PHP_SELF']); ?>">
    Search term:
    <input type="text" name="q" />
    Sort results by:
    <select name="s">
      <option value="timezone">Time zone</option>
      <option value="latitude">Latitude</option>
      <option value="longitude">Longitude</option>
    </select>
    <input type="submit" name="submit" value="Search" />    
    </form>
    <?php
    // check if form is submitted
    // perform necessary validation (omitted for brevity)
    if (isset($_POST['submit'])) {
      // set up Zend auto-loader
      // load Zend REST client classes
      require_once 'Zend/Loader.php';
      Zend_Loader::loadClass('Zend_Rest_Client');
      
      // execute YQL query
      // get list of Flickr places matching search term
      // sort by requested field
      try {
        $client = new Zend_Rest_Client('http://query.yahooapis.com/v1/public/yql');
        $client->q(
          'SELECT latitude, longitude, timezone, content FROM flickr.places 
            WHERE query="' . $_POST['q'] .'" | sort(field="' . $_POST['s'] . '")');
        $result = $client->get();
      } catch (Zend_Rest_Client_Exception $e) {
          echo "Client error: " . $e->getResponse();
      } catch (Exception $e) {
          echo "Error: " . $e->getMessage();
      }
      
      // iterate over query result set
      echo '<h2>Search Results</h2>';
      echo '<table border=1>';
      echo '<tr><th>Name</th><th>Timezone</th>
        <th>Latitude</th><th>Longitude</th></tr>';
      foreach ($result->place as $p) {
        echo '<tr>';
        echo '<td>' . $p . '</td>';  
        echo '<td>' . $p['timezone'] . '</td>';  
        echo '<td>' . $p['latitude'] . '</td>';  
        echo '<td>' . $p['longitude'] . '</td>';  
        echo '</tr>';
      } 
      echo '</table>';
    }
    ?>
  </body>
</html>

図 9 に、リスト 4 の動作を示します。

図 9. 地名のインタラクティブな検索とソート・フィルター
リスト 4 のコードに基づく地名のインタラクティブな検索とソート・フィルターを示す画面のスクリーン・キャプチャー

使用できるすべての YQL 関数については、「YQL Guide」(「参考文献」にリンクを記載) を調べてください。


サンプル・アプリケーション: 地域ごとの気象情報

これまで学んだ内容を基に、PHP を使用して単純な YQL アプリケーションを作成してみましょう。リスト 5 では、ユーザーに対して今いる場所をフォームに入力するよう求め、weather.bylocation テーブルを介して Yahoo! 天気情報に接続して、入力された地域の気象情報を問い合わせるクエリーを実行します。リスト 5 のコードを見てください。

リスト 5. 地域を指定することによる気象情報の取得
<html>
  <head></head>
  <body>  
    <form method="post" action="<?php echo htmlentities
    ($_SERVER['PHP_SELF']); ?>">
    Enter city name:
    <input type="text" name="city" />
    <input type="submit" name="submit" value="Get forecast" />    
    </form>
    <?php
    // check if form is submitted
    // perform necessary validation (omitted for brevity)
    if (isset($_POST['submit'])) {
      // set up Zend auto-loader
      // load Zend REST client classes
      require_once 'Zend/Loader.php';
      Zend_Loader::loadClass('Zend_Rest_Client');

      // execute YQL query
      // get Yahoo! Weather forecast for selected zip code
      try {
        $client = new Zend_Rest_Client('http://query.yahooapis.com/v1/public/yql');
        $client->env('store://datatables.org/alltableswithkeys');  
        $client->q('SELECT * FROM weather.bylocation 
          WHERE location="' . $_POST['city'] . '"');
        $result = $client->get();
      } catch (Zend_Rest_Client_Exception $e) {
          echo "Client error: " . $e->getResponse();
      } catch (Exception $e) {
          echo "Error: " . $e->getMessage();
      }

      // process and print query results
      $data = $result->results->weather->rss->channel->item;
      echo '<h2>' . $data->title . '</h2>';
      echo $data->pubDate . '<br/>';      
      echo $data->description;
    }
    ?>
  </body>
</html>

都市名を入力した Web フォームが送信された後、リスト 5 は Zend_Rest_Client コンポーネントを使用して YQL クエリーを天気情報サービスに送信します。このクエリーは WHERE 節を使って weather.bylocation テーブルの内容をフィルタリングし、指定された郵便番号に対応する気象情報を取得します。クエリーの結果は整形されて、HTML ページとして表示されます。その結果は、図 10 のとおりです。

図 10. YQL クエリーによって取得した、都市の気象情報
YQL クエリーによって取得した、都市の気象情報を示す画面のスクリーン・キャプチャー。インド・ムンバイの 2010年 7月 23日の気象情報が示されています。

リスト 5 ではクエリー・ストリングに新しい変数、env を追加している点に注目してください。この変数が必要となる理由は、weather.bylocation データ・テーブルはいわゆるコミュニティー・テーブルだからです。つまり、このテーブルを維持しているのは Yahoo! 自体ではなく、コミュニティーであるため、YQL サービスはこのテーブルのテーブル定義ファイルがどこにあるのかを自動的に判断することができません。そのため、env 変数を使用してテーブル定義ファイルの場所を指定しなければならないというわけです。この例でその場所に該当するのは、Community Open Data Tables for YQL Web サイトです。このサイトは、すべての YQL コミュニティー・テーブルのリポジトリーとして機能します (リンクについては、「参考文献」を参照)。


ネストされた YQL クエリーの使用

従来の RDBMS は、個々のテーブルを結合し、これらのテーブルに含まれるデータのさまざまなビューを作成できるところにその最大の価値があります。これと同じことを Web サービスで可能にするところが、YQL の最も優れた機能の 1 つです。YQL クエリーを使用すれば、複数の Web サービスからのデータを結合して、サード・パーティーのデータを新しい有用なビューで表示することができます。

この機能には想像し得る限りのあらゆるアプリケーションが考えられますが、その威力を明らかにするには、単純な例が役立ちます。リスト 6 の例では、ユーザーに国名を入力するよう促した後、イベント情報を提供する Web サービスに対してクエリーを実行して、その国で近日中に予定されているイベントのリストを表示します。

リスト 6. 国ごとのイベントの検索
<html>
  <head></head>
  <body>  
    <form method="post" 
      action="<?php echo htmlentities($_SERVER['PHP_SELF']); ?>">
    Search for events in:
    <input type="text" name="country" />
    <input type="submit" name="submit" value="Search" />    
    </form>
    <?php
    // check if form is submitted
    // perform necessary validation (omitted for brevity)
    if (isset($_POST['submit'])) {
      // set up Zend auto-loader
      // load Zend REST client classes
      require_once 'Zend/Loader.php';
      Zend_Loader::loadClass('Zend_Rest_Client');

      // execute YQL query
      // get list of events in requested country
      try {
        $client = new Zend_Rest_Client('http://query.yahooapis.com/v1/public/yql');
        $client->q(
          "SELECT * FROM upcoming.events 
            WHERE country_id IN 
              (SELECT id FROM upcoming.country 
                WHERE name = '" . ucfirst($_POST['country']) . "')");    
        $result = $client->get();
      } catch (Zend_Rest_Client_Exception $e) {
          echo "Client error: " . $e->getResponse();
      } catch (Exception $e) {
          echo "Error: " . $e->getMessage();
      }

      // iterate over query result set
      echo '<h2>Events in ' . ucfirst($_POST['country']) . '</h2>';
      foreach ($result->event as $e) {
        echo '<p>';
        echo '<a href="' . $e['url'] . '">' . $e['name'] . 
          '</a> <br/>';
        echo 'Starts: ' . date('d M Y', strtotime($e['start_date'])). '<br/>'; 
        echo !empty($e['end_date']) ?  'Ends: ' . 
          date('d M Y', strtotime($e['end_date'])) . '<br/>' : '';
        echo 'Location: ' . $e['venue_name'] . '<br/>';
        echo 'Address: ' . 
          sprintf('%s, %s', $e['venue_address'], $e['venue_city']) . '<br/>';
        echo $e['description'] . '<br/>';
        echo '</p>';
      } 
}
?>  
  </body>
</html>

リスト 6 では 2 つのネストされた YQL クエリーを利用しています。内側のクエリーは ”upcoming.country” データ・テーブルにアクセスして、ユーザーが入力した国名に対応する数値による ID を取得します。この数値による ID が外側のクエリーに渡され、そのクエリーが、該当する国別 ID にリンクしたイベントのリストを取得するという仕組みです。

図 11 に、このコードを実行した結果の一例を示します。

図 11. 国を基準に検索できる、近日中に予定されたイベントのリスト
国を基準に検索できる、近日中に予定されたイベントのリストを示す画面のスクリーン・キャプチャー。インド・ハイデラバードのイベントが表示されています。

重要な点として、技術的にはこれは結合ではなく、サブクエリーであることに注意してください。この記事を執筆している時点では、YQL で共通キーによってテーブルをリンク (結合) することはできませんが、クエリーに含まれる別のクエリー (サブクエリー) の結果を使用することはできます。


サンプル・アプリケーション: ベストセラーのリストと価格

ご想像のとおり、単純な SQL ライクな構文で複数の Web インターフェースからのデータを結合できるという言葉は、マッシュアップ開発者の心には甘い調べで響きます。そこで、今度は少し複雑な別のアプリケーションとして、ニューヨーク・タイムズのベストセラー・リストからのデータと、Amazon.com のデータベースからの価格情報を組み合わせ、人気の高い本とその価格および人気度を複合ビューで表示する例を検討します。

このアプリケーションを構築する際の最初のステップは、ニューヨーク・タイムズから現行のベストセラー・リストを取得することです。YQL では nyt.bestsellers テーブルからこの情報を入手できるようになっていますが、このテーブルでクエリーを実行するには、有効な API キーが必要です。ここでは、このキーを持っているという前提で (キーの取得方法の説明へのリンクを「参考文献」に記載してあります)、以下のようなクエリーによって、2010年 7月 21日の週のフィクション分野でのハードカバーのベストセラー・リストを取得します。

SELECT * FROM nyt.bestsellers WHERE listname='Hardcover Fiction' 
AND date='2010-07-21' AND apikey='NYT-API-KEY'

図 12 に、このクエリーによる出力の例を示します。

図 12. YQL クエリーによって取得した、ニューヨーク・タイムズのベストセラーのリスト
YQL クエリーによって取得した、ニューヨーク・タイムズのベストセラーのリストを示す画面のスクリーン・キャプチャー

結果に含まれる各レコードには、その本に固有の ISBN 番号が含まれていることに注目してください。これはアプリケーションの次の部分、つまり Amazon.com で本の価格を調べる部分には不可欠な情報です。

Amazon.com から価格情報を取得するのは、一見すると厄介なタスクのように思えますが、実際にはこれ以上単純にはできないほど単純なタスクです。Amazon.com ではその製品データベースを Amazon ECS Web サービスによってサード・パーティーの開発者に公開しています (API キーを取得するためのリンク、およびその方法に関する情報については、「参考文献」を参照してください)。そして YQL には、この Amazon ECS のデータ・テーブルがあり、以下のようなクエリーを使用して、特定の ISBN に対応する価格情報を取得できるようになっています。

SELECT DetailPageURL, ItemAttributes, SalesRank, MediumImage FROM amazon.ecs 
WHERE AWSAccessKeyId='AWS-KEY' AND secret='AWS-SECRET-KEY' 
AND ResponseGroup='Medium' AND Operation = 'ItemLookup' 
AND ItemAttributes.Binding = 'Hardcover' AND ItemId = '1400065453'

図 13 に上記のクエリーによる出力を示します。

図 13. YQL クエリーによって Amazon.com から取得した製品データ
YQL クエリーによって Amazon.com から取得した製品データを示す画面のスクリーン・キャプチャー

見てのとおり、前に記載した 2 つのクエリーを組み合わせることで、簡単に必要な情報を生成することができます。リスト 7 に、完全なスクリプトを記載します。このスクリプトを試す前に、クエリーに含まれているダミー API キーを忘れずに自分の API キーに置き換えてください。

リスト 7. ベストセラー・リストと価格の取得
<html>
  <head>
    <style type="text/css">
    .item {
      float: left;
      width: 400px;      
      padding:10px;   
    }
    .cover {
      float:left; 
      padding: 5px;
      border: solid 1px black;      
    }
    .data {
      margin-left: 150px;
      font-weight: bolder;  
    }
    </style>
  </head>
  <body>
<?php
// set up Zend auto-loader
// load Zend REST client classes
require_once 'Zend/Loader.php';
Zend_Loader::loadClass('Zend_Rest_Client');

// execute YQL query
// get list of NYT bestsellers
// retrieve image and price from Amazon.com
try {
  $client = new Zend_Rest_Client('http://query.yahooapis.com/v1/public/yql');
  $client->env('store://datatables.org/alltableswithkeys');  
  $client->q(
    "SELECT DetailPageURL, ItemAttributes, SalesRank, MediumImage FROM amazon.ecs 
      WHERE AWSAccessKeyId='AWS-KEY' 
      AND secret='AWS-SECRET-KEY' 
      AND ResponseGroup='Medium' 
      AND Operation = 'ItemLookup' 
      AND ItemAttributes.Binding = 'Hardcover' 
      AND ItemId IN 
        (SELECT isbns.isbn.isbn10 FROM nyt.bestsellers 
          WHERE apikey='NYT-KEY' 
          AND listname='Hardcover Fiction' 
          AND date='2010-07-20') 
    | unique(field='ItemAttributes.Title')");    
  $result = $client->get();
} catch (Zend_Rest_Client_Exception $e) {
    echo "Client error: " . $e->getResponse();
} catch (Exception $e) {
    echo "Error: " . $e->getMessage();
}

// iterate over query result set
echo '<h2>New York Times - Hardcover Fiction Bestsellers</h2>';
$count = 1;
foreach ($result->results->Item as $r) {
  echo '<div class="item">';
  echo '<img class="cover" src="' . $r->MediumImage->URL . '"/>';
  echo '<div class="data">';
  echo $count . '. ';
  echo '<a href="' . $r->DetailPageURL . '">' . 
    $r->ItemAttributes->Title . '</a>';
  echo ' - '. $r->ItemAttributes->Author . '<br/>';
  echo 'Amazon.com Sales Rank: ' . $r->SalesRank . '<br/>';
  echo 'Amazon.com Price: ' . 
    $r->ItemAttributes->ListPrice->FormattedPrice . '';
  echo '</div></div>';
  $count++;
}  
?>  
  </body>
</html>

リスト 7 では前に記載した 2 つのクエリーを組み合わせ、ISBN キーを共通項として使用して、本のタイトル、著者、画像、価格、そして売り上げ順位を含めて合成した結果を生成します。この結果が構文解析されて、HTML ページを生成するために処理されます (図 14 を参照)。

図 14. YQL クエリーによって製品データを組み合わせたベストセラー本のリスト
YQL クエリーによって製品データを組み合わせたベストセラー本のリストを示す画面のスクリーン・キャプチャー

リスト 7 で注目すべき点は、内側のクエリーは厳密に言うと、ベストセラー・リストでの本の ISBN-10 番号しか取得していないことです。この情報はツリー内の数ノード下にあるので、ドット表記を使用して、必要なノードの階層内での正確な位置をクエリー・パーサーに示しています。外側のクエリーに unique フィルターを適用する際にも同じような手法を使用して、結果のフィルタリング基準となるフィールドをドット表記で示しています。


まとめ

以上の例から明らかなように、YQL は Web アプリケーション開発者にとって強力なツールとなります。YQL はさまざまな Web サービスに対する統一したインターフェースとなり、SQL ライクな標準クエリー・メカニズムを使えるようにすることで開発を迅速化し、ターゲットとするサービスに関して調べる手間も省きます。YQL クエリーで WHERE 節を使って結果をフィルタリングすることも、サブ SELECT 文を使って複数のサービスからのデータを結合、つまり「マッシュアップ」することもできます。さらに、強力な XML 処理ツールを備えた PHP を加えれば、疲れ切った Web 開発者でさえも進んで試してみたくなる組み合わせとなります!

この記事で紹介した例は、氷山のほんの一角に過ぎません。YQL には他にも、結果セットのページングや、RSS、Atom、XML、HTML などの文書からのデータの抽出、CREATE および UPDATE クエリーによるデータの追加と変更など、盛りだくさんの機能があります。YQL の機能をさらに詳しく掘り下げる第 2 回の記事をぜひ、お見逃しなく。

参考文献

学ぶために

製品や技術を入手するために

議論するために

コメント

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=XML, Open source
ArticleID=600482
ArticleTitle=YQL と PHP を使用して Web アプリケーションを構築する: 第 1 回
publish-date=11302010