目次


Jaxer を利用してサーバー・サイドで E4X を使う

JavaScript と Jaxer を使用して Web アプリケーションを作成する

Comments

はじめに

この記事では、クライアント・サイドとサーバー・サイドの両方で JavaScript を使用する Web アプリケーションを Jaxer を使用して作成します。このため、読者に Web 開発の経験、特に JavaScript の使用経験があることを前提としています。また、JavaScript と言っても具体的には E4X を利用して XML を処理するため、ある程度 XML を理解していると役に立ちます。このアプリケーションは Aptana Studio™ 1.2.1 を使って作成しましたが、Aptana Studio を使わなくても Jaxer アプリケーションを作成することは可能です。Jaxer 1.0.2 は Aptana Studio とバンドルされているため、Jaxer を別途ダウンロードする必要はありません。ダウンロードのためのリンクについては「参考文献」を参照してください。

Jaxer の概要

Jaxer を利用すると、サーバー・サイドのプログラミング言語として JavaScript を使用することができます。皆さんが通常行う、データベースへのアクセスやファイルの読み書き、あるいは他のサーバーとの通信といった操作はすべて、Java™、PHP、Python、Ruby™ などのプログラミングによって行うことができます。しかし Jaxer を利用すると、今風の Web アプリケーションを JavaScript という 1 つの言語のみを使用して作成することができるのです。動的で対話型の Web アプリケーションを作成している人であれば、既に大量の JavaScript を作成しているはずです。大量の Ajax を作成している人であれば、サーバーで使用する言語と JavaScript との間の変換におそらく大きな時間を費やしているはずです。Jaxer を利用すると、すべてを JavaScript で行えるため、開発作業を単純化することができます。Jaxer の使い方を説明する前に、Jaxer アプリケーションがどのように動作するのかを理解するために、まず Jaxer のアーキテクチャーを簡単に調べることにしましょう。

Jaxer のアーキテクチャー

Jaxer がサーバー上で JavaScript を使うのは確かに独特かもしれませんが、Jaxer のアーキテクチャーは極めて標準的なものです。Jaxer は Apache Web サーバー上で実行される mod_jaxer という 1 つの Apache モジュールにすぎず、そのアーキテクチャーは、PHP や Python、(Phusion Passenger™ を使用する) Ruby on Rails™ などに見られるアーキテクチャーや、(mod_jk を使用する) Tomcat のような Java Web コンテナーと組み合わせて Apache を使用するアーキテクチャーと同じです。図 1 は上位レベルでの Jaxer のアーキテクチャーを示したものです。

図 1. Jaxer のアーキテクチャー
Jaxer のアーキテクチャー
Jaxer のアーキテクチャー

これは極めて標準的なサーバー・サイドのアーキテクチャーです。また Jaxer は PHP など他のサーバー・サイド技術と共通の特徴も持っています。Jaxer は他のものと何も共有しません (ただしセッション・データを共通のデータベースに自動的に保存します)。

では Jaxer は実際にどのようにしてサーバー上で JavaScript を実行するのでしょう。Jaxer は Mozilla® の SpiderMonkey という JavaScript 仮想マシンを使います。SpiderMonkey は Firefox® 3.0 でも使われている JavaScript エンジンです。このため Jaxer は PHP に匹敵する非常に高いパフォーマンスを実現します。Jaxer を利用すると、Firefox でサポートされているすべての JavaScript を使用することができ、Firefox と Internet Explorer の両方でサポートされている JavaScript のサブセットのみに限定されることがありません。この後を読むとわかるとおり、そうした JavaScript の中には関数型プログラミングの構成体もいくつか含まれています (Array.mapArray.reduce、さらには XML の構文解析と生成のための E4X など)。これで Jaxer の動作の概要を理解できたので、Jaxer を使うために何をインストールする必要があるのかを調べてみましょう。

Jaxer をインストールする

