目次


JavaScript を強化した E4X

JavaScript E4X を使用して効率的に XML を処理する

Comments

E4X は、JavaScript プログラミング言語に XML のサポートを追加したものです。XML は、アプリケーションやプラットフォーム間で文書およびデータを交換する上で普遍的に受け入れられる手段として、広く認知されています。この認知度の高さは、これまで文書やデータの共有に伴う相互運用性の問題を効率よく解決してきた XML の折り紙付きの実績が、そのまま反映されたものです。XML の多用途性と強力さは、その構成要素の柔軟性の産物です。E4X は XML の構成要素を使いやすくすることで、XML の柔軟性を大いに高めます。

XML に対応した JavaScript コードを作成するというタスクを単純化するために設計された E4X は、XML のノードおよび属性を操作するために使用できる効率的かつ強力なツールです。E4X の第一の目的は、DOM (Document Object Model) に頼らずに、簡潔で効率的に XML 文書を操作する手段を JavaScript 開発者に提供することです。

JavaScript 言語では、E4X ユーティリティーを使用して新しいプロパティーをグローバル・オブジェクトに知らせます。一方、XML オブジェクトにも、E4X のシリアライズおよび構文解析の関数で役立ついくつかのプロパティーがあります。E4X は既存の JavaScript 演算子の多くを再利用し、これらの演算子を XML の作成、操作、ナビゲーションに使用します。

E4X では、開発にかかる時間が短縮され、学習曲線も非常に短いものとなります。こうした E4X の特徴のおかげで、効率的で容易な読み取りや書き込みなどの操作が後押しされするとともに、無駄が省かれることにより、コーディング作業の単純化やコードの改修作業の強化、さらにはコード・デプロイメント・サイクルの短縮化がもたらされます。その上、柔軟でアジャイルな E4X 技術は、ますます重要性を増してきているモバイル・アプリケーションにもぴったりです。

E4X の威力と柔軟性を明らかにするため、この記事では、XML データを操作するために採用されている主要な機能を説明します。主な入力ソースとして使用するのは、音楽カタログです。この記事に記載するサンプルのほとんどは、リスト 1 の XML 文書をベースとしています。

リスト 1. ほとんどのサンプルで使用する XML の music オブジェクト
<mp3>
   <music genre="classical">
      <artist>Ludwig van Beethoven</artist>
      <song>Fifth Symphony</song>
   </music>
   <music genre="jazz">
      <artist>Grover Washington, Jr.</artist>
      <song>The Best Is Yet to Come</song>
   </music>
   <music genre="classical">
      <artist>Johann Sebastian Bach</artist>
      <song>Double Concerto in D- for Two Violins</song>
   </music>
   <music genre="jazz">
      <artist>Dave Brubeck</artist>
      <song>Take Five</song>
      <song>Truth Is Fallen</song>
   </music>
   <music genre="classical">
      <artist>Johannes Brahms</artist>
      <song>Piano Sonata No. 1 in C major</song>
   </music>
</mp3>

XML オブジェクトの作成

それぞれのプロセスで最初のステップとなるのは、XML オブジェクトを作成することです。E4X には、XML 要素を保持する XML() という型が用意されています。新しい XML オブジェクトを作成するには、リスト 2 に記載する、JavaScript 開発者にはすでにお馴染みのフォーマットを使用します。

リスト 2. XML オブジェクトの作成
      var xmlMusic = new XML() ;

XML オブジェクトが作成できると、XML 文書をロードできるようになります。E4X では、XML オブジェクトを作成する方法として 2 つの E4X 方式を推奨しています。最初に説明するのは、オブジェクトを作成してから、そのオブジェクトをロードするという方式です。その方法をリスト 3 に示します。

リスト 3. XML オブジェクトのロード方式 1
<script type="text/javascript ; e4x=1">

   var xmlMusic=new XML() ;
   xmlMusic = <mp3>
      <music genre="classical">
         <artist>Ludwig van Beethoven</artist>
         <song>Fifth Symphony</song>
      </music>
      <music genre="jazz">
         <artist>Grover Washington, Jr.</artist>
         <song>The Best Is Yet to Come</song>
      </music>
      <music genre="classical">
         <artist>Johann Sebastian Bach</artist>
         <song>Double Concerto in D- for Two Violins</song>
      </music>
      <music genre="jazz">
         <artist>Dave Brubeck</artist>
         <song>Take Five</song>
         <song>Truth Is Fallen</song>
      </music>
      <music genre="classical">
         <artist>Johannes Brahms</artist>
         <song>Piano Sonata No. 1 in C major</song>
      </music>
   </mp3>

</script>

もう一方の方式では、リスト 4 に示すように、要素を作成するときに XML 文書をストリングとしてその要素にロードします。

リスト 4. XML オブジェクトのロード方式 2
<script type="text/javascript ; e4x=1">

   var xmlMusic=new XML('<mp3><music genre="classical">
              <artist>Ludwig van Beethoven</artist>
              <song>Fifth Symphony</song></music>
              <music genre="jazz"><artist>Grover Washington, Jr.</artist>
              <song>The Best Is Yet to Come</song>
              </music><music genre="classical">
              <artist>Johann Sebastian Bach</artist>
              <song>Double Concerto in D- for Two Violins</song></music>
              <music genre="jazz"><artist>Dave Brubeck</artist>
              <song>Take Five</song><song>Truth Is Fallen</song>
              </music><music genre="classical">
              <artist>Johannes Brahms</artist>
              <song>Piano Sonata No. 1 in C major</song>
              </music></mp3>');

</script>

script タグ内に追加された e4x=1 という式に注目してください。E4X は XML を JavaScript オブジェクトに構文解析するために広く使用されていますが、XML 構文を直接使用すると問題が発生する可能性があります。つまり、他のタグ・ベースの環境に組み込むと、予期せぬ問題を生じる可能性があるのです。例えば、HTML では、非互換ブラウザーでスクリプトが表示されないようにするために許容されている方法と E4X が競合します。Mozilla Firefox バージョン 1.5 ではこの問題を踏まえ、HTML ページでは E4X が無効になるようにデフォルト設定されます。この問題を回避するための方法としては、E4X を使用するときには必ず、上記のように script タグ内に type="text/javascript; e4x=1" という形で属性を指定するようにします。

XML オブジェクトは見かけも振る舞いも通常の JavaScript オブジェクトと同様ですが、まったく同じというわけではありません。一部の E4X 構文は、E4X の XML オブジェクトでしか機能しないからです。構文は JavaScript 開発者にお馴染みのものですが、E4X は XML から直接ネイティブ JavaScript オブジェクトにマッピングしやすくするわけではありません。直接マッピングされていると錯覚させているのです。

データへのアクセス

XML オブジェクトは、通常の JavaScript プログラミングで使用するドット (.) および大括弧 ([]) 表記をサポートします。E4X はオブジェクト・プロパティーにアクセスするのではなく、これらの演算子をオーバーロードして、要素の子にアクセスするために使用します。

以下のアクセス例がベースとするのは、上記で作成した xmlMusic オブジェクトです。まず、要素全体のコンテンツを表示するには、リスト 5 の構文を使用します。

リスト 5. 要素の全コンテンツの表示
document.write(xmlMusic);

このステートメントによる出力を以下に記載します。

Ludwig van Beethoven   Fifth Symphony
Grover Washington, Jr. The Best Is Yet to Come
Johann Sebastian Bach Double Concerto in D- for Two Violins
Dave Brubeck Take Five Truth Is Fallen
Johannes Brahms Piano Sonata No. 1 in C major

3 番目のアーティストを調べるには、リスト 6 のようなステートメントを入力します。

リスト 6. 3 番目のアーティストの表示
document.write ( xmlMusic.music[2].artist );

このステートメントによる出力は以下のとおりです。

Johann Sebastian Bach

注: E4X はゼロを基準とするため、3 番目のレコードを取得するために使用するインデックスの値は 2 となります。

1 番目の music ノードのすべてのコンテンツを取得するには、リスト 7 のステートメントを入力することになります。

リスト 7. 1 番目の music ノードの取得
document.write (xmlMusic.music[0].*);

このステートメントによる出力は以下のとおりです。

Ludwig van Beethoven  Fifth Symphony

上記のほんのわずかな例を見ただけでも、E4X を使用すると、至って簡単に XML ノードにアクセスできることがわかるはずです。

属性へのアクセス

XML オブジェクトの属性にアクセスするには、アットマーク記号 (@) を使用します。属性の操作は、XML データの操作のなかでは特に難しい部分になる可能性がありますが、E4X を使用すれば、このタスクが極めて簡単になります。例えば、クラシックのジャンルからすべてのデータを取得するには、リスト 8 のステートメントを入力します。

リスト 8. ノード属性へのアクセス
document.write(xmlMusic.music.(@genre==”classical”) );

このステートメントによる出力は以下のようになります。

Ludwig van Beethoven Fifth Symphony
Johann Sebastian Bach Double Concerto in D- for Two Violins
Johannes Brahms Piano Sonata No. 1 in C major

また、クラシックのジャンルに含まれるアーティストの名前だけを要求する場合は、リスト 9 のステートメントを入力します。

リスト 9. クラシックのアーティスト名の要求
document.write(xmlMusic.music.(@genre=="classical").artist );

上記のステートメントによって、以下のように名前だけが出力されます。

Ludwig van Beethoven
Johann Sebastian Bach
Johannes Brahms

このように、E4X の威力、柔軟性、単純さは明らかです。もはや、操作するのが難しいからという理由だけで、属性を使用しないようにする必要はありません。これまでの例から一目瞭然のとおり、E4X では属性でも難なく処理することができます。

子オブジェクトの追加

E4X では、単純な JavaScript 表記を使って、既存の要素に子要素を追加することができます。既存のアーティストに作品を追加する一例として、Johann Sebastian Bach (ヨハン・セバスティアン・バッハ) に Brandenburg Concertos (ブランデンブルグ協奏曲) を追加するには、リスト 10 のように「+=」演算子を使用します。

リスト 10. 「+=」演算子によるノードの追加
xmlMusic.music[2].song += "Brandenburg concertos" ; 
document.write (xmlMusic.music[2]);

ノードが追加されると、出力は以下のようになります。

Johann Sebastian Bach
Double Concerto in D- for Two Violins
Brandenburg Concertos

このステートメントを実行する以前の xmlMusic オブジェクトには 1 つの作品しかありませんでしたが、これで、バッハの作品は 2 つになりました。

子オブジェクトのコンテンツの変更

要素あるいは属性の値を変更するには、リスト 11 のように新しい値を割り当ててください。

リスト 11. 「=」演算子によるノードの変更
xmlMusic.music[3].song = "Pick Up Sticks" ;
document.write ( xmlMusic.music[3] );

上記による出力は以下のとおりです。

Dave Brubeck
Pick Up Sticks

注: 等号 (=) を使用して xmlMusic.music[3].song のコンテンツを置き換えたため、Dave Brubeck (デイヴ・ブルーベック) の作品が上書きされて新しいエントリーだけが残っています。

子ノードの削除

子ノードを削除するには、リスト 12 のように delete 文を使用することができます。

リスト 12. 子ノードの削除
delete xmlMusic.music.song[1] ;
document.write (xmlMusic.music[1].*);

上記による出力は以下のとおりです。

Grover Washington, Jr.

該当する song ノードは削除されていますが、artist ノードは残っています。

フィルタリング

E4X が提供する特殊なフィルタリング演算子 (括弧) を使用すると、文書内で、一定の基準に合致するノードを選択することができます。このフィルタリング演算子は、条件をデータに適用して、要求された要素を子ノードから取り出します。フィルタリング演算子は、括弧で囲まれた式に基づいて実行されます。実は、この演算子は記事のなかですでに目にしているはずですが、ここで改めて紹介させてください。

リスト 13 は、属性をフィルタリングする場合の一例です。

リスト 13. 属性によるデータのフィルタリング
 document.write (xmlMusic.music.(@genre=="jazz") );

フィルタリングされた出力は以下のようになります。

Grover Washington, Jr. The Best Is Yet to Come
Dave Brubeck Take Five Truth Is Fallen

属性ではありませんが、artist を基準にフィルタリングすることもできます。リスト 14 はその例です。

リスト 14. アーティスト名による作品の検索
document.write (xmlMusic.music.(artist == "Dave Brubeck").song);

フィルタリング後の出力は、以下のようになります。

Take Five
Truth Is Fallen

XMLList の操作

E4X が認識する基本的な型は、XML()XMLList() です。XMLList オブジェクトは、XML プロパティーの順序付きコレクションを表します (例えば、レシピ、大陸、電話番号、あるいは化学元素などのリスト)。複数のノードで構成される E4X オブジェクトは、実際には XML() オブジェクトと XMLList() オブジェクトの組み合わせからなります。XMLList 型は、クエリーを作成する上で非常に貴重なツールで、例えば特定のノードの子を検索するときには XMLList が生成されます。

music オブジェクトを例にすると、複数のノードで構成された XMLList の大まかな構造は、以下のコードのようになります。

<music></music>
<music></music>
<music></music>
<music></music>
<music></music>

XMLList には初期化子があります。初期化子とは、XMLList オブジェクトの初期設定を記述する式のことです。XMLList 初期化子は、XML プロパティーの構造化リストを表現し、要素名が記されない XML 要素構文を使用します。初期化子は <> で始まり、</> で終わります。リスト 15 のコード・シーケンスは、XMLList オブジェクトを初期化する際に使うことができる方法の一例です。

リスト 15. XMLList オブジェクトの初期化
var xmlListObject = 
     <><artist>Ludwig van Beethoven</artist> <song>Fifth Symphony</song></>;

XML オブジェクトと XMLList オブジェクトとでは何が違うのかと言えば、基本的に、XML 型は複数の子ノードを含められる 1 つの特定オブジェクトを扱う一方、XMLList が扱うのは、1 つ以上の XML オブジェクトからなる 1 つのセットであるという点です。

E4X は、単一の XML オブジェクトと、1 つの項目を持つ XMLList との違いが実質的に見分けが付かなくなるように設計されています。そのため、XML の値と、単一の項目を持つ XMLList の値との違いは、さして重要ではありません。

計算の実行

E4X では、XML での場合とまったく同じように XML データに関する計算をすることができます。例えば、数学的に操作できるデータが含まれる新しい XML 文書を使用することになったとします。この XML 文書をリスト 16 に記載します。

リスト 16. 計算の例
<script type="text/javascript ; e4x=1">
 
   var xmlCatalog=new XML() ;
   xmlCatalog=<inventory>
      <item genre="apparel">
         <description>Dress</description>
         <price>50.00</price>
         <quantity>3</quantity>
      </item>
      <item genre="accessory">
         <description>Hat.</description>
         <price>25.00</price>
         <quantity>5</quantity>
      </item>
      <item genre="apparel">
         <description>tie</description>
         <price>15.00</price>
         <quantity>7</quantity>
      </item>
      <item genre="accessory">
         <description>Belt</description>
         <price>15.00</price>
         <quantity>1</quantity>
      </item>
      <item genre="apparel">
         <description>Suit</description>
         <price>100.00</price>
         <quantity>2</quantity>
      </item>
   </inventory>

</script>

以下に記載しているのは、このデータを操作するスクリプトです。While ループを使用して、在庫を合計した値段とともに、現時点で在庫にある商品の合計数を計算します。リスト 17 では、XML オブジェクトのサイズを決定してループを制御するために、length() メソッドを使用しています。

リスト 17. E4X による計算の実行
<script type="text/javascript ; e4x=1">

   var i = 0 ;
   var totItems=0 ;
   var totInventoryValue=0 ;

   while ( i < xmlCatalog.item.length()  )
     {
       totInventoryValue  += xmlCatalog.item[i].quantity *
       xmlCatalog.item[i].price ;
       totItems+= xmlCatalog.item[i].quantity * 1 ;
       i = i + 1 ;
     }
  
   document.write ("Total number of items: " + totItems + "<p>");  
   document.write ("Total inventory value: $" + totInventoryValue + "<p>");

</script>

このスクリプトによる出力は以下のとおりです。

Total number of items: 18
Total inventory value: $595

XMLObject メソッドの使用

E4X では、XML オブジェクトならびに XMLList オブジェクトを操作するための一連のメソッドを提供しています。その一例として、リスト 17 のスクリプトでは、フローを制御するのに length() メソッドを使用した場合、このメソッドがどう機能するのかを調べました。E4X メソッドは、属性、名前空間、要素の識別から子要素の追加、識別に至るまで、さまざまなタスクを実行することできます。

前述したように、E4X は単一の XML オブジェクトと、サイズの値が 1 の XMLList との違いをあいまいにするように設計されています。そのため、XML オブジェクトに使用できるメソッドは、適切なサイズの XMLList オブジェクトにも同じく使用できます。

表 1 に、XML および XMLList オブジェクトに使用可能なメソッドを記載します。記載されたメソッドはすべて、XML オブジェクトに使用できます。「」と示されてリストされているメソッドは、XML オブジェクトと XMLList オブジェクトの両方に使用できるものです。

表 1. XML および XMLList オブジェクトに使用可能なメソッド

XML オブジェクトのメソッド

XMLList オブジェクトへの適用

XML object methods

Available
to XMLList objects
addNamespace(namespace)不可name()不可
appendChild(child)不可namespace([prefix])不可
attribute(attributeName)namespaceDeclarations()不可
attributes()nodeKind()不可
child(propertyName)normalize()
childIndex()不可parent()
children()processingInstructions([name])
comments()prependChild(value)不可
contains(value)removeNamespace(namespace)不可
copy()replace(propertyName, value)不可
descendants([name])setChildren(value)不可
elements([name])setLocalName(name)不可
hasComplexContent()setName(name)不可
hasSimpleContent()setNamespace(ns)不可
inScopeNamespaces()不可text()
insertChildAfter(child1, child2)不可toString()
insertChildBefore(child1, child2)不可toXMLString()
length()valueOf()
localName()不可

リスト 10 では、+= 演算子を用いて xmlMusic オブジェクトに song ノードを追加しました。appendChild() メソッドを使用しても、同じ出力を生成することができます。appendChild() を使った場合、ノードを既存のオブジェクトまたは要素の最後に追加することできます。この機能を説明するため、リスト 18 に、リスト 10 で実行した処理を繰り返します。ただし、ここでは += 演算子の代わりに appendChild() メソッドを使用しています。

リスト 18. appendChild() メソッドによるノードの追加
xmlMusic.music[2].appendChild(<song>Brandenburg Concertos</song>) ; 
document.write (xmlMusic.music[2].*);

This code generates the output:

 Johann Sebastian Bach
Double Concerto in D- for Two Violins
Brandenburg Concertos

以下は、このコードが生成する出力です。

ご覧のように、この出力では XMLList オブジェクトの 3 番目の要素に作品が追加され、リスト 10 に記載したコードと同じ出力結果となっています。

ノードを追加するには、prependChild() メソッドを使うという方法もあります。prependChild() は、指定された要素の子ノードの前にノードを追加するメソッドです。prependChild() メソッドを使用して同じバッハの協奏曲、Brandenburg Concertos を追加するリスト 19 のコードは、この作品を現行の作品リストの最後にではなく、先頭に配置します。

リスト 19. prependChild() メソッドによるノードの追加
xmlMusic.music[2].song[0].prependChild(<song>Brandenburg Concertos</song>) ;
document.write (xmlMusic.music[2].*);

出力を見るとわかるように、元からあった song ノードの前に協奏曲が挿入されています。

 Johann Sebastian Bach
Brandenburg Concertos
Double Concerto in D- for Two Violins

insertBefore() メソッドを使用した場合には、既存の 2 つのノードの間にノードを挿入することができます。リスト 20 で操作するのは、2 つの作品が含まれる Dave Brubeck のデータです。insertBefore() メソッドを用いて、現行の song ノードの間に作品、「Eleven Four」を配置します。

リスト 20. insertBefore() メソッドによるノードの追加
xmlMusic.music[3].insertChildBefore(xmlMusic.music[3].song[1],<song>Eleven Four</song>);
document.write (xmlMusic.music[3].*);

以下は、このコードが生成する出力です。

  Dave Brubeck
Take Five
Eleven Four
Truth Is Fallen

さらに、オブジェクトに含まれる属性を識別する attributes() というメソッドもあります。一例として、xmlMusic オブジェクトの属性をすべて表示するには、リスト 21 のコードを使用します。

リスト 21. attribute() メソッドによる属性の識別
document.write (xmlMusic.music.attributes());

以下のように、このメソッドは xmlMusic オブジェクトに含まれるすべての属性を出力します。

 classical
jazz
classical
jazz
classical

attributes() メソッドを使用すると、ジャンルが jazz に指定されたすべての要素を識別することができます。リスト 22 のコードでは、length() メソッドの助けを借りて、jazz 属性を持つすべてのノードを出力します。

リスト 22. 属性が jazz に指定された要素の識別
   var i = 0 ;

   while ( i < xmlMusic.music.length()  )
     {
       if ( xmlMusic.music[i].attributes() == "jazz"  ) {
	   document.write (xmlMusic.music[i].* + "<p>");
	   }
       i = i + 1 ;
     }

以下は、このコードが生成する出力です。

Grover Washington, Jr. The Best Is Yet to Come
Dave Brubeck Take Five Truth Is Fallen

E4X メソッドは演算子と同様に、XML データを処理するための単純なメカニズムとなります。

ブラウザーとの互換性

E4X は、XML データを操作するための最も単純で簡単な手段の 1 つですが、ブラウザーによってはサポートされない場合もあります。現在、Windows® Internet Explorer® では E4X をサポートしていません。一方、Mozilla Firefox、そしてオープンソースの Rhino JavaScript 技術をベースとしたシステムでは、E4X をサポートしています。

まとめ

この短い記事からおわかりのように、E4X で操作することによって、XML を操作する際に必要となる作業は簡易化されます。JavaScript 開発者が XML データを処理する上で大きな障害となっていたのは、手軽に、そして効率的に XML データを操作する手段がなかったことです。JavaScript は極めて単純でしっかりと体系付けられたスクリプト言語です。この言語に E4X 拡張が加わった JavaScript E4X は、データ操作に関する重大な問題に対する打開案となるはずです。ぜひ、試してみてください。


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


関連トピック


コメント

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

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=XML
ArticleID=328996
ArticleTitle=JavaScript を強化した E4X
publish-date=07152008