tclxml-3.2/examples/tcldom/common.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 package require http
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 ret SetProperties (type win , type log) {
00031
00032 $log tag configure timing -background #bafdff
00033 $log tag configure error -background #ff9d8d
00034 $log tag configure errorhighlight -background #cd3030
00035 $log tag configure related -background #ffe59f
00036 $log tag configure relatedhighlight -background #e8b417
00037 $log tag configure message -background #ffe59f
00038 $log tag configure log -background #b9ffd4
00039
00040 return {}
00041 }
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055 ret Browse (type win , type field , type args) {
00056 upvar \#0 State$win state
00057
00058 set w [expr {$win == "." ? {} : $win}]
00059
00060 array set opts {
00061 -title {Select Document}
00062 -type open
00063 -command {}
00064 }
00065 array set opts $args
00066
00067 set cwd [pwd]
00068 if {$state(cwd) != {}} {
00069 set cwd $state(cwd)
00070 }
00071
00072 switch -- $opts(-type) {
00073 save {
00074 set fname [tk_getSaveFile -parent $win -title [mc $opts(-title)] -initialdir $cwd]
00075 }
00076 open -
00077 default {
00078 set fname [tk_getOpenFile -parent $win -title [mc $opts(-title)] -initialdir $cwd]
00079 }
00080 }
00081
00082 if {![string length $fname]} {
00083 return {}
00084 }
00085
00086 set state($field) file:
00087 set state(cwd) [file dirname $fname]
00088
00089 if {[string length $fname] && [string length $opts(-command)]} {
00090 uplevel #0 $opts(-command)
00091 }
00092
00093 return {}
00094 }
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114 ret ReadAndParseXML (type win , type label , type fname , type baseuri , optional timearr =time , type args) {
00115 upvar 1 $timearr time
00116 upvar \#0 State$win state
00117
00118 array set opts {
00119 -noent 0
00120 -nonet 0
00121 }
00122 array set opts $args
00123
00124 set state(externalentities) 0
00125
00126 Feedback $win [mc "Opening $label document \"$fname\""]
00127 if {[string match http:
00128 FeedbackProgress $win 0
00129 set state(start_download) [clock clicks -milliseconds]
00130 if {[catch {::http::geturl $fname \
00131 -command [list HTTPComplete $win] \
00132 -progress [list HTTPProgress $win] \
00133 -timeout 30000} token]} {
00134 tk_messageBox -message "unable to retrieve $label document \"$fname\" due to \"$token\"" -parent $win -type ok -icon error
00135 return -code error {}
00136 }
00137 ::http::wait $token
00138 if {[::http::status $token] != "ok"} {
00139 return -code error {}
00140 }
00141 set xml [::http::data $token]
00142 ::http::cleanup $token
00143 set time(read) [clock clicks -milliseconds]
00144 } else {
00145 if {[catch {open $fname} ch]} {
00146 tk_messageBox -message "unable to open $label document \"$fname\" due to \"$ch\"" -parent $win -type ok -icon error
00147 return -code error {}
00148 }
00149 set time(open) [clock clicks -milliseconds]
00150 Log timing $win "Opening $label document took [expr $time(open) - $time(start)]ms\n"
00151
00152 Feedback $win [mc "Reading $label document"]
00153 # Take note of encoding information
00154 set encoding {}
00155 gets $ch xmldecl
00156 set re ^[::sgml::cl $::xml::Wsp]*<\\?xml[::sgml::cl $::xml::Wsp]+(version[::sgml::cl $::xml::Wsp]*=[::sgml::cl $::xml::Wsp]*("|')[::sgml::cl ^"']+\\2)?[::sgml::cl $::xml::Wsp]*(encoding[::sgml::cl $::xml::Wsp]*=[::sgml::cl $::xml::Wsp]*("|')([::sgml::cl ^"']+)\\4)?[::sgml::cl $::xml::Wsp]*(standalone[::sgml::cl $::xml::Wsp]*=[::sgml::cl $::xml::Wsp]*("|')(yes|no)\\7)?[::sgml::cl $::xml::Wsp]*\\?>
00157 if {[regexp $re $xmldecl discard allversion delimiter allencoding delimiter encoding allstandalone delimiter]} {
00158 if {[catch {fconfigure $ch -encoding $encoding} msg]} {
00159 if {[catch {fconfigure $ch -encoding [string tolower $encoding]} msg]} {
00160 tk_messageBox -message "unable to read $label document \"$fname\" due to \"$msg\"" -parent $win -type ok -icon error
00161 return -code error {}
00162 }
00163 }
00164 }
00165 set xml $xmldecl\n[read $ch]
00166 close $ch
00167 # Watch out for UTF-16 documents
00168 if {[regexp "^(\xFF\xFE)|(\xFE\xFF)" $xml]} {
00169 set xml [encoding convertfrom unicode $xml]
00170 }
00171 set time(read) [clock clicks -milliseconds]
00172 Log timing $win "Reading $label document took [expr $time(read) - $time(open)]ms\n"
00173 }
00174
00175 Feedback $win [mc "Parsing $label XML"]
00176 if {[catch {dom::parse $xml \
00177 -baseuri [uri_escape $baseuri] \
00178 -defaultexpandinternalentities $opts(-noent) \
00179 -externalentitycommand [list External $win]} doc]} {
00180
00181 if {[string match "unable to*" $doc]} {
00182 Log add $win $doc
00183 } else {
00184 Log addXMLError $win $xml $doc
00185 }
00186 Feedback $win [mc "Parsing $label document failed"]
00187 after 2000 [list Feedback $win {}]
00188 return -code error {}
00189 }
00190 set time(parse) [clock clicks -milliseconds]
00191 Log timing $win "Parsing $label document took [expr $time(parse) - $time(read)]ms\n"
00192 set time(last) $time(parse)
00193
00194 if {$state(xinclude)} {
00195 Feedback $win [mc "$label document XInclude processing"]
00196 # TODO: handle doc in slave interp
00197 if {[catch {dom::xinclude $doc} msg]} {
00198 Log addDocError $win $doc $msg
00199 Feedback $win [mc "$label document XInclude processing failed"]
00200 after 2000 [list Feedback $win {}]
00201 }
00202 set time(xinclude) [clock clicks -milliseconds]
00203 Log timing $win "$label document XInclude took [expr $time(xinclude) - $time(last)]ms\n"
00204 set time(last) $time(xinclude)
00205 }
00206
00207 return $doc
00208 }
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226 ret External (type win , type name , type baseuri , type uri , type id) {
00227 upvar \#0 State$win state
00228
00229 if {$state(nonet) &&
00230 ([string match http:* $uri] || [string match ftp:* $uri])} {
00231 Log entity $win "external entity not loaded, network access not permitted: system ID \"$uri\" public ID \"$id\""
00232 return {}
00233 }
00234
00235 Log entity $win "external entity reference: system ID \"$uri\" public ID \"$id\""
00236
00237 incr state(externalentities)
00238 # resume normal loading of external entity
00239 return -code continue {}
00240 }
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255 ret GetFilename (type win , type entry , type field) {
00256 upvar \#0 State$win state
00257
00258 set state($field) [$entry get]
00259
00260 if {[catch {uri::split $state($field)} spliturl]} {
00261 # Try the URL as a pathname
00262 set fname $state($field)
00263 set state($field) file:
00264 } else {
00265 array set urlarray $spliturl
00266 switch -- $urlarray(scheme) {
00267 http {
00268 set fname $state($field)
00269 }
00270 file {
00271 set fname $urlarray(path)
00272 }
00273 default {
00274 tk_messageBox -message "\"$urlarray(scheme)\" type URLs are not supported" -parent $win -type ok -icon warning
00275 return {}
00276 }
00277 }
00278 }
00279
00280 return $fname
00281 }
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294 ret HTTPComplete (type win , type token) {
00295 upvar \#0 State$win state
00296
00297 $state(progress) itemconfigure $state(progressbar) -state disabled
00298 Log timing $win "Downloading document took [expr [clock clicks -milliseconds] - $state(start_download)]ms\n"
00299
00300 return {}
00301 }
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316 ret HTTPProgress (type win , type token , type total , type current) {
00317 upvar \#0 State$win state
00318
00319 FeedbackProgress $win [expr ($current * 100) / $total]
00320
00321 return {}
00322 }
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335 ret Log (type method , type win , type args) {
00336 upvar \#0 State$win state
00337
00338 set w [expr {$win == "." ? {} : $win}]
00339
00340 switch -- $method {
00341 clear {
00342 $state(messages).log configure -state normal
00343 $state(messages).log delete 1.0 end
00344 $state(messages).log configure -state disabled
00345 }
00346 view {
00347 set what [lindex $args 0]
00348 switch -- $what {
00349 start {
00350 $state(messages).log see 1.0
00351 }
00352 end {
00353 $state(messages).log see end
00354 }
00355 default {
00356 return -code error "don't know how to view \"$what\""
00357 }
00358 }
00359 }
00360 add {
00361 $state(messages).log configure -state normal
00362 $state(messages).log insert end [lindex $args 0]
00363 $state(messages).log configure -state disabled
00364 $state(messages).log see end
00365 }
00366 addXMLError {
00367 $state(messages).log configure -state normal
00368
00369 set xml [lindex $args 0]
00370 set id 0
00371 $state(messages).log insert end [mc "Problems detected in document:\n"]
00372 foreach errormsg [lindex $args 1] {
00373 foreach {domain level code node line message relatedLine dummy related1 related2} $errormsg break
00374 lappend error($line) error$id
00375 lappend related($relatedLine) related$id
00376 $state(messages).log insert end $message [list error error$id]
00377 if {[string index $message end] != "\n"} {
00378 $state(messages).log insert end \n
00379 }
00380 $state(messages).log tag bind error$id <Enter> [list ErrorHighlight $w $state(messages).log error$id $line $relatedLine]
00381 $state(messages).log tag bind error$id <Leave> [list ErrorRemoveHighlight $w $state(messages).log error$id $line $relatedLine]
00382 incr id
00383 }
00384 $state(messages).log insert end \n
00385
00386 set linenum 1
00387 foreach line [split $xml \n] {
00388
00389 if {[info exists error($linenum)]} {
00390 $state(messages).log insert end $line "error errorline$linenum"
00391 } elseif {[info exists related($linenum)]} {
00392 $state(messages).log insert end $line "related relatedline$linenum"
00393 } else {
00394 $state(messages).log insert end $line
00395 }
00396 $state(messages).log insert end \n
00397
00398 incr linenum
00399 }
00400
00401 $state(messages).log configure -state disabled
00402 $state(messages).log see end
00403 }
00404 addDocError {
00405 $state(messages).log configure -state normal
00406
00407 set doc [lindex $args 0]
00408 foreach errormsg [lindex $args 1] {
00409 foreach {domain level code node line message relatedLine dummy related1 related2} $errormsg break
00410 $state(messages).log insert end $message
00411 if {[string index $message end] != "\n"} {
00412 $state(messages).log insert end \n
00413 }
00414 }
00415
00416 $state(messages).log configure -state disabled
00417 $state(messages).log see end
00418 }
00419 addMessage {
00420 $state(messages).log configure -state normal
00421 $state(messages).log insert end [lindex $args 0] message
00422 $state(messages).log configure -state disabled
00423 $state(messages).log see end
00424 }
00425 timing {
00426 if {$state(timing)} {
00427 $state(messages).log configure -state normal
00428 $state(messages).log insert end [lindex $args 0] timing
00429 $state(messages).log configure -state disabled
00430 $state(messages).log see end
00431 }
00432 }
00433 entity {
00434 if {$state(display:entrefs)} {
00435 $state(messages).log configure -state normal
00436 $state(messages).log insert end [lindex $args 0] log \n
00437 $state(messages).log configure -state disabled
00438 $state(messages).log see end
00439 }
00440 }
00441 default {
00442 return -code error "unknown method \"$method\""
00443 }
00444 }
00445
00446 return {}
00447 }
00448
00449
00450
00451 ret ErrorHighlight (type win , type log , type tag , type line , type related) {
00452 $log tag configure $tag -background [$log tag cget errorhighlight -background]
00453 $log tag configure errorline$line -background [$log tag cget errorhighlight -background]
00454 $log tag raise errorline$line error
00455 $log tag configure relatedline$related -background [$log tag cget relatedhighlight -background]
00456 $log tag raise relatedline$related related
00457
00458 return {}
00459 }
00460 ret ErrorRemoveHighlight (type win , type log , type tag , type line , type related) {
00461 Feedback $win {}
00462
00463 $log tag configure $tag -background {}
00464 $log tag configure errorline$line -background {}
00465 $log tag configure relatedline$related -background {}
00466
00467 return {}
00468 }
00469
00470
00471
00472 ret Feedback (type win , type msg) {
00473 upvar \#0 State$win state
00474
00475 set state(feedback) $msg
00476 update
00477
00478 return {}
00479 }
00480 ret FeedbackProgress (type win , type percent) {
00481 upvar \#0 State$win state
00482
00483 $state(progress) coords $state(progressbar) 0 0 $percent 25
00484 update
00485
00486 return {}
00487 }
00488
00489
00490
00491 ret Incr var (
00492 type upvar $, type var , type v
00493 , type if , optional [info =exists v] , optional
00494 incr =v
00495 , type else , optional
00496 set =v 1
00497
00498
00499 , type return $, type v
00500 )
00501
00502 # This should be part of the uri package
00503
00504 proc uri_escape uri {
00505 # TODO: other characters must also be escaped
00506 regsub -all { } $uri {%20} uri
00507
00508 return $uri
00509 }
00510
00511