xmlbuilder2

repository·master·Indexed 19 days ago

https://github.com/oozcitak/xmlbuilder2

An XML builder for Node.js and the browser that provides a chainable API for creating, manipulating, and parsing XML documents. It supports working with XML strings, DOM-like nodes, and plain JavaScript objects. Key features include a streaming API via createCB and fragmentCB for large documents, a convert function for transforming XML to JavaScript objects, and detailed handling of character encoding and decoding during serialization and parsing.

Tokens
35K
Snippets
124
Records
151
Agent score
61%

What's inside xmlbuilder2

  1. Understanding Round Trip behavior: String -> XML -> String

    master

    A round trip from a raw string to an XML document and back to a string may result in different string representations for certain characters due to how they are parsed and re-serialized.

    • CDATA, Comment, and Processing Instruction nodes: These are safe and will result in the same string.
    • Text nodes: May change. For example, ' is decoded to ', but when re-serialized, it remains ' (not '). Numeric references like 	 are decoded to \t and re-serialized as the literal character \t rather than the entity.
    • Attribute nodes: May change. While " is preserved, whitespace characters like 
 (hexadecimal newline) are normalized to 
 (decimal newline) during the round trip.
  2. Understanding Round Trip behavior: XML -> String -> XML

    master

    A round trip from an XML document to its string representation and back to an XML document is safe. All encoded values are correctly decoded back to their original character representations, ensuring data integrity for text and attribute nodes.

    • CDATA, Comment, and Processing Instruction nodes: Safe (no processing).
    • Text nodes: Safe (all encoded values are decoded back).
    • Attribute nodes: Safe (all encoded values are decoded back).
  3. How callback builder functions work

    master

    The createCB and fragmentCB functions allow you to create XML documents in chunks. This is useful for generating very large XML documents without keeping the entire tree in memory, preventing memory exhaustion.

    Key Differences:

    • Memory Efficiency: Unlike the standard create function, these functions serialize data as it is built.
    • Object Type: They return an instance of XMLBuilderCB, which is different from the XMLBuilder returned by create. While method signatures are similar, XMLBuilderCB methods do not return XML node wrappers; instead, they modify the state of the same object instance.
    • Use Case: Use these if you only need the final XML string (or stream). If you need to traverse or process intermediate nodes, use the standard create function instead.
    const { createCB, fragmentCB } = require('xmlbuilder2');
  4. Understand namespace inheritance

    master

    In xmlbuilder2, child element nodes automatically inherit the namespace of their parent element. If a parent element is created with a specific namespace URI, all subsequent children created without an explicit namespace will belong to that same URI.

    const { create } = require('xmlbuilder2');
    
    const root = create()
      .ele('http:/example.com', 'root')
        .ele('node')
      .up();
    
    const node = root.node.firstElementChild;
    console.log(node.namespaceURI); // 'http:/example.com'
  5. How XML serialization handles character encoding

    master

    When serializing an XML document to a string, encoding rules vary by node type:

    • CDATA, Comment, and Processing Instruction nodes: No special processing is performed.
    • Text nodes: Only &, <, and > are encoded into predefined entities. Other characters are left as-is.
    • Attribute nodes: &, <, >, and " are encoded. Note that the apostrophe (') is not encoded because attribute values are always serialized with double quotes. Additionally, whitespace characters \t, \n, and \r are encoded into numeric character references.
  6. Use JS object conversion for special nodes in xmlbuilder2

    master

    When using JS object syntax to create nodes in xmlbuilder2, the keys for special node types have changed from xmlbuilder:

    • Processing Instructions: Use the key "?" where the value is "target content".
    • CDATA Sections: Use the key "$".
    • Comments: Use the key "!".

    You can override these default converters during creation if needed.

    Note: Overriding these will also override the default text converter (which uses #text).

    // Processing Instruction
    const root = create().ele("root").ele({ "?": "target content" });
    
    // CDATA Section
    const root = create().ele("root").ele({ "$": "value" });
    
    // Comment
    const root = create().ele("root").ele({ "!": "value" });
    
    // Overriding converters
    const root = create({ convert: { text: "#text", cdata: "#cdata" } }).ele("root").ele({ "#cdata": "value" });
    
    // Overriding comment converter
    const root = create({ convert: { text: "#text", comment: "#comment" } }).ele("root").ele({ "#comment": "value" });
  7. How XML parsing handles character encoding and decoding

    master

    When parsing an XML string, xmlbuilder2 applies different decoding rules depending on the node type:

    • CDATA, Comment, and Processing Instruction nodes: No special processing is performed. All characters from the input string are passed to the node value as-is.
    • Text and Attribute nodes: The parser decodes the five predefined XML entities, numeric character references (&#nnnn;), and hexadecimal numeric character references (&#xhhhh; - note that the x must be lowercase).
  8. Use namespace aliases with '@' and '@@'

    master

    To avoid repeating long namespace URIs, you can use aliases.

    Built-in Aliases

    The following namespaces are built-in and can be used by prepending them with '@':

    • html: http://www.w3.org/1999/xhtml
    • xml: http://www.w3.org/XML/1998/namespace
    • xmlns: http://www.w3.org/2000/xmlns/
    • mathml: http://www.w3.org/1998/Math/MathML
    • svg: http://www.w3.org/2000/svg
    • xlink: http://www.w3.org/1999/xlink

    Custom Aliases

    Define custom aliases in the create() configuration using the namespaceAlias key. Use the '@' prefix in method calls to reference them.

    Object Conversion Aliases

    When converting a JavaScript object to XML, separate the element name and the alias using '@@', and the attribute name and alias using '@att@@'.

    const { create } = require('xmlbuilder2');
    
    // 1. Using built-in aliases
    const ele1 = create().ele('@xml', 'root').att('@xml', 'att', 'val');
    console.log(ele1.toString()); // '<xml:root xml:att=\'val\'/>'
    
    // 2. Using custom aliases
    const ele2 = create({ namespaceAlias: { ns: 'ns1' } }).ele('@ns', 'p:root').att('@ns', 'p:att', 'val');
    console.log(ele2.toString()); // '<p:root xmlns:p=\'ns1\' p:att=\'val\'/>'
    
    // 3. Using aliases in JS object conversion
    const ele3 = create().ele({ 'root@@xml': { '@att@@xml': 'val' }});
    console.log(ele3.toString()); // '<xml:root xml:att=\'val\'/>'
  9. Declare namespaces for elements and attributes

    master

    You can explicitly assign namespaces to specific elements or attributes using the following patterns:

    Default Namespace for an Element

    Pass the namespace URI as the first argument to .ele() to set a default namespace for that element and its children.

    Namespace Declaration Attribute

    Use .att() with a namespace URI as the first argument to declare a namespace prefix (e.g., xmlns:xsi).

    Element with a Specific Namespace

    Pass the namespace URI as the first argument to .ele() to create an element belonging to that namespace.

    Attribute with a Namespace

    Pass the namespace URI as the first argument to .att() to create a namespaced attribute.

    const { create } = require('xmlbuilder2');
    
    const ns1 = 'http://example.com/ns1';
    const xsi = 'http://www.w3.org/2001/XMLSchema-instance';
    
    // Example: Element with default namespace and a namespaced attribute
    const doc = create().ele(ns1, 'root')
      .att(xsi, 'xsi:schemaLocation', 'http://example.com/n1 schema.xsd')
      .ele(ns1, 'foo').txt('bar').doc();
    
    console.log(doc.end({ headless: true, prettyPrint: true }));
  10. Use xmlbuilder2 with the xpath module

    master

    Because xmlbuilder2 implements the DOM specification, you can use it with any library compatible with DOM interfaces, such as the xpath module. To perform XPath queries on an xmlbuilder2 document, pass doc.node (the underlying DOM node) to the library's selection function.

    Namespaces are fully supported via standard XPath functions like local-name() and namespace-uri().

    const { create } = require('xmlbuilder2');
    const { select } = require('xpath');
    
    const doc = create("<book><title>The Book</title></book>");
    const nodes = select("//title", doc.node);
    
    console.log(nodes[0].localName); // "title"
    console.log(nodes[0].firstChild.data); // "The Book"
    console.log(nodes[0].toString()); // "<title>The Book</title>"