xmlbuilder2 vs xml-js vs xmlbuilder
XML Data Handling: Conversion, Generation, and Streaming
xmlbuilder2xml-jsxmlbuilderSimilar Packages:

XML Data Handling: Conversion, Generation, and Streaming

xml-js, xmlbuilder, and xmlbuilder2 are essential tools for working with XML in JavaScript environments, but they solve different problems. xml-js focuses on converting XML data to JSON objects and vice versa, making it ideal for data interchange and configuration parsing. xmlbuilder and xmlbuilder2 are designed for programmatically generating XML documents from scratch using a chainable API. While xmlbuilder is the classic, stable implementation, xmlbuilder2 is its modern successor, offering improved performance, streaming support for large files, and better compliance with modern JavaScript standards.

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
xmlbuilder29,515,494412940 kB285 months agoMIT
xml-js01,337-1257 years agoMIT
xmlbuilder0926-76 years agoMIT

XML Data Handling: Conversion, Generation, and Streaming Compared

Working with XML in JavaScript often falls into two distinct categories: converting existing XML data into usable objects (parsing) or creating new XML documents from scratch (generation). xml-js handles the former, while xmlbuilder and xmlbuilder2 handle the latter. Understanding these distinctions is critical for architectural decisions, as using a generator for parsing tasks (or vice versa) leads to unnecessary complexity.

πŸ”„ Core Purpose: Conversion vs. Generation

xml-js is a utility for data transformation.

  • It converts XML strings to JavaScript objects (JSON) and back.
  • It does not build a mutable DOM tree for manipulation.
  • Best for reading configs or API payloads.
// xml-js: Convert XML string to JS object
const convert = require('xml-js');
const xml = '<note><to>Tove</to><from>Jani</from></note>';
const result = convert.xml2js(xml, { compact: true });
// Output: { note: { to: { _text: 'Tove' }, from: { _text: 'Jani' } } }

xmlbuilder is a tree builder for generation.

  • You create nodes programmatically and chain methods.
  • It holds the entire document in memory until you call .end().
  • Best for creating SOAP requests or RSS feeds.
// xmlbuilder: Create XML tree
const builder = require('xmlbuilder');
const root = builder.create('note')
  .ele('to').txt('Tove').up()
  .ele('from').txt('Jani').up();
const xml = root.end({ pretty: true });

xmlbuilder2 is the modern tree builder.

  • Similar chainable API to xmlbuilder but with streaming support.
  • Can write directly to a file or stream without holding everything in RAM.
  • Best for large exports or modern Node.js streams.
// xmlbuilder2: Create XML with streaming capability
const { create } = require('xmlbuilder2');
const root = create().ele('note');
root.ele('to').txt('Tove');
root.ele('from').txt('Jani');
const xml = root.end({ prettyPrint: true });

⚑ Performance and Memory: Buffering vs. Streaming

Memory management is the biggest differentiator between the classic and modern builders.

xml-js loads the entire XML string into memory to parse it.

  • Suitable for small to medium payloads (e.g., config files).
  • Can struggle with very large files (100MB+) due to synchronous parsing.
// xml-js: Synchronous parsing (blocks event loop)
const result = convert.xml2js(largeXmlString);

xmlbuilder builds the full document in memory before outputting.

  • Simple to use but risky for large documents.
  • If you generate a 500MB XML file, you need 500MB+ of RAM.
// xmlbuilder: In-memory construction
const doc = builder.create('root');
// ... add thousands of nodes ...
const output = doc.end(); // All in memory

xmlbuilder2 supports streaming output.

  • You can pipe the output directly to a file or HTTP response.
  • Drastically reduces memory footprint for large generations.
// xmlbuilder2: Stream to file
const { create } = require('xmlbuilder2');
const root = create().ele('root');
const writer = root.write({ prettyPrint: true });
writer.pipe(require('fs').createWriteStream('output.xml'));

πŸ› οΈ API Design: Functional vs. Chainable

The way you interact with these libraries affects code readability and maintenance.

xml-js uses a functional API.

  • You pass data and options to a function.
  • Stateless and easy to test.
