Apple Developer Connection
高度な検索
Member Login ログイン | ご入会 ADC連絡先

Dynamic HTMLとXML:XMLHttpRequestオブジェクト

XMLデータとWebサービスの導入が広まるにつれ、HTMLの表示とXMLデータを直接結び付け、ページを再ロードせずに一時的な更新ができると便利だと思うことがあります。あまり知られていませんが、XMLHttpRequestというオブジェクトのおかげで、XMLデータの取得と送信をすべてバックグラウンドで実行できるWebクライアントが増えつつあります。取得したXMLデータを描画可能なHTMLコンテンツに変換するには、クライアント側でDOM (Document Object Model)を使ってXMLドキュメントノードツリーを読み取り、ユーザに表示されるHTML要素を作成します。

経緯およびサポート

Microsoftが最初に、XMLHttpRequestオブジェクトをWindows版Internet Explorer 5にActiveXオブジェクトとして実装しました。Mozillaプロジェクトのエンジニアは、Mozilla 1.0(およびNetscape 7)向けに互換性のあるネイティブバージョンを実装しました。Appleも同様に、Safari 1.2から実装しました。

同様の機能が、W3Cの標準案であるDocument Object Model (DOM) Level 3 Load and Save Specificationにおいてカバーされています。その一方で、XMLHttpRequestオブジェクトのサポートの増加は、このオブジェクトが事実上の標準になっており、W3Cの仕様が最終版となり一般公開されているブラウザへの実装が始まったあとも(それがいつになるかは分かりませんが)このオブジェクトがサポートされる可能性が高いことを意味します。

オブジェクトの作成

XMLHttpRequestオブジェクトのインスタンスを作成するには、ブラウザごとの、オブジェクトのインスタンスの生成方法の違いに対応するための分岐構文が必要です。SafariとMozillaの場合は、単にこのオブジェクトのコンストラクタ関数を呼び出すだけで生成できます。

var req = new XMLHttpRequest();

ActiveXの分岐の場合は、オブジェクトの名前をActiveXコンストラクタに渡します。

var req = new ActiveXObject("Microsoft.XMLHTTP");

どちらのコンストラクタの場合も、返されるオブジェクト参照は、ユーザからまったく見えないところで動作する抽象オブジェクトを指しています。そのメソッドはすべての操作を制御し、そのプロパティは、特にサーバから返される各種のデータを保持します。

オブジェクトのメソッド

サポートされているすべての環境において、XMLHttpRequestオブジェクトのインスタンスは、簡潔ながら強力な一連のメソッドとプロパティを共有します。表1に、Safari 1.2、Mozilla、およびWindows IE 5以上でサポートされているメソッドを示します。

表1.XMLHttpRequestオブジェクトの共通のメソッド

メソッド説明
abort()現在のリクエストを中止します。
getAllResponseHeaders()ヘッダ一式(ラベルと値)を文字列として返します。
getResponseHeader("headerLabel")1つのヘッダラベルの文字列値を返します。
open("method", "URL"[, asyncFlag[, "userName"[, "password"]]])接続先のURL、メソッド、その他これから送信するリクエストの任意の属性を割り当てます。
send(content)リクエストと、必要に応じて送信可能な文字列またはDOMオブジェクトデータを送信します。
setRequestHeader("label", "value")ラベル/値のペアを、リクエストとともに送信するヘッダに割り当てます。

表1に示したメソッドのうち、open()send()は、使われる可能性が最も高いメソッドです。open()は、次の処理のための状況を整えます。2つの必須パラメータは、リクエスト内容を表すHTTPメソッドと、接続先のURLです。methodパラメータには、主にデータ取得のリクエストである操作に対しては"GET"を使い、サーバへのデータ送信、特に長さが512バイトを超える可能性のあるデータ送信の操作に対しては"POST"を使います。URLは、完全なURLと相対的なURLのどちらでも構いません(ただし後述のセキュリティの問題を参照してください)。

重要な任意指定の第3パラメータは、次のトランザクションを非同期に処理するべきかどうかを制御するブール値です。デフォルト値(true)は非同期での処理であり、これはスクリプトの処理が、send()メソッドの呼び出し後すぐに、応答を待たずに実行されることを意味します。この値をfalseに設定すると、スクリプトは、リクエストが送信されてサーバからの応答が届くまで待機します。処理を続ける前に応答を待つのが良いように見えるかもしれませんが、これにはネットワークまたはサーバの問題でトランザクションの完了が妨げられている場合にスクリプトがハングするというリスクがあります。非同期に送信し、リクエストオブジェクトに対するonreadystatechangeイベントを中心にコードを設計するのが安全です。

