Elke SOAP-service die je hebt aangeraakt, elke RSS-feed die je hebt geconsumeerd, elke SVG die je hebt gemanipuleerd — het is allemaal XML. JavaScript heeft twee ingebouwde manieren om het in de browser te parsen, en een solide npm-bibliotheek voor Node.js. Het lastige deel is niet het parsen zelf; het is navigeren door de resulterende DOM, het omgaan met namespaces en niet verrast worden door de eigenaardigheden die iedereen de eerste keer treffen. Laten we de echte patronen doornemen.
DOMParser — XML Parsen in de Browser
De ingebouwde
DOMParser-API
van de browser converteert een XML-string naar een DOM-document. Gebruik het MIME-type 'application/xml'
(niet 'text/html') zodat de parser strikte XML-regels toepast:
const xmlString = `<?xml version="1.0" encoding="UTF-8"?>
<library>
<book isbn="978-0-13-110362-7">
<title>The C Programming Language</title>
<authors>
<author>Brian W. Kernighan</author>
<author>Dennis M. Ritchie</author>
</authors>
<year>1988</year>
<price currency="USD">45.99</price>
</book>
<book isbn="978-0-201-63361-0">
<title>The Pragmatic Programmer</title>
<authors>
<author>Andrew Hunt</author>
<author>David Thomas</author>
</authors>
<year>1999</year>
<price currency="USD">52.00</price>
</book>
</library>`;
const parser = new DOMParser();
const doc = parser.parseFromString(xmlString, 'application/xml');
// Controleer altijd eerst op parseerfouten
const parseError = doc.querySelector('parsererror');
if (parseError) {
throw new Error('XML parse failed: ' + parseError.textContent);
}
console.log(doc.documentElement.tagName); // libraryJSON.parse() dat een uitzondering gooit,
retourneert DOMParser een document met een <parsererror>-element wanneer
parsen mislukt — er wordt geen uitzondering gegenereerd. Als je de foutcontrole overslaat, werk je stilletjes
op een misvormd document en krijg je verwarrende resultaten verderop.Navigeren door de DOM — getElementsByTagName vs querySelector
Zodra je een geparseerd document hebt, zijn er twee hoofd-API's om elementen te vinden. Beide werken, maar ze hebben verschillende sterktes:
// getElementsByTagName — retourneert een live HTMLCollection
const books = doc.getElementsByTagName('book');
console.log(books.length); // 2
// querySelector / querySelectorAll — CSS-selectorsyntaxis, retourneert NodeList
const firstTitle = doc.querySelector('title').textContent;
console.log(firstTitle); // The C Programming Language
// Haal alle titels op
const titles = [...doc.querySelectorAll('title')].map(el => el.textContent);
console.log(titles);
// ['The C Programming Language', 'The Pragmatic Programmer']
// Attributen lezen
const firstBook = doc.querySelector('book');
const isbn = firstBook.getAttribute('isbn');
console.log(isbn); // 978-0-13-110362-7
// Het currency-attribuut van price lezen
const priceEl = firstBook.querySelector('price');
console.log(priceEl.textContent); // 45.99
console.log(priceEl.getAttribute('currency')); // USDIk geef de voorkeur aan querySelector voor gerichte zoekopdrachten — de CSS-selectorsyntaxis is
vertrouwd en beknopt. Gebruik getElementsByTagName wanneer je alle elementen met een
bepaalde tag nodig hebt en een live-collectie wilt (hoewel in de praktijk een gespreide NodeList meestal overzichtelijker is).
Gestructureerde Data Extraheren — Een Praktisch Patroon
Zo wijs je een XML-document toe aan een schone JavaScript-array van objecten — het patroon dat je gebruikt bij het consumeren van een echte XML-API-response:
function parseLibraryXml(xmlString) {
const parser = new DOMParser();
const doc = parser.parseFromString(xmlString, 'application/xml');
if (doc.querySelector('parsererror')) {
throw new Error('Invalid XML');
}
return [...doc.querySelectorAll('book')].map(book => ({
isbn: book.getAttribute('isbn'),
title: book.querySelector('title').textContent.trim(),
authors: [...book.querySelectorAll('author')].map(a => a.textContent.trim()),
year: parseInt(book.querySelector('year').textContent, 10),
price: {
amount: parseFloat(book.querySelector('price').textContent),
currency: book.querySelector('price').getAttribute('currency')
}
}));
}
const books = parseLibraryXml(xmlString);
console.log(books[0].title); // The C Programming Language
console.log(books[0].authors); // ['Brian W. Kernighan', 'Dennis M. Ritchie']
console.log(books[0].price.amount); // 45.99XML met Namespaces Verwerken
Namespaces zijn waar de meeste ontwikkelaars vastlopen. SOAP-responses, Atom-feeds en SVG gebruiken allemaal
XML-namespaces — en een naïeve querySelector('body') retourneert null op een SOAP-document
omdat het element eigenlijk soap:Body is. Zo verwerk je het correct:
const soapResponse = `<?xml version="1.0"?>
<soap:Envelope
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:m="http://www.example.com/orders">
<soap:Header/>
<soap:Body>
<m:GetOrderResponse>
<m:OrderId>ORD-5521</m:OrderId>
<m:Status>Shipped</m:Status>
<m:Total currency="EUR">289.50</m:Total>
</m:GetOrderResponse>
</soap:Body>
</soap:Envelope>`;
const parser = new DOMParser();
const doc = parser.parseFromString(soapResponse, 'application/xml');
// Optie 1: getElementsByTagNameNS — expliciete namespace-URI
const SOAP_NS = 'http://schemas.xmlsoap.org/soap/envelope/';
const ORDER_NS = 'http://www.example.com/orders';
const body = doc.getElementsByTagNameNS(SOAP_NS, 'Body')[0];
const orderId = doc.getElementsByTagNameNS(ORDER_NS, 'OrderId')[0].textContent;
const status = doc.getElementsByTagNameNS(ORDER_NS, 'Status')[0].textContent;
console.log(orderId); // ORD-5521
console.log(status); // Shipped
// Optie 2: XPath met namespace-resolver (flexibeler)
function nsResolver(prefix) {
const namespaces = {
soap: 'http://schemas.xmlsoap.org/soap/envelope/',
m: 'http://www.example.com/orders'
};
return namespaces[prefix] || null;
}
const xpathResult = doc.evaluate(
'//m:OrderId',
doc,
nsResolver,
XPathResult.STRING_TYPE,
null
);
console.log(xpathResult.stringValue); // ORD-5521XPath-query's met evaluate()
XPath is een querytaal voor XML-documenten. De browser stelt deze beschikbaar via
document.evaluate(). Het is krachtiger dan CSS-selectors voor XML — je kunt
query's uitvoeren op attribuutwaarde, positie, tekstinhoud en afkomst.
Zie de MDN XPath-documentatie
voor de volledige expressiesyntaxis:
// Gebruik ons XML-bibliotheekdocument van eerder
function xpath(doc, expression, contextNode = doc) {
const result = doc.evaluate(
expression,
contextNode,
null, // namespace-resolver — null voor XML zonder namespaces
XPathResult.ANY_TYPE,
null
);
return result;
}
// Haal alle boeketitels op
const titlesResult = xpath(doc, '//book/title');
const titles = [];
let node;
while ((node = titlesResult.iterateNext())) {
titles.push(node.textContent);
}
console.log(titles);
// ['The C Programming Language', 'The Pragmatic Programmer']
// Haal het boek met een specifiek ISBN op
const bookResult = doc.evaluate(
'//book[@isbn="978-0-13-110362-7"]/title',
doc, null,
XPathResult.STRING_TYPE,
null
);
console.log(bookResult.stringValue); // The C Programming Language
// Haal boeken op met een prijs boven $50
const expensiveResult = xpath(doc, '//book[price > 50]/title');
let expensiveNode;
while ((expensiveNode = expensiveResult.iterateNext())) {
console.log(expensiveNode.textContent); // The Pragmatic Programmer
}Node.js — fast-xml-parser (de Beste Keuze)
Node.js heeft geen DOMParser. Je hebt twee opties: de op
ingebouwde
node:stream gebaseerde SAX-aanpak gebruiken (omslachtig), of
fast-xml-parser
gebruiken (de juiste keuze voor de meeste gebruiksscenario's). Het is snel, heeft nul afhankelijkheden en retourneert gewone JavaScript-objecten:
npm install fast-xml-parserimport { XMLParser } from 'fast-xml-parser';
const xmlString = `<?xml version="1.0"?>
<library>
<book isbn="978-0-13-110362-7">
<title>The C Programming Language</title>
<year>1988</year>
<price currency="USD">45.99</price>
</book>
<book isbn="978-0-201-63361-0">
<title>The Pragmatic Programmer</title>
<year>1999</year>
<price currency="USD">52.00</price>
</book>
</library>`;
const parser = new XMLParser({
ignoreAttributes: false, // neem XML-attributen mee
attributeNamePrefix: '@_', // prefix attributen om ze te onderscheiden van elementen
isArray: (tagName) => tagName === 'book' // behandel <book> altijd als array
});
const result = parser.parse(xmlString);
const books = result.library.book;
books.forEach(book => {
console.log(book.title); // The C Programming Language
console.log(book['@_isbn']); // 978-0-13-110362-7
console.log(book.price['#text']); // 45.99
console.log(book.price['@_currency']); // USD
});fast-xml-parser je een
object voor één item en een array voor meerdere. De isArray-optie dwingt consistent
arraygedrag af voor benoemde tags — gebruik hem altijd voor elementen waarvan je weet dat ze kunnen herhalen.Foutafhandeling in Node.js
import { XMLParser, XMLValidator } from 'fast-xml-parser';
function parseXmlSafely(xmlString) {
// Valideer eerst — retourneert true of een foutobject
const validation = XMLValidator.validate(xmlString);
if (validation !== true) {
throw new Error(`Invalid XML: ${validation.err.msg} at line ${validation.err.line}`);
}
const parser = new XMLParser({ ignoreAttributes: false, attributeNamePrefix: '@_' });
return parser.parse(xmlString);
}
try {
const data = parseXmlSafely(xmlString);
console.log(data);
} catch (err) {
console.error('XML parsing failed:', err.message);
}Gerelateerde Tools
Bij het werken met XML in JavaScript-projecten: XML Formatter om geminimaliseerde responses op te maken, XML Validator om goed gevormd zijn te controleren vóór het parsen, XML XPath Tester om te experimenteren met XPath-query's, en XML naar JSON als je wilt converteren naar een eenvoudigere structuur.
Samenvatting
In de browser is DOMParser met 'application/xml' je beste optie —
vergeet alleen niet te controleren op parsererror. Voor XML met namespaces gebruik je
getElementsByTagNameNS of XPath met een namespace-resolver. In Node.js
geeft fast-xml-parser je schone JavaScript-objecten zonder de DOM-overhead.
De patronen hier dekken 95% van de reële XML-parseerscenario's — SOAP-responses, RSS-feeds,
configuratiebestanden en meer.