tclparser-8.0.tcl
来自「Linux下的MSN聊天程序源码」· TCL 代码 · 共 358 行
TCL
358 行
# tclparser-8.0.tcl --## This file provides a Tcl implementation of a XML parser.# This file supports Tcl 8.0.## See xml-8.[01].tcl for definitions of character sets and# regular expressions.## Copyright (c) 1998-2004 Zveno Pty Ltd# http://www.zveno.com/# # See the file "LICENSE" in this distribution for information on usage and# redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.## $Id: tclparser-8.0.tcl 5915 2006-01-23 12:43:37Z tjikkun $package require -exact Tcl 8.0package require xmldefs 3.1package require sgmlparser 1.0package provide xml::tclparser 3.1namespace eval xml { # Procedures for parsing XML documents namespace export parser # Procedures for parsing XML DTDs namespace export DTDparser # Counter for creating unique parser objects variable ParserCounter 0}# xml::parser --## Creates XML parser object.## Arguments:# args Unique name for parser object# plus option/value pairs## Recognised Options:# -final Indicates end of document data# -elementstartcommand Called when an element starts# -elementendcommand Called when an element ends# -characterdatacommand Called when character data occurs# -processinginstructioncommand Called when a PI occurs# -externalentityrefcommand Called for an external entity reference## (Not compatible with expat)# -xmldeclcommand Called when the XML declaration occurs# -doctypecommand Called when the document type declaration occurs## -errorcommand Script to evaluate for a fatal error# -warningcommand Script to evaluate for a reportable warning# -statevariable global state variable# -reportempty whether to provide empty element indication## Results:# The state variable is initialised.proc xml::parser {args} { variable ParserCounter if {[llength $args] > 0} { set name [lindex $args 0] set args [lreplace $args 0 0] } else { set name parser[incr ParserCounter] } if {[info command [namespace current]::$name] != {}} { return -code error "unable to create parser object \"[namespace current]::$name\" command" } # Initialise state variable and object command upvar \#0 [namespace current]::$name parser set sgml_ns [namespace parent]::sgml array set parser [list name $name \ -final 1 \ -elementstartcommand ${sgml_ns}::noop \ -elementendcommand ${sgml_ns}::noop \ -characterdatacommand ${sgml_ns}::noop \ -processinginstructioncommand ${sgml_ns}::noop \ -externalentityrefcommand ${sgml_ns}::noop \ -xmldeclcommand ${sgml_ns}::noop \ -doctypecommand ${sgml_ns}::noop \ -warningcommand ${sgml_ns}::noop \ -statevariable [namespace current]::$name \ -reportempty 0 \ internaldtd {} \ ] proc [namespace current]::$name {method args} \ "eval ParseCommand $name \$method \$args" eval ParseCommand [list $name] configure $args return [namespace current]::$name}# xml::ParseCommand --## Handles parse object command invocations## Valid Methods:# cget# configure# parse# reset## Arguments:# parser parser object# method minor command# args other arguments## Results:# Depends on methodproc xml::ParseCommand {parser method args} { upvar \#0 [namespace current]::$parser state switch -- $method { cget { return $state([lindex $args 0]) } configure { foreach {opt value} $args { set state($opt) $value } } parse { ParseCommand_parse $parser [lindex $args 0] } reset { if {[llength $args]} { return -code error "too many arguments" } ParseCommand_reset $parser } default { return -code error "unknown method \"$method\"" } } return {}}# xml::ParseCommand_parse --## Parses document instance data## Arguments:# object parser object# xml data## Results:# Callbacks are invoked, if any are definedproc xml::ParseCommand_parse {object xml} { upvar \#0 [namespace current]::$object parser variable Wsp variable tokExpr variable substExpr set parent [namespace parent] if {![string compare :: $parent]} { set parent {} } set tokenised [lrange \ [${parent}::sgml::tokenise $xml \ $tokExpr \ $substExpr \ -internaldtdvariable [namespace current]::${object}(internaldtd)] \ 4 end] eval ${parent}::sgml::parseEvent \ [list $tokenised \ -emptyelement [namespace code ParseEmpty] \ -parseattributelistcommand [namespace code ParseAttrs]] \ [array get parser -*command] \ [array get parser -entityvariable] \ [array get parser -reportempty] \ [array get parser -final] \ -normalize 0 \ -internaldtd [list $parser(internaldtd)] return {}}# xml::ParseEmpty -- Tcl 8.0 version## Used by parser to determine whether an element is empty.# This should be dead easy in XML. The only complication is# that the RE above can't catch the trailing slash, so we have# to dig it out of the tag name or attribute list.## Tcl 8.1 REs should fix this.## Arguments:# tag element name# attr attribute list (raw)# e End tag delimiter.## Results:# "/" if the trailing slash is found. Optionally, return a list# containing new values for the tag name and/or attribute list.proc xml::ParseEmpty {tag attr e} { if {[string match */ [string trimright $tag]] && \ ![string length $attr]} { regsub {/$} $tag {} tag return [list / $tag $attr] } elseif {[string match */ [string trimright $attr]]} { regsub {/$} [string trimright $attr] {} attr return [list / $tag $attr] } else { return {} }}# xml::ParseAttrs --## Parse element attributes.## There are two forms for name-value pairs:## name="value"# name='value'## Watch out for the trailing slash on empty elements.## Arguments:# attrs attribute string given in a tag## Results:# Returns a Tcl list representing the name-value pairs in the # attribute stringproc xml::ParseAttrs attrs { variable Wsp variable Name # First check whether there's any work to do if {![string compare {} [string trim $attrs]]} { return {} } # Strip the trailing slash on empty elements regsub [format {/[%s]*$} " \t\n\r"] $attrs {} atList set mode name set result {} foreach component [split $atList =] { switch $mode { name { set component [string trim $component] if {[regexp $Name $component]} { lappend result $component } else { return -code error "invalid attribute name \"$component\"" } set mode value:start } value:start { set component [string trimleft $component] set delimiter [string index $component 0] set value {} switch -- $delimiter { \" - ' { if {[regexp [format {%s([^%s]*)%s(.*)} $delimiter $delimiter $delimiter] $component discard value remainder]} { lappend result $value set remainder [string trim $remainder] if {[string length $remainder]} { if {[regexp $Name $remainder]} { lappend result $remainder set mode value:start } else { return -code error "invalid attribute name \"$remainder\"" } } else { set mode end } } else { set value [string range $component 1 end] set mode value:continue } } default { return -code error "invalid value for attribute \"[lindex $result end]\"" } } } value:continue { if {[regexp [format {([^%s]*)%s(.*)} $delimiter $delimiter] $component discard valuepart remainder]} { append value = $valuepart lappend result $value set remainder [string trim $remainder] if {[string length $remainder]} { if {[regexp $Name $remainder]} { lappend result $remainder set mode value:start } else { return -code error "invalid attribute name \"$remainder\"" } } else { set mode end } } else { append value = $component } } end { return -code error "unexpected data found after end of attribute list" } } } switch $mode { name - end { # This is normal } default { return -code error "unexpected end of attribute list" } } return $result}# xml::ParseCommand_reset --## Initialize parser data## Arguments:# object parser object## Results:# Parser data structure initialisedproc xml::ParseCommand_reset object { upvar \#0 [namespace current]::$object parser array set parser [list \ -final 1 \ internaldtd {} \ ]}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?