Skip to content

XMLPrinter

do- edited this page Mar 3, 2025 · 42 revisions

XMLPrinter is a utility class for generating limited size balanced fragments of well formed XML text using a minimalistic API.

const {XMLPrinter} = require ('xml-toolkit')

const xp = new XMLPrinter ({
//  decl: {encoding: 'UTF-8', standalone: 1},
//  space: 2, 
//  attrSpace: 1, 
//  EOL: '\n',
//  level: 0, 
//  encodeLineBreaks: false,
})

const xml = xp
.openElement ('outer')
	.writeAttribute ('id', '1')
	.openElement ('inner')
		.writeCharacters ('txt')
	.closeElement ()
	.openElement ('leaf').closeElement ()
.closeElement ()
.text

Description

XMLPrinter instance accumulates its .text chunk by chunk, synchronously. It has no protection against memory overflow, so you don't print complete huge XML documents this way. But it's OK to use it repeatedly to format multiple isolated elements, with an arbitrary indent (see, the level option, the reset () method).

The output can be:

  • either onelined (when the space option is undefined)
  • or pretty printed, with each nesting level indented with
    • the space string (\t for instance)
    • or space number of 0x20 characters (2 means ' ').

For pretty printing, os.EOL is used as the default line ending. It's overridable with the eponymous option.

By default, attributes are printed in line along with the containing opening tag, but you can set the extra attrSpace: in this case, each attribute is presented on a new line, indented.

For the sake of readability, all \n and \r characters are replaced with numerical entities for both character nodes and attribute values. Though it's possible to turn off this feature with the encodeLineBreaks option.

Note on Namespaces

The basic API ignores XML Namespaces: all names are just strings (that can contain colons), NS declarations can be printed as attributes, ensuring consistency is up to the caller.

However, the high level method writeNode scans its argument and dumps all necessary xmlns[:...] attributes.

Limitations

All values (for both attributes and text nodes) must be provided as Strings. No attempt is made to stringify numbers, dates etc. Any non-string value, including null and undefined, is rejected.

XML comments are not supported by the API, neither are DTDs nor PIs (but the XML declaration).

Constructor Options

Name Default Description
attrSpace undefined The additional indent for attributes. Similarly to space, can be set as a string or a number. When set, a line is added for each attribute. Otherwise, each opening tag belong to one line
decl undefined If set, writeXMLDecl will be called automatically with this argument
encodeLineBreaks true Whether to print line breaking characters as nuberical entities
space undefined A literal string or the number of space (0x20) characters to indent opening and closing tags
level 0 The additional indent level for each string
EOL undefined os.EOL by default, this value is used for line breaks

Properties

Name Type Default Description
text String '' The XML text accumulated so far
stack Array [] Names of nested unclosed elements
isOpening Boolean false Whether the opening tag is left unclosed to append attributes

Methods

Low Level API

Hereafter, the methods are listed in typical calling order, not alphabetically. The return value is always this, to allow chaining.

reset ()

Sets all properties to their default values. If decl option is set, calls writeXMLDecl. Called automatically by the constructor.

writeXMLDecl ({encoding?, standalone?})

Prints <?xml version="1.0" ... ?> with encoding and standalone (when set). Throws an error unless text is empty. The encoding value is copied as is, truthy/falsy standalone is mapped to 'yes'/'no'.

openElement (name)

Prints <${name} prepended with the necessary whitespace leaving the tag opened for appending attributes.

writeAttribute (name, value)

Prints ${name}="${value}" with the needed spacing and character escaping. Throws an error unless an opening tag is still pending.

writeBody (value)

For a zero length value, does nothing.

Otherwise, closes the opening tag (if not yet) and prints the value as is, unescaped: it must be a well formed XML fragment. This low level method is for things like xs:any.

Throws an error when called before opening of after closing the root element.

writeCharacters (value)

Escapes value and proxies to writeBody.

closeElement ()

Prints the indented </${name}> (with the name taken out from the internal stack) or just />.

Convenience Methods

writeNode (node)

Prints out a complete XMLNode, recursively.

Clone this wiki locally