SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

japan.internet.com翻訳記事

JSONを使ってAJAXベースのアプリケーションを高速化する

Webアプリケーションで役立つ軽量なデータ交換フォーマットの利用

JSONをAJAXと一緒に使う

 JSONはJavaScriptであり、AJAXもJavaScriptですから、両者を使って素晴らしいWeb 2.0アプリケーションを構築できないでしょうか。答えはもちろんYESです。今回の記事では、サンプルアプリケーションとしてニュースティッカーを作成しました。図2に、このアプリケーションのアーキテクチャを示します。

図2 ニュースティッカーのアーキテクチャ。データアクセス、ビジネスロジック、プレゼンテーションの各レイヤを分離することを常に心がける
図2 ニュースティッカーのアーキテクチャ。データアクセス、ビジネスロジック、プレゼンテーションの各レイヤを分離することを常に心がける

 この記事の冒頭で、Observerパターンを使ってサンプルアプリケーションを実装すると書きました。図3に、この便利なパターンの簡易バージョンを表すクラス図を示します。

図3 Observerパターン。これは非常によく使われるパターンの1つである
図3 Observerパターン。これは非常によく使われるパターンの1つである

Observerパターン

 Observerパターンは、オブジェクト間に1対多の依存関係を与え、あるオブジェクト(Observee)の状態が変化すると、そのすべての従属者(Observer)に通知が送られて、自動的に更新が実行されるプログラミングスタイルです。ほとんどの専門書では、ObserveeはSubjectと呼ばれます。この記事で「Observee」という呼び名を使うのは、このオブジェクトの役割を強調するためです。Observeeはニュースのダウンロードを担当するオブジェクトで、Observerはニュースを受け取るオブジェクトです。

 サンプルアプリケーションでは、JavaScriptのMarqueeクラスを使ってObserverを実装し、ContentRetrieverクラスを使ってSubject(以下、Observeeと呼ぶ)を実装します。MarqueeContentRetrieverが図3の具象クラスを表すことに注意してください。JavaScriptでは抽象クラスが厳密に定義されないので、これらのクラスは抽象クラスを継承しません。抽象クラスを「シミュレート」することもできますが、これは本稿の対象外のテクニックです。Marqueeの役目は、情報をmarquee要素で表示することです。一方、ContentRetrieverの役目は、JSONフォーマットのニュースをAJAX呼び出しでダウンロードすることです。

 ContentRetrieverでは、HtmlBuilderヘルパクラスを使って、取得したJSONテキストを解析し、HTMLのmarquee要素で表示するHTMLコードを作成します。このヘルパクラスによって、プレゼンテーションのロジックが分離されます。ニュースのフォーマットを変更することになった場合は、HtmlBuilderのロジックを変更するだけで対応できます。サンプルアプリケーションのフォントや色などの定義にはCSSスタイルシートを使います。フォントや色は好みで変更できます。

 以下は、ContentRetrieverクラスのコンストラクタです。

function ContentRetriever(jsonDataRetriever, observerObjectsArray)
{
   // JSONデータの取得と解析
   this.jsonData = "";
   // JSONデータ取得を処理するサーバーサイド
   // コンポーネントのURL
   this.jsonDataRetriever = jsonDataRetriever;
   //AJAXオブジェクト
   this.ajaxObj = createHttpRequest();
   // observerの配列
   this.observerObjectsArray = observerObjectsArray;
}

 最初のパラメータは、ニュースの取得を処理するサーバーサイドコンポーネントのURLです。2番目のパラメータは、ContentRetriever(observee)が情報を取得したという通知を受け取るオブジェクト(observer)の配列です。早い話、以上がObserverパターンの基本形です。1人が仕事をこなし、残りの全員が仕事の完了を告げる知らせをただ待っているのです。createHttpRequest関数では、XMLHttpRequestオブジェクトを作成します。このオブジェクトでブラウザの相違点を吸収します。createHttpRequest関数は、この記事のダウンロードサンプルの「ajax.js」ファイルに定義されています。「demo.htm」ファイルは、ティッカーを作成して表示するJavaScriptコードです。このコードは、次のようなものです。