次の汎用の関数には、分岐によるオブジェクト作成、イベントハンドラの割り当て、GETリクエストの送信が含まれています。関数の引数は、目的のURLを含んだ文字列のみです。この関数では、グローバル変数reqが、オブジェクトコンストラクタから返される値を受け取ることを想定しています。グローバル変数をここで使用することにより、ページのほかの場所にある他の関数の中からでも自由に応答値にアクセスできるようにしています。また、この例では、リクエストオブジェクトの状態の変更に対処するprocessReqChange()関数があることも想定しています。

var req;

function loadXMLDoc(url) {
	req = false;
    // ネイティブのXMLHttpRequestオブジェクトの場合の分岐
    if(window.XMLHttpRequest && !(window.ActiveXObject)) {
    	try {
			req = new XMLHttpRequest();
        } catch(e) {
			req = false;
        }
    // IE/WindowsのActiveXバージョンの場合の分岐
    } else if(window.ActiveXObject) {
       	try {
        	req = new ActiveXObject("Msxml2.XMLHTTP");
      	} catch(e) {
        	try {
          		req = new ActiveXObject("Microsoft.XMLHTTP");
        	} catch(e) {
          		req = false;
        	}
		}
    }
	if(req) {
		req.onreadystatechange = processReqChange;
		req.open("GET", url, true);
		req.send("");
	}
}

注: サーバから返されるデータは、Content-Typetext/xmlに設定して送信する必要があります。text/plainあるいはtext/htmlとして送信されたコンテンツは、リクエストオブジェクトのインスタンスによって受け付けられますが、responseTextプロパティを通じてのみ使用可能です。

オブジェクトのプロパティ

リクエストが送信されると、スクリプトは、表2に示す、すべての実装に共通するいくつかのプロパティを確認できます。 プロパティはすべて読み取り専用です。

表2.XMLHttpRequestオブジェクトの共通のプロパティ

プロパティ説明
onreadystatechange状態が変わるたびに起動するイベントのイベントハンドラ。
readyStateオブジェクトのステータスを表す整数:
0 = 初期化されていない
1 = ロード中
2 = ロード済み
3 = 対話可能
4 = 完了
responseTextサーバプロセスから返されたデータの文字列バージョン。
responseXMLサーバプロセスから返されたデータの、DOM互換のドキュメントオブジェクト。
statusサーバから返された数値コード。たとえば、「Not Found」を表す404や、「OK」を表す200など。
statusTextステータスコードに付ける文字列メッセージ。

リクエストオブジェクトの状態変更イベントを処理するイベントハンドラ関数の内部で、readyStateプロパティを使います。オブジェクトは、作成と処理の間に一時的に状態が変わることがありますが、トランザクションの完了を示す値は4です。

ただし結果に対して操作を行う場合は、事前にトランザクションが正常に完了したことをさらに確認する必要があります。statusプロパティまたはstatusTextプロパティを読み、操作が成功したか失敗したかを確認します。プロパティ値がそれぞれ200OKであれば、成功したことを示しています。

responseTextプロパティまたはresponseXMLプロパティを通じて、サーバから返されたデータにアクセスします。前者は、データの文字列表現だけを提供します。一方、より強力なのが、responseXMLプロパティにあるXMLドキュメントです。このオブジェクトは完全なdocumentノードオブジェクト(DOMのnodeTypeは9)であり、W3CのDOM (Document Object Model)ノードツリーのメソッドとプロパティを使って確認および解析できます。ただしこれはHTMLではなくXMLドキュメントであるため、DOMのHTMLモジュールのメソッドとプロパティを利用することができません。これは、現実には制約ではなく、Core DOMモジュールにより、要素のノード、要素の属性値、要素の内部でネストされているテキストノードを探すさまざまな手段が提供されます。

次のリストは、すべての条件を満たしている場合に限り、応答内容の処理を許可するonreadystatechangeイベントハンドラ関数の骨組みを示しています。

function processReqChange() {
    // reqが「loaded」を示している場合のみ
    if (req.readyState == 4) {
        // 「OK」の場合のみ
        if (req.status == 200) {
            // ・・・処理文がここに入る・・・
        } else {
            alert("There was a problem retrieving the XML data:\n" +
                req.statusText);
        }
    }
}

