A fast, safe, compliant XML parser for Node.js and browsers.
Installations
npm install @rgrove/parse-xml
Developer Guide
Typescript
Yes
Module System
CommonJS, UMD
Min. Node Version
>=14.0.0
Node Version
22.10.0
NPM Version
10.9.0
Releases
Contributors
Unable to fetch Contributors
Languages
JavaScript (56.22%)
TypeScript (43.63%)
HTML (0.15%)
Developer
Download Statistics
Total Downloads
10,582,063
Last Day
16,475
Last Week
70,559
Last Month
309,075
Last Year
3,976,025
GitHub Statistics
304 Stars
182 Commits
16 Forks
6 Watching
1 Branches
4 Contributors
Bundle Size
11.97 kB
Minified
4.41 kB
Minified + Gzipped
Package Meta Information
Latest Version
4.2.0
Package Id
@rgrove/parse-xml@4.2.0
Unpacked Size
366.46 kB
Size
80.96 kB
File Count
82
NPM Version
10.9.0
Node Version
22.10.0
Publised On
25 Oct 2024
Total Downloads
Cumulative downloads
Total Downloads
10,582,063
Last day
-2.5%
16,475
Compared to previous day
Last week
-13.9%
70,559
Compared to previous week
Last month
14.9%
309,075
Compared to previous month
Last year
33.6%
3,976,025
Compared to previous year
Daily Downloads
Weekly Downloads
Monthly Downloads
Yearly Downloads
parse-xml
A fast, safe, compliant XML parser for Node.js and browsers.
Links
Installation
npm install @rgrove/parse-xml
Or, if you like living dangerously, you can load the minified bundle in a browser via Unpkg and use the parseXml
global.
Features
-
Returns a convenient object tree representing an XML document.
-
Works great in Node.js and browsers.
-
Provides helpful, detailed error messages with context when a document is not well-formed.
-
Mostly conforms to XML 1.0 (Fifth Edition) as a non-validating parser (see below for details).
-
Passes all relevant tests in the XML Conformance Test Suite.
-
Written in TypeScript and compiled to ES2020 JavaScript for Node.js and ES2017 JavaScript for browsers. The browser build is also optimized for minification.
-
Zero dependencies.
Not Features
While this parser is capable of parsing document type declarations (<!DOCTYPE ... >
) and including them in the node tree, it doesn't actually do anything with them. External document type definitions won't be loaded, and the parser won't validate the document against a DTD or resolve custom entity references defined in a DTD.
In addition, the only supported character encoding is UTF-8 because it's not feasible (or useful) to support other character encodings in JavaScript.
Examples
Basic Usage
ESM
1import { parseXml } from '@rgrove/parse-xml';
2parseXml('<kittens fuzzy="yes">I like fuzzy kittens.</kittens>');
CommonJS
1const { parseXml } = require('@rgrove/parse-xml');
2parseXml('<kittens fuzzy="yes">I like fuzzy kittens.</kittens>');
The result is an XmlDocument
instance containing the parsed document, with a structure that looks like this (some properties and methods are excluded for clarity; see the API docs for details):
1{ 2 type: 'document', 3 children: [ 4 { 5 type: 'element', 6 name: 'kittens', 7 attributes: { 8 fuzzy: 'yes' 9 }, 10 children: [ 11 { 12 type: 'text', 13 text: 'I like fuzzy kittens.' 14 } 15 ], 16 parent: { ... }, 17 isRootNode: true 18 } 19 ] 20}
All parse-xml objects have toJSON()
methods that return JSON-serializable objects, so you can easily convert an XML document to JSON:
1let json = JSON.stringify(parseXml(xml));
Friendly Errors
When something goes wrong, parse-xml throws an error that tells you exactly what happened and shows you where the problem is so you can fix it.
1parseXml('<foo><bar>baz</foo>');
Output
Error: Missing end tag for element bar (line 1, column 14)
<foo><bar>baz</foo>
^
In addition to a helpful message, error objects have the following properties:
-
column Number
Column where the error occurred (1-based).
-
excerpt String
Excerpt from the input string that contains the problem.
-
line Number
Line where the error occurred (1-based).
-
pos Number
Character position where the error occurred relative to the beginning of the input (0-based).
Why another XML parser?
There are many XML parsers for Node, and some of them are good. However, most of them suffer from one or more of the following shortcomings:
-
Native dependencies.
-
Loose, non-standard parsing behavior that can lead to unexpected or even unsafe results when given input the author didn't anticipate.
-
Kitchen sink APIs that tightly couple a parser with DOM manipulation functions, a stringifier, or other tooling that isn't directly related to parsing and consuming XML.
-
Stream-based parsing. This is great in the rare case that you need to parse truly enormous documents, but can be a pain to work with when all you want is a node tree.
-
Poor error handling.
-
Too big or too Node-specific to work well in browsers.
parse-xml's goal is to be a small, fast, safe, compliant, non-streaming, non-validating, browser-friendly parser, because I think this is an under-served niche.
I think parse-xml demonstrates that it's not necessary to jettison the spec entirely or to write complex code in order to implement a small, fast XML parser.
Also, it was fun.
Benchmark
Here's how parse-xml's performance stacks up against a few comparable libraries:
- fast-xml-parser, which claims to be the fastest pure JavaScript XML parser
- libxmljs2, which is based on the native libxml library written in C
- xmldoc, which is based on sax-js
While libxmljs2 is faster at parsing medium and large documents, its performance comes at the expense of a large C dependency, no browser support, and a history of security vulnerabilities in the underlying libxml2 library.
In these results, "ops/s" refers to operations per second. Higher is faster.
Node.js v22.10.0 / Darwin arm64
Apple M1 Max
Running "Small document (291 bytes)" suite...
Progress: 100%
@rgrove/parse-xml 4.2.0:
253 082 ops/s, ±0.16% | fastest
fast-xml-parser 4.5.0:
127 232 ops/s, ±0.44% | 49.73% slower
libxmljs2 0.35.0 (native):
68 709 ops/s, ±2.77% | slowest, 72.85% slower
xmldoc 1.3.0 (sax-js):
122 345 ops/s, ±0.15% | 51.66% slower
Finished 4 cases!
Fastest: @rgrove/parse-xml 4.2.0
Slowest: libxmljs2 0.35.0 (native)
Running "Medium document (72081 bytes)" suite...
Progress: 100%
@rgrove/parse-xml 4.2.0:
1 350 ops/s, ±0.18% | 29.5% slower
fast-xml-parser 4.5.0:
560 ops/s, ±0.48% | slowest, 70.76% slower
libxmljs2 0.35.0 (native):
1 915 ops/s, ±2.64% | fastest
xmldoc 1.3.0 (sax-js):
824 ops/s, ±0.20% | 56.97% slower
Finished 4 cases!
Fastest: libxmljs2 0.35.0 (native)
Slowest: fast-xml-parser 4.5.0
Running "Large document (1162464 bytes)" suite...
Progress: 100%
@rgrove/parse-xml 4.2.0:
109 ops/s, ±0.17% | 40.11% slower
fast-xml-parser 4.5.0:
48 ops/s, ±0.55% | slowest, 73.63% slower
libxmljs2 0.35.0 (native):
182 ops/s, ±1.16% | fastest
xmldoc 1.3.0 (sax-js):
73 ops/s, ±0.50% | 59.89% slower
Finished 4 cases!
Fastest: libxmljs2 0.35.0 (native)
Slowest: fast-xml-parser 4.5.0
See the parse-xml-benchmark repo for instructions on how to run this benchmark yourself.
License
No vulnerabilities found.
Reason
no dangerous workflow patterns detected
Reason
license file detected
Details
- Info: project has a license file: LICENSE:0
- Info: FSF or OSI recognized license: ISC License: LICENSE:0
Reason
0 existing vulnerabilities detected
Reason
no binaries found in the repo
Reason
detected GitHub workflow tokens with excessive permissions
Details
- Warn: no topLevel permission defined: .github/workflows/ci.yml:1
- Info: topLevel 'contents' permission set to 'read': .github/workflows/docs.yml:10
- Info: no jobLevel write permissions found
Reason
0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Reason
Found 0/30 approved changesets -- score normalized to 0
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
security policy file not detected
Details
- Warn: no security policy file detected
- Warn: no security file to analyze
- Warn: no security file to analyze
- Warn: no security file to analyze
Reason
project is not fuzzed
Details
- Warn: no fuzzer integrations found
Reason
no SAST tool detected
Details
- Warn: no pull requests merged into dev branch
Reason
dependency not pinned by hash detected -- score normalized to 0
Details
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:40: update your workflow using https://app.stepsecurity.io/secureworkflow/rgrove/parse-xml/ci.yml/main?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:42: update your workflow using https://app.stepsecurity.io/secureworkflow/rgrove/parse-xml/ci.yml/main?enable=pin
- Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci.yml:46: update your workflow using https://app.stepsecurity.io/secureworkflow/rgrove/parse-xml/ci.yml/main?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:24: update your workflow using https://app.stepsecurity.io/secureworkflow/rgrove/parse-xml/ci.yml/main?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:26: update your workflow using https://app.stepsecurity.io/secureworkflow/rgrove/parse-xml/ci.yml/main?enable=pin
- Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci.yml:30: update your workflow using https://app.stepsecurity.io/secureworkflow/rgrove/parse-xml/ci.yml/main?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/docs.yml:23: update your workflow using https://app.stepsecurity.io/secureworkflow/rgrove/parse-xml/docs.yml/main?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/docs.yml:26: update your workflow using https://app.stepsecurity.io/secureworkflow/rgrove/parse-xml/docs.yml/main?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/docs.yml:29: update your workflow using https://app.stepsecurity.io/secureworkflow/rgrove/parse-xml/docs.yml/main?enable=pin
- Warn: third-party GitHubAction not pinned by hash: .github/workflows/docs.yml:33: update your workflow using https://app.stepsecurity.io/secureworkflow/rgrove/parse-xml/docs.yml/main?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/docs.yml:41: update your workflow using https://app.stepsecurity.io/secureworkflow/rgrove/parse-xml/docs.yml/main?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/docs.yml:54: update your workflow using https://app.stepsecurity.io/secureworkflow/rgrove/parse-xml/docs.yml/main?enable=pin
- Info: 0 out of 9 GitHub-owned GitHubAction dependencies pinned
- Info: 0 out of 3 third-party GitHubAction dependencies pinned
Score
3.8
/10
Last Scanned on 2025-01-20
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn More