Search code examples
javascriptxmlnode.jsxml-namespacesxmldom

Adding qualified XML element doesn't inherit namespace URI


How can I append an element with a ns-prefix to another and make it inherit namespaceURI mappings from document?

As an example: Instantiating a document parsing an XML string: The pp:q element inherits namespaceURI == 'abc' from root element, but appending a new element pp:q to root, the new element has namespaceURI == null

doc = new DOMParser().parseFromString(
    '<root xmlns:pp="abc">'
       +'<pp:q/>'
       +'<q/>'
    +'</root>'
    ,'text/xml');
root = doc.firstChild;

x = root.getElementsByTagName("pp:q").item(0);
console.log(x.namespaceURI);       // logs abc

y = doc.createElement('pp:q')
root.appendChild(y)
console.log(y.namespaceURI);       //logs null

This example ran in nodejs using xmldom library

[edited below in response to kjhughes]

I tried createElementNS too, but i feel there's something wrong this way too..
appending these lines to the code:

a = doc.createElementNS('abc', 'pp:q');
root.appendChild(a)
console.log(a.namespaceURI);       //abc --- i may say it works, 
                                   //even though i'm required using  
                                   //both prefix *and* namespaceURI manually
                                   //while for the parsed element (x)
                                   //a lookup has been succesfully issued
                                   // but ... 

a1 = doc.createElementNS('abc', 'xx:q');
root.appendChild(a1)
console.log(a1.namespaceURI);       //abc --- but prefix is xx! not according to xmlns declaration!

b = doc.createElementNS('xyz', 'VV:q');
root.appendChild(b)
console.log(b.namespaceURI);       //xyz  --- I can write anything!

console.log(String(doc));          //<root xmlns:pp="abc"><pp:q/><q/><pp:q/><xx:q/><VV:q/></root> 

Solution

  • Per the documentation of document.createElement(),

    var element = document.createElement(tagName);

    element is the created element object.

    tagName is a string that specifies the type of element to be created. The nodeName of the created element is initialized with the value of tagName. Don't use qualified names (like "html:a") with this method.

    You should instead use document.createElementNS().

    Update per question update:

    Be aware that the namespace itself is what's important, not the namespace prefix. There is no obligation on the part of the API to use a specific namespace prefix when you are providing multiple prefixes for a given namespace. Moreover, realize that .namespaceURI is the namespace, not the namespace prefix.