JKL.ParseXMLの属性取得の使い方他

XMLJSONに変換してくれるAjax用ステキライブラリJKL.ParseXML
他のライブラリ(prototype.jsなど)に依存していないので、単体で動きます。ちなみに修正BSDライセンスだそーです。
JavaScriptは書けるけどAjax部分面倒くさい、という方にオススメ。凄く便利。
で、もちろん、JKL.ParseXMLのサイトに使い方がかなり詳しく書いてあるのですが、いかんせんアホなので、分からない部分が多い。
「こういう場合どうするんだ?」って悩んだ所を備忘録的に書いておきます。ではいきます。


使用するサンプルXMLは以下とします。ファイル名:sample.xml

<?xml version="1.0" encoding="Shift_JIS" ?>
<CS_DATA param="GAME">
  <CS_DATA1 param="MAKER_CD" code="01" name="SEGA">
    <CS_DATA1 param="HARD_CD" code="01_001" name="セガサターン"/>
    <CS_DATA1 param="HARD_CD" code="01_002" name="ドリームキャスト"/>
  </CS_DATA1>
  <CS_DATA1 param="MAKER_CD" code="02" name="SONY">
    <CS_DATA1 param="HARD_CD" code="02_001" name="プレイステーション"/>
  </CS_DATA1>
</CS_DATA>


まず属性の取得方法。

var url = "sample.xml";
var http = new JKL.ParseXML( url );
var data = http.parse();

// 全体属性(GAME)
document.write(data["CS_DATA"]["param"] + "<br><br>");
// セガ
document.write(data["CS_DATA"]["CS_DATA1"][0]["param"] + ":" 
             + data["CS_DATA"]["CS_DATA1"][0]["name"] + "<br>");
document.write(data["CS_DATA"]["CS_DATA1"][0]["CS_DATA1"][0]["param"] + ":" 
             + data["CS_DATA"]["CS_DATA1"][0]["CS_DATA1"][0]["name"] + "<br><br>");
// ソニー
document.write(data["CS_DATA"]["CS_DATA1"][1]["param"] + ":" 
             + data["CS_DATA"]["CS_DATA1"][1]["name"] + "<br>");
document.write(data["CS_DATA"]["CS_DATA1"][1]["CS_DATA1"]["param"] + ":" 
             + data["CS_DATA"]["CS_DATA1"][1]["CS_DATA1"]["name"]);

出力結果:

GAME

MAKER_CD:SEGA
HARD_CD:セガサターン

MAKER_CD:SONY
HARD_CD:プレイステーション 


よく見るとソニーだけ少し書き方が違ったりします。
セガで「セガサターン」を取得する所が、

data["CS_DATA"]["CS_DATA1"][0]["CS_DATA1"][0]["name"]

に対し、ソニーの「プレイステーション」を取得する場合は、

data["CS_DATA"]["CS_DATA1"][2]["CS_DATA1"]["name"]

になります。

どうも下階層が1つしか存在しない場合に配列展開が微妙に変わるようです。この場合は、

<CS_DATA1 param="MAKER_CD" code="02" name="SONY">
    <CS_DATA1 param="HARD_CD" code="02_001" name="プレイステーション"/>
</CS_DATA1>

と、プレイステーションの部分が1階層しかない為にこうなります。自分、ここで思いっきりハマりましたよ…。



こういった階層による微妙な違いを意識したくない場合は、全ての要素を配列展開するsetOutputArrayAll()メソッドがあります。
以下のように使います。データ構成は冗長になりますが…。

var url = "sample.xml";
var http = new JKL.ParseXML( url );
http.setOutputArrayAll(); // setOutputArrayAll()メソッド、全ての要素を配列展開
var data = http.parse();

// 全体属性(GAME)
document.write(data["CS_DATA"][0]["param"] + "<br><br>");
// セガ
document.write(data["CS_DATA"][0]["CS_DATA1"][0]["param"] + ":" 
             + data["CS_DATA"][0]["CS_DATA1"][0]["name"] + "<br>");
document.write(data["CS_DATA"][0]["CS_DATA1"][0]["CS_DATA1"][0]["param"] + ":"
             + data["CS_DATA"][0]["CS_DATA1"][0]["CS_DATA1"][0]["name"] + "<br><br>");
// ソニー
document.write(data["CS_DATA"][0]["CS_DATA1"][1]["param"] + ":" 
             + data["CS_DATA"][0]["CS_DATA1"][1]["name"] + "<br>");
document.write(data["CS_DATA"][0]["CS_DATA1"][1]["CS_DATA1"][0]["param"] + ":"
             + data["CS_DATA"][0]["CS_DATA1"][1]["CS_DATA1"][0]["name"]);

出力結果:

GAME

MAKER_CD:SEGA
HARD_CD:セガサターン