<script type="text/javascript">
   var marquee = new Marquee("newsMarquee", 2, true);
   var contentRetriever = new ContentRetriever(
      "./tickerDataRetriever.php", [marquee]);
   //コンテンツを取得する
   contentRetriever.getContent();
</script>

 このコードでは、Marqueeクラス(詳しくは後述)のインスタンスを作成してから、ContentRetrieverオブジェクトを作成し、データ取得を行うPHPスクリプトのURLとobserverオブジェクトの配列(この例ではオブジェクトは1つだけ)を渡します。

 以下は、Marqueeコンストラクタのコードです。

function Marquee(elemId, scrollamount, stopOnMouseOver)
{
   this.elemId = elemId;
   this.scrollamount = scrollamount;
   this.stopOnMouseOver = stopOnMouseOver;

   this.dataArray = [];
   this.errorMessage = "ニュースはありません";
}

 Marqueeコンストラクタのパラメータは、以下の3つです。

  • elemId
  • ニュースを表示するdiv要素のid
  • scrollamount
  • HTMLのmarquee要素のscrollamount属性。スクロール速度を制御できる。
  • stopOnMouseOver
  • マウスポインタをニュース項目の上に移動したときにスクロールを停止するかどうかを制御するブール型属性。

 dataArrayプロパティは、取得された解析済みのニュース項目の配列です。errorMessageプロパティは、ニュースのダウンロードに失敗したときに表示するエラーメッセージです。

 ニュースを実際に取得するメソッドは、ContentRetrieverクラスのgetContent()です。getContent()メソッドのコードを次に示します。

ContentRetriever.prototype.getContent = function()
{
   if (this.ajaxObj)
   {
      var instance = this;
      this.ajaxObj.open('GET', this.jsonDataRetriever, true);
      //コールバック関数
      this.ajaxObj.onreadystatechange =
         function(){instance.processDataRetrieved();};
      this.ajaxObj.send(null);
   }
};

 getContent()では、まずXMLHttpRequestオブジェクトが正常に作成されたことを確認します。次に、HTTPのGETメソッドを使ったAJAX呼び出しと、ニュース取得用のPHPスクリプトのURL、さらに非同期呼び出しを指定するブール値(open()呼び出しの3番目のパラメータtrue)を準備します。非同期の呼び出しなので、呼び出しの完了時に実行されるコールバック関数を定義する必要があります。この例では、processDataRetrievedがコールバック関数です。最後に、他のデータを指定しないで(send()の引数にnullを指定する)AJAX呼び出しを実行します。

 実際のデータを取得するサーバーサイドスクリプト(「tickerDataRetriever.php」ファイル)は、とても単純です。

<?php
//ニュースのフォルダ
$NEWS_FOLDER = "news";

//ニュースのファイル
$filename = "news.txt";
//name of the news file
$localFile = $NEWS_FOLDER . "/" . $filename;

//コンテンツをJSON文字列で返す
print(file_get_contents($localFile));

?>

 説明を省くため、今回はJSONフォーマットをテキストファイルにハードコーディングしました。もちろん、実際に使うアプリケーションでは、データベースやRSSフィードなど、動的なコンテンツのソースから情報を取得することになります。今回使うPHPスクリプトでは、JSONテキストを単に取得して解析し、ContentRetrieverに渡します。以下は、「news.txt」の内容です。

