
Security News
Axios Maintainer Confirms Social Engineering Attack Behind npm Compromise
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.
typescript-xml
Advanced tools
typescript-xml is a lightweight and intuitive TypeScript library for parsing, traversing, querying, and building XML documents. It provides a simple DOM-like API that makes working with XML feel natural in modern TypeScript projects.
parentElement, children, and attributes.getElement(name), findElements(name), and findAllElements(name).Element, Text, Comment, CDATA, ProcessingInstruction, and Doctype.Install the package using your favorite package manager:
# With npm
npm install typescript-xml
# With pnpm
pnpm add typescript-xml
To get started, use the static XmlDocument.parse() method to convert an XML string into a document object.
const xmlString = `
<rss version="2.0">
<channel>
<title>My Feed</title>
<item>
<title>Item 1</title>
</item>
</channel>
</rss>
`;
const document = XmlDocument.parse(xmlString);
If the input string is not well-formed, the parser will throw an Error.
Once parsed, you can easily navigate the document tree.
Start from the rootElement to begin traversal. From any element, you can access its children, attributes, and parentElement.
// Get the root element: <rss>
const rssElement = document.rootElement;
// Get the <channel> element
const channelElement = rssElement.getElement('channel');
if (channelElement) {
// Get all <item> elements within <channel>
const items = channelElement.findElements('item');
console.log(`Found ${items.length} item(s).`);
// Access the text content of the <title> inside the first item
const firstItemTitle = items[0]?.getElement('title')?.innerText;
console.log('First item title:', firstItemTitle); // 'Item 1'
}
The library provides three methods to locate elements:
getElement(name): Returns the first direct child element with the given name, or undefined if not found.findElements(name): Finds direct children of the current node with the provided tag name.findAllElements(name): Finds direct and indirect children of the current node with the provided tag name, searching recursively.To convert your XmlDocument (or any XmlNode) back into a string, use the toXmlString() method. This is useful for saving changes or for sending XML data.
// Get the XML as a compact string
const compactXml = document.toXmlString();
// Or get it nicely formatted
const prettyXml = document.toXmlString({ pretty: true });
console.log(prettyXml);
For very large XML files, loading the entire document into memory can be inefficient. typescript-xml provides an event-based (SAX-style) parser that emits events as it reads the XML stream. This approach is memory-efficient and ideal for processing large datasets.
Use the XmlSaxParser and provide callbacks for the events you want to handle:
const saxParser = new XmlSaxParser({
onStartElement: (event) => {
console.log(`Start Element: ${event.name}`);
if (event.attributes.length > 0) {
const attrs = event.attributes
.map((attr) => `${attr.name}="${attr.value}"`)
.join(', ');
console.log(` Attributes: ${attrs}`);
}
},
onEndElement: (event) => {
console.log(`End Element: ${event.name}`);
},
onText: (event) => {
const trimmedText = event.value.trim();
if (trimmedText) {
console.log(`Text: "${trimmedText}"`);
}
},
});
const xmlStream = `
<library>
<book id="bk101">
<author>Gambardella, Matthew</author>
<title>XML Developer's Guide</title>
<genre>Computer</genre>
</book>
</library>
`;
saxParser.parse(xmlStream);
Here is a more advanced example that showcases combining methods to process a collection of data.
const bookshelfXml = `
<bookshelf>
<book>
<title lang="en">The Hitchhiker's Guide to the Galaxy</title>
<price>12.50</price>
</book>
<book>
<title lang="en">The Lord of the Rings</title>
<price>22.99</price>
</book>
<book>
<title lang="de">Die Verwandlung</title>
<price>9.95</price>
</book>
</bookshelf>
`;
const bookshelfDoc = XmlDocument.parse(bookshelfXml);
const bookshelfRoot = bookshelfDoc.rootElement;
// 1. Find all books and calculate the total price
const allBooks = bookshelfRoot.findAllElements('book');
const totalCost = allBooks
.map(book => {
const priceElement = book.getElement('price');
return priceElement ? parseFloat(priceElement.innerText) : 0;
})
.reduce((sum, price) => sum + price, 0);
console.log(`Total cost: $${totalCost.toFixed(2)}`); // Total cost: $45.44
// 2. Find all English books and log their titles
const englishBooks = bookshelfRoot.findAllElements('book')
.filter(book => {
const title = book.getElement('title');
return title?.getAttribute('lang') === 'en';
});
console.log('English titles:');
englishBooks.forEach(book => {
console.log(`- ${book.getElement('title')?.innerText}`);
});
// 3. Add a new book to the bookshelf
const newBook = new XmlElement('book');
const newTitle = new XmlElement('title');
newTitle.setAttribute('lang', 'en');
newTitle.children.push(new XmlText('Dune'));
const newPrice = new XmlElement('price');
newPrice.children.push(new XmlText('15.00'));
newBook.children.push(newTitle, newPrice);
bookshelfRoot.children.push(newBook);
console.log('\n--- Updated Bookshelf ---');
console.log(bookshelfDoc.toXmlString({ pretty: true }));
For more complex XML creation, XmlBuilder offers a declarative and fluent API to construct documents programmatically. This is especially useful when building documents from data or when the structure is dynamic.
const builder = new XmlBuilder();
builder.element('items', {
nest: () => {
for (let i = 1; i <= 3; i++) {
builder.element('item', {
nest: () => {
builder.attribute('id', `item-${i}`);
builder.element('name', { nest: `Item #${i}` });
builder.element('price', { nest: (i * 1.5).toFixed(2) });
},
});
}
},
});
const doc = builder.buildDocument();
console.log(doc.toXmlString({ pretty: true, indent: ' ' }));
This will produce the following output:
<items>
<item id="item-1">
<name>Item #1</name>
<price>1.50</price>
</item>
<item id="item-2">
<name>Item #2</name>
<price>3.00</price>
</item>
<item id="item-3">
<name>Item #3</name>
<price>4.50</price>
</item>
</items>
typescript-xml provides validation capabilities to ensure your XML documents conform to their schemas and document type definitions.
You can validate XML documents against XSD schemas using the XsdValidator class:
import { XmlDocument, XsdValidator } from 'typescript-xml';
// Your XSD schema
const xsdSchema = `
<?xml version="1.0" encoding="UTF-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="bookshelf">
<xs:complexType>
<xs:sequence>
<xs:element name="book" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="title">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="lang" type="xs:string" use="required" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<xs:element name="price" type="xs:decimal" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="price" type="xs:decimal" minOccurs="0" maxOccurs="1" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
`;
// Your XML document
const xmlDocument = `
<bookshelf>
<book>
<title lang="en">The Hitchhiker's Guide to the Galaxy</title>
<price>12.50</price>
</book>
<price>132.00</price>
</bookshelf>
`;
// Parse and validate
const document = XmlDocument.parse(xmlDocument);
const validator = new XsdValidator(xsdSchema);
try {
validator.validate(document.rootElement);
console.log('✅ XML is valid according to the XSD schema');
} catch (error) {
console.error('❌ Validation failed:', error.message);
}
You can also use the document's built-in validation method:
const document = XmlDocument.parse(xmlDocument);
const validator = new XsdValidator(xsdSchema);
try {
document.validate(validator);
console.log('✅ Document is valid');
} catch (error) {
console.error('❌ Validation failed:', error.message);
}
For documents with DTDs, validation can be performed automatically if the document includes a DOCTYPE declaration:
const xmlWithDtd = `
<!DOCTYPE note [
<!ELEMENT note (to,from,heading,body)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT from (#PCDATA)>
<!ELEMENT heading (#PCDATA)>
<!ELEMENT body (#PCDATA)>
]>
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>
`;
const document = XmlDocument.parse(xmlWithDtd);
try {
document.validate(); // Automatically uses the DTD from the document
console.log('✅ Document is valid according to its DTD');
} catch (error) {
console.error('❌ DTD validation failed:', error.message);
}
typescript-xml is designed for simplicity and ease of use. To maintain its lightweight footprint, it does not currently support:
This library is a faithful port of the dart-xml package, created by Lukas Renggli. A huge thank you to him for the original design and implementation.
This project is licensed under the ISC License. See the LICENSE file for details.
FAQs
A TypeScript XML parser library
The npm package typescript-xml receives a total of 1 weekly downloads. As such, typescript-xml popularity was classified as not popular.
We found that typescript-xml demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.

Security News
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.