IBM®
本文へジャンプ
    Japan [変更]    ご利用条件
 
 
検索範囲検索:    
    ホーム    製品    サービス & ソリューション    サポート & ダウンロード    マイアカウント    
skip to main content

developerWorks Japan  >  XML | Web development  >

XMLの論考: MochiKit

XML の DOM 操作を改善する

developerWorks
ページオプション

JavaScript を要するドキュメントオプションは表示されません

原文はこちら

原文はこちら


レベル: 中級

David Mertz, Ph.D (mertz@gnosis.cx), Author, Gnosis Software, Inc.

2006年 11月 21日

MochiKit は、JavaScript 用の便利な上位ライブラリーです。MochiKit は、Python や Python 標準ライブラリーが提供する多くの便利な機能から主な着想を得ており、また別の側面として、ブラウザーのバージョン間での違いを吸収してくれます。特に MochiKit.DOM は手軽なコンポーネントであり、これを使うことで、「生の」 JavaScript で処理する場合よりもずっと容易に DOM オブジェクトを処理することができます。多くの MochiKit.DOM は XHTML の処理にカスタマイズされているため、特に MochiKit と Ajax を組み合わせる場合には、XHTML でラップされたマイクロフォーマットを使えることは非常に便利かもしれません。

はじめに

私のコラムの最近のゲスト、Dethe Elza は、Ajax やマイクロフォーマット、そして Atom に関して、いくつかの興味深い概念を提示してくれました。これらについて、少し詳しく探る価値がありそうです。この記事では最初のステップとして、Dethe がピコフォーマットに関して書いた記事 (「参考文献」を参照してください) の中で簡単に触れた、素晴らしい ECMAScript ライブラリー、Bob Ippolito による MochiKit について調べることにします。MochiKit には基本的な JavaScript (厳密には ECMAScript) 機能のちょっとした強化がいくつも含まれていますが、その背景にあるのは、Ippolito が関数型プログラミングを好むこと、そして彼が Python の豊富な標準ライブラリーや柔軟な構成体を気に入っているという事実です。多くの面において、MochiKit を使うことによって JavaScript でプログラムできる一方、他の多くの開発者にはおなじみの Python 言語を使っているように見せられるのです。

なぜ XML なのか

このコラムの読者ならよく知っていると思いますが、Ajax に「X」がある主な理由は、Web ブラウザーで実装されているように、ECMAScript が多少は W3C の DOM (Document Object Model) 仕様をサポートしているためです (これは皆さんが実際にどのバージョンのブラウザーを使っているかによります。「多少」といっても実は「少」が「多」を圧倒しているかもしれません)。こんな言い方も変ですが、そのおかげで JavaScript コードは XML や (X)HTML 文書に対するパーサーを自動的に持つことになり、またそうした文書をトラバースし、検索し、そして抽象構造として修正するための API コール群も自動的に持つようになっています。これは DOM が非常に扱いにくい API であるという厄介な事実を除けば、自然な取り合わせに見えます。もちろん皆さんの中には、強い型定義で静的型定義の、そして高度に構造化され、注意深くカプセル化された、Java のような言語 (我々プログラマーは B&D (bondage-and-discipline: 束縛と規律の) 言語と呼んでいます) では、W3C DOM の形式を活用できる、と反論する人もいるかもしれません。しかし ECMAScript のように比較的アジャイルな言語では、DOM を使う動機はほとんど見あたりません。

読者は、(たとえ MochiKit.DOM によって処理が容易になるとしても) そもそもなぜ XML 部分を考慮すべきなのか疑問に思いたくなるかもしれません。つまるところ、JSON は基本的に単なるネイティブの JavaScript データ構造にすぎず (なんと幸いなことに、同時に有効な Python でもあります)、しかも非常に軽量です。とはいえ、XML にもいくつかの利点があります。例えば表示という面では、CSS2 (Cascading Style Sheets 2) を使えば XML を直接スタイリングできます。もちろん、JSON をスタイリング可能な DOM オブジェクトに変換することもできますが、結局それは、XML または (X)HTML に戻すことに他なりません。その一方、ECMAScript インタプリター以外の多くのツールが、JSON を処理する以上に XML を処理することができます。XML を使って構造化データを定義するサーバーからデータが受信され、そしてデータがサーバーに送り返されます。この XML は場合によると、公開された標準に準拠しているスキーマを含めた、既知の、よく定義されたスキーマに従っているかもしれません。全体としての通信フローの中の他のシステムが、SVG や OpenDocument あるいは TEI、あるいはなんらかの ebXML 標準を使っての通信を要求している場合には、そうした混合状態の中に追加レイヤーとして JSON を挿入しない方が、おそらく得策と言えるでしょう。

単純な魔術

幸い MochiKit.DOM は、W3C DOM の意図、つまり抽象的な文書構造に対する API を提供するという意図の下に構築され、そして容易なことは容易に、困難なことは W3C DOM よりもずっと楽にできるように作られています。MochiKit.DOM の本当の魔術は、メソッド・コールの際、さまざまな型のオブジェクトを適切な型に柔軟に変更しようとし、それを再帰的にも行えることです。MochiKit は、明らかに適切な操作がある場合に、必要なものを抽出あるいは変更するために、プログラマーが型をキャストしたりメソッドをコールしたりといった苦労をせずに済むようになっています。しかも、MochiKit の FP を応用した部分アプリケーションを利用すれば、それが非常に便利な場合は、プログラマーは (そしてプログラムは) 非常に楽な思いができるのです。




上に戻る


HTML の何が問題なのか

当然ですが、Web ページは通常 (X)HTML で、あるいは実際には HTML ではないものの HTML に似た何かで作成されます。私は正直なところ、ブラウザーの Quirks モードは非常に素晴らしいと思っています。しかし最近のブラウザーでは広く CSS が実装されているため、適切なスタイリングを備えた XML 文書であれば、どれも同じようにうまく動作します。そして実際のところ、対象となる文書のセマンティクス固有のタグを使うこともできます。最近では (X)HTML を、単にデフォルトの CSS スタイルシートが付属している XML スキーマと考えても、ほとんど問題ないほどになっています。

XML と (X)HTML が同じように一般的になったことは、Ajax の意味合いからは嬉しいことです。MochiKit に付属するサンプルの大部分は、XML あるいは JSON を構文解析して HTML タグにしますが、XML に忠実な概念的に純粋なスタイルも、基本的には可能です。ここに取り上げるいくつかの例では、MochiKit が ajax_tables の例に使っているものと同じ <datatable> XML フォーマットを使いますが、使い方は少し変えています。まず、表を適切にスタイリングしてみましょう。下記は単純な CSS スタイルシートの例です。


リスト 1. table.css
                
datatable {
    display: table;
    width: 99%;
    border: solid 1px;
    margin-left: auto;
    margin-right: auto
    }
columns {
    display: table-header-group;
    background-color: lightblue;
    }
column {
    display: table-cell;
    font-weight: bold;
    border-right: solid 1px;
    }
rows {
    display: table-row-group
    }
row {
    display: table-row
    }
cell {
    display: table-cell; border-right: solid 1px;
    }
            

この CSS を見れば、スタイルリングされた XML 文書の構造を、ほぼ推察することができます。しかし先に進んで、データ・ファイルの 1 つを見てみましょう。


リスト 2. table1.xml
                
<?xml version="1.0"?>
<?xml-stylesheet href="table.css" type="text/css"?>
<datatable>
    <columns>
        <column>First_name</column>
        <column>Last_name</column>
        <column>Domain_name</column>
    </columns>
    <rows>
        <row>
            <cell>Dethe</cell>
            <cell>Elza</cell>
            <cell>livingcode.org</cell>
        </row>
        <row>
            <cell>Bob</cell>
            <cell>Ippolito</cell>
            <cell>bob.pythonmac.org</cell>
        </row>
    </rows>
</datatable>

あまり大したものではありませんが、この静的文書は問題なく公開できます。これを読む人には、次のようなものが見えるはずです。


図 1. Firefox で table1.xml を表示した場合のスクリーンショット
図 1. Firefox で table1.xml を表示した場合のスクリーンショット



上に戻る


XML を操作する

スタイリングされた XML を表示するだけであれば、Ajax は必要なく、そして MochiKit も必要ありません。そこで、XML を使って実際に何かをするコードを作ってみましょう。最初に、良き XML を古風な HTML でラップしましょう。もちろん、魔法の xml:link 属性を使えば XLINK 機能を追加できますが、ここでは単純にしておくことにします。


リスト 3. 表プロジェクト index.html のホーム
                
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
               "http://www.w3.org/TR/html4/strict.dtd">
<html>
  <head>
    <title>DOM made simple</title>
    <script type="text/javascript"
            src="../../lib/MochiKit/MochiKit.js"></script>
    <script type="text/javascript"
            src="../../lib/MochiKit/DOM.js"></script>
    <script type="text/javascript"
            src="table.js"></script>
  </head>
  <body>
  <p id="actions">
    <b onclick="showXML()">[Show current XML]</b>
    <b onclick="showText()">[Show text of table]</b> <br/>
    <b onclick="newChildContent('table1.xml')">[Load table1.xml]</b>
    <b onclick="newChildContent('table2.xml')">[Load table2.xml]</b>
    <b onclick="addRow()">[Add row of data]</b>        </p>
  <iframe name="child" id="child" src="table.xml" width="600" />
  </body>
</html>

リスト 3 のサンプル HTML ページには、次の 3 つの基本部分があります。

  1. 2 つの MochiKit コンポーネントから何らかの ECMAScript を、そしてカスタムのスクリプト・ファイルをロードします。
  2. いくつかのクリック・アクションを定義します。
  3. <iframe> を使って図 1 のような表を表示します。

明らかにわかることですが、もっと本格的なアプリケーションであれば、(おそらくフォームやページ領域、カスタム・ウィジェットなどを使って) より高度な方法でページと対話動作を行うかもしれません。しかしそれは他の記事での話です。

JavaScript を解剖する

HTML の中でコールされる関数をサポートしているのは、いくつかの小さなサポート関数です。リスト 4 は、それらを示しています。


リスト 4. table.js でのサポート・ルーチン
                
childDoc = function() {
    return frames['child'].document;
};
getRows = function() {
    return childDoc().getElementsByTagName('rows')[0];
};
randint = function(n) {
    return Math.floor(Math.random()*n);
}

これらはほとんど自明の簡略表現であり、MochiKit の機能は何も使っていません。2 つの表示関数は、MochiKit のマイナーなコンビニエンス関数を使っています。


リスト 5. table.js の XML 内容を表示する
                
showXML = function() {
    alert(toHTML(childDoc().documentElement));
};
showText = function() {
    alert(scrapeText(childDoc().documentElement));
};

ここにも大したものはありません。遊び用のプログラムでなければ、皆さんなら alert() ボックスの中にポップアップさせる以外に、XML でもっと多くのことをするでしょう (例えばサーバーに返送したり、あるいは少なくともクライアント・アプリケーションの一部として、さらに処理してスキャンしたり、など)。とはいえ、scrapeText() は文書中の全テキスト・ノードを抽出するために便利な関数であり、また toHTML() は (その名前に反して) 予約文字を適切にエスケープし、DOM ツリーを XML ストリングとして描画します。これらによって、少なくとも表 XML の状態を検証することができます。

(少しばかり) 本格的な XML 作業

面白くなるのは、XML コンテンツをロードし、修正するところからです。コメントする前に、まず新しい XML データをロードするコードを示しましょう。


リスト 6. table.js に XML をロードする
                
newChildContent = function(url) {
    var req = getXMLHttpRequest();
    req.overrideMimeType("text/xml");
    req.open("GET", url, true);
    d = sendXMLHttpRequest(req).addCallback(datatableFromXMLRequest);
};
datatableFromXMLRequest = function (req) {
    var xml = req.responseXML;
    var new_rose = xml.getElementsByTagName('rows')[0]
    swapDOM(getRows(),new_rose);
    rows = getRows().getElementsByTagName('row');
    for (var i=0; i < rows.length; i++) {
        setNodeAttribute(rows[i], 'id', 'row'+i);
    }
};

なかなか良い点として最初に気付くことは、MochiKit が (他の一部の JavaScript ライブラリーのように) Microsoft Internet Explorer のさまざまなバージョンによる違いを便利な関数 getXMLHttpRequest() でラップしてくれるため、詳細を気にしなくてよくなることです。またもちろん嬉しいことに、XMLHttpRequest() をサポートする標準準拠のブラウザーでも動作します。もっと興味深い部分は、 MochiKit.Async ツールキットを利用する sendXMLHttpRequest() です。名前からもわかるとおり、これを使うとリクエストを非同期に取得でき、リクエストが成功したかどうかを確認するために待つ間、他の仕事をすることができます。この遊び用のコードではこれを利用していませんが、本物のコードであれば、何をすべきかをリクエストの結果に基づいて決定することができます。例えば MochiKit の ajax_tables.js の例では、据え置き (deferred) オブジェクト d でこれを行っています。


