mrkeyoor.com_
Sat 08 Aug 21:56 UTC
npmUtilsupdated 08 Aug 2026

js2xmlparser

js2xmlparser converts a JavaScript value into a complete XML document string. Plain object keys become element names, arrays become repeated sibling elements, and reserved keys represent attributes, bare text, or a renamed element. It also handles Map and Set values, XML declarations, DTDs, CDATA, pretty-printing, custom type conversion, and insertion into an existing xmlcreate element. It is a serializer, not an XML reader or schema mapper.

Verdict

A good fit when your XML is a direct projection of JSON-shaped data and you can standardize its reserved-key convention. Choose a builder or bidirectional parser once namespaces, streaming, schema validation, or exact mixed-content control become central.

API stability4/5Version 5 exposes a small surface centered on parse, parseToExistingElement, Absent, and one options object. The changelog shows the last breaking redesign happened in 2.0, when the callable export became parse and several option names changed; later majors added behavior without expanding the core model much. Reserved-key semantics are predictable once adopted, though they are part of your data contract.
Docs4/5The README gives a complete object-to-XML example and links to versioned generated API documentation. The TypeScript source comments specify defaults and include examples for aliases, attributes, bare text, handlers, CDATA, wrapping, declarations, DTDs, and formatting. The weak spot is task-oriented guidance: users must assemble several option descriptions to understand arrays, omission, and mixed content.
Maintenance3/5The latest npm version, 5.0.0, was published in September 2022, but the repository was pushed in November 2025 and currently reports only one open issue or pull request. This looks like a small, stable utility receiving occasional upkeep rather than an abandoned repository or an actively developed platform. Its narrow API reduces maintenance pressure, but release cadence is slow.
Ecosystem3/5The package receives 3,800,351 weekly npm downloads and delegates XML construction to the separately published xmlcreate library, so it is well established in dependency trees. It ships its own TypeScript declarations and has no peer setup. Still, its 220 GitHub stars and specialized one-way API are modest beside broader XML packages that parse, build, and support more document operations.

Use it if

  • You need a compact Node.js utility that turns JSON-shaped data into a complete XML string with a named root
  • Your XML format maps cleanly to object keys, repeated array elements, attributes under @, and text under #
  • You need TypeScript declarations, CDATA controls, DTD output, or custom handlers for Date and other JavaScript types
  • You already use xmlcreate and want to append object-shaped data to an XmlElement with parseToExistingElement
Skip it if

Setup reality

Install `js2xmlparser` and import its `parse` function; the package is CommonJS but ships declarations through its `typings` entry. Its only runtime dependency is `xmlcreate`, and there are no peer dependencies, native builds, credentials, or config files. The work is designing an object convention that matches the XML your consumer expects. By default `@` introduces attributes, `#` introduces bare text, and `=` renames the current element. A prefix match is used for attribute and value keys, so keys such as `@meta` and `#2` are structural too. Arrays and Sets produce repeated elements named after the property; they do not add a container unless a `wrapHandlers` function tells the serializer what to call each item. Pretty-printing and an XML declaration are enabled by default, single quotes are used for attributes, empty values become self-closing tags, and validation is enabled. Those defaults can break byte-for-byte fixtures or partners that demand a specific declaration, indentation, quote style, or explicit closing tag. Native objects fall back to `toString()`, which makes Date output dependent on the runtime's local timezone and format unless you install a type handler. Null and undefined are not automatically omitted; return `Absent.instance` from a matching handler when omission is required. CDATA is opt-in, while normal text is escaped. `replaceInvalidChars` substitutes U+FFFD rather than rejecting invalid input, so use it only when lossy cleanup is acceptable. Finally, the result is one in-memory string, not a stream, and XML schema validation remains a separate step.

Patterns

Convert an object to an XML documentserialize-object

const { parse } = require('js2xmlparser');

const xml = parse('user', {
  name: 'Ada',
  active: true,
});
console.log(xml);

The first argument is the required root element name. An XML declaration and pretty formatting are included by default.

