@xmldom/xmldom vs fast-xml-parser vs libxmljs vs xml2js vs xmlbuilder
XML Processing Libraries for JavaScript Applications
@xmldom/xmldomfast-xml-parserlibxmljsxml2jsxmlbuilderSimilar Packages:

XML Processing Libraries for JavaScript Applications

These five npm packages handle XML parsing, validation, and generation in JavaScript and Node.js environments. @xmldom/xmldom provides a W3C-compliant DOM implementation that works in both browsers and Node.js. fast-xml-parser focuses on high-performance parsing and validation with flexible output formats. libxmljs offers native bindings to libxml2 with full XPath and schema validation support but requires compilation. xml2js converts XML to JavaScript objects and vice versa with a mature, stable API. xmlbuilder specializes in programmatically building XML documents with a chainable interface. Each serves different needs based on environment constraints, performance requirements, and feature needs.

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
@xmldom/xmldom0452411 kB525 days agoMIT
fast-xml-parser03,079985 kB336 days agoMIT
libxmljs01,06017.7 MB693 years agoMIT
xml2js04,9663.44 MB2493 years agoMIT
xmlbuilder0926-76 years agoMIT

XML Processing Libraries for JavaScript: A Technical Deep-Dive

Working with XML in JavaScript applications requires choosing the right tool for your specific needs. The five packages we are comparing β€” @xmldom/xmldom, fast-xml-parser, libxmljs, xml2js, and xmlbuilder β€” each take different approaches to XML handling. Let's examine how they solve common problems.

πŸ“„ Parsing XML: Different Approaches

@xmldom/xmldom implements the W3C DOM specification, giving you a familiar document tree structure.

import { DOMParser } from '@xmldom/xmldom';

const parser = new DOMParser();
const doc = parser.parseFromString('<root><item id="1">Hello</item></root>', 'text/xml');
const item = doc.getElementsByTagName('item')[0];
console.log(item.getAttribute('id')); // "1"
console.log(item.textContent); // "Hello"

fast-xml-parser parses XML to JavaScript objects with high performance.

import { XMLParser } from 'fast-xml-parser';

const parser = new XMLParser();
const result = parser.parse('<root><item id="1">Hello</item></root>');
console.log(result.root.item['@_id']); // "1"
console.log(result.root.item['#text']); // "Hello"

libxmljs uses native libxml2 bindings for full XML feature support.

import libxmljs from 'libxmljs';

const doc = libxmljs.parseXmlString('<root><item id="1">Hello</item></root>');
const item = doc.get('//item');
console.log(item.attr('id').value()); // "1"
console.log(item.text()); // "Hello"

xml2js converts XML to plain JavaScript objects.

import { parseStringPromise } from 'xml2js';

const result = await parseStringPromise('<root><item id="1">Hello</item></root>');
console.log(result.root.item[0].$.id); // "1"
console.log(result.root.item[0]._); // "Hello"

xmlbuilder does not parse XML β€” it only builds XML documents. For parsing, you would need to combine it with another library.

// xmlbuilder is for building only, not parsing
// You would use it alongside a parser like:
import { create } from 'xmlbuilder';
// Parsing would require @xmldom/xmldom or fast-xml-parser

πŸ—οΈ Building XML: Generation Capabilities

@xmldom/xmldom can serialize DOM trees back to XML strings.

import { DOMParser, XMLSerializer } from '@xmldom/xmldom';

const parser = new DOMParser();
const doc = parser.parseFromString('<root/>', 'text/xml');
const item = doc.createElement('item');
item.setAttribute('id', '1');
item.textContent = 'Hello';
doc.documentElement.appendChild(item);

const serializer = new XMLSerializer();
const xmlString = serializer.serializeToString(doc);
// <root><item id="1">Hello</item></root>

fast-xml-parser includes XML building capabilities alongside parsing.

import { XMLBuilder } from 'fast-xml-parser';

