-
-
Notifications
You must be signed in to change notification settings - Fork 110
Home
There are a few ways to start building the XML document, each with their own strengths and weaknesses. The most common API is the create
function which provides some common defaults (XML declaration and the root node) and uses the full range of operations that is exposed by xmlbuilder
. However, it keeps the entire XML tree in memory.
The second function is begin
which is almost identical to create
except it creates an empty document without any defaults.
The real advantage of begin
arises when it is used with a callback function. In that case, XML nodes are written as they are created without keeping the XML tree in memory. However, it is not possible the traverse the document tree or modify already written nodes in this mode.
An XML document is created by calling the create
function of the module. All arguments and their default values are shown below.
var xmlbuilder = require('xmlbuilder');
var root = xmlbuilder.create('root',
{version: '1.0', encoding: 'UTF-8', standalone: true},
{pubID: null, sysID: null},
{keepNullNodes: false, keepNullAttributes: false,
headless: false, ignoreDecorators: false,
separateArrayItems: false, noDoubleEncoding: false,
noValidation: false, invalidCharReplacement: undefined,
stringify: {}});
See this page for information on builder options.
The create
function requires the name of the root node. It is not possible to add attributes to the root node here, but create
can be chained with att
to set root node properties. There are also a number of optional arguments for creating the prolog and document type declaration. XML version number will default to 1.0
if omitted. Prolog and document type declaration can be suppressed with the headless
option. It is also possible to define the internal subset of the DTD. See this wiki page for details.
stringify
provides a set of functions which tell XMLBuilder
how to convert values into strings. For example, the following will prepend myns:
to all node names:
var root = xmlbuilder.create('root', {
stringify: {
name: function(val) {
return 'myns:' + val;
}
}
});
See this page for conversion details.
The create
function will return the new root node.
A second export function begin
is also available to start the XML document. With begin
, an empty document is created without the root element or the XML prolog. It accepts the same options as create
although options related the XML prolog are ignored.
var root = xmlbuilder.begin().ele('root', { 'rootAttribute': 'value' });
The begin
function will return the new document node.
begin
can also be used with a callback function. In callback mode, the XML document will be generated in chunks and each chunk will be passed to the supplied function. In this mode, begin
uses a different code path and the builder should use much less memory since the entire XML tree is not kept. There are a few drawbacks though. For example, traversing the document tree or adding attributes to a node after it is written is not possible. It is also not possible to remove nodes or attributes.
xmlbuilder.begin(function(chunk) { process.stdout.write(chunk); })
.dec()
.ele('root')
.ele('xmlbuilder').up()
.end();
IMPORTANT: This version of begin
returns a callback document object where create
(and the non-callback begin
) would return XML node objects. Although the methods of this object uses the same method signatures, the objects returned are not XML nodes but the same callback document object instance whose state is altered with each call. Use this version of begin
only if you are interested in the final XML document string. If you need to process intermediate nodes, use the create
functions or the non-callback version of begin
above.
Child nodes are created with the element
function (can also be abbreviated to ele
or e
).
var ele = root.ele('child',
{'attribute': 'value',
'attribute2': 'value2'},
'node text');
Node attributes and text are optional and can be specified later with the att
and txt
functions.
There are also the insertBefore
and insertAfter
functions for creating child nodes. They accept the same arguments as the element
function.
var ele = root.ele('third')
.insertBefore('first') // Insert the first node before third
.insertAfter('second'); // Insert the second node after first
element
, insertBefore
and insertAfter
will return the newly created child node.
Child nodes can also be created by passing an object to the element
function. Here is an example:
var obj = {
person: {
name: "John",
'@age': 35,
address: {
city: "Istanbul"
},
phone: [
{ '#text': "555-1234", '@type': 'home' },
{ '#text': "555-1235", '@type': 'mobile' }
],
id: function() {
return 42;
}
}
};
var ele = root.ele(obj);
See this wiki page for conversion details. When called with an object, element
, insertBefore
and insertAfter
will return the last top level child node.
Child nodes can also be created with the node
function (can also be abbreviated to nod
or n
). The difference between node
and element
is that node
does not expand objects (i.e. its first argument must be a string).
Child nodes are deleted with the remove
function.
var ele = root.ele('delete me')
.remove()
.ele('child'));
remove
will return its parent node.
Node attributes are created with the attribute
function (can also be abbreviated to att
or a
). attribute
will create a new attribute or overwrite the attribute value if it already exists.
ele.att('attribute', 'value');
Attributes can be deleted with the removeAttribute
function.
ele.removeAttribute('attribute');
att
and removeAttribute
will return the parent node.
Text nodes are created with the text
function (can also be abbreviated to txt
or t
).
ele.txt('node text');
txt
will return its parent node.
Raw text nodes are created with the raw
function (can also be abbreviated to r
).
ele.raw('this will not be escaped');
raw
will return its parent node.
CDATA nodes are created with the cdata
function (can also be abbreviated to dat
or d
). The value
should not include CDATA delimiters
ele.dat('this will be surrounded by CDATA delimiters');
dat
will return its parent node.
XML comments are created with the comment
function (can also be abbreviated to com
or c
).
ele.com('some comment here');
There are also the commentBefore
and commentAfter
functions for creating comments. They accept the same arguments as the comment
function.
com
, commentBefore
and commentAfter
will return their parent node.
XML processing instructions are created with the instruction
function (can also be abbreviated to ins
or i
).
ele.ins('xml-stylesheet', 'type="text/xsl" href="style.xsl"');
There are also the instructionBefore
and instructionAfter
functions for processing instructions. They accept the same arguments as the instruction
function.
ins
, instructionBefore
and instructionAfter
will return their parent node.
instruction
will append an instruction as a child node under its parent element node.
var foo = xmlbuilder.create('foo').instruction('bar', 'version="13.0"');
var xml = foo.end({ 'pretty': true });
<?xml version="1.0" encoding="utf-8"?>
<foo>
<?bar version="13.0"?>
</foo>
instructionBefore
will add an instruction before its parent element node.
var foo = xmlbuilder.create('foo').instructionBefore('bar', 'version="13.0"');
var xml = foo.end({ 'pretty': true });
<?xml version="1.0" encoding="utf-8"?>
<?bar version="13.0"?>
<foo/>
instructionAfter
will add an instruction after its parent element node.
var foo = xmlbuilder.create('foo').instructionAfter('bar', 'version="13.0"');
var xml = foo.end({ 'pretty': true });
<?xml version="1.0" encoding="utf-8"?>
<foo/>
<?bar version="13.0"?>
Sometimes it is useful to generate XML fragments and later import them into a main document. The importDocument
function takes the root node of an XML document and inserts it after the current node.
var peopleNode = xmlbuilder.create('roster').ele('people');
for (var i = 1; i <= 3; i++) {
// Create an XML fragment
person = xmlbuilder.create('person').att('id', i);
// Import the root node of the fragment after
// the people node of the main XML document
peopleNode.importDocument(person);
}
<?xml version="1.0"?>
<roster>
<people>
<person id="1"/>
<person id="2"/>
<person id="3"/>
</people>
</roster>
Each call to ele
will return the newly created child node. The up
function provides a means to return back to the parent node after creating the child node (can also be abbreviated to u
).
root.ele('child')
.up() // we are back at the root node
.txt('root node text');
There are also the prev
and next
functions which return the node before and after the current node. The root
function can be used to get to the document's root node from anywhere in the document.
root.ele('first')
.up()
.ele('second')
.prev() // returns first
.next() // returns second
.root(); // returns root
The doc
function will return the XML document itself. doc
can be called from anywhere in the document.
root.doc().end(); // Convert the entire document to string
Once the XML document is created, it can be converted to a string by calling the end
function from anywhere in the document.
var xmlString = root.end({
pretty: true,
indent: ' ',
newline: '\n',
width: 0,
allowEmpty: false,
spacebeforeslash: ''
});
If allowEmpty
is set, empty nodes will not be self-closed, for example:
root.end({ allowEmpty: true });
// with allowEmpty: true
<?xml version="1.0"?><root></root>
// with allowEmpty: false
<?xml version="1.0"?><root/>
If spacebeforeslash
is set, the given space character(s) will be inserted before closing tags, for example:
root.end({ spacebeforeslash: ' ' });
// with spacebeforeslash set to a space char
<?xml version="1.0" ?><root />
// without spacebeforeslash
<?xml version="1.0"?><root/>
If width
is set to a number greater than zero, element attributes are divided into multiple lines so that lines are not longer than width
characters.
Instead of the entire XML file, fragments can be created by calling the toString
function of a child node.
root.ele('child')
.toString({
pretty: true,
indent: ' ',
offset: 1,
newline: '\n',
spacebeforeslash: ''
}); // convert only the child node to string
The end
function uses the built-in XML writer for converting the XML document to string. Converter functions can be customized while calling end
:
root.end({
writer: {
text: function(node, options, level) { /* customize the text function */ }
}
});
See this page for more information on customizing the writer.
There is also a built-in stream writer that can be used as follows:
var xmlbuilder = require('xmlbuilder');
var writer = xmlbuilder.streamWriter(process.stdout); // pass a writable stream
var root = xmlbuilder.create('root'); // build the XML document
// ...
// ...
root.end(writer); // call end to pass the XML document to the stream writer
If you need to write your own XML writer, you can do so by creating an object that contains a function property named document
which will receive the XML document when the end
function is called.
function MyWriter() {
this.document = function(doc) {
// doc contains the XML document object.
// Built-in writers contain functions to write the
// XML declaration, document type definition and
// the root node which in turn writes child nodes
// recursively.
}
}
// Use the custom writer
var writer = new MyWriter();
var doc = xmlbuilder.create('root').end(writer);