0.1.0 • Published 3 years ago

steady-xml v0.1.0

Weekly downloads
-
License
MIT
Repository
-
Last release
3 years ago

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.