Put attributes on an elementadd-attributes

const xml = parse('product', {
  '@': { id: 'sku-42', currency: 'USD' },
  name: 'Keyboard',
  price: 99,
});

Any object key beginning with the default @ marker is treated as an attribute collection, not as a child element.

Combine element text with attributesmix-text-and-attributes

const xml = parse('message', {
  '@': { lang: 'en' },
  '#': 'Hello & welcome',
});

The # property becomes bare text and special characters are escaped. Use a named child property when you actually want a nested element.

Emit repeated sibling elements from an arrayrepeat-elements

const xml = parse('catalog', {
  item: [
    { '@': { id: 'a' }, '#': 'Alpha' },
    { '@': { id: 'b' }, '#': 'Beta' },
  ],
});

An array under item produces multiple item elements directly. It does not create a separate array wrapper.

Add a container around array itemswrap-array-items

const xml = parse('order', { lines: ['A', 'B'] }, {
  wrapHandlers: {
    lines: () => 'line',
  },
});

This emits a lines container containing line elements. Returning null from the handler keeps the default unwrapped repeated elements.

Choose an element name from datarename-element

const xml = parse('root', {
  entry: {
    '=': 'warning',
    '#': 'Disk space low',
  },
});

The default = alias changes the current element name. Type handlers are not applied to alias values.

Preserve order with Map and numbered text keyspreserve-mixed-order

const content = new Map([
  ['#1', 'Read '],
  ['link', { '@': { href: '/docs' }, '#': 'the docs' }],
  ['#2', ' first.'],
]);

const xml = parse('p', content);

Map iteration order controls placement. Distinct # keys allow text to appear on both sides of a child element.

Use CDATA for selected elementsemit-cdata

const xml = parse('article', {
  title: 'XML tips',
  source: 'if (a < b && b > 0) {}',
}, {
  cdataKeys: ['source'],
});

Only matching element names use CDATA. Embedded ]]> sequences are split safely rather than copied into an invalid CDATA section.

Control declaration and whitespaceformat-output

const xml = parse('response', { ok: true }, {
  declaration: {
    include: true,
    encoding: 'UTF-8',
    standalone: 'yes',
  },
  format: {
    pretty: true,
    indent: '  ',
    newline: '\n',
    doubleQuotes: true,
  },
});

Formatting choices affect serialized bytes. Match the receiving system's fixtures if signatures or strict comparisons are involved.

Serialize dates deterministically and omit nullsnormalize-types

const { parse, Absent } = require('js2xmlparser');

const xml = parse('event', {
  at: new Date('2026-08-08T12:00:00Z'),
  note: null,
}, {
  typeHandlers: {
    '[object Date]': (value) => value.toISOString(),
    '[object Null]': () => Absent.instance,
  },
});

Without handlers, native values use normal string conversion. Returning Absent.instance suppresses the element entirely.

Add a system DTD declarationinclude-dtd

const xml = parse('invoice', { total: 125 }, {
  dtd: {
    include: true,
    name: 'invoice',
    sysId: 'invoice.dtd',
  },
});

With validation enabled, dtd.name is required when the DTD is included; a public identifier also requires a system identifier.

Append object data to an xmlcreate elementappend-existing-element

const { XmlDocument } = require('xmlcreate');
const { parseToExistingElement } = require('js2xmlparser');

const doc = new XmlDocument();
const root = doc.element({ name: 'feed' });
parseToExistingElement(root, { item: ['one', 'two'] });
const xml = doc.toString();

parseToExistingElement adds no root, declaration, or DTD. Those document-level concerns belong to the existing xmlcreate document.

Alternatives

PackageRegistryPick it when
xmlbuilder2npmYou need a fluent builder, namespaces, document manipulation, converters, or callback-based output control
fast-xml-parsernpmYou need both XML parsing and object-to-XML building, with configurable attribute and text-node conventions
xml-jsnpmYou need bidirectional XML and JavaScript conversion with compact and non-compact representations