サーバプロセスのタイムアウトの可能性が懸念される場合は、loadXMLDoc()関数がsend()メソッドのグローバルなタイムスタンプを保存するように変更し、次にイベントハンドラ関数が、イベントの起動のたびに経過時間を計算するように変更することができます。経過時間が許容可能な限度を超えたらreq.abort()メソッドを呼び出し、送信操作を取り消し、ユーザに失敗したことを知らせます。

セキュリティの問題

XMLHttpRequestオブジェクトがブラウザ内で動作するときには、標準的なJavaScript動作の同一ドメイン内セキュリティポリシーを適用します(以前と同じ「サンドボックス」を共有します)。これにはいくつか重要な意味が含まれており、この機能の適用に影響します。

第1に、この機能をサポートするほとんどのブラウザでは、オブジェクトにアクセスするスクリプトが含まれているページは、http:プロトコル経由で取得する必要があります。つまり、特にMozillaやWindowsのIEでは、余分なセキュリティ問題を起こさずにローカルハードディスク(file:プロトコル)からページをテストすることができないということです。実際、MozillaではオブジェクトへのアクセスをUniversalBrowserReadセキュリティ権限の中にラップする必要があります。一方、IEでは、安全でない可能性のある動作が行われようとしていることを示すアラートがユーザに表示され、キャンセルの機会が与えられるだけです。

第2に、URLリクエストの宛先のドメインは、スクリプトが含まれているページを提供するドメインと同じでなければなりません。これは、残念ながらクライアント側のスクリプトでは、Webサービスデータをほかのソースから取得し、そのデータを特定のページに取り込むことができないことを意味します。すべてが同じドメインからのものでなければなりません。このような状況にすれば、ユーザをおびえさせるセキュリティ警告のことを心配する必要はありません。

例:iTunesのRSSフィードからのXMLデータの読み取り

デモンストレーション目的で4つのスタティックなXMLファイルを指定するがあるので試してください。データソースは、いくつかのiTunes Store関連のRSSフィードのスナップショットです。実際のフィードは、サードパーティドメインでホストされているため、サンプルファイルのドメインとライブRSSソースのドメインが異なり、真にダイナミックな例が妨げられます。

リストされている4つのカテゴリの1つを選択すると、スクリプトはそのカテゴリに対応するXMLファイルをロードします。その先のスクリプトは、このXMLファイルからさまざまな要素データを取り出し、2番目のselect要素のオプションを変更します。項目の1つをクリックすると、その項目のXMLデータ内の別の要素が読み取られます。そのデータがHTMLコンテンツとなり、サンプルページ内に、ページを再ロードすることなく表示されます。

サンプルデータには、タグ名に名前空間の指定の付いた要素がいくつか含まれています。Windows版のInternet Explorer(少なくともバージョン6まで)は、DOMのgetElementsByTagNameNS()関数は実装されていません。代わりに、名前空間タグ名を文字通りに扱います。たとえば、<content:encoded>という要素は、ローカル名がencodedでプレフィックスがcontentというタグではなく、タグ名がcontent:encodedの要素として扱われます。サンプルには、getElementTextNS()というユーティリティAPI関数が含まれています。この関数は、オブジェクトモデルの相違に対処しながら、目的とする要素に含まれているテキストノードも取得します。

サンプル(DMG 2.0MB)をダウンロードすると、自分のWebサーバの「Sites」フォルダにこれを置き、http:プロトコル経由でページにアクセスしてこれを試すことができます。XMLサンプルも含めてすべてのファイルを同じディレクトリに置いてください。

クールな組み合わせ

何年もの間、クライアント側の上級デベロッパたちは、バックグラウンドでトランザクションを発生させ、新しく更新されたデータを現在のページに挿入できるように、サーバとの「接続」を維持するためのきれいな方法をしばしば必要としていました。多くのデベロッパが、非表示の自動更新フレームや「フェイスレス」なJavaアプレットなどのテクニックを使うことで自らを苦しめてきました。W3C標準の策定が進められている間、MicrosoftのXMLHttpRequestオブジェクトが重要なギャップを埋め、アプリケーション開発の創造力を高めてくれます。この機能がSafariに追加されたのは喜ばしいことです。

更新: 2005-06-24