XML HttpRequest

Loading XML data over HTTP lets a web page pull structured content from a server without a full page reload, using either the classic XMLHttpRequest object or the modern Fetch API.

Why Load XML Over HTTP?

Before JSON became the default data format for the web, XML was the standard way for browsers to exchange structured data with servers. Many legacy systems, RSS/Atom feeds, SOAP web services, and enterprise APIs still return XML today, so knowing how to fetch and parse it remains a practical skill even in a JSON-dominated world.

Two browser mechanisms can retrieve XML asynchronously: the older XMLHttpRequest (XHR) object, and the newer Promise-based Fetch API. Both ultimately hand you raw text or a parsed Document object that you can query with standard DOM methods.

Using XMLHttpRequest

XMLHttpRequest was purpose-built with XML in mind — its very name reflects that history. When a response's Content-Type header is text/xml or application/xml, the browser automatically parses the body into a Document accessible via responseXML, so you never have to parse it yourself.

Fetching XML with XMLHttpRequest

<!DOCTYPE html>
<html>
<body>

<script>
const xhr = new XMLHttpRequest();

xhr.open('GET', '/data/books.xml', true);

xhr.onreadystatechange = function () {
  if (xhr.readyState === 4 && xhr.status === 200) {
    const xmlDoc = xhr.responseXML;
    const titles = xmlDoc.getElementsByTagName('title');
    for (let i = 0; i < titles.length; i++) {
      console.log(titles[i].textContent);
    }
  }
};

xhr.send();
</script>

</body>
</html>
Note: readyState 4 means the request is complete (DONE); status 200 means the HTTP response succeeded. Checking both avoids reading a partial or failed response.

Using Fetch with a DOMParser

The Fetch API is promise-based and does not know anything about XML — it only understands text, JSON, and binary blobs. To turn a fetched XML string into a queryable document, you pass it through the browser's built-in DOMParser.

Fetching and parsing XML with Fetch

<!DOCTYPE html>
<html>
<body>

<script>
fetch('/data/books.xml')
  .then(response => response.text())
  .then(xmlText => {
    const parser = new DOMParser();
    const xmlDoc = parser.parseFromString(xmlText, 'application/xml');
    const titles = xmlDoc.querySelectorAll('title');
    titles.forEach(node => console.log(node.textContent));
  })
  .catch(error => console.error('Fetch failed:', error));
</script>

</body>
</html>

Because DOMParser returns a real Document, you can use familiar DOM methods on it: getElementsByTagName, querySelector, querySelectorAll, and childNodes traversal all work exactly as they would on an HTML page.

Async/Await Version

Fetching XML with async/await

<!DOCTYPE html>
<html>
<body>

<script>
async function loadBooks(url) {
  const response = await fetch(url);
  if (!response.ok) {
    throw new Error('HTTP error: ' + response.status);
  }
  const xmlText = await response.text();
  const xmlDoc = new DOMParser().parseFromString(xmlText, 'application/xml');
  return xmlDoc.querySelectorAll('book');
}

loadBooks('/data/books.xml').then(books => {
  console.log('Loaded ' + books.length + ' books');
});
</script>

</body>
</html>

Detecting Parse Errors

DOMParser never throws on malformed XML. Instead, it silently returns a document whose root element is <parsererror>. Always check for this element before trusting the parsed result.

  • Check xmlDoc.getElementsByTagName('parsererror').length before using the document
  • Prefer response.ok and response.status checks with fetch to catch HTTP-level failures early
  • Wrap XHR and fetch calls in try/catch or .catch() to handle network failures
  • Set a request timeout for XHR (xhr.timeout) to avoid hanging on unresponsive servers
  • Confirm the server sends a correct Content-Type so responseXML is populated automatically
FeatureXMLHttpRequestFetch API
Syntax styleCallback-based (onreadystatechange)Promise-based (.then/.catch or async/await)
Built-in XML parsingYes, via responseXMLNo, requires DOMParser manually
Request cancellationxhr.abort()AbortController
Upload progress eventsYes, native supportRequires extra work or streams
Browser supportUniversal, very oldModern browsers, widely supported
Note: Fetch does not reject on HTTP error statuses like 404 or 500 — it only rejects on network failure. Always check response.ok explicitly, or you'll silently parse an error page as if it were XML.

Exercise: XML HttpRequest

What is the main purpose of the XMLHttpRequest object?