Although tDOM has excellent parsing capabilities, the internal representation of XML Nodes is hidden in C language structures. Additionally, accessing these structures creates commands which pollute the global namespace. The XML Standard itself recommends something called an XML Infoset. As the name implies, this is a data structure, so that everything should be accessible as a named variable, instead of as an object.method.
Tcl has something called a Namespace which allows developers to organize data and commands into a hierarchical structure similar to an XML Document. The limitations on possible XML Element and Attribute names makes it easy to guarantee that any XML Document can be represented as a hierarchical Tcl Namespace.
# API Signature: (this is a recursive procedure) ::wsdl::instance::new instanceNS xmlList {isDoc 0} # For isntance: ::wsdl::instance::new ::mytns {addressBook {} { {card {type simple} { {name {type full} {{#text {John Smith}}}} { email {} {{#text js@example.com}}}}} { card {} {{name {} {{#text {Fred Bloggs}}}} { email {} {{#text fb@example.net}}}}}}} 1 # This corresponds to the XML Document: <!DOCTYPE addressBook SYSTEM "simple.dtd"> <addressBook> <card type="simple"> <name type="full">John Smith</name> <email>js@example.com</email> </card> <card> <name>Fred Bloggs</name> <email>fb@example.net</email> </card> </addressBook>
namespace eval ::wsdl::instance::x::a:addresses { set .PARTS {address::0 address::1 notes owner} # Address is array, so dummy: namespace eval address {} namespace eval address::0 { set .ATTR(name) address1 set .ATTR(location) home namespace eval street { set .PARTS {.TEXT(0)} set .TEXT(0) "3812 155th Ave. SE" } namespace eval city { set .PARTS {.TEXT(0)} set .TEXT(0) "Bellevue" } namespace eval state { set .PARTS {.TEXT(0)} set .TEXT(0) "WA" } namespace eval zip { set .PARTS {.TEXT(0)} set .TEXT(0) "98006" } set .PARTS {street city state zip} } namespace eval address::1 { set .ATTR(name) address2 set .ATTR(location) work namespace eval street { set .PARTS {.TEXT(0)} set .TEXT(0) "4321 1st Ave. N" } namespace eval city { set .PARTS {.TEXT(0)} set .TEXT(0) "Seattle" } namespace eval state { set .PARTS {.TEXT(0)} set .TEXT(0) "WA" } namespace eval zip { set .PARTS {.TEXT(0)} set .TEXT(0) "98102" } set .PARTS {street city state zip} } namespace eval notes { set .PARTS {.TEXT(0) b .TEXT(1)} set .TEXT(0) " This is a " set .TEXT(1) " idea " namespace eval b { set .PARTS {.TEXT(0)} set .TEXT(0) Great } } namespace eval owner { set .PARTS {} set .ATTR(name) "Tom Jackson" } }
Note that there are many ways to build up the above representation, the one shown being very verbose. The serializing API would be called like this:
::wsdl::instance::toXML ::wsdl::instance::x::a:addresses
Producing the following XML:
<a:addresses> <address location="home" name="address1"> <street>3812 155th Ave. SE</street> <city>Bellevue</city> <state>WA</state> <zip>98006</zip> </address> <address location="work" name="address2"> <street>4321 1st Ave. N</street> <city>Seattle</city> <state>WA</state> <zip>98102</zip> </address> <notes> This is a <b>Great</b> idea </notes> <owner name="Tom Jackson"/> </a:addresses>
The ::wsdl::instance::toXML API highlights the simplicity of passing a complex data structure when it is packaged as a Tcl Namespace. This simplicity will be exploited throughout the tWSDL Package. The Tcl Namespace representation relies on the fact that no XML Element may start with a punctuation mark, in this case a dot ".". Also notice that multiple elements of the same name are represented something like an array.