// xml-js: Functional style
const json = convert.xml2js(xml, { compact: true, spaces: 2 });
const xmlBack = convert.js2xml(json, { compact: true, spaces: 2 });

xmlbuilder uses a chainable, mutable API.

  • You modify the tree step-by-step.
  • .up() is required to move back to the parent node.
// xmlbuilder: Chainable with .up()
builder.create('book')
  .ele('title').txt('Design Patterns').up()
  .ele('author').txt('Gang of Four').up();

xmlbuilder2 uses a refined chainable API.

  • Similar to xmlbuilder but more intuitive.
  • Handles namespaces and attributes more cleanly.
// xmlbuilder2: Chainable with namespace support
const doc = create().ele('http://example.com/ns', 'book');
doc.att('id', '123').ele('title').txt('Modern XML');

🌐 Real-World Scenarios

Scenario 1: Parsing a Sitemap

You need to read a sitemap.xml to extract URLs for a crawler.

  • βœ… Best choice: xml-js
  • Why? You want to convert the XML to a JSON array of URLs quickly.
// xml-js: Parse sitemap
const sitemap = convert.xml2js(fs.readFileSync('sitemap.xml'));
const urls = sitemap.urlset.url.map(u => u.loc);

Scenario 2: Generating a SOAP Request

You need to construct a specific XML payload for a legacy enterprise API.

  • βœ… Best choice: xmlbuilder2
  • Why? You need precise control over namespaces and structure without manual string concatenation.
// xmlbuilder2: SOAP envelope
const root = create().ele('soap:Envelope').att('xmlns:soap', '...');
root.ele('soap:Body').ele('GetUser').ele('UserID').txt('101');
const payload = root.end();

Scenario 3: Exporting Large Logs

You need to export millions of log entries into a single XML archive file.

  • βœ… Best choice: xmlbuilder2 (Streaming)
  • Why? xmlbuilder would crash due to memory limits; xml-js is for parsing, not generation.
// xmlbuilder2: Stream large data
const writer = create().ele('logs').write({ prettyPrint: false });
logs.forEach(log => writer.ele('entry').txt(log));
writer.end();

Scenario 4: Reading Build Configuration

Your build tool reads a simple config.xml file to set environment variables.

  • βœ… Best choice: xml-js
  • Why? Minimal setup, no need for a full DOM, just need key-value pairs.
// xml-js: Read config
const config = convert.xml2js(fs.readFileSync('config.xml'), { compact: true });
const env = config.config.environment._text;

πŸ“Œ Summary Table

Featurexml-jsxmlbuilderxmlbuilder2
Primary UseXML ↔ JSON ConversionXML GenerationXML Generation
API StyleFunctionalChainableChainable
Memory ModelIn-Memory (Buffer)In-Memory (Buffer)Streaming Supported
DependenciesNoneNoneMinimal
Namespace SupportBasicYesAdvanced
MaintenanceActiveStable (Legacy)Active (Modern)

πŸ’‘ Final Recommendation

Think in terms of data flow direction:

  • Reading XML into your app? β†’ Use xml-js. It turns XML into plain JavaScript objects you can work with easily. It is lightweight and perfect for configuration or API data.
  • Writing XML from your app? β†’ Use xmlbuilder2. It is the modern standard for generation. It avoids the memory pitfalls of the original xmlbuilder and supports streaming, which is essential for scalability.
  • Maintaining old code? β†’ xmlbuilder is still stable and works fine for small tasks, but plan to migrate to xmlbuilder2 for long-term health.

Final Thought: Don't mix tools. Use xml-js for parsing data and xmlbuilder2 for creating documents. This separation keeps your architecture clean and performant.

