警告: E4X は非推奨です。E4X は content に対して Firefox 16 からデフォルトで無効に、chrome に対して Firefox 17 からデフォルトで無効に、そして Firefox 18 で削除される予定です。代替として、DOMParser/DOMSerializer または 非ネイティブの JXON アルゴリズムを使用してください。
警告: この記事の内容は古くなっている可能性があります。 最終更新日は 2010 年 11 月 12 日です。英語版の最新の内容も合わせてご覧下さい。
JavaScript 1.6 で導入
JavaScript 1.6 で初めて導入された E4X により、JavaScript 言語にネイティブ XML オブジェクトが導入され、さらに XML 文書リテラルを JavaScript コードに埋め込むための構文も追加されています。
E4X の完全な定義は Ecma-357 仕様 でなされています。この章では実用的な概要を示します。完全なリファレンスではありません。
互換性の問題
<script>
要素のサポートがブラウザの間で広く普及する前は、JavaScript をページに埋め込むときに HTML コメントタグで囲むことで、<script>
を知らないブラウザが JavaScript コードをそのまま表示してしまうのを防ぐということが一般的でした。この慣習はもう不要ですが、古いコードでは残っていることがあります。後方互換性のため、E4X はコメントや CDATA セクションを無視するのがデフォルトの動作です。e4x=1
引数を <script>
タグに加えることでこの制限を無効にできます。
<script type="text/javascript;e4x=1"> ... </script>
XML オブジェクトの作成
E4X には XML オブジェクトを作成する方法が 2 つあります。1 つ目は XML
コンストラクタに文字列を渡す方法です。
var languages = new XML('<languages type="dynamic"><lang>JavaScript</lang><lang>Python</lang></languages>');
2 つ目はスクリプトに XML を XML リテラルとして直接埋め込むことです。
var languages = <languages type="dynamic"> <lang>JavaScript</lang> <lang>Python</lang> </languages>;
どちらの場合も結果として得られるオブジェクトは E4X XML オブジェクトです。これには内部データにアクセスしたりそれを変更したりするための便利な構文が備わっています。
XML オブジェクトは通常の JavaScript オブジェクトのように見え、そのような挙動をとりますが、その 2 つは同じものではありません。E4X では E4X XML オブジェクトにおいてのみ動作する新たな構文が導入されています。その構文は JavaScript プログラマにとって取っつきやすいように設計されていますが、E4X では XML からネイティブ JavaScript オブジェクトへの直接のマッピングが用意されていません。そう見えるだけです。
属性の操作
上記の例を実行すると変数 languages は XML 文書の <languages>
に対応する XML オブジェクトへの参照となります。このノードには type という 1 つの属性があり、それにアクセスしたり、それを変更したりする方法はいくつもあります。
alert(languages.@type); // "dynamic" というアラート languages.@type = "agile"; alert(languages.@type); // "agile" というアラート
alert(languages.toString()); /* アラート: <languages type="agile"><lang>JavaScript</lang><lang>Python</lang></languages> */
XML オブジェクトの操作
XML オブジェクトにはその中身を検査したり変更するためのメソッドがたくさん用意されています。それらは JavaScript の通常のドットや []
という記法をサポートしていますが、オブジェクトのプロパティにアクセスするのではなく、E4X ではその要素の子にアクセスするための演算子として定義されています。
var person = <person> <name>Bob Smith</name> <likes> <os>Linux</os> <browser>Firefox</browser> <language>JavaScript</language> <language>Python</language> </likes> </person>; alert(person.name); // Bob Smith alert(person['name']); // Bob Smith alert(person.likes.browser); // Firefox alert(person['likes'].browser); // Firefox
複数の要素がマッチするようなものにアクセスすると XMLList
が返されます。
alert(person.likes.language.length()); // 2
DOM と同様に *
を使うことですべての子ノードにアクセスすることができます。
alert(person.likes.*.length()); // 4
.
演算子は与えられたノードの直接の子にアクセスしますが、..
演算子はネストの深さにかかわらずすべての子にアクセスします。
alert(person..*.length()); // 11
この場合、length()
メソッドは 11 を返します。結果として得られる XMLList
には要素とテキストノードがともに含まれるためです。
XML 要素を表すオブジェクトには便利なメソッドがたくさん用意されています。そのうちのいくつかを以下に示します。 TODO: Add all of the methods to the JavaScript reference, link from here
alert(person.name.text()) // Bob Smith var xml = person.toXMLString(); // XML からなる文字列 var personCopy = person.copy(); // XML オブジェクトのディープコピー var child = person.child(1); // 2 番目の子ノード:この場合は <likes> 要素
XMLLists の操作
XML オブジェクトに加えて、E4X では XMLList
オブジェクトが導入されています。XMLList
は XML オブジェクトの順序付きの集まりを表します。例えば、要素のリストです。上記の例に続き、次のようにすると <lang>
要素の XMLList
にアクセスすることができます。
var langs = languages.lang;
XMLList
には格納している要素数を知るための length()
メソッドがあります。
alert(languages.lang.length());
JavaScript の配列とは違い、length はプロパティではなくメソッドであり、必ず length()
として呼び出さなければならないことに注意してください。
次のようにしてマッチする要素について繰り返すことができます。
for (var i = 0; i < languages.lang.length(); i++) { alert(languages.lang[i].toString()); }
ここでは配列のアイテムに順にアクセスするときと全く同じ構文を使っています。このように通常の配列に似ているにもかかわらず、XMLList
は forEach
のような Array
のメソッドをサポートしていません。また、Array.forEach()
のような Array のジェネリックスも XMLList
オブジェクトとは互換性がありません。
JavaScript 1.6 で JavaScript の E4X サポートの一部として導入された for each...in 文 を使うこともできます。
for each (var lang in languages.lang) { alert(lang); }
for each...in
は通常の JavaScript のオブジェクトについて使うと、そのオブジェクトに含まれる値(キーではなく)に対して繰り返すこともできます。for...in と同様、配列について使用するのは 全く推奨できません。
整形式の XML を文書を作らずとも、次のような XML リテラル構文を用いて XMLList
を作ることができます。
var xmllist = <> <lang>JavaScript</lang> <lang>Python</lang> </>;
+=
演算子を使うと文書内の XMLList
に要素を新たに追加することができます。
languages.lang += <lang>Ruby</lang>;
通常の DOM メソッドで返されるノードリストとは異なり、XMLList
は静的であり、DOM 内の変更が自動的には反映されません。既存の XML
オブジェクトのサブセットとして XMLList
を作成し、その後オリジナルの XML
を変更した場合、XMLList
にはその変更が反映されません。最新の状態にするには作り直す必要があります。
var languages = <languages> <lang>JavaScript</lang> <lang>Python</lang> </languages>; var lang = languages.lang; alert(lang.length()); // 2 というアラート languages.lang += <lang>Ruby</lang>; alert(lang.length()); // やはり 2 というアラート lang = languages.lang; // XMLList を作り直す alert(lang.length()); // 3 というアラート
検索とフィルタ
E4X には特定の基準にマッチする文書内のノードを選択するための特別な演算子が用意されています。このようなフィルタ演算は丸括弧で囲んだ式で指定します。
var html = <html> <p id="p1">First paragraph</p> <p id="p2">Second paragraph</p> </html>; alert(html.p.(@id == "p1")); // "First paragraph" というアラート
式の手前のパスにマッチするノード(この場合は p 要素)は式が評価される前にスコープチェーンに追加されます。with 文 を使ってノードが指定されているかのような動作です。
したがって、フィルタは現在の要素内の単一ノードの値に対しても実行することができます。
var people = <people> <person> <name>Bob</name> <age>32</age> </person> <person> <name>Joe</name> <age>46</age> </person> </people>; alert(people.person.(name == "Joe").age); // 46 というアラート
フィルタ式に JavaScript 関数を使うこともできます。
function over40(i) { return i > 40; } alert(people.person.(over40(parseInt(age))).name); // Joe というアラート
名前空間の処理
E4X は名前空間を考慮しています。ノードや属性を表すあらゆる XML オブジェクトには QName
オブジェクトを返す name()
メソッドがあり、名前空間要素を簡単に検査することができます。
var xhtml = <html xmlns="https://www.w3.org/1999/xhtml"> <head> <title>Embedded SVG demo</title> </head> <body> <h1>Embedded SVG demo</h1> <svg xmlns="https://www.w3.org/2000/svg" viewBox="0 0 100 100"> <circle cx="50" cy="50" r="20" stroke="orange" stroke-width="2px" fill="yellow" /> </svg> </body> </html>; alert(xhtml.name().localName); // "html" というアラート alert(xhtml.name().uri); // "https://www.w3.org/1999/xhtml" というアラート
名前空間内にある要素にアクセスするには、まずその名前空間についての URI を格納した Namespace
オブジェクトを作ります。
var svgns = new Namespace('https://www.w3.org/2000/svg');
すると、通常の要素指定子の代わりに namespace::localName
の形式で E4X クエリに使用することができます。
var svg = xhtml..svgns::svg; alert(svg); // 文書の <svg> 部分が表示される