# node-xml2js: A Pragmatic XML to JavaScript Converter for Node Developers

> node-xml2js is a CoffeeScript-based library that converts XML to JavaScript objects and back, using sax-js and xmlbuilder-js. It offers a simple callback and Promise API, but its bi-directional fidelity is only guaranteed under default options.

**Leonidas-from-XIV/node-xml2js** — GitHub describes it as XML to JavaScript object converter.. The repository metadata lists CoffeeScript as its primary language. The metadata lists the MIT license. This article stays within the project description and details documented in the GitHub repository README.

- Repository: https://github.com/Leonidas-from-XIV/node-xml2js
- Stars: 4,960 · Forks: 601
- Language: CoffeeScript
- License: MIT
- Published: 2026-08-13 · Updated: 2026-08-18 · Language: en
- Canonical page: https://hysenlabs.com/projects/leonidas-from-xiv-node-xml2js

## What node-xml2js Actually Solves

node-xml2js addresses a narrow but common pain: reading XML in Node.js without writing a parser from scratch or pulling in a heavyweight DOM implementation. The README pitches it as a way to access XML data in a 'sane, easy way', and the core use case is converting XML text into a JavaScript object that you can inspect, manipulate, or serialize to JSON with JSON.stringify. The target audience is JavaScript and CoffeeScript developers who want a quick, callback-based or Promise-based parsing path, and who do not need the full document object model that jsdom provides. The library is not a general-purpose XML toolkit; it is a converter with a specific shape: XML in, object out, and optionally object in, XML out.

## The Parsing Mechanism: sax-js Under the Hood

The parser builds on sax-js, a streaming XML parser, and the README shows two entry points: a standalone parseString function and a Parser class. When you call parseString(xml, callback), the library reads the XML and invokes the callback with an error and a result object. The Parser class offers more control, including a parseString method that accepts a string or a Buffer from fs.readFile, and a parseStringPromise method that returns a Promise. The README stresses that you should create one Parser per file, or call reset() between parses, because reusing a parser without reset is not guaranteed to work. That caveat hints at internal state: sax-js emits events, and xml2js accumulates them into a tree. If you reuse a parser, leftover state can corrupt the next parse. This is a concrete limitation, not a theoretical one, and it shapes how you structure code that processes multiple XML files.

## Getting It Running: Commands and Config Keys

Installation is straightforward: `npm install xml2js` or `bower install xml2js`. The README shows a minimal example: `var parseString = require('xml2js').parseString; parseString(xml, function (err, result) { console.dir(result); });`. Options are passed as a second argument, for example `{trim: true}`. The Builder class is used for the reverse direction: `var builder = new xml2js.Builder(); var xml = builder.buildObject(obj);`. Key configuration keys mentioned are `attrkey`, `charkey`, and `explicitArray`, which control how attributes, character data, and repeated elements are represented in the output object. The README warns that bi-directional conversion is only guaranteed for default configuration, except for those three options. This means if you change other options, such as `cdata` for writing CDATA, you may not get a perfect round-trip. The library also supports `xmlns` attributes in the builder, as shown in the namespace examples, but the README does not detail how the parser handles namespaces, which is a gap you should test yourself.

## The Builder: XML from Objects, With Namespace Support

The Builder side is more than an afterthought. Since version 0.4.0, you can construct XML from a plain object. The README gives a simple example: `{name: 'Super', Surname: 'Man', age: 23}` becomes a `<root>` element with child elements for each key. Attributes are specified with a special `$` key and text content with `_`. This convention is unusual but consistent. The builder also supports XML namespaces, both default and prefixed, by including `xmlns` or `xmlns:prefix` in the `$` object. This is a practical feature for generating SOAP-like payloads or configuration files. However, the README does not explain how the parser handles namespaces on input, so the bi-directional claim may not extend to namespaced documents. If your data uses namespaces heavily, you will need to verify the parser output against your expected object shape, because the documentation is silent on that point.

## Options and Processors: Where the Flexibility Ends

The README mentions that since 0.4.1 you can provide attribute name processors, tag name processors, and element value processors, but the text is truncated at that point, so the exact option names are not given in the material. This is a real limitation of the documentation, not of the library. The known options from the README include `trim` (to trim whitespace in text) and `cdata` (to write CDATA sections in the builder). The README also warns that bi-directional conversion is only guaranteed for default configuration, except for `attrkey`, `charkey`, and `explicitArray`. This means that options like `trim` or `cdata` can break round-trip fidelity. For example, if you parse with `trim: true` and then build the resulting object, the output XML may not match the original. That is a concrete trade-off: you get cleaner objects, but you lose the guarantee of a perfect round-trip. The README does not state which options break fidelity, so you must test each option you plan to use.