How to Choose: xmlbuilder2 vs xml-js vs xmlbuilder

  • xmlbuilder2:

    Choose xmlbuilder2 for new projects that require generating XML documents, especially if you are dealing with large datasets. It supports streaming, which prevents memory overload when creating massive files. Its API is similar to xmlbuilder but modernized, offering better error handling and alignment with current web standards. It is the recommended choice for forward-looking architectures.

  • xml-js:

    Choose xml-js when your primary goal is data conversion between XML and JSON formats. It is the best fit for parsing API responses, reading configuration files, or transforming data structures without needing to manipulate the XML DOM directly. It is lightweight and has no dependencies, making it suitable for both Node.js and browser environments where bundle size matters.

  • xmlbuilder:

    Choose xmlbuilder if you are maintaining a legacy codebase that already depends on it or if you need a proven, stable library for generating small to medium-sized XML documents. It offers a simple, chainable API that is easy to learn. However, for new projects requiring high performance or streaming capabilities, you should evaluate xmlbuilder2 instead.

README for xmlbuilder2

xmlbuilder2

An XML builder for node.js.

GitHub License NPM Version NPM Downloads jsDelivr hits (npm)

Node.js CI Code Coverage

GitHub Sponsors

Installation:

npm install xmlbuilder2

Documentation:

See: https://oozcitak.github.io/xmlbuilder2/

Usage:

xmlbuilder2 is a wrapper around DOM nodes which adds chainable functions to make it easier to create and work with XML documents. For example the following XML document:

<?xml version="1.0"?>
<root att="val">
  <foo>
    <bar>foobar</bar>
  </foo>
  <baz/>
</root>

can be created with the following function chain:

const { create } = require('xmlbuilder2');

const root = create({ version: '1.0' })
  .ele('root', { att: 'val' })
    .ele('foo')
      .ele('bar').txt('foobar').up()
    .up()
    .ele('baz').up()
  .up();

// convert the XML tree to string
const xml = root.end({ prettyPrint: true });
console.log(xml);

The same XML document can be created by converting a JS object into XML nodes:

const { create } = require('xmlbuilder2');

const obj = {
  root: {
    '@att': 'val',
    foo: {
      bar: 'foobar'
    },
    baz: {}
  }
};

const doc = create(obj);
const xml = doc.end({ prettyPrint: true });
console.log(xml);

xmlbuilder2 can also parse and serialize XML documents from different formats:

const { create } = require('xmlbuilder2');

const xmlStr = '<root att="val"><foo><bar>foobar</bar></foo></root>';
const doc = create(xmlStr);

// append a 'baz' element to the root node of the document
doc.root().ele('baz');

const xml = doc.end({ prettyPrint: true });
console.log(xml);

which would output the same document string at the top of this page.

Or you could return a JS object by changing the format argument to 'object':

const obj = doc.end({ format: 'object' });
console.log(obj);
{
  root: {
    '@att': 'val',
    foo: {
      bar: 'foobar'
    },
    baz: {}
  }
}

You can convert between formats in one go with the convert function:

const { convert } = require('xmlbuilder2');

const xmlStr = '<root att="val"><foo><bar>foobar</bar></foo></root>';
const obj = convert(xmlStr, { format: "object" });

console.log(obj);
{
  root: {
    '@att': 'val',
    foo: {
      bar: 'foobar'
    }
  }
}

If you need to do some processing:

const { create } = require('xmlbuilder2');

const root = create().ele('squares');
root.com('f(x) = x^2');
for(let i = 1; i <= 5; i++)
{
  const item = root.ele('data');
  item.att('x', i);
  item.att('y', i * i);
}

const xml = root.end({ prettyPrint: true });
console.log(xml);

This will result in:

<?xml version="1.0"?>
<squares>
  <!-- f(x) = x^2 -->
  <data x="1" y="1"/>
  <data x="2" y="4"/>
  <data x="3" y="9"/>
  <data x="4" y="16"/>
  <data x="5" y="25"/>
</squares>

Usage in the browser:

You can build the minified production bundle (lib/xmlbuilder2.min.js) after cloning the repository and issuing npx webpack in your terminal. The bundle is also in the npm package, so you can also use a public npm CDN like jsDelivr or unpkg:

<!-- latest version from jsDelivr -->
<script src="https://cdn.jsdelivr.net/npm/xmlbuilder2/lib/xmlbuilder2.min.js"></script>
<!-- latest version from unpkg -->
<script src="https://unpkg.com/xmlbuilder2/lib/xmlbuilder2.min.js"></script>

Donations:

Please consider becoming a sponsor to help support development.

:heart: Github Sponsors