{
   "items" :
   [
      {
         "title" : "This is the first item's title",
         "link" : "http://www.alessandrolacava.com",
         "description" : "This is the description of the \"first\" news.
            The link takes you to my Web site"
      },
      {
         "title" : "Second item's title",
         "link" : "http://www.json.org",
         "description" : "You can appreciate how easily you
            can parse JSON text. This link takes you to the JSON Web site"
      },
      {
         "title" : "This is the third item's title.",
         "link" : "http://www.devx.com",
         "description" :
            "The link for this item takes you to the DevX Web site"
      }
   ]
}

 ご覧の通り、このファイルの内容はオブジェクト配列を表すJSON文字列です。各オブジェクトはニュース項目を表し、titlelinkdescriptionの3つのプロパティを持ちます。最初の項目のdescription値で二重引用符をエスケープしていることに注意してください(\")。値の中で二重引用符を使うには、エスケープする必要があります。そうしないと、構文の解析時に二重引用符がフィールド値の終端と解釈されます。この記事の最後で、動的コンテンツの取得時にこのエスケープを自動化する方法を説明します。

 取得した情報(JSONテキスト)を処理する関数は、次のようなコードです。

ContentRetriever.prototype.processDataRetrieved = function()
{
   //要求が完了したか
   if (this.ajaxObj.readyState == 4)
   {
      //要求は正常に処理されたか
      if (this.ajaxObj.status==200)
      {
         //応答は空かどうか
         if(this.ajaxObj.responseText != null &&
            this.ajaxObj.responseText.length > 0)
         {
            var htmlBuilder = new HtmlBuilder(this.ajaxObj.responseText);
            //JSONデータを解析する
            this.jsonData = htmlBuilder.getHtml();
         }
         else
         {
            //エラー発生時はサイズ0の配列を返す
            this.jsonData = [];
         }
         // observerに通知する
         this.notify();
      }
   }
};

 このコードでは、まず要求が正常に実行されたかどうかを確認します。次に、HtmlBuilderオブジェクトをインスタンス化し、これにJSONテキストを渡します。HtmlBuildergetHtmlメソッドでJSON文字列を解析し、marqueeに表示するHTMLコードを作成します。これが終わると、HtmlBuilderからnotifyメソッドを呼び出します。

//すべてのobserverに通知する
ContentRetriever.prototype.notify = function()
{
   //observerのコールバック関数を呼び出して、作成した配列を渡す
   for(var i = 0; i < this.observerObjectsArray.length; i++)
   {
      this.observerObjectsArray[i].update(this.jsonData);
   }
};

 notifyメソッドで、登録済みのすべてのobserver(この例ではmarqueeただ1つ)のupdateメソッドを呼び出します。

 HtmlBuildergetHtml関数は、取得したJSONコードからHTMLを作成する変換処理を行います。

//HTMLコードを作成し、項目のJavaScript配列として返す
HtmlBuilder.prototype.getHtml = function()
{
   var ret = [];
   //JSONテキストをデコードする
   var obj = this.decodeJson();
   //配列を取得する
   var items = obj.items;
   //配列を使ってHTMLコードを作成する
   for(var i = 0; i < items.length; i++)
   {
      var item = "";
      //タイトルを作成する
      item += this.buildTitle(items[i]);
      item += "<br />";
      //説明文を作成する
      item += this.buildDescription(items[i]);
      item += "<br />";
      ret.push(item);
   }
   return ret;
};

 この関数では、JSONテキストを解析し、一連のHTML文字列を作成して、これをJavaScript配列としてContentRetrieverに返します。実際のJSONテキスト解析は、decodeJson関数で行います。

HtmlBuilder.prototype.decodeJson = function()
{
   return eval("(" + this.jsonString + ")");
};

 ご覧のように、JSONデータ全体を解析するコードがわずか1行で済んでいます。たいしたものです。そうでもないとお思いの方は、試しに同じニュースをXMLで表して、JavaScriptで解析してみるとよいでしょう。目からうろこが落ちること請け合いです。

 getHtml関数の残りの部分では、ニュースを使いやすいフォーマットに整え、ニュース項目の配列を作成します。この配列は、ニュースをHTMLのmarquee要素に表示するMarqueeupdateメソッドに渡されるパラメータです。

次のページ
セキュリティ対策と他の言語でのJSONサポート

この記事は参考になりましたか?

japan.internet.com翻訳記事連載記事一覧

もっと読む

この記事の著者

japan.internet.com(ジャパンインターネットコム)

japan.internet.com は、1999年9月にオープンした、日本初のネットビジネス専門ニュースサイト。月間2億以上のページビューを誇る米国 Jupitermedia Corporation (Nasdaq: JUPM) のニュースサイト internet.comEarthWeb.com からの最新記事を日本語に翻訳して掲載するとともに、日本独自のネットビジネス関連記事やレポートを配信。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

Alessandro Lacava(Alessandro Lacava)

イタリアを活動拠点とするソフトウェア開発者、テクニカルライター。Javaと.NETテクノロジ、Webアプリケーション、通信システムを得意分野とする。通信エンジニアリングの資格を保有。連絡先については個人のWebサイトを参照。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/793 2006/12/27 00:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー