Motivation
snitDom: https://bitbucket.org/mittelmark/tcl-code/downloads/tdom0.8.3.kit
Contains tdom0.8.3 (shared libs for Linux-x86, Win32-x86 and OSX-x86), tnc (shared libs as for tdom), snit, uri, snitDom and the patched tcldom3.0 (see below).
tdom is much faster than the tcl-only implementation TclDOM. The usage syntax for both APIs is very different. The idea is to adjust the syntax of TclDOM that it can be used as a dropin replacement for tdom if the latter is not available for a certain platform. So code like the following can be written.
proc createHTML {} { set text "Sample page" set doc [dom createDocument html] set root [$doc documentElement] set head [$doc createElement head] set title [$doc createElement title] $title appendChild [$doc createTextNode "$text"] $root appendChild $head $head appendChild $title $root appendChild [$doc createElement body] foreach style {jsComponents.css dg-mpimg.css} { set link [$doc createElement link] $link setAttribute rel stylesheet $link setAttribute text text/css $link setAttribute href /css/$style $head appendChild $link } puts [$doc asHTML] } catch {package require tdom} if {[info commands dom] eq "dom"} { puts "Output via tdom" } else { puts "tdom not supported on this platform" puts "falling back to TclDOM snitDom dom puts "Output via tcl::dom snitDom" } createHTML
TclDOM changes
TclDOM is missing some node/element commands so I was adding them into the source code of dom.tcl. Here comes the diff:
$ diff tdom0.8.1.vfs/lib/tcldom3.0/dom.tcl /d/tcl-lib/tcldom3.0/dom.tcl 1211,1249d1210 < *stChild { < # firstChild or lastChild < set result [dom::tcl::node cget $token -$method] < } < *Sibling { < # previousSibling or nextSibling < set result [dom::tcl::node cget $token -$method] < } < hasAttribute { < if {[dom::element getAttribute $token [lindex $args 0]] eq ""} { < set result false < } else { < set result true < } < } < *Attribute { < switch $node(node:nodeType) { < textNode {} < default { < if {[llength $args] == 1} { < set result [dom::element $method $token [lindex $args 0]] < } else { < set result [dom::element $method $token [lindex $args 0] [lindex $args 1]] < } < } < } < } < selectNodes { < switch $node(node:nodeType) { < textNode {} < default { < if {[llength $args] == 1} { < set result [dom::selectNode $token [lindex $args 0]] < } else { < set result [dom::selectNode $token [lindex $args 0] [lindex $args 1] [lindex $args 2]] < } < } < } < } 3005,3006c2966,2967 < # dgroth fixes bad browser behaviour with <div foo='bar'/> tags < append result "></$nsPrefix$node(node:localName)>$newline" --- > > append result />$newline
The snitDOM type
# System : SNITDOM_TCL # Module : # Object Name : $RCSfile: 13473,v $ # Revision : $Revision: 1.7 $ # Date : $Date: 2005-02-04 07:01:27 $ # Author : $Author: jcw $ # Last Modified : <050203.1215> # # Description A wrapper type which allows to use tcl::dom with a tdom syntax # # $Log: 13473,v $ # Revision 1.7 2005-02-04 07:01:27 jcw # 13473-1107437321-lwv,134.243.216.133 # # Revision 1.1 2005/02/03 11:14:54 dgroth # initial cvs import # ############################################################################## package require snit 0.93 package require dom::tcl 3.0 package provide snitDom 0.1 snit::type snitDom { variable DOMDOC method createDocument {docElemName args} { # Creates a new DOM document object with # one element node # with node name docElemName set DOMDOC [dom::DOMImplementation create] set document [sdomDocument %AUTO% $DOMDOC] $document CreateRoot $docElemName return $document } method createDocumentNode {} { # not tested yet set DOMDOC [dom::DOMImplementation create] set document [sdomDocument %AUTO% $DOMDOC] return $document } method parse {xml} { set DOMDOC [dom::DOMImplementation parse $xml] set document [sdomDocument %AUTO% $DOMDOC] return $document } method delete {} { # not tested yet dom::DOMImplementation destroy $DOMDOC } } snit::type sdomDocument { variable DOMDOC #variable ROOT delegate method * to DOMDOC constructor {doc args} { set DOMDOC $doc # no options so no configurelist #$self configurelist $args } method CreateRoot {rootElem} { dom::document createElement $DOMDOC $rootElem #return $ROOT } method documentElement {} { return [dom::document cget $DOMDOC -documentElement] # return $ROOT } method asHTML {} { regsub {.+?<html>} [dom::serialize $DOMDOC -method "html" -indent true] <html> html return $html } method asXML {} { return [dom::serialize $DOMDOC -method "xml"] } }
Starkit, ready to use
https://bitbucket.org/mittelmark/tcl-code/downloads/tdom0.8.3.kit
Contains tdom0.8.3 (shared libs for Linux-x86, Win32-x86 and OSX-x86), snit, snitDom and the patched tcldom3.0.
Sample session
% cd /home/dgroth/mytcl % wget https://bitbucket.org/mittelmark/tcl-code/downloads/tdom0.8.3.kit % tclkit-8.4.19 (mytcl) 1 % source tdom0.8.3.kit (mytcl) 2 % package require snitDom (mytcl) 3 % proc createHTML {} { > set text "Sample page" > set doc [dom createDocument html] > set root [$doc documentElement] > set head [$doc createElement head] > > set title [$doc createElement title] > $title appendChild [$doc createTextNode "$text"] > $root appendChild $head > $head appendChild $title > $root appendChild [$doc createElement body] > foreach style {jsComponents.css dg-mpimg.css} { > set link [$doc createElement link] > $link setAttribute rel stylesheet > $link setAttribute text text/css > $link setAttribute href /css/$style > $head appendChild $link > } > puts [$doc asHTML] > } (mytcl) 4 % # just in case tdom was loaded (mytcl) 5 % catch {package require tdom} 0 (mytcl) 6 % if {[info commands dom] eq "dom"} { > puts "Output via tdom" > } else { > puts "tdom not supported on this platform" > snitDom dom > puts "Output via tcl::dom snitDom" > } Output via tdom (mytcl) 7 % (mytcl) 7 % createHTML <html> <head> <title>Sample page</title><link rel="stylesheet" text="text/css" href="/css/jsComponents.css"><link rel="stylesheet" text="text/css" href="/css/dg-mpimg.css"> </head><body></body> </html> (mytcl) 8 % rename dom "" (mytcl) 9 % package require snitDom 0.1 (mytcl) 10 % snitDom dom ::dom (mytcl) 11 % createHTML <html> <head> <title>Sample page</title> <link href="/css/jsComponents.css" text="text/css" rel="stylesheet"></link> <link href="/css/dg-mpimg.css" text="text/css" rel="stylesheet"></link> </head> <body></body> </html>
See also snit.