tclparser-8.0.tcl
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 package require -exact Tcl 8.0
00020
00021 package require xmldefs 3.2
00022
00023 package require sgmlparser 1.0
00024
00025 package provide xml::tclparser 3.2
00026
00027 namespace xml {
00028
00029
00030 namespace export parser
00031
00032 namespace export DTDparser
00033
00034
00035 variable ParserCounter 0
00036
00037 }
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067 ret xml::parser (type args) {
00068 variable ParserCounter
00069
00070 if {[llength $args] > 0} {
00071 set name [lindex $args 0]
00072 set args [lreplace $args 0 0]
00073 } else {
00074 set name parser[incr ParserCounter]
00075 }
00076
00077 if {[info command [namespace current]::$name] != {}} {
00078 return -code error "unable to create parser object \"[namespace current]::$name\" command"
00079 }
00080
00081 # Initialise state variable and object command
00082 upvar \#0 [namespace current]::$name parser
00083 set sgml_ns [namespace parent]::sgml
00084 array set parser [list name $name \
00085 -final 1 \
00086 -elementstartcommand ${sgml_ns}::noop \
00087 -elementendcommand ${sgml_ns}::noop \
00088 -characterdatacommand ${sgml_ns}::noop \
00089 -processinginstructioncommand ${sgml_ns}::noop \
00090 -externalentityrefcommand ${sgml_ns}::noop \
00091 -xmldeclcommand ${sgml_ns}::noop \
00092 -doctypecommand ${sgml_ns}::noop \
00093 -warningcommand ${sgml_ns}::noop \
00094 -statevariable [namespace current]::$name \
00095 -reportempty 0 \
00096 internaldtd {} \
00097 ]
00098
00099 proc [namespace current]::$name {method args} \
00100 "eval ParseCommand $name \$method \$args"
00101
00102 eval ParseCommand [list $name] configure $args
00103
00104 return [namespace current]::$name
00105 }
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125 ret xml::ParseCommand (type parser , type method , type args) {
00126 upvar \#0 [namespace current]::$parser state
00127
00128 switch -- $method {
00129 cget {
00130 return $state([lindex $args 0])
00131 }
00132 configure {
00133 foreach {opt value} $args {
00134 set state($opt) $value
00135 }
00136 }
00137 parse {
00138 ParseCommand_parse $parser [lindex $args 0]
00139 }
00140 reset {
00141 if {[llength $args]} {
00142 return -code error "too many arguments"
00143 }
00144 ParseCommand_reset $parser
00145 }
00146 default {
00147 return -code error "unknown method \"$method\""
00148 }
00149 }
00150
00151 return {}
00152 }
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165 ret xml::ParseCommand_parse (type object , type xml) {
00166 upvar \#0 [namespace current]::$object parser
00167 variable Wsp
00168 variable tokExpr
00169 variable substExpr
00170
00171 set parent [namespace parent]
00172 if {![string compare :: $parent]} {
00173 set parent {}
00174 }
00175
00176 set tokenised [lrange \
00177 [${parent}::sgml::tokenise $xml \
00178 $tokExpr \
00179 $substExpr \
00180 -internaldtdvariable [namespace current]::${object}(internaldtd)] \
00181 4 end]
00182
00183 eval ${parent}::sgml::parseEvent \
00184 [list $tokenised \
00185 -emptyelement [namespace code ParseEmpty] \
00186 -parseattributelistcommand [namespace code ParseAttrs]] \
00187 [array get parser -*command] \
00188 [array get parser -entityvariable] \
00189 [array get parser -reportempty] \
00190 [array get parser -final] \
00191 -normalize 0 \
00192 -internaldtd [list $parser(internaldtd)]
00193
00194 return {}
00195 }
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215 ret xml::ParseEmpty (type tag , type attr , type e) {
00216
00217 if {[string match */ [string trimright $tag]] && \
00218 ![string length $attr]} {
00219 regsub {/$} $tag {} tag
00220 return [list / $tag $attr]
00221 } elseif {[string match */ [string trimright $attr]]} {
00222 regsub {/$} [string trimright $attr] {} attr
00223 return [list / $tag $attr]
00224 } else {
00225 return {}
00226 }
00227
00228 }
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248 ret xml::ParseAttrs attrs (
00249 type variable , type Wsp
00250 , type variable , type Name
00251
00252 # , type First , type check , type whether , type there', type s , type any , type work , type to , type do
00253 , type if , optional ![string =compare { [, type string , type trim $, type attrs]]) {
00254 return {}
00255 }
00256
00257
00258 regsub [format {/[%s]*$} " \t\n\r"] $attrs {} atList
00259
00260 mode = name
00261 result = {}
00262 foreach component [split $atList =] {
00263 switch $mode {
00264 name {
00265 component = [string trim $component]
00266 if {[regexp $Name $component]} {
00267 lappend result $component
00268 } else {
00269 return -code error "invalid attribute name \"$component\""
00270 }
00271 mode = value:start
00272 }
00273 value:start {
00274 component = [string trimleft $component]
00275 delimiter = [string index $component 0]
00276 value = {}
00277 switch -- $delimiter {
00278 \" -
00279 ' {
00280 if {[regexp [format {%s([^%s]*)%s(.*)} $delimiter $delimiter $delimiter] $component discard value remainder]} {
00281 lappend result $value
00282 remainder = [string trim $remainder]
00283 if {[string length $remainder]} {
00284 if {[regexp $Name $remainder]} {
00285 lappend result $remainder
00286 mode = value:start
00287 } else {
00288 return -code error "invalid attribute name \"$remainder\""
00289 }
00290 } else {
00291 mode = end
00292 }
00293 } else {
00294 value = [string range $component 1 end]
00295 mode = value:continue
00296 }
00297 }
00298 default {
00299 return -code error "invalid value for attribute \"[lindex $result end]\""
00300 }
00301 }
00302 }
00303 value:continue {
00304 if {[regexp [format {([^%s]*)%s(.*)} $delimiter $delimiter] $component discard valuepart remainder]} {
00305 append value = $valuepart
00306 lappend result $value
00307 remainder = [string trim $remainder]
00308 if {[string length $remainder]} {
00309 if {[regexp $Name $remainder]} {
00310 lappend result $remainder
00311 mode = value:start
00312 } else {
00313 return -code error "invalid attribute name \"$remainder\""
00314 }
00315 } else {
00316 mode = end
00317 }
00318 } else {
00319 append value = $component
00320 }
00321 }
00322 end {
00323 return -code error "unexpected data found after end of attribute list"
00324 }
00325 }
00326 }
00327
00328 switch $mode {
00329 name -
00330 end {
00331
00332 }
00333 default {
00334 return -code error "unexpected end of attribute list"
00335 }
00336 }
00337
00338 return $result
00339 }
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351 ret xml::ParseCommand_reset object (
00352 type upvar \#0 [, type namespace , type current]::$, type object , type parser
00353
00354 , type array , type set , type parser [, type list \
00355 -, type final 1 \
00356 , type internaldtd , optional \
00357 ]
00358 )
00359
00360