HTML in XMLHttpRequest

  • Revision slug: HTML_in_XMLHttpRequest
  • Revision title: HTML in XMLHttpRequest
  • Revision id: 32032
  • Created:
  • Creator: Nickolay
  • Is current revision? No
  • Comment update link to XMLHttpRequest; one or more formatting changes

Revision Content

The W3C XMLHttpRequest specification adds HTML parsing support to XMLHttpRequest, which originally supported only XML parsing. This feature allows Web apps to obtain an HTML resource as a parsed DOM using XMLHttpRequest.

Limitations

To discourage the synchronous use of XMLHttpRequest, HTML support is not available in the synchronous mode. Also, HTML support is only available if the responseType property has been set to "document". This limitation avoids wasting time parsing HTML uselessly when legacy code uses XMLHttpRequest in the default mode to retrieve responseText for text/html resources. Also, this limitation avoids problems with legacy code that assumes that responseXML is null for HTTP error pages (which often have a text/html response  body).

Usage

Retrieving an HTML resource as a DOM using XMLHttpRequest works just like retrieving an XML resource as a DOM using XMLHttpRequest, except you can't use the synchronous mode and you have to explicitly request a document by assigning the string "document" to the responseType property of the XMLHttpRequest object after calling open() but before calling send().

var xhr = new XMLHttpRequest();
xhr.onload = function() {
  alert(this.responseXML.title);
}
xhr.open("GET", "file.html");
xhr.responseType = "document";
xhr.send();

Feature Detection

There are two challenges to detecting if a browser supports HTML parsing in XMLHttpRequest. First, the detection result is obtained asynchronously, because HTML support is only available in the asynchronous mode. Second, you have to actually fetch a test document over HTTP, because testing with a data: URL would end up testing data: URL support instead.

Thus, to detect HTML support, a test HTML file is needed on the server. This test file is small and is not well-formed XML:

<title>&amp;&<</title>

If the file is named detect.html, the following function can be used for detecting HTML parsing support:

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);
  }
}

The argument callback is a function that will be called asynchronously with true as the only argument if HTML parsing is supported and false as the only argument if HTML parsing is not supported.

Character Encoding

If the character encoding is declared in the HTTP Content-Type header, that character encoding is used. Failing that, if there is a byte order mark, the encoding indicated by the byte order mark is used. Failing that, if the is a meta tag that declares the encoding within the first 1024 bytes of the file, that encoding is used. Otherwise, the file is decoded as UTF-8.

Browser compatibility

{{ CompatibilityTable() }}

Feature Chrome Firefox (Gecko) Internet Explorer Opera Safari (WebKit)
Basic support --- 11 --- --- {{ compatno() }}
(535.14)
Feature Android Firefox Mobile (Gecko) IE Phone Opera Mobile Safari Mobile
Basic support --- 11 --- --- ---

Specifications

  • {{ spec("http://dvcs.w3.org/hg/xhr/raw-file/tip/Overview.html", "XMLHttpRequest", "ED") }}

Revision Source

<p>The W3C <a class="external" href="http://dvcs.w3.org/hg/xhr/raw-file/tip/Overview.html">XMLHttpRequest</a> specification adds HTML parsing support to <a href="/en/DOM/XMLHttpRequest" title="en/DOM/XMLHttpRequest"><code>XMLHttpRequest</code></a>, which originally supported only XML parsing. This feature allows Web apps to obtain an HTML resource as a parsed DOM using <code>XMLHttpRequest</code>.</p>
<h3>Limitations</h3>
<p>To discourage the synchronous use of <code>XMLHttpRequest</code>, HTML support is not available in the synchronous mode. Also, HTML support is only available if the <code>responseType</code> property has been set to <code>"document"</code>. This limitation avoids wasting time parsing HTML uselessly when legacy code uses <code>XMLHttpRequest</code> in the default mode to retrieve <code>responseText</code> for <code>text/html</code> resources. Also, this limitation avoids problems with legacy code that assumes that <code>responseXML</code> is null for HTTP error pages (which often have a <code>text/html</code> response  body).</p>
<h3>Usage</h3>
<p>Retrieving an HTML resource as a DOM using <code>XMLHttpRequest</code> works just like retrieving an XML resource as a DOM using <code>XMLHttpRequest</code>, except you can't use the synchronous mode and you have to explicitly request a document by assigning the string <code>"document"</code> to the <code>responseType</code> property of the <code>XMLHttpRequest</code> object after calling <code>open()</code> but before calling <code>send()</code>.</p>
<pre>var xhr = new XMLHttpRequest();
xhr.onload = function() {
  alert(this.responseXML.title);
}
xhr.open("GET", "file.html");
xhr.responseType = "document";
xhr.send();
</pre>
<h3>Feature Detection</h3>
<p>There are two challenges to detecting if a browser supports HTML parsing in <code>XMLHttpRequest</code>. First, the detection result is obtained asynchronously, because HTML support is only available in the asynchronous mode. Second, you have to actually fetch a test document over HTTP, because testing with a <code>data:</code> URL would end up testing <code>data:</code> URL support instead.</p>
<p>Thus, to detect HTML support, a test HTML file is needed on the server. This test file is small and is not well-formed XML:</p>
<pre>&lt;title&gt;&amp;amp;&amp;&lt;&lt;/title&gt;</pre>
<p>If the file is named <code>detect.html</code>, the following function can be used for detecting HTML parsing support:</p>
<pre>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 &amp;&amp; !done) {
      done = true;
      callback(!!(this.responseXML &amp;&amp; this.responseXML.title &amp;&amp; this.responseXML.title == "&amp;&amp;&lt;"));
    }
  }
  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);
  }
}
</pre>
<p>The argument <code>callback</code> is a function that will be called asynchronously with <code>true</code> as the only argument if HTML parsing is supported and <code>false</code> as the only argument if HTML parsing is not supported.</p>
<h3>Character Encoding</h3>
<p>If the character encoding is declared in the HTTP <code>Content-Type</code> header, that character encoding is used. Failing that, if there is a byte order mark, the encoding indicated by the byte order mark is used. Failing that, if the is a <code>meta</code> tag that declares the encoding within the first 1024 bytes of the file, that encoding is used. Otherwise, the file is decoded as UTF-8.</p>
<h3 name="Browser_Compatibility">Browser compatibility</h3>
<p>{{ CompatibilityTable() }}</p>
<div id="compat-desktop"> <table class="compat-table"> <tbody> <tr> <th>Feature</th> <th>Chrome</th> <th>Firefox (Gecko)</th> <th>Internet Explorer</th> <th>Opera</th> <th>Safari (WebKit)</th> </tr> <tr> <td>Basic support</td> <td>---</td> <td>11</td> <td>---</td> <td>---</td> <td>{{ compatno() }}<br> (<a class="external" href="http://trac.webkit.org/changeset/103106">535.14</a>)</td> </tr> </tbody> </table>
</div>
<div id="compat-mobile"> <table class="compat-table"> <tbody> <tr> <th>Feature</th> <th>Android</th> <th>Firefox Mobile (Gecko)</th> <th>IE Phone</th> <th>Opera Mobile</th> <th>Safari Mobile</th> </tr> <tr> <td>Basic support</td> <td>---</td> <td>11</td> <td>---</td> <td>---</td> <td>---</td> </tr> </tbody> </table>
</div>
<h3>Specifications</h3>
<ul> <li>{{ spec("http://dvcs.w3.org/hg/xhr/raw-file/tip/Overview.html", "XMLHttpRequest", "ED") }}</li>
</ul>
Revert to this revision