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> 
2
  • Did you try a1 = doc.createElementNS('abc', 'q');, if this results in an element pp:q? Commented May 14, 2014 at 12:43
  • a1 = doc.createElementNS('abc', 'q') ends up with a1.namespaceURI == 'abc' and an <q/> element ! Commented May 14, 2014 at 20:10

2 Answers 2

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.

Sign up to request clarification or add additional context in comments.

4 Comments

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!
(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 (<root xmlns:pp="abc"><pp:q/><q/><pp:q/><xx:q/><VV:q/></root> is not.), you will find the calls to be less awkward.
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 namespaceURIs, and.. this is why when an element is created with a NS that NS is not overwritable?
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 <xxx/> 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?
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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.