[JavaScript]responseXMLではまった

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

[JavaScript]responseXMLではまった

XMLHttpRequestのresponseXMLを使ってJavaScriptでXMLを読み込んでいたときにいろいろとつまづいたので、サンプルコードを書きつつメモ。間違いやもっといい方法などがあればぜひ教えていただきたい。

サンプルのXMLは、ホットペッパー Webサービス料理名マスタAPI(application/xml)のデータを使わせてもらった。

一部抜粋すると↓のような感じ。

ホットペッパー Webサービス - 料理名マスタAPI

<Results>
    <NumberOfResults>64</NumberOfResults>
    <APIVersion>1.11</APIVersion>
    <Food>
        <FoodCD>R001</FoodCD>
        <FoodName>和食全般</FoodName>
    </Food>
    <Food>
        <FoodCD>R002</FoodCD>
        <FoodName>懐石料理</FoodName>
    </Food>
</Result>

1. クロスドメイン通信はできない

これはXHRの基本的な制約。api.hotpepper.jp以外のドメインからapi.hotpepper.jpのデータをXHRで取ってくることはできない。普通はここでつまづくことはないのだが、サーバーサイドとクライアントサイドで連携しつつ、複数のリクエストをあちこちに送信してると時々間違える。しかも、iframeや<script src="...">はクロスドメイン可能だから余計こんがらがって。

これを解決するには、一度自分のサーバーで外部ドメインのデータを取得して、改めて出力しなおす必要がある。PHPであれば↓の2行で可能(ただし、php.iniで allow_url_fopenが有効になっている必要がある)。

<?php
echo file_get_contents('http://api.hotpepper.jp/Food/V110/?key=guest');

セキュリティ上のリスクは高いが。

2. Content-typeをapplication/xmlに指定しなければいけない

これはFirefoxの仕様。Content-typeがtext/htmlのままになっていると、FirefoxでresponseXMLの値を取得したときにnullになる。

/* use prototype.js */
new Ajax.Request('/proxy.php', {
    onComplete: function(xhr) {
        window.alert(xhr.responseXML);    /* Firefoxではnull */
    }
});

これを解決するにはサーバーサイドのプロキシスクリプトを以下のように変更する。

<?php
header('Content-type: application/xml');
echo file_get_contents('http://api.hotpepper.jp/Food/V110/?key=guest');

3. DOMのノードモデルを理解していないと要素中の値を取得できない

DOMのことは詳しくはわからないが、DOMではelementノード(要素ノード)とtextノードというのは別物らしい。つまり、

<APIVersion>1.11</APIVersion>

↑のようなXMLがあったとき、APIVersionという名前のelementノードと、その中の'1.11'というtextノードは別物。'1.11'はAPIVersionの子要素に当たる。従って、APIVersionの中の'1.11'という文字列を取得するには↓のように書く。

var node = xml.getElementsByTagName('APIVersion')[0];

window.alert(node.firstChild.nodeValue);    /* 1.11 */

↓ではダメ。

window.alert(node.nodeValue);    /* null */

elementノードに対して直接nodeValueは使えないが、かわりにtextContentやtextというプロパティが存在する。ただし、ブラウザ依存なので、クロスブラウザするには↓のように書く必要がある。

(function(node) {
    try {
        return node.textContent;
    } catch (e) {
        return node.text;
    }
})(xml.getElementById('APIVersion')[0]);

4. IEとその他で改行・空白文字の扱いが違う

HTMLの仕様では、行頭や行末にある改行・空白文字は無視されるが、XMLではそれらもtextノードとして扱われることになっている。しかし、IEは行頭行末の空白文字をtextノードとして扱わずに無視する。

従って、↓のようなXMLで、

<Food>
    <FoodCD>R001</FoodCD>
    <FoodName>和食全般</FoodName>
</Food>

↓のようなJavaScriptコードを書いた場合、

var node = xml.getElementsByTagName('Food')[0].firstChild;

nodeに割り当てられるのは、IEではFoodCDというelementノードだが、Firefoxなどでは改行と空白からなるtextノードである。

5. IEでは、XMLオブジェクトをfor inで走査できない

下のコードはIE6では動作しない。IE7がどうなのかは知らない。

new Ajax.Request('/proxy.php', {
    onComplete: function(xhr) {
        var xml = xhr.responseXML;
        for (var e in xml)
            document.body.innerHTML += e + ' = ' + xml[e] + '<br/>';
    }
});

「このオブジェクトではサポートされていない操作です」というメッセージとともに止まる。

6. IEではXMLオブジェクトにプロパティを追加できない

下のコードはIEでは動かない。

new Ajax.Request('/proxy.php', {
    onComplete: function(xhr) {
        var xml = xhr.responseXML;
        xml.fetch = function(tagName) {
            return this.getElementsByTagName(tagName)[0].firstChild.nodeValue;
        };
        window.alert('NumberOfResults = ' + xml.fetch('NumberOfResults'));
        window.alert('APIVersion = ' + xml.fetch('APIVersion'));
    }
});

IEではXMLオブジェクトにフィールドやメソッドを追加することができない。このようなことをしたい場合は、クロージャを使って下のように書く。

new Ajax.Request('/proxy.php', {
    onComplete: function(xhr) {
        var xml = xhr.responseXML;
        var fetch = function(tagName) {
            return xml.getElementsByTagName(tagName)[0].firstChild.nodeValue;
        };
        window.alert('NumberOfResults = ' + fetch('NumberOfResults'));
        window.alert('APIVersion = ' + fetch('APIVersion'));
    }
});

これならIEでも動く。

IE6のXMLオブジェクトはJavaScriptでのサポートが遅れている。IE7では改善されているのだろうか?

結論

PHPサイドで適当に処理して、JSONを吐き出すスクリプトを組むのが一番楽なのではないかと思った。

スポンサーサイト

関連記事

トラックバック URL

http://liosk.blog103.fc2.com/tb.php/34-f915c9d3

トラックバック

XMLパース
ajax使っていて自分もはまってしまった事。 http://liosk.blog103.fc2.com/blog-entry-34.html
  • 2008-09-08
  • 発信元: 独身SEの世迷言
Python CGI で 掲示板みたいなものを作る~Ajax編~
今回は、 JavaScript ファイルを追加して、いわゆる "Ajax" に挑戦してみます。
  • 2009-06-11
  • 発信元: 新適当マイコン電子工作研究所
Ajax.RequestのresponseXMLでXMLが取得できない場合の対処法
世の中はお盆休み中ですが、この間に滞っていたAjaxごにょごにょプロジェクトを再始動。 なんかトライ&エラーのテストプログラムばかり大量量産してます...。 「Prototype」のAjax.Requ...
  • 2009-08-15
  • 発信元: ID-Blogger

コメント

ぶっちゃけIEをカットすればいい話
あんなのがWindowsに標準でついてるのがそもそもの問題.
  • 2009-09-04
  • by 名無し
  • id:rZ5Dsd/2
  • 編集

コメントの投稿

お名前
コメント
編集キー
 
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。