jQueryのAjaxでxmlをパースする

xmlのパースは今までphpのsimple_xmlみたいなものを使ってきましたが、なかなかこれだけでは仕事にならないというのもあって、最近はAjaxで処理してしまうという頻度が非常に増えています。実際はHTMLに吐き出される情報がローカルのみなのでHTMLソース時代には何も書かれていないというのが、問題なんだか問題じゃないんだか、むしろその方がいいのか...って話ですが、いわゆる素人さんにはそんなこと全然関係なくて、ただただ見てくれがいいという問題が最終的な落とし所になるので、Ajaxでいいじゃないかということになります。

$.ajaxメソッドを使う

 jQueryでxmlをパースするときは、$.ajaxメソッドを使います。かなり楽チンです。このメソッドはjQueryのプラグインみたいに使える(というか、Pluginはメソッドなのですが)ので、適当なオプションを与えるだけでかなり簡単に使えます。
 

$.ajax({
    url: "http://www.omnioo.com/ajax_xml/info.xml",
    async: true,
    cache: false,
    dataType:"xml",
    error: function(){
        alert('Error loading XML document');
    },
    success: function(xml){
        //ここでパースする
    }
});


 全体的にはこんな感じです。というかこれだけです。

オプション

 
$.ajaxのプロパティーにいろんなオプションを設定できます。とても便利です。
url: 
xmlのURLを書きます。 httpからはじまるURLでリモートでXMLファイルにアクセスできる他、普通に相対パスも指定できます。

url: "http://www.omnioo.com/ajax_xml/info.xml",
あるいは、
url: "../ajax_xml/info.xml",

というような書き方ができます。

async:
 これは同期するかしないかというオプションです。ブール値(true/false)で設定します。同期するとブラウザーはxmlが更新されると自動的に読みにいって同期します。非同期にするとブラウザーが明示的にxmlの値を取りにゆくまで(リロードとかするまで)データを取得しません。チャットみたいなものだと同期(true)、phpとかperl的なサーバーサイドスクリプト的な動きだと非同期(false)ということになります。問題がなければ通常trueでよいです。

cache:
 これもブール値で通信結果をキャシュするかしないかを設定します。通信が貧弱な環境ではキャッシュを使うのもよいでしょうけど、現在のような強力なインフラがある状況下では殆ど必要ないです。falseでいいです。

dateType:
 日付の取得をどうやってするかを決めます。面倒な方は省略してください。自動的に取得されます。上記ではxmlから日付を引っ張ってくる設定です。xmlのパースなのでxmlとしておいてよいでしょう。実際に詳細に設定したい場合は、きちんとしたドキュメント読んだ方がいいです。詳細はここでは割愛。

error:
 通信ができなかった時実行されます。書いておいた方がいい時もありますが、邪魔になる時もあります。アラートじゃなくて代用の作業を書いておく方がいいかもです。私はjQueryで適当な場所に書き出すようにしています。

success:
 実際にxmlをパースする関数を定義してゆきます。つまり通信が成功したときの作業を書きます。ここがコアになる部分です。

xmlをパースする(アトリビュート)

 xmlの解析はeachでループさせてやります。xmlは構造上ネストしてあるので一番上の階層から順番にだぐってゆけばいいです。ここでは、
<?xml version="1.0" encoding="utf-8" ?>
<data update="5月17日(火)">
    <game status="9:00" location="札幌">
        <top score="1" team="赤" />
        <bottom score="2" team="白" />
        <vote>3837</vote>
    </game>
    <game status="10:00" location="大阪">
        <top score="7" team="青" />
        <bottom score="8" team="緑" />
        <vote>7463</vote>
    </game>
    <game status="12:00" location="東京">
        <top score="9" team="黄色" />
        <bottom score="10" team="紫" />
        <vote>8324</vote>
    </game>
    <game status="15:00" location="博多">
        <top score="11" team="黒" />
        <bottom score="12" team="橙" />
        <vote>2764</vote>
    </game>
</data>

というような適当なxmlをパースします。

eachを使ってループして取り出す

eachの使い方はご存知でしょうか?jQueryでのループは十中八九eachでやります。
$(xml).find('game').each(function(i){
//ここでいろいろやる。
});
 まずは、xmlをセレクタとして、gameを探します。gameにたどり着いたらgame内をループして洗い出すという寸法です。iは必要ないです。ここでは取り出した順番がわかるように入れておいてあげます。

アトリビュートの値を取り出す

 ここから先はいろんなやり方があるのですが、ここではかなり単純化して値を取り出します。

[script]
$(xml).find('game').each(function(i){
    var status_value = $(this).attr('status');
    $("#date").append(status_value);
}
[html][/html]
<div id="date"><div>
 statusを探して時間を取得しています。gameの中(this)のアトリビュートなのでattrで取得しています。ループで複数の値を取るのでappendでどんどん後ろに追加してゆきます。
$("#date").append(status_value+':');
とか区切り文字を入れた方がわかりやすいかもです。配列に格納したりいろいろできるので用途によって書き分けてください。
 これらを繰り返してゆくと、ネストされた値もそれぞれ同様に取り出せます。
var team_top = $(this).find('top').attr('team');

 これは、game(this) > topのアトリビュートのteamの値を取り出します。


$(xml).find('game').each(function(i){

    var status_value = $(this).attr('status');
    $("#date").append(status_value);

    var team_top = $(this).find('top').attr('team');
    $("#team1").append(team_top);

    var team_bottom = $(this).find('bottom').attr('team');
    $("#team2").append(team_bottom);
  
    //...
}

というような感じです。

xmlをパースする(タグ内の値)

 普通にXMLの値を取り出すには、findメソッドとtextメソッドを使って取り出します。私はtextメソッドを使うのを忘れて結構大変な目にあったのでご注意。

$(xml).find('game').each(function(i){

    var vote_value = $(this).find('vote').text();
    $("#vote").append(vote_value);
    //...
}

$(this).find(<対象のタグ>).text();というようにメソッドチェーンで最後にテキストで取り出すのが正解です。これでテキストとして取り出せますが、$(this).find(<対象のタグ>);で取り出すと、一見テキストで取り出せたように見えますが、数値計算などする時にparseInt()にかけると、[Object object]という謎の値が入ってきます。更に強引にparseInt()して計算するとNaNが返ります。最後にtext()しないと値が変になります。

var sum=0;
var i=0;
$(xml).find('game').each(function(i){

    var vote_value = $(this).find('vote').text();
    vote_value = parseInt(vote_value);
    sum = sum + vote_value;
}
$("#vote").text(sum);

これが正しく動く書き方です。