Jaxer は、Windows®、Mac OS® X、Linux®、Solaris™ をはじめとする大部分のプラットフォームで使用することができます。Jaxer は Apache にバンドルされているため、他には何もダウンロードする必要がありません。しかしもっと手軽に Jaxer を使い始めるためには、単純に Aptana Studio をダウンロードしてしまうことです (「参考文献」を参照)。Aptana Studio は JavaScript 開発者にとって素晴らしい IDE なので、いずれにしてもダウンロードしておくとよいかもしれません。また、Aptana Studio には組み込みの Apache/Jaxer サーバーも含まれているため、Web アプリケーションを作成して即座に Jaxer 上で実行させることができます。Aptana Studio は Eclipse のプラグインであり、スタンドアロンのアプリケーションとして (Eclipse をバンドルした状態で) ダウンロードすることも、あるいは既に Eclipse を使用している場合にはプラグインとしてダウンロードすることもできます。

Aptana Studio を使い始める場合には、まず Jaxer シェルを試してみてください。Jaxer シェルでは、JavaScript を入力することができ、その JavaScript を Jaxer の中で直接実行することができます。また、Jaxer シェルを利用するとサーバー上で直接コードのテストとデバッグを行えるため、非常に便利です。図 2 は Jaxer シェルを使って Jaxer の API の一部を試している様子を示しています。

図 2. Jaxer シェル
Jaxer シェル
Jaxer シェル

Jaxer を使用するアプリケーションを作成するためには、新しいプロジェクトを作成し、Aptana Projects > Default Web Projects の順に選択します。このウィザードの中で、Jaxer のサポートを追加するための画面が表示されます。プロジェクトを作成すると、任意の HTML ファイルを右クリックして Run As > JavaScript Web Application の順に選択することができます。これによってファイルが Jaxer にデプロイされ、そのページがデフォルトの Web ブラウザーに表示されます。Firefox を使用している場合には、JavaScript のデバッグ用によく使われる Firebug プラグインを使用したプラグインが Jaxer に用意されているので、それを使うことができます。Jaxer バージョンのプラグインを使うと、Aptana Studio の中で実際のコードをデバッグすることができます。これで Aptana Studio と Jaxer の準備ができたので、サンプル・アプリケーションを作成し、Jaxer がサーバー・サイドの E4X をサポートすることを説明することにしましょう。

サンプル・アプリケーション: JavaScript を使って Flickr を検索する

ではサンプル・アプリケーションを作成しましょう。ここでは非常に簡単にするために、人気の写真共有サイトである Flickr の中から写真を検索するアプリケーションを作成します。このアプリケーションは Flickr Web サービスを使用して、指定されたタグを持つすべての写真を検索します。Flickr はこのデータを XML で提供するため、この XML をサーバー上で E4X を使って処理します。まず、この XML がどのようなものか、そして E4X を使ってこの XML をどう処理するのかを調べましょう。

E4X を使って XML を構文解析する

Flickr Web サービスはデータをさまざまなフォーマットで提供します (XML や JSON、さらにはシリアライズした PHP など)。デフォルトのフォーマットは XML です。リスト 1 は Flickr Web サービスからの出力の例です。

リスト 1. Flickr から出力される XML の例
<?xml version="1.0" encoding="utf-8" ?>
<rsp stat="ok">
<photos page="1" pages="20626" perpage="16" total="330003">
    <photo id="3284086892" owner="49356365@N00" secret="a072efd762" 
server="3294" farm="4" title="Snow Day" ispublic="1" isfriend="0" isfamily="0" />
    <photo id="3283258525" owner="49356365@N00" secret="30c9b39aa1" 
server="3409" farm="4" title="Snow Day" ispublic="1" isfriend="0" isfamily="0" />
    <photo id="3284079858" owner="49356365@N00" secret="798d6ca888" 
server="3517" farm="4" title="Snow Day" ispublic="1" isfriend="0" isfamily="0" />
    <photo id="3284077350" owner="49356365@N00" secret="c27902242e" 
server="3413" farm="4" title="Snow Day" ispublic="1" isfriend="0" isfamily="0" />
    <photo id="3283262179" owner="49356365@N00" secret="2b2e36cafd" 