リスト 7. ajax_tables.js での据え置き (deferred) オブジェクトの処理
                
// call this.initWithData(data) once it's ready
d.addCallback(this.initWithData);
// except for a simple cancellation, log the error
d.addErrback(function (err) {
    if (err instanceof CancelledError) {
        return;
    }
    logError(err);
});

table.js では、単純にリクエストがローカル・ファイルのロードに成功するものと想定しています。そして<rows> 要素を、標準の DOM .getElementsByTagName() メソッドを使って取り出しています。しかしもっと複雑な DOM 構文を処理する場合には、MochiKit の swapDOM() を使った方が便利で早道です。しかし私は最初、文書要素全体を swapDOM(childDoc().documentElement,xml.documentElement) で交換できるのではないかと思っていました。残念ながら、これでは新しいノードは追加できません。おそらく読者の皆さんは、なぜこれが成功しないか説明できるかもしれません。当然ですが、何を交換するかはアプリケーションの詳細に依存します。しかし私は、階層構造の最上部を選択するだけでは文書要素全体を変換できないことが不満でした。

少し余分ですが、私のコールバック関数では <row> 要素に id 属性も追加します。DOM メソッド .getElementsById() の周囲に数多くの MochiKit 要素ショートカットがありますが、それらは iframe DOM のコンテキストではなくメイン文書のコンテキストを想定しています。そのため私の遊び用アプリケーションにとっては、その大部分をどう使うべきか、明白ではありません。もし私がメイン文書しか気にしないのであれば、次のようなショートカットを使ったはずです。


リスト 8. Firebug の対話型コンソール
                
>>> $('child')
<iframe width="600" src="table.xml" id="child" name="child">
>>> $('actions')
<p id="actions">

いくつかの MochiKit 関数では、ノードの名前にノード id を使うことができ、そうすることでノードに何らかのアクションを行うことができます。例えば、addElementClass("foo","newClass") は、「foo」という id を持つ要素に newClass を追加しますが、その要素が持っていた既存のクラスを妨害することはありません。

XML を調整する

文書のロードは、始まりとしてはかなり最低限のことですが、私のサンプル・コードは、それ以上のことをほとんどしていません。しかし MochiKit.DOM で XML や (X)HTML を扱う際にもう 1 つ便利なものは、単純な DOM 作成関数です。これは MochiKit のイテレーターと関数型プログラミングと非常にうまく連係動作します。既に大部分の HTML 関数は事前構築されたコンビニエンス関数 (慣習的に名前はすべて大文字です) を持っていますが、XML フォーマット用に独自のものを作ることも容易にできます。例えば下記は、XML 表に (たわいのない) 行を追加する方法を示しています。


リスト 9. table.js での DOM 作成の魔術
                
ROW = createDOMFunc('row');
CELL = createDOMFunc('cell');
newRow = function(cells) {
    return ROW({'type':'name'}, map(partial(CELL, null), cells));
};
addRow = function() {
    fn = ['John','Jane','Jim','Jill','June'][randint(5)];
    ln = ['Wu','Williams','Wegner','Wulu','Watanabi'][randint(5)];
    dn = ['gnosis.cx','google.com','gmail.com',
               'gnu.org','groklaw.net'][randint(5)];
    appendChildNodes(getRows(), newRow([fn,ln,dn]));
};

私が追加した行が、ほとんど無意味なことがわかると思います。つまり各フィールドに対して、いくつかの値をランダムな順序で入れ替えているだけですが、追加した行同士が同じにならないようにするにはこれで十分です。クールな DOM 関数 ROW() と CELL() には、ちょっとした魔術が含まれています。特に newRow() 関数内でこれらの関数を組み合わせたところに含まれています。ここでは単に可能性を示す意味で、各 <row> に type="name" 属性を追加しています。null ではなく辞書を渡せば、一連の属性が作成されます。




上に戻る


作業を楽にする