const builder = new XMLBuilder({ ignoreAttributes: false });
const obj = {
  root: {
    item: {
      '@_id': '1',
      '#text': 'Hello'
    }
  }
};
const xmlString = builder.build(obj);
// <root><item id="1">Hello</item></root>

libxmljs can create XML documents programmatically with native performance.

import libxmljs from 'libxmljs';

const doc = new libxmljs.Document();
const root = doc.node('root');
const item = root.node('item').attr('id', '1').text('Hello');
const xmlString = doc.toString();
// <root><item id="1">Hello</item></root>

xml2js includes a Builder class for converting objects back to XML.

import { Builder } from 'xml2js';

const builder = new Builder();
const obj = {
  root: {
    item: {
      $: { id: '1' },
      _: 'Hello'
    }
  }
};
const xmlString = builder.buildObject(obj);
// <root><item id="1">Hello</item></root>

xmlbuilder specializes in XML generation with a clean chainable API.

import { create } from 'xmlbuilder';

const xml = create({ version: '1.0' })
  .ele('root')
    .ele('item').att('id', '1').txt('Hello')
  .end({ pretty: true });
// <?xml version="1.0"?>
// <root>
//   <item id="1">Hello</item>
// </root>

πŸ” Querying XML: XPath and DOM Navigation

@xmldom/xmldom supports standard DOM methods but has limited XPath support.

import { DOMParser } from '@xmldom/xmldom';

const doc = new DOMParser().parseFromString('<root><item id="1"/><item id="2"/></root>', 'text/xml');
const items = doc.getElementsByTagName('item');
console.log(items.length); // 2
// XPath requires additional setup or libraries

fast-xml-parser does not support XPath β€” you query the resulting JavaScript object.

import { XMLParser } from 'fast-xml-parser';

const parser = new XMLParser();
const result = parser.parse('<root><item id="1"/><item id="2"/></root>');
const items = Array.isArray(result.root.item) ? result.root.item : [result.root.item];
console.log(items.length); // 2

libxmljs has full XPath support built in.

import libxmljs from 'libxmljs';

const doc = libxmljs.parseXmlString('<root><item id="1"/><item id="2"/></root>');
const items = doc.find('//item[@id]');
console.log(items.length); // 2
console.log(items[0].attr('id').value()); // "1"

xml2js does not support XPath β€” you navigate the JavaScript object structure.

import { parseStringPromise } from 'xml2js';

const result = await parseStringPromise('<root><item id="1"/><item id="2"/></root>');
const items = result.root.item;
console.log(items.length); // 2
console.log(items[0].$.id); // "1"

xmlbuilder does not support querying β€” it is for building only.

// xmlbuilder has no query capabilities
// Use it with a parser library for full XML workflow

⚑ Performance and Environment Constraints

@xmldom/xmldom runs everywhere β€” browsers and Node.js β€” with no native dependencies.

// Works identically in browser and Node.js
import { DOMParser } from '@xmldom/xmldom';
// No compilation needed, pure JavaScript

fast-xml-parser is pure JavaScript with optimized performance for large files.

// Pure JS, no native dependencies
import { XMLParser } from 'fast-xml-parser';
// Known for speed in benchmark tests

libxmljs requires native compilation and Node.js only.

// Requires node-gyp compilation
import libxmljs from 'libxmljs';
// Will NOT work in browsers
// May have installation issues on some platforms

xml2js is pure JavaScript and works in both environments.

// Pure JS, browser and Node.js compatible
import { parseStringPromise } from 'xml2js';
// Mature and stable

xmlbuilder is pure JavaScript with broad environment support.

// Pure JS, works everywhere
import { create } from 'xmlbuilder';
// No compilation required

βœ… Validation Support

@xmldom/xmldom has limited validation β€” it parses but does not validate against schemas.

import { DOMParser } from '@xmldom/xmldom';