server="3149" farm="4" title="Snow Day" ispublic="1" isfriend="0" isfamily="0" />
    <photo id="3284084794" owner="49356365@N00" secret="57afa6f5f8"
server="3294" farm="4" title="Snow Day" ispublic="1" isfriend="0" isfamily="0" />
    <photo id="3284081008" owner="49356365@N00" secret="5cd1b5a932" 
server="3435" farm="4" title="Snow Day" ispublic="1" isfriend="0" isfamily="0" />
    <photo id="3284085910" owner="49356365@N00" secret="0a51105dcd" 
server="3487" farm="4" title="Snow Day" ispublic="1" isfriend="0" isfamily="0" />
    <photo id="3283263823" owner="49356365@N00" secret="944da852f9"
server="3407" farm="4" title="Snow Day" ispublic="1" isfriend="0" isfamily="0" />
    <photo id="3284082986" owner="49356365@N00" secret="2d0f3c3755" 
server="3282" farm="4" title="Snow Day" ispublic="1" isfriend="0" isfamily="0" />
    <photo id="3283236151" owner="49356365@N00" secret="2299cca4e1" 
server="3146" farm="4" title="Snow Day" ispublic="1" isfriend="0" isfamily="0" />
    <photo id="3283249899" owner="49356365@N00" secret="e23d563cef" 
server="3623" farm="4" title="Snow Day" ispublic="1" isfriend="0" isfamily="0" />
</photos>
</rsp>

このようなデータをサーバー・サイドの Java コードで構文解析する必要があるとしたら、あるいはクライアント・サイドの JavaScript コードで構文解析する場合であっても、DOM API を使うかもしれません。DOM API は単純な方法ですが、コードが非常に冗長になる可能性があります。E4X を使用すると、コードははるかに単純になります。リスト 2 は Flickr から出力される XML を構文解析するコードを示しています。

リスト 2. Flickr の XML を E4X で構文解析する
/*
 * Parses XML in the following format:
 *     <photo id="3283249899" owner="49356365@N00" secret="e23d563cef" 
 *   server="3623" farm="4" title="Snow Day" ispublic="1" isfriend="0" 
 *   isfamily="0" />
 */
function FlickrPhoto(xml){
    this.id = xml.@id.toXMLString();
    this.owner = xml.@owner.toXMLString();
    this.secret = xml.@secret.toXMLString();
    this.server = xml.@server.toXMLString();
    this.farm = xml.@farm.toXMLString();
    this.caption = xml.@title.toXMLString();
    this.url = "http://farm"+ this.farm + ".static.flickr.com/"+
    this.server +"/"+ this.id +"_"+ this.secret +".jpg";
    this.toHtml = function(){
        var html = <img src={this.url} alt={this.caption} 
title={this.caption}></img>;
        return html.toXMLString();
    }    
}

まず、コードの前にあるコメントを読んでください。このコメントは入力パラメーターとして想定される XML のタイプを示しています。これはリスト 1 のサンプル XML の中にある 1 つの photo 要素です。photo 要素の各属性 (id、owner、その他) の値は、FlickrPhoto という JavaScript クラスの似たような名前のプロパティーにマッピングされるようにします。つまり、例えば XML の server 属性にアクセスするためには xml.@server.toXMLString() を使います。toXMLString メソッドは、server 属性のデータをストリングで表現したものを返します。

上記の url プロパティー・セットによって、画像に対する URL が Flickr Web サービスのデータから単純に作成されます。もっと興味深いものは toHtml メソッドです。このメソッドが XML リテラルを使用していることに注目してください。E4X は XML の中にあるデータへのアクセスに便利なだけではなく、XML を作成するためにも便利なのです。もちろん、HTML は (あるいはもっと正確に言えば XHTML は) XML でもあるため、E4X を使って HTML 表現を作成することができます。この場合の HTML 表現は img タグです。このタグをストリングとして作成することもできますが、E4X で表現した方がスマートです。url プロパティーと caption プロパティーがどのようにして XML 表現の中に直接埋め込まれているかに注目してください。では、Flickr から得られた XML をこうしたオブジェクトの 1 つに入れるためにはどうするのでしょう。そのためにはプロキシーが必要です。

