ActionScriptによるXMLデータ処理(1) - XML読み込みと解析

Flash(ActionScript)はXMLオブジェクトやXMLSocketオブジェクトが標準装備されており、ムービー内で必要となる何らかのテキストデータをswfに読み込ませる場合や、swfとサーバーCGIとの間でデータの通信を行う際には、XML形式データを使用するのが便利である。テキストの読み込みはloadVariables関数やLoadVars オブジェクトなどを用いて行うことも可能であるが、これらはマルチバイト文字のエンコードに関して不確実性があり、問題が生じる場合がある。ここではXMLデータをURL(ファイル)またはサーバーCGIから読み込み、その解析を行うコードの実装例を紹介する。

関連項目:ActionScriptによるXMLデータ構築

XMLの読み込み

XMLを読み込むコードは次のようになる。

XMLを単純にファイル(URL)から読み込む場合

// ---- XMLの単純なロード
 infoXML = new XML();
 infoXML.ignoreWhite = true; // 改行などの空白を無視
 infoXML.onLoad = function(success) { _root.parseDataXML(success ? this : null);};
 infoXML.load("data.xml");

サーバー(CGI)にXMLデータを送信して結果のXMLを受け取る場合

// ---- XMLデータを送信して結果XMLをロード
 infoXML = new XML();
 infoResultXML = new XML();
 infoResultXML.ignoreWhite = true; // 改行などの空白を無視
 infoResultXML.onLoad = function(success) { _root.parseDataXML(success ? this : null);};
 infoXML.sendAndLoad("data.cgi", infoResultXML);

XMLが行末に改行を含む場合、それらはテキストノードデータとして扱われる。それを無視するにはignoreWhiteのプロパティをtrueに設定する。ロードは非同期に行われるため、onLoadイベントハンドラ関数を設定し、読み込み完了時に自動的にXMLデータ解析等の処理を行うように構成する。 onLoad関数内でthisはXMLオブジェクト自体を指すため、他で定義したユーザ関数を呼び出す場合は絶対パスで指定する必要がある。

XMLの解析

XMLはデータ(エレメント)が入れ子になった階層構造(ツリー構造)が特徴であるため、その解析にはスタックと再帰関数を用いるのが常套手段となる。再帰関数によってXMLの全ノードを網羅的にスキャンし、目的とする要素にたどり着いたところで必要なデータを取り込む。

// ---- XML解析
 function parseDataXML(infoXML) {
     if (!infoXML) {
         trace("XML読み込みエラー");
         return; 
     }
    // ---- データを格納する配列を用意
     this.infoData = new Array();
     this.infoActiveItem = new Array();
     // ---- ルートを起点として解析プロシージャ呼び出し
     procParseDataXML(infoXML, null); 
 }
 // ---- XML parser プロシージャ
 function procParseDataXML(infoXML, infoStack) {
     if (!infoStack) var infoStack = new Array();
     var strNodeName = infoXML.nodeName.toLowerCase();
     // ---- ノード名をスタックに積む
     infoStack.unshift(strNodeName);
     // ---- XML内でのエレメントの絶対パス取得
     var strNodePath = infoStack.join(".");
     // ---- パス(またはノード名)に応じて必要なデータを取り出す
     if (strNodePath == "item.data.") {
         // ---- データ配列に新たな要素を追加
         this.infoActiveItem = new Array();
         this.infoData.push(this.infoActiveItem);
         // ---- 属性を全て取得
         var strAttribute;
         for(strAttribute in infoXML.attributes) {
             this.infoActiveItem[strAttribute.toLowerCase()] =infoXML.attributes[strAttribute];
         }
    }
     var i;
     // ---- 子ノード解析
     for(i in infoXML.childNodes) {
         if (infoXML.childNodes[i].nodeType == 3) {
             // ---- テキストノード
             this.infoActiveItem[infoStack[0]] += infoXML.childNodes[i].nodeValue;
         }
         else {
             //---- エレメント(関数の再帰呼び出し)
             procParseDataXML(infoXML.childNodes[i], infoStack);
         }
     } 
     // ---- スタックから取り出し&破棄
     infoStack.shift();
 }

再帰関数を用いる方法は単に数行程度の短いXMLデータを読み込む場合に用いるには、やや冗長な印象もあるが、XMLのノード構成にあわせて解析部をハードコーディングした場合はXMLの構造変化の度にコードを書き換える必要があるのに対し、この方法であればXMLのノードの構成がどんなに変更されても同じコードで対応できる。また、どんなに長いXMLデータでもこの関数一つで処理できるのが利点である。