この記事では、ごく簡単な紹介を行いました。MochiKit と MochiKit.DOM は、私が説明したことをはるかに上回ることをします。しかしこの記事だけでも、便利なラッパーのおかげで、完全な W3C DOM の呼び出しがいかに容易になるかを示せたと思います。ここでは多くを示しませんでしたが、MochiKit.DOM は、実際に MochiKit.DOM の関数に渡された引数を特定の関数が使用するものに変換することに関しては慎重です。例えば、id 属性に名前を付けるストリングは、多くの場合ノードそのものと交換が可能です。またシーケンスやイテレーターは、アンロールした方が適切な場合にはアンロールされます。

私がこの記事を書きながら気が付いた、もう 1 つ便利なものは、FireBug と呼ばれる非常に素晴らしい Firefox プラグインです (「参考文献」を参照してください)。この記事は FireBug の解説記事ではありませんが、FireBug は JavaScript や XML、そして Web ページ一般のデバッグや実験のためのリッチな環境を提供します。FireBug の特徴としておそらく最も素晴らしいは、対話型のコンソールでしょう。このコンソールでは、Python の対話型シェルでコマンドを試すのと同じように JavaScript コマンドを (MochiKit で機能強化したものも含めて) 試すことができます。おまけに、もちろん FireBug には、そのためのデバッガーとインスペクターも用意されています (また現在の DOM をビューしたり、Ajax アプリケーションを理解するために XMLHttpRequest() の結果を検証したりすることもできます)。



参考文献

学ぶために
  • 「XML の論考: マイクロフォーマットよりも軽いピコフォーマット」 (Dethe Elza 著、developerWorks、2006年8月) を読んでください。そして X のない Ajax に MochiKit を使って (YAML よりも軽い) JSON を活用し、マイクロフォーマットの生成タスクに reStructured Text を適用してください。

  • Separate data and formatting with microformats」(Jack Herrington 著、developerWorks、2006年7月) を読み、標準の XHTML を使ってデータを埋め込むための新しい方法を探ってください。

  • MochiKit のホームを訪れてください。安定かつ最先端のバージョンのドキュメンテーションやダウンロードが用意されています。

  • ECMA International の Standard ECMA-262 を訪れ、ECMAScript Language Specification を正確に読んでください。

  • Appendix D of the DOM specification を調べ、Level 2 Document Object Model HTML 定義のための ECMAScript バインディングについて学んでください。

  • CSS と XML を一緒に使用する上での要点を知るために、毎度ながら、W3C の仕様 Associating Style Sheets with XML documents Version 1.0 を調べてください。

  • XML および関連技術において IBM 認証開発者になる方法については、IBM XML certification を参照してください。

  • XML 記事一覧 には、developerWorks XML ゾーンをご利用ください。広範な話題を網羅した技術記事やヒント、チュートリアル、技術標準、IBM レッドブックなどが用意されています。

  • developerWorks technical events and webcasts で最新情報を入手してください。


製品や技術を入手するために
  • FireBug について読み、あるいはこのエクステンションをダウンロードしてください。

  • IBM trial software を利用して皆さんの次期開発プロジェクトを構築してください。developerWorks から直接ダウンロードすることができます。


議論するために
  • XML zone discussion forums に参加してください。これらのフォーラムでは、XML を中心に議論が行われています。

  • developerWorks blogs から developerWorks のコミュニティーに加わってください。


著者について

Photo of David Mertz

David Mertz氏は多くの分野で活躍しています。ソフトウェア開発や、それについて著述もしています。その他、学術政策理念について分野を問わず、関係する雑誌に記事も書いています。かなり以前には、超限集合論、ロジック、モデル理論などを研究していました。その後、労働組合組織者として活動していました。そして、David Mertz氏自身は人生の半ばにもまだ達していないと思っているので、これから何かほかの仕事をするかもしれません。




記事の評価


サイト改善のため、ご意見をお寄せください。こちらのフォームからお願いいたします。



 


 


不充分・不完全である大変素晴らしい
 


この記事を共有する

del.icio.us del.icio.us newsing newsing FC2ブックマーク FC2ブックマーク
Choix! Choix! ニフティクリップ ニフティクリップ Yahoo!ブックマーク Yahoo!ブックマーク
MM/memo MM/memo CZブックマーク CZブックマーク livedoorクリップ livedoorクリップ
はてなブックマーク はてなブックマーク Buzzurl(バザール) Buzzurl(バザール)




上に戻る


    日本IBMについて プライバシー お問い合わせ