3

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> 
aleclofabbro
  • 1,635
  • 1
  • 18
  • 35

2 Answers2

1

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.

kjhughes
  • 106,133
  • 27
  • 181
  • 240
  • Ok, it's reasonable, but: #1:the prefix _is_ important when parsing an xml, as the namespace is looked up according to it.. #2:if i createElementNS and append like in last 2 examples (a1,b) the serialization looses ``.namespaceURI`` unless i manually-explicitally addAttributeNS according to the added element.. that's really awkward! – aleclofabbro May 14 '14 at 18:39
  • (1) The namespace prefix is arbitrary; mind your assumptions when using multiple, different namespace prefixes for the same namespace name. (2) Take care to declare all namespace prefixes that you use. I believe that when you fix your calls such that your document is [namespace-well-formed](http://www.w3.org/TR/xml-names/#Conformance) (`` is *not*.), you will find the calls to be less awkward. – kjhughes May 14 '14 at 19:07
  • So, it means that the right way is to take _personally detailed_ care of everything using ``DOM`` apis, and, in this case, use ``element.lookupPrefix()`` and ``element.lookupNamespaceURI()`` to keep elements consistent with ``prefixes`` and ``namespaceURI``s, and.. this is why when an element is created with a ``NS`` that ``NS`` is not overwritable? – aleclofabbro May 14 '14 at 21:47
  • Let me finally ask to clarify: having ``xmlns:ns="abc"`` on ``root`` element and appending a ``createElementNS('abc', 'xxx')`` (``xxx`` without any prefix or with ``prefix != 'ns'``) i'll have ```` with namespace ``abc`` .. when i serialize the dom to string and save it, `xxx`'s namespace is lost for next consumers. Is this how it is supposed to be, or i am missing something? – aleclofabbro May 14 '14 at 23:32
0

You are getting confused, because you use console.log(String(doc)); to output the XML. Use XML serializer instead: console.log((new XMLSerializer()).serializeToString(doc));

Other points to keep in mind

  1. Always use createElementNS() when creating elements that have a namespace URI (with or without a prefix).
  2. The namespace prefix doesn't matter. What matters are the namespace URI and the corresponding namespace definition (that either binds the URI to a prefix or makes the namespace a default namespace).
  3. If any element or attribute uses some prefix that prefix must be bound to a namespace URI. Otherwise the document will be (namespace) invalid.
  4. Do not use mimetype text/xml, it will lead to serious encoding problems and is deprecated. Use application/xml - or in this case application/xhtml+xml - instead.
jasso
  • 13,736
  • 2
  • 36
  • 50