const parser = new DOMParser();
// No built-in schema validation
// Will parse invalid XML without throwing errors in some cases
const doc = parser.parseFromString('<root><item>', 'text/xml');

fast-xml-parser includes optional validation features.

import { XMLParser, XMLValidator } from 'fast-xml-parser';

const isValid = XMLValidator.validate('<root><item/></root>');
console.log(isValid); // true if valid

const parser = new XMLParser({ ignoreAttributes: false });

libxmljs has full XML Schema and DTD validation support.

import libxmljs from 'libxmljs';

const doc = libxmljs.parseXmlString('<root><item/></root>');
// Can validate against XSD schemas
// Full validation capabilities from libxml2

xml2js does not include validation β€” it assumes input is valid XML.

import { parseStringPromise } from 'xml2js';

// No validation built in
// Will throw on malformed XML but no schema validation
try {
  await parseStringPromise('<root><item>');
} catch (err) {
  console.error(err); // Parse error
}

xmlbuilder does not validate β€” it generates XML structures.

import { create } from 'xmlbuilder';

// No validation β€” builds whatever structure you define
const xml = create().ele('root').ele('item').end();

🌐 Real-World Scenarios

Scenario 1: Browser-Based XML Editor

You are building an XML editor that runs in the browser with DOM manipulation.

  • βœ… Best choice: @xmldom/xmldom
  • Why? W3C DOM compatibility means you can use standard DOM APIs.
import { DOMParser, XMLSerializer } from '@xmldom/xmldom';

const parser = new DOMParser();
const doc = parser.parseFromString(xmlString, 'text/xml');
// Use standard DOM methods like getElementById, appendChild, etc.

Scenario 2: High-Volume XML Processing Pipeline

You need to process thousands of XML files quickly in Node.js.

  • βœ… Best choice: fast-xml-parser
  • Why? Performance optimized for speed with validation options.
import { XMLParser } from 'fast-xml-parser';

const parser = new XMLParser();
const results = files.map(file => parser.parse(file.content));
// Fast parsing for bulk operations

Scenario 3: Complex XML with XPath Queries

You need to query XML documents with complex XPath expressions.

  • βœ… Best choice: libxmljs
  • Why? Full XPath support from libxml2.
import libxmljs from 'libxmljs';

const doc = libxmljs.parseXmlString(xmlString);
const nodes = doc.find('//book[author="Smith"]');
// Powerful XPath queries

Scenario 4: Simple XML to Object Conversion

You receive XML API responses and want JavaScript objects.

  • βœ… Best choice: xml2js
  • Why? Mature, stable, and straightforward object conversion.
import { parseStringPromise } from 'xml2js';

const data = await parseStringPromise(apiResponse);
// Easy access: data.root.item[0].$.id

Scenario 5: Generating XML Reports

You need to create XML documents programmatically for reports.

  • βœ… Best choice: xmlbuilder
  • Why? Clean chainable API for building complex structures.
import { create } from 'xmlbuilder';

const report = create({ version: '1.0' })
  .ele('report')
    .ele('header').txt('Monthly Report')
    .ele('data').dat(new Date())
  .end({ pretty: true });

πŸ“Œ Summary Table

PackageEnvironmentNative DepsXPathValidationBuild XMLParse XML
@xmldom/xmldomBrowser + Node❌LimitedβŒβœ… (serialize)βœ… (DOM)
fast-xml-parserBrowser + NodeβŒβŒβœ…βœ…βœ…
libxmljsNode onlyβœ…βœ…βœ…βœ…βœ…
xml2jsBrowser + NodeβŒβŒβŒβœ…βœ…
xmlbuilderBrowser + NodeβŒβŒβŒβœ…βŒ

⚠️ Deprecation and Maintenance Notes

As of current documentation, none of these five packages are officially deprecated. However:

  • libxmljs requires native compilation which can cause installation issues on some platforms and prevents browser usage.
  • xml2js is mature but development has slowed β€” it is stable but not actively adding new features.
  • @xmldom/xmldom is the maintained fork of the original xmldom package (which is deprecated).

