I found properly creating new elements in an XML document using tDOM a challenge. After some help in the Tcl chat I was shown a few working solutions.

Using createElementNS

package require tdom

set xml  {<ns1:Root xmlns="http://default.com" xmlns:ns1="http://some.otherns.com">
    <ns1:Item>Here be text</ns1:Item>
</ns1:Root>}

dom parse $xml doc
set root [$doc documentElement]
set item [$doc createElementNS  http://some.otherns.com ns1:Item]
set text [$doc createTextNode "other text"]
$item appendChild $text
$root appendChild $item
puts [$root asXML]
<ns1:Root xmlns="http://default.com" xmlns:ns1="http://some.otherns.com/">
    <ns1:Item>Here be text</ns1:Item>
    <ns1:Item>other text</ns1:Item>
</ns1:Root>

Using appendFromScript

I find this option more elegant as it’s much more ergonomic in use. It’s almost like a DSL to create XML chunks.

package require tdom
set xml  {<ns1:Root xmlns="http://default.com" xmlns:ns1="http://some.otherns.com">
    <ns1:Item>Here be text</ns1:Item>
</ns1:Root>}

dom parse $xml doc
dom createNodeCmd -namespace http://some.otherns.com element ns1:Item
dom createNodeCmd textNode t

set root [$doc documentElement]
$root appendFromScript {
    ns1:Item {t Othertext}
}
puts [$root asXML]
<ns1:Root xmlns="http://default.com/" xmlns:ns1="http://some.otherns.com/">
    <ns1:Item>Here be text</ns1:Item>
    <ns1:Item>Othertext</ns1:Item>
</ns1:Root>

Note

The previous version of this post used $doc childNodes to get the root element of the dom tree. This usually works, but the correct way is to use $doc documentElement. Observe the difference in the script below:

package require tdom
set xml "<a/><!-- Comment -->"
set doc [dom parse $xml]
puts "WRONG: [$doc childNodes]"
puts "GOOD:  [$doc documentElement]"

Which prints:

WRONG: domNode0x7f738c43ebb0 domNode0x7f738c43ec10
GOOD:  domNode0x7f738c43ebb0