## Limitations and Failure Modes

The most explicit failure mode is parser reuse. The README says that reusing a Parser without calling reset() is 'not guaranteed work always, if ever', and recommends creating a new Parser per file. That is a strong warning, and it means you cannot treat a Parser as a stateless utility. Another limitation is the depth of inspection: Node's util.inspect stops at depth 2, so console.dir on a parsed object shows only `[Object]` at deeper levels. The README suggests using `util.inspect(result, false, null)` or configuring the eyes inspector with `maxLength: false`. This is not a bug in xml2js, but it is a practical annoyance that will hit you on the first nested XML document. The library is also not a full DOM parser, as the README notes, so if you need to traverse the document, modify nodes, or handle complex XPath-like queries, you should look at jsdom. For very large XML files, the streaming nature of sax-js may help, but the README does not discuss memory usage or performance, so you should benchmark on your own data.

## Alternatives: jsdom and the DOM Approach

The README explicitly points to jsdom as an alternative for those who need a full DOM parser. The difference in approach is fundamental: xml2js converts XML to a plain JavaScript object, losing the document structure, comments, processing instructions, and the ability to navigate the tree with DOM methods. jsdom parses XML into a DOM tree, which you can query with getElementById, querySelector, and other DOM APIs. If you need to manipulate the document or extract data based on complex structure, jsdom is the better fit. Another alternative is xml-simple, which the README mentions as a prior approach that xml2js aims to replace. xml-simple also converts XML to a simple object, but the README implies xml2js offers more options and a Builder. For a modern project, you might also consider fast-xml-parser or xml2js's own descendants, but the material does not mention them, so I cannot compare. The key distinction is that xml2js is a thin converter, not a DOM implementation, and that boundary shapes every use case.

## Maintenance and License Considerations

The repository is written in CoffeeScript, which is a maintenance consideration. CoffeeScript is less widely used than plain JavaScript, and while the compiled output is what npm installs, contributors need to understand CoffeeScript to modify the source. The project is MIT-licensed, which is permissive and allows commercial use, modification, and redistribution, with the requirement to include the copyright notice. The README does not mention a changelog or release cadence, and the repository metadata shows no recent releases retrieved, so the maintenance status is unclear. The last push is unknown, which means you should check the repository's commit history before adopting it for a long-term project. The library has been around since at least 0.1.11, as the README references, and it has a stable API, but the lack of visible release activity is a signal to verify that it still works with your Node.js version.

## Conclusion

Adopt node-xml2js if you need a quick, dependency-light way to turn XML into plain JavaScript objects in a Node.js or CoffeeScript project, especially for one-off parsing or simple round-trips with default settings. Avoid it if you require full DOM manipulation, strict namespace handling, or guaranteed fidelity with custom options. Before adopting, verify the exact behavior of attrkey, charkey, and explicitArray for your data, and test round-trip conversion with your own XML samples, since the README only promises bi-directional fidelity under default configuration.

## FAQ

### What is a node XML, and does xml2js give me a DOM?

xml2js converts XML into a plain JavaScript object and supports bi-directional conversion, so it can also build XML from an object. If you are looking for a full DOM parser, the project points you at JSDom instead.

### How do I install xml2js?

Two documented routes: `npm install xml2js`, which downloads xml2js and all dependencies, and `bower install xml2js`, which does the same through Bower. The version in the package manifest is 0.6.2.

### Which xml2js parse form should I use?

`require('xml2js').parseString` works from 0.2.3 and takes options as its second argument. `new xml2js.Parser()` was added in 0.1.11 and can be called without `new` from 0.2.8. `parseStringPromise` exists both as a parser method and as a module level function.

### Can one xml2js Parser handle several files?

One parser per file is the recommended route and the one the project promises will always just work. Calling `reset()` on an existing parser is the alternative, while reusing a parser and hoping is documented as not guaranteed to work always, if ever.

### Does xml2js rebuild the same XML it parsed?

Only under the default configuration. A one to one bi-directional conversion is guaranteed for defaults, except that `attrkey`, `charkey` and `explicitArray` can be redefined, which is where a round trip stops matching the input.

## Sources

- [Official README](https://github.com/Leonidas-from-XIV/node-xml2js#readme)
- [Project repository](https://github.com/Leonidas-from-XIV/node-xml2js)
- [README](https://github.com/Leonidas-from-XIV/node-xml2js/blob/master/README.md)
- [Releases](https://github.com/Leonidas-from-XIV/node-xml2js/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/leonidas-from-xiv-node-xml2js
