XMLHttpRequest 仕様は HTML のパース処理をサポートしました (これまで XMLHttpRequest は XML のパース処理しかサポートしていませんでした)。これによって、Web アプリは XMLHttpRequest から HTML をパース済の DOM として取得できます。
制限
非同期ではない XMLHttpRequest の利用を推奨しないことから、同期モードではサポートされていません。また、HTML のサポートは responseType プロパティの値が "document" にセットされているときにのみ有効です。この制限を課すことにより、デフォルトモードで responseText が text/html なリソースを取得する XMLHttpRequest を利用する古いコードが、リソースを不必要に HTML としてパースする必要がなくなります。また、HTTP エラーページについて responseXML が null を返すことを想定した古いコードで問題が起こることも防げます (HTTP エラーページはレスポンスボディが text/html であることが多いのです)。
HTML パース処理の利用
XMLHttpRequest で HTML を DOM として取得するのは、XML を DOM として取得するのとそう変わりません。ただ、非同期モードを利用しなければいけないことと、XMLHttpRequest オブジェクトの open() をコールしたあと、send() をコールする前に responseType プロパティに "document" を指定し、明示的に文書をリクエストしなければいけないという違いがあります。
var xhr = new XMLHttpRequest();
xhr.onload = function() {
alert(this.responseXML.title);
}
xhr.open("GET", "file.html");
xhr.responseType = "document";
xhr.send();
HTML サポートの検出
方法 1 ― 同期モードのエラーを利用
この方法は「強制的に非同期」である性質を利用するものです。XMLHttpRequest オブジェクトの responseType を同期モードで呼び出した後にセットするのです。これは HTML パース処理をサポートするブラウザではエラーを投げることになります。サポートしないブラウザでは、エラーが起こりません。
function HTMLinXHR() {
if (!window.XMLHttpRequest)
return false;
var req = new window.XMLHttpRequest();
req.open('GET', window.location.href, false);
try {
req.responseType = 'document';
} catch(e) {
return true;
}
return false;
}
この方法は同期モードで行われるため、外部リソースに頼る必要がありません。しかし、実際の機能ではなくサポートされていそうという状況を確かめるものなので、次に紹介する方法よりも確実なものではありません。
方法 2 ― 実際に取得し確実に検出
XMLHttpRequest で HTML のパース処理がサポートされているかを確実に確かめるのには2つの課題があります。まず、この機能が非同期モードでしかサポートされていないことから、検出した結果が非同期であることを確かめなければいけません。そして、テストする文書が HTTP 上になければいけません。なぜなら、data: URL による取得では data: URL のサポートも確かめなければいけないからです。
つまり、HTML サポートを検出するには、サーバ上にテスト用の HTML 文書が必要なのです。このテストファイルは小さく、そして well-formed な XML 文書であってはいけません。
<title>&&<</title>
このファイルが detect.html という名前だった場合、HTML サポートを検出する関数は次のように書けます。
function detectHtmlInXhr(callback) {
if (!window.XMLHttpRequest) {
window.setTimeout(function() { callback(false); }, 0);
return;
}
var done = false;
var xhr = new window.XMLHttpRequest();
xhr.onreadystatechange = function() {
if (this.readyState == 4 && !done) {
done = true;
callback(!!(this.responseXML && this.responseXML.title && this.responseXML.title == "&&<"));
}
}
xhr.onabort = xhr.onerror = function() {
if (!done) {
done = true;
callback(false);
}
}
try {
xhr.open("GET", "detect.html");
xhr.responseType = "document";
xhr.send();
} catch (e) {
window.setTimeout(function() {
if (!done) {
done = true;
callback(false);
}
}, 0);
}
}
引数の callback は HTML サポートがある場合には true を、サポートがない場合は false を引数にとり、非同期にコールされる関数です。
文字エンコーディング
HTTP の Content-Type ヘッダで文字エンコーディングが宣言されている場合は、そのエンコーディングが使用されます。そうでない場合、もし byte order mark がある場合は、その BOM が示すエンコーディングを使用します。そうでない場合、もしファイルの先頭 1024 バイト以内にエンコーディングを宣言する meta 要素がある場合は、そのエンコーディングが使用されます。それもない場合、ファイルは UTF-8 としてデコードされます。
ブラウザの互換性
| 機能 | Chrome | Firefox (Gecko) | Internet Explorer | Opera | Safari (WebKit) |
|---|---|---|---|---|---|
| サポート | 18 | 11 | 10 | --- | 未サポート (535.14) |
| 機能 | Android | Firefox Mobile (Gecko) | IE Phone | Opera Mobile | Safari Mobile |
|---|---|---|---|---|---|
| サポート | --- | 11 | --- | --- | --- |