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

steady-xml

v0.1.0

Published

**English** | [中文](./README.zh-CN.md)

Downloads

7,960

Readme

steady-xml

English | 中文

A zero-dependence TypeScript library for the steady conversion and processing of XML data.

Origin

After I convert some XML data to JSON for processing, I expect to intact convert it back to XML data which including interlaced element nodes, CDATA nodes, DOCTYPE nodes, comments and so on.

I looked for some famous XML processing libraries (fast-xml-parser, node-xml2js), but most of them consistently chose a compressed conversion to pursue small space and high performance. Although I found a library (xml-js) that can retain as much information as possible, unfortunately it seems to unmaintained.

This is the origin of this library. The core of this library is to preserve XML information as much as possible during the conversion and processing so that the data can be restored intact. space and performance are not the primary concerns.

Features

This library using a class XmlNode to describe XML nodes and relationships. It can construct XmlNode tree from both XML data or JSON, or generate either XML data or JSON from XmlNode.

The algorithm of XML data parsing is referred to fast-xml-parser to a certain extent, which is an excellent algorithm that provides a guarantee for the speed of parsing.

Currently can be resolved nodes:

  • Element (includes attributes)
  • Declaration (includes attributes)
  • Comment
  • DocumentType
  • Text
  • ProcessingInstruction
  • CDATA

Install

yarn add steady-xml

Shorthand

XML to XmlNode

import { parseXmlString } from 'steady-xml'

const rootNode = parseXmlString('<element></element>')

XmlNode to XML:

import { XmlNode, XmlNodeType } from 'steady-xml'

const rootNode = new XmlNode(XmlNodeType.Root)

rootNode.toXmlString()
rootNode.toXmlString('\t', '\n')
rootNode.toXmlString('', '')`${rootNode}`

JSON to XmlNode

import { buildFromJson } from 'steady-xml'

const rootNode = buildFromJson({ name: 'element' })

XmlNode to JSON:

import { XmlNode, XmlNodeType } from 'steady-xml'

const rootNode = new XmlNode(XmlNodeType.Root)

rootNode.toJsObject()
JSON.stringify(rootNode)

Props

type TextValue = string | number | boolean | null

function parseXmlString(xmlString: string, props?: Partial<ParseProps>): XmlNode

interface ParseProps {
  // ignore parse node attributes
  // default: false
  ignoreAttributes: boolean

  // should parse node value
  // default: true
  parseNodeValue: boolean

  // should trim string values
  // default: true
  trimValues: boolean

  // parse node value method
  // default: v => v
  valueProcessor: (value: string, type: XmlNodeType, name: string) => TextValue

  // parse attribute values method
  // default: v => v
  attributeProcessor: (value: string, name: string, type: XmlNodeType) => TextValue
}

function buildFromJson<T extends Record<string, any>>(json: T, props?: Partial<BuildProps>): XmlNode

interface BuildProps {
  // name property key
  // default: 'name'
  nameKey: string

  // type property key
  // default: 'type'
  typeKey: string

  // value property key
  // default: 'value'
  valueKey: string

  // attributes property key
  // default: 'attributes'
  attributesKey: string | false

  // children property key
  // default: 'children'
  childrenKey: string

  // self closing property key
  // default: 'selfClosing'
  selfClosingKey: string | false

  // prefix property key
  // default: 'prefix'
  prefixKey: string | false

  // should trim string values
  // default: true
  trimValues: boolean

  // explicitly specify whether the json is a root node
  // if be specified false, will judge according type
  // if is not a root node, it will as element root node
  // default: false
  isRoot: boolean

  // whether name includes prefix
  // default: false
  prefixInName: boolean

  // parse node value method
  // default: v => v
  valueProcessor: (value: TextValue, type: XmlNodeType, name: string) => TextValue

  // parse attribute values method
  // default: v => v
  attributeProcessor: (value: TextValue, name: string, type: XmlNodeType) => TextValue
}

enum XmlNodeType {
  // is not a real XML node type, only use as the XML data entry
  Root = 'Root',

  // <?xml version="1.0"?>
  Declaration = 'Declaration',

  // <!-- some content -->
  Comment = 'Comment',

  // <!DOCTYPE Items [<!ENTITY number "123">]>
  DocumentType = 'DocumentType',

  // <element></element>
  Element = 'Element',

  // pure text node
  Text = 'Text',

  // <?pi target="target"?>
  Instruction = 'Instruction',

  // <![CDATA[<foo></bar>]]>
  CDATA = 'CDATA'
}

interface XmlJsObject {
  name?: string
  prefix?: string
  type: XmlNodeType
  attributes?: Record<string, unknown>
  value?: any
  selfClosing?: true
  children?: XmlJsObject[]
}

declare class XmlNode {
  // node name
  name: string

  // node type
  type: XmlNodeType

  // parend node
  parent: XmlNode | null

  // chidl node list
  children: XmlNode[] | null

  // attribute map
  attributes: Record<string, unknown>

  // node value
  value: any

  // is self closing
  selfClosing: boolean

  // node prefix
  prefix: string

  constructor(name: string, type: XmlNodeType, parent?: XmlNode | null, value?: any)

  // chain set name
  setName(value: string): this

  // chain set type
  setType(value: XmlNodeType): this

  // chain set parent node
  setParent(value: XmlNode | null): this

  // chain set children list
  setChildren(value: XmlNode[] | null): this

  // chain set attribute map
  setAttributes(value: Record<string, unknown>): this

  // chain set value
  setValue(value: any): this

  // chain set self closing
  setSelfClosing(value: boolean): this

  // chain set prefix
  setPrefix(value: string): this

  // chain add attribute
  addAttribute(name: string, value: unknown): this

  // chain remove attribute
  removeAttribute(name: string): this

  // chain add child node
  addChild(childNode: XmlNode): void

  // chain remove child node
  removeChild(childNode: XmlNode): this

  // generate json data
  toJsObject(): XmlJsObject

  // generate xml string data
  toXmlString(indentChar?: string, newLine?: string, indentCount?: number): string
}

License

MIT License.