AMG:
Coroutines are especially well suited to parsing XML in
SAX mode, i.e. as a stream of events. Here's one way to do it with
tDOM:
# parseXmlFile --
# Parses an XML file using the supplied event dispatch table.
# Source: http://wiki.tcl.tk/49298
proc parseXmlFile {dispatch filename args} {
# Create parser coroutine.
for {set i 0} {[llength [info commands [set coro Parse$i]]]} {incr i} {}
coroutine $coro apply {{Dispatch} {
while {1} {
# Yield to the Expat parser, which will invoke this coroutine again
# the next time a registered event occurs. The return value of
# [yieldto] will be the event type and arguments.
set Args [lrange [set Key [yieldto return -level 0]] 1 end]
# Run all applicable event handlers, starting with most specific.
for {} {[llength $Key]} {set Key [lreplace $Key end end]} {
if {[dict exists $Dispatch $Key]} {
lassign $Args {*}[lindex [dict get $Dispatch $Key] 0]
eval [lindex [dict get $Dispatch $Key] 1]
}
}
}
}} $dispatch
# Create Expat parser and glue to the parser coroutine.
set parser [expat]
foreach event [lsort -unique [lmap i [dict keys $dispatch] {lindex $i 0}]] {
if {[string index $event 0] eq "-"} {
$parser configure $event [list $coro $event]
}
}
# Enable TNC to automatically validate against DTD schema.
catch {tnc $parser enable}
# Initialize parser coroutine.
if {[dict exists $dispatch initialize]} {
$coro initialize $filename {*}$args
}
# Run Expat parser, which will exercise the coroutine.
$parser parsefile $filename
$parser free
# Finalize parser coroutine.
if {[dict exists $dispatch finalize]} {
return [$coro finalize]
} else {
rename $coro {}
}
}
Examples to come.