πŸ’‘ Final Recommendation

Think in terms of environment, features, and workflow:

  • Need browser support? β†’ Avoid libxmljs, choose from the pure JS options.
  • Need XPath queries? β†’ libxmljs is your only full-featured option.
  • Need maximum speed? β†’ fast-xml-parser leads in performance benchmarks.
  • Need DOM compatibility? β†’ @xmldom/xmldom provides W3C DOM APIs.
  • Just converting XML to objects? β†’ xml2js is stable and straightforward.
  • Only generating XML? β†’ xmlbuilder has the cleanest building API.

Final Thought: XML processing in JavaScript has matured significantly. Choose based on your specific constraints β€” environment compatibility, feature requirements, and performance needs β€” rather than trying to find one solution that does everything.

How to Choose: @xmldom/xmldom vs fast-xml-parser vs libxmljs vs xml2js vs xmlbuilder

  • @xmldom/xmldom:

    Choose @xmldom/xmldom if you need a pure JavaScript DOM implementation that works identically in browsers and Node.js. It is ideal when you want W3C DOM compatibility without native dependencies, especially for isomorphic applications or when working with existing DOM-based code.

  • fast-xml-parser:

    Choose fast-xml-parser if performance is your top priority and you need flexible parsing options including validation. It works well for high-volume XML processing where speed matters and you want both parsing and building capabilities in one package.

  • libxmljs:

    Choose libxmljs if you need full XML feature support including XPath queries and schema validation in a Node.js-only environment. Avoid it for browser projects or when you cannot handle native module compilation requirements.

  • xml2js:

    Choose xml2js if you want to convert XML directly to JavaScript objects for easy manipulation. It is best for projects where you treat XML as data rather than a document structure and need a stable, well-tested solution.

  • xmlbuilder:

    Choose xmlbuilder if your primary need is generating XML documents programmatically. It excels when you need to build complex XML structures with a clean, chainable API rather than parsing existing XML.

README for @xmldom/xmldom

@xmldom/xmldom

Since version 0.7.0 this package is published to npm as @xmldom/xmldom and no longer as xmldom, because we are no longer able to publish xmldom.
For better readability in the docs, we will continue to talk about this library as "xmldom".

license(MIT) no dependencies codecov install size

OpenSSF Best Practices OpenSSF Scorecard Socket Badge snyk.io package health

npm:latest npm:next npm:lts

bug issues help-wanted issues

xmldom is a javascript ponyfill to provide the following APIs that are present in modern browsers to other runtimes:

  • convert an XML string into a DOM tree
    new DOMParser().parseFromString(xml, mimeType) => Document
    
  • create, access and modify a DOM tree
    new DOMImplementation().createDocument(...) => Document
    
  • serialize a DOM tree back into an XML string
    new XMLSerializer().serializeToString(node) => string
    

The target runtimes xmldom supports are currently Node >= v14.6 (and very likely any other ES5 compatible runtime).

When deciding how to fix bugs or implement features, xmldom tries to stay as close as possible to the various related specifications/standards.
As indicated by the version starting with 0., this implementation is not feature complete and some implemented features differ from what the specifications describe.
Issues and PRs for such differences are always welcome, even when they only provide a failing test case.

This project was forked from it's original source in 2019, more details about that transition can be found in the CHANGELOG.

Usage

Install:

npm install @xmldom/xmldom

Example:

In NodeJS

const { DOMParser, XMLSerializer } = require('@xmldom/xmldom')

const source = `<xml xmlns="a">
	<child>test</child>
	<child/>
</xml>`

const doc = new DOMParser().parseFromString(source, 'text/xml')

const serialized = new XMLSerializer().serializeToString(doc)

