npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

txml

v6.0.0

Published

fastest XML DOM Parser for node/browser/worker

Readme

tXml v6.0 - Modern XML Parser

npm version License: MIT

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?

  1. Tiny - ~1.5kb minified + gzipped
  2. Fast - 5-10x faster than sax/xml2js, 2-3x faster than fast-xml-parser
  3. Zero dependencies - No bloat, no security concerns
  4. Universal - Works in Node.js, Deno, Bun, browsers, and workers
  5. Fault-tolerant - Parses even malformed XML
  6. Simple API - Easy to use and understand
  7. Well-tested - 100% test coverage
  8. 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)
  • decodeEntities: boolean - Decode XML entities in text and attributes (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: Use selfClosingTags instead
  • filter: (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' } }

You can also pass an XML string directly:

import { simplify } from 'txml';

const result = simplify('<user><name>Alice</name></user>');
// { user: { name: 'Alice' } }

stringify(nodes, options?)

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>'

Options:

  • encodeEntities: boolean - Encode XML entities in text and attributes during output (default: false)
import { parse, stringify } from 'txml';

const nodes = parse('<root a="x &amp; y">a &lt; b</root>', { decodeEntities: true });
const xml = stringify(nodes, { encodeEntities: true });
// '<root a="x &amp; y">a &lt; b</root>'

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());

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());

for await (const node of xmlStream) {
  console.log(node);
}

Other Functions

  • filter(nodes, filterFn) - Filter nodes recursively
  • toContentString(nodes) - Extract text content
  • getElementById(xml, id, simplified?) - Find element by ID
  • getElementsByClassName(xml, className, simplified?) - Find elements by class
  • isTextNode(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());

let count = 0;
for await (const node of stream) {
  count++;
  if (count % 1000 === 0) console.log(`Processed ${count} nodes`);
}

When offset is omitted, tXml auto-detects the root opening tag and starts emitting child elements. Pass a numeric or string offset only when you need explicit control.

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:

  1. Fork the repo
  2. Create a feature branch
  3. Add tests for new features
  4. 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/