MAKER_CD:SONY
HARD_CD:プレイステーション 

これで全て同じようにかけるようになりました。
ちなみに全属性を取得する場合(入れ子過ぎますね…):

var url = "sample.xml";
var http = new JKL.ParseXML( url );
http.setOutputArrayAll(); // setOutputArrayAll()メソッド、全ての要素を配列展開
var data = http.parse();

for ( var i = 0; i < data["CS_DATA"].length; i++ ) {
    // 全体属性GAME
    document.write(data["CS_DATA"][i]["param"] + "<br><br>");

    for ( var j = 0; j < data["CS_DATA"][i]["CS_DATA1"].length; j++ ) {
        // メーカー
        document.write(data["CS_DATA"][i]["CS_DATA1"][j]["param"] + ":"
                     + data["CS_DATA"][i]["CS_DATA1"][j]["name"] + "<br>");

	for ( var k = 0; k < data["CS_DATA"][i]["CS_DATA1"][j]["CS_DATA1"].length; k++ ) {
            // ハード
            document.write(data["CS_DATA"][i]["CS_DATA1"][j]["CS_DATA1"][k]["param"] + ":"
                         + data["CS_DATA"][i]["CS_DATA1"][j]["CS_DATA1"][k]["name"] + "<br>");

	}
	document.write("<br>");
    }
}

全属性取得の出力結果:

GAME

MAKER_CD:SEGA
HARD_CD:セガサターン
HARD_CD:ドリームキャスト

MAKER_CD:SONY
HARD_CD:プレイステーション

ちなみにsetOutputArrayAll()メソッドの部分も他のメソッドに変えると他の挙動をします。
公式サイトの説明見れば分かると思うので特に書きませんが…。



あと、凄い単純なのにアホなので全く気づかなかった事を書いて終わりにします。
今まで書いたやつは全て同期モードですが、非同期モードの書き方です。サイトの説明通りに書くと、

var url = "sample.xml";
var http = new JKL.ParseXML( url );
var func = function(data) { // 呼出先関数定義
    for ( var i = 0; i < data["CS_DATA"].length; i++ ) {
        // 全体属性GAME
	document.write(data["CS_DATA"][i]["param"] + "<br><br>");

	for ( var j = 0; j < data["CS_DATA"][i]["CS_DATA1"].length; j++ ) {
            // メーカー
	    document.write(data["CS_DATA"][i]["CS_DATA1"][j]["param"] + ":"
                         + data["CS_DATA"][i]["CS_DATA1"][j]["name"] + "<br>");

	    for ( var k = 0; k < data["CS_DATA"][i]["CS_DATA1"][j]["CS_DATA1"].length; k++ ) {
                // ハード
		document.write(data["CS_DATA"][i]["CS_DATA1"][j]["CS_DATA1"][k]["param"] + ":"
                             + data["CS_DATA"][i]["CS_DATA1"][j]["CS_DATA1"][k]["name"] + "<br>");

	    }
	    document.write("<br>");
	}
    }
}
http.async( func ); // 呼出先関数指定
http.setOutputArrayAll(); // setOutputArrayAll()メソッド、全ての要素を配列展開
http.parse();

こんな感じになります。出力結果は、上の「全属性取得の出力結果」と同じね。
ただ、この書き方だと、呼出先関数定義の関数がやたら長くなった場合分かりにくい。
どうしようもないのかなぁ、と思っていたら、こう書けば良かったんですね…。

var url = "sample.xml";
var http = new JKL.ParseXML( url );
// 呼出先関数定義&指定
http.async(
    function(data) {
	for ( var i = 0; i < data["CS_DATA"].length; i++ ) {
            // 全体属性GAME
	    document.write(data["CS_DATA"][i]["param"] + "<br><br>");

	    for ( var j = 0; j < data["CS_DATA"][i]["CS_DATA1"].length; j++ ) {
                // メーカー
		document.write(data["CS_DATA"][i]["CS_DATA1"][j]["param"] + ":"
                             + data["CS_DATA"][i]["CS_DATA1"][j]["name"] + "<br>");

		for ( var k = 0; k < data["CS_DATA"][i]["CS_DATA1"][j]["CS_DATA1"].length; k++ ) {
                    // ハード
		    document.write(data["CS_DATA"][i]["CS_DATA1"][j]["CS_DATA1"][k]["param"] + ":"
                                 + data["CS_DATA"][i]["CS_DATA1"][j]["CS_DATA1"][k]["name"] + "<br>");

		}
		document.write("<br>");
	    }
	}
    }
)
http.setOutputArrayAll(); // setOutputArrayAll()メソッド、全ての要素を配列展開
http.parse();

こうすると、どの関数を実行するのかも分かりやすくなると思います。
関数定義してから指定だと、ちょっと面倒な気もしますし。


説明は以上です。ではでは。