XML Tutorial · XML in Code · Lesson 20 of 28
XML in JavaScript
Parsing and creating XML in the browser with DOMParser, XMLSerializer, document.evaluate (XPath) and XSLTProcessor, and options for Node.js.
Built into every browser
| API | Does |
|---|---|
new DOMParser().parseFromString(text, "application/xml") |
Parse XML into a DOM Document |
new XMLSerializer().serializeToString(doc) |
Turn a DOM back into text |
doc.evaluate(xpath, context, nsResolver, type) |
XPath 1.0 queries |
new XSLTProcessor() |
XSLT 1.0 transformations |
fetch(url).then(r => r.text()) |
Load XML from a server |
The examples on this page run live below the code, in a sandboxed frame. They write their results into the page, because the DOM APIs they use aren't available in the background worker the site's JavaScript runner uses.
Parsing and errors
DOMParser never throws. A malformed document comes back containing a <parsererror> element, so always check:
<pre id="out"></pre>
<script>
const lines = [];
const parse = (text) => {
const doc = new DOMParser().parseFromString(text, "application/xml");
const error = doc.querySelector("parsererror");
return error ? { error: "malformed XML" } : { doc };
};
const good = parse(`<order id="1042"><item sku="TEA-01" qty="2">Green tea</item></order>`);
const item = good.doc.querySelector("item");
lines.push(`order ${good.doc.documentElement.getAttribute("id")}: ${item.getAttribute("qty")} x ${item.textContent}`);
const bad = parse(`<order><item>tea</order>`);
lines.push(`broken input: ${bad.error}`);
const created = document.implementation.createDocument(null, "note", null);
created.documentElement.setAttribute("lang", "en");
created.documentElement.textContent = "Tea & cake";
lines.push(new XMLSerializer().serializeToString(created));
document.getElementById("out").textContent = lines.join("\n");
</script>
XPath with document.evaluate
<pre id="out"></pre>
<script>
const xml = `<shop>
<product sku="TEA-01" category="drinks"><name>Green tea</name><price>3.50</price><stock>40</stock></product>
<product sku="COF-02" category="drinks"><name>Coffee beans</name><price>9.90</price><stock>0</stock></product>
<product sku="MUG-07" category="kitchen"><name>Camel mug</name><price>12.00</price><stock>15</stock></product>
<product sku="PAN-03" category="kitchen"><name>Frying pan</name><price>29.00</price><stock>4</stock></product>
</shop>`;
const doc = new DOMParser().parseFromString(xml, "application/xml");
const lines = [];
const nodes = doc.evaluate("//product[price > 10]/name", doc, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
for (let i = 0; i < nodes.snapshotLength; i++) lines.push("over 10: " + nodes.snapshotItem(i).textContent);
const total = doc.evaluate("sum(//stock)", doc, null, XPathResult.NUMBER_TYPE, null).numberValue;
lines.push("total stock: " + total);
const ns = new DOMParser().parseFromString('<c xmlns="urn:shop"><p>tea</p></c>', "application/xml");
const resolver = (prefix) => ({ s: "urn:shop" })[prefix] || null;
lines.push("namespaced: " + ns.evaluate("string(//s:p)", ns, resolver, XPathResult.STRING_TYPE, null).stringValue);
document.getElementById("out").textContent = lines.join("\n");
</script>
XSLT in the browser
<div id="out"></div>
<script>
const xml = new DOMParser().parseFromString(`<shop>
<product sku="TEA-01" category="drinks"><name>Green tea</name><price>3.50</price><stock>40</stock></product>
<product sku="COF-02" category="drinks"><name>Coffee beans</name><price>9.90</price><stock>0</stock></product>
<product sku="MUG-07" category="kitchen"><name>Camel mug</name><price>12.00</price><stock>15</stock></product>
<product sku="PAN-03" category="kitchen"><name>Frying pan</name><price>29.00</price><stock>4</stock></product>
</shop>`, "application/xml");
const xsl = new DOMParser().parseFromString(`
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/shop">
<ul>
<xsl:for-each select="product[stock > 0]">
<xsl:sort select="price" data-type="number"/>
<li><b><xsl:value-of select="name"/></b>: <xsl:value-of select="price"/></li>
</xsl:for-each>
</ul>
</xsl:template>
</xsl:stylesheet>`, "application/xml");
const processor = new XSLTProcessor();
processor.importStylesheet(xsl);
document.getElementById("out").appendChild(processor.transformToFragment(xml, document));
</script>
Node.js
Node has no built-in XML parser. Popular choices are fast-xml-parser (XML to and from JavaScript objects),
@xmldom/xmldom (the W3C DOM API, often paired with xpath), sax (streaming) and libxmljs2 (libxml2
bindings with XSD validation). Disable entity expansion for untrusted input.
Test yourself
How does DOMParser report malformed XML?
It returns a document containing a parsererror elementIt throws a SyntaxErrorIt returns nullIt logs a warning and drops bad elements
Show answer
Answer: It returns a document containing a parsererror element
DOMParser never throws for XML; check for a parsererror element.