Note: in Typescript and ES6 (see #316) you can use the import approach, as follows:

import { DOMParser } from '@xmldom/xmldom'

API Reference

  • DOMParser:

    parseFromString(xmlsource, mimeType)
    
    • options extension by xmldom (not DOM standard!!)
    // the options argument can be used to modify behavior
    // for more details check the documentation on the code or type definition  
    new DOMParser(options)
    
  • XMLSerializer

    serializeToString(node)
    

DOM level2 method and attribute:

  • Node

    readonly class properties (aka NodeType),
    these can be accessed from any Node instance node:
    if (node.nodeType === node.ELEMENT_NODE) {...

    1. ELEMENT_NODE (1)
    2. ATTRIBUTE_NODE (2)
    3. TEXT_NODE (3)
    4. CDATA_SECTION_NODE (4)
    5. ENTITY_REFERENCE_NODE (5)
    6. ENTITY_NODE (6)
    7. PROCESSING_INSTRUCTION_NODE (7)
    8. COMMENT_NODE (8)
    9. DOCUMENT_NODE (9)
    10. DOCUMENT_TYPE_NODE (10)
    11. DOCUMENT_FRAGMENT_NODE (11)
    12. NOTATION_NODE (12)

    attribute:

    • nodeValue | prefix | textContent

    readonly attribute:

    • nodeName | nodeType | parentNode | parentElement | childNodes | firstChild | lastChild | previousSibling | nextSibling | attributes | ownerDocument | namespaceURI | localName | isConnected | baseURI

    method:

    • insertBefore(newChild, refChild)
    • replaceChild(newChild, oldChild)
    • removeChild(oldChild)
    • appendChild(newChild)
    • hasChildNodes()
    • cloneNode(deep)
    • normalize()
    • contains(otherNode)
    • getRootNode()
    • isEqualNode(otherNode)
    • isSameNode(otherNode)
    • isSupported(feature, version)
    • hasAttributes()
  • DOMException

    extends the Error type thrown as part of DOM API.

    readonly class properties:

    • INDEX_SIZE_ERR (1)
    • DOMSTRING_SIZE_ERR (2)
    • HIERARCHY_REQUEST_ERR (3)
    • WRONG_DOCUMENT_ERR (4)
    • INVALID_CHARACTER_ERR (5)
    • NO_DATA_ALLOWED_ERR (6)
    • NO_MODIFICATION_ALLOWED_ERR (7)
    • NOT_FOUND_ERR (8)
    • NOT_SUPPORTED_ERR (9)
    • INUSE_ATTRIBUTE_ERR (10)
    • INVALID_STATE_ERR (11)
    • SYNTAX_ERR (12)
    • INVALID_MODIFICATION_ERR (13)
    • NAMESPACE_ERR (14)
    • INVALID_ACCESS_ERR (15)

    attributes:

    • code with a value matching one of the above constants.
  • DOMImplementation

    method:

    • hasFeature(feature, version) (deprecated)
    • createDocumentType(qualifiedName, publicId, systemId)
    • createDocument(namespaceURI, qualifiedName, doctype)
  • Document : Node

    readonly attribute:

    • doctype | implementation | documentElement

    method:

    • createElement(tagName)
    • createDocumentFragment()
    • createTextNode(data)
    • createComment(data)
    • createCDATASection(data)
    • createProcessingInstruction(target, data)
    • createAttribute(name)
    • createEntityReference(name)
    • getElementsByTagName(tagname)
    • importNode(importedNode, deep)
    • createElementNS(namespaceURI, qualifiedName)
    • createAttributeNS(namespaceURI, qualifiedName)
    • getElementsByTagNameNS(namespaceURI, localName)
    • getElementById(elementId)
  • DocumentFragment : Node

  • Element : Node

    readonly attribute:

    • tagName

    method:

    • getAttribute(name)
    • setAttribute(name, value)
    • removeAttribute(name)
    • getAttributeNode(name)
    • setAttributeNode(newAttr)
    • removeAttributeNode(oldAttr)
    • getElementsByTagName(name)
    • getAttributeNS(namespaceURI, localName)
    • setAttributeNS(namespaceURI, qualifiedName, value)
    • removeAttributeNS(namespaceURI, localName)
    • getAttributeNodeNS(namespaceURI, localName)
    • setAttributeNodeNS(newAttr)
    • getElementsByTagNameNS(namespaceURI, localName)
    • hasAttribute(name)
    • hasAttributeNS(namespaceURI, localName)
  • Attr : Node

    attribute:

    • value

    readonly attribute:

    • name | specified | ownerElement
  • NodeList

    readonly attribute:

    • length

    method:

    • item(index)
  • NamedNodeMap

    readonly attribute:

    • length

    method:

    • getNamedItem(name)
    • setNamedItem(arg)
    • removeNamedItem(name)
    • item(index)
    • getNamedItemNS(namespaceURI, localName)
    • setNamedItemNS(arg)
    • removeNamedItemNS(namespaceURI, localName)
  • CharacterData : Node

    method:

    • substringData(offset, count)
    • appendData(arg)
    • insertData(offset, arg)
    • deleteData(offset, count)
    • replaceData(offset, count, arg)
  • Text : CharacterData

    method:

    • splitText(offset)
  • CDATASection

  • Comment : CharacterData

  • DocumentType

    readonly attribute:

    • name | entities | notations | publicId | systemId | internalSubset
  • Notation : Node

    readonly attribute:

    • publicId | systemId
  • Entity : Node

    readonly attribute:

    • publicId | systemId | notationName
  • EntityReference : Node

  • ProcessingInstruction : Node

    attribute:

    • data readonly attribute:
    • target

DOM level 3 support:

  • Node

    attribute:

    • textContent

    method:

    • isDefaultNamespace(namespaceURI)
    • lookupNamespaceURI(prefix)

DOM Living Standard support:

  • ParentNode mixin (on Document, DocumentFragment, Element)

    readonly attribute:

    • children

DOM extension by xmldom

  • [Node] Source position extension;

    attribute:

    • lineNumber //number starting from 1
    • columnNumber //number starting from 1

Specs

The implementation is based on several specifications:

Overview of related specifications and their relations

DOM Parsing and Serialization

From the W3C DOM Parsing and Serialization (WD 2016) xmldom provides an implementation for the interfaces:

  • DOMParser
  • XMLSerializer

Note that there are some known deviations between this implementation and the W3 specifications.

Note: The latest version of this spec has the status "Editors Draft", since it is under active development. One major change is that the definition of the DOMParser interface has been moved to the HTML spec

DOM

The original author claims that xmldom implements [DOM Level 2] in a "fully compatible" way and some parts of [DOM Level 3], but there are not enough tests to prove this. Both Specifications are now superseded by the [DOM Level 4 aka Living standard] wich has a much broader scope than xmldom. In the past, there have been multiple (even breaking) changes to align xmldom with the living standard, so if you find a difference that is not documented, any contribution to resolve the difference is very welcome (even just reporting it as an issue).

xmldom implements the following interfaces:

  • Attr
  • CDATASection
  • CharacterData
  • Comment
  • Document
  • DocumentFragment
  • DocumentType
  • DOMException
  • DOMImplementation
  • Element
  • Entity
  • EntityReference
  • LiveNodeList
  • NamedNodeMap
  • Node
  • NodeList
  • Notation
  • ProcessingInstruction
  • Text

more details are available in the (incomplete) API Reference section.

HTML

xmldom does not have any goal of supporting the full spec, but it has some capability to parse, report and serialize things differently when it is told to parse HTML (by passing the HTML namespace).

SAX, XML, XMLNS

xmldom has an own SAX parser implementation to do the actual parsing, which implements some interfaces in alignment with the Java interfaces SAX defines:

  • XMLReader
  • DOMHandler

There is an idea/proposal to make it possible to replace it with something else in https://github.com/xmldom/xmldom/issues/55