プロキシーを使う

ブラウザーの中で XMLHttpRequest を使ってリモート呼び出しを行うことができますが、その呼び出しは Web ページと同じドメインから行う必要があります。このルールがあるため、Flickr を直接呼び出すことはできません。Flickr を呼び出すためにはサーバーからプロキシーを使って呼び出す必要があります。Jaxer では、これを非常に容易に行うことができます。単純にスクリプト要素の中で通常の場合と同じように JavaScript を宣言しますが、属性を追加することによって、この JavaScript をプロキシーとして使うことを Jaxer に通知します。リスト 3 を見てください。

リスト 3. プロキシーを使って Flickr を検索するページ
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
      <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
      <title>Flickr Search</title>
    <script type="text/javascript" runat="server-proxy">            
// server side code goes here        
    </script>
    <script type="text/javascript">
        function getData(){
            var tag = document.getElementById("tag").value;
            var response = getFlickr(tag);
            document.getElementById("out").innerHTML = response;
        }
    </script>
    </head>
    <body>
        <div>
            <span>Search:</span>
        <input type="text" id="tag"></input>
            <input type="button" value="Show Photos" onclick="getData()"/>
      </div>
    <div id="out">Output will go here</div>
    </body>
</html>

最初の script タブに注目してください。このタグは server-proxy に設定された runat 属性を持っています。この属性によって、このブロックの中にあるすべてのコードはサーバー上で実行されること、ただしそれらのコードをクライアントから呼び出せる必要があることを Jaxer に通知します。Jaxer はクライアント上にプロキシー・オブジェクトを作成します。

この例では 1 つのテキスト入力フィールドと 1 つのボタンを持つ単純な HTML フォームを作成しています。ユーザーがボタンをクリックすると getData 関数が呼び出されます。この関数はテキスト・フィールドに入力されたデータを引数に取り、それを getFlickr 関数に渡します。しかし getFlickr 関数はどこにあるのでしょう。getFlickr 関数はサーバー上で定義されています。Jaxer ライブラリーはこの関数のプロキシーを作成し、この関数をクライアント・コード (リスト 3) によって呼び出せるようにします。この関数が Flickr Web サービスにアクセスします。ではこれがどのように動作するのかを調べてみましょう。

Web サービスを呼び出す

サーバー上では、クライアント上で使用できるものをすべて使用することができます。例えば XMLHttpRequest を使ってリモート Web サービスを呼び出すことができます。しかしサーバーにはほとんど制約がないため、Jaxer にはリモート Web サービスの呼び出しを容易にするための API が用意されています。リスト 4 はそのためのコードを示しています。

リスト 4. サーバー上で Flickr を呼び出す
function getFlickr(tag){
    const API_KEY = "Your Key Goes here";
    var url = "http://api.flickr.com/services/rest/?method=" +
        "flickr.photos.search&per_page=16&api_key="+ API_KEY + 
        "&tags="+tag;
    var raw = Jaxer.Web.get(url);
    Jaxer.Log.debug("Got data from Flickr=" + raw);
    var rsp = new XML(raw.replace(/<\?(.*?)\?>/,''));
    var photos = [rsp.photos.photo[i] for (i in rsp.photos.photo)];
    photos = photos.map(function(x) new FlickrPhoto(x));
    var html = photos.reduce(function (previous, current){
        return previous + current.toHtml();
    }, "");                
    return html;
}

リスト 4 のコードは非常に簡潔ですが、ここでは多くのことが行われています。第 1 に、Flickr Web サービスに対する URL を作成します。Flickr を呼び出すためには API キーが必要です。API_KEY 変数が const として宣言されていることに注目してください。const は JavaScript 1.5 の一部ですが、Internet Explorer ではサポートされていません。名前からわかるように、const は変数を読み取り専用の定数として宣言します。

