Creating XML with namespaces with JavaScript and the W3C DOM

Let’s assume you want to create the following XML document with JavaScript and the W3C DOM API:

<root xmlns="http://example.com/ns1"><foo><bar>foobar</bar></foo></root>

The key to doing that properly is to undestand the following: in the XML markup there is an XML default namespace declaration attribute xmlns=”http://example.com/ns1″ on the “root” element that is in scope for the “root” element and all its descendant elements (e.g. the “foo” and the “bar” element) meaning all three elements, the “root” element, the “foo” element and the “bar” element are in that namespace http://example.com/ns1. To create that XML document programmatically you have to create all three elements in that namespace. Thus to create the “root” element you use the createDocument method and pass in namespace and name and to create the descendant elements you use the method createElementNS method and each time pass in the namespace and the name:

var ns1 = 'http://example.com/ns1';

var doc = document.implementation.createDocument(ns1, 'root', null);
var foo = doc.createElementNS(ns1, 'foo');
var bar = doc.createElementNS(ns1, 'bar');
bar.appendChild(document.createTextNode('foobar'));
foo.appendChild(bar);
doc.documentElement.appendChild(foo);

That creates an XML DOM document that, when serialized, looks as the above document. Here is an example showing that. As you can see, the DOM code did not need to create the default namespace declaration attribute at all, nevertheless, the serializer, when serializing the DOM tree, adds it.

Let’s look at a further example that includes elements and attributes in two namespaces:

<root xmlns="http://example.com/ns1"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://example.com/n1 schema.xsd">
<foo>
<bar>foobar</bar>
</foo>
</root>

[Note: for better reading I have inserted whitespace in the XML markup but the code I will show will focus on creating the elements and attributes only, not the whitespace.] In the above XML sample we now have two additional attributes, one namespace declaration attribute xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” and one attribute in that namespace, the xsi:schemaLocation attribute. Again we do not have to create any namespace declaration attributes at all, it suffices to use the previous code and add a call to setAttributeNS and pass in the namespace and the qualified name and the value to create the xsi:schemaLocation attribute:

var ns1 = 'http://example.com/ns1';
var xsi = 'http://www.w3.org/2001/XMLSchema-instance';

var doc = document.implementation.createDocument(ns1, 'root', null);
doc.documentElement.setAttributeNS(xsi, 'xsi:schemaLocation', 'http://example.com/n1 schema.xsd');

var foo = doc.createElementNS(ns1, 'foo');
var bar = doc.createElementNS(ns1, 'bar');
bar.appendChild(document.createTextNode('foobar'));
foo.appendChild(bar);
doc.documentElement.appendChild(foo);

 

Here is an example showing the result. Again, the serializer creates all necessary namespace declaration attributes, as long as elements and attributes have been created in the namespaces they belong to. The only reason to create a namespace declaration attribute explicitly is to enforce its output on an element where the namespace is not used. Let’s look at a further example:

<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<script type="text/ecmascript" xlink:href="foo.js"/>
</svg>

In that XML document the XLink namespace http://www.w3.org/1999/xlink is defined on the root element, the ‘svg’ element, although the namespace is only used on the ‘script’ child element’s attribute xlink:href. This time, if we want to ensure the namespace declaration attribute appears on the ‘svg’ element, we have to explicitly set it on that element (and need to know that namespace declaration attributes are per definition in the namespace http://www.w3.org/2000/xmlns/):

var svgNs = 'http://www.w3.org/2000/svg';
var xlinkNs = 'http://www.w3.org/1999/xlink';

var doc = document.implementation.createDocument(svgNs, 'svg', null);
doc.documentElement.setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:xlink', xlinkNs);

var script = doc.createElementNS(svgNs, 'script');
script.setAttributeNS(null, 'type', 'text/ecmascript');
script.setAttributeNS(xlinkNs, 'xlink:href', 'foo.js');

doc.documentElement.appendChild(script);

 

Here is an example showing the result. If we did not set the namespace declaration attribute on the ‘svg’ element then the resulting serialized document would nevertheless be namespace well-formed XML, only the serializer would add the namespace declaration on the ‘script’ element.

So keep two things in mind when creating XML with namespaces programmatically with the W3C DOM API: you need to create each element and attribute in the namespace it belongs to, passing in the namespace URI to methods like createElementNS or setAttributeNS. And you do not need to create namespace declaration attribute explicitly, unless you want to enforce its appearance on an element where the namespace is not used (like the root element of your document).

The first rule is also of importance when you want to add elements or attributes to an already loaded document. Assuming we have loaded the following document

<root xmlns="http://example.com/ns1">
<foo/>
</root>

and want to add a ‘bar’ element in the same namespace as the other elements then often people assume they can create a ‘bar’ element with createElement(‘bar’) and add it to the root element and that it then takes on the namespace of the root element. That is not the case however, createElement(‘bar’) creates a ‘bar’ element in no namespace and when you insert that as a child of the above ‘root’ element and serialize the serializer will add <bar xmlns=””/> to ensure the created element is serialized in no namespace. So to properly add a ‘bar’ element in the same namespace as the ‘root’ element you again need to use createElementNS and pass in the namespace URI:

var bar = doc.createElementNS(doc.documentElement.namespaceURI, 'bar');
doc.documentElement.appendChild(bar);

 

4 thoughts on “Creating XML with namespaces with JavaScript and the W3C DOM

  1. Hi there Martin,
    Thanks for the wonderful post! Very helpful indeed-=)
    When I click on Here is an example, I get the following:
    ” Example creating an XML document with namespaces with JavaScript and the W3C DOM
    No W3C DOM Level 2 createDocument support. ”

    Any help on this would be highly appreciated!

    Regards,
    Haitham

Leave a Reply

Your email address will not be published. Required fields are marked *