TXml
:zap:very small and fast xml-parser in pure javascript:zap:
Install / Use
/learn @TobiasNickel/TXmlREADME
tXml v6.0 - Modern XML Parser
A tiny, fast, and modern XML/HTML parser for JavaScript. Works everywhere: Node.js, Deno, Bun, Browsers, and Web Workers.
✨ What's New in v6.0
- 🎉 Zero dependencies! (removed
through2) - 🚀 Native ES Modules with full CommonJS support
- 📘 Proper TypeScript definitions (hand-written, no more
any) - 🌐 Web Streams API support (browsers, Deno, Bun)
- ⚡ Faster with native Node.js streams
- 🎯 Modern runtime support: Node 18+, Deno, Bun
Upgrading from v5? See the Migration Guide
Why tXml?
- Tiny - ~1.5kb minified + gzipped
- Fast - 5-10x faster than sax/xml2js, 2-3x faster than fast-xml-parser
- Zero dependencies - No bloat, no security concerns
- Universal - Works in Node.js, Deno, Bun, browsers, and workers
- Fault-tolerant - Parses even malformed XML
- Simple API - Easy to use and understand
- Well-tested - 100% test coverage
- Modern - ES Modules, TypeScript, Web Streams
Installation
npm install txml
Quick Start
Node.js / Bun
import * as tXml from 'txml';
const xml = '<user name="John"><age>30</age></user>';
const result = tXml.parse(xml);
console.log(result);
// [{
// tagName: 'user',
// attributes: { name: 'John' },
// children: [{ tagName: 'age', attributes: {}, children: ['30'] }]
// }]
Deno
import * as tXml from 'npm:txml';
const xml = '<user name="John"><age>30</age></user>';
const result = tXml.parse(xml);
Browser (ES Module)
<script type="module">
import * as tXml from 'https://esm.sh/txml';
const result = tXml.parse('<root>test</root>');
</script>
Browser (UMD)
<script src="https://unpkg.com/txml/dist/txml.min.js"></script>
<script>
const result = txml.parse('<root>test</root>');
</script>
TypeScript
import { parse, TNode, ParseOptions } from 'txml';
const options: ParseOptions = {
keepComments: true,
simplify: false
};
const result: (TNode | string)[] = parse('<root>test</root>', options);
API
parse(xml, options?)
Parse XML/HTML string into a DOM-like object.
import { parse } from 'txml';
const result = parse('<user><name>Alice</name></user>');
Options:
keepComments: boolean- Preserve XML comments (default: false)keepWhitespace: boolean- Preserve whitespace text nodes (default: false)simplify: boolean- Auto-simplify output (default: false)selfClosingTags: string[]- Tags that are self-closing (void elements) (default: ['img', 'br', 'input', 'meta', 'link', 'hr'])noChildNodes: string[]- Deprecated: UseselfClosingTagsinsteadfilter: (node, index, depth, path) => boolean- Filter nodes during parsing
Note on Attributes: Element attributes can have three types of values:
- String value:
<div id="test">→{id: "test"}- null: Attribute without value:
<input disabled>→{disabled: null}- Empty string: Attribute with empty value:
<input value="">→{value: ""}
simplify(nodes)
Simplify parsed DOM to a cleaner structure (similar to PHP's SimpleXML).
import { parse, simplify } from 'txml';
const xml = '<user><name>Alice</name><age>25</age></user>';
const result = simplify(parse(xml));
console.log(result);
// { user: { name: 'Alice', age: '25' } }
stringify(nodes)
Convert parsed nodes back to XML string.
import { parse, stringify } from 'txml';
const nodes = parse('<user><name>Alice</name></user>');
const xml = stringify(nodes);
// '<user><name>Alice</name></user>'
transformStream(offset?, options?)
Create a Node.js Transform stream for parsing large XML files.
import { transformStream } from 'txml';
import fs from 'node:fs';
const stream = fs.createReadStream('large.xml')
.pipe(transformStream(0));
for await (const node of stream) {
console.log(node);
}
transformWebStream(offset?, options?)
New in v6! Create a Web Streams API TransformStream (works in browsers, Deno, Bun).
import { transformWebStream } from 'txml';
const response = await fetch('data.xml');
const xmlStream = response.body
.pipeThrough(new TextDecoderStream())
.pipeThrough(transformWebStream(0));
for await (const node of xmlStream) {
console.log(node);
}
Other Functions
filter(nodes, filterFn)- Filter nodes recursivelytoContentString(nodes)- Extract text contentgetElementById(xml, id, simplified?)- Find element by IDgetElementsByClassName(xml, className, simplified?)- Find elements by classisTextNode(node)- Type guard to check if a node is a text node (string)isElementNode(node)- Type guard to check if a node is an element node (TNode)
Examples
Parse RSS Feed
import { parse, simplify } from 'txml';
const rss = await fetch('https://example.com/feed.xml').then(r => r.text());
const dom = parse(rss, { selfClosingTags: [] }); // RSS uses <link> differently
const simplified = simplify(dom);
simplified.rss.channel.item.forEach(item => {
console.log(item.title, item.link);
});
Parse with Attributes
import { parse } from 'txml';
const svg = '<svg width="100" height="100"><circle r="50"/></svg>';
const [svgNode] = parse(svg);
console.log(svgNode.attributes.width); // '100'
console.log(svgNode.children[0].tagName); // 'circle'
Stream Large Files
import { transformStream } from 'txml';
import fs from 'node:fs';
const stream = fs.createReadStream('huge.xml')
.pipe(transformStream('<root>'.length));
let count = 0;
for await (const node of stream) {
count++;
if (count % 1000 === 0) console.log(`Processed ${count} nodes`);
}
Filter During Parse
import { parse } from 'txml';
const xml = '<root><item id="1"/><item id="2"/><other/></root>';
const items = parse(xml, {
filter: (node) => node.tagName === 'item'
});
// Only returns <item> nodes
Type Guards for Mixed Node Arrays
import { parse, isTextNode, isElementNode } from 'txml';
const xml = '<div>Hello <span>World</span>!</div>';
const [div] = parse(xml);
// Filter and process different node types
div.children.forEach(child => {
if (isTextNode(child)) {
console.log('Text:', child);
} else if (isElementNode(child)) {
console.log('Element:', child.tagName, child.attributes);
}
});
// Or use for filtering
const textNodes = div.children.filter(isTextNode);
const elementNodes = div.children.filter(isElementNode);
Tree-Shaking
Import only what you need:
// Full package (includes streams, ~3kb)
import * as tXml from 'txml';
// Parser only (no Node.js deps, ~1.5kb)
import { parse, simplify } from 'txml/txml';
// Stream only
import { transformStream } from 'txml/transform-stream';
Performance
tXml is one of the fastest pure JavaScript XML parsers:
| Parser | Time (ms) | Relative | |--------|-----------|----------| | tXml | 100 | 1x | | fast-xml-parser | 250 | 2.5x slower | | xml2js | 800 | 8x slower | | Native DOMParser | 95 | 0.95x faster* |
*Native DOMParser is browser-only and not available in Node.js
Browser Support
- Chrome, Firefox, Safari, Edge (modern versions)
- IE11 (with polyfills for Object.keys, Array.forEach)
Requirements
- Node.js: 18.0.0 or higher
- Deno: Any version
- Bun: Any version
- Browsers: Modern browsers with ES6 support
Need Node.js < 18? Use txml@5 (see Migration Guide)
Development
# Install dependencies
npm install
# Build
npm run build
# Test
npm test
# Test specific file
node --test test/test-basic.js
License
MIT © Tobias Nickel
Contributing
Contributions are welcome! Please:
- Fork the repo
- Create a feature branch
- Add tests for new features
- Submit a pull request
Credits
Created by Tobias Nickel in 2015. Major modernization in 2025 (v6.0).
Try it online: https://tnickel.de/2017/04/02/2017-04-txml-online/