次に、Flickr Web サービスを呼び出すために Jaxer.Web.get API を使っています。これは Jaxer ライブラリーの一部であり、この API を使用すると、何ら制限なしに任意のリモート・サーバーに同期呼び出しを行うことができます。この API を使用する方が XMLHttpRequest を使用するよりもはるかに簡単です。この API から得られる結果を引数として、別の Jaxer API である Jaxer.Log.debug を使用して Flickr のデータをログに記録します。Jaxer のログに対しては Aptana Studio から直接アクセスすることができます。Jaxer.Log.debug はデフォルトでは ERROR レベルのメッセージしかログに記録しないため、ログ・レベルを調整する必要があるかもしれません。

Flickr から得られたデータは構文解析されて XML オブジェクトになります。このオブジェクトに対して最初に正規表現を実行していることに注目してください。この正規表現によって XML 宣言 (<?xml version="1.0" encoding="utf-8" ?>) を削除します。こうする理由は E4X が XML 宣言を想定していないためです。XML オブジェクトが得られると、rsp.photos.photo という表現を使って photo 要素のリストを取得することができます。rsp.photos.photo がどのようにリスト 1 の要素構造と突き合わせを行うかに注目してください。

次の式 (var photos で始まる式) は経験豊富な JavaScript 開発者にとっても見慣れないものかもしれません。これは配列内包表記であり、JavaScript 1.7 の一部であったものです。通常はさまざまなブラウザーに対応する必要があるため、このタイプの関数型プログラミング・スタイルも JavaScript では見慣れないものかもしれません。Python をよく知っている人にとっては、これは Python でのリスト内包表記と非常に似ているように思えるかもしれません。この場合は rsp.photos.photo オブジェクトに対して繰り返し処理を行います。このオブジェクトは XMLList オブジェクト、つまりリストであり、このリストの各要素はリスト 1 で見た XML の photo ノードに対応します。内包表記によって作成される配列の各要素は XMLList の XML 要素です。つまり XMLList を配列に変換したのです。なぜこうしたのでしょう。理由は簡単で、Array クラスには便利な API がいくつかあり、それらの方が XMLList の API よりも扱いやすいからです。では説明を続けましょう。

配列の中に photo XML オブジェクトが得られたら、この配列に対して map 関数を呼び出します。map 関数も関数型プログラミングの構成体です。map 関数は 1 つのパラメーター (関数) を引数に取り、その関数を配列の各要素に適用します。その結果新しい配列が作成されますが、新しい配列の i 番目の要素は元の配列の i 番目の要素にその関数を適用した結果です。実際にはこの 2 行のコード (配列内包表記と map 関数) を 1 つにまとめることができますが、ここではサーバー・サイドの JavaScript を使って強力なことができるということをわかりやすく説明するために、両者を分離したままにしています。

最後にもう 1 つ、より高度な JavaScript 機能を使います。それは配列に対する reduce メソッドです。このメソッドは JavaScript 1.8 で導入され、すべての配列内包表記や map 関数と同様、Python での構成体に非常によく似ています (これは他の多くの関数型言語で fold として知られています)。reduce メソッドは関数と初期値という 2 つの引数を取ります。関数には previouscurrent という 2 つのパラメーターがあります。previous パラメーターは初期値 (この場合は空のストリング) から始まります。current パラメーターは配列の最初の要素から始まります。このパラメーターを使って関数を呼び出した結果が次の previous パラメーターとなり、配列の次の要素を current パラメーターとして同じことを行います。このプロセスを配列のすべての要素が終わるまで続けます。この場合は空のストリングで始まり、最初の要素に対して toHtml メソッドを呼び出した結果にその空のストリングを連結します。次にその連結した結果を、配列の 2 番目の要素に対して toHtml メソッドを呼び出した結果に連結します。この繰り返しを続けます。最終的に、配列の各要素に toHtml を適用した結果が連結されることになります。表 1 はこの繰り返しプロセスを示したものです。

表 1. 配列の各要素に toHtml が適用されて連結される結果
繰り返し回数previous パラメーターcurrent パラメーター戻り値
0 """"
1""photos[0]photos[0].toHtml()
2photos[0].toHtml()photos[1]photos[0].toHtml()
+
photos[1].toHtml()
3photos[0].toHtml()
+
photos[1].toHtml()
photos[2]photos[0].toHtml()
+
photos[1].toHtml()
+
photos[2].toHtml()

従って最終的に、map 式は各要素を引数に取り、各要素の toHtml メソッドを適用し、そしてすべての値を連結します。クライアント・コードに戻ると、こうした繰り返しプロセスの結果がクライアントに返送され、その結果を使ってクライアントの DOM が更新されます。このようにして、クライアントは Flickr から得られたすべての画像を表示します。

まとめ

この記事では、Jaxer を利用することで JavaScript のみを使って強力な Web アプリケーションを作成できることを説明しました。サーバー上で JavaScript を実行することは風変わりなことではありません。JavaScript は極めて最新の強力なプログラミング言語です。特に、JavaScript の E4X 機能を活用すると、XML 文書を自由自在に加工して容易に XML 表現を作成することができます。サーバー上で JavaScript を実行すると、他にも表現力豊かな機能を実現することができます。この強力な言語をサーバーとクライアントの両方で組み合わせて使用できると非常に魅力的です。Jaxer を利用すれば、こうしたことが全て可能になり、皆さんも今すぐに JavaScript のスキルを新たな方法で生かすことができるのです。


ダウンロード可能なリソース


関連トピック

  • JavaScript を強化した E4X」(Grace Walker 著、developerWorks、2008年7月) を読み、E4 を使ってさまざまなことを行えることを学んでください (XML データに対する単純で容易な構文解析、計算、編集、等々)。
  • Ajax and scripting Web services with E4X」(Paul Fremantle と Anthony Elder の共著、developerWorks、2005年4月) を読み、Ajax アプリケーションにとって E4X がいかに便利なものか、また JavaScript 用の E4X 拡張機能を利用すると XML を非常に容易にスクリプト化できることを学んでください。
  • エレガントな JavaScript を作成するための関数型プログラミングの使用」(Shantanu Bhattacharya 著、developerWorks、2006年6月) を読み、JavaScript が関数型プログラミングの心臓部であること、それを念頭に置くことでどんなことが実現できるかを学んでください。
  • 魅力的なPython: Pythonでの関数プログラミング: 第1回」(David Mertz 著、developerWorks、2001年3月) を読み、JavaScript の持つ高度な機能の多くが Python と似ていることを学んでください。
  • Jaxer Guide には Jaxer に関するすべての情報とサーバー上で JavaScript を実行する方法が説明されています。
  • E4X に関する疑問に突き当たった場合には Mozilla の Processing XML with E4X ページを調べてみてください。
  • 君のプログラミング言語で、これ、できる?」(Joel Spolsky 著、2006年8月1日) は、楽しいながらも深く考えさせる見方で JavaScript の強力さを解説しています。
  • Build an Ajax-enabled application using the Google Web Toolkit and Apache Geronimo」(Michael Galpin 著、developerWorks、2007年5月) は Geronimo と Google Web Toolkit とを組み合わせ、高度な Ajax Web アプリケーションを迅速に作成する方法を解説しています。
  • XML および関連技術において IBM 認定技術者になる方法については、IBM XML certification を参照してください。
  • developerWorks の XML ゾーンは XML の技術ライブラリーとして、広範な話題を網羅した技術記事やヒント、チュートリアル、技術標準、IBM Redbooks などを用意しています。
  • developerWorks の Web development ゾーンには技術記事やヒント、チュートリアル、技術標準などが豊富に用意されています。
  • developerWorks podcasts ではソフトウェア開発者のための興味深いインタビューや議論を聞くことができます。
  • この記事で使用した Aptana Studio 1.2.1 をダウンロードして試してみてください。
  • オンラインの写真管理アプリケーション、Flickr のサイトを訪れてください。
  • Phusion Passenger (Ruby on Rails) と Jaxer のアーキテクチャーを比較してください。

コメント

コメントを登録するにはサインインあるいは登録してください。

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=XML, Web development, Open source
ArticleID=379508
ArticleTitle=Jaxer を利用してサーバー・サイドで E4X を使う
publish-date=03032009