XML.ObjTree クラスは、Perl 用の
XML::TreePP
モジュールの JavaScript 版です。
XML ファイルと JavaScript オブジェクト(連想配列)間の相互変換を行います。
prototype.js または
JSAN の
HTTP.Request
クラスと併用することで、
JKL.ParseXML の
後継
としても利用できます。
ECMA-357 の普及を待たずに、
ECMAScript for XML (E4X)
風のXMLのオブジェクト利用が可能になります。
Intel Mac 版の Safari で、
DOMParser オブジェクトの async プロパティが read-only となる点にも対応しています。
IE で(サーバ上でなく)ローカルのXMLファイルを開きやすくなりました。(2006/08/14)
ダウンロードは、 JSAN または ↓コチラからどうぞ。
アーカイブ:
XML.ObjTree-0.24.tar.gz
TARGZ
.js ソースファイル単体:
lib/XML/ObjTree.js
JavaScript
IE 7、Firefox 1.5.0、Opera 8.53、Safari 2.0.3 で
動作確認済
です。
.tar.gz アーカイブにはテストファイルなどが含まれますが、
動作に必要なのは lib/XML/ObjTree.js ファイルだけです。
その他の JSAN 系クラスには依存しないので、単体で利用できます。
通常通り、<script> 要素で読み込む場合は以下のようになります。
DEMO
<html> <head> <script src="lib/XML/ObjTree.js"></script> </head> <body> <script><!-- var xotree = new XML.ObjTree(); var xml = '<?xml version="1.0"?><root><node>Hello, World!</node></root>'; var tree = xotree.parseXML( xml ); // source to tree document.write( "message: "+tree.root.node ); // --></script> </body> </html>
または、JSAN の use メソッドによる動的ロード機能を使うなら↓のようにも書けます。
DEMO
<html> <head> <script src="lib/JSAN.js"></script> </head> <body> <script><!-- JSAN.addRepository("lib"); JSAN.errorLevel = "die"; JSAN.use( 'XML.ObjTree' ); var xotree = new XML.ObjTree(); var tree = { root: { node: "Hello, World!" } }; var xml = xotree.writeXML( tree ); // tree to source xml = xml.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">"); document.write( "xml: "+xml ); // --></script> </body> </html>
個人的には、JSAN を使わずに、<script> 要素で明示的に読み込んだ方が分かりやすいと思います。
以下のようなXMLファイルを展開する場合を想定します。
<?xml version="1.0" encoding="UTF-8"?> <family name="山田"> <father>太郎</father> <mother>花子</mother> <children> <girl>和江</girl> <boy>一郎</boy> <boy>次郎</boy> </children> </family>
上記の XML ファイルは、 parseXML() メソッドのより、 以下のような JavaScript オブジェクト(連想配列)に展開されます。
{ 'family': { '-name': '山田', 'father': '太郎', 'mother': '花子', 'children': { 'girl': '和江' 'boy': [ '一郎', '次郎' ] } } };
逆に、writeXML() メソッドで反対方向
(JavaScriptオブジェクト→XMLコード)に変換できます。
JavaScript 上で手軽に XML コードを生成できるため、
XML-RPC リクエストなどに利用できます。
各要素ごとに展開ルールを見ていきます。
XML の要素は、それぞれ JavaScript のオブジェクト(プロパティ)に展開されます。
要素のネストはオブジェクトのネストとなるため、
子要素には .(ピリオド)を区切り文字としてアクセスできます。
tree.family.father; # お父さんの名前
XML の属性値は、属性名の先頭に - (ハイフン)を付けたプロパティに展開されます。
tree.family["-name"]; # 家族の姓
attr_prefix プロパティにより、ハイフンでなく @(アットマーク)を プリフィックスとして使用できます。E4X 風になります。
子要素名に同じ要素名が複数回登場する場合は、配列に展開されます。
tree.family.children.boy[0]; # お兄さんの名前 tree.family.children.boy[1]; # 弟の名前 tree.family.children.girl; # 女の子の名前(姉妹はいないので配列化されない)
xotree = new XML.ObjTree()
XML.ObjTree クラスのコンストラクタです。
今のところ、特に引数はありません。
xotree.force_array = [ "rdf:li", "item", "-xmlns" ];
XML.ObjTree オブジェクトのプロパティとしては、 force_array が利用可能です。
デフォルト動作では、XML→JavaScript オブジェクト(連想配列)への展開時は
子要素の登場回数で配列化するか否かを自動的に決定しますが、
force_array プロパティで「必ず配列化する要素名・属性名」を指定できます。
force_array プロパティで指定していない要素名・属性名は
デフォルト動作で自動判別されます。
例えば、RDF ファイルでは、<rdf:li> や <item> 要素は
複数回登場する可能性があることが予め分かっていますから、
force_array プロパティを指定することで自動判別を回避し、
強制的に配列化を行います。
配列化どうかのチェックを省けるため、スクリプトの動作がより安全になります。
(可能な限り force_array プロパティを使用することが推奨されます)
xotree.attr_prefix = '@';
XML の属性を JavaScript のオブジェクトに展開した際の識別用のプリフィックス文字を
指定します。デフォルトは「-」半角ハイフンです。
「@」を指定すると、
ECMAScript for XML (E4X)
風になります。
なお、attr_prefix は必ず1文字で指定します。(空・2文字〜は無効)
tree = xotree.parseXML( xmlsrc );
parseXML メソッドは、
XML ソースコードをパースして、JavaScript オブジェクト(連想配列)に展開します。
なお、XML ソースコードから DOM への展開の内部処理では、 Firefox 等では DOMParser クラスを利用しています。 IE では、ActiveX の XMLDOM を利用しています。 XML::TreePP とは異なり、自前で文字列解析は行っていません。
tree = xotree.parseDOM( domnode );
parseDOM メソッドは、
DOM ツリーをパースして、JavaScript オブジェクト(連想配列)に展開します。
主に、XMLHTTPRequest の responseXML.documentElement を
指定することを想定しています。
XML ファイル全体でなくて、XML から取得した DOM ツリーの一部分のみを
展開する場合にも利用できます。
それ以外の用途としては、
表示している HTML ページ自身も DOM なので、そのまま指定できたりします。
(※ Opera は HTML の属性名が大文字になっていたり、互換性がなくて困ります…)
tree = xotree.parseHTTP( url, options );
parseHTTP メソッドは、
ウェブサーバから XML ファイルを受信して、JavaScript オブジェクト(連想配列)に展開します。
内部的に、
JSAN の
HTTP.Request クラスまたは
prototype.js
の Ajax.Request クラスを利用します。
HTTP/Request.js または prototype.js のどちらかのファイルを
予めロードしておく必要があります。
なお、ブラウザのセキュリティ制限により、表示している HTML ファイルとは違う ドメイン上にある XML ファイルへはアクセスできないのでご注意ください。
第1引数は、XMLファイルのURLを指定します。
もちろん、静的なXMLファイルでなく、CGI などの呼び出しでも構いません。
第2引数は、HTTP.Request/Ajax.Request クラスのオプションオブジェクトを指定します。
method, postBody, parameters, onLoading プロパティなどを指定できます。
単純に GET メソッドを使用する場合は、空 {} にするか省略できます。
POST メソッドを使用する場合は、postBody か parameters を指定してください。
XMLHTTPRequest の同期モード(sync)で通信を行うため、 サーバからのレスポンスが完了するのを待ってから展開処理を行います。 ↓の非同期モード(async)を利用した方が、操作性が向上します。
xotree.parseHTTP( url, options, callback );
XMLHTTPRequest の非同期モード(async)で通信を行います。
通信完了を待たずにparseHTTPメソッド自体は終了して、次の行の処理に進みます。
XML の受信が完了した後(onCompleteイベント)に、
第3引数で指定したコールバック関数が呼び出されます。
コールバック関数は、 第1引数にXMLファイルの内容を展開したJavaScriptオブジェクト、 第2引数にXMLHTTPRequestインスタンスを付けて呼び出されます。
xmlsrc = xotree.writeXML( tree );
writeXML メソッドは、
JavaScript オブジェクト(連想配列)から XML ソースコードを生成します。
XML-RPC のリクエストボディなどに利用できます。
テキストノードのみの要素や、テキストノードを持たない要素は JavaScript オブジェクトとして単純に展開されますが、 テキストノードと属性の両方を持つ要素や テキストノードと子要素を持つ要素の場合、 テキストノードの値を単純にJavaScriptオブジェクトのプロパティ値としては 格納できないため、 #text というプロパティ名に展開されます。
var xotree = new XML.ObjTree(); var xmlsrc = '<span class="author">Kawasaki Yusuke</span>'; var tree = xotree.parseXML( xmlsrc ); var class = tree.span["-class"]; # 属性名の先頭は - var name = tree.span["#text"]; # テキストノード
以下のサンプルは、index.html(タグの閉じ忘れ等がないもの)の <html> 要素の lang="〜" 属性の値を表示します。
var xotree = new XML.ObjTree(); var url = "http://example.com/index.html"; var tree = xotree.parseHTTP( url ); alert( tree.html["-lang"] );
なお、parseHTTP() メソッドを呼び出す前に、 予め HTTP/Request.js or prototype.js をロードしておく必要があります。
以下のサンプルは、 トラックバックping を送信して、その返り値を表示しています。
var xotree = new XML.ObjTree(); var url = "http://example.com/mt-tb.cgi"; var opts = { postBody: "title=...&excerpt=...&url=...&blog_name=..." }; var func = function ( tree ) { alert( tree.response.error ); }; xotree.parseHTTP( url, opts, func );
parseHTTP() メソッドの第3引数として、
コールバック関数(無名ファンクション)を指定しています。
このコールバック関数は、onComplete イベント時に呼び出されます。
以下のサンプルは、簡易的な RSS リーダーです。
RDF ファイルを受信して、各記事を <div> 要素で並べて表示します。
var xotree = new XML.ObjTree(); xotree.force_array = [ "rdf:li", "item" ]; var url = "http://example.com/news-rdf.xml"; var func = function( tree ) { var elem = document.getElementById("rss_here"); for( var i=0; i<tree["rdf:RDF"].item.length; i++ ) { var divtag = document.createElement( "div" ); var atag = document.createElement( "a" ); atag.href = tree["rdf:RDF"].item[i].link; var title = tree["rdf:RDF"].item[i].title; var tnode = document.createTextNode( title ); atag.appendChild( tnode ); divtag.appendChild( atag ); elem.appendChild( divtag ); } }; xotree.parseHTTP( url, {}, func );
以下のサンプルでは、writeXML() メソッドで生成した
weblogUpdates.ping
の XML-RPC リクエストを、
prototype.js を利用してサーバに送信し、
その返り値(XML)を parseDOM() メソッドで確認しています。
var xotree = new XML.ObjTree(); var reqtree = { methodCall: { methodName: "weblogUpdates.ping", params: { param: [ { value: "Kawa.net xp top page" }, // 1st param { value: "http://www.kawa.net/" } // 2nd param ] } } }; var reqxml = xotree.writeXML( reqtree ); // JS-Object to XML code var url = "http://example.com/xmlrpc"; var func = function( req ) { var resdom = req.responseXML.documentElement; xotree.force_array = [ "member" ]; var restree = xotree.parseDOM( resdom ); // XML-DOM to JS-Object alert( restree.methodResponse.params.param.value.struct.member[0].value.string ); }; var opt = { method: "post", postBody: reqxml, asynchronous: true, onComplete: func }; new Ajax.Request( url, opt );
prototype.js を直接呼ばずに、parseHTTP()メソッドを利用した方が スクリプトはシンプルになりますが、prototype.js が好きだったり、 何か直接細かい処理を行いたい場合には、parseDOM()メソッドの方がいいかもしれません。
XML.ObjTree の前身である
JKL.ParseXML
クラス(jkl-parsexml.js)は、
XMLHTTPRequest へのラッパールーチンを内蔵しています。
このラッパーは、IE では状況に応じて
Microsoft.XMLDOM(DOMDocument)を利用することで
Content-Type: 許容問題 に対応するなど、細かい配慮もあります。
XML.ObjTreeクラス | JKL.ParseXMLクラス | |
---|---|---|
公開開始 | 2006/04/06 | 2005/05/18 |
ライブラリ依存関係 |
parseHTTP() メソッドのみ、
HTTP.Request クラス または prototype.js のいずれかが必要 それ以外のメソッドでは依存なし。単体でOK | 依存ライブラリなし 単体のみで利用可能 |
XMLソースコード→JSオブジェクト | ○ parseXML()で対応 | × 非対応 |
DOMツリー→JSオブジェクト | ○ parseDOM()で対応 | △ parseDocument()で対応(非公開) |
外部XMLファイル→JSオブジェクト | ○ parseHTTP()で対応 | ○ parse()で対応(これがメイン機能) |
JSオブジェクト→XMLソースコード | ○ writeXML()で対応 | × 非対応 |
XML以外の形式→JSオブジェクト | × 非対応 | ○ サブクラスで各形式に対応 |
application/rdf+xml等 | △ ブラウザ依存 | ○ できるだけ対応 |
JKL.ParseXML クラスが サブクラス などの拡張で XMLHTTPRequest のラッパー用途を志向しているのに対し、 XML.ObjTree クラスは XMLHTTPRequest のラッパーは既存の他クラスに任せて、 XML コード生成も含めた XML 処理に特化したクラスとなっています。
prototype.js や他の JSAN 系クラスとの親和性は、XML.ObjTree クラスの方が高いです。
逆に、難しいこと抜きに XMLHTTPRequest も含めてシンプルに使いたい場合は
JKL.ParseXML クラスが適しているかと思われます。
トラックバックURL:http://www.kawa.net/service/tb/ajaxtb.cgi/works/js/xml/objtree.html
Kawa.netxp © Copyright 2006 Yusuke Kawasaki