tdom-0.9.6-src/0000755000175000017500000000000015025767703011760 5ustar rolfrolftdom-0.9.6-src/doc/0000755000175000017500000000000015025767703012525 5ustar rolfrolftdom-0.9.6-src/doc/tnc.xml0000644000175000017500000001251215025767703014034 0ustar rolfrolf tnc tnc is an expat parser object extension, that validates the XML stream against the document DTD while parsing. package require tdom package require tnc set parser [expat] tnc $parser enable
DESCRIPTION

tnc adds the C handler set "tnc" to a tcl expat parser obj. This handler set is a simple DTD validator. If the validator detects a validation error, it sets the interp result, signals error and stops parsing. There isn't any validation error recovering. As a consequence, only valid documents are completely parsed.

This handler set has only three methods:

tnc parserObj enable

Adds the tnc C handler set to a Tcl expat parser object.

tnc parserObj remove

Removes the tnc validatore from the parser parserObj and frees all information, stored by it.

tnc parserObj getValidateCmd

Returns a new created validation command, if one is available from the parser command, otherwise it signals error. The name of the validation command is the validateCmdName, if this optional argument was given, or a random chosen name. A validation command is available in a parser command, if the parser with tnc enabled was previously used, to parse an XML document with a valid doctype declaration, a valid external subset, if one was given by the doctype declaration, and a valid internal subset. The further document doesn't need to be valid, to make the validation command available. The validation command can only get received one time from the parser command. The created validation command has this syntax:

validationCmd method ?args?

The valid methods are:

validateDocument domDocument ?varName? Checks, if the given domDocument is valid against the DTD information represented by the validation command. Returns 1, if the document ist valid, 0 otherwise. If the varName argument is given, then the variable it names is set to the detected reason for the validation error or to the empty string in case of a valid document. validateTree elementNode ?varName? Checks, if the given subtree with domNode as root element is a possible valid subtree of a document conforming to the DTD information represented by the validation command. IDREF could not checked, while validating only a subtree, but it is checked, that every known ID attribute in the subtree is unique. Returns 1, if the subtree is OK, 0 otherwise. If the varName argument is given, then the variable it names is set to the detected reason for the validation error or to the empty string in case of a valid subtree. validateAttributes elementNode ?varName? Checks, if there is an element declaration for the name of the elementNode in the DTD represented by the validation command and, if yes, if the attributes of the elementNode are conform to the ATTLIST declarations for that element in the DTD. Returns 1, if the attributes and there value types are OK, 0 otherwise. If the varName argument is given, then the variable it names is set to the detected reason for the validation error or to the empty string in case the element has all its required attributes, only declared attributes and the values of the attributes matches there type. delete Deletes the validation command and frees the memory used by it. Returns the empty string.
BUGS

The validation error reports could be much more informative and user-friendly.

The validator doesn't detect ambiguous content models (see XML recomendation Section 3.2.1 and Appendix E). Most Java validators also doesn't, but handle such content models right anyhow. Tnc does not; if your DTD has such ambiguous content models, tnc can not used to validate documents against such (not completely XML spec compliant) DTDs.

It isn't possible to validate XML documents with standalone="yes" in the XML Declaration

Violations of the validity constraints Proper Group/PE Nesting and Proper Conditional Section/PE Nesting are not detected. They could only happen inside a invalid DTD, not in the content of a document.

Validation DTD
tdom-0.9.6-src/doc/pullparser.n0000644000175000017500000001675615025767703015114 0ustar rolfrolf'\" '\" Generated from pullparser.xml '\" '\" BEGIN man.macros .if t .wh -1.3i ^B .nr ^l \n(.l .ad b .de AP .ie !"\\$4"" .TP \\$4 .el \{\ . ie !"\\$2"" .TP \\n()Cu . el .TP 15 .\} .ta \\n()Au \\n()Bu .ie !"\\$3"" \{\ \&\\$1 \\fI\\$2\\fP (\\$3) .\".b .\} .el \{\ .br .ie !"\\$2"" \{\ \&\\$1 \\fI\\$2\\fP .\} .el \{\ \&\\fI\\$1\\fP .\} .\} .. .de AS .nr )A 10n .if !"\\$1"" .nr )A \\w'\\$1'u+3n .nr )B \\n()Au+15n .\" .if !"\\$2"" .nr )B \\w'\\$2'u+\\n()Au+3n .nr )C \\n()Bu+\\w'(in/out)'u+2n .. .AS Tcl_Interp Tcl_CreateInterp in/out .de BS .br .mk ^y .nr ^b 1u .if n .nf .if n .ti 0 .if n \l'\\n(.lu\(ul' .if n .fi .. .de BE .nf .ti 0 .mk ^t .ie n \l'\\n(^lu\(ul' .el \{\ .\" Draw four-sided box normally, but don't draw top of .\" box if the box started on an earlier page. .ie !\\n(^b-1 \{\ \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .el \}\ \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .\} .fi .br .nr ^b 0 .. .de VS .if !"\\$2"" .br .mk ^Y .ie n 'mc \s12\(br\s0 .el .nr ^v 1u .. .de VE .ie n 'mc .el \{\ .ev 2 .nf .ti 0 .mk ^t \h'|\\n(^lu+3n'\L'|\\n(^Yu-1v\(bv'\v'\\n(^tu+1v-\\n(^Yu'\h'-|\\n(^lu+3n' .sp -1 .fi .ev .\} .nr ^v 0 .. .de ^B .ev 2 'ti 0 'nf .mk ^t .if \\n(^b \{\ .\" Draw three-sided box if this is the box's first page, .\" draw two sides but no top otherwise. .ie !\\n(^b-1 \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c .el \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c .\} .if \\n(^v \{\ .nr ^x \\n(^tu+1v-\\n(^Yu \kx\h'-\\nxu'\h'|\\n(^lu+3n'\ky\L'-\\n(^xu'\v'\\n(^xu'\h'|0u'\c .\} .bp 'fi .ev .if \\n(^b \{\ .mk ^y .nr ^b 2 .\} .if \\n(^v \{\ .mk ^Y .\} .. .de DS .RS .nf .sp .. .de DE .fi .RE .sp .. .de SO .SH "STANDARD OPTIONS" .LP .nf .ta 5.5c 11c .ft B .. .de SE .fi .ft R .LP See the \\fBoptions\\fR manual entry for details on the standard options. .. .de OP .LP .nf .ta 4c Command-Line Name: \\fB\\$1\\fR Database Name: \\fB\\$2\\fR Database Class: \\fB\\$3\\fR .fi .IP .. .de CS .RS .nf .ta .25i .5i .75i 1i .if t .ft C .. .de CE .fi .if t .ft R .RE .. .de UL \\$1\l'|0\(ul'\\$2 .. '\" END man.macros .TH pullparser n "" Tcl "" .BS .SH NAME tdom::pullparser \- Create an XML pull parser command .SH SYNOPSIS .nf package require tdom \fBtdom::pullparser\fP \fIcmdName\fR \fR?\fP -ignorewhitecdata \fR?\fP .fi .BE .SH "DESCRIPTION " .PP This command creates XML pull parser commands with a simple API, along the lines of a simple StAX parser. After creation, you've to set an input source, to do anything useful with the pull parser. For this see the methods \fIinput\fR, \fIinputchannel\fR and \fIinputfile\fR. .PP The parser has always a \fIstate\fR. You start parsing the XML data until some next state, do what has to be done and skip again to the next state. XML well-formedness errors along the way will be reported as TCL_ERROR with additional info in the error message. .PP The pull parsers don't follow external entities and are XML 1.0 only, they know nothing about XML Namespaces. You get the tags and attribute names as in the source. You aren't noticed about comments, processing instructions and external entities; they are silently ignored for you. CDATA Sections are handled as if their content would have been provided without using a CDATA Section. .PP On the brighter side is that character entity and attribute default declarations in the internal subset are respected (because of using expat as underlying parser). It is probably somewhat faster than a comperable implementation with the SAX interface. It's a nice programming model. It's a slim interface. .PP If the option \fI-ignorewhitecdata\fR is given, the created XML pull parser command will ignore any white space only (' ', \et, \&\en and \er) text content between START_TAG and START_TAG / END_TAG. The parser won't stop at such input and will create TEXT state events only for not white space only text. .PP Not all methods are valid in every state. The parser will raise TCL_ERROR if a method is called in a state the method isn't valid for. Valid methods of the created commands are: .TP \&\fB\fBstate\fP \&\fRThis method is valid in all parser states. The possible return values and their meanings are: .RS .IP "\(bu" \&\fIREADY\fR - The parser is created or reset, but no input is set. .IP "\(bu" \&\fISTART_DOCUMENT\fR - Input is set, parser is ready to start parsing. .IP "\(bu" \&\fISTART_TAG\fR - Parser has stopped parsing at a start tag. .IP "\(bu" \&\fIEND_TAG\fR - Parser has stopped parsing at an end tag .IP "\(bu" \&\fITEXT\fR - Parser has stopped parsing to report text between tags. .IP "\(bu" \&\fIEND_DOKUMENT\fR - Parser has finished parsing without error. .IP "\(bu" \&\fIPARSE_ERROR\fR - Parser stopped parsing at XML error in input. .RE .TP \&\fB\fBinput\fP \fIdata\fB \&\fRThis method is only valid in state \fIREADY\fR. It prepares the parser to use \fIdata\fR as XML input to parse and switches the parser into state START_DOCUMENT. .TP \&\fB\fBinputchannel\fP \fIchannel\fB \&\fRThis method is only valid in state \fIREADY\fR. It prepares the parser to read the XML input to parse out of \&\fIchannel\fR and switches the parser into state START_DOCUMENT. .TP \&\fB\fBinputfile\fP \fIfilename\fB \&\fRThis method is only valid in state \fIREADY\fR. It open \fIfilename\fR and prepares the parser to read the XML input to parse out of that file. The method returns TCL_ERROR, if the file could not be open in read mode. Otherwise it switches the parser into state START_DOCUMENT. .TP \&\fB\fBnext\fP \&\fRThis method is valid in state \fISTART_DOCUMENT\fR, \&\fISTART_TAG\fR, \fIEND_TAG\fR and \fITEXT\fR. It continues parsing of the XML input until the next event, which it will return. .TP \&\fB\fBtag\fP \&\fRThis method is only valid in states \fISTART_TAG\fR and \&\fIEND_TAG\fR. It returns the tag name of the current start or end tag. .TP \&\fB\fBattributes\fP \&\fRThis method is only valid in state \fISTART_TAG\fR. It returns all attributes of the element in a name value list. .TP \&\fB\fBtext\fP \&\fRThis method is only valid in state \fITEXT\fR. It returns the character data of the event. There will be always at most one TEXT event between START_TAG and the next START_TAG or END_TAG event. .TP \&\fB\fBskip\fP \&\fRThis method is only valid in state \fISTART_TAG\fR. It skips to the corresponding end tag and ignores all events (but not XML parsing errors) on the way and returns the new state END_TAG. .TP \&\fB\fBfind-element\fP \fR?\fP tagname | -names tagnames \fR?\fP \&\fRThis method is only valid in states \&\fISTART_DOCUMENT\fR, \fISTART_TAG\fR and \fIEND_TAG\fR. It skips forward until the next element start tag with tag name \&\fItagname\fR and returns the new state START_TAG. If a list of tagnames is provided with the \fI-names\fR option, any of the \fItagnames\fR match. If there isn't such an element the parser stops at the end of the input and returns END_DOCUMENT. .TP \&\fB\fBreset\fP \&\fRThis method is valid in all parser states. It resets the parser into READY state and returns that. .TP \&\fB\fBdelete\fP \&\fRThis method is valid in all parser states. It deletes the parser command. .PP Miscellaneous methods: .TP \&\fB\fBline\fP \&\fRThis method is valid in all parser states except READY and TEXT. It returns the line number of the parsing position. Line counting starts with 1. .TP \&\fB\fBcolumn\fP \&\fRThis method is valid in all parser states except READY and TEXT. It returns the offset, from the beginning of the current line, of the parsing position. Column counting starts with 0. .SH KEYWORDS XML, pull, parsing tdom-0.9.6-src/doc/dom.n0000644000175000017500000007503315025767703013473 0ustar rolfrolf'\" '\" Generated from dom.xml '\" '\" BEGIN man.macros .if t .wh -1.3i ^B .nr ^l \n(.l .ad b .de AP .ie !"\\$4"" .TP \\$4 .el \{\ . ie !"\\$2"" .TP \\n()Cu . el .TP 15 .\} .ta \\n()Au \\n()Bu .ie !"\\$3"" \{\ \&\\$1 \\fI\\$2\\fP (\\$3) .\".b .\} .el \{\ .br .ie !"\\$2"" \{\ \&\\$1 \\fI\\$2\\fP .\} .el \{\ \&\\fI\\$1\\fP .\} .\} .. .de AS .nr )A 10n .if !"\\$1"" .nr )A \\w'\\$1'u+3n .nr )B \\n()Au+15n .\" .if !"\\$2"" .nr )B \\w'\\$2'u+\\n()Au+3n .nr )C \\n()Bu+\\w'(in/out)'u+2n .. .AS Tcl_Interp Tcl_CreateInterp in/out .de BS .br .mk ^y .nr ^b 1u .if n .nf .if n .ti 0 .if n \l'\\n(.lu\(ul' .if n .fi .. .de BE .nf .ti 0 .mk ^t .ie n \l'\\n(^lu\(ul' .el \{\ .\" Draw four-sided box normally, but don't draw top of .\" box if the box started on an earlier page. .ie !\\n(^b-1 \{\ \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .el \}\ \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .\} .fi .br .nr ^b 0 .. .de VS .if !"\\$2"" .br .mk ^Y .ie n 'mc \s12\(br\s0 .el .nr ^v 1u .. .de VE .ie n 'mc .el \{\ .ev 2 .nf .ti 0 .mk ^t \h'|\\n(^lu+3n'\L'|\\n(^Yu-1v\(bv'\v'\\n(^tu+1v-\\n(^Yu'\h'-|\\n(^lu+3n' .sp -1 .fi .ev .\} .nr ^v 0 .. .de ^B .ev 2 'ti 0 'nf .mk ^t .if \\n(^b \{\ .\" Draw three-sided box if this is the box's first page, .\" draw two sides but no top otherwise. .ie !\\n(^b-1 \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c .el \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c .\} .if \\n(^v \{\ .nr ^x \\n(^tu+1v-\\n(^Yu \kx\h'-\\nxu'\h'|\\n(^lu+3n'\ky\L'-\\n(^xu'\v'\\n(^xu'\h'|0u'\c .\} .bp 'fi .ev .if \\n(^b \{\ .mk ^y .nr ^b 2 .\} .if \\n(^v \{\ .mk ^Y .\} .. .de DS .RS .nf .sp .. .de DE .fi .RE .sp .. .de SO .SH "STANDARD OPTIONS" .LP .nf .ta 5.5c 11c .ft B .. .de SE .fi .ft R .LP See the \\fBoptions\\fR manual entry for details on the standard options. .. .de OP .LP .nf .ta 4c Command-Line Name: \\fB\\$1\\fR Database Name: \\fB\\$2\\fR Database Class: \\fB\\$3\\fR .fi .IP .. .de CS .RS .nf .ta .25i .5i .75i 1i .if t .ft C .. .de CE .fi .if t .ft R .RE .. .de UL \\$1\l'|0\(ul'\\$2 .. '\" END man.macros .TH dom n "" Tcl "" .BS .SH NAME dom \- Create an in-memory DOM tree from XML .SH SYNOPSIS .nf package require tdom \&\fBdom\fP \fImethod\fR ?\fIarg arg ...\fR? .fi .BE .SH "DESCRIPTION " .PP This command provides the creation of DOM trees in memory. In the usual case a string containing a XML information is parsed and converted into a DOM tree. Other possible parse input may be HTML or JSON. The \fImethod\fR indicates a specific subcommand. .PP The valid methods are: .TP \&\fB\fBdom\fP \fBparse\fP ?\fIoptions\fB? ?\fIdata\fB? \&\fRParses the XML information and builds up the DOM tree in memory providing a Tcl object command to this DOM document object. Example: .RS .CS dom parse $xml doc $doc documentElement root .CE .PP parses the XML in the variable xml, creates the DOM tree in memory, make a reference to the document object, visible in Tcl as a document object command, and assigns this new object name to the variable doc. When doc gets freed, the DOM tree and the associated Tcl command object (document and all node objects) are freed automatically. .CS set document [dom parse $xml] set root [$document documentElement] .CE .PP parses the XML in the variable xml, creates the DOM tree in memory, make a reference to the document object, visible in Tcl as a document object command, and returns this new object name, which is then stored in \&\fIdocument\fR. To free the underlying DOM tree and the associative Tcl object commands (document + nodes + fragment nodes) the document object command has to be explicitly deleted by: .CS $document delete .CE or .CS rename $document "" .CE .PP The valid options are: .IP "\fB-simple\fR" If \fI-simple\fR is specified, a simple but fast parser is used (conforms not fully to XML recommendation). That should double parsing and DOM generation speed. The encoding of the data is not transformed inside the parser. The simple parser does not respect any encoding information in the XML declaration. It skips over the internal DTD subset and ignores any information in it. Therefore, it doesn't include defaulted attribute values into the tree, even if the according attribute declaration is in the internal subset. It also doesn't expand internal or external entity references other than the predefined entities and character references .IP "\fB-html\fR" If \fI-html\fR is specified, a fast HTML parser is used, which tries to even parse badly formed HTML into a DOM tree. If the HTML document given to parse does not have a single root element (as it was legal up to HTML 4.01) and the -forest option is not used then a html node will be inserted as document element, with the HTML input data top level elements as children. .IP "\fB-html5\fR" This option is only available if tDOM was build with --enable-html5. Use the \fIfeatureinfo\fR method if you need to know if this feature is build in. If \&\fI-html5\fR is specified, the gumbo lib html5 parser (https://github.com/google/gumbo-parser) is used to build the DOM tree. This is, as far as it goes, XML namespace-aware (which means for example that all HTML elements are in the html5 namespace). Since this probably isn't wanted by a lot of users and adds only burden for no good in a lot of use cases \fI-html5\fR can be combined with \fI-ignorexmlns\fR, in which case all nodes and attributes in the DOM tree are not in an XML namespace. All tag and attribute names in the DOM tree will be lower case, even for foreign elements not in the xhtml, svg or mathml namespace. The DOM tree may include nodes, that the parser inserted because they are implied by the context (as , , etc.). Input longer than 4 GByte byte length is not supported by the underlying gumbo parser. .IP "\fB-json\fR" If \fI-json\fR is specified, the \fIdata\fR is expected to be a valid JSON string (according to RFC 7159). The command returns an ordinary DOM document with nesting token inside the JSON data translated into tree hierarchy. If a JSON array value is itself an object or array then container element nodes named (in a default build) arraycontainer or objectcontainer, respectively, are inserted into the tree. The JSON serialization of this document (with the domDoc method \fIasJSON\fR) is the same JSON information as the \fIdata\fR, preserving JSON datatypes, allowing non-unique member names of objects while preserving their order and the full range of JSON string values. JSON datatype handling is done with an additional property "sticking" at the doc and tree nodes. This property isn't contained in an XML serialization of the document. If you need to store the JSON data represented by a document, store the JSON serialization and parse it back from there. Apart from this JSON type information the returned doc command or handle is an ordinary DOM doc, which may be investigated or modified with the full range of the doc and node methods. Please note that the element node names and the text node values within the tree may be outside of what the appropriate XML productions allow. .IP "\fB-jsonroot \fR" If given makes the given element name the document element of the resulting doc. The parsed content of the JSON string will be the children of this document element node. .IP "\fB-jsonmaxnesting \fIinteger\fP\fR" This option only has effect if used together with the \fI-json\fR option. The current implementation uses a recursive descent JSON parser. In order to avoid using excess stack space, any JSON input that has more than a certain levels of nesting is considered invalid. The default maximum nesting is 2000. The option -jsonmaxnesting allows the user to adjust that. .IP "\fB--\fR" The option \fI--\fR marks the end of options. To give this option isn't strictly necessary even in the case of JSON parsing, for which valid data may start with a "-". If parsing json and if the second to last or last argument start with a "-" and isn't a known option name it will be treated as JSON data. .IP "\fB-keepEmpties\fR" If \fI-keepEmpties\fR is specified then text nodes which contain only whitespaces will be part of the resulting DOM tree. In default case (\fI-keepEmpties\fR not given) those empty text nodes are removed at parsing time. .IP "\fB-keepCDATA\fR" If \fI-keepCDATA\fR is specified then CDATA sections aren't added to the tree as text nodes (and, if necessary, combined with sibling text nodes into one text node) as without this option but are added as CDATA_SECTION_NODEs to the tree. Please note that the resulting tree isn't prepared for XPath selects or to be the source or the stylesheet of an XSLT transformation. If not combined with \fI-keepEmpties\fR only not whitespace only CDATA sections will be added to the resulting DOM tree. .IP "\fB-channel \fI\fP\fR" If \fI-channel \fR is specified, the input to be parsed is read from the specified channel. The encoding setting of the channel (via fconfigure -encoding) is respected, ie the data read from the channel are converted to UTF-8 according to the encoding settings before the data is parsed. .IP "\fB-baseurl \fI\fP\fR" If \fI-baseurl \fR is specified, the baseURI is used as the base URI of the document. External entities references in the document are resolved relative to this base URI. This base URI is also stored within the DOM tree. .IP "\fB-feedbackAfter \fI<#bytes>\fP\fR" If \fI-feedbackAfter <#bytes>\fR is specified, the Tcl command given by \&\fI-feedbackcmd\fR is evaluated at the first element start within the document (or an external entity) after the start of the document or external entity or the last such call after #bytes. For backward compatibility if no -feedbackcmd is given but there is a Tcl proc named ::dom::domParseFeedback this proc is used as -feedbackcmd. If there isn't such a proc and -feedbackAfter is used it is an error to not also use -feedbackcmd. If the called script raises error, then parsing will be aborted, the \fIdom parse\fR call returns error, with the script error msg as error msg. If the called script \fIreturn -code break\fR, the parsing will abort and the \fIdom parse\fR call will return the empty string. .IP "\fB-feedbackcmd \fI} test html5-3.2 {Bad data} {html5} { set doc [dom parse -html5 -ignorexmlns {}] set result [$doc asXML -indent none] $doc delete set result } {} test html5-4.1 {Tag name case normalization} {html5} { set doc [dom parse -html5 -ignorexmlns {}] set result [$doc asXML -indent none] $doc delete set result } {} test html5-4.2 {Tag name case normalization} {html5} { set doc [dom parse -html5 -ignorexmlns {}] set result [$doc asXML -indent none] $doc delete set result } {} test html5-4.3 {Attribute normalization} {html5} { set doc [dom parse -html5 -ignorexmlns {}] set result [$doc asXML -indent none] $doc delete set result } {} test html5-4.4 {ID Attribute handling} {html5} { set doc [dom parse -html5 -ignorexmlns {

}] set result [[$doc getElementById 1] getAttribute id] $doc delete set result } {1} set xhtml {h "http://www.w3.org/1999/xhtml"} set svg {svg "http://www.w3.org/2000/svg"} set mathml {mml "http://www.w3.org/1998/Math/MathML"} set xlink {xlink "http://www.w3.org/1999/xlink"} set html5 {

text

} test html5-5.1 {svg subtrees} {html5} { set doc [dom parse -html5 $html5] set result [$doc selectNodes -namespaces $xhtml {string(/h:html/h:body/h:p[2])}] $doc delete set result } {text} set html5 { HTML5 SVG demo

HTML5 SVG Demo

A nice green circle:
Created by DKS. This is free code
} test html5-5.2 {svg subtrees} {html5} { set doc [dom parse -html5 $html5] set svg [$doc selectNodes -namespaces $svg //svg:circle] set result [$svg @fill] $doc delete set result } {green} set html5 { Binomial Theorem

Binomial Theorem:

a + b 2 = a 2 + b 2 + 2 a b } test html5-5.3 {mathml subtrees} {html5} { set doc [dom parse -html5 $html5] set mis [$doc selectNodes -namespaces $mathml //mml:mi] set result "" foreach mi $mis { append result [$mi text] } $doc delete set result } {ababab} set html5 { } test html5-5.4 {xlink attribute} {html5} { set doc [dom parse -html5 $html5] set node [$doc selectNodes -namespaces $xlink {//*[@xlink:href]}] set result [$node getAttributeNS [lindex $xlink 1] href] $doc delete set result } {huge-red-circle.svg} test html5-5.5 {xlink attribute} {html5} { set doc [dom parse -html5 -ignorexmlns $html5] set node [$doc getElementById "image"] set result [$node getAttribute "xlink:href"] $doc delete set result } {huge-red-circle.svg} # cleanup ::tcltest::cleanupTests return tdom-0.9.6-src/tests/all-bench.tcl0000644000175000017500000000672615025767703015466 0ustar rolfrolf# all-bench.tcl -- # # This file contains the top-level script to run the tDOM bench mark # suite. # # Copyright (c) 2007 by Rolf Ade (rolf@pointsman.de). # # $Id$ # # The script knows the options: # # -interppath # Adds a path to the list of pathes, which are searched for tclshs # with the pattern given by the -pattern option. Every time, this # option is given, the option value is added to the search list. If # not given, it is set to directory the tclsh, running the script, # lives in. # # -norm # See man bench, ::bench::norm # # -pattern # Specifies the search pattern for tclshs in the search # directories. Defaults to tclsh* # # -file # Specifies the search pattern for bench files in the same directory # as the all-bench.tcl. The default is *.bench. # # Every known option to ::bench::run (as of 0.3.1) are passed throu to # that command. See man bench for the details. # # Example: # tclsh all-bench.tcl \ # -interppath /usr/local/lib \ # -pkgdir ~/tdom/tdom-0.8.2 \ # -pkgdir ~/tdom/tdom-0.8.2-mod # # You can measure the same tDOM version against various tclshs, or # different tDOM versions with the same tclsh, or different tDOM # versions with differenct tclshs, all side by side. # # Don't run this script with a tcldomsh, until you know, what you're # doing. # bench 0.3.1 added the -pkgdir flag; we need at least that version, # if we want to compare more than one tDOM versions side by side. package require bench 0.3.1 package require bench::out::text # Defaults / Initialization set interpPattern tclsh* set benchFilePattern *.bench set interpPaths [list] set benchFlags [list] # Empty string means: no normalization set norm "" foreach {arg argValue} $argv { switch -- $arg { "-interppath" { lappend interpPaths $argValue } "-norm" { if {![string is integer -strict $argValue] || $argValue < 1} { puts stderr "The option -norm expects a postiv integer as\ value." exit 1 } set norm $argValue } "-pattern" { set interpPattern $argValue } "-file" { set benchFilePattern $argValue } default { switch -- $arg { "-errors" - "-threads" - "-match" - "-rmatch" - "-iters" - "-pkgdir" { lappend benchFlags $arg $argValue } default { puts stderr "Unknown option '$arg'" exit 1 } } } } } if {[llength $interpPaths] == 0} { lappend interpPaths [file dirname [info nameofexecutable]] } set interps [bench::locate $interpPattern $interpPaths] if {![llength $interps]} { puts stderr "No interpreters found" exit 1 } if {[llength $benchFlags]} { set cmd [linsert $benchFlags 0 bench::run] } else { set cmd [list bench::run] } set benchfiles [glob -nocomplain [file join [file dir [info script]] \ $benchFilePattern]] if {![llength $benchfiles]} { puts stderr "No benchmark files found." exit 1 } set results "" foreach interp $interps { set run $cmd lappend run $interp $benchfiles set results [::bench::merge $results [eval $run]] } if {$norm ne ""} { set results [::bench::norm $results $norm] } puts [::bench::out::text $results] tdom-0.9.6-src/tests/all.tcl0000644000175000017500000000107415025767703014400 0ustar rolfrolf# all.tcl -- # # This file contains a top-level script to run all of the Tcl # tests. Execute it by invoking "tclsh all.test". # # Copyright (c) 1998-1999 by Scriptics Corporation. # All rights reserved. # # RCS: @(#) $Id$ # source [file join [file dir [info script]] loadtdom.tcl] singleProcess 1 if {$tcl_version < 8.5} { # We still support 8.4 to some degree testsDirectory [file dirname [info script]] } else { configure {*}$argv -testdir [file dirname [info script]] } runAllTests # See http://mini.net/tcl/3248 for an explanation. proc exit args {} tdom-0.9.6-src/tests/domjson.test0000644000175000017500000057412015025767703015505 0ustar rolfrolf# Features covered: JSON parser # # This file contains a collection of tests for the JSON parser. # Tested functionalities: # json-1.*: JSON syntax tests # json-2.*: Valid JSON, that could not parsed into DOM # json-3.*: JSON unescaping # json-4.*: Unicode # json-5.*: Max nesting # json-6.*: asJSON # json-7.*: jsonType # json-8.*: appendFromScript # json-9.*: cloneNode # json-10.*: asTclValue # json-11.*: asTypedList # json-12.*: createFromTypedList # json-13.*: jsonEscape # Copyright (c) 2017 Rolf Ade. source [file join [file dir [info script]] loadtdom.tcl] testConstraint needExpand 1 if {$tcl_version < 8.5} { testConstraint needExpand 0 } # See below the comment in proc dom for explanation if {[info commands _dom] eq ""} { testConstraint nonetest 1 } else { testConstraint nonetest 0 } namespace eval nodeCmds { dom createNodeCmd elementNode e1 dom createNodeCmd -jsonType ARRAY elementNode jae1 dom createNodeCmd elementNode e2 dom createNodeCmd commentNode c dom createNodeCmd textNode t dom createNodeCmd -jsonType TRUE textNode true dom createNodeCmd -jsonType FALSE textNode false dom createNodeCmd -jsonType NULL textNode null dom createNodeCmd -jsonType NUMBER textNode number dom createNodeCmd cdataNode cdata dom createNodeCmd piNode pi dom createNodeCmd -jsonType BOOLEAN textNode boolean } test json-1.1 {Parse JSON} { set doc [dom parse -json {{"a":"avalue","b":"bvalue","c":0.123}}] set result [$doc asXML -indent none] $doc delete set result } "
avaluebvalue0.123" test json-1.2 {Parse JSON} { set doc [dom parse -json { {"a" : [ "avalue" ] } }] set result [$doc asXML -indent none] $doc delete set result } {avalue} test json-1.3 {Parse JSON} { set doc [dom parse -json {{"a":"a value","b":"1value"}}] set result [$doc asXML -indent none] $doc delete set result } "a value1value" test json-1.4 {Parse JSON - nested object} { set doc [dom parse -json {{"a":{"aa":"aavalue","bb":"bbvalue"},"b":"bvalue","c":0.123}}] set result [$doc asXML -indent none] $doc delete set result } "aavaluebbvaluebvalue0.123" test json-1.5 {Parse JSON - array} { set doc [dom parse -json {{"a": [1,2,3,4,"abc"]}}] set result [$doc asXML -indent none] $doc delete set result } "1234abc" test json-1.6 {Parse JSON - true, false, null} { set doc [dom parse -json {{"a":true,"b":false,"c":null,"d":"true","e":""}}] set result [$doc asXML -indent none] $doc delete set result } {truefalsenulltrue} test json-1.7 {Parse JSON - array in nested object} { set doc [dom parse -json {{"a":{"aa":[1,2,3,4,"abc"]},"b":"bvalue"}}] set result [$doc asXML -indent none] $doc delete set result } "1234abcbvalue" test json-1.8 {Parse JSON - true, false, null} { set doc [dom parse -json -jsonroot "JSONObject" {{"a":true,"b":false,"c":null,"d":"true","e":""}}] set result [$doc asXML -indent none] $doc delete set result } {truefalsenulltrue} test json-1.9 {JSON syntax error} {nonetest} { set result [catch {dom parse -json {{"a" "a value"}}} errMsg] list $result $errMsg } {1 {error "JSON syntax error" at position 5 "{"a" " <--Error-- a value"}"}} test json-1.10 {JSON syntax error} {nonetest} { set result [catch {dom parse -json {{"a":00.23}}} errMsg] list $result $errMsg } {1 {error "JSON syntax error" at position 6 "{"a":00 <--Error-- .23}"}} test json-1.11 {JSON syntax error} {nonetest} { set result [catch {dom parse -json {{"a":-00.23}}} errMsg] list $result $errMsg } {1 {error "JSON syntax error" at position 7 "{"a":-00 <--Error-- .23}"}} test json-1.12 {JSON syntax error} {nonetest} { set result [catch {dom parse -json {{"a":.23}}} errMsg] list $result $errMsg } {1 {error "JSON syntax error" at position 5 "{"a":. <--Error-- 23}"}} test json-1.13 {JSON syntax error} {nonetest} { set result [catch {dom parse -json {{"a":-.23}}} errMsg] list $result $errMsg } {1 {error "JSON syntax error" at position 6 "{"a":-. <--Error-- 23}"}} test json-1.14 {JSON syntax error} {nonetest} { set result [catch {dom parse -json {{"a":-}}} errMsg] list $result $errMsg } {1 {error "JSON syntax error" at position 5 "{"a":- <--Error-- }"}} test json-1.15 {Parse JSON - nested object} { set doc [dom parse -json {["a",["aa","bb"],"b"]}] set result [$doc asXML -indent none] $doc delete set result } "aaabbb" set notJsons { {{null}} {{1.23}} {{"string"}} {{"e":}} } test json-1.16 {Invalid input} {nonetest} { set result "" set ind 0 foreach notJson $notJsons { if {![catch {dom parse -json $notJson docNode} errMsg]} { lappend result $errMsg } } set result } "" test json-1.17 {Literal binary 0 (NUL, '\0') is not allowed in input} {nonetest} { catch {dom parse -json "\"a\u0000\""} } 1 test json-1.18 {Escaped binary 0 (NUL, '\0') is OK} { dom parse -json "\"a\\u0000\"" doc set result [$doc asJSON] $doc delete set result } "\"a\\u0000\"" test json-1.19 {Invalid input - incomplete \u escape} {nonetest} { set result 1 foreach jsonstr { "ab\u00" "ab\ua" "ab\u12" "ab\u123" "ab\u123g" "ab\u12g" "ab\u1g" "ab\ug" "\u00" "\ua" "\u12" "\u123" "\u123g" "\u12g" "\u1g" "\ug" } { if {![catch {dom parse -json $jsonstr}]} { set result 0 break } } set result } 1 test json-1.20 {Escaped binary 0} {needExpand} { dom parse -json "\"a\\u0000\"" doc set textvalue [$doc selectNodes string(node())] set result [string length $textvalue] binary scan $textvalue c2 result2 lappend result {*}$result2 $doc delete set result } {2 97 0} test json-1.21 {Single \u encoded surrogate} { dom parse -json {"abc\uD835"} doc set result [$doc asXML -escapeNonASCII -indent none] $doc delete set result } {abc�} test json-1.22 {\u encoded surrogate pair} { dom parse -json {"abc\uD835\uDD38"} doc set result [$doc asXML -escapeNonASCII -indent none] $doc delete set result } {abc𝔸} test json-2.1 {invalid xml name} { set doc [dom parse -json {{"a":"a value","1b":"1value", "a\nb":"a\nb", "":"empty string"}}] set result [$doc asXML -indent none] $doc delete set result } {a value<1b>1valuea b<>empty string} test json-3.1 {Unescaping} { set doc [dom parse -json {{"a":"a\nvalue","b":"value\tvalue"}}] set result [$doc asXML -indent none] $doc delete set result } "a valuevalue\tvalue" test json-3.2 {Unescaping} { set doc [dom parse -json {{"a":"a\nvalue", "b":"12\u0077\u2221ec"}}] set result [$doc asXML -indent none -escapeNonASCII] $doc delete set result } "a value12w∡ec" test json-3.3 {Unescaping} { set doc [dom parse -json {{"a":"\u0077\u2221"}}] set result [$doc asXML -indent none -escapeNonASCII] $doc delete set result } "w∡" test json-3.4 {unescaping} { set doc [dom parse -jsonroot json -json {["\\a"]}] set result [$doc asXML -indent none] $doc delete set result } {\a} test json-3.4.1 {unescaping} { set doc [dom parse -jsonroot json -json {["\\a","\u0071"]}] set result [$doc asXML -indent none] $doc delete set result } {\aq} test json-3.5 {unescaping} {nonetest} { set result [catch {dom parse -json {{"this":"a\lb"}}} errMsg] list $result $errMsg } {1 {error "JSON syntax error" at position 11 "{"this":"a\l <--Error-- b"}"}} test json-3.6 {unescaping} { set doc [dom parse -json {{"this":"a\nbc"}}] set result [$doc asXML -indent none] $doc delete set result } {a bc} test json-3.7 {unescaping} { set doc [dom parse -json {{"this":"a\u0077\t\u0078bc"}}] set result [$doc asXML -indent none] $doc delete set result } "aw\txbc" test json-3.8 {unescaping} { set doc [dom parse -json {{"this":"a\u000b"}}] set result [$doc asXML -indent none] $doc delete set result } "a\u000b" test json-3.9 {unescaping} { set doc [dom parse -json {{"this":"a\u0077","that":"\t\u0078bc"}}] set result [$doc asXML -indent none] $doc delete set result } "aw\txbc" proc toutf8s s { set result "" foreach c [split $s ""] { set s [encoding convertto utf-8 $c] binary scan $s H* x append result [regsub -all -expanded {..} [string toupper $x] {\x&}] } return $result } test json-4.1 {html entities as JSON data} {Tcl9} { set file [file join [file dir [info script]] data/htmlmathml.json] set fd [open $file] set json [read $fd] close $fd set doc [dom parse -json $json] array unset entities set entities [list] set olentities [list] set maxe 0 set maxv 0 foreach entity [$doc selectNodes characters/*] { set ename [$entity nodeName] set evalue [[$entity firstChild] nodeValue] if {[string index $evalue 0] eq " "} { set evalue [string trim $evalue] } set eutf8 [toutf8s $evalue] if {[string length $ename] > $maxe} { set maxe [string length $ename] } if {[string length $eutf8] > $maxv} { set maxv [string length $eutf8] } if {[string length $ename] < [string length $eutf8]/4 - 2} { lappend olentities $ename $eutf8 $evalue } else { lappend entities $ename $eutf8 $evalue } } $doc delete set result "\n" incr maxe 4 incr maxv 4 foreach {name bytes glyphs} $entities { append result [format " { %-${maxe}s%-${maxv}s 0 },\n" \"$name\", \"$bytes\",] } set result } { { "AElig", "\xC3\x86", 0 }, { "AMP", "\x26", 0 }, { "Aacute", "\xC3\x81", 0 }, { "Abreve", "\xC4\x82", 0 }, { "Acirc", "\xC3\x82", 0 }, { "Acy", "\xD0\x90", 0 }, { "Afr", "\xF0\x9D\x94\x84", 0 }, { "Agrave", "\xC3\x80", 0 }, { "Alpha", "\xCE\x91", 0 }, { "Amacr", "\xC4\x80", 0 }, { "And", "\xE2\xA9\x93", 0 }, { "Aogon", "\xC4\x84", 0 }, { "Aopf", "\xF0\x9D\x94\xB8", 0 }, { "ApplyFunction", "\xE2\x81\xA1", 0 }, { "Aring", "\xC3\x85", 0 }, { "Ascr", "\xF0\x9D\x92\x9C", 0 }, { "Assign", "\xE2\x89\x94", 0 }, { "Atilde", "\xC3\x83", 0 }, { "Auml", "\xC3\x84", 0 }, { "Backslash", "\xE2\x88\x96", 0 }, { "Barv", "\xE2\xAB\xA7", 0 }, { "Barwed", "\xE2\x8C\x86", 0 }, { "Bcy", "\xD0\x91", 0 }, { "Because", "\xE2\x88\xB5", 0 }, { "Bernoullis", "\xE2\x84\xAC", 0 }, { "Beta", "\xCE\x92", 0 }, { "Bfr", "\xF0\x9D\x94\x85", 0 }, { "Bopf", "\xF0\x9D\x94\xB9", 0 }, { "Breve", "\xCB\x98", 0 }, { "Bscr", "\xE2\x84\xAC", 0 }, { "Bumpeq", "\xE2\x89\x8E", 0 }, { "CHcy", "\xD0\xA7", 0 }, { "COPY", "\xC2\xA9", 0 }, { "Cacute", "\xC4\x86", 0 }, { "Cap", "\xE2\x8B\x92", 0 }, { "CapitalDifferentialD", "\xE2\x85\x85", 0 }, { "Cayleys", "\xE2\x84\xAD", 0 }, { "Ccaron", "\xC4\x8C", 0 }, { "Ccedil", "\xC3\x87", 0 }, { "Ccirc", "\xC4\x88", 0 }, { "Cconint", "\xE2\x88\xB0", 0 }, { "Cdot", "\xC4\x8A", 0 }, { "Cedilla", "\xC2\xB8", 0 }, { "CenterDot", "\xC2\xB7", 0 }, { "Cfr", "\xE2\x84\xAD", 0 }, { "Chi", "\xCE\xA7", 0 }, { "CircleDot", "\xE2\x8A\x99", 0 }, { "CircleMinus", "\xE2\x8A\x96", 0 }, { "CirclePlus", "\xE2\x8A\x95", 0 }, { "CircleTimes", "\xE2\x8A\x97", 0 }, { "ClockwiseContourIntegral", "\xE2\x88\xB2", 0 }, { "CloseCurlyDoubleQuote", "\xE2\x80\x9D", 0 }, { "CloseCurlyQuote", "\xE2\x80\x99", 0 }, { "Colon", "\xE2\x88\xB7", 0 }, { "Colone", "\xE2\xA9\xB4", 0 }, { "Congruent", "\xE2\x89\xA1", 0 }, { "Conint", "\xE2\x88\xAF", 0 }, { "ContourIntegral", "\xE2\x88\xAE", 0 }, { "Copf", "\xE2\x84\x82", 0 }, { "Coproduct", "\xE2\x88\x90", 0 }, { "CounterClockwiseContourIntegral", "\xE2\x88\xB3", 0 }, { "Cross", "\xE2\xA8\xAF", 0 }, { "Cscr", "\xF0\x9D\x92\x9E", 0 }, { "Cup", "\xE2\x8B\x93", 0 }, { "CupCap", "\xE2\x89\x8D", 0 }, { "DD", "\xE2\x85\x85", 0 }, { "DDotrahd", "\xE2\xA4\x91", 0 }, { "DJcy", "\xD0\x82", 0 }, { "DScy", "\xD0\x85", 0 }, { "DZcy", "\xD0\x8F", 0 }, { "Dagger", "\xE2\x80\xA1", 0 }, { "Darr", "\xE2\x86\xA1", 0 }, { "Dashv", "\xE2\xAB\xA4", 0 }, { "Dcaron", "\xC4\x8E", 0 }, { "Dcy", "\xD0\x94", 0 }, { "Del", "\xE2\x88\x87", 0 }, { "Delta", "\xCE\x94", 0 }, { "Dfr", "\xF0\x9D\x94\x87", 0 }, { "DiacriticalAcute", "\xC2\xB4", 0 }, { "DiacriticalDot", "\xCB\x99", 0 }, { "DiacriticalDoubleAcute", "\xCB\x9D", 0 }, { "DiacriticalGrave", "\x60", 0 }, { "DiacriticalTilde", "\xCB\x9C", 0 }, { "Diamond", "\xE2\x8B\x84", 0 }, { "DifferentialD", "\xE2\x85\x86", 0 }, { "Dopf", "\xF0\x9D\x94\xBB", 0 }, { "Dot", "\xC2\xA8", 0 }, { "DotDot", "\xE2\x83\x9C", 0 }, { "DotEqual", "\xE2\x89\x90", 0 }, { "DoubleContourIntegral", "\xE2\x88\xAF", 0 }, { "DoubleDot", "\xC2\xA8", 0 }, { "DoubleDownArrow", "\xE2\x87\x93", 0 }, { "DoubleLeftArrow", "\xE2\x87\x90", 0 }, { "DoubleLeftRightArrow", "\xE2\x87\x94", 0 }, { "DoubleLeftTee", "\xE2\xAB\xA4", 0 }, { "DoubleLongLeftArrow", "\xE2\x9F\xB8", 0 }, { "DoubleLongLeftRightArrow", "\xE2\x9F\xBA", 0 }, { "DoubleLongRightArrow", "\xE2\x9F\xB9", 0 }, { "DoubleRightArrow", "\xE2\x87\x92", 0 }, { "DoubleRightTee", "\xE2\x8A\xA8", 0 }, { "DoubleUpArrow", "\xE2\x87\x91", 0 }, { "DoubleUpDownArrow", "\xE2\x87\x95", 0 }, { "DoubleVerticalBar", "\xE2\x88\xA5", 0 }, { "DownArrow", "\xE2\x86\x93", 0 }, { "DownArrowBar", "\xE2\xA4\x93", 0 }, { "DownArrowUpArrow", "\xE2\x87\xB5", 0 }, { "DownBreve", "\xCC\x91", 0 }, { "DownLeftRightVector", "\xE2\xA5\x90", 0 }, { "DownLeftTeeVector", "\xE2\xA5\x9E", 0 }, { "DownLeftVector", "\xE2\x86\xBD", 0 }, { "DownLeftVectorBar", "\xE2\xA5\x96", 0 }, { "DownRightTeeVector", "\xE2\xA5\x9F", 0 }, { "DownRightVector", "\xE2\x87\x81", 0 }, { "DownRightVectorBar", "\xE2\xA5\x97", 0 }, { "DownTee", "\xE2\x8A\xA4", 0 }, { "DownTeeArrow", "\xE2\x86\xA7", 0 }, { "Downarrow", "\xE2\x87\x93", 0 }, { "Dscr", "\xF0\x9D\x92\x9F", 0 }, { "Dstrok", "\xC4\x90", 0 }, { "ENG", "\xC5\x8A", 0 }, { "ETH", "\xC3\x90", 0 }, { "Eacute", "\xC3\x89", 0 }, { "Ecaron", "\xC4\x9A", 0 }, { "Ecirc", "\xC3\x8A", 0 }, { "Ecy", "\xD0\xAD", 0 }, { "Edot", "\xC4\x96", 0 }, { "Efr", "\xF0\x9D\x94\x88", 0 }, { "Egrave", "\xC3\x88", 0 }, { "Element", "\xE2\x88\x88", 0 }, { "Emacr", "\xC4\x92", 0 }, { "EmptySmallSquare", "\xE2\x97\xBB", 0 }, { "EmptyVerySmallSquare", "\xE2\x96\xAB", 0 }, { "Eogon", "\xC4\x98", 0 }, { "Eopf", "\xF0\x9D\x94\xBC", 0 }, { "Epsilon", "\xCE\x95", 0 }, { "Equal", "\xE2\xA9\xB5", 0 }, { "EqualTilde", "\xE2\x89\x82", 0 }, { "Equilibrium", "\xE2\x87\x8C", 0 }, { "Escr", "\xE2\x84\xB0", 0 }, { "Esim", "\xE2\xA9\xB3", 0 }, { "Eta", "\xCE\x97", 0 }, { "Euml", "\xC3\x8B", 0 }, { "Exists", "\xE2\x88\x83", 0 }, { "ExponentialE", "\xE2\x85\x87", 0 }, { "Fcy", "\xD0\xA4", 0 }, { "Ffr", "\xF0\x9D\x94\x89", 0 }, { "FilledSmallSquare", "\xE2\x97\xBC", 0 }, { "FilledVerySmallSquare", "\xE2\x96\xAA", 0 }, { "Fopf", "\xF0\x9D\x94\xBD", 0 }, { "ForAll", "\xE2\x88\x80", 0 }, { "Fouriertrf", "\xE2\x84\xB1", 0 }, { "Fscr", "\xE2\x84\xB1", 0 }, { "GJcy", "\xD0\x83", 0 }, { "GT", "\x3E", 0 }, { "Gamma", "\xCE\x93", 0 }, { "Gammad", "\xCF\x9C", 0 }, { "Gbreve", "\xC4\x9E", 0 }, { "Gcedil", "\xC4\xA2", 0 }, { "Gcirc", "\xC4\x9C", 0 }, { "Gcy", "\xD0\x93", 0 }, { "Gdot", "\xC4\xA0", 0 }, { "Gfr", "\xF0\x9D\x94\x8A", 0 }, { "Gg", "\xE2\x8B\x99", 0 }, { "Gopf", "\xF0\x9D\x94\xBE", 0 }, { "GreaterEqual", "\xE2\x89\xA5", 0 }, { "GreaterEqualLess", "\xE2\x8B\x9B", 0 }, { "GreaterFullEqual", "\xE2\x89\xA7", 0 }, { "GreaterGreater", "\xE2\xAA\xA2", 0 }, { "GreaterLess", "\xE2\x89\xB7", 0 }, { "GreaterSlantEqual", "\xE2\xA9\xBE", 0 }, { "GreaterTilde", "\xE2\x89\xB3", 0 }, { "Gscr", "\xF0\x9D\x92\xA2", 0 }, { "Gt", "\xE2\x89\xAB", 0 }, { "HARDcy", "\xD0\xAA", 0 }, { "Hacek", "\xCB\x87", 0 }, { "Hat", "\x5E", 0 }, { "Hcirc", "\xC4\xA4", 0 }, { "Hfr", "\xE2\x84\x8C", 0 }, { "HilbertSpace", "\xE2\x84\x8B", 0 }, { "Hopf", "\xE2\x84\x8D", 0 }, { "HorizontalLine", "\xE2\x94\x80", 0 }, { "Hscr", "\xE2\x84\x8B", 0 }, { "Hstrok", "\xC4\xA6", 0 }, { "HumpDownHump", "\xE2\x89\x8E", 0 }, { "HumpEqual", "\xE2\x89\x8F", 0 }, { "IEcy", "\xD0\x95", 0 }, { "IJlig", "\xC4\xB2", 0 }, { "IOcy", "\xD0\x81", 0 }, { "Iacute", "\xC3\x8D", 0 }, { "Icirc", "\xC3\x8E", 0 }, { "Icy", "\xD0\x98", 0 }, { "Idot", "\xC4\xB0", 0 }, { "Ifr", "\xE2\x84\x91", 0 }, { "Igrave", "\xC3\x8C", 0 }, { "Im", "\xE2\x84\x91", 0 }, { "Imacr", "\xC4\xAA", 0 }, { "ImaginaryI", "\xE2\x85\x88", 0 }, { "Implies", "\xE2\x87\x92", 0 }, { "Int", "\xE2\x88\xAC", 0 }, { "Integral", "\xE2\x88\xAB", 0 }, { "Intersection", "\xE2\x8B\x82", 0 }, { "InvisibleComma", "\xE2\x81\xA3", 0 }, { "InvisibleTimes", "\xE2\x81\xA2", 0 }, { "Iogon", "\xC4\xAE", 0 }, { "Iopf", "\xF0\x9D\x95\x80", 0 }, { "Iota", "\xCE\x99", 0 }, { "Iscr", "\xE2\x84\x90", 0 }, { "Itilde", "\xC4\xA8", 0 }, { "Iukcy", "\xD0\x86", 0 }, { "Iuml", "\xC3\x8F", 0 }, { "Jcirc", "\xC4\xB4", 0 }, { "Jcy", "\xD0\x99", 0 }, { "Jfr", "\xF0\x9D\x94\x8D", 0 }, { "Jopf", "\xF0\x9D\x95\x81", 0 }, { "Jscr", "\xF0\x9D\x92\xA5", 0 }, { "Jsercy", "\xD0\x88", 0 }, { "Jukcy", "\xD0\x84", 0 }, { "KHcy", "\xD0\xA5", 0 }, { "KJcy", "\xD0\x8C", 0 }, { "Kappa", "\xCE\x9A", 0 }, { "Kcedil", "\xC4\xB6", 0 }, { "Kcy", "\xD0\x9A", 0 }, { "Kfr", "\xF0\x9D\x94\x8E", 0 }, { "Kopf", "\xF0\x9D\x95\x82", 0 }, { "Kscr", "\xF0\x9D\x92\xA6", 0 }, { "LJcy", "\xD0\x89", 0 }, { "LT", "\x3C", 0 }, { "Lacute", "\xC4\xB9", 0 }, { "Lambda", "\xCE\x9B", 0 }, { "Lang", "\xE2\x9F\xAA", 0 }, { "Laplacetrf", "\xE2\x84\x92", 0 }, { "Larr", "\xE2\x86\x9E", 0 }, { "Lcaron", "\xC4\xBD", 0 }, { "Lcedil", "\xC4\xBB", 0 }, { "Lcy", "\xD0\x9B", 0 }, { "LeftAngleBracket", "\xE2\x9F\xA8", 0 }, { "LeftArrow", "\xE2\x86\x90", 0 }, { "LeftArrowBar", "\xE2\x87\xA4", 0 }, { "LeftArrowRightArrow", "\xE2\x87\x86", 0 }, { "LeftCeiling", "\xE2\x8C\x88", 0 }, { "LeftDoubleBracket", "\xE2\x9F\xA6", 0 }, { "LeftDownTeeVector", "\xE2\xA5\xA1", 0 }, { "LeftDownVector", "\xE2\x87\x83", 0 }, { "LeftDownVectorBar", "\xE2\xA5\x99", 0 }, { "LeftFloor", "\xE2\x8C\x8A", 0 }, { "LeftRightArrow", "\xE2\x86\x94", 0 }, { "LeftRightVector", "\xE2\xA5\x8E", 0 }, { "LeftTee", "\xE2\x8A\xA3", 0 }, { "LeftTeeArrow", "\xE2\x86\xA4", 0 }, { "LeftTeeVector", "\xE2\xA5\x9A", 0 }, { "LeftTriangle", "\xE2\x8A\xB2", 0 }, { "LeftTriangleBar", "\xE2\xA7\x8F", 0 }, { "LeftTriangleEqual", "\xE2\x8A\xB4", 0 }, { "LeftUpDownVector", "\xE2\xA5\x91", 0 }, { "LeftUpTeeVector", "\xE2\xA5\xA0", 0 }, { "LeftUpVector", "\xE2\x86\xBF", 0 }, { "LeftUpVectorBar", "\xE2\xA5\x98", 0 }, { "LeftVector", "\xE2\x86\xBC", 0 }, { "LeftVectorBar", "\xE2\xA5\x92", 0 }, { "Leftarrow", "\xE2\x87\x90", 0 }, { "Leftrightarrow", "\xE2\x87\x94", 0 }, { "LessEqualGreater", "\xE2\x8B\x9A", 0 }, { "LessFullEqual", "\xE2\x89\xA6", 0 }, { "LessGreater", "\xE2\x89\xB6", 0 }, { "LessLess", "\xE2\xAA\xA1", 0 }, { "LessSlantEqual", "\xE2\xA9\xBD", 0 }, { "LessTilde", "\xE2\x89\xB2", 0 }, { "Lfr", "\xF0\x9D\x94\x8F", 0 }, { "Ll", "\xE2\x8B\x98", 0 }, { "Lleftarrow", "\xE2\x87\x9A", 0 }, { "Lmidot", "\xC4\xBF", 0 }, { "LongLeftArrow", "\xE2\x9F\xB5", 0 }, { "LongLeftRightArrow", "\xE2\x9F\xB7", 0 }, { "LongRightArrow", "\xE2\x9F\xB6", 0 }, { "Longleftarrow", "\xE2\x9F\xB8", 0 }, { "Longleftrightarrow", "\xE2\x9F\xBA", 0 }, { "Longrightarrow", "\xE2\x9F\xB9", 0 }, { "Lopf", "\xF0\x9D\x95\x83", 0 }, { "LowerLeftArrow", "\xE2\x86\x99", 0 }, { "LowerRightArrow", "\xE2\x86\x98", 0 }, { "Lscr", "\xE2\x84\x92", 0 }, { "Lsh", "\xE2\x86\xB0", 0 }, { "Lstrok", "\xC5\x81", 0 }, { "Lt", "\xE2\x89\xAA", 0 }, { "Map", "\xE2\xA4\x85", 0 }, { "Mcy", "\xD0\x9C", 0 }, { "MediumSpace", "\xE2\x81\x9F", 0 }, { "Mellintrf", "\xE2\x84\xB3", 0 }, { "Mfr", "\xF0\x9D\x94\x90", 0 }, { "MinusPlus", "\xE2\x88\x93", 0 }, { "Mopf", "\xF0\x9D\x95\x84", 0 }, { "Mscr", "\xE2\x84\xB3", 0 }, { "Mu", "\xCE\x9C", 0 }, { "NJcy", "\xD0\x8A", 0 }, { "Nacute", "\xC5\x83", 0 }, { "Ncaron", "\xC5\x87", 0 }, { "Ncedil", "\xC5\x85", 0 }, { "Ncy", "\xD0\x9D", 0 }, { "NegativeMediumSpace", "\xE2\x80\x8B", 0 }, { "NegativeThickSpace", "\xE2\x80\x8B", 0 }, { "NegativeThinSpace", "\xE2\x80\x8B", 0 }, { "NegativeVeryThinSpace", "\xE2\x80\x8B", 0 }, { "NestedGreaterGreater", "\xE2\x89\xAB", 0 }, { "NestedLessLess", "\xE2\x89\xAA", 0 }, { "NewLine", "\x0A", 0 }, { "Nfr", "\xF0\x9D\x94\x91", 0 }, { "NoBreak", "\xE2\x81\xA0", 0 }, { "NonBreakingSpace", "\xC2\xA0", 0 }, { "Nopf", "\xE2\x84\x95", 0 }, { "Not", "\xE2\xAB\xAC", 0 }, { "NotCongruent", "\xE2\x89\xA2", 0 }, { "NotCupCap", "\xE2\x89\xAD", 0 }, { "NotDoubleVerticalBar", "\xE2\x88\xA6", 0 }, { "NotElement", "\xE2\x88\x89", 0 }, { "NotEqual", "\xE2\x89\xA0", 0 }, { "NotEqualTilde", "\xE2\x89\x82\xCC\xB8", 0 }, { "NotExists", "\xE2\x88\x84", 0 }, { "NotGreater", "\xE2\x89\xAF", 0 }, { "NotGreaterEqual", "\xE2\x89\xB1", 0 }, { "NotGreaterFullEqual", "\xE2\x89\xA7\xCC\xB8", 0 }, { "NotGreaterGreater", "\xE2\x89\xAB\xCC\xB8", 0 }, { "NotGreaterLess", "\xE2\x89\xB9", 0 }, { "NotGreaterSlantEqual", "\xE2\xA9\xBE\xCC\xB8", 0 }, { "NotGreaterTilde", "\xE2\x89\xB5", 0 }, { "NotHumpDownHump", "\xE2\x89\x8E\xCC\xB8", 0 }, { "NotHumpEqual", "\xE2\x89\x8F\xCC\xB8", 0 }, { "NotLeftTriangle", "\xE2\x8B\xAA", 0 }, { "NotLeftTriangleBar", "\xE2\xA7\x8F\xCC\xB8", 0 }, { "NotLeftTriangleEqual", "\xE2\x8B\xAC", 0 }, { "NotLess", "\xE2\x89\xAE", 0 }, { "NotLessEqual", "\xE2\x89\xB0", 0 }, { "NotLessGreater", "\xE2\x89\xB8", 0 }, { "NotLessLess", "\xE2\x89\xAA\xCC\xB8", 0 }, { "NotLessSlantEqual", "\xE2\xA9\xBD\xCC\xB8", 0 }, { "NotLessTilde", "\xE2\x89\xB4", 0 }, { "NotNestedGreaterGreater", "\xE2\xAA\xA2\xCC\xB8", 0 }, { "NotNestedLessLess", "\xE2\xAA\xA1\xCC\xB8", 0 }, { "NotPrecedes", "\xE2\x8A\x80", 0 }, { "NotPrecedesEqual", "\xE2\xAA\xAF\xCC\xB8", 0 }, { "NotPrecedesSlantEqual", "\xE2\x8B\xA0", 0 }, { "NotReverseElement", "\xE2\x88\x8C", 0 }, { "NotRightTriangle", "\xE2\x8B\xAB", 0 }, { "NotRightTriangleBar", "\xE2\xA7\x90\xCC\xB8", 0 }, { "NotRightTriangleEqual", "\xE2\x8B\xAD", 0 }, { "NotSquareSubset", "\xE2\x8A\x8F\xCC\xB8", 0 }, { "NotSquareSubsetEqual", "\xE2\x8B\xA2", 0 }, { "NotSquareSuperset", "\xE2\x8A\x90\xCC\xB8", 0 }, { "NotSquareSupersetEqual", "\xE2\x8B\xA3", 0 }, { "NotSubset", "\xE2\x8A\x82\xE2\x83\x92", 0 }, { "NotSubsetEqual", "\xE2\x8A\x88", 0 }, { "NotSucceeds", "\xE2\x8A\x81", 0 }, { "NotSucceedsEqual", "\xE2\xAA\xB0\xCC\xB8", 0 }, { "NotSucceedsSlantEqual", "\xE2\x8B\xA1", 0 }, { "NotSucceedsTilde", "\xE2\x89\xBF\xCC\xB8", 0 }, { "NotSuperset", "\xE2\x8A\x83\xE2\x83\x92", 0 }, { "NotSupersetEqual", "\xE2\x8A\x89", 0 }, { "NotTilde", "\xE2\x89\x81", 0 }, { "NotTildeEqual", "\xE2\x89\x84", 0 }, { "NotTildeFullEqual", "\xE2\x89\x87", 0 }, { "NotTildeTilde", "\xE2\x89\x89", 0 }, { "NotVerticalBar", "\xE2\x88\xA4", 0 }, { "Nscr", "\xF0\x9D\x92\xA9", 0 }, { "Ntilde", "\xC3\x91", 0 }, { "Nu", "\xCE\x9D", 0 }, { "OElig", "\xC5\x92", 0 }, { "Oacute", "\xC3\x93", 0 }, { "Ocirc", "\xC3\x94", 0 }, { "Ocy", "\xD0\x9E", 0 }, { "Odblac", "\xC5\x90", 0 }, { "Ofr", "\xF0\x9D\x94\x92", 0 }, { "Ograve", "\xC3\x92", 0 }, { "Omacr", "\xC5\x8C", 0 }, { "Omega", "\xCE\xA9", 0 }, { "Omicron", "\xCE\x9F", 0 }, { "Oopf", "\xF0\x9D\x95\x86", 0 }, { "OpenCurlyDoubleQuote", "\xE2\x80\x9C", 0 }, { "OpenCurlyQuote", "\xE2\x80\x98", 0 }, { "Or", "\xE2\xA9\x94", 0 }, { "Oscr", "\xF0\x9D\x92\xAA", 0 }, { "Oslash", "\xC3\x98", 0 }, { "Otilde", "\xC3\x95", 0 }, { "Otimes", "\xE2\xA8\xB7", 0 }, { "Ouml", "\xC3\x96", 0 }, { "OverBar", "\xE2\x80\xBE", 0 }, { "OverBrace", "\xE2\x8F\x9E", 0 }, { "OverBracket", "\xE2\x8E\xB4", 0 }, { "OverParenthesis", "\xE2\x8F\x9C", 0 }, { "PartialD", "\xE2\x88\x82", 0 }, { "Pcy", "\xD0\x9F", 0 }, { "Pfr", "\xF0\x9D\x94\x93", 0 }, { "Phi", "\xCE\xA6", 0 }, { "Pi", "\xCE\xA0", 0 }, { "PlusMinus", "\xC2\xB1", 0 }, { "Poincareplane", "\xE2\x84\x8C", 0 }, { "Popf", "\xE2\x84\x99", 0 }, { "Pr", "\xE2\xAA\xBB", 0 }, { "Precedes", "\xE2\x89\xBA", 0 }, { "PrecedesEqual", "\xE2\xAA\xAF", 0 }, { "PrecedesSlantEqual", "\xE2\x89\xBC", 0 }, { "PrecedesTilde", "\xE2\x89\xBE", 0 }, { "Prime", "\xE2\x80\xB3", 0 }, { "Product", "\xE2\x88\x8F", 0 }, { "Proportion", "\xE2\x88\xB7", 0 }, { "Proportional", "\xE2\x88\x9D", 0 }, { "Pscr", "\xF0\x9D\x92\xAB", 0 }, { "Psi", "\xCE\xA8", 0 }, { "QUOT", "\x22", 0 }, { "Qfr", "\xF0\x9D\x94\x94", 0 }, { "Qopf", "\xE2\x84\x9A", 0 }, { "Qscr", "\xF0\x9D\x92\xAC", 0 }, { "RBarr", "\xE2\xA4\x90", 0 }, { "REG", "\xC2\xAE", 0 }, { "Racute", "\xC5\x94", 0 }, { "Rang", "\xE2\x9F\xAB", 0 }, { "Rarr", "\xE2\x86\xA0", 0 }, { "Rarrtl", "\xE2\xA4\x96", 0 }, { "Rcaron", "\xC5\x98", 0 }, { "Rcedil", "\xC5\x96", 0 }, { "Rcy", "\xD0\xA0", 0 }, { "Re", "\xE2\x84\x9C", 0 }, { "ReverseElement", "\xE2\x88\x8B", 0 }, { "ReverseEquilibrium", "\xE2\x87\x8B", 0 }, { "ReverseUpEquilibrium", "\xE2\xA5\xAF", 0 }, { "Rfr", "\xE2\x84\x9C", 0 }, { "Rho", "\xCE\xA1", 0 }, { "RightAngleBracket", "\xE2\x9F\xA9", 0 }, { "RightArrow", "\xE2\x86\x92", 0 }, { "RightArrowBar", "\xE2\x87\xA5", 0 }, { "RightArrowLeftArrow", "\xE2\x87\x84", 0 }, { "RightCeiling", "\xE2\x8C\x89", 0 }, { "RightDoubleBracket", "\xE2\x9F\xA7", 0 }, { "RightDownTeeVector", "\xE2\xA5\x9D", 0 }, { "RightDownVector", "\xE2\x87\x82", 0 }, { "RightDownVectorBar", "\xE2\xA5\x95", 0 }, { "RightFloor", "\xE2\x8C\x8B", 0 }, { "RightTee", "\xE2\x8A\xA2", 0 }, { "RightTeeArrow", "\xE2\x86\xA6", 0 }, { "RightTeeVector", "\xE2\xA5\x9B", 0 }, { "RightTriangle", "\xE2\x8A\xB3", 0 }, { "RightTriangleBar", "\xE2\xA7\x90", 0 }, { "RightTriangleEqual", "\xE2\x8A\xB5", 0 }, { "RightUpDownVector", "\xE2\xA5\x8F", 0 }, { "RightUpTeeVector", "\xE2\xA5\x9C", 0 }, { "RightUpVector", "\xE2\x86\xBE", 0 }, { "RightUpVectorBar", "\xE2\xA5\x94", 0 }, { "RightVector", "\xE2\x87\x80", 0 }, { "RightVectorBar", "\xE2\xA5\x93", 0 }, { "Rightarrow", "\xE2\x87\x92", 0 }, { "Ropf", "\xE2\x84\x9D", 0 }, { "RoundImplies", "\xE2\xA5\xB0", 0 }, { "Rrightarrow", "\xE2\x87\x9B", 0 }, { "Rscr", "\xE2\x84\x9B", 0 }, { "Rsh", "\xE2\x86\xB1", 0 }, { "RuleDelayed", "\xE2\xA7\xB4", 0 }, { "SHCHcy", "\xD0\xA9", 0 }, { "SHcy", "\xD0\xA8", 0 }, { "SOFTcy", "\xD0\xAC", 0 }, { "Sacute", "\xC5\x9A", 0 }, { "Sc", "\xE2\xAA\xBC", 0 }, { "Scaron", "\xC5\xA0", 0 }, { "Scedil", "\xC5\x9E", 0 }, { "Scirc", "\xC5\x9C", 0 }, { "Scy", "\xD0\xA1", 0 }, { "Sfr", "\xF0\x9D\x94\x96", 0 }, { "ShortDownArrow", "\xE2\x86\x93", 0 }, { "ShortLeftArrow", "\xE2\x86\x90", 0 }, { "ShortRightArrow", "\xE2\x86\x92", 0 }, { "ShortUpArrow", "\xE2\x86\x91", 0 }, { "Sigma", "\xCE\xA3", 0 }, { "SmallCircle", "\xE2\x88\x98", 0 }, { "Sopf", "\xF0\x9D\x95\x8A", 0 }, { "Sqrt", "\xE2\x88\x9A", 0 }, { "Square", "\xE2\x96\xA1", 0 }, { "SquareIntersection", "\xE2\x8A\x93", 0 }, { "SquareSubset", "\xE2\x8A\x8F", 0 }, { "SquareSubsetEqual", "\xE2\x8A\x91", 0 }, { "SquareSuperset", "\xE2\x8A\x90", 0 }, { "SquareSupersetEqual", "\xE2\x8A\x92", 0 }, { "SquareUnion", "\xE2\x8A\x94", 0 }, { "Sscr", "\xF0\x9D\x92\xAE", 0 }, { "Star", "\xE2\x8B\x86", 0 }, { "Sub", "\xE2\x8B\x90", 0 }, { "Subset", "\xE2\x8B\x90", 0 }, { "SubsetEqual", "\xE2\x8A\x86", 0 }, { "Succeeds", "\xE2\x89\xBB", 0 }, { "SucceedsEqual", "\xE2\xAA\xB0", 0 }, { "SucceedsSlantEqual", "\xE2\x89\xBD", 0 }, { "SucceedsTilde", "\xE2\x89\xBF", 0 }, { "SuchThat", "\xE2\x88\x8B", 0 }, { "Sum", "\xE2\x88\x91", 0 }, { "Sup", "\xE2\x8B\x91", 0 }, { "Superset", "\xE2\x8A\x83", 0 }, { "SupersetEqual", "\xE2\x8A\x87", 0 }, { "Supset", "\xE2\x8B\x91", 0 }, { "THORN", "\xC3\x9E", 0 }, { "TRADE", "\xE2\x84\xA2", 0 }, { "TSHcy", "\xD0\x8B", 0 }, { "TScy", "\xD0\xA6", 0 }, { "Tab", "\x09", 0 }, { "Tau", "\xCE\xA4", 0 }, { "Tcaron", "\xC5\xA4", 0 }, { "Tcedil", "\xC5\xA2", 0 }, { "Tcy", "\xD0\xA2", 0 }, { "Tfr", "\xF0\x9D\x94\x97", 0 }, { "Therefore", "\xE2\x88\xB4", 0 }, { "Theta", "\xCE\x98", 0 }, { "ThickSpace", "\xE2\x81\x9F\xE2\x80\x8A", 0 }, { "ThinSpace", "\xE2\x80\x89", 0 }, { "Tilde", "\xE2\x88\xBC", 0 }, { "TildeEqual", "\xE2\x89\x83", 0 }, { "TildeFullEqual", "\xE2\x89\x85", 0 }, { "TildeTilde", "\xE2\x89\x88", 0 }, { "Topf", "\xF0\x9D\x95\x8B", 0 }, { "TripleDot", "\xE2\x83\x9B", 0 }, { "Tscr", "\xF0\x9D\x92\xAF", 0 }, { "Tstrok", "\xC5\xA6", 0 }, { "Uacute", "\xC3\x9A", 0 }, { "Uarr", "\xE2\x86\x9F", 0 }, { "Uarrocir", "\xE2\xA5\x89", 0 }, { "Ubrcy", "\xD0\x8E", 0 }, { "Ubreve", "\xC5\xAC", 0 }, { "Ucirc", "\xC3\x9B", 0 }, { "Ucy", "\xD0\xA3", 0 }, { "Udblac", "\xC5\xB0", 0 }, { "Ufr", "\xF0\x9D\x94\x98", 0 }, { "Ugrave", "\xC3\x99", 0 }, { "Umacr", "\xC5\xAA", 0 }, { "UnderBar", "\x5F", 0 }, { "UnderBrace", "\xE2\x8F\x9F", 0 }, { "UnderBracket", "\xE2\x8E\xB5", 0 }, { "UnderParenthesis", "\xE2\x8F\x9D", 0 }, { "Union", "\xE2\x8B\x83", 0 }, { "UnionPlus", "\xE2\x8A\x8E", 0 }, { "Uogon", "\xC5\xB2", 0 }, { "Uopf", "\xF0\x9D\x95\x8C", 0 }, { "UpArrow", "\xE2\x86\x91", 0 }, { "UpArrowBar", "\xE2\xA4\x92", 0 }, { "UpArrowDownArrow", "\xE2\x87\x85", 0 }, { "UpDownArrow", "\xE2\x86\x95", 0 }, { "UpEquilibrium", "\xE2\xA5\xAE", 0 }, { "UpTee", "\xE2\x8A\xA5", 0 }, { "UpTeeArrow", "\xE2\x86\xA5", 0 }, { "Uparrow", "\xE2\x87\x91", 0 }, { "Updownarrow", "\xE2\x87\x95", 0 }, { "UpperLeftArrow", "\xE2\x86\x96", 0 }, { "UpperRightArrow", "\xE2\x86\x97", 0 }, { "Upsi", "\xCF\x92", 0 }, { "Upsilon", "\xCE\xA5", 0 }, { "Uring", "\xC5\xAE", 0 }, { "Uscr", "\xF0\x9D\x92\xB0", 0 }, { "Utilde", "\xC5\xA8", 0 }, { "Uuml", "\xC3\x9C", 0 }, { "VDash", "\xE2\x8A\xAB", 0 }, { "Vbar", "\xE2\xAB\xAB", 0 }, { "Vcy", "\xD0\x92", 0 }, { "Vdash", "\xE2\x8A\xA9", 0 }, { "Vdashl", "\xE2\xAB\xA6", 0 }, { "Vee", "\xE2\x8B\x81", 0 }, { "Verbar", "\xE2\x80\x96", 0 }, { "Vert", "\xE2\x80\x96", 0 }, { "VerticalBar", "\xE2\x88\xA3", 0 }, { "VerticalLine", "\x7C", 0 }, { "VerticalSeparator", "\xE2\x9D\x98", 0 }, { "VerticalTilde", "\xE2\x89\x80", 0 }, { "VeryThinSpace", "\xE2\x80\x8A", 0 }, { "Vfr", "\xF0\x9D\x94\x99", 0 }, { "Vopf", "\xF0\x9D\x95\x8D", 0 }, { "Vscr", "\xF0\x9D\x92\xB1", 0 }, { "Vvdash", "\xE2\x8A\xAA", 0 }, { "Wcirc", "\xC5\xB4", 0 }, { "Wedge", "\xE2\x8B\x80", 0 }, { "Wfr", "\xF0\x9D\x94\x9A", 0 }, { "Wopf", "\xF0\x9D\x95\x8E", 0 }, { "Wscr", "\xF0\x9D\x92\xB2", 0 }, { "Xfr", "\xF0\x9D\x94\x9B", 0 }, { "Xi", "\xCE\x9E", 0 }, { "Xopf", "\xF0\x9D\x95\x8F", 0 }, { "Xscr", "\xF0\x9D\x92\xB3", 0 }, { "YAcy", "\xD0\xAF", 0 }, { "YIcy", "\xD0\x87", 0 }, { "YUcy", "\xD0\xAE", 0 }, { "Yacute", "\xC3\x9D", 0 }, { "Ycirc", "\xC5\xB6", 0 }, { "Ycy", "\xD0\xAB", 0 }, { "Yfr", "\xF0\x9D\x94\x9C", 0 }, { "Yopf", "\xF0\x9D\x95\x90", 0 }, { "Yscr", "\xF0\x9D\x92\xB4", 0 }, { "Yuml", "\xC5\xB8", 0 }, { "ZHcy", "\xD0\x96", 0 }, { "Zacute", "\xC5\xB9", 0 }, { "Zcaron", "\xC5\xBD", 0 }, { "Zcy", "\xD0\x97", 0 }, { "Zdot", "\xC5\xBB", 0 }, { "ZeroWidthSpace", "\xE2\x80\x8B", 0 }, { "Zeta", "\xCE\x96", 0 }, { "Zfr", "\xE2\x84\xA8", 0 }, { "Zopf", "\xE2\x84\xA4", 0 }, { "Zscr", "\xF0\x9D\x92\xB5", 0 }, { "aacute", "\xC3\xA1", 0 }, { "abreve", "\xC4\x83", 0 }, { "ac", "\xE2\x88\xBE", 0 }, { "acE", "\xE2\x88\xBE\xCC\xB3", 0 }, { "acd", "\xE2\x88\xBF", 0 }, { "acirc", "\xC3\xA2", 0 }, { "acute", "\xC2\xB4", 0 }, { "acy", "\xD0\xB0", 0 }, { "aelig", "\xC3\xA6", 0 }, { "af", "\xE2\x81\xA1", 0 }, { "afr", "\xF0\x9D\x94\x9E", 0 }, { "agrave", "\xC3\xA0", 0 }, { "alefsym", "\xE2\x84\xB5", 0 }, { "aleph", "\xE2\x84\xB5", 0 }, { "alpha", "\xCE\xB1", 0 }, { "amacr", "\xC4\x81", 0 }, { "amalg", "\xE2\xA8\xBF", 0 }, { "amp", "\x26", 0 }, { "and", "\xE2\x88\xA7", 0 }, { "andand", "\xE2\xA9\x95", 0 }, { "andd", "\xE2\xA9\x9C", 0 }, { "andslope", "\xE2\xA9\x98", 0 }, { "andv", "\xE2\xA9\x9A", 0 }, { "ang", "\xE2\x88\xA0", 0 }, { "ange", "\xE2\xA6\xA4", 0 }, { "angle", "\xE2\x88\xA0", 0 }, { "angmsd", "\xE2\x88\xA1", 0 }, { "angmsdaa", "\xE2\xA6\xA8", 0 }, { "angmsdab", "\xE2\xA6\xA9", 0 }, { "angmsdac", "\xE2\xA6\xAA", 0 }, { "angmsdad", "\xE2\xA6\xAB", 0 }, { "angmsdae", "\xE2\xA6\xAC", 0 }, { "angmsdaf", "\xE2\xA6\xAD", 0 }, { "angmsdag", "\xE2\xA6\xAE", 0 }, { "angmsdah", "\xE2\xA6\xAF", 0 }, { "angrt", "\xE2\x88\x9F", 0 }, { "angrtvb", "\xE2\x8A\xBE", 0 }, { "angrtvbd", "\xE2\xA6\x9D", 0 }, { "angsph", "\xE2\x88\xA2", 0 }, { "angst", "\xC3\x85", 0 }, { "angzarr", "\xE2\x8D\xBC", 0 }, { "aogon", "\xC4\x85", 0 }, { "aopf", "\xF0\x9D\x95\x92", 0 }, { "ap", "\xE2\x89\x88", 0 }, { "apE", "\xE2\xA9\xB0", 0 }, { "apacir", "\xE2\xA9\xAF", 0 }, { "ape", "\xE2\x89\x8A", 0 }, { "apid", "\xE2\x89\x8B", 0 }, { "apos", "\x27", 0 }, { "approx", "\xE2\x89\x88", 0 }, { "approxeq", "\xE2\x89\x8A", 0 }, { "aring", "\xC3\xA5", 0 }, { "ascr", "\xF0\x9D\x92\xB6", 0 }, { "ast", "\x2A", 0 }, { "asymp", "\xE2\x89\x88", 0 }, { "asympeq", "\xE2\x89\x8D", 0 }, { "atilde", "\xC3\xA3", 0 }, { "auml", "\xC3\xA4", 0 }, { "awconint", "\xE2\x88\xB3", 0 }, { "awint", "\xE2\xA8\x91", 0 }, { "bNot", "\xE2\xAB\xAD", 0 }, { "backcong", "\xE2\x89\x8C", 0 }, { "backepsilon", "\xCF\xB6", 0 }, { "backprime", "\xE2\x80\xB5", 0 }, { "backsim", "\xE2\x88\xBD", 0 }, { "backsimeq", "\xE2\x8B\x8D", 0 }, { "barvee", "\xE2\x8A\xBD", 0 }, { "barwed", "\xE2\x8C\x85", 0 }, { "barwedge", "\xE2\x8C\x85", 0 }, { "bbrk", "\xE2\x8E\xB5", 0 }, { "bbrktbrk", "\xE2\x8E\xB6", 0 }, { "bcong", "\xE2\x89\x8C", 0 }, { "bcy", "\xD0\xB1", 0 }, { "bdquo", "\xE2\x80\x9E", 0 }, { "becaus", "\xE2\x88\xB5", 0 }, { "because", "\xE2\x88\xB5", 0 }, { "bemptyv", "\xE2\xA6\xB0", 0 }, { "bepsi", "\xCF\xB6", 0 }, { "bernou", "\xE2\x84\xAC", 0 }, { "beta", "\xCE\xB2", 0 }, { "beth", "\xE2\x84\xB6", 0 }, { "between", "\xE2\x89\xAC", 0 }, { "bfr", "\xF0\x9D\x94\x9F", 0 }, { "bigcap", "\xE2\x8B\x82", 0 }, { "bigcirc", "\xE2\x97\xAF", 0 }, { "bigcup", "\xE2\x8B\x83", 0 }, { "bigodot", "\xE2\xA8\x80", 0 }, { "bigoplus", "\xE2\xA8\x81", 0 }, { "bigotimes", "\xE2\xA8\x82", 0 }, { "bigsqcup", "\xE2\xA8\x86", 0 }, { "bigstar", "\xE2\x98\x85", 0 }, { "bigtriangledown", "\xE2\x96\xBD", 0 }, { "bigtriangleup", "\xE2\x96\xB3", 0 }, { "biguplus", "\xE2\xA8\x84", 0 }, { "bigvee", "\xE2\x8B\x81", 0 }, { "bigwedge", "\xE2\x8B\x80", 0 }, { "bkarow", "\xE2\xA4\x8D", 0 }, { "blacklozenge", "\xE2\xA7\xAB", 0 }, { "blacksquare", "\xE2\x96\xAA", 0 }, { "blacktriangle", "\xE2\x96\xB4", 0 }, { "blacktriangledown", "\xE2\x96\xBE", 0 }, { "blacktriangleleft", "\xE2\x97\x82", 0 }, { "blacktriangleright", "\xE2\x96\xB8", 0 }, { "blank", "\xE2\x90\xA3", 0 }, { "blk12", "\xE2\x96\x92", 0 }, { "blk14", "\xE2\x96\x91", 0 }, { "blk34", "\xE2\x96\x93", 0 }, { "block", "\xE2\x96\x88", 0 }, { "bne", "\x3D\xE2\x83\xA5", 0 }, { "bnequiv", "\xE2\x89\xA1\xE2\x83\xA5", 0 }, { "bnot", "\xE2\x8C\x90", 0 }, { "bopf", "\xF0\x9D\x95\x93", 0 }, { "bot", "\xE2\x8A\xA5", 0 }, { "bottom", "\xE2\x8A\xA5", 0 }, { "bowtie", "\xE2\x8B\x88", 0 }, { "boxDL", "\xE2\x95\x97", 0 }, { "boxDR", "\xE2\x95\x94", 0 }, { "boxDl", "\xE2\x95\x96", 0 }, { "boxDr", "\xE2\x95\x93", 0 }, { "boxH", "\xE2\x95\x90", 0 }, { "boxHD", "\xE2\x95\xA6", 0 }, { "boxHU", "\xE2\x95\xA9", 0 }, { "boxHd", "\xE2\x95\xA4", 0 }, { "boxHu", "\xE2\x95\xA7", 0 }, { "boxUL", "\xE2\x95\x9D", 0 }, { "boxUR", "\xE2\x95\x9A", 0 }, { "boxUl", "\xE2\x95\x9C", 0 }, { "boxUr", "\xE2\x95\x99", 0 }, { "boxV", "\xE2\x95\x91", 0 }, { "boxVH", "\xE2\x95\xAC", 0 }, { "boxVL", "\xE2\x95\xA3", 0 }, { "boxVR", "\xE2\x95\xA0", 0 }, { "boxVh", "\xE2\x95\xAB", 0 }, { "boxVl", "\xE2\x95\xA2", 0 }, { "boxVr", "\xE2\x95\x9F", 0 }, { "boxbox", "\xE2\xA7\x89", 0 }, { "boxdL", "\xE2\x95\x95", 0 }, { "boxdR", "\xE2\x95\x92", 0 }, { "boxdl", "\xE2\x94\x90", 0 }, { "boxdr", "\xE2\x94\x8C", 0 }, { "boxh", "\xE2\x94\x80", 0 }, { "boxhD", "\xE2\x95\xA5", 0 }, { "boxhU", "\xE2\x95\xA8", 0 }, { "boxhd", "\xE2\x94\xAC", 0 }, { "boxhu", "\xE2\x94\xB4", 0 }, { "boxminus", "\xE2\x8A\x9F", 0 }, { "boxplus", "\xE2\x8A\x9E", 0 }, { "boxtimes", "\xE2\x8A\xA0", 0 }, { "boxuL", "\xE2\x95\x9B", 0 }, { "boxuR", "\xE2\x95\x98", 0 }, { "boxul", "\xE2\x94\x98", 0 }, { "boxur", "\xE2\x94\x94", 0 }, { "boxv", "\xE2\x94\x82", 0 }, { "boxvH", "\xE2\x95\xAA", 0 }, { "boxvL", "\xE2\x95\xA1", 0 }, { "boxvR", "\xE2\x95\x9E", 0 }, { "boxvh", "\xE2\x94\xBC", 0 }, { "boxvl", "\xE2\x94\xA4", 0 }, { "boxvr", "\xE2\x94\x9C", 0 }, { "bprime", "\xE2\x80\xB5", 0 }, { "breve", "\xCB\x98", 0 }, { "brvbar", "\xC2\xA6", 0 }, { "bscr", "\xF0\x9D\x92\xB7", 0 }, { "bsemi", "\xE2\x81\x8F", 0 }, { "bsim", "\xE2\x88\xBD", 0 }, { "bsime", "\xE2\x8B\x8D", 0 }, { "bsol", "\x5C", 0 }, { "bsolb", "\xE2\xA7\x85", 0 }, { "bsolhsub", "\xE2\x9F\x88", 0 }, { "bull", "\xE2\x80\xA2", 0 }, { "bullet", "\xE2\x80\xA2", 0 }, { "bump", "\xE2\x89\x8E", 0 }, { "bumpE", "\xE2\xAA\xAE", 0 }, { "bumpe", "\xE2\x89\x8F", 0 }, { "bumpeq", "\xE2\x89\x8F", 0 }, { "cacute", "\xC4\x87", 0 }, { "cap", "\xE2\x88\xA9", 0 }, { "capand", "\xE2\xA9\x84", 0 }, { "capbrcup", "\xE2\xA9\x89", 0 }, { "capcap", "\xE2\xA9\x8B", 0 }, { "capcup", "\xE2\xA9\x87", 0 }, { "capdot", "\xE2\xA9\x80", 0 }, { "caps", "\xE2\x88\xA9\xEF\xB8\x80", 0 }, { "caret", "\xE2\x81\x81", 0 }, { "caron", "\xCB\x87", 0 }, { "ccaps", "\xE2\xA9\x8D", 0 }, { "ccaron", "\xC4\x8D", 0 }, { "ccedil", "\xC3\xA7", 0 }, { "ccirc", "\xC4\x89", 0 }, { "ccups", "\xE2\xA9\x8C", 0 }, { "ccupssm", "\xE2\xA9\x90", 0 }, { "cdot", "\xC4\x8B", 0 }, { "cedil", "\xC2\xB8", 0 }, { "cemptyv", "\xE2\xA6\xB2", 0 }, { "cent", "\xC2\xA2", 0 }, { "centerdot", "\xC2\xB7", 0 }, { "cfr", "\xF0\x9D\x94\xA0", 0 }, { "chcy", "\xD1\x87", 0 }, { "check", "\xE2\x9C\x93", 0 }, { "checkmark", "\xE2\x9C\x93", 0 }, { "chi", "\xCF\x87", 0 }, { "cir", "\xE2\x97\x8B", 0 }, { "cirE", "\xE2\xA7\x83", 0 }, { "circ", "\xCB\x86", 0 }, { "circeq", "\xE2\x89\x97", 0 }, { "circlearrowleft", "\xE2\x86\xBA", 0 }, { "circlearrowright", "\xE2\x86\xBB", 0 }, { "circledR", "\xC2\xAE", 0 }, { "circledS", "\xE2\x93\x88", 0 }, { "circledast", "\xE2\x8A\x9B", 0 }, { "circledcirc", "\xE2\x8A\x9A", 0 }, { "circleddash", "\xE2\x8A\x9D", 0 }, { "cire", "\xE2\x89\x97", 0 }, { "cirfnint", "\xE2\xA8\x90", 0 }, { "cirmid", "\xE2\xAB\xAF", 0 }, { "cirscir", "\xE2\xA7\x82", 0 }, { "clubs", "\xE2\x99\xA3", 0 }, { "clubsuit", "\xE2\x99\xA3", 0 }, { "colon", "\x3A", 0 }, { "colone", "\xE2\x89\x94", 0 }, { "coloneq", "\xE2\x89\x94", 0 }, { "comma", "\x2C", 0 }, { "commat", "\x40", 0 }, { "comp", "\xE2\x88\x81", 0 }, { "compfn", "\xE2\x88\x98", 0 }, { "complement", "\xE2\x88\x81", 0 }, { "complexes", "\xE2\x84\x82", 0 }, { "cong", "\xE2\x89\x85", 0 }, { "congdot", "\xE2\xA9\xAD", 0 }, { "conint", "\xE2\x88\xAE", 0 }, { "copf", "\xF0\x9D\x95\x94", 0 }, { "coprod", "\xE2\x88\x90", 0 }, { "copy", "\xC2\xA9", 0 }, { "copysr", "\xE2\x84\x97", 0 }, { "crarr", "\xE2\x86\xB5", 0 }, { "cross", "\xE2\x9C\x97", 0 }, { "cscr", "\xF0\x9D\x92\xB8", 0 }, { "csub", "\xE2\xAB\x8F", 0 }, { "csube", "\xE2\xAB\x91", 0 }, { "csup", "\xE2\xAB\x90", 0 }, { "csupe", "\xE2\xAB\x92", 0 }, { "ctdot", "\xE2\x8B\xAF", 0 }, { "cudarrl", "\xE2\xA4\xB8", 0 }, { "cudarrr", "\xE2\xA4\xB5", 0 }, { "cuepr", "\xE2\x8B\x9E", 0 }, { "cuesc", "\xE2\x8B\x9F", 0 }, { "cularr", "\xE2\x86\xB6", 0 }, { "cularrp", "\xE2\xA4\xBD", 0 }, { "cup", "\xE2\x88\xAA", 0 }, { "cupbrcap", "\xE2\xA9\x88", 0 }, { "cupcap", "\xE2\xA9\x86", 0 }, { "cupcup", "\xE2\xA9\x8A", 0 }, { "cupdot", "\xE2\x8A\x8D", 0 }, { "cupor", "\xE2\xA9\x85", 0 }, { "cups", "\xE2\x88\xAA\xEF\xB8\x80", 0 }, { "curarr", "\xE2\x86\xB7", 0 }, { "curarrm", "\xE2\xA4\xBC", 0 }, { "curlyeqprec", "\xE2\x8B\x9E", 0 }, { "curlyeqsucc", "\xE2\x8B\x9F", 0 }, { "curlyvee", "\xE2\x8B\x8E", 0 }, { "curlywedge", "\xE2\x8B\x8F", 0 }, { "curren", "\xC2\xA4", 0 }, { "curvearrowleft", "\xE2\x86\xB6", 0 }, { "curvearrowright", "\xE2\x86\xB7", 0 }, { "cuvee", "\xE2\x8B\x8E", 0 }, { "cuwed", "\xE2\x8B\x8F", 0 }, { "cwconint", "\xE2\x88\xB2", 0 }, { "cwint", "\xE2\x88\xB1", 0 }, { "cylcty", "\xE2\x8C\xAD", 0 }, { "dArr", "\xE2\x87\x93", 0 }, { "dHar", "\xE2\xA5\xA5", 0 }, { "dagger", "\xE2\x80\xA0", 0 }, { "daleth", "\xE2\x84\xB8", 0 }, { "darr", "\xE2\x86\x93", 0 }, { "dash", "\xE2\x80\x90", 0 }, { "dashv", "\xE2\x8A\xA3", 0 }, { "dbkarow", "\xE2\xA4\x8F", 0 }, { "dblac", "\xCB\x9D", 0 }, { "dcaron", "\xC4\x8F", 0 }, { "dcy", "\xD0\xB4", 0 }, { "dd", "\xE2\x85\x86", 0 }, { "ddagger", "\xE2\x80\xA1", 0 }, { "ddarr", "\xE2\x87\x8A", 0 }, { "ddotseq", "\xE2\xA9\xB7", 0 }, { "deg", "\xC2\xB0", 0 }, { "delta", "\xCE\xB4", 0 }, { "demptyv", "\xE2\xA6\xB1", 0 }, { "dfisht", "\xE2\xA5\xBF", 0 }, { "dfr", "\xF0\x9D\x94\xA1", 0 }, { "dharl", "\xE2\x87\x83", 0 }, { "dharr", "\xE2\x87\x82", 0 }, { "diam", "\xE2\x8B\x84", 0 }, { "diamond", "\xE2\x8B\x84", 0 }, { "diamondsuit", "\xE2\x99\xA6", 0 }, { "diams", "\xE2\x99\xA6", 0 }, { "die", "\xC2\xA8", 0 }, { "digamma", "\xCF\x9D", 0 }, { "disin", "\xE2\x8B\xB2", 0 }, { "div", "\xC3\xB7", 0 }, { "divide", "\xC3\xB7", 0 }, { "divideontimes", "\xE2\x8B\x87", 0 }, { "divonx", "\xE2\x8B\x87", 0 }, { "djcy", "\xD1\x92", 0 }, { "dlcorn", "\xE2\x8C\x9E", 0 }, { "dlcrop", "\xE2\x8C\x8D", 0 }, { "dollar", "\x24", 0 }, { "dopf", "\xF0\x9D\x95\x95", 0 }, { "dot", "\xCB\x99", 0 }, { "doteq", "\xE2\x89\x90", 0 }, { "doteqdot", "\xE2\x89\x91", 0 }, { "dotminus", "\xE2\x88\xB8", 0 }, { "dotplus", "\xE2\x88\x94", 0 }, { "dotsquare", "\xE2\x8A\xA1", 0 }, { "doublebarwedge", "\xE2\x8C\x86", 0 }, { "downarrow", "\xE2\x86\x93", 0 }, { "downdownarrows", "\xE2\x87\x8A", 0 }, { "downharpoonleft", "\xE2\x87\x83", 0 }, { "downharpoonright", "\xE2\x87\x82", 0 }, { "drbkarow", "\xE2\xA4\x90", 0 }, { "drcorn", "\xE2\x8C\x9F", 0 }, { "drcrop", "\xE2\x8C\x8C", 0 }, { "dscr", "\xF0\x9D\x92\xB9", 0 }, { "dscy", "\xD1\x95", 0 }, { "dsol", "\xE2\xA7\xB6", 0 }, { "dstrok", "\xC4\x91", 0 }, { "dtdot", "\xE2\x8B\xB1", 0 }, { "dtri", "\xE2\x96\xBF", 0 }, { "dtrif", "\xE2\x96\xBE", 0 }, { "duarr", "\xE2\x87\xB5", 0 }, { "duhar", "\xE2\xA5\xAF", 0 }, { "dwangle", "\xE2\xA6\xA6", 0 }, { "dzcy", "\xD1\x9F", 0 }, { "dzigrarr", "\xE2\x9F\xBF", 0 }, { "eDDot", "\xE2\xA9\xB7", 0 }, { "eDot", "\xE2\x89\x91", 0 }, { "eacute", "\xC3\xA9", 0 }, { "easter", "\xE2\xA9\xAE", 0 }, { "ecaron", "\xC4\x9B", 0 }, { "ecir", "\xE2\x89\x96", 0 }, { "ecirc", "\xC3\xAA", 0 }, { "ecolon", "\xE2\x89\x95", 0 }, { "ecy", "\xD1\x8D", 0 }, { "edot", "\xC4\x97", 0 }, { "ee", "\xE2\x85\x87", 0 }, { "efDot", "\xE2\x89\x92", 0 }, { "efr", "\xF0\x9D\x94\xA2", 0 }, { "eg", "\xE2\xAA\x9A", 0 }, { "egrave", "\xC3\xA8", 0 }, { "egs", "\xE2\xAA\x96", 0 }, { "egsdot", "\xE2\xAA\x98", 0 }, { "el", "\xE2\xAA\x99", 0 }, { "elinters", "\xE2\x8F\xA7", 0 }, { "ell", "\xE2\x84\x93", 0 }, { "els", "\xE2\xAA\x95", 0 }, { "elsdot", "\xE2\xAA\x97", 0 }, { "emacr", "\xC4\x93", 0 }, { "empty", "\xE2\x88\x85", 0 }, { "emptyset", "\xE2\x88\x85", 0 }, { "emptyv", "\xE2\x88\x85", 0 }, { "emsp", "\xE2\x80\x83", 0 }, { "emsp13", "\xE2\x80\x84", 0 }, { "emsp14", "\xE2\x80\x85", 0 }, { "eng", "\xC5\x8B", 0 }, { "ensp", "\xE2\x80\x82", 0 }, { "eogon", "\xC4\x99", 0 }, { "eopf", "\xF0\x9D\x95\x96", 0 }, { "epar", "\xE2\x8B\x95", 0 }, { "eparsl", "\xE2\xA7\xA3", 0 }, { "eplus", "\xE2\xA9\xB1", 0 }, { "epsi", "\xCE\xB5", 0 }, { "epsilon", "\xCE\xB5", 0 }, { "epsiv", "\xCF\xB5", 0 }, { "eqcirc", "\xE2\x89\x96", 0 }, { "eqcolon", "\xE2\x89\x95", 0 }, { "eqsim", "\xE2\x89\x82", 0 }, { "eqslantgtr", "\xE2\xAA\x96", 0 }, { "eqslantless", "\xE2\xAA\x95", 0 }, { "equals", "\x3D", 0 }, { "equest", "\xE2\x89\x9F", 0 }, { "equiv", "\xE2\x89\xA1", 0 }, { "equivDD", "\xE2\xA9\xB8", 0 }, { "eqvparsl", "\xE2\xA7\xA5", 0 }, { "erDot", "\xE2\x89\x93", 0 }, { "erarr", "\xE2\xA5\xB1", 0 }, { "escr", "\xE2\x84\xAF", 0 }, { "esdot", "\xE2\x89\x90", 0 }, { "esim", "\xE2\x89\x82", 0 }, { "eta", "\xCE\xB7", 0 }, { "eth", "\xC3\xB0", 0 }, { "euml", "\xC3\xAB", 0 }, { "euro", "\xE2\x82\xAC", 0 }, { "excl", "\x21", 0 }, { "exist", "\xE2\x88\x83", 0 }, { "expectation", "\xE2\x84\xB0", 0 }, { "exponentiale", "\xE2\x85\x87", 0 }, { "fallingdotseq", "\xE2\x89\x92", 0 }, { "fcy", "\xD1\x84", 0 }, { "female", "\xE2\x99\x80", 0 }, { "ffilig", "\xEF\xAC\x83", 0 }, { "fflig", "\xEF\xAC\x80", 0 }, { "ffllig", "\xEF\xAC\x84", 0 }, { "ffr", "\xF0\x9D\x94\xA3", 0 }, { "filig", "\xEF\xAC\x81", 0 }, { "fjlig", "\x66\x6A", 0 }, { "flat", "\xE2\x99\xAD", 0 }, { "fllig", "\xEF\xAC\x82", 0 }, { "fltns", "\xE2\x96\xB1", 0 }, { "fnof", "\xC6\x92", 0 }, { "fopf", "\xF0\x9D\x95\x97", 0 }, { "forall", "\xE2\x88\x80", 0 }, { "fork", "\xE2\x8B\x94", 0 }, { "forkv", "\xE2\xAB\x99", 0 }, { "fpartint", "\xE2\xA8\x8D", 0 }, { "frac12", "\xC2\xBD", 0 }, { "frac13", "\xE2\x85\x93", 0 }, { "frac14", "\xC2\xBC", 0 }, { "frac15", "\xE2\x85\x95", 0 }, { "frac16", "\xE2\x85\x99", 0 }, { "frac18", "\xE2\x85\x9B", 0 }, { "frac23", "\xE2\x85\x94", 0 }, { "frac25", "\xE2\x85\x96", 0 }, { "frac34", "\xC2\xBE", 0 }, { "frac35", "\xE2\x85\x97", 0 }, { "frac38", "\xE2\x85\x9C", 0 }, { "frac45", "\xE2\x85\x98", 0 }, { "frac56", "\xE2\x85\x9A", 0 }, { "frac58", "\xE2\x85\x9D", 0 }, { "frac78", "\xE2\x85\x9E", 0 }, { "frasl", "\xE2\x81\x84", 0 }, { "frown", "\xE2\x8C\xA2", 0 }, { "fscr", "\xF0\x9D\x92\xBB", 0 }, { "gE", "\xE2\x89\xA7", 0 }, { "gEl", "\xE2\xAA\x8C", 0 }, { "gacute", "\xC7\xB5", 0 }, { "gamma", "\xCE\xB3", 0 }, { "gammad", "\xCF\x9D", 0 }, { "gap", "\xE2\xAA\x86", 0 }, { "gbreve", "\xC4\x9F", 0 }, { "gcirc", "\xC4\x9D", 0 }, { "gcy", "\xD0\xB3", 0 }, { "gdot", "\xC4\xA1", 0 }, { "ge", "\xE2\x89\xA5", 0 }, { "gel", "\xE2\x8B\x9B", 0 }, { "geq", "\xE2\x89\xA5", 0 }, { "geqq", "\xE2\x89\xA7", 0 }, { "geqslant", "\xE2\xA9\xBE", 0 }, { "ges", "\xE2\xA9\xBE", 0 }, { "gescc", "\xE2\xAA\xA9", 0 }, { "gesdot", "\xE2\xAA\x80", 0 }, { "gesdoto", "\xE2\xAA\x82", 0 }, { "gesdotol", "\xE2\xAA\x84", 0 }, { "gesl", "\xE2\x8B\x9B\xEF\xB8\x80", 0 }, { "gesles", "\xE2\xAA\x94", 0 }, { "gfr", "\xF0\x9D\x94\xA4", 0 }, { "gg", "\xE2\x89\xAB", 0 }, { "ggg", "\xE2\x8B\x99", 0 }, { "gimel", "\xE2\x84\xB7", 0 }, { "gjcy", "\xD1\x93", 0 }, { "gl", "\xE2\x89\xB7", 0 }, { "glE", "\xE2\xAA\x92", 0 }, { "gla", "\xE2\xAA\xA5", 0 }, { "glj", "\xE2\xAA\xA4", 0 }, { "gnE", "\xE2\x89\xA9", 0 }, { "gnap", "\xE2\xAA\x8A", 0 }, { "gnapprox", "\xE2\xAA\x8A", 0 }, { "gne", "\xE2\xAA\x88", 0 }, { "gneq", "\xE2\xAA\x88", 0 }, { "gneqq", "\xE2\x89\xA9", 0 }, { "gnsim", "\xE2\x8B\xA7", 0 }, { "gopf", "\xF0\x9D\x95\x98", 0 }, { "grave", "\x60", 0 }, { "gscr", "\xE2\x84\x8A", 0 }, { "gsim", "\xE2\x89\xB3", 0 }, { "gsime", "\xE2\xAA\x8E", 0 }, { "gsiml", "\xE2\xAA\x90", 0 }, { "gt", "\x3E", 0 }, { "gtcc", "\xE2\xAA\xA7", 0 }, { "gtcir", "\xE2\xA9\xBA", 0 }, { "gtdot", "\xE2\x8B\x97", 0 }, { "gtlPar", "\xE2\xA6\x95", 0 }, { "gtquest", "\xE2\xA9\xBC", 0 }, { "gtrapprox", "\xE2\xAA\x86", 0 }, { "gtrarr", "\xE2\xA5\xB8", 0 }, { "gtrdot", "\xE2\x8B\x97", 0 }, { "gtreqless", "\xE2\x8B\x9B", 0 }, { "gtreqqless", "\xE2\xAA\x8C", 0 }, { "gtrless", "\xE2\x89\xB7", 0 }, { "gtrsim", "\xE2\x89\xB3", 0 }, { "gvertneqq", "\xE2\x89\xA9\xEF\xB8\x80", 0 }, { "gvnE", "\xE2\x89\xA9\xEF\xB8\x80", 0 }, { "hArr", "\xE2\x87\x94", 0 }, { "hairsp", "\xE2\x80\x8A", 0 }, { "half", "\xC2\xBD", 0 }, { "hamilt", "\xE2\x84\x8B", 0 }, { "hardcy", "\xD1\x8A", 0 }, { "harr", "\xE2\x86\x94", 0 }, { "harrcir", "\xE2\xA5\x88", 0 }, { "harrw", "\xE2\x86\xAD", 0 }, { "hbar", "\xE2\x84\x8F", 0 }, { "hcirc", "\xC4\xA5", 0 }, { "hearts", "\xE2\x99\xA5", 0 }, { "heartsuit", "\xE2\x99\xA5", 0 }, { "hellip", "\xE2\x80\xA6", 0 }, { "hercon", "\xE2\x8A\xB9", 0 }, { "hfr", "\xF0\x9D\x94\xA5", 0 }, { "hksearow", "\xE2\xA4\xA5", 0 }, { "hkswarow", "\xE2\xA4\xA6", 0 }, { "hoarr", "\xE2\x87\xBF", 0 }, { "homtht", "\xE2\x88\xBB", 0 }, { "hookleftarrow", "\xE2\x86\xA9", 0 }, { "hookrightarrow", "\xE2\x86\xAA", 0 }, { "hopf", "\xF0\x9D\x95\x99", 0 }, { "horbar", "\xE2\x80\x95", 0 }, { "hscr", "\xF0\x9D\x92\xBD", 0 }, { "hslash", "\xE2\x84\x8F", 0 }, { "hstrok", "\xC4\xA7", 0 }, { "hybull", "\xE2\x81\x83", 0 }, { "hyphen", "\xE2\x80\x90", 0 }, { "iacute", "\xC3\xAD", 0 }, { "ic", "\xE2\x81\xA3", 0 }, { "icirc", "\xC3\xAE", 0 }, { "icy", "\xD0\xB8", 0 }, { "iecy", "\xD0\xB5", 0 }, { "iexcl", "\xC2\xA1", 0 }, { "iff", "\xE2\x87\x94", 0 }, { "ifr", "\xF0\x9D\x94\xA6", 0 }, { "igrave", "\xC3\xAC", 0 }, { "ii", "\xE2\x85\x88", 0 }, { "iiiint", "\xE2\xA8\x8C", 0 }, { "iiint", "\xE2\x88\xAD", 0 }, { "iinfin", "\xE2\xA7\x9C", 0 }, { "iiota", "\xE2\x84\xA9", 0 }, { "ijlig", "\xC4\xB3", 0 }, { "imacr", "\xC4\xAB", 0 }, { "image", "\xE2\x84\x91", 0 }, { "imagline", "\xE2\x84\x90", 0 }, { "imagpart", "\xE2\x84\x91", 0 }, { "imath", "\xC4\xB1", 0 }, { "imof", "\xE2\x8A\xB7", 0 }, { "imped", "\xC6\xB5", 0 }, { "in", "\xE2\x88\x88", 0 }, { "incare", "\xE2\x84\x85", 0 }, { "infin", "\xE2\x88\x9E", 0 }, { "infintie", "\xE2\xA7\x9D", 0 }, { "inodot", "\xC4\xB1", 0 }, { "int", "\xE2\x88\xAB", 0 }, { "intcal", "\xE2\x8A\xBA", 0 }, { "integers", "\xE2\x84\xA4", 0 }, { "intercal", "\xE2\x8A\xBA", 0 }, { "intlarhk", "\xE2\xA8\x97", 0 }, { "intprod", "\xE2\xA8\xBC", 0 }, { "iocy", "\xD1\x91", 0 }, { "iogon", "\xC4\xAF", 0 }, { "iopf", "\xF0\x9D\x95\x9A", 0 }, { "iota", "\xCE\xB9", 0 }, { "iprod", "\xE2\xA8\xBC", 0 }, { "iquest", "\xC2\xBF", 0 }, { "iscr", "\xF0\x9D\x92\xBE", 0 }, { "isin", "\xE2\x88\x88", 0 }, { "isinE", "\xE2\x8B\xB9", 0 }, { "isindot", "\xE2\x8B\xB5", 0 }, { "isins", "\xE2\x8B\xB4", 0 }, { "isinsv", "\xE2\x8B\xB3", 0 }, { "isinv", "\xE2\x88\x88", 0 }, { "it", "\xE2\x81\xA2", 0 }, { "itilde", "\xC4\xA9", 0 }, { "iukcy", "\xD1\x96", 0 }, { "iuml", "\xC3\xAF", 0 }, { "jcirc", "\xC4\xB5", 0 }, { "jcy", "\xD0\xB9", 0 }, { "jfr", "\xF0\x9D\x94\xA7", 0 }, { "jmath", "\xC8\xB7", 0 }, { "jopf", "\xF0\x9D\x95\x9B", 0 }, { "jscr", "\xF0\x9D\x92\xBF", 0 }, { "jsercy", "\xD1\x98", 0 }, { "jukcy", "\xD1\x94", 0 }, { "kappa", "\xCE\xBA", 0 }, { "kappav", "\xCF\xB0", 0 }, { "kcedil", "\xC4\xB7", 0 }, { "kcy", "\xD0\xBA", 0 }, { "kfr", "\xF0\x9D\x94\xA8", 0 }, { "kgreen", "\xC4\xB8", 0 }, { "khcy", "\xD1\x85", 0 }, { "kjcy", "\xD1\x9C", 0 }, { "kopf", "\xF0\x9D\x95\x9C", 0 }, { "kscr", "\xF0\x9D\x93\x80", 0 }, { "lAarr", "\xE2\x87\x9A", 0 }, { "lArr", "\xE2\x87\x90", 0 }, { "lAtail", "\xE2\xA4\x9B", 0 }, { "lBarr", "\xE2\xA4\x8E", 0 }, { "lE", "\xE2\x89\xA6", 0 }, { "lEg", "\xE2\xAA\x8B", 0 }, { "lHar", "\xE2\xA5\xA2", 0 }, { "lacute", "\xC4\xBA", 0 }, { "laemptyv", "\xE2\xA6\xB4", 0 }, { "lagran", "\xE2\x84\x92", 0 }, { "lambda", "\xCE\xBB", 0 }, { "lang", "\xE2\x9F\xA8", 0 }, { "langd", "\xE2\xA6\x91", 0 }, { "langle", "\xE2\x9F\xA8", 0 }, { "lap", "\xE2\xAA\x85", 0 }, { "laquo", "\xC2\xAB", 0 }, { "larr", "\xE2\x86\x90", 0 }, { "larrb", "\xE2\x87\xA4", 0 }, { "larrbfs", "\xE2\xA4\x9F", 0 }, { "larrfs", "\xE2\xA4\x9D", 0 }, { "larrhk", "\xE2\x86\xA9", 0 }, { "larrlp", "\xE2\x86\xAB", 0 }, { "larrpl", "\xE2\xA4\xB9", 0 }, { "larrsim", "\xE2\xA5\xB3", 0 }, { "larrtl", "\xE2\x86\xA2", 0 }, { "lat", "\xE2\xAA\xAB", 0 }, { "latail", "\xE2\xA4\x99", 0 }, { "late", "\xE2\xAA\xAD", 0 }, { "lates", "\xE2\xAA\xAD\xEF\xB8\x80", 0 }, { "lbarr", "\xE2\xA4\x8C", 0 }, { "lbbrk", "\xE2\x9D\xB2", 0 }, { "lbrace", "\x7B", 0 }, { "lbrack", "\x5B", 0 }, { "lbrke", "\xE2\xA6\x8B", 0 }, { "lbrksld", "\xE2\xA6\x8F", 0 }, { "lbrkslu", "\xE2\xA6\x8D", 0 }, { "lcaron", "\xC4\xBE", 0 }, { "lcedil", "\xC4\xBC", 0 }, { "lceil", "\xE2\x8C\x88", 0 }, { "lcub", "\x7B", 0 }, { "lcy", "\xD0\xBB", 0 }, { "ldca", "\xE2\xA4\xB6", 0 }, { "ldquo", "\xE2\x80\x9C", 0 }, { "ldquor", "\xE2\x80\x9E", 0 }, { "ldrdhar", "\xE2\xA5\xA7", 0 }, { "ldrushar", "\xE2\xA5\x8B", 0 }, { "ldsh", "\xE2\x86\xB2", 0 }, { "le", "\xE2\x89\xA4", 0 }, { "leftarrow", "\xE2\x86\x90", 0 }, { "leftarrowtail", "\xE2\x86\xA2", 0 }, { "leftharpoondown", "\xE2\x86\xBD", 0 }, { "leftharpoonup", "\xE2\x86\xBC", 0 }, { "leftleftarrows", "\xE2\x87\x87", 0 }, { "leftrightarrow", "\xE2\x86\x94", 0 }, { "leftrightarrows", "\xE2\x87\x86", 0 }, { "leftrightharpoons", "\xE2\x87\x8B", 0 }, { "leftrightsquigarrow", "\xE2\x86\xAD", 0 }, { "leftthreetimes", "\xE2\x8B\x8B", 0 }, { "leg", "\xE2\x8B\x9A", 0 }, { "leq", "\xE2\x89\xA4", 0 }, { "leqq", "\xE2\x89\xA6", 0 }, { "leqslant", "\xE2\xA9\xBD", 0 }, { "les", "\xE2\xA9\xBD", 0 }, { "lescc", "\xE2\xAA\xA8", 0 }, { "lesdot", "\xE2\xA9\xBF", 0 }, { "lesdoto", "\xE2\xAA\x81", 0 }, { "lesdotor", "\xE2\xAA\x83", 0 }, { "lesg", "\xE2\x8B\x9A\xEF\xB8\x80", 0 }, { "lesges", "\xE2\xAA\x93", 0 }, { "lessapprox", "\xE2\xAA\x85", 0 }, { "lessdot", "\xE2\x8B\x96", 0 }, { "lesseqgtr", "\xE2\x8B\x9A", 0 }, { "lesseqqgtr", "\xE2\xAA\x8B", 0 }, { "lessgtr", "\xE2\x89\xB6", 0 }, { "lesssim", "\xE2\x89\xB2", 0 }, { "lfisht", "\xE2\xA5\xBC", 0 }, { "lfloor", "\xE2\x8C\x8A", 0 }, { "lfr", "\xF0\x9D\x94\xA9", 0 }, { "lg", "\xE2\x89\xB6", 0 }, { "lgE", "\xE2\xAA\x91", 0 }, { "lhard", "\xE2\x86\xBD", 0 }, { "lharu", "\xE2\x86\xBC", 0 }, { "lharul", "\xE2\xA5\xAA", 0 }, { "lhblk", "\xE2\x96\x84", 0 }, { "ljcy", "\xD1\x99", 0 }, { "ll", "\xE2\x89\xAA", 0 }, { "llarr", "\xE2\x87\x87", 0 }, { "llcorner", "\xE2\x8C\x9E", 0 }, { "llhard", "\xE2\xA5\xAB", 0 }, { "lltri", "\xE2\x97\xBA", 0 }, { "lmidot", "\xC5\x80", 0 }, { "lmoust", "\xE2\x8E\xB0", 0 }, { "lmoustache", "\xE2\x8E\xB0", 0 }, { "lnE", "\xE2\x89\xA8", 0 }, { "lnap", "\xE2\xAA\x89", 0 }, { "lnapprox", "\xE2\xAA\x89", 0 }, { "lne", "\xE2\xAA\x87", 0 }, { "lneq", "\xE2\xAA\x87", 0 }, { "lneqq", "\xE2\x89\xA8", 0 }, { "lnsim", "\xE2\x8B\xA6", 0 }, { "loang", "\xE2\x9F\xAC", 0 }, { "loarr", "\xE2\x87\xBD", 0 }, { "lobrk", "\xE2\x9F\xA6", 0 }, { "longleftarrow", "\xE2\x9F\xB5", 0 }, { "longleftrightarrow", "\xE2\x9F\xB7", 0 }, { "longmapsto", "\xE2\x9F\xBC", 0 }, { "longrightarrow", "\xE2\x9F\xB6", 0 }, { "looparrowleft", "\xE2\x86\xAB", 0 }, { "looparrowright", "\xE2\x86\xAC", 0 }, { "lopar", "\xE2\xA6\x85", 0 }, { "lopf", "\xF0\x9D\x95\x9D", 0 }, { "loplus", "\xE2\xA8\xAD", 0 }, { "lotimes", "\xE2\xA8\xB4", 0 }, { "lowast", "\xE2\x88\x97", 0 }, { "lowbar", "\x5F", 0 }, { "loz", "\xE2\x97\x8A", 0 }, { "lozenge", "\xE2\x97\x8A", 0 }, { "lozf", "\xE2\xA7\xAB", 0 }, { "lpar", "\x28", 0 }, { "lparlt", "\xE2\xA6\x93", 0 }, { "lrarr", "\xE2\x87\x86", 0 }, { "lrcorner", "\xE2\x8C\x9F", 0 }, { "lrhar", "\xE2\x87\x8B", 0 }, { "lrhard", "\xE2\xA5\xAD", 0 }, { "lrm", "\xE2\x80\x8E", 0 }, { "lrtri", "\xE2\x8A\xBF", 0 }, { "lsaquo", "\xE2\x80\xB9", 0 }, { "lscr", "\xF0\x9D\x93\x81", 0 }, { "lsh", "\xE2\x86\xB0", 0 }, { "lsim", "\xE2\x89\xB2", 0 }, { "lsime", "\xE2\xAA\x8D", 0 }, { "lsimg", "\xE2\xAA\x8F", 0 }, { "lsqb", "\x5B", 0 }, { "lsquo", "\xE2\x80\x98", 0 }, { "lsquor", "\xE2\x80\x9A", 0 }, { "lstrok", "\xC5\x82", 0 }, { "lt", "\x3C", 0 }, { "ltcc", "\xE2\xAA\xA6", 0 }, { "ltcir", "\xE2\xA9\xB9", 0 }, { "ltdot", "\xE2\x8B\x96", 0 }, { "lthree", "\xE2\x8B\x8B", 0 }, { "ltimes", "\xE2\x8B\x89", 0 }, { "ltlarr", "\xE2\xA5\xB6", 0 }, { "ltquest", "\xE2\xA9\xBB", 0 }, { "ltrPar", "\xE2\xA6\x96", 0 }, { "ltri", "\xE2\x97\x83", 0 }, { "ltrie", "\xE2\x8A\xB4", 0 }, { "ltrif", "\xE2\x97\x82", 0 }, { "lurdshar", "\xE2\xA5\x8A", 0 }, { "luruhar", "\xE2\xA5\xA6", 0 }, { "lvertneqq", "\xE2\x89\xA8\xEF\xB8\x80", 0 }, { "lvnE", "\xE2\x89\xA8\xEF\xB8\x80", 0 }, { "mDDot", "\xE2\x88\xBA", 0 }, { "macr", "\xC2\xAF", 0 }, { "male", "\xE2\x99\x82", 0 }, { "malt", "\xE2\x9C\xA0", 0 }, { "maltese", "\xE2\x9C\xA0", 0 }, { "map", "\xE2\x86\xA6", 0 }, { "mapsto", "\xE2\x86\xA6", 0 }, { "mapstodown", "\xE2\x86\xA7", 0 }, { "mapstoleft", "\xE2\x86\xA4", 0 }, { "mapstoup", "\xE2\x86\xA5", 0 }, { "marker", "\xE2\x96\xAE", 0 }, { "mcomma", "\xE2\xA8\xA9", 0 }, { "mcy", "\xD0\xBC", 0 }, { "mdash", "\xE2\x80\x94", 0 }, { "measuredangle", "\xE2\x88\xA1", 0 }, { "mfr", "\xF0\x9D\x94\xAA", 0 }, { "mho", "\xE2\x84\xA7", 0 }, { "micro", "\xC2\xB5", 0 }, { "mid", "\xE2\x88\xA3", 0 }, { "midast", "\x2A", 0 }, { "midcir", "\xE2\xAB\xB0", 0 }, { "middot", "\xC2\xB7", 0 }, { "minus", "\xE2\x88\x92", 0 }, { "minusb", "\xE2\x8A\x9F", 0 }, { "minusd", "\xE2\x88\xB8", 0 }, { "minusdu", "\xE2\xA8\xAA", 0 }, { "mlcp", "\xE2\xAB\x9B", 0 }, { "mldr", "\xE2\x80\xA6", 0 }, { "mnplus", "\xE2\x88\x93", 0 }, { "models", "\xE2\x8A\xA7", 0 }, { "mopf", "\xF0\x9D\x95\x9E", 0 }, { "mp", "\xE2\x88\x93", 0 }, { "mscr", "\xF0\x9D\x93\x82", 0 }, { "mstpos", "\xE2\x88\xBE", 0 }, { "mu", "\xCE\xBC", 0 }, { "multimap", "\xE2\x8A\xB8", 0 }, { "mumap", "\xE2\x8A\xB8", 0 }, { "nGg", "\xE2\x8B\x99\xCC\xB8", 0 }, { "nGtv", "\xE2\x89\xAB\xCC\xB8", 0 }, { "nLeftarrow", "\xE2\x87\x8D", 0 }, { "nLeftrightarrow", "\xE2\x87\x8E", 0 }, { "nLl", "\xE2\x8B\x98\xCC\xB8", 0 }, { "nLtv", "\xE2\x89\xAA\xCC\xB8", 0 }, { "nRightarrow", "\xE2\x87\x8F", 0 }, { "nVDash", "\xE2\x8A\xAF", 0 }, { "nVdash", "\xE2\x8A\xAE", 0 }, { "nabla", "\xE2\x88\x87", 0 }, { "nacute", "\xC5\x84", 0 }, { "nang", "\xE2\x88\xA0\xE2\x83\x92", 0 }, { "nap", "\xE2\x89\x89", 0 }, { "napE", "\xE2\xA9\xB0\xCC\xB8", 0 }, { "napid", "\xE2\x89\x8B\xCC\xB8", 0 }, { "napos", "\xC5\x89", 0 }, { "napprox", "\xE2\x89\x89", 0 }, { "natur", "\xE2\x99\xAE", 0 }, { "natural", "\xE2\x99\xAE", 0 }, { "naturals", "\xE2\x84\x95", 0 }, { "nbsp", "\xC2\xA0", 0 }, { "nbump", "\xE2\x89\x8E\xCC\xB8", 0 }, { "nbumpe", "\xE2\x89\x8F\xCC\xB8", 0 }, { "ncap", "\xE2\xA9\x83", 0 }, { "ncaron", "\xC5\x88", 0 }, { "ncedil", "\xC5\x86", 0 }, { "ncong", "\xE2\x89\x87", 0 }, { "ncongdot", "\xE2\xA9\xAD\xCC\xB8", 0 }, { "ncup", "\xE2\xA9\x82", 0 }, { "ncy", "\xD0\xBD", 0 }, { "ndash", "\xE2\x80\x93", 0 }, { "ne", "\xE2\x89\xA0", 0 }, { "neArr", "\xE2\x87\x97", 0 }, { "nearhk", "\xE2\xA4\xA4", 0 }, { "nearr", "\xE2\x86\x97", 0 }, { "nearrow", "\xE2\x86\x97", 0 }, { "nedot", "\xE2\x89\x90\xCC\xB8", 0 }, { "nequiv", "\xE2\x89\xA2", 0 }, { "nesear", "\xE2\xA4\xA8", 0 }, { "nesim", "\xE2\x89\x82\xCC\xB8", 0 }, { "nexist", "\xE2\x88\x84", 0 }, { "nexists", "\xE2\x88\x84", 0 }, { "nfr", "\xF0\x9D\x94\xAB", 0 }, { "ngE", "\xE2\x89\xA7\xCC\xB8", 0 }, { "nge", "\xE2\x89\xB1", 0 }, { "ngeq", "\xE2\x89\xB1", 0 }, { "ngeqq", "\xE2\x89\xA7\xCC\xB8", 0 }, { "ngeqslant", "\xE2\xA9\xBE\xCC\xB8", 0 }, { "nges", "\xE2\xA9\xBE\xCC\xB8", 0 }, { "ngsim", "\xE2\x89\xB5", 0 }, { "ngt", "\xE2\x89\xAF", 0 }, { "ngtr", "\xE2\x89\xAF", 0 }, { "nhArr", "\xE2\x87\x8E", 0 }, { "nharr", "\xE2\x86\xAE", 0 }, { "nhpar", "\xE2\xAB\xB2", 0 }, { "ni", "\xE2\x88\x8B", 0 }, { "nis", "\xE2\x8B\xBC", 0 }, { "nisd", "\xE2\x8B\xBA", 0 }, { "niv", "\xE2\x88\x8B", 0 }, { "njcy", "\xD1\x9A", 0 }, { "nlArr", "\xE2\x87\x8D", 0 }, { "nlE", "\xE2\x89\xA6\xCC\xB8", 0 }, { "nlarr", "\xE2\x86\x9A", 0 }, { "nldr", "\xE2\x80\xA5", 0 }, { "nle", "\xE2\x89\xB0", 0 }, { "nleftarrow", "\xE2\x86\x9A", 0 }, { "nleftrightarrow", "\xE2\x86\xAE", 0 }, { "nleq", "\xE2\x89\xB0", 0 }, { "nleqq", "\xE2\x89\xA6\xCC\xB8", 0 }, { "nleqslant", "\xE2\xA9\xBD\xCC\xB8", 0 }, { "nles", "\xE2\xA9\xBD\xCC\xB8", 0 }, { "nless", "\xE2\x89\xAE", 0 }, { "nlsim", "\xE2\x89\xB4", 0 }, { "nlt", "\xE2\x89\xAE", 0 }, { "nltri", "\xE2\x8B\xAA", 0 }, { "nltrie", "\xE2\x8B\xAC", 0 }, { "nmid", "\xE2\x88\xA4", 0 }, { "nopf", "\xF0\x9D\x95\x9F", 0 }, { "not", "\xC2\xAC", 0 }, { "notin", "\xE2\x88\x89", 0 }, { "notinE", "\xE2\x8B\xB9\xCC\xB8", 0 }, { "notindot", "\xE2\x8B\xB5\xCC\xB8", 0 }, { "notinva", "\xE2\x88\x89", 0 }, { "notinvb", "\xE2\x8B\xB7", 0 }, { "notinvc", "\xE2\x8B\xB6", 0 }, { "notni", "\xE2\x88\x8C", 0 }, { "notniva", "\xE2\x88\x8C", 0 }, { "notnivb", "\xE2\x8B\xBE", 0 }, { "notnivc", "\xE2\x8B\xBD", 0 }, { "npar", "\xE2\x88\xA6", 0 }, { "nparallel", "\xE2\x88\xA6", 0 }, { "nparsl", "\xE2\xAB\xBD\xE2\x83\xA5", 0 }, { "npart", "\xE2\x88\x82\xCC\xB8", 0 }, { "npolint", "\xE2\xA8\x94", 0 }, { "npr", "\xE2\x8A\x80", 0 }, { "nprcue", "\xE2\x8B\xA0", 0 }, { "npre", "\xE2\xAA\xAF\xCC\xB8", 0 }, { "nprec", "\xE2\x8A\x80", 0 }, { "npreceq", "\xE2\xAA\xAF\xCC\xB8", 0 }, { "nrArr", "\xE2\x87\x8F", 0 }, { "nrarr", "\xE2\x86\x9B", 0 }, { "nrarrc", "\xE2\xA4\xB3\xCC\xB8", 0 }, { "nrarrw", "\xE2\x86\x9D\xCC\xB8", 0 }, { "nrightarrow", "\xE2\x86\x9B", 0 }, { "nrtri", "\xE2\x8B\xAB", 0 }, { "nrtrie", "\xE2\x8B\xAD", 0 }, { "nsc", "\xE2\x8A\x81", 0 }, { "nsccue", "\xE2\x8B\xA1", 0 }, { "nsce", "\xE2\xAA\xB0\xCC\xB8", 0 }, { "nscr", "\xF0\x9D\x93\x83", 0 }, { "nshortmid", "\xE2\x88\xA4", 0 }, { "nshortparallel", "\xE2\x88\xA6", 0 }, { "nsim", "\xE2\x89\x81", 0 }, { "nsime", "\xE2\x89\x84", 0 }, { "nsimeq", "\xE2\x89\x84", 0 }, { "nsmid", "\xE2\x88\xA4", 0 }, { "nspar", "\xE2\x88\xA6", 0 }, { "nsqsube", "\xE2\x8B\xA2", 0 }, { "nsqsupe", "\xE2\x8B\xA3", 0 }, { "nsub", "\xE2\x8A\x84", 0 }, { "nsubE", "\xE2\xAB\x85\xCC\xB8", 0 }, { "nsube", "\xE2\x8A\x88", 0 }, { "nsubset", "\xE2\x8A\x82\xE2\x83\x92", 0 }, { "nsubseteq", "\xE2\x8A\x88", 0 }, { "nsubseteqq", "\xE2\xAB\x85\xCC\xB8", 0 }, { "nsucc", "\xE2\x8A\x81", 0 }, { "nsucceq", "\xE2\xAA\xB0\xCC\xB8", 0 }, { "nsup", "\xE2\x8A\x85", 0 }, { "nsupE", "\xE2\xAB\x86\xCC\xB8", 0 }, { "nsupe", "\xE2\x8A\x89", 0 }, { "nsupset", "\xE2\x8A\x83\xE2\x83\x92", 0 }, { "nsupseteq", "\xE2\x8A\x89", 0 }, { "nsupseteqq", "\xE2\xAB\x86\xCC\xB8", 0 }, { "ntgl", "\xE2\x89\xB9", 0 }, { "ntilde", "\xC3\xB1", 0 }, { "ntlg", "\xE2\x89\xB8", 0 }, { "ntriangleleft", "\xE2\x8B\xAA", 0 }, { "ntrianglelefteq", "\xE2\x8B\xAC", 0 }, { "ntriangleright", "\xE2\x8B\xAB", 0 }, { "ntrianglerighteq", "\xE2\x8B\xAD", 0 }, { "nu", "\xCE\xBD", 0 }, { "num", "\x23", 0 }, { "numero", "\xE2\x84\x96", 0 }, { "numsp", "\xE2\x80\x87", 0 }, { "nvDash", "\xE2\x8A\xAD", 0 }, { "nvHarr", "\xE2\xA4\x84", 0 }, { "nvap", "\xE2\x89\x8D\xE2\x83\x92", 0 }, { "nvdash", "\xE2\x8A\xAC", 0 }, { "nvge", "\xE2\x89\xA5\xE2\x83\x92", 0 }, { "nvgt", "\x3E\xE2\x83\x92", 0 }, { "nvinfin", "\xE2\xA7\x9E", 0 }, { "nvlArr", "\xE2\xA4\x82", 0 }, { "nvle", "\xE2\x89\xA4\xE2\x83\x92", 0 }, { "nvlt", "\x3C\xE2\x83\x92", 0 }, { "nvltrie", "\xE2\x8A\xB4\xE2\x83\x92", 0 }, { "nvrArr", "\xE2\xA4\x83", 0 }, { "nvrtrie", "\xE2\x8A\xB5\xE2\x83\x92", 0 }, { "nvsim", "\xE2\x88\xBC\xE2\x83\x92", 0 }, { "nwArr", "\xE2\x87\x96", 0 }, { "nwarhk", "\xE2\xA4\xA3", 0 }, { "nwarr", "\xE2\x86\x96", 0 }, { "nwarrow", "\xE2\x86\x96", 0 }, { "nwnear", "\xE2\xA4\xA7", 0 }, { "oS", "\xE2\x93\x88", 0 }, { "oacute", "\xC3\xB3", 0 }, { "oast", "\xE2\x8A\x9B", 0 }, { "ocir", "\xE2\x8A\x9A", 0 }, { "ocirc", "\xC3\xB4", 0 }, { "ocy", "\xD0\xBE", 0 }, { "odash", "\xE2\x8A\x9D", 0 }, { "odblac", "\xC5\x91", 0 }, { "odiv", "\xE2\xA8\xB8", 0 }, { "odot", "\xE2\x8A\x99", 0 }, { "odsold", "\xE2\xA6\xBC", 0 }, { "oelig", "\xC5\x93", 0 }, { "ofcir", "\xE2\xA6\xBF", 0 }, { "ofr", "\xF0\x9D\x94\xAC", 0 }, { "ogon", "\xCB\x9B", 0 }, { "ograve", "\xC3\xB2", 0 }, { "ogt", "\xE2\xA7\x81", 0 }, { "ohbar", "\xE2\xA6\xB5", 0 }, { "ohm", "\xCE\xA9", 0 }, { "oint", "\xE2\x88\xAE", 0 }, { "olarr", "\xE2\x86\xBA", 0 }, { "olcir", "\xE2\xA6\xBE", 0 }, { "olcross", "\xE2\xA6\xBB", 0 }, { "oline", "\xE2\x80\xBE", 0 }, { "olt", "\xE2\xA7\x80", 0 }, { "omacr", "\xC5\x8D", 0 }, { "omega", "\xCF\x89", 0 }, { "omicron", "\xCE\xBF", 0 }, { "omid", "\xE2\xA6\xB6", 0 }, { "ominus", "\xE2\x8A\x96", 0 }, { "oopf", "\xF0\x9D\x95\xA0", 0 }, { "opar", "\xE2\xA6\xB7", 0 }, { "operp", "\xE2\xA6\xB9", 0 }, { "oplus", "\xE2\x8A\x95", 0 }, { "or", "\xE2\x88\xA8", 0 }, { "orarr", "\xE2\x86\xBB", 0 }, { "ord", "\xE2\xA9\x9D", 0 }, { "order", "\xE2\x84\xB4", 0 }, { "orderof", "\xE2\x84\xB4", 0 }, { "ordf", "\xC2\xAA", 0 }, { "ordm", "\xC2\xBA", 0 }, { "origof", "\xE2\x8A\xB6", 0 }, { "oror", "\xE2\xA9\x96", 0 }, { "orslope", "\xE2\xA9\x97", 0 }, { "orv", "\xE2\xA9\x9B", 0 }, { "oscr", "\xE2\x84\xB4", 0 }, { "oslash", "\xC3\xB8", 0 }, { "osol", "\xE2\x8A\x98", 0 }, { "otilde", "\xC3\xB5", 0 }, { "otimes", "\xE2\x8A\x97", 0 }, { "otimesas", "\xE2\xA8\xB6", 0 }, { "ouml", "\xC3\xB6", 0 }, { "ovbar", "\xE2\x8C\xBD", 0 }, { "par", "\xE2\x88\xA5", 0 }, { "para", "\xC2\xB6", 0 }, { "parallel", "\xE2\x88\xA5", 0 }, { "parsim", "\xE2\xAB\xB3", 0 }, { "parsl", "\xE2\xAB\xBD", 0 }, { "part", "\xE2\x88\x82", 0 }, { "pcy", "\xD0\xBF", 0 }, { "percnt", "\x25", 0 }, { "period", "\x2E", 0 }, { "permil", "\xE2\x80\xB0", 0 }, { "perp", "\xE2\x8A\xA5", 0 }, { "pertenk", "\xE2\x80\xB1", 0 }, { "pfr", "\xF0\x9D\x94\xAD", 0 }, { "phi", "\xCF\x86", 0 }, { "phiv", "\xCF\x95", 0 }, { "phmmat", "\xE2\x84\xB3", 0 }, { "phone", "\xE2\x98\x8E", 0 }, { "pi", "\xCF\x80", 0 }, { "pitchfork", "\xE2\x8B\x94", 0 }, { "piv", "\xCF\x96", 0 }, { "planck", "\xE2\x84\x8F", 0 }, { "planckh", "\xE2\x84\x8E", 0 }, { "plankv", "\xE2\x84\x8F", 0 }, { "plus", "\x2B", 0 }, { "plusacir", "\xE2\xA8\xA3", 0 }, { "plusb", "\xE2\x8A\x9E", 0 }, { "pluscir", "\xE2\xA8\xA2", 0 }, { "plusdo", "\xE2\x88\x94", 0 }, { "plusdu", "\xE2\xA8\xA5", 0 }, { "pluse", "\xE2\xA9\xB2", 0 }, { "plusmn", "\xC2\xB1", 0 }, { "plussim", "\xE2\xA8\xA6", 0 }, { "plustwo", "\xE2\xA8\xA7", 0 }, { "pm", "\xC2\xB1", 0 }, { "pointint", "\xE2\xA8\x95", 0 }, { "popf", "\xF0\x9D\x95\xA1", 0 }, { "pound", "\xC2\xA3", 0 }, { "pr", "\xE2\x89\xBA", 0 }, { "prE", "\xE2\xAA\xB3", 0 }, { "prap", "\xE2\xAA\xB7", 0 }, { "prcue", "\xE2\x89\xBC", 0 }, { "pre", "\xE2\xAA\xAF", 0 }, { "prec", "\xE2\x89\xBA", 0 }, { "precapprox", "\xE2\xAA\xB7", 0 }, { "preccurlyeq", "\xE2\x89\xBC", 0 }, { "preceq", "\xE2\xAA\xAF", 0 }, { "precnapprox", "\xE2\xAA\xB9", 0 }, { "precneqq", "\xE2\xAA\xB5", 0 }, { "precnsim", "\xE2\x8B\xA8", 0 }, { "precsim", "\xE2\x89\xBE", 0 }, { "prime", "\xE2\x80\xB2", 0 }, { "primes", "\xE2\x84\x99", 0 }, { "prnE", "\xE2\xAA\xB5", 0 }, { "prnap", "\xE2\xAA\xB9", 0 }, { "prnsim", "\xE2\x8B\xA8", 0 }, { "prod", "\xE2\x88\x8F", 0 }, { "profalar", "\xE2\x8C\xAE", 0 }, { "profline", "\xE2\x8C\x92", 0 }, { "profsurf", "\xE2\x8C\x93", 0 }, { "prop", "\xE2\x88\x9D", 0 }, { "propto", "\xE2\x88\x9D", 0 }, { "prsim", "\xE2\x89\xBE", 0 }, { "prurel", "\xE2\x8A\xB0", 0 }, { "pscr", "\xF0\x9D\x93\x85", 0 }, { "psi", "\xCF\x88", 0 }, { "puncsp", "\xE2\x80\x88", 0 }, { "qfr", "\xF0\x9D\x94\xAE", 0 }, { "qint", "\xE2\xA8\x8C", 0 }, { "qopf", "\xF0\x9D\x95\xA2", 0 }, { "qprime", "\xE2\x81\x97", 0 }, { "qscr", "\xF0\x9D\x93\x86", 0 }, { "quaternions", "\xE2\x84\x8D", 0 }, { "quatint", "\xE2\xA8\x96", 0 }, { "quest", "\x3F", 0 }, { "questeq", "\xE2\x89\x9F", 0 }, { "quot", "\x22", 0 }, { "rAarr", "\xE2\x87\x9B", 0 }, { "rArr", "\xE2\x87\x92", 0 }, { "rAtail", "\xE2\xA4\x9C", 0 }, { "rBarr", "\xE2\xA4\x8F", 0 }, { "rHar", "\xE2\xA5\xA4", 0 }, { "race", "\xE2\x88\xBD\xCC\xB1", 0 }, { "racute", "\xC5\x95", 0 }, { "radic", "\xE2\x88\x9A", 0 }, { "raemptyv", "\xE2\xA6\xB3", 0 }, { "rang", "\xE2\x9F\xA9", 0 }, { "rangd", "\xE2\xA6\x92", 0 }, { "range", "\xE2\xA6\xA5", 0 }, { "rangle", "\xE2\x9F\xA9", 0 }, { "raquo", "\xC2\xBB", 0 }, { "rarr", "\xE2\x86\x92", 0 }, { "rarrap", "\xE2\xA5\xB5", 0 }, { "rarrb", "\xE2\x87\xA5", 0 }, { "rarrbfs", "\xE2\xA4\xA0", 0 }, { "rarrc", "\xE2\xA4\xB3", 0 }, { "rarrfs", "\xE2\xA4\x9E", 0 }, { "rarrhk", "\xE2\x86\xAA", 0 }, { "rarrlp", "\xE2\x86\xAC", 0 }, { "rarrpl", "\xE2\xA5\x85", 0 }, { "rarrsim", "\xE2\xA5\xB4", 0 }, { "rarrtl", "\xE2\x86\xA3", 0 }, { "rarrw", "\xE2\x86\x9D", 0 }, { "ratail", "\xE2\xA4\x9A", 0 }, { "ratio", "\xE2\x88\xB6", 0 }, { "rationals", "\xE2\x84\x9A", 0 }, { "rbarr", "\xE2\xA4\x8D", 0 }, { "rbbrk", "\xE2\x9D\xB3", 0 }, { "rbrace", "\x7D", 0 }, { "rbrack", "\x5D", 0 }, { "rbrke", "\xE2\xA6\x8C", 0 }, { "rbrksld", "\xE2\xA6\x8E", 0 }, { "rbrkslu", "\xE2\xA6\x90", 0 }, { "rcaron", "\xC5\x99", 0 }, { "rcedil", "\xC5\x97", 0 }, { "rceil", "\xE2\x8C\x89", 0 }, { "rcub", "\x7D", 0 }, { "rcy", "\xD1\x80", 0 }, { "rdca", "\xE2\xA4\xB7", 0 }, { "rdldhar", "\xE2\xA5\xA9", 0 }, { "rdquo", "\xE2\x80\x9D", 0 }, { "rdquor", "\xE2\x80\x9D", 0 }, { "rdsh", "\xE2\x86\xB3", 0 }, { "real", "\xE2\x84\x9C", 0 }, { "realine", "\xE2\x84\x9B", 0 }, { "realpart", "\xE2\x84\x9C", 0 }, { "reals", "\xE2\x84\x9D", 0 }, { "rect", "\xE2\x96\xAD", 0 }, { "reg", "\xC2\xAE", 0 }, { "rfisht", "\xE2\xA5\xBD", 0 }, { "rfloor", "\xE2\x8C\x8B", 0 }, { "rfr", "\xF0\x9D\x94\xAF", 0 }, { "rhard", "\xE2\x87\x81", 0 }, { "rharu", "\xE2\x87\x80", 0 }, { "rharul", "\xE2\xA5\xAC", 0 }, { "rho", "\xCF\x81", 0 }, { "rhov", "\xCF\xB1", 0 }, { "rightarrow", "\xE2\x86\x92", 0 }, { "rightarrowtail", "\xE2\x86\xA3", 0 }, { "rightharpoondown", "\xE2\x87\x81", 0 }, { "rightharpoonup", "\xE2\x87\x80", 0 }, { "rightleftarrows", "\xE2\x87\x84", 0 }, { "rightleftharpoons", "\xE2\x87\x8C", 0 }, { "rightrightarrows", "\xE2\x87\x89", 0 }, { "rightsquigarrow", "\xE2\x86\x9D", 0 }, { "rightthreetimes", "\xE2\x8B\x8C", 0 }, { "ring", "\xCB\x9A", 0 }, { "risingdotseq", "\xE2\x89\x93", 0 }, { "rlarr", "\xE2\x87\x84", 0 }, { "rlhar", "\xE2\x87\x8C", 0 }, { "rlm", "\xE2\x80\x8F", 0 }, { "rmoust", "\xE2\x8E\xB1", 0 }, { "rmoustache", "\xE2\x8E\xB1", 0 }, { "rnmid", "\xE2\xAB\xAE", 0 }, { "roang", "\xE2\x9F\xAD", 0 }, { "roarr", "\xE2\x87\xBE", 0 }, { "robrk", "\xE2\x9F\xA7", 0 }, { "ropar", "\xE2\xA6\x86", 0 }, { "ropf", "\xF0\x9D\x95\xA3", 0 }, { "roplus", "\xE2\xA8\xAE", 0 }, { "rotimes", "\xE2\xA8\xB5", 0 }, { "rpar", "\x29", 0 }, { "rpargt", "\xE2\xA6\x94", 0 }, { "rppolint", "\xE2\xA8\x92", 0 }, { "rrarr", "\xE2\x87\x89", 0 }, { "rsaquo", "\xE2\x80\xBA", 0 }, { "rscr", "\xF0\x9D\x93\x87", 0 }, { "rsh", "\xE2\x86\xB1", 0 }, { "rsqb", "\x5D", 0 }, { "rsquo", "\xE2\x80\x99", 0 }, { "rsquor", "\xE2\x80\x99", 0 }, { "rthree", "\xE2\x8B\x8C", 0 }, { "rtimes", "\xE2\x8B\x8A", 0 }, { "rtri", "\xE2\x96\xB9", 0 }, { "rtrie", "\xE2\x8A\xB5", 0 }, { "rtrif", "\xE2\x96\xB8", 0 }, { "rtriltri", "\xE2\xA7\x8E", 0 }, { "ruluhar", "\xE2\xA5\xA8", 0 }, { "rx", "\xE2\x84\x9E", 0 }, { "sacute", "\xC5\x9B", 0 }, { "sbquo", "\xE2\x80\x9A", 0 }, { "sc", "\xE2\x89\xBB", 0 }, { "scE", "\xE2\xAA\xB4", 0 }, { "scap", "\xE2\xAA\xB8", 0 }, { "scaron", "\xC5\xA1", 0 }, { "sccue", "\xE2\x89\xBD", 0 }, { "sce", "\xE2\xAA\xB0", 0 }, { "scedil", "\xC5\x9F", 0 }, { "scirc", "\xC5\x9D", 0 }, { "scnE", "\xE2\xAA\xB6", 0 }, { "scnap", "\xE2\xAA\xBA", 0 }, { "scnsim", "\xE2\x8B\xA9", 0 }, { "scpolint", "\xE2\xA8\x93", 0 }, { "scsim", "\xE2\x89\xBF", 0 }, { "scy", "\xD1\x81", 0 }, { "sdot", "\xE2\x8B\x85", 0 }, { "sdotb", "\xE2\x8A\xA1", 0 }, { "sdote", "\xE2\xA9\xA6", 0 }, { "seArr", "\xE2\x87\x98", 0 }, { "searhk", "\xE2\xA4\xA5", 0 }, { "searr", "\xE2\x86\x98", 0 }, { "searrow", "\xE2\x86\x98", 0 }, { "sect", "\xC2\xA7", 0 }, { "semi", "\x3B", 0 }, { "seswar", "\xE2\xA4\xA9", 0 }, { "setminus", "\xE2\x88\x96", 0 }, { "setmn", "\xE2\x88\x96", 0 }, { "sext", "\xE2\x9C\xB6", 0 }, { "sfr", "\xF0\x9D\x94\xB0", 0 }, { "sfrown", "\xE2\x8C\xA2", 0 }, { "sharp", "\xE2\x99\xAF", 0 }, { "shchcy", "\xD1\x89", 0 }, { "shcy", "\xD1\x88", 0 }, { "shortmid", "\xE2\x88\xA3", 0 }, { "shortparallel", "\xE2\x88\xA5", 0 }, { "shy", "\xC2\xAD", 0 }, { "sigma", "\xCF\x83", 0 }, { "sigmaf", "\xCF\x82", 0 }, { "sigmav", "\xCF\x82", 0 }, { "sim", "\xE2\x88\xBC", 0 }, { "simdot", "\xE2\xA9\xAA", 0 }, { "sime", "\xE2\x89\x83", 0 }, { "simeq", "\xE2\x89\x83", 0 }, { "simg", "\xE2\xAA\x9E", 0 }, { "simgE", "\xE2\xAA\xA0", 0 }, { "siml", "\xE2\xAA\x9D", 0 }, { "simlE", "\xE2\xAA\x9F", 0 }, { "simne", "\xE2\x89\x86", 0 }, { "simplus", "\xE2\xA8\xA4", 0 }, { "simrarr", "\xE2\xA5\xB2", 0 }, { "slarr", "\xE2\x86\x90", 0 }, { "smallsetminus", "\xE2\x88\x96", 0 }, { "smashp", "\xE2\xA8\xB3", 0 }, { "smeparsl", "\xE2\xA7\xA4", 0 }, { "smid", "\xE2\x88\xA3", 0 }, { "smile", "\xE2\x8C\xA3", 0 }, { "smt", "\xE2\xAA\xAA", 0 }, { "smte", "\xE2\xAA\xAC", 0 }, { "smtes", "\xE2\xAA\xAC\xEF\xB8\x80", 0 }, { "softcy", "\xD1\x8C", 0 }, { "sol", "\x2F", 0 }, { "solb", "\xE2\xA7\x84", 0 }, { "solbar", "\xE2\x8C\xBF", 0 }, { "sopf", "\xF0\x9D\x95\xA4", 0 }, { "spades", "\xE2\x99\xA0", 0 }, { "spadesuit", "\xE2\x99\xA0", 0 }, { "spar", "\xE2\x88\xA5", 0 }, { "sqcap", "\xE2\x8A\x93", 0 }, { "sqcaps", "\xE2\x8A\x93\xEF\xB8\x80", 0 }, { "sqcup", "\xE2\x8A\x94", 0 }, { "sqcups", "\xE2\x8A\x94\xEF\xB8\x80", 0 }, { "sqsub", "\xE2\x8A\x8F", 0 }, { "sqsube", "\xE2\x8A\x91", 0 }, { "sqsubset", "\xE2\x8A\x8F", 0 }, { "sqsubseteq", "\xE2\x8A\x91", 0 }, { "sqsup", "\xE2\x8A\x90", 0 }, { "sqsupe", "\xE2\x8A\x92", 0 }, { "sqsupset", "\xE2\x8A\x90", 0 }, { "sqsupseteq", "\xE2\x8A\x92", 0 }, { "squ", "\xE2\x96\xA1", 0 }, { "square", "\xE2\x96\xA1", 0 }, { "squarf", "\xE2\x96\xAA", 0 }, { "squf", "\xE2\x96\xAA", 0 }, { "srarr", "\xE2\x86\x92", 0 }, { "sscr", "\xF0\x9D\x93\x88", 0 }, { "ssetmn", "\xE2\x88\x96", 0 }, { "ssmile", "\xE2\x8C\xA3", 0 }, { "sstarf", "\xE2\x8B\x86", 0 }, { "star", "\xE2\x98\x86", 0 }, { "starf", "\xE2\x98\x85", 0 }, { "straightepsilon", "\xCF\xB5", 0 }, { "straightphi", "\xCF\x95", 0 }, { "strns", "\xC2\xAF", 0 }, { "sub", "\xE2\x8A\x82", 0 }, { "subE", "\xE2\xAB\x85", 0 }, { "subdot", "\xE2\xAA\xBD", 0 }, { "sube", "\xE2\x8A\x86", 0 }, { "subedot", "\xE2\xAB\x83", 0 }, { "submult", "\xE2\xAB\x81", 0 }, { "subnE", "\xE2\xAB\x8B", 0 }, { "subne", "\xE2\x8A\x8A", 0 }, { "subplus", "\xE2\xAA\xBF", 0 }, { "subrarr", "\xE2\xA5\xB9", 0 }, { "subset", "\xE2\x8A\x82", 0 }, { "subseteq", "\xE2\x8A\x86", 0 }, { "subseteqq", "\xE2\xAB\x85", 0 }, { "subsetneq", "\xE2\x8A\x8A", 0 }, { "subsetneqq", "\xE2\xAB\x8B", 0 }, { "subsim", "\xE2\xAB\x87", 0 }, { "subsub", "\xE2\xAB\x95", 0 }, { "subsup", "\xE2\xAB\x93", 0 }, { "succ", "\xE2\x89\xBB", 0 }, { "succapprox", "\xE2\xAA\xB8", 0 }, { "succcurlyeq", "\xE2\x89\xBD", 0 }, { "succeq", "\xE2\xAA\xB0", 0 }, { "succnapprox", "\xE2\xAA\xBA", 0 }, { "succneqq", "\xE2\xAA\xB6", 0 }, { "succnsim", "\xE2\x8B\xA9", 0 }, { "succsim", "\xE2\x89\xBF", 0 }, { "sum", "\xE2\x88\x91", 0 }, { "sung", "\xE2\x99\xAA", 0 }, { "sup", "\xE2\x8A\x83", 0 }, { "sup1", "\xC2\xB9", 0 }, { "sup2", "\xC2\xB2", 0 }, { "sup3", "\xC2\xB3", 0 }, { "supE", "\xE2\xAB\x86", 0 }, { "supdot", "\xE2\xAA\xBE", 0 }, { "supdsub", "\xE2\xAB\x98", 0 }, { "supe", "\xE2\x8A\x87", 0 }, { "supedot", "\xE2\xAB\x84", 0 }, { "suphsol", "\xE2\x9F\x89", 0 }, { "suphsub", "\xE2\xAB\x97", 0 }, { "suplarr", "\xE2\xA5\xBB", 0 }, { "supmult", "\xE2\xAB\x82", 0 }, { "supnE", "\xE2\xAB\x8C", 0 }, { "supne", "\xE2\x8A\x8B", 0 }, { "supplus", "\xE2\xAB\x80", 0 }, { "supset", "\xE2\x8A\x83", 0 }, { "supseteq", "\xE2\x8A\x87", 0 }, { "supseteqq", "\xE2\xAB\x86", 0 }, { "supsetneq", "\xE2\x8A\x8B", 0 }, { "supsetneqq", "\xE2\xAB\x8C", 0 }, { "supsim", "\xE2\xAB\x88", 0 }, { "supsub", "\xE2\xAB\x94", 0 }, { "supsup", "\xE2\xAB\x96", 0 }, { "swArr", "\xE2\x87\x99", 0 }, { "swarhk", "\xE2\xA4\xA6", 0 }, { "swarr", "\xE2\x86\x99", 0 }, { "swarrow", "\xE2\x86\x99", 0 }, { "swnwar", "\xE2\xA4\xAA", 0 }, { "szlig", "\xC3\x9F", 0 }, { "target", "\xE2\x8C\x96", 0 }, { "tau", "\xCF\x84", 0 }, { "tbrk", "\xE2\x8E\xB4", 0 }, { "tcaron", "\xC5\xA5", 0 }, { "tcedil", "\xC5\xA3", 0 }, { "tcy", "\xD1\x82", 0 }, { "tdot", "\xE2\x83\x9B", 0 }, { "telrec", "\xE2\x8C\x95", 0 }, { "tfr", "\xF0\x9D\x94\xB1", 0 }, { "there4", "\xE2\x88\xB4", 0 }, { "therefore", "\xE2\x88\xB4", 0 }, { "theta", "\xCE\xB8", 0 }, { "thetasym", "\xCF\x91", 0 }, { "thetav", "\xCF\x91", 0 }, { "thickapprox", "\xE2\x89\x88", 0 }, { "thicksim", "\xE2\x88\xBC", 0 }, { "thinsp", "\xE2\x80\x89", 0 }, { "thkap", "\xE2\x89\x88", 0 }, { "thksim", "\xE2\x88\xBC", 0 }, { "thorn", "\xC3\xBE", 0 }, { "tilde", "\xCB\x9C", 0 }, { "times", "\xC3\x97", 0 }, { "timesb", "\xE2\x8A\xA0", 0 }, { "timesbar", "\xE2\xA8\xB1", 0 }, { "timesd", "\xE2\xA8\xB0", 0 }, { "tint", "\xE2\x88\xAD", 0 }, { "toea", "\xE2\xA4\xA8", 0 }, { "top", "\xE2\x8A\xA4", 0 }, { "topbot", "\xE2\x8C\xB6", 0 }, { "topcir", "\xE2\xAB\xB1", 0 }, { "topf", "\xF0\x9D\x95\xA5", 0 }, { "topfork", "\xE2\xAB\x9A", 0 }, { "tosa", "\xE2\xA4\xA9", 0 }, { "tprime", "\xE2\x80\xB4", 0 }, { "trade", "\xE2\x84\xA2", 0 }, { "triangle", "\xE2\x96\xB5", 0 }, { "triangledown", "\xE2\x96\xBF", 0 }, { "triangleleft", "\xE2\x97\x83", 0 }, { "trianglelefteq", "\xE2\x8A\xB4", 0 }, { "triangleq", "\xE2\x89\x9C", 0 }, { "triangleright", "\xE2\x96\xB9", 0 }, { "trianglerighteq", "\xE2\x8A\xB5", 0 }, { "tridot", "\xE2\x97\xAC", 0 }, { "trie", "\xE2\x89\x9C", 0 }, { "triminus", "\xE2\xA8\xBA", 0 }, { "triplus", "\xE2\xA8\xB9", 0 }, { "trisb", "\xE2\xA7\x8D", 0 }, { "tritime", "\xE2\xA8\xBB", 0 }, { "trpezium", "\xE2\x8F\xA2", 0 }, { "tscr", "\xF0\x9D\x93\x89", 0 }, { "tscy", "\xD1\x86", 0 }, { "tshcy", "\xD1\x9B", 0 }, { "tstrok", "\xC5\xA7", 0 }, { "twixt", "\xE2\x89\xAC", 0 }, { "twoheadleftarrow", "\xE2\x86\x9E", 0 }, { "twoheadrightarrow", "\xE2\x86\xA0", 0 }, { "uArr", "\xE2\x87\x91", 0 }, { "uHar", "\xE2\xA5\xA3", 0 }, { "uacute", "\xC3\xBA", 0 }, { "uarr", "\xE2\x86\x91", 0 }, { "ubrcy", "\xD1\x9E", 0 }, { "ubreve", "\xC5\xAD", 0 }, { "ucirc", "\xC3\xBB", 0 }, { "ucy", "\xD1\x83", 0 }, { "udarr", "\xE2\x87\x85", 0 }, { "udblac", "\xC5\xB1", 0 }, { "udhar", "\xE2\xA5\xAE", 0 }, { "ufisht", "\xE2\xA5\xBE", 0 }, { "ufr", "\xF0\x9D\x94\xB2", 0 }, { "ugrave", "\xC3\xB9", 0 }, { "uharl", "\xE2\x86\xBF", 0 }, { "uharr", "\xE2\x86\xBE", 0 }, { "uhblk", "\xE2\x96\x80", 0 }, { "ulcorn", "\xE2\x8C\x9C", 0 }, { "ulcorner", "\xE2\x8C\x9C", 0 }, { "ulcrop", "\xE2\x8C\x8F", 0 }, { "ultri", "\xE2\x97\xB8", 0 }, { "umacr", "\xC5\xAB", 0 }, { "uml", "\xC2\xA8", 0 }, { "uogon", "\xC5\xB3", 0 }, { "uopf", "\xF0\x9D\x95\xA6", 0 }, { "uparrow", "\xE2\x86\x91", 0 }, { "updownarrow", "\xE2\x86\x95", 0 }, { "upharpoonleft", "\xE2\x86\xBF", 0 }, { "upharpoonright", "\xE2\x86\xBE", 0 }, { "uplus", "\xE2\x8A\x8E", 0 }, { "upsi", "\xCF\x85", 0 }, { "upsih", "\xCF\x92", 0 }, { "upsilon", "\xCF\x85", 0 }, { "upuparrows", "\xE2\x87\x88", 0 }, { "urcorn", "\xE2\x8C\x9D", 0 }, { "urcorner", "\xE2\x8C\x9D", 0 }, { "urcrop", "\xE2\x8C\x8E", 0 }, { "uring", "\xC5\xAF", 0 }, { "urtri", "\xE2\x97\xB9", 0 }, { "uscr", "\xF0\x9D\x93\x8A", 0 }, { "utdot", "\xE2\x8B\xB0", 0 }, { "utilde", "\xC5\xA9", 0 }, { "utri", "\xE2\x96\xB5", 0 }, { "utrif", "\xE2\x96\xB4", 0 }, { "uuarr", "\xE2\x87\x88", 0 }, { "uuml", "\xC3\xBC", 0 }, { "uwangle", "\xE2\xA6\xA7", 0 }, { "vArr", "\xE2\x87\x95", 0 }, { "vBar", "\xE2\xAB\xA8", 0 }, { "vBarv", "\xE2\xAB\xA9", 0 }, { "vDash", "\xE2\x8A\xA8", 0 }, { "vangrt", "\xE2\xA6\x9C", 0 }, { "varepsilon", "\xCF\xB5", 0 }, { "varkappa", "\xCF\xB0", 0 }, { "varnothing", "\xE2\x88\x85", 0 }, { "varphi", "\xCF\x95", 0 }, { "varpi", "\xCF\x96", 0 }, { "varpropto", "\xE2\x88\x9D", 0 }, { "varr", "\xE2\x86\x95", 0 }, { "varrho", "\xCF\xB1", 0 }, { "varsigma", "\xCF\x82", 0 }, { "varsubsetneq", "\xE2\x8A\x8A\xEF\xB8\x80", 0 }, { "varsubsetneqq", "\xE2\xAB\x8B\xEF\xB8\x80", 0 }, { "varsupsetneq", "\xE2\x8A\x8B\xEF\xB8\x80", 0 }, { "varsupsetneqq", "\xE2\xAB\x8C\xEF\xB8\x80", 0 }, { "vartheta", "\xCF\x91", 0 }, { "vartriangleleft", "\xE2\x8A\xB2", 0 }, { "vartriangleright", "\xE2\x8A\xB3", 0 }, { "vcy", "\xD0\xB2", 0 }, { "vdash", "\xE2\x8A\xA2", 0 }, { "vee", "\xE2\x88\xA8", 0 }, { "veebar", "\xE2\x8A\xBB", 0 }, { "veeeq", "\xE2\x89\x9A", 0 }, { "vellip", "\xE2\x8B\xAE", 0 }, { "verbar", "\x7C", 0 }, { "vert", "\x7C", 0 }, { "vfr", "\xF0\x9D\x94\xB3", 0 }, { "vltri", "\xE2\x8A\xB2", 0 }, { "vnsub", "\xE2\x8A\x82\xE2\x83\x92", 0 }, { "vnsup", "\xE2\x8A\x83\xE2\x83\x92", 0 }, { "vopf", "\xF0\x9D\x95\xA7", 0 }, { "vprop", "\xE2\x88\x9D", 0 }, { "vrtri", "\xE2\x8A\xB3", 0 }, { "vscr", "\xF0\x9D\x93\x8B", 0 }, { "vsubnE", "\xE2\xAB\x8B\xEF\xB8\x80", 0 }, { "vsubne", "\xE2\x8A\x8A\xEF\xB8\x80", 0 }, { "vsupnE", "\xE2\xAB\x8C\xEF\xB8\x80", 0 }, { "vsupne", "\xE2\x8A\x8B\xEF\xB8\x80", 0 }, { "vzigzag", "\xE2\xA6\x9A", 0 }, { "wcirc", "\xC5\xB5", 0 }, { "wedbar", "\xE2\xA9\x9F", 0 }, { "wedge", "\xE2\x88\xA7", 0 }, { "wedgeq", "\xE2\x89\x99", 0 }, { "weierp", "\xE2\x84\x98", 0 }, { "wfr", "\xF0\x9D\x94\xB4", 0 }, { "wopf", "\xF0\x9D\x95\xA8", 0 }, { "wp", "\xE2\x84\x98", 0 }, { "wr", "\xE2\x89\x80", 0 }, { "wreath", "\xE2\x89\x80", 0 }, { "wscr", "\xF0\x9D\x93\x8C", 0 }, { "xcap", "\xE2\x8B\x82", 0 }, { "xcirc", "\xE2\x97\xAF", 0 }, { "xcup", "\xE2\x8B\x83", 0 }, { "xdtri", "\xE2\x96\xBD", 0 }, { "xfr", "\xF0\x9D\x94\xB5", 0 }, { "xhArr", "\xE2\x9F\xBA", 0 }, { "xharr", "\xE2\x9F\xB7", 0 }, { "xi", "\xCE\xBE", 0 }, { "xlArr", "\xE2\x9F\xB8", 0 }, { "xlarr", "\xE2\x9F\xB5", 0 }, { "xmap", "\xE2\x9F\xBC", 0 }, { "xnis", "\xE2\x8B\xBB", 0 }, { "xodot", "\xE2\xA8\x80", 0 }, { "xopf", "\xF0\x9D\x95\xA9", 0 }, { "xoplus", "\xE2\xA8\x81", 0 }, { "xotime", "\xE2\xA8\x82", 0 }, { "xrArr", "\xE2\x9F\xB9", 0 }, { "xrarr", "\xE2\x9F\xB6", 0 }, { "xscr", "\xF0\x9D\x93\x8D", 0 }, { "xsqcup", "\xE2\xA8\x86", 0 }, { "xuplus", "\xE2\xA8\x84", 0 }, { "xutri", "\xE2\x96\xB3", 0 }, { "xvee", "\xE2\x8B\x81", 0 }, { "xwedge", "\xE2\x8B\x80", 0 }, { "yacute", "\xC3\xBD", 0 }, { "yacy", "\xD1\x8F", 0 }, { "ycirc", "\xC5\xB7", 0 }, { "ycy", "\xD1\x8B", 0 }, { "yen", "\xC2\xA5", 0 }, { "yfr", "\xF0\x9D\x94\xB6", 0 }, { "yicy", "\xD1\x97", 0 }, { "yopf", "\xF0\x9D\x95\xAA", 0 }, { "yscr", "\xF0\x9D\x93\x8E", 0 }, { "yucy", "\xD1\x8E", 0 }, { "yuml", "\xC3\xBF", 0 }, { "zacute", "\xC5\xBA", 0 }, { "zcaron", "\xC5\xBE", 0 }, { "zcy", "\xD0\xB7", 0 }, { "zdot", "\xC5\xBC", 0 }, { "zeetrf", "\xE2\x84\xA8", 0 }, { "zeta", "\xCE\xB6", 0 }, { "zfr", "\xF0\x9D\x94\xB7", 0 }, { "zhcy", "\xD0\xB6", 0 }, { "zigrarr", "\xE2\x87\x9D", 0 }, { "zopf", "\xF0\x9D\x95\xAB", 0 }, { "zscr", "\xF0\x9D\x93\x8F", 0 }, { "zwj", "\xE2\x80\x8D", 0 }, { "zwnj", "\xE2\x80\x8C", 0 }, } test json-5.1 {-jsonmaxnesting 0} { set result [catch {dom parse -json -jsonmaxnesting 0 {{"this":"that"}}} errMsg] list $result $errMsg } {1 {error "Maximum JSON object/array nesting depth exceeded" at position 0 "{ <--Error-- "this":"that"}"}} test json-5.2 {-jsonmaxnesting 0} { set result [catch {dom parse -json -jsonmaxnesting 0 {["this","that"]}} errMsg] list $result $errMsg } {1 {error "Maximum JSON object/array nesting depth exceeded" at position 0 "[ <--Error-- "this","that"]"}} test json-5.3 {-jsonmaxnesting 0} { set result [catch {dom parse -jsonroot o -json -jsonmaxnesting 0 {["this","that"]}} errMsg] list $result $errMsg } {1 {error "Maximum JSON object/array nesting depth exceeded" at position 0 "[ <--Error-- "this","that"]"}} test json-5.4 {-jsonmaxnesting} { set doc [dom parse -json -jsonmaxnesting 2 {{"this":{"foo":"that"}}}] set result [$doc asXML -indent none] $doc delete set result } {that} test json-5.5 {-jsonmaxnesting} { set result [catch {dom parse -json -jsonmaxnesting 1 \ {{"this":{"foo":"that"}}}} errMsg] list $result $errMsg } {1 {error "Maximum JSON object/array nesting depth exceeded" at position 8 "{"this":{ <--Error-- "foo":"that"}}"}} test json-5.6 {-jsonmaxnesting} { set doc [dom parse -json -jsonmaxnesting 2 { { "this": { "foo":"that", "bar":"grill" }, "two": "value", "three": { "t1":"t1value", "t2":"t2value" }, "four": ["a","b","c"] }}] set result [$doc asXML] $doc delete set result } { that grill value t1value t2value abc } set jsons { {{"a":"avalue","b":"bvalue","c":0.123}} {{"a":["avalue"]}} {{"a":"a value","b":"1value"}} {{"a":{"aa":"aavalue","bb":"bbvalue"},"b":"bvalue","c":0.123}} {{"a":[1,2,3,4,"abc"]}} {{"a":true,"b":false,"c":null,"d":"true","e":""}} {{"a":{"aa":[1,2,3,4,"abc"]},"b":"bvalue"}} {{"a":true,"b":false,"c":null,"d":"true","e":""}} {["a",["aa","bb"],"b"]} {{"a":"a\nvalue","b":"value\tvalue"}} {["\\\\a"]} {["a\"b"]} {{"b":"a \"b c\" d","b":"a \"b c\" d"}} {{"this":"a\nbc"}} {{"this":{"foo":"that"}}} {{"this":{"foo":"that","bar":"grill"},"two":"value","three":{"t1":"t1value","t2":"t2value"},"four":["a","b","c"]}} {"only a string"} {null} {1.23} {true} {false} {{}} {[]} {[[]]} {[["x"]]} {""} {[[[[["a"]]]]]} {{"x":[{"id":"foo"}]}} {"http://foo.bar"} } test json-6.1 {asJSON} { set failedlist [list] set ind 0 foreach json $jsons { set doc [dom parse -json $json] set out [$doc asJSON] if {$json ne $out} { lappend failedlist "$ind : '$json' : '$out'" } incr ind } set failedlist } {} test json-6.2 {asJSON - slash will not be escaped while serializing} { set doc [dom parse -json {"http:\/\/foo.bar"}] set result [$doc asJSON] $doc delete set result } {"http://foo.bar"} test json-6.3 {asJSON - docNode serialization} { dom createDocumentNode docNode set result [$docNode asJSON] $docNode delete set result } {{}} test json-6.4 {asJSON - doc serialization} { dom createDocument root docNode set result [$docNode asJSON] $docNode delete set result } {{"root":""}} test json-6.5 {asJSON - serialization of control characters} { set doc [dom parse -json "\"a\\u0000\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007\\u0008\\u0009\\u000A\\u000B\\u000C\\u000D\\u000E\\u000F\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017\\u0018\\u0019\\u001A\\u001B\\u001C\\u001D\\u001E\\u001F\\u0020b\""] set result [$doc asJSON] $doc delete set result } {"a\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f b"} test json-6.6 {asJSON -indent} { set doc [dom parse -json {{"a":{"aa":[1,2,3,4,"abc"]},"b":"bvalue"}}] set result [$doc asJSON -indent 2] $doc delete set result } {{ "a": { "aa": [ 1, 2, 3, 4, "abc" ] }, "b": "bvalue" }} test json-6.7 {asJSON -indent} { set doc [dom parse -json {{"a":{"aa":[1,2,3,4,"abc"]},"b":"bvalue"}}] set result [$doc asJSON -indent tabs] $doc delete set result } {{ "a": { "aa": [ 1, 2, 3, 4, "abc" ] }, "b": "bvalue" }} if {[info commands _dom] eq ""} { test json-7.1 {jsonType} { set doc [dom parse {foo}] set root [$doc documentElement] set result [list] lappend result [$root asJSON] lappend result [$root jsonType] $root jsonType ARRAY lappend result [$root asJSON] $doc delete set result } {{"foo"} NONE {["foo"]}} test json-7.2 {jsonType} { set doc [dom createDocumentNode] set result [$doc jsonType] lappend result [$doc asJSON] lappend result [catch {$doc jsonType foo}] $doc jsonType ARRAY lappend result [$doc asJSON] $doc jsonType OBJECT lappend result [$doc asJSON] $doc delete set result } {NONE {{}} 1 {[]} {{}}} test json-8.1 {appendFromScript} { set doc [dom createDocumentNode] $doc appendFromScript { nodeCmds::e1 } set result [list] lappend result [$doc asJSON] set root [$doc documentElement] lappend result [$root asJSON] $doc removeChild [$doc firstChild] $doc appendFromScript { nodeCmds::jae1 } lappend result [$doc asJSON] set root [$doc documentElement] lappend result [$root asJSON] lappend result [$root jsonType] $doc delete set result } {{{"e1":""}} {{}} {{"jae1":[]}} {[]} ARRAY} test json-8.2 {appendFromScript} { set doc [dom createDocumentNode] $doc appendFromScript { nodeCmds::t "some string" } set result [$doc asJSON] $doc delete set result } {"some string"} test json-8.3 {appendFromScript} { set doc [dom createDocumentNode] $doc appendFromScript { nodeCmds::t "" nodeCmds::true "" nodeCmds::false "" nodeCmds::null "" } set result [$doc asJSON] $doc delete set result } {["",true,false,null]} test json-8.4 {appendFromScript - text node with type NUMBER} { set doc [dom createDocumentNode] $doc appendFromScript { nodeCmds::number "" nodeCmds::number "0" nodeCmds::number "123456789012345678901234567890.12345679e-0003" nodeCmds::number "42 " nodeCmds::number " 42" nodeCmds::number "-" } set result [$doc asJSON] $doc delete set result } {["",0,123456789012345678901234567890.12345679e-0003,"42 "," 42","-"]} test json-8.5 {createNodeCmd - wrong jsonType} { catch {dom createNodeCmd -jsonType OBJECT textNode textNodeWithJsonTypeObject} } 1 test json-8.6 {text nodes with json type NULL, TRUE or FALSE} { set doc [dom createDocumentNode] $doc jsonType ARRAY $doc appendFromScript { nodeCmds::null nodeCmds::true nodeCmds::false } set result [$doc asJSON] $doc delete set result } {[null,true,false]} test json-8.7 {text nodes with json type NULL, TRUE or FALSE} { set doc [dom createDocument doc] $doc jsonType ARRAY $doc appendFromScript { nodeCmds::null nodeCmds::true nodeCmds::false } set result [$doc asXML -indent none] $doc delete set result } {} test json-8.8 {text nodes with json type NULL, TRUE or FALSE} { set doc [dom createDocument doc] set root [$doc documentElement] $root appendFromScript { nodeCmds::null nodeCmds::true nodeCmds::false } set result [$doc asXML -indent none] $doc delete set result } {} test json-8.9 {text nodes with json type NULL, TRUE or FALSE} { set doc [dom createDocument doc] $doc jsonType ARRAY $doc appendFromScript { nodeCmds::null nodeCmds::true nodeCmds::false } set result [$doc asXML -indent none] $doc delete set result } {} test json-8.10 {text node json type BOOLEAN} { set doc [dom createDocumentNode] $doc jsonType ARRAY $doc appendFromScript { nodeCmds::boolean foo nodeCmds::boolean true nodeCmds::boolean false } set result [$doc asJSON] $doc delete set result } {["foo",true,false]} test json-8.11 {text node json type BOOLEAN} { set doc [dom createDocumentNode] $doc jsonType ARRAY foreach value {foo 1 0} { set newtextnode [$doc createTextNode $value] $newtextnode jsonType BOOLEAN $doc appendChild $newtextnode } set result [$doc asJSON] $doc delete set result } {["foo",true,false]} test json-8.12 {text node json type BOOLEAN} { set doc [dom createDocumentNode] $doc jsonType ARRAY $doc appendFromScript { foreach value {foo 1 0 true false TRue falSE yes no YES NO bar} { nodeCmds::boolean $value } } set result [$doc asJSON] $doc delete set result } {["foo",true,false,true,false,true,false,true,false,true,false,"bar"]} } test json-9.1 {cloneNode -deep} { dom parse -json {[["a",1,"b",{"foo":"bar","baz":"boo"},null],"",null]} doc dom createDocument some other $other documentElement root $root appendChild [[$doc firstChild] cloneNode -deep] set result [[$root firstChild] asJSON] $doc delete $other delete set result } {["a",1,"b",{"foo":"bar","baz":"boo"},null]} test json-9.2 {cloneNode} { dom parse -json {[["a",1,"b",{"foo":"bar","baz":"boo"},null],"",null]} doc dom createDocument some other $other documentElement root $root appendChild [[$doc firstChild] cloneNode] set result [[$root firstChild] asJSON] $doc delete $other delete set result } {[]} test json-9.3 {cloneNode} { dom parse -json {{"string":"bar","number":1,"boolean":true,"array":[1,2,3],"object":{"foo":"bar","baz":"boo"}}} doc dom createDocument some other $other documentElement root foreach child [$doc childNodes] { $root appendChild [$child cloneNode -deep] } set result [list] foreach child [$root childNodes] { lappend result [$child asJSON] } $doc delete $other delete set result } {{"bar"} 1 true {[1,2,3]} {{"foo":"bar","baz":"boo"}}} test json-10.1 {asDict} { set json {{ "Titel": "Wirtschaftsinformatik", "Keywords": "Documentation for Keywords", "Keywords": ["Introduction","Basics"] }} set doc [dom parse -json $json] set dict [::tdom::json::asDict $doc] $doc delete dict get $dict Keywords } {Introduction Basics} test json-10.2 {asDict object members named objectcontainer and arraycontainer} { set json {{ "Titel": "Wirtschaftsinformatik", "objectcontainer": {"a":"b","c":"d"}, "arraycontainer": ["Introduction","Basics"] }} set doc [dom parse -json $json] set dict [::tdom::json::asDict $doc] $doc delete set result "" lappend result [dict get $dict objectcontainer] lappend result [dict get $dict arraycontainer] } {{a b c d} {Introduction Basics}} test json-10.2.1 {asDict} { set json {{ "Titel": "Wirtschaftsinformatik", "Keywords": "Documentation for Keywords", "Keywords": ["Introduction","Basics"] }} set doc [dom parse -json $json] set dict [::tdom::json::asDict $doc] $doc delete dict get $dict Keywords } {Introduction Basics} test json-10.2.2 {asDict object members named objectcontainer and arraycontainer} { set json {{ "Titel": "Wirtschaftsinformatik", "objectcontainer": {"a":"b","c":"d"}, "arraycontainer": ["Introduction","Basics"] }} set doc [dom parse -json $json] set dict [::tdom::json::asDict $doc] $doc delete set result "" lappend result [dict get $dict objectcontainer] lappend result [dict get $dict arraycontainer] } {{a b c d} {Introduction Basics}} test json-10.3 {asTclValue} { set json {{ "Titel": "Wirtschaftsinformatik", "Keywords": "Documentation for Keywords", "Keywords": ["Introduction","Basics"] }} set doc [dom parse -json $json] set dict [$doc asTclValue] $doc delete dict get $dict Keywords } {Introduction Basics} test json-10.3.1 {asTclValue} { set json {{ "Titel": "Wirtschaftsinformatik", "Keywords": "Documentation for Keywords", "Keywords": ["Introduction","Basics"] }} set doc [dom parse -json -jsonroot myjson $json] set myjson [$doc documentElement] set dict [$myjson asTclValue] $doc delete dict get $dict Keywords } {Introduction Basics} test json-10.4 {asTclValue object members named objectcontainer and arraycontainer} { set json {{ "Titel": "Wirtschaftsinformatik", "objectcontainer": {"a":"b","c":"d"}, "arraycontainer": ["Introduction","Basics"] }} set doc [dom parse -json $json] set dict [$doc asTclValue] $doc delete set result "" lappend result [dict get $dict objectcontainer] lappend result [dict get $dict arraycontainer] } {{a b c d} {Introduction Basics}} test json-10.4.1 {asTclValue object members named objectcontainer and arraycontainer} { set json {{ "Titel": "Wirtschaftsinformatik", "objectcontainer": {"a":"b","c":"d"}, "arraycontainer": ["Introduction","Basics"] }} set doc [dom parse -json -jsonroot myjson $json] set myjson [$doc documentElement] set dict [$myjson asTclValue] $doc delete set result "" lappend result [dict get $dict objectcontainer] lappend result [dict get $dict arraycontainer] } {{a b c d} {Introduction Basics}} test json-10.5 {asTclValue} { set result "" foreach json { \"foo\" -1.23 null false true } { set doc [dom parse -json $json] lappend result [$doc asTclValue resulttype] $resulttype $doc delete } set result } {foo string -1.23 string null string false string true string} test json-10.5.1 {asTclValue} { set result "" foreach json { \"foo\" -1.23 null false true } { set doc [dom parse -json -jsonroot myjson $json] set myjson [$doc documentElement] lappend result [$myjson asTclValue resulttype] $resulttype $doc delete } set result } {foo string -1.23 string null string false string true string} test json-10.6 {asTclValue} { set result "" foreach json { ["bar"] [1,2] [null,true,false] } { set doc [dom parse -json $json] set thisresult [$doc asTclValue resulttype] lappend result $thisresult $resulttype [llength $thisresult] $doc delete } set result } {bar list 1 {1 2} list 2 {null true false} list 3} test json-10.6.1 {asTclValue} { set result "" foreach json { ["bar"] [1,2] [null,true,false] } { set doc [dom parse -json -jsonroot myjson $json] set myjson [$doc documentElement] set thisresult [$myjson asTclValue resulttype] lappend result $thisresult $resulttype [llength $thisresult] $doc delete } set result } {bar list 1 {1 2} list 2 {null true false} list 3} test json-10.7 {asTclValue} { set json {{ "Titel": "Wirtschaftsinformatik", "Keywords": ["Introduction","Basics"], "Year": 2022 }} set doc [dom parse -json $json] set dict [$doc asTclValue resulttype] $doc delete list $dict $resulttype } {{Titel Wirtschaftsinformatik Keywords {Introduction Basics} Year 2022} dict} test json-10.7.1 {asTclValue} { set json {{ "Titel": "Wirtschaftsinformatik", "Keywords": ["Introduction","Basics"], "Year": 2022 }} set doc [dom parse -json -jsonroot myjson $json] set myjson [$doc documentElement] set dict [$myjson asTclValue resulttype] $doc delete list $dict $resulttype } {{Titel Wirtschaftsinformatik Keywords {Introduction Basics} Year 2022} dict} test json-11.1 {asTypedList} { set json {{ "Titel": "Wirtschaftsinformatik", "Keywords": ["Introduction","Basics"], "Year": 2022 }} set doc [dom parse -json $json] set result [$doc asTypedList] $doc delete set result } {OBJECT {Titel {STRING Wirtschaftsinformatik} Keywords {ARRAY {{STRING Introduction} {STRING Basics}}} Year {NUMBER 2022}}} test json-11.2 {asTypedList} { set json {{ "stringproperty": "abc", "objectproperty": {"one": 1, "two": "two"}, "array": ["foo", -2.23, null, true, false, {"one": 1, "two": "two"}, [2,16,24]], "number": 2022, "null": null, "true": true, "false": false }} set doc [dom parse -json $json] set result [$doc asTypedList] $doc delete set result } {OBJECT {stringproperty {STRING abc} objectproperty {OBJECT {one {NUMBER 1} two {STRING two}}} array {ARRAY {{STRING foo} {NUMBER -2.23} NULL TRUE FALSE {OBJECT {one {NUMBER 1} two {STRING two}}} {ARRAY {{NUMBER 2} {NUMBER 16} {NUMBER 24}}}}} number {NUMBER 2022} null NULL true TRUE false FALSE}} test json-11.3 {asTypedList} { set json {{ "one two": "abc", "one\u007btwo": "abc", " one two ": "edf" }} set doc [dom parse -json $json] set result [$doc asTypedList] $doc delete set result } {OBJECT {{one two} {STRING abc} one\{two {STRING abc} { one two } {STRING edf}}} test json-11.4 {asTypedList} { set result "" foreach json { {"string foo"} null true false -1.23 } { set doc [dom parse -json $json] lappend result [$doc asTypedList] $doc delete } set result } {{STRING {string foo}} NULL TRUE FALSE {NUMBER -1.23}} test json-11.5 {asTypedList} { set result "" set json {{ "Keywords": ["Introduction","Basics"], "Data": {"one": "two", "three": true}, "Titel": "Wirtschaftsinformatik" }} set doc [dom parse -json $json] set node [$doc firstChild] while {$node ne ""} { lappend result [$node asTypedList] set node [$node nextSibling] } $doc delete set result } {{ARRAY {{STRING Introduction} {STRING Basics}}} {OBJECT {one {STRING two} three TRUE}} {STRING Wirtschaftsinformatik}} if {[info commands _dom] eq ""} { test json-12.1 {createFromTypedList} { set doc [dom createFromTypedList {OBJECT {Titel {STRING Wirtschaftsinformatik} Keywords {ARRAY {{STRING Introduction} {STRING Basics}}} Year {NUMBER 2022}}}] set result [$doc asJSON] $doc delete set result } {{"Titel":"Wirtschaftsinformatik","Keywords":["Introduction","Basics"],"Year":2022}} test json-12.2 {createFromTypedList} { set typedList {OBJECT {Titel {STRING Wirtschaftsinformatik} Keywords {ARRAY {{STRING Introduction} {STRING Basics}}} Year {NUMBER 2022}}} set doc [dom createFromTypedList $typedList] set result [$doc asTypedList] $doc delete expr {$typedList eq $result} } 1 proc createFromTypedList {list} { dom createFromTypedList $list doc if {$list eq [$doc asTypedList]} { return "" } error "Invalid turnaround." } test json-12.3 {createFromTypedList} { createFromTypedList {OBJECT {Titel {STRING Wirtschaftsinformatik} Keywords {ARRAY {{STRING Introduction} {STRING Basics}}} Year {NUMBER 2022}}} } {} test json-12.4 {createFromTypedList} { set result "" foreach json { {STRING foo} NULL TRUE FALSE {NUMBER -1.23} } { set doc [dom createFromTypedList $json] set this [$doc asTypedList] if {$json ne $this} { lappend result "json $json this $this" } else { lappend result 1 } $doc delete } set result } {1 1 1 1 1} test json-12.5 {createFromTypedList} { set result "" foreach wrong { NUL "" {one two} {STRING two three} } { catch {dom createFromTypedList $wrong} errMsg lappend result $errMsg } set result } {{Invalid typed list format: Unkown symbol "NUL".} {Invalid typed list format: Empty list.} {Invalid typed list format: Unkown symbol "one".} {Invalid typed list format: Too much list elements.}} test json-12.6 {createFromTypedList} { catch {dom createFromTypedList {OBJECT {one {STRING two} two {}}}} errMsg set errMsg } {Invalid typed list format: object property "two": Empty list.} test json-12.7 {createFromTypedList} { catch {dom createFromTypedList {OBJECT {one {STRING two} two {ARRAY {{NUMBER 1} {NULL foo}}}}}} errMsg set errMsg } {Invalid typed list format: object property "two": array element 2: No value expected for NULL.} test json-12.8 {createFromTypedList} { set doc [dom createFromTypedList {OBJECT {"Titel with spaces" {STRING Wirtschaftsinformatik} Keywords {ARRAY {{STRING Introduction} {STRING Basics}}} Year {NUMBER 2022}}}] set result [$doc asJSON] $doc delete set result } {{"Titel with spaces":"Wirtschaftsinformatik","Keywords":["Introduction","Basics"],"Year":2022}} test json-13.1 {jsonEscape} { set result "" set strings "" for {set i 0} {$i < 32} {incr i} { lappend strings [subst [format "\\u00%02x" $i]] } foreach str $strings { lappend result [dom jsonEscape $str] } set result } {{\u0000} {\u0001} {\u0002} {\u0003} {\u0004} {\u0005} {\u0006} {\u0007} {\b} {\t} {\n} {\u000b} {\f} {\r} {\u000e} {\u000f} {\u0010} {\u0011} {\u0012} {\u0013} {\u0014} {\u0015} {\u0016} {\u0017} {\u0018} {\u0019} {\u001a} {\u001b} {\u001c} {\u001d} {\u001e} {\u001f}} test json-13.2 {jsonEscape} { set result "" foreach str [list \ a\u0000 \ b\u000c \ ä\u001a \ abc\n\r \ abc\n\rfoo\u0002 \ some\u0000\u000C\u0018\n\u001felse\"other \ \\\\ \ foo\\\\bar \ \\\" ] { lappend result [dom jsonEscape $str] } set result } {{a\u0000} {b\f} {ä\u001a} {abc\n\r} {abc\n\rfoo\u0002} {some\u0000\f\u0018\n\u001felse\"other} {\\\\} {foo\\\\bar} {\\\"}} } test json-13.3 {jsonEscape} { set str "" set expresult "" for {set i 0 } {$i < 20} {incr i} { append str "abc\"\\\u0000\u000c\u001c123+" append expresult "abc\\\"\\\\\\u0000\\f\\u001c123+" } expr {[dom jsonEscape $str] == $expresult ? 1 : 0} } 1 if {[info commands _dom] eq ""} { rename dom _dom proc dom {args} { if {[lindex $args 0] != "parse" || [lsearch -exact $args "-json"] < 0} { return [uplevel 1 [linsert $args 0 _dom]] } set haveData 0 set uplevelVar "" for {set x 1} {$x < [llength $args]} {incr x} { switch -- [lindex $args $x] { "-jsonroot" - "-jsonmaxnesting" - "-channel" - "-baseurl" - "-externalentitycommand" { incr x } "-json" - "--" - "-keepEmpties" - "-keepCDATA" { # do nothing, the options are flags } default { if {$haveData} { set uplevelVar [lindex $args $x] } else { set data [lindex $args $x] set haveData 1 } } } } if {[catch { _dom parse -json $data doc } errMsg]} { # Some tests check if invalid json data is detected. Since # we need valid json data for what is tested here that # tests should be marked with constraint nonetest. To # raise error here does not help much because if the test # data is expected to be invalid the command will be # [catch]ed. Therefore the puts to catch attention. puts "Unexpeced invalid json data '$data'" } set njson [$doc asJSON] set typedList [$doc asTypedList] _dom createFromTypedList $typedList docFromTyped if {$njson ne [$docFromTyped asJSON]} { error "Normalized json '$data' differs from normalized json created with createFromTypedList" } return [uplevel 1 [linsert $args 0 _dom]] } source [file join [file dir [info script]] domjson.test] rename dom {} rename _dom dom } tdom-0.9.6-src/tests/schema.test0000644000175000017500000104661315025767703015276 0ustar rolfrolf# Features covered: Schema validation # # Tested functionalities: # schema-1.*: Basics, interface # schema-2.*: Grammar definition ref # schema-3.*: Grammar definition choice # schema-4.*: Script level validation with event # schema-5.*: dom parse -validateCmd # schema-6.*: expat parser -validateCmd # schema-7.*: Validation checks. # schema-8.*: tdom::schema validate method # schema-9.*: Choice # schema-10.*: Any # schema-11.*: attribute, nsattribute # schema-12.*: schemaCmd domvalidate # schema-13.*: XML namespaces # schema-14.*: text # schema-15.*: Constraint cmd tcl # schema-16.*: interleave # schema-17.*: info # schema-18.*: reportcmd, validation error recover # schema-19.*: keyspace # schema-20.*: domunique # schema-21.*: internal: buffers # schema-22.*: defelementtype, elementtype # schema-23.*: validatefile # schema-24.*: validatechannel # schema-25.*: domxpathboolean # schema-26.*: info domNode # schema-27.*: Text constraint commands available outsite schema context # schema-28,*: tdom and interp # schema-29.*: text constrain jsontype # # Copyright (c) 2018-2022 Rolf Ade. source [file join [file dir [info script]] loadtdom.tcl] if {[dom featureinfo schema]} { if {[join [lrange [split [package present Tcl] .] 0 1] .] <= 8.4} { testConstraint 8.5 false testConstraint listformat false } else { testConstraint 8.5 true testConstraint listformat true } proc dummycallback {args} {} proc sortcps {a b} { switch -- [string compare [lindex $a 0] [lindex $b 0]] { -1 {return -1} 1 {return 1} default { return [string compare [lindex $a 1] [lindex $b 1]] } } } test schema-1.1 {create} { tdom::schema create grammar grammar start doc grammar delete } {} test schema-1.2 {grammar cmd outside context} { catch {tdom::schema::element} } {1} test schema-1.3 {grammar cmd} { tdom::schema create grammar grammar defpattern somePattern { element foo ! } grammar delete } {} test schema-1.4 {grammar cmd} { tdom::schema create grammar grammar defpattern somePattern { for {set i 0} {$i < 100} {incr i} { element foo$i ! } } grammar delete } {} test schema-1.5 {grammar cmd} { tdom::schema create grammar grammar defelement doc { element elm1 element elm2 * } grammar defelement elm1 {} grammar defelement elm2 {} grammar delete } {} test schema-1.6 {quants} { tdom::schema create grammar grammar defelement doc { element elm1 element elm2 * element elm3 ! element elm4 + element elm5 ? element elm6 1 element elm7 5 element elm8 12 element elm9 {0 3} element elm9 {1 12} element elm10 "8 " } grammar delete } {} test schema-1.7 {quants} { tdom::schema create grammar grammar defelement doc { for {set i 0} {$i < 100} {incr i} { element elm$i [list $i [expr {$i + 1}]] } } grammar delete } {} test schema-1.8 {Same element name in different Namespaces} { tdom::schema create grammar grammar defelement doc { element elm1 element elm2 } grammar defelement doc ns1 { # Forward defined element inherits child namespace element elm1 element elm2 } grammar defelement doc ns2 { # Forward defined element inherits child namespace element elm1 element elm2 } grammar defelement elm1 ns2 {} grammar defelement elm2 ns2 any set result [catch { grammar defelement elm1 ns1 { choice { element fooElem element barElem + } error } }] grammar defelement elm1 ns1 any grammar defelement elm2 ns1 {} grammar delete set result } 1 test schema-1.9 {Same element name in different Namespaces} { tdom::schema create grammar set result [catch { grammar defelement doc { element elm1 element elm2 } grammar defelement doc ns1 { # Forward defined element inherits child namespace element elm1 element elm2 } grammar defelement doc ns2 { # Forward defined element inherits child namespace element elm1 element elm2 } grammar defelement elm1 ns2 {} grammar defelement elm2 ns2 any grammar defelement elm1 ns1 { choice { element fooElem element barElem + } error } }] grammar delete set result } 1 test schema-1.10 {Local element definition} { tdom::schema create grammar grammar defelement doc { element elm1 element elm1 1 { element a element b } } grammar defelement c text grammar defelement d text grammar defelement elm1 { element c element d } grammar delete } {} test schema-1.11 {define} { tdom::schema create grammar set result [catch {grammar define { element elm1 }} errMsg] grammar delete lappend result $errMsg } {1 {Command not allowed at top level in schema define evaluation}} test schema-1.12 {define} { tdom::schema create grammar set result [catch {grammar define { defelement elm1 { element a element b } element elm1 }} errMsg] grammar delete lappend result $errMsg } {1 {Command not allowed at top level in schema define evaluation}} test schema-1.13 {define lots of elements} { tdom::schema create s s define { defelement elm1 { for {set i 1} {$i <= 1000} {incr i} { element a$i ? } } for {set i 1} {$i <= 1000} {incr i} { defelement a$i {} } } s delete } {} test schema-1.14 {refer local element definition with element} { tdom::schema create s s define { defelement elm1 { element elm ! { element a ! { text } } } defelement elm2 { element elm } } set result [list] foreach xml { foo foo } { lappend result [s validate $xml] } s delete set result } {1 0 0 1} test schema-1.14a1 {define start w/ namespace} { tdom::schema create s s start doc http://foo.bar s defelement doc http://foo.bar { element a element b } foreach elm {a b} { s defelement $elm http://foo.bar {} } set result [list] foreach xml { {} {} {} {} } { lappend result [s validate $xml] } s delete set result } {1 1 1 0} test schema-1.14a {define start w/ namespace} { tdom::schema create s s prefixns {ns1 http://foo.bar} s start doc ns1 s defelement doc ns1 { element a element b } foreach elm {a b} { s defelement $elm ns1 {} } set result [list] foreach xml { {} {} {} {} } { lappend result [s validate $xml] } s delete set result } {1 1 1 0} test schema-1.15 {call structure constraint outside define/defelement} { set result [catch {tdom::schema::element foo} errMsg] lappend result $errMsg tdom::schema create grammar lappend result [catch {tdom::schema::element foo} errMsg] lappend result $errMsg lappend result [catch {grammar define {::tdom::schema::element foo}} errMsg] lappend result $errMsg lappend result [catch {grammar defelement bar {::tdom::schema::element foo}} errMsg] lappend result $errMsg grammar delete set result } {1 {Command called outside of schema context} 1 {Command called outside of schema context} 1 {Command not allowed at top level in schema define evaluation} 0 {}} test schema-1.16 {call another schema cmd in a schema definition script} { tdom::schema create s1 s1 define { defelement s1a { element s1b * element s1c } ::tdom::schema ::s2 s2 define { defelement s1a { element s1b * element s1c } } defelement s1b { element s1b1 } } set result [list] foreach xml { } { lappend result [s1 validate $xml] lappend result [s2 validate $xml] } s1 delete s2 delete set result } {0 0 0 1 1 1 1 0} test schema-1.17 {call schema cmd evaluation in his own schema definition script} { tdom::schema create s1 set result [catch {s1 define { defelement s1a { s1 defelement s1b { element s1b1 } element s1b * element s1c } }} errMsg] s1 delete set result } 1 test schema-1.18 {delete schema cmd in definition script} { tdom::schema create s s define { defelement e { s delete element e1 1 { set ::result [catch {s delete}] } } } lappend result [info commands s] } {1 {}} test schema-1.19 {call top level schema cmd in definition script} { tdom::schema create s set result [catch {s define { defelement e { element e1 1 { deftexttype foo {minLength 1} defelement bar {} } element bar } }}] lappend result [info commands s] s delete set result } {1 s} test schema-1.20 {call top level schema cmd in definition script} { tdom::schema create s set result [catch {s defelement e { element e1 1 { deftexttype foo {minLength 1} defelement bar {} } element bar } }] lappend result [info commands s] s delete set result } {1 s} test schema-1.21 {Create other schema cmd in definition script} { tdom::schema create s1 s1 defelement e { element e1 1 {} element e1 1 { ::tdom::schema create ::s2 ::s2 define { defelement s2 { element s2e element s2ee } foreach e {s2e s2ee} { defelement $e {text} } } } } set result [info commands s1] lappend result [info commands s2] foreach xml { foo } { lappend result [s1 validate $xml] lappend result [s2 validate $xml] } s2 delete s1 delete set result } {s1 s2 1 0 0 1} test schema-1.22 {nrForwardDefinitions} { tdom::schema create s set result [list] s define { defelement e { lappend ::result [s info nrForwardDefinitions] element e1 lappend ::result [s info nrForwardDefinitions] element e1 lappend ::result [s info nrForwardDefinitions] element e2 lappend ::result [s info nrForwardDefinitions] } foreach e {e1 e2} { defelement $e {text} lappend ::result [s info nrForwardDefinitions] } } s delete set result } {0 1 1 2 1 0} test schema-1.23 {prefixns} { tdom::schema create s set result [list] lappend result [s prefixns] lappend result [s prefixns {a b}] lappend result [s prefixns] lappend result [s prefixns {a b a b c d}] lappend result [s prefixns {}] lappend result [s prefixns ""] lappend result [catch {s prefixns a b c} errMsg] lappend result $errMsg lappend result [catch {s prefixns {a b c}} errMsg] lappend result $errMsg lappend result [catch {s prefixns "a \{"} errMsg] lappend result $errMsg s delete set result } {{} {a b} {a b} {a b a b c d} {} {} 1 {wrong # args: should be "s prefixns ?prefixUriList?"} 1 {The optional argument to prefixns must be a 'prefix namespace' pairs list} 1 {The optional argument to prefixns must be a 'prefix namespace' pairs list}} test schema-1.24 {prefixns} { tdom::schema create s set result [list] lappend result [s define prefixns] lappend result [s define {prefixns {a b}}] lappend result [s define {prefixns}] lappend result [s define {prefixns {a b a b c d}}] lappend result [s define {prefixns {}}] lappend result [s define {prefixns ""}] lappend result [catch {s define {prefixns a b c}} errMsg] lappend result $errMsg lappend result [catch {s define {prefixns {a b c}}} errMsg] lappend result $errMsg lappend result [catch {s define {prefixns "a \{"}} errMsg] lappend result $errMsg s delete set result } {{} {a b} {a b} {a b a b c d} {} {} 1 {wrong # args: should be "prefixns ?prefixUriList?"} 1 {The optional argument to prefixns must be a 'prefix namespace' pairs list} 1 {The optional argument to prefixns must be a 'prefix namespace' pairs list}} test schema-1.25 {prefixns} { set result [list] set schema { defelement doc ns1 { element e } } set xml {} # 1 tdom::schema create s s define $schema lappend result [s validate $xml] s delete # 2 tdom::schema create s s prefixns {ns1 http://tdom.org/test} s define $schema lappend result [s validate $xml] s delete # 3 tdom::schema create s s prefixns {ns1 http://foo.bar} s define $schema lappend result [s validate $xml] s delete # 4 tdom::schema create s s prefixns {ns1 http://tdom.org/test ns1 http://foo.bar} s define $schema lappend result [s validate $xml] s delete # 5 tdom::schema create s s prefixns {ns1 http://foo.bar ns1 http://tdom.org/test} s define $schema lappend result [s validate $xml] s delete # 6 tdom::schema create s s prefixns {ns1 http://foo.bar} s prefixns {ns1 http://tdom.org/test ns1 http://foo.bar} s define $schema lappend result [s validate $xml] s delete # 7 tdom::schema create s s define { prefixns {ns1 http://tdom.org/test} defelement doc ns1 { element e } prefixns {ns2 http://foo.bar} defelement e ns2 {text {minLength 1}} } lappend result [s validate $xml] s delete # 8 tdom::schema create s s define { prefixns {ns1 http://tdom.org/test} defelement doc ns1 { namespace http://foo.bar { element e } } prefixns {ns2 http://foo.bar} defelement e ns2 {text {minLength 1}} } lappend result [s validate $xml] # 9 lappend result [s validate {}] # 10 lappend result [s validate {foo}] s delete # 11 tdom::schema create s s define { prefixns {ns1 http://tdom.org/test ns2 http://foo.bar} defelement doc ns1 { namespace ns2 { element e } } prefixns {ns2 http://foo.bar} defelement e ns2 {text {minLength 1}} } lappend result [s validate $xml] # 12 lappend result [s validate {}] # 13 lappend result [s validate {foo}] s delete set result } {0 1 0 1 0 1 1 0 0 1 0 0 1} test schema-1.26 {prefixns} { tdom::schema create s set result [list] lappend result [catch { s defelement doc { prefixns {a http://foo.bar} namespace a { element e } } } errMsg] lappend result $errMsg lappend result [catch { s defelement doc { namespace a { element e } prefixns {a http://foo.bar} } } errMsg] lappend result $errMsg lappend result [catch { s define { defelement doc { prefixns {a http://foo.bar} namespace a { element e } } } } errMsg] lappend result $errMsg lappend result [catch { s define { defelement doc { s prefixns {a http://foo.bar} namespace a { element e } } } } errMsg] lappend result $errMsg s delete set result } {1 {Command only allowed at lop level} 1 {Command only allowed at lop level} 1 {Command not allowed in nested schema define script} 1 {This recursive call is not allowed}} test schema-1.27 {prefixns} { tdom::schema create s s define { prefixns {a http:://some.uri} defelement doc a {} } set result [s validate {} errMsg] lappend result $errMsg s delete set result } {0 {error "Unknown element" at line 1 character 20}} test schema-1.28 {defelement} { tdom::schema s set result [catch { s defelement e { defelement a { element b } } }] s delete set result } 1 test schema-1.29 {defelement} { tdom::schema s catch { s defelement e { element a element b error "some" } } s defelement e { element a element b } set result [list] foreach xml { } { lappend result [s validate $xml] } s delete set result } {0 0 1 0} test schema-1.30 {recurive allowed element} { tdom::schema s s define { defelement doc { element n } defelement n { element n ? } } set xml "" # That's 200000 (and one) nesting level append xml [string repeat "" 20000] append xml "" append xml [string repeat "" 20000] append xml "" set result [s validate $xml] s delete set result } 1 test schema-1.31 {recurive allowed element} { tdom::schema s s define { defelement doc { element n } defelement n { element n ? } } set xml "" # That's 200000 (and one) nesting level append xml [string repeat "" 20000] append xml "" append xml [string repeat "" 20000] append xml "" set result [s validate $xml errMsg] s delete list $result $errMsg } {0 {error "Element "a" doesn't match" at line 1 character 600009}} test schema-1.32 {Unknown root element} { tdom::schema s s define { defelement e { element doc ? { element e } } } set result [s validate ] s delete set result } 0 test schema-1.33 {Error after local defined element} { tdom::schema s set result [catch { s define { defelement a { element b ! { element c ! {} error "triggered" } element a ! { element c ! {} } error } } }] s delete set result } 1 test schema-1.34 {defelement nested in defelement nested in define} { tdom::schema s set result [catch { s define { defelement a { defelement b { element c ! {} } } } } errMsg] s delete lappend result $errMsg } {1 {Command not allowed in nested schema define script}} test schema-1.35 {deftexttype nested in deftexttype nested in define} { tdom::schema s set result [catch { s define { deftexttype foo { minLength 2 ::tdom::schema::deftexttype bar { maxLength 2 } } } } errMsg] s define { deftexttype foo { minLength 2 } deftexttype bar { maxLength 2 } } s delete lappend result $errMsg } {1 {Command called in invalid schema context}} test schema-1.36 {list quant with *} { tdom::schema s s define { defelement doc { element child {2 *} } } set xmls { } lappend xmls "[string repeat 100]" set result "" foreach xml $xmls { lappend result [s validate $xml] } s delete set result } {0 0 1 1 1} test schema-1.37 {invalid quant} { tdom::schema s set result [catch {s define { defelement doc {element foo {a b c} {text}} }}] lappend result [catch {s define { defelement doc {element foo {* *} {text}} }}] s delete set result } {1 1} test schema-1.38 {list quant with *} { tdom::schema s s define { defelement doc { element child {0 *} } } set xmls { } lappend xmls "[string repeat 100]" set result "" foreach xml $xmls { lappend result [s validate $xml] } s delete set result } {1 1 1 1 1} test schema-1.39 {defelement - wrong # of args} { tdom::schema s set result "" catch { s define { defelement e } } errMsg lappend result $errMsg catch { s defelement e } errMsg lappend result $errMsg catch { s define { defelement e 1 2 3 } } errMsg lappend result $errMsg catch { s defelement e 1 2 3 } errMsg lappend result $errMsg s delete set result } {{wrong # args: should be "defelement ?? pattern"} {wrong # args: should be "s defelement ?? pattern"} {wrong # args: should be "defelement ?? pattern"} {wrong # args: should be "s defelement ?? pattern"}} test schema-2.1 {grammar definition: ref} { tdom::schema create grammar grammar defpattern thisPattern { element a element b } grammar defpattern thatPattern { element c element d } grammar defelement doc { ref thisPattern ref thatPattern ? } grammar delete } {} test schema-2.2 {grammar definition: ref} { tdom::schema create grammar set result [grammar info nrForwardDefinitions] grammar defelement doc { ref thisPattern ref thatPattern ? } lappend result [grammar info nrForwardDefinitions] grammar delete set result } {0 2} test schema-2.3 {forward defined ref} { set defs { { ref thisPattern ? } { ref thatPattern } { ref thisPattern ? ref thatPattern } { ref thisPattern ? element a } { ref thatPattern element a } } set xmlinput { } set result [list] foreach def $defs { tdom::schema create s s defelement doc $def foreach xml $xmlinput { lappend result [s validate $xml errMsg] } s delete } set result } {1 0 0 1 0 0 1 0 0 0 1 0 0 1 0} test schema-2.3a {forward defined ref} { tdom::schema s s defelement doc { ref some element a } set result [s validate ] lappend result [s info nrForwardDefinitions] s delete set result } {1 2} test schema-2.4 {forward definded element} { set defs { { element thisElement ? } { element thatElement } { element thisElement ? element thatElement } { element thisElement ? element a } { element thatElement element a } } set xmlinput { } set result [list] foreach def $defs { tdom::schema create s s defelement doc $def foreach xml $xmlinput { lappend result [s validate $xml errMsg] } s delete } set result } {1 0 0 0 0 0 0 0 0 0 1 0 0 0 0} test schema-3.1 {grammar definition: choice} { tdom::schema create grammar grammar defelement doc { element elm choice { element fooElem element barElem + } choice ? { element one {2 3} element two } element three } grammar delete } {} test schema-3.2 {grammar definition: choice} { tdom::schema create grammar grammar defpattern thisPattern { element elm choice { element fooElem element barElem + } choice ? { element one {2 3} element two } element three } grammar delete } {} proc pullValidate {g xml} { tdom::pullparser pp pp input $xml while {[pp next] ne "END_DOCUMENT"} { switch [pp state] { "START_TAG" { $g event start [pp tag] } "END_TAG" { $g event end } "TEXT" { $g event text [pp text] } } } } test schema-4.1 {validation} { tdom::schema create grammar grammar defelement doc { element e1 element e2 * } foreach e {e1 e2} { grammar defelement $e {} } pullValidate grammar { } if {[grammar info vstate] ne "FINISHED"} { error "Wrong state." } grammar reset pullValidate grammar { } if {[grammar info validationstate] ne "FINISHED"} { error "Wrong state." } grammar reset pullValidate grammar { } if {[grammar info vstate] ne "FINISHED"} { error "Wrong state." } grammar delete } {} test schema-4.1a {validation} { tdom::schema create s s defelement doc { element e1 element e2 * } foreach e {e1 e2} { s defelement $e {} } set result [list] foreach xml { } { lappend result [s validate $xml] } s delete set result } {1 1 1} test schema-4.2 {validation} { tdom::schema create s s defelement doc { element e1 * } s defelement e1 { element ee1 element ee2 } foreach e {ee1 ee2} { s defelement $e {} } set result [list] foreach xml { } { lappend result [s validate $xml] } s delete set result } {1 0 1 1 0} test schema-4.3 {validation} { tdom::schema s s define { defelement addressBook { element card * } defelement card { element name element email } foreach e {name email} { defelement $e {text} } } set result [s validate { John Smith js@example.com Fred Bloggs fb@example.net }] s delete set result } 1 proc schema-4.4 {scmd} { global result catch {$scmd event start foo} errMsg lappend result $errMsg } test schema-4.4 {event on itself in called script} { tdom::schema s s defelement doc { element a ? tcl schema-4.4 [self] element b ? } set result [list] foreach xml { } { lappend result [s validate $xml] } s delete set result } {{This method is not allowed in nested evaluation} 1 {This method is not allowed in nested evaluation} 1 {This method is not allowed in nested evaluation} 1} proc schema-4.5 {scmd} { global result $scmd event start foo } test schema-4.5 {event on itself in called script} { tdom::schema s s defelement doc { element a ? tcl schema-4.5 [self] element b ? } set result [list] foreach xml { } { lappend result [catch {s validate $xml errMsg} errMsg] lappend result $errMsg } s delete set result } {1 {error "This method is not allowed in nested evaluation" at line 1 character 6} 1 {error "This method is not allowed in nested evaluation" at line 1 character 15} 1 {error "This method is not allowed in nested evaluation" at line 1 character 13}} test schema-4.6 {event start with namespace} { tdom::schema s s defelement doc http://tdom.org/test { element a ! text } s event start doc http://tdom.org/test s event start a http://tdom.org/test s event text "some text" s event end s event end s delete } {} test schema-4.7 {event start with namespace} { tdom::schema s s defelement doc http://tdom.org/test { element a 1 { attribute att1 } } s event start doc http://tdom.org/test set result [catch {s event start a http://tdom.org/test} errMsg] lappend result $errMsg s delete set result } {1 {Missing mandatory attribute(s)}} test schema-4.8 {event start with namespace} { tdom::schema s s defelement doc http://tdom.org/test { element a 1 { attribute att1 } } s event start doc http://tdom.org/test s event start a {att1 "some data"} http://tdom.org/test s event end s event end s delete } {} test schema-4.9 {event start with namespace w/ namespaced attribute} { tdom::schema s s defelement doc http://tdom.org/test { element a 1 { nsattribute att1 http://tdom.org/test } } s event start doc http://tdom.org/test s event start a {{att1 http://tdom.org/test} "some data"} http://tdom.org/test s event end s event end } {} proc schema-4.10 {scmd} { error "Error raised in schema-4.10" } test schema-4.10 {event - tcl error in called script} { tdom::schema s s defelement doc { tcl schema-4.10 [self] element a } s event start doc set result [catch {s event start a} errMsg] lappend result $errMsg s delete set result } {1 {Error raised in schema-4.10}} test schema-4.11 {event - invalid root} { tdom::schema s s defelement doc {} s reportcmd dummycallback s event start doo s delete } {} test schema-4.12 {event - text without root} { tdom::schema s s defelement doc {} s reportcmd dummycallback set result [catch {s event text foo} errMsg] lappend result $errMsg s delete set result } {1 {No validation started}} test schema-4.13 {event - successive text nodes} { tdom::schema s s define { defelement doc { text integer text { oneOf { integer fixed "foo" } } text number } } set result "" foreach input { {1 2 3} {1 foo 3.2} {1 2 3 4} {foo 2 3} {1 foo} } { lappend result [catch { s event start doc foreach value $input { s event text $value } s event end }] s reset } s delete set result } {0 0 1 1 1} test schema-5.1 {dom parse -validateCmd} { set result [catch { [dom parse -validateCmd tdom::schema ] }] } 1 test schema-5.2 {dom parse -validateCmd} { tdom::schema create grammar grammar defelement doc { element e1 element e2 * } foreach e {e1 e2} { grammar defelement $e {} } dom parse -validateCmd grammar { } doc $doc delete dom parse -validateCmd grammar { } doc $doc delete dom parse -validateCmd grammar { } doc $doc delete } {} proc schema-5.3 {base systemId publicId} { return [list "string" "" ""] } test schema-5.3 {dom parse -validateCmd} { tdom::schema create grammar grammar defelement doc { element e1 element e2 * } foreach e {e1 e2} { grammar defelement $e {} } set result [catch {dom parse -validateCmd grammar \ -externalentitycommand schema-5.3 { ]> &e1;} doc} errMsg] grammar delete set result } 1 test schema-5.4 {define} { tdom::schema create grammar grammar define { defelement elm1 { element a element b } defelement a { element c } defelement b {} defelement c {} } set doc [dom parse -validateCmd grammar { }] $doc delete grammar delete } {} test schema-5.5 {validate tmml doc files} { tdom::schema s set docdir [file join [file dir [info script]] ../doc] set file [file join $docdir tmml.schema] set fd [open $file] set tmmlschema [read $fd] close $fd s define $tmmlschema set result {} foreach tmmlfile { domDoc.xml domNode.xml dom.xml expatapi.xml expat.xml pullparser.xml schema.xml tdomcmd.xml } { set file [file join $docdir $tmmlfile] set fd [open $file] set tmmldoc [read $fd] close $fd lappend result [s validate $tmmldoc] } s delete set result } {1 1 1 1 1 1 1 1} test schema-5.6 {validate tmml doc files} { tdom::schema s s defelement doc { element e1 element e2 * } s event start doc set result [catch {dom parse -validateCmd s {}}] set result } {1} test schema-6.1 {expat parser with -validateCmd} { tdom::schema create grammar grammar defelement doc { element e1 element e2 * } foreach e {e1 e2} { grammar defelement $e {} } ::xml::parser p -validateCmd grammar set result [catch {p parse {}} errMsg] p delete grammar delete set result } 1 test schema-6.2 {expat parser with -validateCmd} { tdom::schema create grammar grammar defelement doc { element e1 element e2 * } foreach e {e1 e2} { grammar defelement $e {} } ::xml::parser p -validateCmd grammar -final 0 set result [list] p parse {} errMsg] lappend result $errMsg lappend result [grammar info vstate] p parse {1/>} p configure -final 1 p reset lappend result [grammar validate ] grammar delete p delete set result } {1 {The schema command is busy} VALIDATING 1} test schema-6.3 {expat parser with -validateCmd} { tdom::schema create grammar grammar defelement doc { element e1 element e2 * } foreach e {e1 e2} { grammar defelement $e {} } ::xml::parser p -validateCmd grammar -final 0 set result [list] p parse {} errMsg] lappend result $errMsg lappend result [grammar info vstate] p parse {c>} p configure -final 1 p reset lappend result [grammar validate ] grammar delete p delete set result } {0 1 READY 1} test schema-6.4 {expat parser with -validateCmd} { tdom::schema create grammar grammar defelement doc { element e1 element e2 * } foreach e {e1 e2} { grammar defelement $e {} } ::xml::parser p -validateCmd grammar -final 0 set result [list] p parse {} errMsg] lappend result $errMsg lappend result [grammar info vstate] p parse {c} p parse {>} p configure -final 1 p reset lappend result [grammar validate ] grammar delete p delete set result } {0 1 READY 1} proc elementstart-6.5 {name attList} { lappend ::result $name } test schema-6.5 {expat parser with -validateCmd} { tdom::schema create grammar grammar defelement doc { element e1 element e2 * } foreach e {e1 e2} { grammar defelement $e {} } ::xml::parser p -validateCmd grammar -final 0\ -elementstartcommand elementstart-6.5 set result [list] p parse {} p configure -final 1 p reset lappend result [grammar validate ] grammar delete p delete set result } {doc e1 1} proc elementstart-6.6 {name attList} { lappend ::result $name if {$name eq "doc"} { grammar delete } } test schema-6.6 {expat parser with -validateCmd} { tdom::schema create grammar grammar defelement doc { element e1 element e2 * } foreach e {e1 e2} { grammar defelement $e {} } ::xml::parser p -validateCmd grammar -final 0\ -elementstartcommand elementstart-6.6 set result [list] p parse {} p configure -final 1 p reset lappend result [info command grammar] p delete set result } {doc e1 {}} test schema-6.7 {expat parser with deleted -validateCmd} { tdom::schema create grammar grammar defelement doc { element e1 element e2 * } foreach e {e1 e2} { grammar defelement $e {} } ::xml::parser p -validateCmd grammar p parse "" p reset grammar delete p parse "" p reset set result [catch {p parse ""}] p delete set result } {1} test schema-7.1 {group} { tdom::schema create grammar grammar defelement doc { element e1 group ! { element e1 element e2 } element e2 * } foreach e {e1 e2} { grammar defelement $e {} } dom parse -validateCmd grammar { } doc $doc delete grammar delete } {} test schema-7.1.1 {group} { tdom::schema create grammar grammar define { defelement doc { element e1 group ! { element e1 element e2 } group ! { element e1 element e2 } element e2 * } foreach e {e1 e2} { defelement $e {} } } dom parse -validateCmd grammar { } doc $doc delete grammar delete } {} test schema-7.2 {group} { tdom::schema create grammar grammar defelement doc { element e1 group 2 { element e1 element e2 } element e2 * } foreach e {e1 e2} { grammar defelement $e {} } dom parse -validateCmd grammar { } doc $doc delete grammar delete } {} test schema-7.2.1 {group} { tdom::schema create grammar grammar define { defelement doc { element e1 group 2 { element e1 element e2 } element e2 * } foreach e {e1 e2} { defelement $e {} } } dom parse -validateCmd grammar { } doc $doc delete grammar delete } {} test schema-7.3 {group with inline defined element} { tdom::schema create grammar grammar define { defelement doc { element e1 group 2 { element e1 1 { element e2 } element e2 } element e2 * } foreach e {e1 e2} { defelement $e {} } } dom parse -validateCmd grammar { } doc $doc delete grammar delete } {} test schema-7.4 {group with inline defined element} { tdom::schema create grammar grammar define { defelement doc { group { element e1 element e1 1 { element e2 } element e2 } } foreach e {e1 e2} { defelement $e {} } } dom parse -validateCmd grammar { } doc $doc delete grammar delete } {} test schema-7.5 {group with inline defined element} { tdom::schema create grammar grammar define { defelement doc { group { element e1 element e1 1 { element e2 } element e2 } } foreach e {e1 e2} { defelement $e {} } } ::xml::parser p -validateCmd grammar p parse { } p delete grammar delete } {} test schema-7.6 {nested groups via refs} { tdom::schema create grammar grammar define { defpattern a foouri { group { element e1 element e1 1 { element e2 } element e2 } element e3 ? } defpattern b foouri { element b1 3 group 3 { element b2 ref a } } foreach e {e1 e2 e3 b1 b2} { defelement $e foouri {} } defelement doc foouri { group { ref a ref b } } } set result [grammar validate { }] grammar delete set result } 1 test schema-7.7 {nested groups via refs} { tdom::schema create grammar grammar define { defpattern a { group { element e1 element e1 1 { element e2 } element e2 } element e3 ? } defpattern b { element b1 * group 1 { element b2 ref a } } foreach e {e1 e2 e3 b1 b2} { defelement $e {} } defelement doc { group 2 { ref b } } } set doc [dom parse -validateCmd grammar { }] $doc delete set result [grammar validate { } msg] grammar delete set result } 1 test schema-7.8 {nested groups via refs} { tdom::schema create grammar grammar define { defpattern a foouri { group { element e1 element e1 1 { element e2 } element e2 } element e3 ? } foreach e {e1 e2 e3 b1 b2} { defelement $e foouri {} } defelement doc foouri { group { ref a } } } set doc [dom parse -validateCmd grammar { }] $doc delete grammar delete } {} test schema-7.9 {loop over seq} { tdom::schema create grammar grammar define { defelement doc { group * { element a element b } element c } foreach e {a b c} { defelement $e {} } } set result [grammar validate ] grammar delete set result } 1 test schema-7.10 {loop over seq} { tdom::schema create grammar grammar define { defelement doc { group { element a element b } element c } foreach e {a b c} { defelement $e {} } } set result [grammar validate ] grammar delete set result } 0 test schema-7.10a {loop over seq} { tdom::schema create grammar set result [catch {grammar define { defelement doc { group 2 { element a element b } element c foreach e {a b c} { defelement $e {} } } }}] grammar delete set result } 1 test schema-7.10b {loop over seq} { tdom::schema create grammar grammar define { defelement doc { group { element a element b } element c } foreach e {a b c} { defelement $e {} } } set result [grammar validate errMsg] grammar delete set result } 0 test schema-7.10c {loop over seq} { tdom::schema create grammar grammar define { defelement doc { group { element a element b } element c } foreach e {a b c} { defelement $e {} } } set result [catch { set doc [dom parse -validateCmd grammar ] }] grammar delete set result } 1 test schema-7.11 {loop over seq} { tdom::schema create grammar grammar define { defelement doc { group * { element a element b } element c } foreach e {a b c} { defelement $e {} } } set result [list] foreach xml { } { lappend result [grammar validate $xml] } grammar delete set result } {1 1 1 0} test schema-7.11b {loop over seq} { tdom::schema create grammar grammar define { defelement doc { group 2 { element a ? element b ? } element c } foreach e {a b c} { defelement $e {} } } set result [list] foreach xml { } { lappend result [grammar validate $xml] } grammar delete set result } {1 1 1 0} test schema-7.12 {loop over seq} { tdom::schema create grammar grammar define { defelement doc { group { element a element b } element c } foreach e {a b c} { defelement $e {} } } set result [grammar validate errMsg] lappend result [grammar validate ] lappend result [grammar validate ] lappend result [grammar validate ] lappend result [grammar validate ] grammar delete set result } {0 0 1 0 0} test schema-7.13 {long sequence} { tdom::schema create s s define { defelement doc { for {set i 1} {$i < 200} {incr i} { element e$i } } for {set i 1} {$i < 200} {incr i} { defelement e$i {element a} } defelement a {} } set xml "" for {set i 1} {$i < 200} {incr i} { append xml "" } append xml "" set result [s validate $xml] s delete set result } 1 test schema-7.14 {mixed} { tdom::schema create s s define { defelement doc { mixed { element a element b } } foreach e {a b} { defelement $e {} } } set result [list] foreach xml { text text some some } { lappend result [s validate $xml] } s delete set result } {1 1 1 1 1 0} test schema-7.14a {mixed} { tdom::schema create s s define { defelement doc { mixed ! { element a element b } } foreach e {a b} { defelement $e {} } } set result [list] foreach xml { text text {to much} some } { lappend result [s validate $xml] } s delete set result } {1 0 1 0 0 0} test schema-7.14b {mixed} { tdom::schema create s s define { defelement doc { mixed ! { element a * element b } } foreach e {a b} { defelement $e {} } } set result [list] foreach xml { text text {to much} some } { lappend result [s validate $xml] } s delete set result } {1 0 1 1 1 0 0 0 0} test schema-7.15 {choice with optional choices} { tdom::schema create s s define { defelement doc { choice { element a * element b * } element c } foreach e {a b c} { defelement $e {} } } set result [list] foreach xml { } { lappend result [s validate $xml] } s delete set result } {0 0 1 0 1 1 1} test schema-7.15a {choice with optional choices} { tdom::schema create s s define { defelement doc { choice { element a * element b * } } foreach e {a b} { defelement $e {} } } set result [list] foreach xml { } { lappend result [s validate $xml] } s delete set result } {1 1 0 1 0 0 1} test schema-7.15b {choice with optional choices} { tdom::schema create s s define { defelement doc { choice { element a * element b } } foreach e {a b} { defelement $e {} } } set result [list] foreach xml { } { lappend result [s validate $xml] } s delete set result } {1 1 0 1 0 0 1} test schema-7.16 {choice with optional choices} { tdom::schema create s s define { defelement doc { choice { element a * group * { element aa element ab ? } } element c } foreach e {a aa ab c} { defelement $e {} } } set result [list] foreach xml { } { lappend result [s validate $xml] } s delete set result } {0 0 1 0 1 1 1 1 1} test schema-7.17 {choice with optional choices} { tdom::schema create s s define { defelement doc { choice { element a * group { element aa element ab ? } } element c } foreach e {a aa ab c} { defelement $e {} } } set result [list] foreach xml { } { lappend result [s validate $xml] } s delete set result } {0 0 1 0 1 1 0 0 1} test schema-7.18 {choice} { tdom::schema create s s define { defelement doc { choice { element a group { element aa element ab ? } } element c } foreach e {a aa ab c} { defelement $e {} } } set result [list] foreach xml { } { lappend result [s validate $xml] } s delete set result } {0 0 1 0 0 1 0 0 0} test schema-7.19 {choice with quantified choice} { tdom::schema create s s define { defelement doc { choice { element a {0 2} group { element aa element ab ? } } element c } foreach e {a aa ab c} { defelement $e {} } } set result [list] foreach xml { } { lappend result [s validate $xml] } s delete set result } {0 0 1 1 0 0 0 1 0 0 1} test schema-7.20 {group with only optional content} { tdom::schema create s s define { defelement doc { element a group { element b ? element c ? } } foreach e {a b c} { defelement $e {} } } set result [list] foreach xml { } { lappend result [s validate $xml] } s delete set result } {0 1 1 0 1 1 0} test schema-7.21 {group with only optional content} { set def { group + { element c ? element a ? element b ? } element d } set result [list] tdom::schema s s defelement doc $def foreach xml { } { lappend result [s validate $xml] } s delete set result } {0 0 1 1 1 1 1 1 1 0} test schema-7.22 {Constraint text content in seq} { tdom::schema s s defelement doc { element a text { minLength 4 } element b } set result [list] foreach xml { 1234 123 12345 { } { } } { lappend result [s validate $xml] } s delete set result } {0 1 0 1 0 0} test schema-7.23 {Whitespace in implicit defined element} { tdom::schema s s defelement doc { element a } set result [list] foreach xml { { } { } { } {12} { } { } } { lappend result [s validate $xml] } s delete set result } {0 1 1 1 1 0 0 0 0} test schema-7.23a {Whitespace in implicit defined element} { tdom::schema s s defelement doc { element a } set result [list] foreach xml { { } } { lappend result [s validate $xml] } s delete set result } {0} test schema-8.1 {validate method} { tdom::schema create grammar grammar defelement doc { element e1 element e2 * } foreach e {e1 e2} { grammar defelement $e {} } set result [grammar validate ] lappend result [grammar validate errMsg] lappend result [grammar validate errMsg] lappend result [grammar validate errMsg] lappend result [grammar validate errMsg] grammar delete set result } {1 0 1 1 0} test schema-8.2 {validate method} { tdom::schema create grammar grammar defelement doc foouri { element e1 element e2 * } foreach e {e1 e2} { grammar defelement $e foouri {} } set result [grammar validate {}] lappend result [grammar validate {} errMsg] grammar delete set result } {1 0} test schema-8.3 {validate method: white space between elements} { tdom::schema create grammar grammar define { defpattern a { group { element e1 element e1 1 { element e2 } element e2 } element e3 ? } defpattern b { element b1 * group 2 { element b2 ref a } } foreach e {e1 e2 e3 b1 b2} { defelement $e {} } defelement doc { group { ref b } } } set result [grammar validate { } msg] grammar delete set result } 1 test schema-8.4 {illegal text} { tdom::schema create grammar grammar define { defelement doc { group * { element a element b } element c } foreach e {a b c} { defelement $e {} } } set result [grammar validate wrong errMsg] grammar delete set result } 0 test schema-8.5 {illegal text - expat not signaling XML_STATUS_SUSPENDED although XML_StopParser() was called in handler, again.} { tdom::schema create grammar grammar define { defelement doc { group * { element a element b } element c } foreach e {a b c} { defelement $e {} } } set result [grammar validate wrong errMsg] grammar delete set result } 0 test schema-8.6 {} { tdom::schema create s s define { defelement doc {} } set result [s validate ] lappend result [s validate ] s start mydoc lappend result [s validate ] s delete set result } {1 0 0} proc schema-8.7 {scmd} { global result lappend result "in schema-8.7" $scmd delete error "this is deliberate" } test schema-8.7 {Delete schema cmd in script called by validation} { set result "" lappend result [info commands s] tdom::schema s lappend result [info commands s] s defelement doc { tcl schema-8.7 [self] } lappend result [catch {s validate } errMsg] lappend result $errMsg lappend result [info commands s] lappend result [catch {s delete}] } {{} s {in schema-8.7} 1 {error "this is deliberate" at line 1 character 6} {} 1} proc extRefHandler-8.8 {base systemId publicId} { switch $systemId { "e1" {return [list string $base "o"]} "e2" {return [list string $base "abc"]} default {error "extRefHandler: Unexpeted SYSTEM id"} } } test schema-8.8 {External entities} { set result "" tdom::schema s s define { defelement doc { text {enumeration {boo bar baz}} element e { element ee {text} } } } foreach xml { { ]> b&e1;o&e2; } } { lappend result [s validate -externalentitycommand extRefHandler-8.8 $xml] } s delete set result } {1} test schema-9.1 {choice} { tdom::schema create grammar grammar define { defelement doc foouri { choice * { element e1 element e2 } } foreach e {e1 e2} { defelement $e foouri {} } } set result [grammar validate {}] lappend result [grammar validate {}] lappend result [grammar validate {}] lappend result [grammar validate {}] lappend result [grammar validate {}] lappend result [grammar validate {}] grammar delete set result } {1 1 1 1 1 1} test schema-9.2 {group} { tdom::schema create grammar grammar define { defelement doc foouri { group { element e1 element e2 * } } foreach e {e1 e2} { defelement $e foouri {} } } set result [grammar validate {}] lappend result [grammar validate {}] lappend result [grammar validate {}] lappend result [grammar validate {}] lappend result [grammar validate {}] lappend result [grammar validate {}] lappend result [grammar validate {}] grammar delete set result } {0 1 0 0 0 0 1} test schema-9.3 {choice} { tdom::schema create grammar grammar define { defelement doc foouri { choice * { element e1 group { element e2 element e3 } } } foreach e {e1 e2} { defelement $e foouri {} } } set result [grammar validate {}] lappend result [grammar validate {}] lappend result [grammar validate {}] lappend result [grammar validate {}] lappend result [grammar validate {}] lappend result [grammar validate {}] lappend result [grammar validate {}] grammar delete set result } {1 1 1 1 1 1 0} test schema-9.4 {choice} { tdom::schema create grammar grammar define { defelement doc foouri { choice 2 { element e1 group { element e2 element e3 } } } foreach e {e1 e2 e3} { defelement $e foouri {} } } set result [grammar validate {}] lappend result [grammar validate {}] lappend result [grammar validate {}] lappend result [grammar validate {}] lappend result [grammar validate {}] lappend result [grammar validate {}] lappend result [grammar validate {}] lappend result [grammar validate {}] grammar delete set result } {0 0 0 1 1 1 1 0} test schema-9.5 {choice as choice child} { tdom::schema create grammar grammar define { defelement doc { choice { element e1 element e2 choice { element e2 element e3 } } } foreach e {e1 e2 e3} { defelement $e foouri {} } } set result [list] foreach xml { } { lappend result [grammar validate $xml] } grammar delete set result } {0 1 0 1 1 0} test schema-9.6 {mixed as choice child} { tdom::schema create grammar grammar define { defelement doc { choice { element e1 element e2 mixed { element e2 element e3 } } } foreach e {e1 e2 e3} { defelement $e foouri {} } } set result [list] foreach xml { {} {} {} {} {} } { lappend result [grammar validate $xml] } grammar delete set result } {1 1 0 1 1 0} test schema-9.7 {choice as mixed child} { tdom::schema create grammar grammar define { defelement doc { mixed { element e1 element e2 choice { element e2 element e3 } } } foreach e {e1 e2 e3} { defelement $e foouri {} } } set result [list] foreach xml { {} {} {} {} {} } { lappend result [grammar validate $xml] } grammar delete set result } {1 1 1 1 1 0} test schema-9.8 {choice as choice child} { tdom::schema create grammar grammar define { defelement doc { choice { element e1 element e2 choice 2 { element e3 element e4 } } } } set result [list] foreach xml { {} {} {} {} {} {} } { lappend result [grammar validate $xml] } grammar delete set result } {0 1 0 1 1 1 0} test schema-9.9 {choice with optional cp belong the choices} { tdom::schema create grammar grammar define { defelement doc { element e1 choice { element e2 element e3 ? } element e4 ? } } set result [list] foreach xml { {} {} {} {} {} {} } { lappend result [grammar validate $xml] } grammar delete set result } {0 1 1 1 1 1 1} test schema-9.10 {choice with may choices} { tdom::schema create grammar grammar define { defelement doc { element e1 choice * { for {set i 1} {$i <= 20} {incr i} { element ee$i } } element e2 ? } } set result [list] foreach xml { {} {} {} {} {} {} } { lappend result [grammar validate $xml] } grammar delete set result } {0 1 1 1 1 0 1} test schema-9.11 {choice with may choices} { tdom::schema create grammar grammar define { defelement doc { element e1 choice * { for {set i 1} {$i <= 20} {incr i} { namespace foo { element ee$i } element ee$i } } element e2 ? } } set result [list] foreach xml { {} {} {} {} {} {} {} } { lappend result [grammar validate $xml] } grammar delete set result } {0 1 1 1 1 0 1} test schema-10.1 {any} { tdom::schema create s s define { defelement doc { element a any element b } defelement a {} defelement b {} } set result [list] foreach xml { text } { lappend result [s validate $xml] } s delete set result } {1 1} test schema-10.2 {any} { tdom::schema create s s define { defelement doc { element a any 1 element b } defelement a {} defelement b {} } set result [s validate {}] lappend result [s validate {}] lappend result [s validate {}] lappend result [s validate {text}] s delete set result } {1 0 0 1} test schema-10.3 {any} { tdom::schema create s s define { defelement doc { element a any ? element b } defelement a {} defelement b {} } set result [s validate {}] lappend result [s validate {}] lappend result [s validate {}] lappend result [s validate {text}] s delete set result } {1 0 0 1} test schema-10.4 {any} { tdom::schema create s s define { defelement doc { element a any 2 element b } defelement a {} defelement b {} } set result [list] foreach xml { {} {} {} {text} } { lappend result [s validate $xml] } s delete set result } {0 1 0 0} test schema-10.5 {any} { tdom::schema create s s define { defelement doc { element a any http://foo.bar 2 element b } defelement a {} defelement b {} } set result [list] foreach xml { {} {} {} {text} {some} {some} {some} } { lappend result [s validate $xml] } s delete set result } {0 0 0 0 1 1 0} test schema-10.6 {any} { tdom::schema create s s define { defelement doc { any } } set result [list] foreach xml { {} } { lappend result [s validate $xml] } s delete set result } {1} test schema-10.7 {any} { set xmls { {} {} {} {text} {some} {} } set result [list] foreach schema { { defelement doc { element a any element b } } { defelement doc { element a any {""} element b } } { defelement doc { element a any {"" http://foo.grill} element b } } { defelement doc { element a any {http://foo.grill http://foo.bar} element b } } { prefixns {bar http://foo.bar grill http://foo.grill} defelement doc { element a any {bar grill} element b } } } { tdom::schema create s s define $schema foreach xml $xmls { lappend result [s validate $xml] } s delete } set result } {1 1 0 1 1 1 1 1 0 1 0 0 1 1 0 1 0 1 0 0 0 0 1 1 0 0 0 0 1 1} test schema-10.8 {any -not} { set xmls { {} {} {} {text} {some} {} } set result [list] foreach schema { { defelement doc { element a any -not {} element b } } { defelement doc { element a any -not {""} element b } } { defelement doc { element a any -not {"" http://foo.grill} element b } } { defelement doc { element a any -not {http://foo.grill http://foo.bar} element b } } { prefixns {bar http://foo.bar grill http://foo.grill} defelement doc { element a any -not {bar grill} element b } } } { tdom::schema create s s define $schema foreach xml $xmls { lappend result [s validate $xml] } s delete } set result } {1 1 0 1 1 1 0 0 0 0 1 1 0 0 0 0 1 0 1 1 0 1 0 0 1 1 0 1 0 0} test schema-10.9 {any --} { set xmls { {} {some} {some} } tdom::schema create s s define { defelement doc { element a any -- -not element b } } set result "" foreach xml $xmls { lappend result [s validate $xml] } s delete set result } {0 1 0} test schema-10.10 {any} { set xmls { {} {} {} {text} {some} {} } set result [list] foreach schema { { defelement doc { element a any -- element b } } { defelement doc { element a any -- {""} element b } } { defelement doc { element a any -- {"" http://foo.grill} element b } } { defelement doc { element a any -- {http://foo.grill http://foo.bar} element b } } { prefixns {bar http://foo.bar grill http://foo.grill} defelement doc { element a any -- {bar grill} element b } } } { tdom::schema create s s define $schema foreach xml $xmls { lappend result [s validate $xml] } s delete } set result } {1 1 0 1 1 1 1 0 0 1 0 0 1 0 0 1 0 1 0 0 0 0 1 1 0 0 0 0 1 1} test schema-11.1 {attribute} { tdom::schema create s s define { defelement doc { attribute attr1 attribute attr2 ? } } set result [s validate {}] lappend result [s validate {}] lappend result [s validate {}] lappend result [s validate {}] s delete set result } {1 1 0 0} test schema-11.1a {attribute} { tdom::schema create s s define { defelement doc { attribute attr1 attribute attr2 ? } } set result [list] foreach xml { {} {} {} {} } { lappend result [catch {set doc [dom parse -validateCmd s $xml]} errMsg] catch {$doc delete} s reset } s delete set result } {0 0 1 1} test schema-11.1b {attribute} { tdom::schema create s s define { defelement doc { attribute attr1 attribute attr2 ? } } ::xml::parser p -validateCmd s set result [list] foreach xml { {} {} {} {} } { lappend result [catch {p parse $xml} errMsg] p reset s reset } s delete p delete set result } {0 0 1 1} test schema-11.2 {attribute} { tdom::schema create s s define { defelement e { attribute attr1 element e 1 { attribute attr3 ? attribute attr4 ! } attribute attr2 ? } } set result [s validate {}] lappend result [s validate {}] lappend result [s validate {}] lappend result [s validate {}] lappend result [s validate {}] s delete set result } {1 1 0 1 0} test schema-11.2a {attribute} { tdom::schema create s s define { defelement e { attribute attr1 element e 1 { attribute attr3 ? attribute attr4 ! } attribute attr2 ? } } set result [list] foreach xml { {} {} {} {} {} } { lappend result [catch {set doc [dom parse -validateCmd s $xml]} errMsg] catch {$doc delete} s reset } s delete set result } {0 0 1 0 1} test schema-11.2b {attribute} { tdom::schema create s s define { defelement e { attribute attr1 element e 1 { attribute attr3 ? attribute attr4 ! } attribute attr2 ? } } ::xml::parser p -validateCmd s set result [list] foreach xml { {} {} {} {} {} } { lappend result [catch {p parse $xml} errMsg] p reset s reset } p delete s delete set result } {0 0 1 0 1} test schema-11.3 {attribute} { tdom::schema create s s define { defelement e { attribute attr1 attribute attr3 ? attribute attr4 ! attribute attr2 ? } } set result [s validate errMsg] lappend result $errMsg s delete set result } {0 {error "Missing mandatory attribute(s): attr1 attr4" at line 1 character 4}} test schema-11.3a {attribute} { tdom::schema create s s define { defelement e { attribute attr1 attribute attr3 ? attribute attr4 ! attribute attr2 ? } } set result [catch {dom parse -validateCmd s } errMsg] lappend result $errMsg s delete set result } {1 {Missing mandatory attribute(s): attr1 attr4, referenced at line 1 character 4}} test schema-11.3b {attribute} { tdom::schema create s s define { defelement e { attribute attr1 attribute attr3 ? attribute attr4 ! attribute attr2 ? } } ::xml::parser p -validateCmd s set result [catch {p parse } errMsg] lappend result $errMsg p delete s delete set result } {1 {Missing mandatory attribute(s): attr1 attr4}} test schema-11.4 {attribute} { tdom::schema create s s define { defelement doc { element e 1 { attribute foo nsattribute lang http://www.w3.org/XML/1998/namespace ? } } } set result [s validate {}] s delete set result } {1} test schema-11.4_1 {attribute} { tdom::schema create s s prefixns {1 http://www.w3.org/XML/1998/namespace} s define { defelement doc { element e 1 { attribute foo nsattribute lang 1 ? } } } set result [s validate {}] s delete set result } {1} test schema-11.4a {attribute} { tdom::schema create s s define { defelement doc { element e 1 { attribute foo nsattribute lang http://www.w3.org/XML/1998/namespace ? } } } set result [catch {set doc [dom parse -validateCmd s {}]}] s delete $doc delete set result } 0 test schema-11.4b {attribute} { tdom::schema create s s define { defelement doc { element e 1 { attribute foo nsattribute lang http://www.w3.org/XML/1998/namespace } } } set result [s validate {}] s delete set result } {1} test schema-11.5 {nsattribute} { tdom::schema create s s define { defelement doc { element e 1 { attribute foo nsattribute lang http://www.w3.org/XML/1998/namespace ? } } } set result [catch {set doc [dom parse -validateCmd s {}]}] s delete $doc delete set result } 0 test schema-11.5a {nsattribute} { tdom::schema create s s prefixns {ns1 http://www.w3.org/XML/1998/namespace} s define { defelement doc { element e 1 { attribute foo nsattribute lang ns1 ? } } } set result [catch {set doc [dom parse -validateCmd s {}]}] s delete $doc delete set result } 0 test schema-11.6 {nsattribute} { tdom::schema create s s define { defelement doc { element e 1 { attribute foo nsattribute lang http://www.w3.org/XML/1998/namespace } } } set result [list] foreach xml { {} {} {} {} } { lappend result [catch {set doc [dom parse -validateCmd s $xml]} errMsg] lappend result $errMsg s reset } s delete set result } {1 {Missing mandatory attribute(s): http://www.w3.org/XML/1998/namespace:lang, referenced at line 1 character 19} 1 {Missing mandatory attribute(s): foo, referenced at line 1 character 23} 1 {Unknown attribute "unknown", referenced at line 1 character 24} 1 {Missing mandatory attribute(s): foo http://www.w3.org/XML/1998/namespace:lang, referenced at line 1 character 9}} test schema-11.6 {nsattribute} { tdom::schema create s s prefixns {ns1 http://www.w3.org/XML/1998/namespace} s define { defelement doc { element e 1 { attribute foo nsattribute lang ns1 } } } set result [list] foreach xml { {} {} {} {} } { lappend result [catch {set doc [dom parse -validateCmd s $xml]} errMsg] lappend result $errMsg s reset } s delete set result } {1 {Missing mandatory attribute(s): http://www.w3.org/XML/1998/namespace:lang, referenced at line 1 character 19} 1 {Missing mandatory attribute(s): foo, referenced at line 1 character 23} 1 {Unknown attribute "unknown", referenced at line 1 character 24} 1 {Missing mandatory attribute(s): foo http://www.w3.org/XML/1998/namespace:lang, referenced at line 1 character 9}} test schema-11.7 {attribute} { set defs { {defelement doc {attribute foo}} {defelement doc {group {attribute foo}}} {defpattern some {attribute foo}} {defelement doc {element {attribute foo}}} } set result [list] foreach def $defs { tdom::schema create s lappend result [catch {s define $def}] s delete } set result } {0 1 1 0} test schema-11.8 {attribute} { tdom::schema s s define { defelement doc { element e ! { attribute abc attribute def attribute ghi attribute jkl attribute mno attribute pqr } } } set result [list] foreach xml { {} {} {} } { lappend result [s validate $xml] } s delete set result } {1 0 0} test schema-11.8a {attribute} { tdom::schema s s define { defelement doc { element e ! { attribute abc attribute def attribute ghi attribute optional ? attribute jkl attribute mno attribute pqr } } } set result [list] foreach xml { {} {} {} {} {} {} } { lappend result [s validate $xml] } s delete set result } {1 0 0 1 0 0} proc schema-11.8b {scmd errType} { lappend ::result $errType lappend ::result [$scmd info vaction name] lappend ::result [$scmd info vaction namespace] } test schema-11.8b {attribute} { tdom::schema s s define { defelement doc { element e ! { attribute abc attribute def attribute ghi attribute optional ? attribute jkl attribute mno attribute pqr } } } s reportcmd schema-11.8b set result [list] foreach xml { {} {} {} {} {} {} } { lappend result [s validate $xml] } s delete set result } {1 MISSING_ATTRIBUTE mno {} 1 UNKNOWN_ATTRIBUTE unknown {} 1 1 MISSING_ATTRIBUTE mno {} 1 UNKNOWN_ATTRIBUTE unknown {} 1} test schema-11.9 {attribute} { tdom::schema s s define { prefixns {ns1 http://foo.bar ns2 http://foo.grill ns3 http://bar.grill} defelement doc { element e ! { nsattribute abc ns1 nsattribute abc ns2 attribute abc attribute def attribute optional ? nsattribute optional ns3 ? attribute ghi attribute jkl attribute mno attribute pqr } } } set result [list] foreach xml { {} {} {} {} {} {} } { lappend result [s validate $xml] } s delete set result } {0 1 0 0 1 0} test schema-11.10 {attribute} { tdom::schema s s define { prefixns {ns1 http://foo.bar ns2 http://foo.grill} defelement doc { element e ! { nsattribute abc ns1 nsattribute abc ns2 attribute abc attribute def attribute ghi attribute jkl attribute mno attribute pqr } } } set result [list] foreach xml { {} {} {} } { dom parse $xml doc lappend result [s domvalidate $doc] $doc delete } s delete set result } {0 1 0} test schema-11.10a {attribute} { tdom::schema s s define { prefixns {ns1 http://foo.bar ns2 http://foo.grill ns3 http://bar.grill} defelement doc { element e ! { nsattribute abc ns1 nsattribute abc ns2 attribute abc attribute def attribute optional ? nsattribute optional ns3 ? attribute ghi attribute jkl attribute mno attribute pqr } } } s reportcmd schema-11.8b set result [list] foreach xml { {} {} {} {} {} {} {} } { lappend result [s validate $xml] } s delete set result } {MISSING_ATTRIBUTE abc {} 1 1 MISSING_ATTRIBUTE abc http://foo.bar 1 UNKNOWN_ATTRIBUTE abc http://bar.grill 1 MISSING_ATTRIBUTE abc {} 1 1 UNKNOWN_ATTRIBUTE abc http://bar.grill 1} proc schema-11.11 {scmd errType} { lappend ::result $errType } test schema-11.11 {attribute - required missing} { tdom::schema s s defelement doc { element a + { attribute mode } } s reportcmd schema-11.11 set result "" set doc [dom parse ] lappend result [s domvalidate $doc] $doc delete s delete set result } {MISSING_ATTRIBUTE 1} test schema-12.1 {domvalidate} { tdom::schema s s define { defelement addressBook { element card * } defelement card { element name element email } foreach e {name email} { defelement $e {text} } } set doc [dom parse { John Smith js@example.com Fred Bloggs fb@example.net }] set result [s domvalidate $doc] lappend result [s domvalidate [$doc documentElement]] lappend result [s domvalidate [[$doc documentElement] firstChild]] lappend result [s domvalidate [[[$doc documentElement] firstChild] firstChild]] $doc delete s delete set result } {1 1 1 1} test schema-12.2 {domvalidate} { tdom::schema s s define { defelement addressBook { element card * } defelement card { element name element email } foreach e {name email} { defelement $e {text} } } set doc [dom parse { John Smith js@example.com Fred Bloggs fb@example.net John Smith }] set result [s domvalidate $doc errMsg] lappend result $errMsg $doc delete s delete set result } {0 {/addressBook/card[2]/some: Element "some" doesn't match}} test schema-12.3 {domvalidate w/ attribute} { tdom::schema s s define { defelement doc { attribute type {fixed "1.2"} element a element b } foreach e {a b} { defelement $e {} } } set result [list] foreach xml { {} {} {} {} {} } { set doc [dom parse $xml] lappend result [s domvalidate [$doc documentElement]] lappend result [s validate $xml] $doc delete } s delete set result } {1 1 0 0 0 0 0 0 0 0} test schema-12.4 {domvalidate w/ text} { tdom::schema s s define { defelement doc { attribute type {fixed "1.2"} element a element b } foreach e {a b} { defelement $e text } } set result [list] foreach xml { {} {content} {contentsome text} {textcontentsome text} {some text} } { set doc [dom parse $xml] lappend result [s domvalidate [$doc documentElement]] lappend result [s validate $xml] $doc delete } s delete set result } {1 1 1 1 1 1 0 0 0 0} test schema-12.5 {domvalidate doch w/ xml namespace} { tdom::schema s s define { defelement addressBook http://foo.bar { element card * } defelement card http://foo.bar { element name element email } foreach e {name email} { defelement $e http://foo.bar {text} } } set doc [dom parse { John Smith js@example.com Fred Bloggs fb@example.net }] set result [s domvalidate $doc] lappend result [s domvalidate [$doc documentElement]] lappend result [s domvalidate [[$doc documentElement] firstChild]] lappend result [s domvalidate [[[$doc documentElement] firstChild] firstChild]] $doc delete set doc [dom parse { John Smith js@example.com Fred Bloggs fb@example.net }] lappend result [s domvalidate $doc] lappend result [s domvalidate [$doc documentElement]] lappend result [s domvalidate [[$doc documentElement] firstChild]] lappend result [s domvalidate [[[$doc documentElement] firstChild] firstChild]] $doc delete s delete set result } {1 1 1 1 1 1 1 1} test schema-12.5a {domvalidate doc w/ xml namespace} { tdom::schema s s prefixns {fb http://foo.bar} s define { defelement addressBook fb { element card * } defelement card fb { element name element email } foreach e {name email} { defelement $e fb {text} } } set doc [dom parse { John Smith js@example.com Fred Bloggs fb@example.net }] set result [s domvalidate $doc] lappend result [s domvalidate [$doc documentElement]] lappend result [s domvalidate [[$doc documentElement] firstChild]] lappend result [s domvalidate [[[$doc documentElement] firstChild] firstChild]] $doc delete set doc [dom parse { John Smith js@example.com Fred Bloggs fb@example.net }] lappend result [s domvalidate $doc] lappend result [s domvalidate [$doc documentElement]] lappend result [s domvalidate [[$doc documentElement] firstChild]] lappend result [s domvalidate [[[$doc documentElement] firstChild] firstChild]] $doc delete s delete set result } {1 1 1 1 1 1 1 1} test schema-12.6 {domvalidate only root} { tdom::schema s s reportcmd dummycallback s start doc set doc [dom parse ] set result [s domvalidate $doc] s defelement doc {} lappend result [s domvalidate $doc] s delete $doc delete set result } {1 1} test schema-12.7 {domvalidate invalid root} { tdom::schema s s start doc s reportcmd dummycallback set doc [dom parse ] set result [s domvalidate $doc] s delete $doc delete set result } 1 dom createNodeCmd textNode t test schema-12.8 {domvalidate - successive text nodes} { tdom::schema s s define { defelement doc { text integer text { oneOf { integer fixed "foo" } } text number } } set result "" foreach input { {1 2 3} {1 foo 3.2} {1 2 3 4} } { set doc [dom createDocument doc] set root [$doc documentElement] $root appendFromScript { foreach value $input { t $value } } lappend result [s domvalidate $doc] $doc delete } s delete set result } {1 1 0} test schema-13.1 {XML namespaces} { tdom::schema create s s defelement doc ns1 { # Forward defined element inherits child namespace element elm1 element elm2 } s defelement elm1 ns2 {} s defelement elm1 ns1 { choice { element fooElem element barElem + } } s defelement elm2 ns1 {} s defelement fooElem ns1 {} s defelement barElem ns1 {} set result [list] foreach xml { {} {} {} {} {} } { lappend result [s validate $xml] } s delete set result } {0 1 1 1 0} test schema-13.2 {XML namespaces} { tdom::schema create s s defelement doc ns1 { namespace ns2 { element elm1 } # Forward defined element inherits child namespace element elm2 } s defelement elm1 ns2 {} s defelement elm1 ns1 { choice { element fooElem element barElem + } } s defelement elm2 ns1 {} s defelement fooElem ns1 {} s defelement barElem ns1 {} set result [list] foreach xml { {} {} {} {} {} } { lappend result [s validate $xml] } s delete set result } {0 0 0 0 1} test schema-13.3 {Not namespaced elements inside namespaced ones} { tdom::schema s s define { defelement doc ns1 { namespace "" { element e } } defelement e {text {fixed "here"}} } set result "" foreach xml { {here} {here} {here} {here} } { lappend result [s validate $xml] } s delete set result } {1 1 1 0} test schema-14.1 {text: integer} { tdom::schema s s defelement doc { text { integer } } set result [list] foreach xml { 5 eeee 56666 { } { 97 } } { lappend result [s validate $xml] } s delete set result } {0 0 1 0 1 0 0} test schema-14.1.1 {text: integer} { tdom::schema s s defelement doc { text { integer tcl } } set result [list] foreach xml { 5 eeee 56666 { } { +34 } {034} {0034 } {0xAB} } { lappend result [s validate $xml] } s delete set result } {0 0 1 0 1 0 1 1 1 1} test schema-14.1.2 {text: integer} { tdom::schema s s defelement doc { text { integer xsd } } set result [list] foreach xml { 5 eeee 56666 { } { +34 } {034} {0034 } {0xAB} } { lappend result [s validate $xml] } s delete set result } {0 0 1 0 1 0 0 1 0 0} proc proc-14.2 {param text} { if {$text in {one two tree}} { return true } return false } test schema-14.2 {text: tcl} {8.5} { tdom::schema s s define { defelement doc { element a element b } defelement a { text {tcl string is lower -strict} } defelement b { text {tcl proc-14.2 foo} } } set result [list] foreach xml { abctwo aBctwo abcfour } { lappend result [s validate $xml] } s delete set result } {0 0 1 0 0} test schema-14.3 {attribute text: tcl} {8.5} { tdom::schema s s define { defelement doc { element e 1 { attribute a ! {tcl string is lower -strict} attribute b ? {tcl proc-14.2 foo} } } } set result [list] foreach xml { {} {} {} {} } { lappend result [s validate $xml] } s delete set result } {1 0 0 1} test schema-14.4 {text: fixed} { tdom::schema s s define { defelement doc { element e * } defelement e { attribute a ! {fixed enabled} text {fixed something} } } set result [list] foreach xml { {something} {something} {something else} {somethingsomething} {somethingnot} } { lappend result [s validate $xml] } s delete set result } {1 1 0 0 0 0} test schema-14.5 {text: enumeration} { tdom::schema s s define { defelement doc { element e * } defelement e { attribute a {enumeration {enabled disabled}} text {enumeration {enabled disabled "a third"}} } } set result [list] foreach xml { {disabled} {disableda third} {something} {something else} {enabled disabled} } { lappend result [s validate $xml] } s delete set result } {1 1 1 0 0 0} test schema-14.6 {text: match (glob style)} { tdom::schema s s define { defelement doc { element e * } defelement e { text {match {[a-zA-Z]*1[_!]}} } } set result [list] foreach xml { {disabled1_} {dis able1_} {something} {a1!} {a1!/} } { lappend result [s validate $xml] } s delete set result } {1 1 1 0 1 0} test schema-14.6a {text: match (glob style) -nocase} { tdom::schema s s define { defelement doc { element e * } defelement e { text {match -nocase {[A-Z]*1[_!]}} } } set result [list] foreach xml { {disabled1_} {dis able1_} {something} {a1!} {a1!/} } { lappend result [s validate $xml] } s delete set result } {1 1 1 0 1 0} test schema-14.7 {text: regexp} { tdom::schema s s define { defelement doc { element e * } defelement e { text {regexp {^[a-zA-Z]*1[_!]$}} } } set result [list] foreach xml { {disabled1_} {dis able1_} {something} {a1!} {a1!/} } { lappend result [s validate $xml] } s delete set result } {1 0 0 1 0} test schema-14.8 {text: nmtoken, nmtokens} { tdom::schema s s define { defelement doc { attribute a {nmtoken} attribute b {nmtokens} attribute c ? } } set result [list] foreach xml { {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} } { lappend result [s validate $xml] } s delete set result } {1 1 1 0 0 1 1 1 1 1 1 1 0 0 0} test schema-14.9 {text: date} { tdom::schema s s define { defelement doc { text date } } set result [list] foreach xml { foo 1 12 1234-12-31 1234-14-31 1234-12-00 1234-02-31 2000-02-29 2001-02-29 2004-02-29 -2004-02-29 1900-02-29 1234-02-01 1234-08-10 1234-08-222 { 1234-08-22} {1234-08-22 } 11234-08-22 0000-02-01 10000-08-22 10000-02-29 10000-02-29Z 2012-03-07Z {2012-03-07Z } 2012-03-07a 2012-03-07+ 2012-03-07+00:00 2012-03-07-00:00 2012-03-07+02:00 2012-03-07+02:70 2012-03-07+12:30 2012-03-07+14:30 2012-03-07+14:00 2012-03-07-14:00 2012-03-07-14:01 2012-03-07-2:30 2012-03-07-02:30Z {2012-03-07-02:30 } 02027-02-01 } { lappend result [s validate $xml] } s delete set result } {0 0 0 0 0 1 0 0 0 1 0 1 1 0 1 1 0 0 0 1 0 1 1 1 1 0 0 0 1 1 1 0 1 0 1 1 0 0 0 0 0} test schema-14.10 {text: number tcl} { tdom::schema s s define { defelement doc { text {number tcl} } } set result [list] foreach xml { { } foo 1 12 1234-12-31 -14.23 .777 -1.2e5 { -1.2e5 } { -1.2e5 e} } { lappend result [s validate $xml] } s delete set result } {0 0 0 0 1 1 0 1 1 1 1 0} test schema-14.10a {text: number xsd} { tdom::schema s s define { defelement doc { text number } } set result [list] foreach xml { { } foo 1 { 1} {1 } { 1 } 12 1234-12-31 -14.23 .777 -1.2e5 { -1.2e5 } { -1.2e5 e} } { lappend result [s validate $xml] } s delete set result } {0 0 0 0 1 0 0 0 1 0 1 1 0 0 0} test schema-14.11 {text: maxLength} { tdom::schema s s define { defelement doc { text { maxLength 6 } } } set result [list] foreach xml { foo 1 12 1234-12-31 -14.23 👮ሴሴሴሴሴ 👮ሴሴሴሴሴ👮 } { lappend result [s validate $xml] } s delete set result } {1 1 1 1 1 0 1 1 0} test schema-14.12 {text: maxLength} { tdom::schema s s define { defelement doc { text {minLength 6} } } set result [list] foreach xml { foo 1 12 1234-12-31 -14.23 👮ሴሴሴሴ 👮ሴሴሴሴሴ 👮ሴሴሴሴሴ👮 } { lappend result [s validate $xml] } s delete set result } {0 0 0 0 0 1 1 0 1 1} test schema-14.13 {text: two constraints} { tdom::schema s s define { defelement doc { text { minLength 6 maxLength 8 } } } set result [list] foreach xml { foo 1 12 1234-12-31 -14.23 👮ሴሴሴሴ 👮ሴሴሴሴሴ 👮ሴሴሴሴሴ👮 1234567890 12345678901234567890 } { lappend result [s validate $xml] } s delete set result } {0 0 0 0 1 0 1 1 0 0} test schema-14.14 {text: one of two types} { tdom::schema s s define { defelement doc { choice { text { minLength 1 maxLength 3 } text {date} } } } set result [list] foreach xml { foo 1 12 1234-12-31 -14.23 👮ሴሴሴሴ 1234-12 12345678901234567890 } { lappend result [s validate $xml] } s delete set result } {0 0 1 1 1 1 0 0 0 0} test schema-14.15 {text: oneOf} { tdom::schema s s define { defelement doc { text { oneOf { maxLength 3 date } } } } set result [list] foreach xml { foo 1 12 1234-12-31 -14.23 👮ሴሴሴሴ 1234-12 12345678901234567890 } { lappend result [s validate $xml] } s delete set result } {1 1 1 1 1 1 0 0 0 0} test schema-14.16 {text: oneOf} { tdom::schema s s define { defelement doc { text { minLength 1 oneOf { maxLength 3 date } } } } set result [list] foreach xml { foo 1 12 1234-12-31 -14.23 👮ሴሴሴሴ 1234-12 12345678901234567890 } { lappend result [s validate $xml] } s delete set result } {0 0 1 1 1 1 0 0 0 0} test schema-14.17 {text: oneOf w/ allOf} { tdom::schema s s define { defelement doc { text { minLength 1 oneOf { allOf { maxLength 3 minLength 1 } date } } } } set result [list] foreach xml { foo 1 12 1234-12-31 -14.23 👮ሴሴሴሴ 1234-12 12345678901234567890 } { lappend result [s validate $xml] } s delete set result } {0 0 1 1 1 1 0 0 0 0} test schema-14.18 {deftexttype} { tdom::schema s s deftexttype len2-4 { minLength 2 maxLength 4 } s defelement doc { element e ! {text type len2-4} } set result [list] foreach xml { { } {1} {12} { } {123} {1234} {1234 } {12345} {123ሴ} } { lappend result [s validate $xml] set rc [catch {dom parse -validateCmd s $xml doc}] if {$rc == 0} { $doc delete } lappend result $rc } s delete set result } {0 1 0 1 0 1 0 1 0 1 1 0 1 0 1 0 1 0 0 1 0 1 1 0} test schema-14.18a {deftexttype} { tdom::schema s s define { deftexttype len2-4 { minLength 2 maxLength 4 } defelement doc { element e ! {text type len2-4} } } set result [list] foreach xml { { } {1} {12} { } {123} {1234} {1234 } {12345} {123ሴ} } { lappend result [s validate $xml] set rc [catch {dom parse -validateCmd s $xml doc}] if {$rc == 0} { $doc delete } lappend result $rc } s delete set result } {0 1 0 1 0 1 0 1 0 1 1 0 1 0 1 0 1 0 0 1 0 1 1 0} test schema-14.18b {deftexttype} { tdom::schema s s define { deftexttype len2-4 { minLength 2 maxLength 4 } tdom::schema s1 s1 define { deftexttype len2-4 { minLength 2 maxLength 4 } defelement doc { element e ! {text type len2-4} } } defelement doc { element e ! {text type len2-4} } } set result [list] foreach xml { { } {1} {12} { } {123} {1234} {1234 } {12345} {123ሴ} } { lappend result [s validate $xml] lappend result [s1 validate $xml] set rc [catch {dom parse -validateCmd s $xml doc}] if {$rc == 0} { $doc delete } lappend result $rc set rc [catch {dom parse -validateCmd s1 $xml doc}] if {$rc == 0} { $doc delete } lappend result $rc } s1 delete s delete set result } {0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 0 0 1 1 0 0 1 1 1 1 0 0} test schema-14.19 {deftexttype} { tdom::schema s s deftexttype len2-4 { minLength 2 maxLength 4 } s defelement doc { element e } s defelement e { attribute this type len2-4 attribute foo ? type len2-4 } set result [list] foreach xml { {} {} {} {} {} {} {} {} {} } { lappend result [s validate $xml errMsg] set rc [catch {dom parse -validateCmd s $xml doc}] if {$rc == 0} { $doc delete } lappend result $rc } s delete set result } {0 1 0 1 1 0 0 1 1 0 0 1 1 0 0 1 0 1 0 1} test schema-14.19a {deftexttype} { tdom::schema s s deftexttype len2-4 { minLength 2 maxLength 4 } s defelement doc { element e ! { attribute this type len2-4 attribute foo ? type len2-4 } } set result [list] foreach xml { {} {} {} {} {} {} {} {} {} } { lappend result [s validate $xml] set rc [catch {dom parse -validateCmd s $xml doc}] if {$rc == 0} { $doc delete } lappend result $rc } s delete set result } {0 1 0 1 1 0 0 1 1 0 0 1 1 0 0 1 0 1 0 1} test schema-14.20 {deftexttype} { tdom::schema s s deftexttype len2-4 { minLength 2 maxLength 4 } s defelement doc { element e ! { nsattribute this http://tdom.org/test { minLength 2 maxLength 4 } nsattribute foo http://tdom.org/test ? type len2-4 } } set result [list] foreach xml { {} {} {} {} {} {} {} {} {} } { lappend result [s validate $xml] } s delete set result } {0 0 1 0 1 0 1 0 0 0} test schema-14.20a {deftexttype} { tdom::schema s s deftexttype len2-4 { minLength 2 maxLength 4 } s define { prefixns { ns2 http://tdom.org/test nsfoo http://foo.bar ns2 http://baz.boo } defelement doc { element e ! { nsattribute this ns2 { minLength 2 maxLength 4 } nsattribute foo ns2 ? type len2-4 } } } set result [list] foreach xml { {} {} {} {} {} {} {} {} {} } { lappend result [s validate $xml] } s delete set result } {0 0 1 0 1 0 1 0 0 0} test schema-14.21 {strip} { tdom::schema s s define { defelement a { text { strip { minLength 3 maxLength 5 } } } } set result [list] foreach xml { { } { 3 } {123} { 123 } { 123 } {1234} {12345} {123456} { 12 34 } } { lappend result [s validate $xml] } s delete set result } {0 0 0 0 1 1 1 1 1 0 1} test schema-14.22 {split} { tdom::schema s s define { defelement doc { element a 1 { text { split { number } } } } } set result [list] foreach xml { { } {1} {-2.1} { -2.1 } {-a} {-a b c} { 1 2 3.5} { 1 a 3.5} {1 2 fooo} {1 2 fooo } } { lappend result [s validate $xml] } s delete set result } {0 0 0 1 1 1 0 0 1 0 0 0} proc schema-14.23 {text} { return [split $text] } test schema-14.23 {split} { tdom::schema s s define { defelement doc { element a 1 { text { split tcl schema-14.23 { number } } } } } set result [list] foreach xml { { } {1} {-2.1} { -2.1 } {-a} {-a b c} {1 2 3.5} { 1 a 3.5} {1 2 fooo} {1 2 3 -4.5} } { lappend result [s validate $xml errMsg] } s delete set result } {0 0 0 1 1 0 0 0 0 0 0 1} proc schema-14.24 {text} { global schema-14.24 switch ${schema-14.24} { 1 {return {1 2 3}} 2 {return {-23.4 .5}} 3 {return {0 a 5}} default {error "Unexpected value of the global var schema-14.24."} } } test schema-14.24 {split} { set schema-14.24 0 tdom::schema s s define { defelement doc { element a 1 { text { split tcl schema-14.24 { number } } } } } set result [list] foreach xml { { } {-a} {1 2 3 -4.5} } { incr schema-14.24 lappend result [s validate $xml errMsg] } s delete set result } {1 1 0} proc schema-14.24a {arg1 arg2 text} { global schema-14.24a if {$arg1 ne "foo" || $arg2 ne "bar"} { error "Unexpected args" } switch ${schema-14.24a} { 1 {return {1 2 3}} 2 {return {-23.4 .5}} 3 {return {0 a 5}} default {error "Unexpected value of the global var schema-14.24."} } } test schema-14.24a {split} { set schema-14.24a 0 tdom::schema s s define { defelement doc { element a 1 { text { split tcl schema-14.24a foo bar { number } } } } } set result [list] foreach xml { { } {-a} {1 2 3 -4.5} } { incr schema-14.24a lappend result [s validate $xml] } s delete set result } {1 1 0} test schema-14.25 {element content id/idref} { tdom::schema s s define { defelement doc { interleave { element id * element idref * } } defelement id {text id} defelement idref {text idref} } set result [list] foreach xml { abc abc abcabc abcabc abcabcabc abcabcabc {abcabcab c} abcabcabc abc123 } { lappend result [s validate $xml] } s delete set result } {1 1 0 1 1 1 1 0 0 0} test schema-14.26 {attribute id/idref} { tdom::schema s s define { defelement doc { interleave { element id * element idref * } } defelement id {attribute id id} defelement idref {attribute idref idref} } set result [list] foreach xml { {} {} {} {} {} {} {} {} {} } { lappend result [s validate $xml] } s delete set result } {1 1 0 1 1 1 1 0 0 0} test schema-14.27 {base64} { tdom::schema s s define { defelement doc { text base64 } } set result [list] foreach xml { {ZVL1} {zvL1} {zvü1} {0a BED E+9} {ub1sU3==} {abc} {===} } { lappend result [s validate $xml] } s delete set result } {1 1 1 0 1 1 0 0} test schema-14.28 {element content id/idref} { tdom::schema s s define { defelement doc { interleave { element id * element idref * element ida * element idrefa * } } defelement id {text id} defelement idref {text idref} defelement ida {text {id a}} defelement idrefa {text {idref a}} } set result [list] foreach xml { abcabc abc abcabc 1abcabcfooabc abcabcabcabc abcabcabcabc } { lappend result [s validate $xml] } s delete set result } {1 1 0 0 0 1 1} test schema-14.29 {element content id/idref} { tdom::schema s s define { defelement doc { interleave { element id * element idref * element ida * element idrefa * } } defelement id {text {id b}} defelement idref {text {idref b}} defelement ida {text {id a}} defelement idrefa {text {idref a}} } set result [list] foreach xml { abcabc abc abcabc 1abcabcfooabc abcabcabcabc abcabcabcabc } { lappend result [s validate $xml] } s delete set result } {1 1 0 0 0 1 1} test schema-14.30 {text: boolean (xsd)} { tdom::schema s s defelement doc { text boolean } set result [list] foreach xml { 5 00 01 1 11 false {false } False FALSE true { true} TrUe } { lappend result [s validate $xml] } s delete set result } {0 0 0 0 0 1 0 1 0 0 0 1 0 0} test schema-14.30a {text: boolean (xsd)} { tdom::schema s s defelement doc { text {boolean xsd} } set result [list] foreach xml { 5 00 01 1 11 false {false } False FALSE true { true} TrUe } { lappend result [s validate $xml] } s delete set result } {0 0 0 0 0 1 0 1 0 0 0 1 0 0} test schema-14.31 {text: boolean (tcl)} { tdom::schema s s defelement doc { text {boolean tcl} } set result [list] foreach xml { 5 0 01 1 11 false f no {no } n { n } {false } False FALSE true { true} TrUe ON } { lappend result [s validate $xml] } s delete set result } {0 0 0 1 0 1 0 1 1 1 0 1 0 0 1 1 1 0 1 1} test schema-14.32 {text: negativeInteger} { tdom::schema s s defelement doc { text negativeInteger } set result [list] foreach xml { 5782 3 +2 +002 1 01 +0 +000 0 -0 -000 -002 -1 -12345 - + { } { -23 } } { lappend result [s validate $xml] } s delete set result } {0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0} test schema-14.32.1 {text: negativeInteger tcl} { tdom::schema s s defelement doc { text {negativeInteger tcl} } set result [list] foreach xml { 5782 3 +2 +002 1 01 +0 +000 0 -0 -000 -002 -1 -12345 - + { } { -23 } } { lappend result [s validate $xml] } s delete set result } {0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 1} test schema-14.33 {text: nonNegativeInteger} { tdom::schema s s defelement doc { text nonNegativeInteger } set result [list] foreach xml { 5782 3 +2 +002 1 01 +0 +000 0 -0 -000 -002 -1 -12345 - + { } } { lappend result [s validate $xml] } s delete set result } {0 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0} test schema-14.33.1 {text: nonNegativeInteger tcl} { tdom::schema s s defelement doc { text {nonNegativeInteger tcl} } set result [list] foreach xml { 5782 3 +2 +002 1 01 +0 +000 0 -0 -000 -002 -1 -12345 - + { } } { lappend result [s validate $xml] } s delete set result } {0 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0} test schema-14.34 {text: nonPositiveInteger} { tdom::schema s s defelement doc { text nonPositiveInteger } set result [list] foreach xml { 5782 3 +2 +002 1 01 +0 +000 0 -0 -000 -002 -1 -12345 - + { } } { lappend result [s validate $xml] } s delete set result } {0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0} test schema-14.34.1 {text: nonPositiveInteger tcl} { tdom::schema s s defelement doc { text {nonPositiveInteger tcl} } set result [list] foreach xml { 5782 3 +2 +002 1 01 +0 +000 0 -0 -000 -002 -1 -12345 - + { } } { lappend result [s validate $xml] } s delete set result } {0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0} test schema-14.35 {text: positiveInteger} { tdom::schema s s defelement doc { text positiveInteger } set result [list] foreach xml { 5782 3 +2 +002 1 01 +0 +000 0 -0 -000 -002 -1 -12345 - + { } } { lappend result [s validate $xml] } s delete set result } {0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0} test schema-14.35.1 {text: positiveInteger tcl} { tdom::schema s s defelement doc { text {positiveInteger tcl} } set result [list] foreach xml { 5782 3 +2 +002 1 01 +0 +000 0 -0 -000 -002 -1 -12345 - + { } } { lappend result [s validate $xml] } s delete set result } {0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0} test schema-14.36 {text: hexBinary} { tdom::schema s s defelement doc { text {hexBinary} } set result [list] foreach xml { 5782 3ABCDEF0 +2 2 abcd abcde abcdef abcdefg { a0123b} {a0123b } a0123b } { lappend result [s validate $xml] } s delete set result } {0 1 1 0 0 1 0 1 0 0 0 1} test schema-14.37 {text: unsignedByte} { tdom::schema s s defelement doc { text {unsignedByte} } set result [list] foreach xml { 7 +255 -255 -000255 256 65535 000000000000000065535 65536 4294967295 00000000000000004294967295 4294967296 18446744073709551615 018446744073709551615 18446744073709551616 28446744073709551614 3ABCDEF0 { a0123b} {a0123b } a0123b 1.2 } { lappend result [s validate $xml] } s delete set result } {0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0} test schema-14.38 {text: unsignedShort} { tdom::schema s s defelement doc { text {unsignedShort} } set result [list] foreach xml { 7 +255 -255 -000255 256 65535 000000000000000065535 65536 4294967295 00000000000000004294967295 4294967296 18446744073709551615 018446744073709551615 18446744073709551616 28446744073709551614 3ABCDEF0 { a0123b} {a0123b } a0123b 1.2 } { lappend result [s validate $xml] } s delete set result } {0 1 1 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0} test schema-14.39 {text: unsignedInt} { tdom::schema s s defelement doc { text {unsignedInt} } set result [list] foreach xml { 7 +255 -255 -000255 256 65535 000000000000000065535 65536 4294967295 00000000000000004294967295 4294967296 18446744073709551615 018446744073709551615 18446744073709551616 28446744073709551614 3ABCDEF0 { a0123b} {a0123b } a0123b 1.2 } { lappend result [s validate $xml] } s delete set result } {0 1 1 0 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0} test schema-14.40 {text: unsignedLong} { tdom::schema s s defelement doc { text {unsignedLong} } set result [list] foreach xml { 7 +255 -255 -000255 256 65535 000000000000000065535 65536 4294967295 00000000000000004294967295 4294967296 18446744073709551615 018446744073709551615 18446744073709551616 28446744073709551614 3ABCDEF0 { a0123b} {a0123b } a0123b 1.2 } { lappend result [s validate $xml] } s delete set result } {0 1 1 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0} test schema-14.37.1 {text: byte} { tdom::schema s s defelement doc { text {byte} } set result [list] foreach xml { 7 +127 -128 -129 -0002 128 { 34} 0 {101 } a } { lappend result [s validate $xml] } s delete set result } {0 1 1 1 0 1 0 0 1 0 0} test schema-14.38.1 {text: short} { tdom::schema s s defelement doc { text {short} } set result [list] foreach xml { 7 +255 -255 -000255 256 32767 32768 -32768 -32769 -0 -b } { lappend result [s validate $xml] } s delete set result } {0 1 1 1 1 1 1 0 1 0 1 0} test schema-14.41 {text constrains commands outside text constraint} {8.5} { set cmds [info command tdom::schema::text::*] set result {} tdom::schema s foreach cmd $cmds { lappend result [catch {$cmd "some text"}] lappend result [catch { s define [subst "{$cmd}"] } errMsg] lappend result [catch { s define [subst { start doc $cmd }] } errMsg] lappend result [catch { s define [subst { start doc defelement doc { $cmd } }] } errMsg] } if {$result eq [lrepeat [expr {[llength $cmds] * 4}] 1]} { set result 1 } else { set result 0 } set result } 1 test schema-14.43 {text constraint setvar} { tdom::schema s namespace eval ::schema-14.43 { } s defelement doc { text { setvar from_schema-14.43 setvar ::schema-14.43::foo } } s validate "this" s delete list ${::schema-14.43::foo} ${from_schema-14.43} } {this this} test schema-14.44 {text constraint setvar} { tdom::schema s namespace eval ::schema-14.43 { } s defelement doc { element a ! {text {setvar from_schema-14.44}} element b ! {text {setvar from_schema-14.44}} } set result [s validate "ab"] s delete lappend result ${from_schema-14.44} } {1 b} test schema-14.45 {text constraint whitespace} { tdom::schema s s defelement doc { text { whitespace preserve { oneOf { fixed foo allOf { minLength 5 integer } } } } } set result [list] foreach xml { foo 12345 1234 1234a } { lappend result [s validate $xml] } s delete set result } {0 0 1 1 0 0} test schema-14.46 {text constraint whitespace} { tdom::schema s s defelement doc { text { whitespace replace { fixed "foo bar" } } } set result [list] foreach xml { {foo bar} {foo bar} {foo bar} {foo bar} } { lappend result [s validate $xml] } s delete set result } {0 0 1 1 1 0} test schema-14.47 {text constraint whitespace} { tdom::schema s s defelement doc { text { whitespace collapse { fixed "foo bar" } } } set result [list] foreach xml { {foo bar} {foo bar} {foo bar} {foo bar} { foo bar } { foo bar rr} } { lappend result [s validate $xml] } s delete set result } {0 0 1 1 1 1 1 0} test schema-14.48 {text constraint whitespace} { tdom::schema s s defelement doc { text { whitespace preserve { fixed "foo[string repeat " " 300]bar" } } } set xmls { } lappend xmls "foo[string repeat " " 300]bar" set result [list] foreach xml $xmls { lappend result [s validate $xml] } s delete set result } {0 1} test schema-14.49 {text constraint whitespace} { tdom::schema s s defelement doc { text { whitespace collapse { fixed "foo [string repeat "x" 1200]bar" } } } set xmls { } lappend xmls "[string repeat " " 300]foo[string repeat " " 300][string repeat "x" 1200]bar[string repeat " " 300]" set result [list] foreach xml $xmls { lappend result [s validate $xml] } s delete set result } {0 1} test schema-14.50 {text constraint whitespace} { tdom::schema s s defelement doc { element b ! { text { whitespace replace { fixed "foo[string repeat " " 400]bar" } } } } set xml append xml foo [string repeat " \t " 100] bar append xml set result [s validate $xml] s delete set result } 1 test schema-14.51 {text constraint whitespace} { tdom::schema s s defelement doc { element a ! { text { whitespace collapse { fixed "foo [string repeat "x" 1200]bar" } } } element b ! { text { whitespace replace { fixed "foo[string repeat " " 8000]bar" } } } } set xml append xml [string repeat " " 20] foo " " [string repeat x 1200] bar \ [string repeat " " 8000] append xml foo [string repeat " \t " 2000] bar append xml set result [s validate $xml] s delete set result } 1 test schema-14.52 {text constraint whitespace} { tdom::schema s s defelement doc { element a + { text { not { fixed foo fixed bar } } } } set result "" foreach xml { foo bar grill grill bar } { lappend result [s validate $xml] } s delete set result } {0 0 1 1 1 0} test schema-14.54 {text constraint dateTime} { tdom::schema s s define { defelement doc { text dateTime } } set result "" foreach xml { foo 1 2020-07-08T15:58:17 2020-07-08T15:20:00 2020-07-08T15:20:17.7 2020-07-08T15:58:17+02:00 2020-07-08T15:20:17.789 2020-07-08T15:20:17.7890 2020-07-08T15:20:17.0 2020-07-08T15:20:17. 2020-07-08T15:20:17.+02:00 2020-07-08T15:20:17.Z 2020-07-08T15:20:17+Z 2020-07-08T00:20 2020-07-08T00:60:00 2020-07-08T24:00:00 2020-07-08T24:00:00.1 2020-07-08T24:01:00 2020-07-08T24:00:01 2020-12-2215:20:00 2020-12-22 2020-07-08T15:20:17.789+02:00 2020-07-08T15:20:17-02:00 2020-07-08T15:20:17-02:00.0 2020-07-08T15:20:17.0-02:00 " 2020-07-08T15:20:17.0-02:00" "2020-07-08T15:20:17.0-02:00 " } { lappend result [s validate $xml] } s delete set result } {0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 1 0 0 0 0 0 1 1 0 1 0 0} test schema-14.55 {text constraint time} { tdom::schema s s define { defelement doc { text time } } set result "" foreach xml { foo 1 15:58:17 15:20:00 15:20:17.7 15:58:17+02:00 15:20:17.789 15:20:17.7890 15:20:17.0 15:20:17. 15:20:17.+02:00 15:20:17.Z 15:20:17+Z 00:20 00:60:00 24:00:00 24:00:00.1 24:01:00 24:00:01 15:20:17.789+02:00 15:20:17-02:00 15:20:17-02:00.0 15:20:17.0-02:00 " 15:20:17.0-02:00" "T15:20:17.0-02:00 " } { lappend result [s validate $xml] } s delete set result } {0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 1 0 0 0 1 1 0 1 0 0} test schema-14.56 {length} { tdom::schema s s defelement doc { element e ! { text {length 2} } } set result [list] foreach xml { {1} {12} { } {123} {1ሴ} } { lappend result [s validate $xml] set rc [catch {dom parse -validateCmd s $xml doc}] if {$rc == 0} { $doc delete } lappend result $rc } s delete set result } {0 1 0 1 0 1 1 0 1 0 0 1 1 0} test schema-14.57 {length} { tdom::schema s s defelement doc { element e ! { text {length 0} } } set result [list] foreach xml { {1} {12} { } } { lappend result [s validate $xml] } s delete set result } {1 1 0 0 0} test schema-14.58 {text constraint command syntax} { tdom::schema s s deftexttype len2-4 { minLength 2 maxLength 4 } set result [catch {s defelement doc { element e ! {text typs len2-4} }}] s delete set result } 1 test schema-14.59 {Tcl error in text constraint script} { tdom::schema s s defelement doc { element a } set result [catch { s defelement a { text {error "triggered"} } }] s delete set result } 1 test schema-14.60 {Empty element} { tdom::schema s s defelement doc { element a } s defelement a { attribute att ? } ::xml::parser p -validateCmd s set result [list] foreach xml { { } { } { } { } } { lappend result [s validate $xml] lappend result [catch {p parse $xml}] set doc "" lappend result [catch {set doc [dom parse -validateCmd s $xml]}] if {$doc ne ""} { $doc delete } } s delete p delete set result } {0 1 1 1 0 0 1 0 0 1 0 0 1 0 0 0 1 1} test schema-14.61 {Empty element} { tdom::schema s s defelement doc { element a } s defelement a { attribute att ? text } ::xml::parser p -validateCmd s set result [list] foreach xml { { } { } { } { } } { lappend result [s validate $xml] lappend result [catch {p parse $xml}] set doc "" lappend result [catch {set doc [dom parse -validateCmd s $xml]}] if {$doc ne ""} { $doc delete } } s delete p delete set result } {0 1 1 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0} test schema-14.62 {Empty element} { tdom::schema s s defelement doc { element a } ::xml::parser p -validateCmd s set result [list] foreach xml { { } { } { } { } } { lappend result [s validate $xml] lappend result [catch {p parse $xml}] set doc "" lappend result [catch {set doc [dom parse -validateCmd s $xml]}] if {$doc ne ""} { $doc delete } } s delete p delete set result } {0 1 1 1 0 0 1 0 0 1 0 0 0 1 1 0 1 1} test schema-14.63 {type} { tdom::schema s s define { defelement doc { element e + { text { type len2-4 integer } } } deftexttype len2-4 { minLength 2 maxLength 4 } } set result [list] foreach xml { 1 12 12a } { lappend result [s validate $xml] } s delete set result } {0 1 0} test schema-14.64 {text type} { tdom::schema s s define { defelement doc { element child 1 { attribute attr ? { type ns1:mytype } } } deftexttype ns1:mytype { integer } } set result [list] foreach xml { {} {} {} {} {} {} } { lappend result [s validate $xml] } set result } {1 1 0 0 0 0} test schema-14.65 {text type} { tdom::schema s s define { defelement doc { element child 1 { attribute attr ? { type ns1:mytype } } } } set result [list] foreach xml { {} {} {} {} {} {} } { lappend result [s validate $xml] } set result } {1 1 1 1 0 0} test schema-15.1 {constraint cmd tcl} { tdom::schema s s define { defelement a { tcl append ::schema-15.1 [self] element b tcl append ::schema-15.1 [self] } } set ::schema-15.1 "" set msg "nottouched" set result [s validate {} msg] s delete lappend result $msg ${::schema-15.1} set result } {1 nottouched ss} proc schema-15.2-astart {args} { append ::schema-15.2 astart } proc schema-15.2-aend {args} { append ::schema-15.2 aend } test schema-15.2 {constraint cmd tcl} { tdom::schema s s define { defelement doc { element a * } defelement a { tcl schema-15.2-astart element b ! text element c ! text tcl schema-15.2-aend } } set schema-15.2 "" set msg "nottouched" set result [s validate {foobar} msg] s delete lappend result $msg ${schema-15.2} set result } {1 nottouched astartaendastartaend} proc schema-15.3 {type cmd} { lappend ::schema-15.3 $type [$cmd info stack top] } test schema-15.3 {constraint cmd tcl} {8.5} { tdom::schema s s define { defelement doc { element a * } defelement a { tcl schema-15.3 astart [self] element b ! text element c ! text tcl schema-15.3 aend [self] } } set schema-15.3 "" set msg "nottouched" set result [s validate {foobar} msg] s delete lappend result $msg {*}${schema-15.3} set result } {1 nottouched astart a aend a astart a aend a} proc schema-15.4 {text cmd} { if {$text ne "in docContent"} {error "unexpected text argument"} set ::schema-15.4 [$cmd info stack inside] } test schema-15.4 {constraint cmd tcl} { tdom::schema s s define { defelement doc { ref docContent } defpattern docContent { element a tcl schema-15.4 "in docContent" [self] text element b } } set schema-15.4 "" set result [s validate {foo}] s delete lappend result [set schema-15.4] set result } {1 doc} test schema-16.1 {interleave} { tdom::schema s s define { defelement doc { interleave { element a element b element c } } foreach e {a b c} { defelement $e {} } } set result [list] foreach xml { 12 } { lappend result [s validate $xml] } s delete set result } {0 1 1 1 0 0 0} # It's in fact a missing feature: handling ambiguity. # test schema-16.2 {interleave} {knownBug} { # tdom::schema s # s define { # defelement doc { # interleave { # element a 1 { # attribute type {fixed foo} # } # element a 1 { # attribute type {fixed bar} # } # element a 1 { # attribute type {fixed grill} # } # } # } # foreach e {a b c} { # defelement $e {} # } # } # set result [list] # foreach xml { # # {} # {} # {} # {} # {} # 12 # } { # lappend result [s validate $xml] # } # s delete # set result # } {0 1 1 1 0 0} test schema-16.3 {interleave} { tdom::schema s s define { defelement doc { interleave { element a element b + element c } } foreach e {a b c} { defelement $e {} } } set result [list] foreach xml { 12 } { lappend result [s validate $xml] } s delete set result } {0 1 1 1 1 0 0} test schema-16.4 {interleave} { tdom::schema s s define { defelement doc { interleave { element a element b ? element c } } foreach e {a b c} { defelement $e {} } } set result [list] foreach xml { 12 } { lappend result [s validate $xml] } s delete set result } {0 1 1 1 0 1 0} test schema-16.5 {interleave} { tdom::schema s s define { defelement doc { interleave { element a element b * element c } } foreach e {a b c} { defelement $e {} } } set result [list] foreach xml { 12 } { lappend result [s validate $xml] } s delete set result } {0 1 1 1 1 1 0} test schema-16.6 {interleave} { tdom::schema s s define { foreach e {a b1 b2 c} { defelement $e {} } defelement doc { interleave { element a group * { element b1 element b2 } element c } } } set result [list] foreach xml { 12 } { lappend result [s validate $xml] } s delete set result } {0 1 1 1 0 1 1 0} test schema-16.7 {interleave} { tdom::schema s s define { foreach e {a b1 b2 c} { defelement $e {} } defelement doc { interleave { element a group { element b1 element b2 } element c } } } set result [list] foreach xml { 12 } { lappend result [s validate $xml] } s delete set result } {0 1 1 1 0 0 0 0} test schema-16.8 {interleave} { tdom::schema s s define { foreach e {a b1 b2 c} { defelement $e {} } defelement doc { interleave { element a group ? { element b1 element b2 } element c } } } set result [list] foreach xml { 12 } { lappend result [s validate $xml] } s delete set result } {0 1 1 1 0 0 1 0} test schema-16.9 {interleave} { tdom::schema s s define { foreach e {a b1 b2 c} { defelement $e {} } defelement doc { interleave { element a group + { element b1 element b2 } element c } } } set result [list] foreach xml { 12 } { lappend result [s validate $xml] } s delete set result } {0 1 1 1 0 1 0 0} test schema-16.10 {interleave} { tdom::schema s s define { foreach e {a b1 b2 c} { defelement $e {} } defelement doc { interleave { element a group ? { element b1 element b2 } element c } } } set result [list] foreach xml { 12 } { lappend result [s validate $xml] } s delete set result } {0 1 1 1 0 0 1 0} test schema-16.11 {interleave} { tdom::schema s s define { foreach e {a b1 b2 c} { defelement $e {} } defelement doc { interleave { element a choice { element b1 element b2 } element c } } } set result [list] foreach xml { 12 } { lappend result [s validate $xml] } s delete set result } {0 1 1 1 0 0 0 0} test schema-16.12 {interleave} { tdom::schema s s define { foreach e {a b1 b2 c} { defelement $e {} } defelement doc { interleave { element a choice ? { element b1 element b2 } element c } } } set result [list] foreach xml { 12 } { lappend result [s validate $xml] } s delete set result } {0 1 1 1 0 0 1 0} test schema-16.13 {interleave} { tdom::schema s s define { foreach e {a b1 b2 c} { defelement $e {} } defelement doc { interleave { element a choice + { element b1 element b2 } element c } } } set result [list] foreach xml { 12 } { lappend result [s validate $xml] } s delete set result } {0 1 1 1 1 1 0 0} test schema-16.14 {interleave} { tdom::schema s s define { foreach e {a b1 b2 c} { defelement $e {} } defelement doc { interleave { element a choice * { element b1 element b2 } element c } } } set result [list] foreach xml { 12 } { lappend result [s validate $xml] } s delete set result } {0 1 1 1 1 1 1 0} test schema-16.15 {interleave} { tdom::schema s s define { foreach e {a b1 b11 b2 c} { defelement $e {} } defelement doc { interleave { element a choice * { element b1 group { element b11 element b2 } } element c } } } set result [list] foreach xml { 12 } { lappend result [s validate $xml] } s delete set result } {0 1 0 1 0 1 1 0} test schema-16.16 {interleave} { tdom::schema s s define { foreach e {a b1 b11 b2 c} { defelement $e {} } defelement items { interleave { element a element b ? } element c } defelement doc { element items + } } set result [list] foreach xml { {} {} {} } { lappend result [s validate $xml errMsg] } s delete set result } {1 1 0} test schema-16.17 {interleave with all child cp optional} { tdom::schema s s defelement doc { interleave { element a ? element b ? element c ? } element d } set result [list] foreach xml { } { lappend result [s validate $xml] } s delete set result } {0 1 1 1 1 1 1 1 0 1} test schema-16.18 {interleave with all content cp optional} { tdom::schema s s defelement doc { interleave { element a ? element b ? choice { element c ? element c1 ? element c2 ? } } } set result [list] foreach xml { } { lappend result [s validate $xml] } s delete set result } {1 1 1 1 1 1 1 0 1 1 0} test schema-16.19 {interleave with all child cp optional} { tdom::schema s s defelement doc { interleave { element a ? element b ? choice { element c ? element c1 ? element c2 ? } } element d } set result [list] foreach xml { } { lappend result [s validate $xml] } s delete set result } {0 1 1 1 1 1 1 1 0 1} test schema-16.20 {interleave with all child cp optional} { tdom::schema s s defelement doc { interleave { element a ? element b ? group { element c ? element c1 ? element c2 ? } } element d } set result [list] foreach xml { } { lappend result [s validate $xml] } s delete set result } {0 1 1 1 1 1 1 1 0 1} test schema-16.21 {interleave with all child cp optional} { tdom::schema s s defelement doc { interleave { element a ? element b ? group { element c ? element c1 ? element c2 ? } } } set result [list] foreach xml { } { lappend result [s validate $xml] } s delete set result } {1 1 1 1 1 1 1 0 1 1 0 1 0 1 0} test schema-16.22 {interleave} { tdom::schema s s defelement doc { interleave { element a element b * } } set result [list] foreach xml { } { lappend result [s validate $xml] } s delete set result } {0 1 0 1 1 1 1 0} test schema-17.1 {info} { tdom::schema s s define { foreach e {a b1 b11 b2 c} { defelement $e {} } } set result [lsort [s info definedElements]] s delete set result } {a b1 b11 b2 c} test schema-17.2 {info} { tdom::schema s s define { defelement b { element b1 element b2 } defelement a { element a1 element a2 } } set result [lsort [s info definedElements]] s delete set result } {a b} test schema-17.3 {info} { tdom::schema s s define { defelement b { element b1 1 text element a element b2 } defelement a { element a1 element a2 } } set result [lsort [s info definedElements]] s delete set result } {a b} test schema-17.3a {info definedElements} { tdom::schema s s define { prefixns {ns1 http://ns1.foo ns2 http://ns2.foo} defelement b ns1 { element b1 1 text element a element b2 } defelement b ns2 { element b1 1 text element a element b2 } defelement b { element b1 1 text element a element b2 } defelement a { element a1 element a2 } } set result [lsort -command sortcps [s info definedElements]] s delete set result } {a b {b http://ns1.foo} {b http://ns2.foo}} test schema-17.4 {info} { tdom::schema s s define { defelement b { element b1 1 text element a element b2 } defelement a { element a1 element a2 } } set result [s info definition b] s delete set result } {defelement b { element b1 1 text element a element b2 }} test schema-17.5 {info expected} { tdom::schema s s define { defelement doc { choice ? { element a element c element b } element toplevel ? element musthave element aftermust } } s event start doc set result [s info expected] s delete lsort $result } {a b c musthave toplevel} test schema-17.5a {info expected -ignorematched} { tdom::schema s s define { defelement doc { choice ? { element a element c element b } element toplevel ? element musthave element aftermust } } s event start doc set result [s info expected -ignorematched] s delete lsort $result } {a b c musthave toplevel} test schema-17.5b {info expected} { tdom::schema s s define { defelement doc { choice ? { element a element c element b } element toplevel ? element musthave element aftermust } } s event start doc set result [s info expected -onlymandatory] s delete lsort $result } {musthave} test schema-17.6 {info expected} { tdom::schema s s prefixns {foo http://foo.bar} s define { defelement doc { choice ? { element a element c element b } element toplevel ? namespace foo { element musthave } element aftermust } } s event start doc set result [s info expected] s delete lsort $result } {a b c {musthave http://foo.bar} toplevel} test schema-17.6a {info expected -ignorematched} { tdom::schema s s prefixns {foo http://foo.bar} s define { defelement doc { choice ? { element a element c element b } element toplevel ? namespace foo { element musthave } element aftermust } } s event start doc set result [s info expected -ignorematched] s delete lsort $result } {a b c {musthave http://foo.bar} toplevel} test schema-17.6b {info expected -onlymandatory} { tdom::schema s s prefixns {foo http://foo.bar} s define { defelement doc { choice ? { element a element c element b } element toplevel ? namespace foo { element musthave } element aftermust } } s event start doc set result [s info expected -onlymandatory] s delete lsort $result } {{musthave http://foo.bar}} test schema-17.7 {info expected} {listformat} { tdom::schema s s prefixns {foo http://foo.bar} s define { defelement doc { mixed { element a element c element b } element toplevel ? namespace foo { element musthave } element aftermust } } s event start doc set result [s info expected] s delete lsort $result } {a b c {musthave http://foo.bar} toplevel {{#text} {}}} test schema-17.7a {info expected -ignorematched} {listformat} { tdom::schema s s prefixns {foo http://foo.bar} s define { defelement doc { mixed { element a element c element b } element toplevel ? namespace foo { element musthave } element aftermust } } s event start doc set result [s info expected -ignorematched] s delete lsort $result } {a b c {musthave http://foo.bar} toplevel {{#text} {}}} test schema-17.7b {info expected -onlymandatory} { tdom::schema s s prefixns {foo http://foo.bar} s define { defelement doc { mixed { element a element c element b } element toplevel ? namespace foo { element musthave } element aftermust } } s event start doc set result [s info expected -onlymandatory] s delete lsort $result } {{musthave http://foo.bar}} test schema-17.8 {info expected} {8.5} { tdom::schema s s defelement doc { choice ? { element a element c element b } element toplevel ? element musthave element aftermust } set result [s info expected] s define { foreach elm {a b c} { defelement $elm {} } } lappend result {*}[lsort [s info expected]] s event start doc lappend result {*}[lsort [s info expected]] s event start c s event end lappend result {*}[lsort [s info expected]] s delete set result } {doc a b c doc a b c musthave toplevel musthave toplevel} test schema-17.8a {info expected -ignorematched} {8.5} { tdom::schema s s defelement doc { choice ? { element a element c element b } element toplevel ? element musthave element aftermust } set result [s info expected -ignorematched] s define { foreach elm {a b c} { defelement $elm {} } } lappend result {*}[lsort [s info expected -ignorematched]] s event start doc lappend result {*}[lsort [s info expected -ignorematched]] s event start c s event end lappend result {*}[lsort [s info expected -ignorematched]] s delete set result } {doc a b c doc a b c musthave toplevel musthave toplevel} test schema-17.8b {info expected -onlymandatory} {8.5} { tdom::schema s s defelement doc { choice ? { element a element c element b } element toplevel ? element musthave element aftermust } set result [s info expected -ignorematched] s define { foreach elm {a b c} { defelement $elm {} } } lappend result {*}[lsort [s info expected -onlymandatory]] s event start doc lappend result {*}[lsort [s info expected -onlymandatory]] s event start c s event end lappend result {*}[lsort [s info expected -onlymandatory]] s delete set result } {doc a b c doc musthave musthave} proc schema-17.9 {scmd} { global result foreach e [lsort [$scmd info expected]] { lappend result $e } } test schema-17.9 {info expected from scripted constrain} { tdom::schema s s define { defpattern some { element a ? group ? { element b ? tcl schema-17.9 [self] } element c } defelement doc { ref some ? element may ? element must } } set result "" lappend result [s validate {}] s delete set result } {a b c may must 1} test schema-17.9.1 {info expected from scripted constrain} { tdom::schema s s define { defpattern some { element a ? group ? { element b ? tcl schema-17.9 [self] } element c } defelement doc { element othermay ? ref some ? element may ? element must } } set result "" lappend result [s validate {}] s delete set result } {a b c may must othermay 1} proc schema-17.9a {scmd} { global result foreach e [lsort [$scmd info expected -onlymandatory]] { lappend result $e } } test schema-17.9a {info expected from scripted constrain} { tdom::schema s s define { defpattern some { element a ? group ? { element b ? tcl schema-17.9a [self] } element c } defelement doc { ref some ? element may ? element must } } set result "" lappend result [s validate {}] s delete set result } {must 1} test schema-17.9a.1 {info expected from scripted constrain} { tdom::schema s s define { defpattern some { element a ? group ? { element b ? tcl schema-17.9a [self] } choice ! { element c1 ref some ? } } defelement doc { ref some ? element may ? element must } } set result "" lappend result [s validate {}] s delete set result } {must 1} test schema-17.10 {info expected interleave} {8.5} { set defs { { interleave { element a ? element b element c ? } element d } { interleave { element a ? element b ? element c ? } element d } { interleave ? { element a ? element b element c ? } element d } } set result [list] foreach def $defs { tdom::schema s s defelement doc $def s event start doc lappend result {*}[lsort [s info expected]] s delete } set result } {a b c a b c d a b c d} test schema-17.10a {info expected interleave} {8.5} { set defs { { interleave { element a ? element b element c ? } element d } { interleave { element a ? element b ? element c ? } element d } { interleave ? { element a ? element b element c ? } element d } } set result [list] foreach def $defs { tdom::schema s s defelement doc $def s event start doc lappend result {*}[lsort [s info expected -ignorematched]] s delete } set result } {a b c a b c d a b c d} test schema-17.11 {info expected} { set defs { { group + { element c ? element a ? element b ? } element d } } set result [list] foreach def $defs { tdom::schema s s defelement doc $def s event start doc s event start b s event end set result [lsort [s info expected]] s delete } set result } {a b c d} test schema-17.11a {info expected} { set defs { { group + { element c ? element a ? element b ? } element d } } set result [list] foreach def $defs { tdom::schema s s defelement doc $def s event start doc s event start b s event end set result [lsort [s info expected -ignorematched]] s delete } set result } {d} test schema-17.12 {info expected} {8.5} { tdom::schema s s define { prefixns {ns1 http://foo.bar} defelement doc { element a any any ns1 ? element b ? } } s event start doc s event start a s event end set result [lsort [s info expected]] s event start something s event end lappend result {*}[lsort [s info expected]] s delete set result } {{ {}} { http://foo.bar} { {}} b} test schema-17.12a {info expected} {8.5} { tdom::schema s s define { prefixns {ns1 http://foo.bar} defelement doc { element a any any ns1 ? element b ? } } s event start doc s event start a s event end set result [lsort [s info expected -ignorematched]] s event start something s event end lappend result {*}[lsort [s info expected -ignorematched]] s delete set result } {{ {}} { http://foo.bar} { {}} b} test schema-17.12b {info expected} {8.5} { tdom::schema s s define { prefixns {ns1 http://foo.bar} defelement doc { element a any {""} any ns1 ? element b ? } } s event start doc s event start a s event end set result [lsort [s info expected]] s event start something s event end lappend result {*}[lsort [s info expected]] s delete set result } {{ {{}}} { http://foo.bar} { {}} b} test schema-17.12b {info expected} {8.5} { tdom::schema s s define { prefixns {ns1 http://foo.bar} defelement doc { element a any {"" ns1} any ns1 ? element b ? } } s event start doc s event start a s event end set result [lsort [s info expected]] s event start something s event end lappend result {*}[lsort [s info expected]] s delete set result } {{ {{} http://foo.bar}} { http://foo.bar} { {}} b} proc schema-17.13 {scmd args} { global fromReportCmd set fromReportCmd [lsort [$scmd info expected]] } test schema-17.13 {info expected} {8.5} { set defs { { element a element b ? } { element a ? element b } { element a ? element b ? } } set xmlinput { } set result [list] set defnr 0 foreach def $defs { tdom::schema s s defelement doc $def s reportcmd schema-17.13 set xmlnr 0 foreach xml $xmlinput { set fromReportCmd "" lappend result $defnr/$xmlnr: [s validate $xml errMsg] lappend result {*}$fromReportCmd incr xmlnr } s delete incr defnr } set result } {0/0: 1 a 0/1: 1 0/2: 1 a 0/3: 1 0/4: 1 a 0/5: 1 { {}} b 1/0: 1 a b 1/1: 1 b 1/2: 1 1/3: 1 1/4: 1 a b 1/5: 1 b 2/0: 1 2/1: 1 2/2: 1 2/3: 1 2/4: 1 { {}} a b 2/5: 1 { {}} b} proc schema-17.13a {scmd args} { global fromReportCmd set fromReportCmd [lsort [$scmd info expected -ignorematched]] } test schema-17.13a {info expected} {8.5} { set defs { { element a element b ? } { element a ? element b } { element a ? element b ? } } set xmlinput { } set result [list] set defnr 0 foreach def $defs { tdom::schema s s defelement doc $def s reportcmd schema-17.13a set xmlnr 0 foreach xml $xmlinput { set fromReportCmd "" lappend result $defnr/$xmlnr: [s validate $xml errMsg] lappend result {*}$fromReportCmd incr xmlnr } s delete incr defnr } set result } {0/0: 1 a 0/1: 1 0/2: 1 a 0/3: 1 0/4: 1 a 0/5: 1 { {}} b 1/0: 1 a b 1/1: 1 b 1/2: 1 1/3: 1 1/4: 1 a b 1/5: 1 b 2/0: 1 2/1: 1 2/2: 1 2/3: 1 2/4: 1 { {}} a b 2/5: 1 { {}} b} proc schema-17.14 {scmd args} { global result foreach e [lsort [$scmd info expected]] { lappend result $e } } test schema-17.14 {info expected} { set defs { { group + { element c ? element a ? element b ? } tcl schema-17.14 [self] element d } } set result [list] foreach def $defs { tdom::schema s s reportcmd schema-17.14 s defelement doc $def s event start doc s event start unknownElement s delete } set result } {a b c d a b c d} proc schema-17.14a {scmd args} { global result foreach e [lsort [$scmd info expected -ignorematched]] { lappend result $e } } test schema-17.14a {info expected} { set defs { { group + { element c ? element a ? element b ? } tcl schema-17.14 [self] element d } } set result [list] foreach def $defs { tdom::schema s s reportcmd schema-17.14 s defelement doc $def s event start doc s event start unknownElement s delete } set result } {a b c d a b c d} proc schema-17.15 {type cmd} { lappend ::result $type [$cmd info stack inside] } test schema-17.15 {info inside} { tdom::schema s s define { defelement doc { element a * } defelement a { tcl schema-17.15 astart [self] element b ! text element c ! text tcl schema-17.15 aend [self] } } set result {} s validate {foobar} s delete set result } {astart {a doc} aend {a doc} astart {a doc} aend {a doc}} test schema-17.16 {info expected} {8.5} { tdom::schema s s defelement doc { element a group { group { group { element aaaa element bbbb ? } element bbb ? } element bb ? } element b } set result [list] foreach xml { } { lappend result [s validate $xml] } s reportcmd schema-17.13 foreach xml { } { set fromReportCmd "" lappend result [s validate $xml] lappend result {*}$fromReportCmd } s delete set result } {0 0 1 1 aaaa 1 b bb bbb bbbb 1} test schema-17.16_1 {info expected} {8.5} { tdom::schema s s defelement doc { element a group { group { group { element aaaa element bbbb ? } element bbb ? } element bb ? } element b } set result [list] foreach xml { } { lappend result [s validate $xml] } s reportcmd schema-17.13 foreach xml { } { set fromReportCmd "" lappend result [s validate $xml] lappend result {*}$fromReportCmd } s delete set result } {0 0 1 1 aaaa 1 b bb bbb bbbb 1} test schema-17.16a {info expected} {8.5} { tdom::schema s s defelement doc { element a group { group { group { element aaaa * element bbbb ? } element bbb ? } element bb ? } element b } set result [list] foreach xml { } { lappend result [s validate $xml] } s reportcmd schema-17.13a foreach xml { } { set fromReportCmd "" lappend result [s validate $xml] lappend result {*}$fromReportCmd } s delete set result } {0 0 1 1 aaaa b bb bbb bbbb 1 b bb bbb bbbb 1} test schema-17.16a_1 {info expected} {8.5} { tdom::schema s s defelement doc { element a group { group { group { element aaaa * element bbbb ? } element bbb ? } element bb ? } element b } set result [list] foreach xml { } { lappend result [s validate $xml] } s reportcmd schema-17.13a foreach xml { } { set fromReportCmd "" lappend result [s validate $xml] lappend result {*}$fromReportCmd } s delete set result } {0 0 1 1 aaaa b bb bbb bbbb 1 b bb bbb bbbb 1} test schema-17.16b {info expected} {8.5} { tdom::schema s s defelement doc { element a group { group { group { element aaaa ? element bbbb ? } element bbb ? } element bb ? } element b } set result [list] foreach xml { } { lappend result [s validate $xml] } s reportcmd schema-17.13 foreach xml { } { set fromReportCmd "" lappend result [s validate $xml] lappend result {*}$fromReportCmd } s delete set result } {0 0 1 1 aaaa b bb bbb bbbb 1 b bb bbb bbbb 1} test schema-17.16c {info expected} {8.5} { tdom::schema s s defelement doc { element a group { group { group { element aaaa + element bbbb ? } element bbb ? } element bb ? } element b } set result [list] foreach xml { } { lappend result [s validate $xml] } s reportcmd schema-17.13 foreach xml { } { set fromReportCmd "" lappend result [s validate $xml] lappend result {*}$fromReportCmd } s delete set result } {0 0 1 1 aaaa 1 aaaa b bb bbb bbbb 1} proc schema-17.17 {scmd args} { global fromReportCmd set fromReportCmd [list [$scmd info line] [$scmd info column]] } test schema-17.17 {info expected} {8.5} { tdom::schema s s defelement doc { element a group { group { group { element aaaa + element bbbb ? } element bbb ? } element bb ? } element b } set result [list] foreach xml { } { lappend result [s validate $xml] } s reportcmd schema-17.17 foreach xml { } { set fromReportCmd "" lappend result [s validate $xml] lappend result {*}$fromReportCmd } s delete set result } {0 0 1 1 1 9 1 1 16 1} test schema-17.18 {info typedefinition} { tdom::schema s s prefixns {ns http://my.foo} s defelementtype a ns { element a type a element a type a2 } set result [s info typedefinition a ns] s delete set result } {defelementtype a http://my.foo { element a type a element a type a2 }} test schema-17.18a {info typedefinition} { tdom::schema s s prefixns {ns http://my.foo} s define { defelementtype a ns { element a type a element a type a2 } } set result [s info typedefinition a ns] s delete set result } {defelementtype a http://my.foo { element a type a element a type a2 }} proc schema-17.19 {schemacmd} { lappend ::result [$schemacmd info stack associated] } test schema-17.19 {info stack associated} { tdom::schema s s defelement doc { element a + } s defelement a { associate "fo bar baz" tcl schema-17.19 [self] } set result [list] foreach xml { } { lappend result [s validate $xml] } s delete set result } {{fo bar baz} 1 {fo bar baz} {fo bar baz} 1} test schema-17.19a {info stack associated} { tdom::schema s s defelement doc { element a + } s defelement a { associate "fo bar baz" tcl schema-17.19 [self] element b } set result [list] foreach xml { } { lappend result [s validate $xml] } s delete set result } {{fo bar baz} 1 {fo bar baz} {fo bar baz} 1} proc schema-17.20 {schemacmd args} { lappend ::result [$schemacmd info stack associated] } test schema-17.20 {info stack associated} { tdom::schema s s defelement doc { element a + } s defelement a { associate "fo bar baz" # Only local defined element b ? } s reportcmd schema-17.20 set result [list] foreach xml { } { lappend result [s validate $xml] } s delete set result } {{} 1 1 1 {fo bar baz} 1 {} 1} proc schema-17.21 {scmd errorInfo} { lappend ::result [$scmd info expected] } test schema-17.21 {info expected} { tdom::schema s s defelement doc { element a + {} element b ! {} } s reportcmd schema-17.21 set result "" lappend result [s validate {}] s delete set result } {{a b} 1} proc schema-17.21a {scmd errorInfo} { lappend ::result [$scmd info expected -ignorematched] } test schema-17.21a {info expected} { tdom::schema s s defelement doc { element a + {} element b ! {} } s reportcmd schema-17.21a set result "" lappend result [s validate {}] s delete set result } {b 1} proc schema-17.22 {scmd errorInfo} { global fromReportCmd if {[$scmd info vaction] eq "MATCH_ELEMENT_START"} { lappend fromReportCmd "matching [$scmd info vaction name]" "expecting [lsort [$scmd info expected]]" if {$errorInfo eq "MISSING_ELEMENT"} { return ignore } } else { lappend fromReportCmd "END_EVENT expecting [$scmd info expected]" } } test schema-17.22 {return "ignore" from recover script for MISSING_ELEMENT_MATCH_START} {8.5} { set defs { { element a element b element c } } set xmlinput { } set result [list] set defnr 0 foreach def $defs { tdom::schema s s defelement doc $def s reportcmd schema-17.22 set xmlnr 0 foreach xml $xmlinput { set fromReportCmd "" lappend result $defnr/$xmlnr: [s validate $xml errMsg] lappend result {*}$fromReportCmd incr xmlnr } s delete incr defnr } set result } {0/0: 1 {END_EVENT expecting a} 0/1: 1 {END_EVENT expecting b} 0/2: 1 {matching b} {expecting a} {END_EVENT expecting c} 0/3: 1 {matching c} {expecting a} {matching c} {expecting b} 0/4: 1 {END_EVENT expecting c} 0/5: 1 {matching c} {expecting b} 0/6: 1 {matching b} {expecting a} 0/7: 1 {matching unknown} {expecting a} {matching unknown} {expecting b} {matching unknown} {expecting c} {matching unknown} {expecting { {}}} 0/8: 1 {matching unknown} {expecting b} {matching unknown} {expecting c} {matching unknown} {expecting { {}}}} proc schema-17.23 {scmd errorInfo} { global fromReportCmd if {[$scmd info vaction] eq "MATCH_ELEMENT_START"} { lappend fromReportCmd "matching [$scmd info vaction name]" "expecting [lsort [$scmd info expected]]" if {$errorInfo in {"MISSING_ELEMENT" "UNEXPECTED_ELEMENT"}} { return vanish } } else { lappend fromReportCmd "END_EVENT expecting [$scmd info expected]" } } test schema-17.23 {return "vanish" from recover handler} {8.5} { set def { defelement doc { element a ref b element d ? } defpattern b { element b ref c } defpattern c { element c + } } set xmlinput { foocontentfoocontent } set result [list] tdom::schema s s define $def s reportcmd schema-17.23 set xmlnr 0 foreach xml $xmlinput { set fromReportCmd "" lappend result $xmlnr: [s validate $xml errMsg] lappend result {*}$fromReportCmd incr xmlnr } s delete set result } {0: 1 {END_EVENT expecting a} 1: 1 {END_EVENT expecting b} 2: 1 {matching b} {expecting a} {END_EVENT expecting a} 3: 1 {matching c} {expecting a} {END_EVENT expecting a} 4: 1 {END_EVENT expecting c} 5: 1 {matching c} {expecting b} {END_EVENT expecting b} 6: 1 {matching b} {expecting a} {matching c} {expecting a} {END_EVENT expecting a} 7: 1 {matching unknown} {expecting a} {END_EVENT expecting a} 8: 1 {matching unknown} {expecting b} {END_EVENT expecting b} 9: 1 {matching unknown} {expecting b} 10: 1 {matching unknown} {expecting b} 11: 1 {matching unknown} {expecting c} 12: 1 {matching unknown} {expecting c} 13: 1 {matching unknown} {expecting { {}} c d} 14: 1 {matching unknown} {expecting { {}} c d} 15: 1 {matching unknown} {expecting c} {matching unknown1} {expecting { {}} c d} {matching unknown2} {expecting { {}}} {matching unknown3} {expecting { {}}} 16: 1 {matching unknown} {expecting b} {matching unknown} {expecting c} 17: 1 {matching unknown1} {expecting c} {matching unknown2} {expecting c}} test schema-17.24 {info patterndefinition} { tdom::schema s set result "" s defpattern foo {element bar; element baz} lappend result [s info patterndefinition foo] s defpattern foo someNamespace {element e1; element e2} lappend result [s info patterndefinition foo someNamespace] lappend result [catch {s info patterndefinition dontexists} errMsg] lappend result $errMsg lappend result [catch {s info patterndefinition foo wrongNamespace} errMsg] lappend result $errMsg s delete set result } {{defpattern foo {element bar; element baz}} {defpattern foo someNamespace {element e1; element e2}} 1 {Unknown pattern definition} 1 {Unknown pattern definition}} test schema-17.25 {info definedPatterns} { tdom::schema create grammar grammar defpattern thisPattern { element a element b } grammar defpattern thatPattern someNamespace { element c element d } grammar defelement doc { ref thisPattern ref thatPattern ? } set result [lsort -index 0 [grammar info definedPatterns]] grammar delete set result } {{thatPattern someNamespace} thisPattern} proc schema-17.26 {scmd errorInfo} { global fromReportCmd if {$errorInfo eq "MISSING_ELEMENT" && [$scmd info vaction] eq "MATCH_ELEMENT_END"} { lappend fromReportCmd "END_EVENT [$scmd info vaction name]" "expecting [lsort [$scmd info expected]]" return "ignore" } else { lappend fromReportCmd "[$scmd info vaction] expecting [$scmd info expected]" } } test schema-17.26 {return "ignore" from recover handler for element end event} {8.5} { tdom::schema s s define { defelement doc { element a ref bpat element d } defpattern bpat { element b ref c } defpattern c { element c + } } s reportcmd schema-17.26 set result "" set xmlnr 0 foreach xml { } { set ::fromReportCmd "" lappend result $xmlnr: [s validate $xml errMsg] lappend result {*}$fromReportCmd incr xmlnr } s delete set result } {0: 1 {END_EVENT doc} {expecting a} {END_EVENT doc} {expecting b} {END_EVENT doc} {expecting d} 1: 1 {END_EVENT doc} {expecting b} {END_EVENT doc} {expecting d} 2: 1 {END_EVENT doc} {expecting c} {END_EVENT doc} {expecting d} 3: 1 {MATCH_ELEMENT_START expecting c} 4: 1 5: 1} test schema-17.27 {return "ignore" from recover handler for element end event} {8.5} { tdom::schema s s define { defelement doc { element a element b element c element d } } s reportcmd schema-17.26 set result "" set xmlnr 0 foreach xml { } { set ::fromReportCmd "" lappend result $xmlnr: [s validate $xml errMsg] lappend result {*}$fromReportCmd incr xmlnr } s delete set result } {0: 1 {END_EVENT doc} {expecting a} {END_EVENT doc} {expecting b} {END_EVENT doc} {expecting c} {END_EVENT doc} {expecting d} 1: 1 {END_EVENT doc} {expecting b} {END_EVENT doc} {expecting c} {END_EVENT doc} {expecting d} 2: 1 {END_EVENT doc} {expecting c} {END_EVENT doc} {expecting d} 3: 1 {MATCH_ELEMENT_START expecting c} 4: 1 5: 1 {MATCH_ELEMENT_START expecting d}} proc schema-17.28 {userarg scmd errType} { append ::result $userarg $scmd $errType } test schema-17.28 {reportcmd with additional args} { tdom::schema s s defelement doc { element a } s reportcmd "schema-17.28 foo" set result "" s validate }] lappend result $rc s delete set result } {s MISSING_TEXT 1} test schema-18.1a {reportcmd} { tdom::schema s s define { defelement doc { element e text {minLength 1} element e } } s reportcmd schema-18 set result "" set rc [s validate {}] lappend result $rc s delete set result } {s MISSING_TEXT 1} test schema-18.2 {reportcmd} { tdom::schema s s define { defelement doc { element a element b element c } } s reportcmd schema-18 set result "" set rc [s validate {}] lappend result $rc s delete set result } {s MISSING_ELEMENT 1} test schema-18.3 {reportcmd} { tdom::schema s s define { defelement doc { element a } } s reportcmd schema-18 set result "" foreach xml { baz bazgrill } { set rc [s validate $xml] lappend result $rc } s delete set result } {s UNKNOWN_ROOT_ELEMENT 1 s UNKNOWN_ROOT_ELEMENT 1 s UNKNOWN_ROOT_ELEMENT 1 s UNKNOWN_ROOT_ELEMENT 1} test schema-18.4 {reportcmd} { tdom::schema s s define { defelement doc { element items * { element item * { attribute ref {integer} } } } } s reportcmd schema-18 set result [list] foreach xml { {} {} } { lappend result [s validate $xml] } s delete set result } {1 s INVALID_ATTRIBUTE_VALUE s INVALID_ATTRIBUTE_VALUE 1} test schema-18.5 {reportcmd} { tdom::schema s s define { defelement doc { element items * { element item * { text {minLength 2} } } } } s reportcmd schema-18 set result [list] foreach xml { {1} {1} {>12ab} } { lappend result [s validate $xml] } s delete set result } {s INVALID_VALUE 1 s INVALID_VALUE s MISSING_TEXT 1 1} test schema-18.6 {reportcmd} { tdom::schema s s define { defelement item { text { key lang minLength 2 } } defelement items { keyspace lang { element item + } } defelement doc { element items + } } s reportcmd schema-18 set result [list] foreach xml { {12ab} {1212} {1212abcd} {1212abcd1212} } { lappend result [s validate $xml] } s delete set result } {1 s INVALID_VALUE 1 s INVALID_VALUE 1 s INVALID_VALUE s INVALID_VALUE 1} proc schema-18.7 {args} { global result lappend result "tclcallback" } test schema-18.7 {reportcmd} { tdom::schema s s define { defelement a {} defelement b {} defelement c {} defelement items { interleave { element a element b } tcl schema-18.7 element c } defelement doc { element items + } } s reportcmd schema-18 set result [list] foreach xml { {} {} {} {} } { lappend result [s validate $xml] } s delete set result } {tclcallback 1 tclcallback tclcallback 1 tclcallback s MISSING_ELEMENT tclcallback 1 tclcallback s MISSING_ELEMENT tclcallback s MISSING_ELEMENT 1} test schema-18.8 {reportcmd} { tdom::schema s s define { defelement a {} defelement b {} defelement c {} defelement items { element a element b element c } defelement doc { element items + } } s reportcmd schema-18 set result [list] foreach xml { {} } { lappend result [s validate $xml] } s delete set result } {s MISSING_ELEMENT s MISSING_ELEMENT 1} test schema-18.9 {reportcmd} { tdom::schema s s define { defelement a {} defelement b {} defelement c {} defelement doc { group + { element a element b element c } } } s reportcmd schema-18 set result [list] foreach xml { {} } { lappend result [s validate $xml] } s delete set result } {s MISSING_ELEMENT 1} test schema-18.10 {reportcmd} { tdom::schema s s define { defelement a {} defelement b {} defelement c {} defelement doc { group + { element a element b group + { element c } } } } s reportcmd schema-18 set result [list] foreach xml { {} } { lappend result [s validate $xml] } s delete set result } {s MISSING_ELEMENT 1} test schema-18.11 {reportcmd} { tdom::schema s s define { defelement a {} defelement b {} defelement c {} defelement doc { element a element b element c } } s reportcmd schema-18 set result [list] foreach xml { } { lappend result [s validate $xml] } s delete set result } {1 s MISSING_ELEMENT 1 s MISSING_ELEMENT 1 s MISSING_ELEMENT 1 s MISSING_ELEMENT 1 s UNEXPECTED_ELEMENT 1} test schema-18.12 {non existing reportcmd cmd} { tdom::schema s s defelement doc { element a } s reportcmd ::tdom::_dontExists_ set result [catch {s validate } errMsg] lappend result $errMsg s delete set result } {1 {error "invalid command name "::tdom::_dontExists_"" at line 1 character 6}} proc 18-13 {scmd errType} { global result lappend result {reportcmd called} } test schema-18.13 {reportcmd} { tdom::schema s s define { defelement header { group { choice { group { element prevlocs element latestloc ? } group { element latestloc element prevlocs ? } } } } } s reportcmd 18-13 set result [list] foreach xml {
} { lappend result [s validate $xml] } s delete set result } {{reportcmd called} 1 1 1 1 1} proc schema-18.14 {scmd errortype} { lappend ::result $errortype lappend ::result [$scmd info expected] lappend ::result [$scmd info vaction] lappend ::result [$scmd info vaction name] lappend ::result [$scmd info vaction namespace] lappend ::result [$scmd info vaction text] } test schema-18.14 {info vaction in reportcmd} {listformat} { tdom::schema s s reportcmd schema-18.14 s define { defelement doc { element e + { attribute attr1 { fixed on } text { minLength 4 } } } } set result [list] foreach xml { 123 {1234} } { lappend result [s validate $xml] } s delete set result } {MISSING_ELEMENT e MATCH_ELEMENT_END doc {} {} 1 MISSING_ELEMENT e MATCH_ELEMENT_START b {} {} 1 MISSING_ATTRIBUTE {{{#text} {}}} MATCH_ELEMENT_START attr1 {} {} INVALID_VALUE {{{#text} {}}} MATCH_TEXT e {} 123 1 INVALID_ATTRIBUTE_VALUE {{{#text} {}}} MATCH_ATTRIBUTE_TEXT attr1 {} off 1} test schema-18.15 {info vaction in reportcmd} { tdom::schema s s reportcmd schema-18.14 s define { defelement doc { element e + { attribute attr1 attribute attr2 ? { minLength 3 } } } } set result [list] foreach xml { {} {} {} } { lappend result [s validate $xml] } s delete set result } {1 INVALID_ATTRIBUTE_VALUE {{ {}}} MATCH_ATTRIBUTE_TEXT attr2 {} a MISSING_ATTRIBUTE {{ {}}} MATCH_ELEMENT_START attr1 {} {} 1 UNKNOWN_ATTRIBUTE {{ {}}} MATCH_ELEMENT_START foo {} {} MISSING_ATTRIBUTE {{ {}}} MATCH_ELEMENT_START attr1 {} {} 1} proc appendtoresult {scmd errortype} { lappend ::result $errortype } test schema-18.16 {unexpected text} { set defs { { defelement doc { ref r1 } defpattern r1 { element e ? {} } } { defelement doc { element e ? {} } } } set result [list] foreach def $defs { tdom::schema s s reportcmd appendtoresult s define $def lappend result [s validate {unexpected text}] s delete } set result } {UNEXPECTED_TEXT 1 UNEXPECTED_TEXT 1} test schema-18.17 {unexpected text} { tdom::schema s s reportcmd appendtoresult s define { defelement doc { ref r1 element c ! {} } defpattern r1 { element a ! {} element b ! {} } } set result [list] foreach xml { unexpected_text
unexpected_text unexpected_text unexpected_text } { lappend result [s validate $xml] } s delete set result } {UNEXPECTED_TEXT MISSING_ELEMENT 1 UNEXPECTED_TEXT MISSING_ELEMENT 1 UNEXPECTED_TEXT MISSING_ELEMENT 1 UNEXPECTED_TEXT 1} proc schema-18.18 {scmd errortype} { lappend ::result $errortype lappend ::result [$scmd info expected] } test schema-18.18 {missing element at MATCH_ELEMENT_END} { set defs { { defelement doc { ref r1 } defpattern r1 { element a ! {} element b ! {} } } { defelement doc { element a 1 {} element b 1 {} } } { defelement doc { element a0 ! {} ref r1 } defpattern r1 { element a ! {} element b ! {} } } { defelement doc { element a0 ! {} ref r1 element b0 ! {} } defpattern r1 { element a ! {} element b ! {} } } } set result [list] foreach def $defs { tdom::schema s s reportcmd schema-18.18 s define $def lappend result [s validate {}] s delete } set result } {MISSING_ELEMENT a 1 MISSING_ELEMENT a 1 MISSING_ELEMENT a0 1 MISSING_ELEMENT a0 1} test schema-18.19 {unexpected text} { tdom::schema s s reportcmd appendtoresult s define { defelement doc { ref r1 ? element c ? {} } defpattern r1 { element a ? {} element b ? {} } } set result [list] foreach xml { unexpected_text unexpected_text unexpected_text unexpected_text unexpected_text unexpected_text } { lappend result [s validate $xml] } s delete set result } {UNEXPECTED_TEXT 1 UNEXPECTED_TEXT 1 UNEXPECTED_TEXT 1 UNEXPECTED_TEXT 1 UNEXPECTED_TEXT 1 UNEXPECTED_TEXT 1} test schema-18.20 {Missing element on element end} { tdom::schema s s reportcmd appendtoresult s define { defelement doc { element a * { element b ! {} element c ! {} } } } set result [list] foreach xml { unexpected_text unexpected_text unexpected } { lappend result [s validate $xml] } s delete set result } {1 1 MISSING_ELEMENT 1 UNEXPECTED_TEXT MISSING_ELEMENT 1 UNEXPECTED_TEXT MISSING_ELEMENT 1 MISSING_ELEMENT 1 MISSING_ELEMENT MISSING_ELEMENT 1 MISSING_ELEMENT UNEXPECTED_TEXT 1} test schema-18.21 {reportcmd argument handling} { tdom::schema s set result "" lappend result [s reportcmd] s reportcmd "" lappend result [s reportcmd] s reportcmd dummycallback lappend result [s reportcmd] s reportcmd "" s reportcmd "" lappend result [s reportcmd] s reportcmd dummycallback lappend result [s reportcmd] s delete set result } {{} {} dummycallback {} dummycallback} proc schema-18.22 {that scmd errorType} { lappend ::result $that $errorType } test schema-18.22 {reportcmd with arguments} { tdom::schema s s reportcmd "schema-18.22 this" s defelement doc { element a element b } set result "" lappend result [s validate {}] s delete set result } {this MISSING_ELEMENT 1} proc validatedSAX {g xml {keepEmpties 1}} { set args [list -validateCmd $g] if {!$keepEmpties} { lappend args -ignorewhitespace 1 } xml::parser p {*}$args set rc [catch {p parse $xml} errMsg] p delete return $rc } proc validatedDOM {g xml {keepEmpties 0}} { set args [list -validateCmd $g] if {$keepEmpties} { lappend args -keepEmpties } set rc [catch { set doc [dom parse {*}$args $xml] } errMsg] if {$doc ne ""} { $doc delete } return $rc } proc postValidation {g xml} { set doc [dom parse $xml] set rc [$g domvalidate $doc errMsg] #puts "error : $errMsg" $doc delete return $rc } test schema-19.1 {keyspace} { tdom::schema s s define { defelement doc { element items * { keyspace ref { element item * { attribute ref ? { key ref } } } } } } set result [list] foreach xml { {} {} {} {} {} {} } { lappend result [s validate $xml] } s delete set result } {1 0 1 1 1 0} test schema-19.2 {keyspace} { tdom::schema s s define { defelement doc { element items * { keyspace ref { element item * { attribute ref ? { key ref } } } } } } s reportcmd schema-18 set result [list] foreach xml { {} {} } { lappend result [s validate $xml] } s delete set result } {s INVALID_ATTRIBUTE_VALUE s INVALID_ATTRIBUTE_VALUE 1 1} test schema-19.3 {keyspace} { tdom::schema s s define { defelement doc { element items * } defelement items { keyspace my { element item * } } defelement item { attribute id ? { key my } attribute ref ? { keyref my } } } s reportcmd schema-18 set result [list] foreach xml { {} {} {} {} } { lappend result [s validate $xml] } s delete set result } {1 1 s INVALID_KEYREF 1 s INVALID_KEYREF 1} proc log19.4 {msg} { lappend ::result $msg } proc report19.4 {scmd errortype} { lappend ::result $errortype } test schema-19.4 {keyspace w/ recover} { tdom::schema s s define { defelement doc { element m * { tcl log19.4 "before a" element a ? { keyspace lang { element a1 ? { attribute lang ? {key lang} } } keyspace lang { element a2 ? {text {key lang}} } } tcl log19.4 "before b" element b ? { keyspace lang { element b1 ? { attribute lang ? {key lang} } } } } } } s reportcmd report19.4 set result [list] foreach xml { {} } { lappend result [s validate $xml] } s delete set result } {{before a} UNEXPECTED_ELEMENT {before b} {before a} {before b} UNEXPECTED_ELEMENT 1} test schema-20.1 {domunique} { set schema { prefixns {ns1 http://tdom.org/test} defelement doc { domunique ${::schema-20.1} @ref } } set result [list] foreach ::schema-20.1 { a ./../a /foo a/b {a | b} a|b (a|b) {a/b/c | b/c/d | c/d/e} .//a //a a/@ref a/b/c {a//b[1]/c} (.//b|a)/c ns1:a a/.//b/c {} { } " " } { tdom::schema s lappend result [catch {s define $schema} errMsg] #puts $errMsg s delete } set result } {0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1} test schema-20.2 {domunique} { tdom::schema s s define { defelement doc { domunique item @ref element item * { attribute ref ? } } } set result [list] foreach xml { {} {} {} {} } { lappend result [postValidation s $xml] } s delete set result } {1 0 1 0} test schema-20.2a {domunique} { tdom::schema s s define { defelement doc { domunique item @ref itemrefkey IGNORE_EMPTY_FIELD_SET element item * { attribute ref ? } } } set result [list] foreach xml { {} {} {} {} } { lappend result [postValidation s $xml] } s delete set result } {1 0 1 1} test schema-20.2b {domunique} { tdom::schema s s define { defelement doc { domunique item @ref itemrefkey EMPTY_FIELD_SET_VALUE abc element item * { attribute ref ? } } } set result [list] foreach xml { {} {} {} {} } { lappend result [postValidation s $xml] } s delete set result } {1 0 0 0} test schema-20.3 {domunique} { tdom::schema s s define { defelement doc { element items * { element item * { attribute ref ? } domunique item @ref } } } set result [list] foreach xml { {} {} {} {} {} {} } { lappend result [postValidation s $xml] } s delete set result } {1 0 1 1 1 0} test schema-20.4 {domunique} { tdom::schema s s define { defelement doc { domunique item {@ref @id} element item * { attribute ref ? attribute id ? } } } set result [list] foreach xml { {} {} {} {} {} } { lappend result [postValidation s $xml] } s delete set result } {1 0 1 0 1} test schema-20.5 {domunique} { tdom::schema s s define { defelement doc { domunique item ref element item * { element ref ! text } } } set result [list] foreach xml { {1foo} {11} } { lappend result [postValidation s $xml] } s delete set result } {1 0} proc schema-20.6 {scmd errortype} { lappend ::result $errortype \ [$scmd info vaction name] \ [$scmd info vaction text] \ [[$scmd info domNode] nodeName] } test schema-20.6 {domunique} { tdom::schema s s define { defelement doc { domunique item ref itemunique element item * { element ref ! text } } } s reportcmd schema-20.6 set result [list] foreach xml { {1foo} {foofoo} } { lappend result [postValidation s $xml] } s delete set result } {1 DOM_KEYCONSTRAINT itemunique foo doc 1} test schema-20.7 {domunique} { tdom::schema s set result [catch {s define { defelement doc { domunique item {} element item * { attribute ref ? } } }}] s delete set result } {1} test schema-21.1 {CONTENT_ARRAY_SIZE_INIT} { tdom::schema s s defelement doc { for {set i 1} {$i <= 30} {incr i} { element e ? } } set result [list] foreach xml [list \ [string repeat 9] \ [string repeat 27] \ [string repeat 37]] { lappend result [s validate $xml] } s delete set result } {1 1 1 0} test schema-22.1 {defelementtype} { tdom::schema s s defelementtype a_type { element e1 } s defelement doc { element a type a_type } set result [list] foreach xml { } { lappend result [s validate $xml] } s delete set result } {0 0 1} test schema-22.2 {defelementtype} { tdom::schema s s defelement doc { element a type a_type } s defelementtype a_type { element e1 } set result [list] foreach xml { } { lappend result [s validate $xml] } s delete set result } {0 0 1} test schema-22.3 {defelementtype} { tdom::schema s s defelement doc { element a type a element a type a2 } s defelementtype a { element e1 } s defelementtype a2 { element e2 } set result [list] foreach xml { } { lappend result [s validate $xml] } s delete set result } {0 0 0 1 0 0} test schema-22.4 {defelementtype} { tdom::schema s catch {s defelement doc { element atype a element a type a2 error "my" }} s defelement doc { element a type a element a type a2 } catch {s defelementtype a { element e1 error my }} s defelementtype a { element e1 } catch {s defelementtype a2 { element e2 error my }} s defelementtype a2 { element e2 } set result [list] foreach xml { } { lappend result [s validate $xml] } s delete set result } {0 0 0 1 0 0} test schema-22.5 {defelementtype} { tdom::schema s s prefixns {ns http://my.foo} s defelement doc ns { element a type a element a type a2 } s defelementtype a ns { element e1 } s defelementtype a2 ns { element e2 } set result [list] foreach xml { {} {} {} {} {} {} } { lappend result [s validate $xml] } s delete set result } {0 0 0 1 0 0} test schema-22.6 {defelementtype} { tdom::schema s s prefixns {ns http://my.foo} s defelement doc ns { element a type a element a type a2 } s defelementtype a ns { element e type e1 } s defelementtype a2 ns { element e type e2 } set result [lsort -index 0 [s info definedElementtypes]] s delete set result } {{a http://my.foo} {a2 http://my.foo}} test schema-22.6a {info definedElementtypes} { tdom::schema s s prefixns {ns1 http://ns1.foo ns2 http://ns2.foo} s defelementtype a ns1 { element e type e1 } s defelementtype a ns2 { element e type e2 } set result [lsort -command sortcps [s info definedElementtypes]] s delete set result } {{a http://ns1.foo} {a http://ns2.foo}} test schema-22.7 {defelementtype} { tdom::schema s s defelement doc { element e1 type e1type element e2 * type e2type } foreach e {e1 e2} { s defelementtype ${e}type {} } set result [list] foreach xml { } { lappend result [s validate $xml] } s delete set result } {0 1 1 1 1 0 0} test schema-22.8 {defelementtype} { tdom::schema s s defelement doc { element e1 type e1type element e2 * type e2type } set result [list] foreach xml { {} grill } { lappend result [s validate $xml] } s delete set result } {0 0 0 0 1 0 0 1} test schema-22.9 {defelementtype} { tdom::schema s catch { s define { defelement a { element a1 type a1type } defelement b { element b1 type e1type element b1 ? type e2type } defelementtype a1type { element a1 } defelementtype e1type text defelementtype e2type { element c for {set i 1} {$i <= 100} {incr i} { attribute att$i ? } attribute musthave } error "triggered" } } s define { defelement a { element a1 type a1type } defelement b { element b1 type e1type element b1 ? type e2type } defelementtype a1type { element a1 } defelementtype e1type text defelementtype e2type { element c for {set i 1} {$i <= 100} {incr i} { attribute att$i ? } attribute musthave ! } } s defelement doc { element e1 type e1type element e2 * type e2type element a element b + } set result [list] foreach xml { { foo } { foo } } { lappend result [s validate $xml] } s delete set result } {0 1} test schema-23.1 {validatefile} { tdom::schema s s define { set fd [open [file join [file dir [info script]] ../doc/tmml.schema] r] eval [read $fd] close $fd } set result [s validatefile [file join [file dir [info script]] ../doc/schema.xml]] s delete set result } 1 test schema-24.1 {validatechannel} { tdom::schema s s define { set fd [open [file join [file dir [info script]] ../doc/tmml.schema] r] eval [read $fd] close $fd } set fd [open [file join [file dir [info script]] ../doc/schema.xml] r] set result [s validatechannel $fd] close $fd s delete set result } 1 test schema-25.1 {domxpathboolean} { tdom::schema s s define { defelement doc { element width ! text element length ! text element height ! text domxpathboolean "width * length * height <= 20000" volumeconstraint } } set result [list] foreach xml { 135 2000.0100.02.0 2000.0100.0-2 2.33.57.6 11foo 112000-01-01 } { lappend result [postValidation s $xml] } s delete set result } {1 0 1 1 0 0 0} test schema-25.2 {domxpathboolean} { tdom::schema s s prefixns { this http://that.org other http://this.org } s define { defelement doc this { element width ! text namespace other { element length ! text } element height ! text domxpathboolean "this:width * other:length * this:height <= 20000" volumeconstraint } } set result [list] foreach xml { {135} {2000.0100.02.0} {2000.0100.0-2} {2.33.57.6} {11foo} {112000-01-01} {} } { lappend result [postValidation s $xml] } s delete set result } {1 0 1 1 0 0 0} proc schema-25.3 {scmd errortype} { lappend ::result $errortype [$scmd info vaction name] } test schema-25.3 {domxpathboolean} { tdom::schema s s define { defelement doc { element width ! text element length ! text element height ! text domxpathboolean "width * length * height <= 20000" volumeconstraint } } s reportcmd schema-25.3 set result [list] foreach xml { 135 2000.0100.02.0 2000.0100.0-2 2.33.57.6 11foo 112000-01-01 } { lappend result [postValidation s $xml] } s delete set result } {1 DOM_XPATH_BOOLEAN volumeconstraint 1 1 1 DOM_XPATH_BOOLEAN volumeconstraint 1 DOM_XPATH_BOOLEAN volumeconstraint 1 DOM_XPATH_BOOLEAN volumeconstraint 1} test schema-25.4 {domxpathboolean} { tdom::schema s s define { defelement doc { element width ! text element length ! text element height ! text domxpathboolean "width * length * height <= 20000" volume domunique width|length|height . unique domxpathboolean "width < length and length < height" sequence } } s reportcmd schema-25.3 set result [list] set nr 1 foreach xml { 135 2000.0100.02.0 2000.0100.0-2 2.33.57.6 11foo 112000-01-01 } { lappend result "Nr$nr:" incr nr lappend result [postValidation s $xml] } s delete set result } {Nr1: 1 Nr2: DOM_XPATH_BOOLEAN volume DOM_XPATH_BOOLEAN sequence 1 Nr3: DOM_XPATH_BOOLEAN sequence 1 Nr4: 1 Nr5: DOM_XPATH_BOOLEAN volume DOM_KEYCONSTRAINT unique DOM_XPATH_BOOLEAN sequence 1 Nr6: DOM_XPATH_BOOLEAN volume DOM_KEYCONSTRAINT unique DOM_XPATH_BOOLEAN sequence 1 Nr7: DOM_XPATH_BOOLEAN volume DOM_KEYCONSTRAINT unique DOM_XPATH_BOOLEAN sequence 1} test schema-25.5 {domxpathboolean - xpath argument invalid} { tdom::schema s set result [catch { s defelement doc { domxpathboolean "a + + b" } } errMsg] lappend result $errMsg s delete set result } {1 {Error in selector xpath: 'NodeTest: Expected "WCARDNAME" for 'a + + b' Parsed symbols: 0 WCARDNAME 0 000000000 0 a 1 PLUS 0 000000000 2 2 PLUS 0 000000000 4 3 WCARDNAME 0 000000000 6 b}} proc ::dom::xpathFunc::compare {ctxNode pos nodeListType nodeList args} { if {[llength $args] != 4} { error "XPath function date: Expected two arguments but got [expr {[llength $args] / 2}]" } lassign $args arg1Typ arg1Value arg2Typ arg2Value set arg1 [::dom::xpathFuncHelper::coerce2string $arg1Typ $arg1Value] set arg2 [::dom::xpathFuncHelper::coerce2string $arg2Typ $arg2Value] return [list number [string compare $arg1 $arg2]] } proc schema-25.6 {scmd errorType} { lappend ::result $errorType [$scmd info vaction name] } test schema-25.6 {domxpathboolean - scripted XPath function} {8.5} { tdom::schema s s reportcmd schema-25.6 s define { defelement doc { element a ! { text domxpathboolean {compare('foo','bar') > 0} first domxpathboolean {compare('foo','bar') < 0} second } } } set doc [dom parse {2020-07-30}] set result "" lappend result [s domvalidate $doc] set result } {DOM_XPATH_BOOLEAN second 1} proc schema-26.1 {scmd} { lappend ::result "fromtcl: [[$scmd info domNode] nodeName]" } test schema-26.1 {info domNode} { tdom::schema s s defelement doc { tcl schema-26.1 [self] element e ? } set result "" lappend result [s info domNode] foreach xml { {unexpected text} {unexpected text} {unexpected text} } { dom parse $xml doc lappend result [s domvalidate $doc] $doc delete } s delete set result } {{} {fromtcl: doc} 1 {fromtcl: doc} 1 {fromtcl: doc} 0 {fromtcl: doc} 0 {fromtcl: doc} 0 {fromtcl: doc} 0} proc schema-26.2 {scmd errortype} { lappend ::result $errortype [[$scmd info domNode] nodeName] } test schema-26.2 {info domNode} { tdom::schema s s defelement doc { tcl schema-26.1 [self] element e ? } s reportcmd schema-26.2 set result "" lappend result [s info domNode] foreach xml { {unexpected text} {unexpected text} {unexpected text} } { dom parse $xml doc lappend result [s domvalidate $doc] $doc delete } s delete set result } {{} {fromtcl: doc} 1 {fromtcl: doc} 1 {fromtcl: doc} UNEXPECTED_TEXT doc {fromtcl: doc} 1 {fromtcl: doc} UNEXPECTED_TEXT doc {fromtcl: doc} 1 {fromtcl: doc} UNEXPECTED_TEXT doc {fromtcl: doc} UNEXPECTED_ELEMENT unknown 1 {fromtcl: doc} UNEXPECTED_ELEMENT unknown 1} proc schema-26.3 {scmd errortype} { lappend ::result $errortype [$scmd info domNode] } test schema-26.3 {info domNode} { tdom::schema s s defelement doc { tcl schema-26.3 [self] "fromTcl" element e ? } s reportcmd schema-26.3 set result "" lappend result [s info domNode] foreach xml { {unexpected text} {unexpected text} {unexpected text} } { lappend result [s validate $xml] } s delete set result } {{} fromTcl {} 1 fromTcl {} 1 fromTcl {} UNEXPECTED_TEXT {} fromTcl {} 1 fromTcl {} UNEXPECTED_TEXT {} fromTcl {} 1 fromTcl {} UNEXPECTED_TEXT {} fromTcl {} UNEXPECTED_ELEMENT {} 1 fromTcl {} UNEXPECTED_ELEMENT {} 1} proc schema-27.1 {args} { lappend ::result [::tdom::type::time 23:24:45] } test schema-27.1 {Called from evaluated code} { tdom::schema s s defelement doc { tcl schema-27.1 element e 1 } set result "" lappend result [s validate ] s delete set result } {1 1} test schema-27.2 {Called from evaluated code} { tdom::schema s s defelement doc { text { tcl schema-27.1 } } set result "" lappend result [s validate foo] s delete set result } {1 1} test schema-27.3 {Called from recover script} { tdom::schema s s defelement doc { element e 1 } s reportcmd schema-27.1 set result "" lappend result [s validate ] s delete set result } {1 1} test schema-27.4 {Called as part of validation} { tdom::schema s s defelement doc { tcl schema-27.1 element e 1 } set result "" lappend result [s validate ] s delete set result } {1 1} test schema-27.5 {Called during schema script evaluation} { tdom::schema s set result "" s defelement doc { set ::result [::tdom::type::time 12:20:00] element e 1 } s delete set result } 1 test schema-27.6 {date outside schema context} { set result {} foreach txt { "" foo 1 12 1234-12-31 1234-14-31 1234-12-00 1234-02-31 2000-02-29 2001-02-29 2004-02-29 -2004-02-29 1900-02-29 1234-02-01 1234-08-10 1234-08-222 " 1234-08-22" "1234-08-22 " 11234-08-22 0000-02-01 10000-08-22 10000-02-29 10000-02-29Z 2012-03-07Z "2012-03-07Z " 2012-03-07a 2012-03-07+ 2012-03-07+00:00 2012-03-07-00:00 2012-03-07+02:00 2012-03-07+02:70 2012-03-07+12:30 2012-03-07+14:30 2012-03-07+14:00 2012-03-07-14:00 2012-03-07-14:01 2012-03-07-2:30 2012-03-07-02:30Z "2012-03-07-02:30 " 02027-02-01 } { lappend result [tdom::type::date $txt] } set result } {0 0 0 0 1 0 0 0 1 0 1 1 0 1 1 0 0 0 1 0 1 1 1 1 0 0 0 1 1 1 0 1 0 1 1 0 0 0 0 0} test schema-27.7 {dateTime outside schema context} { set result "" foreach txt { "" foo 1 2020-07-08T15:58:17 2020-07-08T15:20:00 2020-07-08T15:20:17.7 2020-07-08T15:58:17+02:00 2020-07-08T15:20:17.789 2020-07-08T15:20:17.7890 2020-07-08T15:20:17.0 2020-07-08T15:20:17. 2020-07-08T15:20:17.+02:00 2020-07-08T15:20:17.Z 2020-07-08T15:20:17+Z 2020-07-08T00:20 2020-07-08T00:60:00 2020-07-08T24:00:00 2020-07-08T24:00:00.1 2020-07-08T24:01:00 2020-07-08T24:00:01 2020-12-2215:20:00 2020-12-22 2020-07-08T15:20:17.789+02:00 2020-07-08T15:20:17-02:00 2020-07-08T15:20:17-02:00.0 2020-07-08T15:20:17.0-02:00 " 2020-07-08T15:20:17.0-02:00" "2020-07-08T15:20:17.0-02:00 " } { lappend result [tdom::type::dateTime $txt] } set result } {0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 1 0 0 0 0 0 1 1 0 1 0 0} test schema-27.8 {time outside schema context} { set result "" foreach txt { "" foo 1 07:15:00 07:15:00.023 07:15:00+05:00 07:15:00Z 00:00:00 24:00:00 7:15:00 07:15 07:15.4:23 12:60:12 12:61:12 12:71:12 24:31:12 25:31:12 55:31:12 12:31:60 12:31:61 12:31:77 } { lappend result [tdom::type::time $txt] } set result } {0 0 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0} test schema-27.9 {duration outside schema context} { set result "" foreach txt { "" foo 1 P2Y6M5DT12H35M30S P1DT2H P20M PT20M P0Y20M0D P0Y -P60D PT1M30.5S P-20M P20MT P1YM5D P15.5Y P1D2H 1Y2M P2M1Y P PT15.S PT.5S } { lappend result [tdom::type::duration $txt] } set result } {0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0} test schema-28.1 {schema use in child interp while in schema context} { tdom::schema s set result [catch {s defelement doc { interp create childinterp load {} Tdom childinterp childinterp eval { ::tdom::schema::element fromchild } element this }}] if {$result} { s defelement doc { element this } } set result [s validate { }] s delete interp delete childinterp set result } 0 test schema-28.2 {called outside schema context} { catch {::tdom::schema::element elm} } 1 test schema-28.3 {schema use in child interp while in schema context} { tdom::schema s s defelement doc { interp create childinterp load {} Tdom childinterp childinterp eval { tdom::schema s s defelement doc { element child element this } } element this } set result "" foreach xml { } { lappend result [s validate $xml] } lappend result {*}[childinterp eval { set result "" foreach xml { } { lappend result [s validate $xml] } set result return {1 0} }] s delete interp delete childinterp set result } {0 1 1 0} test schema-29.1 {text constraint jsontype} { tdom::schema s s defelement JSON { element astring {text {jsontype STRING}} element anumber {text {jsontype NUMBER}} element atrue {text {jsontype TRUE}} element afalse {text {jsontype FALSE}} element anull {text {jsontype NULL}} } set result "" foreach json { {{ "astring": "0.123", "anumber": 0.123, "atrue": true, "afalse": false, "anull": null }} {{ "astring": "0.123", "anumber": "0.123", "atrue": true, "afalse": false, "anull": null }} } { set jdoc [dom parse -json -jsonroot JSON $json] lappend result [s domvalidate [$jdoc documentElement]] $jdoc delete } s delete set result } {1 0} test schema-29.2 {text constraint jsontype} { tdom::schema s s define { defelement JSON { element astring {text type jsonString} element anumber {text type jsonNumber} } deftexttype jsonString {jsontype STRING} deftexttype jsonNumber {jsontype NUMBER} } set result "" foreach json { {{ "astring": "0.123", "anumber": 0.123 }} {{ "astring": "0.123", "anumber": "0.123" }} } { set jdoc [dom parse -json -jsonroot JSON $json] lappend result [s domvalidate [$jdoc documentElement]] $jdoc delete } s delete set result } {1 0} test schema-29.3 {structure constraint jsontype} { tdom::schema s s define { defelement JSON { element aarray { jsontype ARRAY text {jsontype STRING} text {jsontype NUMBER} } element aobject { jsontype OBJECT interleave { element astring {text type jsonString} element anumber {text type jsonNumber} } } } deftexttype jsonString {jsontype STRING} deftexttype jsonNumber {jsontype NUMBER} } set result "" foreach json { {{ "aarray": ["some text", -23.45], "aobject": { "anumber": 3, "astring": "foo bar" } }} {{ "aarray": {"some key": -23.45}, "aobject": { "anumber": 3, "astring": "foo bar" } }} } { set jdoc [dom parse -json -jsonroot JSON $json] lappend result [s domvalidate [$jdoc documentElement] errMsg] $jdoc delete } s delete set result } {1 0} test schema-29.4 {structure constraint jsontype} { tdom::schema s s define { defelement JSON { element aobject {jsontype ARRAY} } } set result "" foreach json { {{ "aobject": {} }} {{ "aobject": [] }} } { set jdoc [dom parse -json -jsonroot JSON $json] lappend result [s domvalidate [$jdoc documentElement]] $jdoc delete } s delete set result } {0 1} test schema-29.5 {structure constraint jsontype} { tdom::schema s s define { defelement JSON { element aobject type jsonarry jsontype OBJECT } defelementtype jsonarry {jsontype ARRAY} } set result "" foreach json { {{ "aobject": {} }} {{ "aobject": [] }} } { set jdoc [dom parse -json -jsonroot JSON $json] lappend result [s domvalidate [$jdoc documentElement]] $jdoc delete } s delete set result } {0 1} } tdom-0.9.6-src/tests/decls.test0000644000175000017500000002346415025767703015126 0ustar rolfrolf# Features covered: Declarations # # This file tests the parser's performance on markup declarations. # Sourcing this file into Tcl runs the tests and generates output # for errors. No output means no errors were found. # # Copyright (c) 2000 Zveno Pty Ltd. # # $Id$ source [file join [file dir [info script]] loadtdom.tcl] set baseURI file://[file join [pwd] [file dir [info script]] decls.test] catch {unset elements} proc elementDecl {name cmodel} { set ::elements($name) $cmodel } catch {unset attrs} proc attlistDecl {name attName type dfltValue isrequired} { lappend ::attrs($name/$attName) $type $isrequired $dfltValue } catch {unset entities} proc entityDecl {name is_param value base systemId publicId notationName} { set ::entities($name) [list $is_param $value $base $systemId $publicId $notationName] } catch {unset cdata} proc CData data { append ::cdata [string trim $data] } proc extRefH {base systemId publicId} { if {![regexp {^[a-zA-Z]+://} $systemId]} { regsub {^[a-zA-Z]+://} $base {} base set basedir [file dirname $base] set systemId "[set basedir]/[set systemId]" } else { regsub {^[a-zA-Z]+://} $systemId systemId } if {[catch {set fd [open $systemId]}]} { return -code error \ -errorinfo "Failed to open external entity $systemId" } return [list channel $systemId $fd] } proc extRefHstr {base systemId publicId} { if {![regexp {^[a-zA-Z]+://} $systemId]} { regsub {^[a-zA-Z]+://} $base {} base set basedir [file dirname $base] set systemId "[set basedir]/[set systemId]" } else { regsub {^[a-zA-Z]+://} $systemId systemId } if {[catch {set fd [open $systemId]}]} { return -code error \ -errorinfo "Failed to open external entity $systemId" } return [list string $systemId [read $fd [file size $systemId]]] } # Internal DTD subset test decls-1.1 {element declaration} { catch {unset ::elements} array set ::elements {} catch {rename xml::decls-1.1 {}} set parser [xml::parser decls-1.1 \ -elementdeclcommand elementDecl] $parser parse { ]> } array get ::elements } {Test {MIXED {} {} {}}} test decls-2.1 {attribute list declaration, implied} { catch {unset ::attrs} array set ::attrs {} catch {rename xml::decls-2.1 {}} set parser [xml::parser decls-2.1 \ -attlistdeclcommand attlistDecl] $parser parse { ]> } array get ::attrs } {Test/test {CDATA 0 {}}} test decls-2.2 {attribute list declaration, enum} { catch {unset ::attrs} array set ::attrs {} catch {rename xml::decls-2.2 {}} set parser [xml::parser decls-2.2 \ -attlistdeclcommand attlistDecl] $parser parse { ]> } array get ::attrs } {Test/test {(LGL|OTH) 0 LGL}} test decls-3.1 {entity declarations} { catch {unset ::entities} array set ::entities {} catch {rename xml::decls-3.1 {}} set parser [xml::parser decls-3.1 \ -entitydeclcommand entityDecl] $parser parse { ]> } array get ::entities } {testEnt {0 {replacement text} {} {} {} {}}} test decls-4.1 {parameter entity declarations} { catch {unset ::entities} array set ::entities {} catch {unset ::elements} array set ::elements {} catch {rename xml::decls-4.1 {}} set parser [xml::parser decls-4.1 \ -paramentityparsing notstandalone \ -elementdeclcommand elementDecl] $parser parse { %PEnt; ]> } array get ::elements } {Test {MIXED {} {} {}}} # NB. entity.test tests entity replacement as well # External entities test decls-5.1 {external entity} { catch {unset ::elements} array set ::elements {} catch {rename xml::decls-5.1 {}} set parser [xml::parser decls-5.1 \ -paramentityparsing notstandalone \ -externalentitycommand extRefH \ -elementdeclcommand elementDecl \ -baseurl $baseURI] $parser parse { } array get ::elements } {Test {MIXED {} {} {}}} test decls-5.2 {external DTD subset} { catch {unset ::elements} array set ::elements {} catch {unset ::entities} array set ::entities {} catch {rename xml::decls-5.2 {}} set parser [xml::parser decls-5.2 \ -paramentityparsing notstandalone \ -externalentitycommand extRefH \ -elementdeclcommand elementDecl \ -baseurl $baseURI] $parser parse { } array get ::elements } {Test {MIXED {} {} {}}} test decls-5.3 {external entity} { catch {unset ::elements} array set ::elements {} catch {unset ::entities} array set ::entities {} catch {unset ::externals} array set ::externals {} catch {rename xml::decls-5.3 {}} set parser [xml::parser decls-5.3 \ -paramentityparsing notstandalone \ -externalentitycommand extRefH \ -elementdeclcommand elementDecl \ -baseurl $baseURI] $parser parse { %module; ]> } array get ::elements } {Test {MIXED {} {} {}}} test decls-5.4 {external entity} { catch {unset ::elements} array set ::elements {} catch {rename xml::decls-5.4 {}} set parser [xml::parser decls-5.4 \ -paramentityparsing notstandalone \ -externalentitycommand extRefHstr \ -elementdeclcommand elementDecl \ -baseurl $baseURI] $parser parse { } array get ::elements } {Test {MIXED {} {} {}}} test decls-5.5 {external DTD subset} { catch {unset ::elements} array set ::elements {} catch {unset ::entities} array set ::entities {} catch {rename xml::decls-5.5 {}} set parser [xml::parser decls-5.5 \ -paramentityparsing notstandalone \ -externalentitycommand extRefHstr \ -elementdeclcommand elementDecl \ -baseurl $baseURI] $parser parse { } array get ::elements } {Test {MIXED {} {} {}}} test decls-5.6 {external entity} { catch {unset ::elements} array set ::elements {} catch {unset ::entities} array set ::entities {} catch {unset ::externals} array set ::externals {} catch {rename xml::decls-5.6 {}} set parser [xml::parser decls-5.6 \ -paramentityparsing notstandalone \ -externalentitycommand extRefHstr \ -elementdeclcommand elementDecl \ -baseurl $baseURI] $parser parse { %module; ]> } array get ::elements } {Test {MIXED {} {} {}}} # Conditional Sections test decls-6.1 {conditional section: include} { catch {unset ::elements} array set ::elements {} catch {rename xml::decls-6.1 {}} set parser [xml::parser decls-6.1 \ -paramentityparsing notstandalone \ -externalentitycommand extRefH \ -elementdeclcommand elementDecl \ -baseurl $baseURI] $parser parse { } array get ::elements } {Test {MIXED {} {} {}}} test decls-6.2 {conditional section: include, empty} { catch {unset ::elements} array set ::elements {} catch {rename xml::decls-6.2 {}} set parser [xml::parser decls-6.2 \ -paramentityparsing notstandalone \ -externalentitycommand extRefH \ -elementdeclcommand elementDecl \ -baseurl $baseURI] $parser parse { } array get ::elements } {} test decls-6.3 {conditional section: include, empty} { catch {unset ::elements} array set ::elements {} catch {rename xml::decls-6.3 {}} set parser [xml::parser decls-6.3 \ -paramentityparsing notstandalone \ -externalentitycommand extRefH \ -elementdeclcommand elementDecl \ -baseurl $baseURI] $parser parse { } array get ::elements } {} test decls-6.4 {conditional section: include, nested} { catch {unset ::elements} array set ::elements {} catch {rename xml::decls-6.4 {}} set parser [xml::parser decls-6.4 \ -paramentityparsing notstandalone \ -externalentitycommand extRefH \ -elementdeclcommand elementDecl \ -baseurl $baseURI] $parser parse { } array size ::elements } 3 test decls-6.6 {conditional section/PE combo} { catch {unset ::elements} array set ::elements {} catch {rename xml::decls-6.6 {}} set parser [xml::parser decls-6.6 \ -paramentityparsing notstandalone \ -externalentitycommand extRefH \ -elementdeclcommand elementDecl \ -baseurl $baseURI] $parser parse { } array size ::elements } 2 foreach parser [info commands decls-*] { $parser free } # cleanup ::tcltest::cleanupTests return tdom-0.9.6-src/tests/comment.test0000644000175000017500000001145115025767703015467 0ustar rolfrolf# Features covered: comments # # This file tests the parser's performance on comments. # Sourcing this file into Tcl runs the tests and generates output # for errors. No output means no errors were found. # # Copyright (c) 1998-2000 Zveno Pty Ltd. # # $Id$ source [file join [file dir [info script]] loadtdom.tcl] catch {unset result} proc pcdata data { append ::result $data } proc comment data { append ::comment $data } proc Estart {tagName attrList} { switch -- $tagName { test - Test { } default { incr ::element } } } proc EStop tagname { } test comment-1.1 {Simple comment} { set ::result {} set ::comment {} set ::element 0 catch {rename xml::comment-1.1 {}} set parser [xml::parser comment-1.1 \ -elementstartcommand Estart \ -elementendcommand EStop \ -characterdatacommand pcdata \ -commentcommand comment] $parser parse { } list $::comment $::result $::element } {{ This is a comment } {} 0} test comment-1.2 {Simple comment, no white space} { set ::result {} set ::comment {} set ::element 0 catch {rename xml::comment-1.2 {}} set parser [xml::parser comment-1.2 \ -elementstartcommand Estart \ -elementendcommand EStop \ -characterdatacommand pcdata \ -commentcommand comment] $parser parse { } list $::comment $::result $::element } {{This is a comment} {} 0} test comment-1.3 {Simple comment, within PCDATA} { set ::result {} set ::comment {} set ::element 0 catch {rename xml::comment-1.3 {}} set parser [xml::parser comment-1.3 \ -elementstartcommand Estart \ -elementendcommand EStop \ -characterdatacommand pcdata \ -commentcommand comment] $parser parse { surrounding PCDATA } list $::comment $::result $::element } {{This is a comment} {surrounding PCDATA} 0} test comment-1.4 {Simple comment, no white space} { set ::result {} set ::comment {} set ::element 0 catch {rename xml::comment-1.3 {}} set parser [xml::parser comment-1.3 \ -elementstartcommand Estart \ -elementendcommand EStop \ -characterdatacommand pcdata \ -commentcommand comment] $parser parse { } list $::comment $::result $::element } {comment {} 0} test comment-1.5 {comment, with nested element} { set ::result {} set ::comment {} set ::element 0 catch {rename xml::comment-1.4 {}} set parser [xml::parser comment-1.4 \ -elementstartcommand Estart \ -elementendcommand EStop \ -characterdatacommand pcdata \ -commentcommand comment] $parser parse { } list $::comment $::result $::element } {{ comment } {} 0} test comment-2.1 {comment with an angle bracket} { set ::result {} set ::comment {} set ::element 0 catch {rename xml::comment-2.1 {}} set parser [xml::parser comment-2.1 \ -elementstartcommand Estart \ -elementendcommand EStop \ -characterdatacommand pcdata \ -commentcommand comment] $parser parse { } list $::comment $::result $::element } {{ This is a > greater than sign } {} 0} test comment-2.2 {comment with multiple angle brackets} { set ::result {} set ::comment {} set ::element 0 catch {rename xml::comment-2.2 {}} set parser [xml::parser comment-2.2 \ -elementstartcommand Estart \ -elementendcommand EStop \ -characterdatacommand pcdata \ -commentcommand comment] $parser parse { } list $::comment $::result $::element } {{ } {} 0} set comment_2_3 [format {
} \}] test comment-2.3 {comment with entities} { set ::result {} set ::comment {} set ::element 0 catch {rename xml::comment-2.3 {}} set parser [xml::parser comment-2.3 \ -elementstartcommand Estart \ -elementendcommand EStop \ -characterdatacommand pcdata \ -commentcommand comment] $parser parse " " list [string compare $::comment ${comment_2_3}] [string trim $::result] $::element } [list 0 {} 2] foreach parser [info commands comment-*] { $parser free } # cleanup ::tcltest::cleanupTests return tdom-0.9.6-src/tests/htmlreader.test0000644000175000017500000041440115025767703016156 0ustar rolfrolf# Features covered: HTML parser # # This file contains a collection of tests for the HTML parser. # Tested functionalities: # html-1.*: Character encoding # html-2.*: Parsing tests # html-3.*: Bad data # html-4.*: DOM building # # Copyright (c) 2002-2007 Rolf Ade. # # RCS: @(#) $Id$ source [file join [file dir [info script]] loadtdom.tcl] test html-1.1 {HTML character entities} { set doc [dom parse -html { ¡Äü}] set root [$doc documentElement] set body [$root firstChild] set result [$body text] $doc delete set result } "\u00A0\u00A1\u00c4\u00fc" test html-1.2 {character entities} { set doc [dom parse -html {ÖÄÄ}] set root [$doc documentElement] set body [$root firstChild] set result [$body text] $doc delete set result } "\u00d6\u00c4\u00c4" test html-1.3 {character entities} { set doc [dom parse -html {€∋}] set root [$doc documentElement] set result [$root text] $doc delete set result } "\u20ac\u220b" test html-1.4 {Invalid numeric character entity} { set doc [dom parse -html {'xyz}] set root [$doc documentElement] set result [$root text] $doc delete set result } "'xyz" test html-1.5 {Numeric character entity} { set doc [dom parse -html {�}] set root [$doc documentElement] set result [$root text] $doc delete set result } "�" test html-1.6 {Numeric character entity} { set doc [dom parse -html {�}] set root [$doc documentElement] set result [$root text] $doc delete set result } "�" test html-1.7 {character entities} { set doc [dom parse -html {¼}] set root [$doc documentElement] set result [$root text] $doc delete set result } "\u00bc" proc toutf8 c { set s [encoding convertto utf-8 $c] binary scan $s H* x regsub -all -expanded {..} $x {\x&} } test html-1.8 {character entities} {Tcl9} { set result "" foreach {entity byteseq} { "AElig" "\\xC3\\x86" "AMP" "\\x26" "Aacute" "\\xC3\\x81" "Abreve" "\\xC4\\x82" "Acirc" "\\xC3\\x82" "Acy" "\\xD0\\x90" "Afr" "\\xF0\\x9D\\x94\\x84" "Agrave" "\\xC3\\x80" "Alpha" "\\xCE\\x91" "Amacr" "\\xC4\\x80" "And" "\\xE2\\xA9\\x93" "Aogon" "\\xC4\\x84" "Aopf" "\\xF0\\x9D\\x94\\xB8" "ApplyFunction" "\\xE2\\x81\\xA1" "Aring" "\\xC3\\x85" "Ascr" "\\xF0\\x9D\\x92\\x9C" "Assign" "\\xE2\\x89\\x94" "Atilde" "\\xC3\\x83" "Auml" "\\xC3\\x84" "Backslash" "\\xE2\\x88\\x96" "Barv" "\\xE2\\xAB\\xA7" "Barwed" "\\xE2\\x8C\\x86" "Bcy" "\\xD0\\x91" "Because" "\\xE2\\x88\\xB5" "Bernoullis" "\\xE2\\x84\\xAC" "Beta" "\\xCE\\x92" "Bfr" "\\xF0\\x9D\\x94\\x85" "Bopf" "\\xF0\\x9D\\x94\\xB9" "Breve" "\\xCB\\x98" "Bscr" "\\xE2\\x84\\xAC" "Bumpeq" "\\xE2\\x89\\x8E" "CHcy" "\\xD0\\xA7" "COPY" "\\xC2\\xA9" "Cacute" "\\xC4\\x86" "Cap" "\\xE2\\x8B\\x92" "CapitalDifferentialD" "\\xE2\\x85\\x85" "Cayleys" "\\xE2\\x84\\xAD" "Ccaron" "\\xC4\\x8C" "Ccedil" "\\xC3\\x87" "Ccirc" "\\xC4\\x88" "Cconint" "\\xE2\\x88\\xB0" "Cdot" "\\xC4\\x8A" "Cedilla" "\\xC2\\xB8" "CenterDot" "\\xC2\\xB7" "Cfr" "\\xE2\\x84\\xAD" "Chi" "\\xCE\\xA7" "CircleDot" "\\xE2\\x8A\\x99" "CircleMinus" "\\xE2\\x8A\\x96" "CirclePlus" "\\xE2\\x8A\\x95" "CircleTimes" "\\xE2\\x8A\\x97" "ClockwiseContourIntegral" "\\xE2\\x88\\xB2" "CloseCurlyDoubleQuote" "\\xE2\\x80\\x9D" "CloseCurlyQuote" "\\xE2\\x80\\x99" "Colon" "\\xE2\\x88\\xB7" "Colone" "\\xE2\\xA9\\xB4" "Congruent" "\\xE2\\x89\\xA1" "Conint" "\\xE2\\x88\\xAF" "ContourIntegral" "\\xE2\\x88\\xAE" "Copf" "\\xE2\\x84\\x82" "Coproduct" "\\xE2\\x88\\x90" "CounterClockwiseContourIntegral" "\\xE2\\x88\\xB3" "Cross" "\\xE2\\xA8\\xAF" "Cscr" "\\xF0\\x9D\\x92\\x9E" "Cup" "\\xE2\\x8B\\x93" "CupCap" "\\xE2\\x89\\x8D" "DD" "\\xE2\\x85\\x85" "DDotrahd" "\\xE2\\xA4\\x91" "DJcy" "\\xD0\\x82" "DScy" "\\xD0\\x85" "DZcy" "\\xD0\\x8F" "Dagger" "\\xE2\\x80\\xA1" "Darr" "\\xE2\\x86\\xA1" "Dashv" "\\xE2\\xAB\\xA4" "Dcaron" "\\xC4\\x8E" "Dcy" "\\xD0\\x94" "Del" "\\xE2\\x88\\x87" "Delta" "\\xCE\\x94" "Dfr" "\\xF0\\x9D\\x94\\x87" "DiacriticalAcute" "\\xC2\\xB4" "DiacriticalDot" "\\xCB\\x99" "DiacriticalDoubleAcute" "\\xCB\\x9D" "DiacriticalGrave" "\\x60" "DiacriticalTilde" "\\xCB\\x9C" "Diamond" "\\xE2\\x8B\\x84" "DifferentialD" "\\xE2\\x85\\x86" "Dopf" "\\xF0\\x9D\\x94\\xBB" "Dot" "\\xC2\\xA8" "DotDot" "\\xE2\\x83\\x9C" "DotEqual" "\\xE2\\x89\\x90" "DoubleContourIntegral" "\\xE2\\x88\\xAF" "DoubleDot" "\\xC2\\xA8" "DoubleDownArrow" "\\xE2\\x87\\x93" "DoubleLeftArrow" "\\xE2\\x87\\x90" "DoubleLeftRightArrow" "\\xE2\\x87\\x94" "DoubleLeftTee" "\\xE2\\xAB\\xA4" "DoubleLongLeftArrow" "\\xE2\\x9F\\xB8" "DoubleLongLeftRightArrow" "\\xE2\\x9F\\xBA" "DoubleLongRightArrow" "\\xE2\\x9F\\xB9" "DoubleRightArrow" "\\xE2\\x87\\x92" "DoubleRightTee" "\\xE2\\x8A\\xA8" "DoubleUpArrow" "\\xE2\\x87\\x91" "DoubleUpDownArrow" "\\xE2\\x87\\x95" "DoubleVerticalBar" "\\xE2\\x88\\xA5" "DownArrow" "\\xE2\\x86\\x93" "DownArrowBar" "\\xE2\\xA4\\x93" "DownArrowUpArrow" "\\xE2\\x87\\xB5" "DownBreve" "\\xCC\\x91" "DownLeftRightVector" "\\xE2\\xA5\\x90" "DownLeftTeeVector" "\\xE2\\xA5\\x9E" "DownLeftVector" "\\xE2\\x86\\xBD" "DownLeftVectorBar" "\\xE2\\xA5\\x96" "DownRightTeeVector" "\\xE2\\xA5\\x9F" "DownRightVector" "\\xE2\\x87\\x81" "DownRightVectorBar" "\\xE2\\xA5\\x97" "DownTee" "\\xE2\\x8A\\xA4" "DownTeeArrow" "\\xE2\\x86\\xA7" "Downarrow" "\\xE2\\x87\\x93" "Dscr" "\\xF0\\x9D\\x92\\x9F" "Dstrok" "\\xC4\\x90" "ENG" "\\xC5\\x8A" "ETH" "\\xC3\\x90" "Eacute" "\\xC3\\x89" "Ecaron" "\\xC4\\x9A" "Ecirc" "\\xC3\\x8A" "Ecy" "\\xD0\\xAD" "Edot" "\\xC4\\x96" "Efr" "\\xF0\\x9D\\x94\\x88" "Egrave" "\\xC3\\x88" "Element" "\\xE2\\x88\\x88" "Emacr" "\\xC4\\x92" "EmptySmallSquare" "\\xE2\\x97\\xBB" "EmptyVerySmallSquare" "\\xE2\\x96\\xAB" "Eogon" "\\xC4\\x98" "Eopf" "\\xF0\\x9D\\x94\\xBC" "Epsilon" "\\xCE\\x95" "Equal" "\\xE2\\xA9\\xB5" "EqualTilde" "\\xE2\\x89\\x82" "Equilibrium" "\\xE2\\x87\\x8C" "Escr" "\\xE2\\x84\\xB0" "Esim" "\\xE2\\xA9\\xB3" "Eta" "\\xCE\\x97" "Euml" "\\xC3\\x8B" "Exists" "\\xE2\\x88\\x83" "ExponentialE" "\\xE2\\x85\\x87" "Fcy" "\\xD0\\xA4" "Ffr" "\\xF0\\x9D\\x94\\x89" "FilledSmallSquare" "\\xE2\\x97\\xBC" "FilledVerySmallSquare" "\\xE2\\x96\\xAA" "Fopf" "\\xF0\\x9D\\x94\\xBD" "ForAll" "\\xE2\\x88\\x80" "Fouriertrf" "\\xE2\\x84\\xB1" "Fscr" "\\xE2\\x84\\xB1" "GJcy" "\\xD0\\x83" "GT" "\\x3E" "Gamma" "\\xCE\\x93" "Gammad" "\\xCF\\x9C" "Gbreve" "\\xC4\\x9E" "Gcedil" "\\xC4\\xA2" "Gcirc" "\\xC4\\x9C" "Gcy" "\\xD0\\x93" "Gdot" "\\xC4\\xA0" "Gfr" "\\xF0\\x9D\\x94\\x8A" "Gg" "\\xE2\\x8B\\x99" "Gopf" "\\xF0\\x9D\\x94\\xBE" "GreaterEqual" "\\xE2\\x89\\xA5" "GreaterEqualLess" "\\xE2\\x8B\\x9B" "GreaterFullEqual" "\\xE2\\x89\\xA7" "GreaterGreater" "\\xE2\\xAA\\xA2" "GreaterLess" "\\xE2\\x89\\xB7" "GreaterSlantEqual" "\\xE2\\xA9\\xBE" "GreaterTilde" "\\xE2\\x89\\xB3" "Gscr" "\\xF0\\x9D\\x92\\xA2" "Gt" "\\xE2\\x89\\xAB" "HARDcy" "\\xD0\\xAA" "Hacek" "\\xCB\\x87" "Hat" "\\x5E" "Hcirc" "\\xC4\\xA4" "Hfr" "\\xE2\\x84\\x8C" "HilbertSpace" "\\xE2\\x84\\x8B" "Hopf" "\\xE2\\x84\\x8D" "HorizontalLine" "\\xE2\\x94\\x80" "Hscr" "\\xE2\\x84\\x8B" "Hstrok" "\\xC4\\xA6" "HumpDownHump" "\\xE2\\x89\\x8E" "HumpEqual" "\\xE2\\x89\\x8F" "IEcy" "\\xD0\\x95" "IJlig" "\\xC4\\xB2" "IOcy" "\\xD0\\x81" "Iacute" "\\xC3\\x8D" "Icirc" "\\xC3\\x8E" "Icy" "\\xD0\\x98" "Idot" "\\xC4\\xB0" "Ifr" "\\xE2\\x84\\x91" "Igrave" "\\xC3\\x8C" "Im" "\\xE2\\x84\\x91" "Imacr" "\\xC4\\xAA" "ImaginaryI" "\\xE2\\x85\\x88" "Implies" "\\xE2\\x87\\x92" "Int" "\\xE2\\x88\\xAC" "Integral" "\\xE2\\x88\\xAB" "Intersection" "\\xE2\\x8B\\x82" "InvisibleComma" "\\xE2\\x81\\xA3" "InvisibleTimes" "\\xE2\\x81\\xA2" "Iogon" "\\xC4\\xAE" "Iopf" "\\xF0\\x9D\\x95\\x80" "Iota" "\\xCE\\x99" "Iscr" "\\xE2\\x84\\x90" "Itilde" "\\xC4\\xA8" "Iukcy" "\\xD0\\x86" "Iuml" "\\xC3\\x8F" "Jcirc" "\\xC4\\xB4" "Jcy" "\\xD0\\x99" "Jfr" "\\xF0\\x9D\\x94\\x8D" "Jopf" "\\xF0\\x9D\\x95\\x81" "Jscr" "\\xF0\\x9D\\x92\\xA5" "Jsercy" "\\xD0\\x88" "Jukcy" "\\xD0\\x84" "KHcy" "\\xD0\\xA5" "KJcy" "\\xD0\\x8C" "Kappa" "\\xCE\\x9A" "Kcedil" "\\xC4\\xB6" "Kcy" "\\xD0\\x9A" "Kfr" "\\xF0\\x9D\\x94\\x8E" "Kopf" "\\xF0\\x9D\\x95\\x82" "Kscr" "\\xF0\\x9D\\x92\\xA6" "LJcy" "\\xD0\\x89" "LT" "\\x3C" "Lacute" "\\xC4\\xB9" "Lambda" "\\xCE\\x9B" "Lang" "\\xE2\\x9F\\xAA" "Laplacetrf" "\\xE2\\x84\\x92" "Larr" "\\xE2\\x86\\x9E" "Lcaron" "\\xC4\\xBD" "Lcedil" "\\xC4\\xBB" "Lcy" "\\xD0\\x9B" "LeftAngleBracket" "\\xE2\\x9F\\xA8" "LeftArrow" "\\xE2\\x86\\x90" "LeftArrowBar" "\\xE2\\x87\\xA4" "LeftArrowRightArrow" "\\xE2\\x87\\x86" "LeftCeiling" "\\xE2\\x8C\\x88" "LeftDoubleBracket" "\\xE2\\x9F\\xA6" "LeftDownTeeVector" "\\xE2\\xA5\\xA1" "LeftDownVector" "\\xE2\\x87\\x83" "LeftDownVectorBar" "\\xE2\\xA5\\x99" "LeftFloor" "\\xE2\\x8C\\x8A" "LeftRightArrow" "\\xE2\\x86\\x94" "LeftRightVector" "\\xE2\\xA5\\x8E" "LeftTee" "\\xE2\\x8A\\xA3" "LeftTeeArrow" "\\xE2\\x86\\xA4" "LeftTeeVector" "\\xE2\\xA5\\x9A" "LeftTriangle" "\\xE2\\x8A\\xB2" "LeftTriangleBar" "\\xE2\\xA7\\x8F" "LeftTriangleEqual" "\\xE2\\x8A\\xB4" "LeftUpDownVector" "\\xE2\\xA5\\x91" "LeftUpTeeVector" "\\xE2\\xA5\\xA0" "LeftUpVector" "\\xE2\\x86\\xBF" "LeftUpVectorBar" "\\xE2\\xA5\\x98" "LeftVector" "\\xE2\\x86\\xBC" "LeftVectorBar" "\\xE2\\xA5\\x92" "Leftarrow" "\\xE2\\x87\\x90" "Leftrightarrow" "\\xE2\\x87\\x94" "LessEqualGreater" "\\xE2\\x8B\\x9A" "LessFullEqual" "\\xE2\\x89\\xA6" "LessGreater" "\\xE2\\x89\\xB6" "LessLess" "\\xE2\\xAA\\xA1" "LessSlantEqual" "\\xE2\\xA9\\xBD" "LessTilde" "\\xE2\\x89\\xB2" "Lfr" "\\xF0\\x9D\\x94\\x8F" "Ll" "\\xE2\\x8B\\x98" "Lleftarrow" "\\xE2\\x87\\x9A" "Lmidot" "\\xC4\\xBF" "LongLeftArrow" "\\xE2\\x9F\\xB5" "LongLeftRightArrow" "\\xE2\\x9F\\xB7" "LongRightArrow" "\\xE2\\x9F\\xB6" "Longleftarrow" "\\xE2\\x9F\\xB8" "Longleftrightarrow" "\\xE2\\x9F\\xBA" "Longrightarrow" "\\xE2\\x9F\\xB9" "Lopf" "\\xF0\\x9D\\x95\\x83" "LowerLeftArrow" "\\xE2\\x86\\x99" "LowerRightArrow" "\\xE2\\x86\\x98" "Lscr" "\\xE2\\x84\\x92" "Lsh" "\\xE2\\x86\\xB0" "Lstrok" "\\xC5\\x81" "Lt" "\\xE2\\x89\\xAA" "Map" "\\xE2\\xA4\\x85" "Mcy" "\\xD0\\x9C" "MediumSpace" "\\xE2\\x81\\x9F" "Mellintrf" "\\xE2\\x84\\xB3" "Mfr" "\\xF0\\x9D\\x94\\x90" "MinusPlus" "\\xE2\\x88\\x93" "Mopf" "\\xF0\\x9D\\x95\\x84" "Mscr" "\\xE2\\x84\\xB3" "Mu" "\\xCE\\x9C" "NJcy" "\\xD0\\x8A" "Nacute" "\\xC5\\x83" "Ncaron" "\\xC5\\x87" "Ncedil" "\\xC5\\x85" "Ncy" "\\xD0\\x9D" "NegativeMediumSpace" "\\xE2\\x80\\x8B" "NegativeThickSpace" "\\xE2\\x80\\x8B" "NegativeThinSpace" "\\xE2\\x80\\x8B" "NegativeVeryThinSpace" "\\xE2\\x80\\x8B" "NestedGreaterGreater" "\\xE2\\x89\\xAB" "NestedLessLess" "\\xE2\\x89\\xAA" "NewLine" "\\x0A" "Nfr" "\\xF0\\x9D\\x94\\x91" "NoBreak" "\\xE2\\x81\\xA0" "NonBreakingSpace" "\\xC2\\xA0" "Nopf" "\\xE2\\x84\\x95" "Not" "\\xE2\\xAB\\xAC" "NotCongruent" "\\xE2\\x89\\xA2" "NotCupCap" "\\xE2\\x89\\xAD" "NotDoubleVerticalBar" "\\xE2\\x88\\xA6" "NotElement" "\\xE2\\x88\\x89" "NotEqual" "\\xE2\\x89\\xA0" "NotEqualTilde" "\\xE2\\x89\\x82\\xCC\\xB8" "NotExists" "\\xE2\\x88\\x84" "NotGreater" "\\xE2\\x89\\xAF" "NotGreaterEqual" "\\xE2\\x89\\xB1" "NotGreaterFullEqual" "\\xE2\\x89\\xA7\\xCC\\xB8" "NotGreaterGreater" "\\xE2\\x89\\xAB\\xCC\\xB8" "NotGreaterLess" "\\xE2\\x89\\xB9" "NotGreaterSlantEqual" "\\xE2\\xA9\\xBE\\xCC\\xB8" "NotGreaterTilde" "\\xE2\\x89\\xB5" "NotHumpDownHump" "\\xE2\\x89\\x8E\\xCC\\xB8" "NotHumpEqual" "\\xE2\\x89\\x8F\\xCC\\xB8" "NotLeftTriangle" "\\xE2\\x8B\\xAA" "NotLeftTriangleBar" "\\xE2\\xA7\\x8F\\xCC\\xB8" "NotLeftTriangleEqual" "\\xE2\\x8B\\xAC" "NotLess" "\\xE2\\x89\\xAE" "NotLessEqual" "\\xE2\\x89\\xB0" "NotLessGreater" "\\xE2\\x89\\xB8" "NotLessLess" "\\xE2\\x89\\xAA\\xCC\\xB8" "NotLessSlantEqual" "\\xE2\\xA9\\xBD\\xCC\\xB8" "NotLessTilde" "\\xE2\\x89\\xB4" "NotNestedGreaterGreater" "\\xE2\\xAA\\xA2\\xCC\\xB8" "NotNestedLessLess" "\\xE2\\xAA\\xA1\\xCC\\xB8" "NotPrecedes" "\\xE2\\x8A\\x80" "NotPrecedesEqual" "\\xE2\\xAA\\xAF\\xCC\\xB8" "NotPrecedesSlantEqual" "\\xE2\\x8B\\xA0" "NotReverseElement" "\\xE2\\x88\\x8C" "NotRightTriangle" "\\xE2\\x8B\\xAB" "NotRightTriangleBar" "\\xE2\\xA7\\x90\\xCC\\xB8" "NotRightTriangleEqual" "\\xE2\\x8B\\xAD" "NotSquareSubset" "\\xE2\\x8A\\x8F\\xCC\\xB8" "NotSquareSubsetEqual" "\\xE2\\x8B\\xA2" "NotSquareSuperset" "\\xE2\\x8A\\x90\\xCC\\xB8" "NotSquareSupersetEqual" "\\xE2\\x8B\\xA3" "NotSubset" "\\xE2\\x8A\\x82\\xE2\\x83\\x92" "NotSubsetEqual" "\\xE2\\x8A\\x88" "NotSucceeds" "\\xE2\\x8A\\x81" "NotSucceedsEqual" "\\xE2\\xAA\\xB0\\xCC\\xB8" "NotSucceedsSlantEqual" "\\xE2\\x8B\\xA1" "NotSucceedsTilde" "\\xE2\\x89\\xBF\\xCC\\xB8" "NotSuperset" "\\xE2\\x8A\\x83\\xE2\\x83\\x92" "NotSupersetEqual" "\\xE2\\x8A\\x89" "NotTilde" "\\xE2\\x89\\x81" "NotTildeEqual" "\\xE2\\x89\\x84" "NotTildeFullEqual" "\\xE2\\x89\\x87" "NotTildeTilde" "\\xE2\\x89\\x89" "NotVerticalBar" "\\xE2\\x88\\xA4" "Nscr" "\\xF0\\x9D\\x92\\xA9" "Ntilde" "\\xC3\\x91" "Nu" "\\xCE\\x9D" "OElig" "\\xC5\\x92" "Oacute" "\\xC3\\x93" "Ocirc" "\\xC3\\x94" "Ocy" "\\xD0\\x9E" "Odblac" "\\xC5\\x90" "Ofr" "\\xF0\\x9D\\x94\\x92" "Ograve" "\\xC3\\x92" "Omacr" "\\xC5\\x8C" "Omega" "\\xCE\\xA9" "Omicron" "\\xCE\\x9F" "Oopf" "\\xF0\\x9D\\x95\\x86" "OpenCurlyDoubleQuote" "\\xE2\\x80\\x9C" "OpenCurlyQuote" "\\xE2\\x80\\x98" "Or" "\\xE2\\xA9\\x94" "Oscr" "\\xF0\\x9D\\x92\\xAA" "Oslash" "\\xC3\\x98" "Otilde" "\\xC3\\x95" "Otimes" "\\xE2\\xA8\\xB7" "Ouml" "\\xC3\\x96" "OverBar" "\\xE2\\x80\\xBE" "OverBrace" "\\xE2\\x8F\\x9E" "OverBracket" "\\xE2\\x8E\\xB4" "OverParenthesis" "\\xE2\\x8F\\x9C" "PartialD" "\\xE2\\x88\\x82" "Pcy" "\\xD0\\x9F" "Pfr" "\\xF0\\x9D\\x94\\x93" "Phi" "\\xCE\\xA6" "Pi" "\\xCE\\xA0" "PlusMinus" "\\xC2\\xB1" "Poincareplane" "\\xE2\\x84\\x8C" "Popf" "\\xE2\\x84\\x99" "Pr" "\\xE2\\xAA\\xBB" "Precedes" "\\xE2\\x89\\xBA" "PrecedesEqual" "\\xE2\\xAA\\xAF" "PrecedesSlantEqual" "\\xE2\\x89\\xBC" "PrecedesTilde" "\\xE2\\x89\\xBE" "Prime" "\\xE2\\x80\\xB3" "Product" "\\xE2\\x88\\x8F" "Proportion" "\\xE2\\x88\\xB7" "Proportional" "\\xE2\\x88\\x9D" "Pscr" "\\xF0\\x9D\\x92\\xAB" "Psi" "\\xCE\\xA8" "QUOT" "\\x22" "Qfr" "\\xF0\\x9D\\x94\\x94" "Qopf" "\\xE2\\x84\\x9A" "Qscr" "\\xF0\\x9D\\x92\\xAC" "RBarr" "\\xE2\\xA4\\x90" "REG" "\\xC2\\xAE" "Racute" "\\xC5\\x94" "Rang" "\\xE2\\x9F\\xAB" "Rarr" "\\xE2\\x86\\xA0" "Rarrtl" "\\xE2\\xA4\\x96" "Rcaron" "\\xC5\\x98" "Rcedil" "\\xC5\\x96" "Rcy" "\\xD0\\xA0" "Re" "\\xE2\\x84\\x9C" "ReverseElement" "\\xE2\\x88\\x8B" "ReverseEquilibrium" "\\xE2\\x87\\x8B" "ReverseUpEquilibrium" "\\xE2\\xA5\\xAF" "Rfr" "\\xE2\\x84\\x9C" "Rho" "\\xCE\\xA1" "RightAngleBracket" "\\xE2\\x9F\\xA9" "RightArrow" "\\xE2\\x86\\x92" "RightArrowBar" "\\xE2\\x87\\xA5" "RightArrowLeftArrow" "\\xE2\\x87\\x84" "RightCeiling" "\\xE2\\x8C\\x89" "RightDoubleBracket" "\\xE2\\x9F\\xA7" "RightDownTeeVector" "\\xE2\\xA5\\x9D" "RightDownVector" "\\xE2\\x87\\x82" "RightDownVectorBar" "\\xE2\\xA5\\x95" "RightFloor" "\\xE2\\x8C\\x8B" "RightTee" "\\xE2\\x8A\\xA2" "RightTeeArrow" "\\xE2\\x86\\xA6" "RightTeeVector" "\\xE2\\xA5\\x9B" "RightTriangle" "\\xE2\\x8A\\xB3" "RightTriangleBar" "\\xE2\\xA7\\x90" "RightTriangleEqual" "\\xE2\\x8A\\xB5" "RightUpDownVector" "\\xE2\\xA5\\x8F" "RightUpTeeVector" "\\xE2\\xA5\\x9C" "RightUpVector" "\\xE2\\x86\\xBE" "RightUpVectorBar" "\\xE2\\xA5\\x94" "RightVector" "\\xE2\\x87\\x80" "RightVectorBar" "\\xE2\\xA5\\x93" "Rightarrow" "\\xE2\\x87\\x92" "Ropf" "\\xE2\\x84\\x9D" "RoundImplies" "\\xE2\\xA5\\xB0" "Rrightarrow" "\\xE2\\x87\\x9B" "Rscr" "\\xE2\\x84\\x9B" "Rsh" "\\xE2\\x86\\xB1" "RuleDelayed" "\\xE2\\xA7\\xB4" "SHCHcy" "\\xD0\\xA9" "SHcy" "\\xD0\\xA8" "SOFTcy" "\\xD0\\xAC" "Sacute" "\\xC5\\x9A" "Sc" "\\xE2\\xAA\\xBC" "Scaron" "\\xC5\\xA0" "Scedil" "\\xC5\\x9E" "Scirc" "\\xC5\\x9C" "Scy" "\\xD0\\xA1" "Sfr" "\\xF0\\x9D\\x94\\x96" "ShortDownArrow" "\\xE2\\x86\\x93" "ShortLeftArrow" "\\xE2\\x86\\x90" "ShortRightArrow" "\\xE2\\x86\\x92" "ShortUpArrow" "\\xE2\\x86\\x91" "Sigma" "\\xCE\\xA3" "SmallCircle" "\\xE2\\x88\\x98" "Sopf" "\\xF0\\x9D\\x95\\x8A" "Sqrt" "\\xE2\\x88\\x9A" "Square" "\\xE2\\x96\\xA1" "SquareIntersection" "\\xE2\\x8A\\x93" "SquareSubset" "\\xE2\\x8A\\x8F" "SquareSubsetEqual" "\\xE2\\x8A\\x91" "SquareSuperset" "\\xE2\\x8A\\x90" "SquareSupersetEqual" "\\xE2\\x8A\\x92" "SquareUnion" "\\xE2\\x8A\\x94" "Sscr" "\\xF0\\x9D\\x92\\xAE" "Star" "\\xE2\\x8B\\x86" "Sub" "\\xE2\\x8B\\x90" "Subset" "\\xE2\\x8B\\x90" "SubsetEqual" "\\xE2\\x8A\\x86" "Succeeds" "\\xE2\\x89\\xBB" "SucceedsEqual" "\\xE2\\xAA\\xB0" "SucceedsSlantEqual" "\\xE2\\x89\\xBD" "SucceedsTilde" "\\xE2\\x89\\xBF" "SuchThat" "\\xE2\\x88\\x8B" "Sum" "\\xE2\\x88\\x91" "Sup" "\\xE2\\x8B\\x91" "Superset" "\\xE2\\x8A\\x83" "SupersetEqual" "\\xE2\\x8A\\x87" "Supset" "\\xE2\\x8B\\x91" "THORN" "\\xC3\\x9E" "TRADE" "\\xE2\\x84\\xA2" "TSHcy" "\\xD0\\x8B" "TScy" "\\xD0\\xA6" "Tab" "\\x09" "Tau" "\\xCE\\xA4" "Tcaron" "\\xC5\\xA4" "Tcedil" "\\xC5\\xA2" "Tcy" "\\xD0\\xA2" "Tfr" "\\xF0\\x9D\\x94\\x97" "Therefore" "\\xE2\\x88\\xB4" "Theta" "\\xCE\\x98" "ThickSpace" "\\xE2\\x81\\x9F\\xE2\\x80\\x8A" "ThinSpace" "\\xE2\\x80\\x89" "Tilde" "\\xE2\\x88\\xBC" "TildeEqual" "\\xE2\\x89\\x83" "TildeFullEqual" "\\xE2\\x89\\x85" "TildeTilde" "\\xE2\\x89\\x88" "Topf" "\\xF0\\x9D\\x95\\x8B" "TripleDot" "\\xE2\\x83\\x9B" "Tscr" "\\xF0\\x9D\\x92\\xAF" "Tstrok" "\\xC5\\xA6" "Uacute" "\\xC3\\x9A" "Uarr" "\\xE2\\x86\\x9F" "Uarrocir" "\\xE2\\xA5\\x89" "Ubrcy" "\\xD0\\x8E" "Ubreve" "\\xC5\\xAC" "Ucirc" "\\xC3\\x9B" "Ucy" "\\xD0\\xA3" "Udblac" "\\xC5\\xB0" "Ufr" "\\xF0\\x9D\\x94\\x98" "Ugrave" "\\xC3\\x99" "Umacr" "\\xC5\\xAA" "UnderBar" "\\x5F" "UnderBrace" "\\xE2\\x8F\\x9F" "UnderBracket" "\\xE2\\x8E\\xB5" "UnderParenthesis" "\\xE2\\x8F\\x9D" "Union" "\\xE2\\x8B\\x83" "UnionPlus" "\\xE2\\x8A\\x8E" "Uogon" "\\xC5\\xB2" "Uopf" "\\xF0\\x9D\\x95\\x8C" "UpArrow" "\\xE2\\x86\\x91" "UpArrowBar" "\\xE2\\xA4\\x92" "UpArrowDownArrow" "\\xE2\\x87\\x85" "UpDownArrow" "\\xE2\\x86\\x95" "UpEquilibrium" "\\xE2\\xA5\\xAE" "UpTee" "\\xE2\\x8A\\xA5" "UpTeeArrow" "\\xE2\\x86\\xA5" "Uparrow" "\\xE2\\x87\\x91" "Updownarrow" "\\xE2\\x87\\x95" "UpperLeftArrow" "\\xE2\\x86\\x96" "UpperRightArrow" "\\xE2\\x86\\x97" "Upsi" "\\xCF\\x92" "Upsilon" "\\xCE\\xA5" "Uring" "\\xC5\\xAE" "Uscr" "\\xF0\\x9D\\x92\\xB0" "Utilde" "\\xC5\\xA8" "Uuml" "\\xC3\\x9C" "VDash" "\\xE2\\x8A\\xAB" "Vbar" "\\xE2\\xAB\\xAB" "Vcy" "\\xD0\\x92" "Vdash" "\\xE2\\x8A\\xA9" "Vdashl" "\\xE2\\xAB\\xA6" "Vee" "\\xE2\\x8B\\x81" "Verbar" "\\xE2\\x80\\x96" "Vert" "\\xE2\\x80\\x96" "VerticalBar" "\\xE2\\x88\\xA3" "VerticalLine" "\\x7C" "VerticalSeparator" "\\xE2\\x9D\\x98" "VerticalTilde" "\\xE2\\x89\\x80" "VeryThinSpace" "\\xE2\\x80\\x8A" "Vfr" "\\xF0\\x9D\\x94\\x99" "Vopf" "\\xF0\\x9D\\x95\\x8D" "Vscr" "\\xF0\\x9D\\x92\\xB1" "Vvdash" "\\xE2\\x8A\\xAA" "Wcirc" "\\xC5\\xB4" "Wedge" "\\xE2\\x8B\\x80" "Wfr" "\\xF0\\x9D\\x94\\x9A" "Wopf" "\\xF0\\x9D\\x95\\x8E" "Wscr" "\\xF0\\x9D\\x92\\xB2" "Xfr" "\\xF0\\x9D\\x94\\x9B" "Xi" "\\xCE\\x9E" "Xopf" "\\xF0\\x9D\\x95\\x8F" "Xscr" "\\xF0\\x9D\\x92\\xB3" "YAcy" "\\xD0\\xAF" "YIcy" "\\xD0\\x87" "YUcy" "\\xD0\\xAE" "Yacute" "\\xC3\\x9D" "Ycirc" "\\xC5\\xB6" "Ycy" "\\xD0\\xAB" "Yfr" "\\xF0\\x9D\\x94\\x9C" "Yopf" "\\xF0\\x9D\\x95\\x90" "Yscr" "\\xF0\\x9D\\x92\\xB4" "Yuml" "\\xC5\\xB8" "ZHcy" "\\xD0\\x96" "Zacute" "\\xC5\\xB9" "Zcaron" "\\xC5\\xBD" "Zcy" "\\xD0\\x97" "Zdot" "\\xC5\\xBB" "ZeroWidthSpace" "\\xE2\\x80\\x8B" "Zeta" "\\xCE\\x96" "Zfr" "\\xE2\\x84\\xA8" "Zopf" "\\xE2\\x84\\xA4" "Zscr" "\\xF0\\x9D\\x92\\xB5" "aacute" "\\xC3\\xA1" "abreve" "\\xC4\\x83" "ac" "\\xE2\\x88\\xBE" "acE" "\\xE2\\x88\\xBE\\xCC\\xB3" "acd" "\\xE2\\x88\\xBF" "acirc" "\\xC3\\xA2" "acute" "\\xC2\\xB4" "acy" "\\xD0\\xB0" "aelig" "\\xC3\\xA6" "af" "\\xE2\\x81\\xA1" "afr" "\\xF0\\x9D\\x94\\x9E" "agrave" "\\xC3\\xA0" "alefsym" "\\xE2\\x84\\xB5" "aleph" "\\xE2\\x84\\xB5" "alpha" "\\xCE\\xB1" "amacr" "\\xC4\\x81" "amalg" "\\xE2\\xA8\\xBF" "amp" "\\x26" "and" "\\xE2\\x88\\xA7" "andand" "\\xE2\\xA9\\x95" "andd" "\\xE2\\xA9\\x9C" "andslope" "\\xE2\\xA9\\x98" "andv" "\\xE2\\xA9\\x9A" "ang" "\\xE2\\x88\\xA0" "ange" "\\xE2\\xA6\\xA4" "angle" "\\xE2\\x88\\xA0" "angmsd" "\\xE2\\x88\\xA1" "angmsdaa" "\\xE2\\xA6\\xA8" "angmsdab" "\\xE2\\xA6\\xA9" "angmsdac" "\\xE2\\xA6\\xAA" "angmsdad" "\\xE2\\xA6\\xAB" "angmsdae" "\\xE2\\xA6\\xAC" "angmsdaf" "\\xE2\\xA6\\xAD" "angmsdag" "\\xE2\\xA6\\xAE" "angmsdah" "\\xE2\\xA6\\xAF" "angrt" "\\xE2\\x88\\x9F" "angrtvb" "\\xE2\\x8A\\xBE" "angrtvbd" "\\xE2\\xA6\\x9D" "angsph" "\\xE2\\x88\\xA2" "angst" "\\xC3\\x85" "angzarr" "\\xE2\\x8D\\xBC" "aogon" "\\xC4\\x85" "aopf" "\\xF0\\x9D\\x95\\x92" "ap" "\\xE2\\x89\\x88" "apE" "\\xE2\\xA9\\xB0" "apacir" "\\xE2\\xA9\\xAF" "ape" "\\xE2\\x89\\x8A" "apid" "\\xE2\\x89\\x8B" "apos" "\\x27" "approx" "\\xE2\\x89\\x88" "approxeq" "\\xE2\\x89\\x8A" "aring" "\\xC3\\xA5" "ascr" "\\xF0\\x9D\\x92\\xB6" "ast" "\\x2A" "asymp" "\\xE2\\x89\\x88" "asympeq" "\\xE2\\x89\\x8D" "atilde" "\\xC3\\xA3" "auml" "\\xC3\\xA4" "awconint" "\\xE2\\x88\\xB3" "awint" "\\xE2\\xA8\\x91" "bNot" "\\xE2\\xAB\\xAD" "backcong" "\\xE2\\x89\\x8C" "backepsilon" "\\xCF\\xB6" "backprime" "\\xE2\\x80\\xB5" "backsim" "\\xE2\\x88\\xBD" "backsimeq" "\\xE2\\x8B\\x8D" "barvee" "\\xE2\\x8A\\xBD" "barwed" "\\xE2\\x8C\\x85" "barwedge" "\\xE2\\x8C\\x85" "bbrk" "\\xE2\\x8E\\xB5" "bbrktbrk" "\\xE2\\x8E\\xB6" "bcong" "\\xE2\\x89\\x8C" "bcy" "\\xD0\\xB1" "bdquo" "\\xE2\\x80\\x9E" "becaus" "\\xE2\\x88\\xB5" "because" "\\xE2\\x88\\xB5" "bemptyv" "\\xE2\\xA6\\xB0" "bepsi" "\\xCF\\xB6" "bernou" "\\xE2\\x84\\xAC" "beta" "\\xCE\\xB2" "beth" "\\xE2\\x84\\xB6" "between" "\\xE2\\x89\\xAC" "bfr" "\\xF0\\x9D\\x94\\x9F" "bigcap" "\\xE2\\x8B\\x82" "bigcirc" "\\xE2\\x97\\xAF" "bigcup" "\\xE2\\x8B\\x83" "bigodot" "\\xE2\\xA8\\x80" "bigoplus" "\\xE2\\xA8\\x81" "bigotimes" "\\xE2\\xA8\\x82" "bigsqcup" "\\xE2\\xA8\\x86" "bigstar" "\\xE2\\x98\\x85" "bigtriangledown" "\\xE2\\x96\\xBD" "bigtriangleup" "\\xE2\\x96\\xB3" "biguplus" "\\xE2\\xA8\\x84" "bigvee" "\\xE2\\x8B\\x81" "bigwedge" "\\xE2\\x8B\\x80" "bkarow" "\\xE2\\xA4\\x8D" "blacklozenge" "\\xE2\\xA7\\xAB" "blacksquare" "\\xE2\\x96\\xAA" "blacktriangle" "\\xE2\\x96\\xB4" "blacktriangledown" "\\xE2\\x96\\xBE" "blacktriangleleft" "\\xE2\\x97\\x82" "blacktriangleright" "\\xE2\\x96\\xB8" "blank" "\\xE2\\x90\\xA3" "blk12" "\\xE2\\x96\\x92" "blk14" "\\xE2\\x96\\x91" "blk34" "\\xE2\\x96\\x93" "block" "\\xE2\\x96\\x88" "bne" "\\x3D\\xE2\\x83\\xA5" "bnequiv" "\\xE2\\x89\\xA1\\xE2\\x83\\xA5" "bnot" "\\xE2\\x8C\\x90" "bopf" "\\xF0\\x9D\\x95\\x93" "bot" "\\xE2\\x8A\\xA5" "bottom" "\\xE2\\x8A\\xA5" "bowtie" "\\xE2\\x8B\\x88" "boxDL" "\\xE2\\x95\\x97" "boxDR" "\\xE2\\x95\\x94" "boxDl" "\\xE2\\x95\\x96" "boxDr" "\\xE2\\x95\\x93" "boxH" "\\xE2\\x95\\x90" "boxHD" "\\xE2\\x95\\xA6" "boxHU" "\\xE2\\x95\\xA9" "boxHd" "\\xE2\\x95\\xA4" "boxHu" "\\xE2\\x95\\xA7" "boxUL" "\\xE2\\x95\\x9D" "boxUR" "\\xE2\\x95\\x9A" "boxUl" "\\xE2\\x95\\x9C" "boxUr" "\\xE2\\x95\\x99" "boxV" "\\xE2\\x95\\x91" "boxVH" "\\xE2\\x95\\xAC" "boxVL" "\\xE2\\x95\\xA3" "boxVR" "\\xE2\\x95\\xA0" "boxVh" "\\xE2\\x95\\xAB" "boxVl" "\\xE2\\x95\\xA2" "boxVr" "\\xE2\\x95\\x9F" "boxbox" "\\xE2\\xA7\\x89" "boxdL" "\\xE2\\x95\\x95" "boxdR" "\\xE2\\x95\\x92" "boxdl" "\\xE2\\x94\\x90" "boxdr" "\\xE2\\x94\\x8C" "boxh" "\\xE2\\x94\\x80" "boxhD" "\\xE2\\x95\\xA5" "boxhU" "\\xE2\\x95\\xA8" "boxhd" "\\xE2\\x94\\xAC" "boxhu" "\\xE2\\x94\\xB4" "boxminus" "\\xE2\\x8A\\x9F" "boxplus" "\\xE2\\x8A\\x9E" "boxtimes" "\\xE2\\x8A\\xA0" "boxuL" "\\xE2\\x95\\x9B" "boxuR" "\\xE2\\x95\\x98" "boxul" "\\xE2\\x94\\x98" "boxur" "\\xE2\\x94\\x94" "boxv" "\\xE2\\x94\\x82" "boxvH" "\\xE2\\x95\\xAA" "boxvL" "\\xE2\\x95\\xA1" "boxvR" "\\xE2\\x95\\x9E" "boxvh" "\\xE2\\x94\\xBC" "boxvl" "\\xE2\\x94\\xA4" "boxvr" "\\xE2\\x94\\x9C" "bprime" "\\xE2\\x80\\xB5" "breve" "\\xCB\\x98" "brvbar" "\\xC2\\xA6" "bscr" "\\xF0\\x9D\\x92\\xB7" "bsemi" "\\xE2\\x81\\x8F" "bsim" "\\xE2\\x88\\xBD" "bsime" "\\xE2\\x8B\\x8D" "bsol" "\\x5C" "bsolb" "\\xE2\\xA7\\x85" "bsolhsub" "\\xE2\\x9F\\x88" "bull" "\\xE2\\x80\\xA2" "bullet" "\\xE2\\x80\\xA2" "bump" "\\xE2\\x89\\x8E" "bumpE" "\\xE2\\xAA\\xAE" "bumpe" "\\xE2\\x89\\x8F" "bumpeq" "\\xE2\\x89\\x8F" "cacute" "\\xC4\\x87" "cap" "\\xE2\\x88\\xA9" "capand" "\\xE2\\xA9\\x84" "capbrcup" "\\xE2\\xA9\\x89" "capcap" "\\xE2\\xA9\\x8B" "capcup" "\\xE2\\xA9\\x87" "capdot" "\\xE2\\xA9\\x80" "caps" "\\xE2\\x88\\xA9\\xEF\\xB8\\x80" "caret" "\\xE2\\x81\\x81" "caron" "\\xCB\\x87" "ccaps" "\\xE2\\xA9\\x8D" "ccaron" "\\xC4\\x8D" "ccedil" "\\xC3\\xA7" "ccirc" "\\xC4\\x89" "ccups" "\\xE2\\xA9\\x8C" "ccupssm" "\\xE2\\xA9\\x90" "cdot" "\\xC4\\x8B" "cedil" "\\xC2\\xB8" "cemptyv" "\\xE2\\xA6\\xB2" "cent" "\\xC2\\xA2" "centerdot" "\\xC2\\xB7" "cfr" "\\xF0\\x9D\\x94\\xA0" "chcy" "\\xD1\\x87" "check" "\\xE2\\x9C\\x93" "checkmark" "\\xE2\\x9C\\x93" "chi" "\\xCF\\x87" "cir" "\\xE2\\x97\\x8B" "cirE" "\\xE2\\xA7\\x83" "circ" "\\xCB\\x86" "circeq" "\\xE2\\x89\\x97" "circlearrowleft" "\\xE2\\x86\\xBA" "circlearrowright" "\\xE2\\x86\\xBB" "circledR" "\\xC2\\xAE" "circledS" "\\xE2\\x93\\x88" "circledast" "\\xE2\\x8A\\x9B" "circledcirc" "\\xE2\\x8A\\x9A" "circleddash" "\\xE2\\x8A\\x9D" "cire" "\\xE2\\x89\\x97" "cirfnint" "\\xE2\\xA8\\x90" "cirmid" "\\xE2\\xAB\\xAF" "cirscir" "\\xE2\\xA7\\x82" "clubs" "\\xE2\\x99\\xA3" "clubsuit" "\\xE2\\x99\\xA3" "colon" "\\x3A" "colone" "\\xE2\\x89\\x94" "coloneq" "\\xE2\\x89\\x94" "comma" "\\x2C" "commat" "\\x40" "comp" "\\xE2\\x88\\x81" "compfn" "\\xE2\\x88\\x98" "complement" "\\xE2\\x88\\x81" "complexes" "\\xE2\\x84\\x82" "cong" "\\xE2\\x89\\x85" "congdot" "\\xE2\\xA9\\xAD" "conint" "\\xE2\\x88\\xAE" "copf" "\\xF0\\x9D\\x95\\x94" "coprod" "\\xE2\\x88\\x90" "copy" "\\xC2\\xA9" "copysr" "\\xE2\\x84\\x97" "crarr" "\\xE2\\x86\\xB5" "cross" "\\xE2\\x9C\\x97" "cscr" "\\xF0\\x9D\\x92\\xB8" "csub" "\\xE2\\xAB\\x8F" "csube" "\\xE2\\xAB\\x91" "csup" "\\xE2\\xAB\\x90" "csupe" "\\xE2\\xAB\\x92" "ctdot" "\\xE2\\x8B\\xAF" "cudarrl" "\\xE2\\xA4\\xB8" "cudarrr" "\\xE2\\xA4\\xB5" "cuepr" "\\xE2\\x8B\\x9E" "cuesc" "\\xE2\\x8B\\x9F" "cularr" "\\xE2\\x86\\xB6" "cularrp" "\\xE2\\xA4\\xBD" "cup" "\\xE2\\x88\\xAA" "cupbrcap" "\\xE2\\xA9\\x88" "cupcap" "\\xE2\\xA9\\x86" "cupcup" "\\xE2\\xA9\\x8A" "cupdot" "\\xE2\\x8A\\x8D" "cupor" "\\xE2\\xA9\\x85" "cups" "\\xE2\\x88\\xAA\\xEF\\xB8\\x80" "curarr" "\\xE2\\x86\\xB7" "curarrm" "\\xE2\\xA4\\xBC" "curlyeqprec" "\\xE2\\x8B\\x9E" "curlyeqsucc" "\\xE2\\x8B\\x9F" "curlyvee" "\\xE2\\x8B\\x8E" "curlywedge" "\\xE2\\x8B\\x8F" "curren" "\\xC2\\xA4" "curvearrowleft" "\\xE2\\x86\\xB6" "curvearrowright" "\\xE2\\x86\\xB7" "cuvee" "\\xE2\\x8B\\x8E" "cuwed" "\\xE2\\x8B\\x8F" "cwconint" "\\xE2\\x88\\xB2" "cwint" "\\xE2\\x88\\xB1" "cylcty" "\\xE2\\x8C\\xAD" "dArr" "\\xE2\\x87\\x93" "dHar" "\\xE2\\xA5\\xA5" "dagger" "\\xE2\\x80\\xA0" "daleth" "\\xE2\\x84\\xB8" "darr" "\\xE2\\x86\\x93" "dash" "\\xE2\\x80\\x90" "dashv" "\\xE2\\x8A\\xA3" "dbkarow" "\\xE2\\xA4\\x8F" "dblac" "\\xCB\\x9D" "dcaron" "\\xC4\\x8F" "dcy" "\\xD0\\xB4" "dd" "\\xE2\\x85\\x86" "ddagger" "\\xE2\\x80\\xA1" "ddarr" "\\xE2\\x87\\x8A" "ddotseq" "\\xE2\\xA9\\xB7" "deg" "\\xC2\\xB0" "delta" "\\xCE\\xB4" "demptyv" "\\xE2\\xA6\\xB1" "dfisht" "\\xE2\\xA5\\xBF" "dfr" "\\xF0\\x9D\\x94\\xA1" "dharl" "\\xE2\\x87\\x83" "dharr" "\\xE2\\x87\\x82" "diam" "\\xE2\\x8B\\x84" "diamond" "\\xE2\\x8B\\x84" "diamondsuit" "\\xE2\\x99\\xA6" "diams" "\\xE2\\x99\\xA6" "die" "\\xC2\\xA8" "digamma" "\\xCF\\x9D" "disin" "\\xE2\\x8B\\xB2" "div" "\\xC3\\xB7" "divide" "\\xC3\\xB7" "divideontimes" "\\xE2\\x8B\\x87" "divonx" "\\xE2\\x8B\\x87" "djcy" "\\xD1\\x92" "dlcorn" "\\xE2\\x8C\\x9E" "dlcrop" "\\xE2\\x8C\\x8D" "dollar" "\\x24" "dopf" "\\xF0\\x9D\\x95\\x95" "dot" "\\xCB\\x99" "doteq" "\\xE2\\x89\\x90" "doteqdot" "\\xE2\\x89\\x91" "dotminus" "\\xE2\\x88\\xB8" "dotplus" "\\xE2\\x88\\x94" "dotsquare" "\\xE2\\x8A\\xA1" "doublebarwedge" "\\xE2\\x8C\\x86" "downarrow" "\\xE2\\x86\\x93" "downdownarrows" "\\xE2\\x87\\x8A" "downharpoonleft" "\\xE2\\x87\\x83" "downharpoonright" "\\xE2\\x87\\x82" "drbkarow" "\\xE2\\xA4\\x90" "drcorn" "\\xE2\\x8C\\x9F" "drcrop" "\\xE2\\x8C\\x8C" "dscr" "\\xF0\\x9D\\x92\\xB9" "dscy" "\\xD1\\x95" "dsol" "\\xE2\\xA7\\xB6" "dstrok" "\\xC4\\x91" "dtdot" "\\xE2\\x8B\\xB1" "dtri" "\\xE2\\x96\\xBF" "dtrif" "\\xE2\\x96\\xBE" "duarr" "\\xE2\\x87\\xB5" "duhar" "\\xE2\\xA5\\xAF" "dwangle" "\\xE2\\xA6\\xA6" "dzcy" "\\xD1\\x9F" "dzigrarr" "\\xE2\\x9F\\xBF" "eDDot" "\\xE2\\xA9\\xB7" "eDot" "\\xE2\\x89\\x91" "eacute" "\\xC3\\xA9" "easter" "\\xE2\\xA9\\xAE" "ecaron" "\\xC4\\x9B" "ecir" "\\xE2\\x89\\x96" "ecirc" "\\xC3\\xAA" "ecolon" "\\xE2\\x89\\x95" "ecy" "\\xD1\\x8D" "edot" "\\xC4\\x97" "ee" "\\xE2\\x85\\x87" "efDot" "\\xE2\\x89\\x92" "efr" "\\xF0\\x9D\\x94\\xA2" "eg" "\\xE2\\xAA\\x9A" "egrave" "\\xC3\\xA8" "egs" "\\xE2\\xAA\\x96" "egsdot" "\\xE2\\xAA\\x98" "el" "\\xE2\\xAA\\x99" "elinters" "\\xE2\\x8F\\xA7" "ell" "\\xE2\\x84\\x93" "els" "\\xE2\\xAA\\x95" "elsdot" "\\xE2\\xAA\\x97" "emacr" "\\xC4\\x93" "empty" "\\xE2\\x88\\x85" "emptyset" "\\xE2\\x88\\x85" "emptyv" "\\xE2\\x88\\x85" "emsp" "\\xE2\\x80\\x83" "emsp13" "\\xE2\\x80\\x84" "emsp14" "\\xE2\\x80\\x85" "eng" "\\xC5\\x8B" "ensp" "\\xE2\\x80\\x82" "eogon" "\\xC4\\x99" "eopf" "\\xF0\\x9D\\x95\\x96" "epar" "\\xE2\\x8B\\x95" "eparsl" "\\xE2\\xA7\\xA3" "eplus" "\\xE2\\xA9\\xB1" "epsi" "\\xCE\\xB5" "epsilon" "\\xCE\\xB5" "epsiv" "\\xCF\\xB5" "eqcirc" "\\xE2\\x89\\x96" "eqcolon" "\\xE2\\x89\\x95" "eqsim" "\\xE2\\x89\\x82" "eqslantgtr" "\\xE2\\xAA\\x96" "eqslantless" "\\xE2\\xAA\\x95" "equals" "\\x3D" "equest" "\\xE2\\x89\\x9F" "equiv" "\\xE2\\x89\\xA1" "equivDD" "\\xE2\\xA9\\xB8" "eqvparsl" "\\xE2\\xA7\\xA5" "erDot" "\\xE2\\x89\\x93" "erarr" "\\xE2\\xA5\\xB1" "escr" "\\xE2\\x84\\xAF" "esdot" "\\xE2\\x89\\x90" "esim" "\\xE2\\x89\\x82" "eta" "\\xCE\\xB7" "eth" "\\xC3\\xB0" "euml" "\\xC3\\xAB" "euro" "\\xE2\\x82\\xAC" "excl" "\\x21" "exist" "\\xE2\\x88\\x83" "expectation" "\\xE2\\x84\\xB0" "exponentiale" "\\xE2\\x85\\x87" "fallingdotseq" "\\xE2\\x89\\x92" "fcy" "\\xD1\\x84" "female" "\\xE2\\x99\\x80" "ffilig" "\\xEF\\xAC\\x83" "fflig" "\\xEF\\xAC\\x80" "ffllig" "\\xEF\\xAC\\x84" "ffr" "\\xF0\\x9D\\x94\\xA3" "filig" "\\xEF\\xAC\\x81" "fjlig" "\\x66\\x6A" "flat" "\\xE2\\x99\\xAD" "fllig" "\\xEF\\xAC\\x82" "fltns" "\\xE2\\x96\\xB1" "fnof" "\\xC6\\x92" "fopf" "\\xF0\\x9D\\x95\\x97" "forall" "\\xE2\\x88\\x80" "fork" "\\xE2\\x8B\\x94" "forkv" "\\xE2\\xAB\\x99" "fpartint" "\\xE2\\xA8\\x8D" "frac12" "\\xC2\\xBD" "frac13" "\\xE2\\x85\\x93" "frac14" "\\xC2\\xBC" "frac15" "\\xE2\\x85\\x95" "frac16" "\\xE2\\x85\\x99" "frac18" "\\xE2\\x85\\x9B" "frac23" "\\xE2\\x85\\x94" "frac25" "\\xE2\\x85\\x96" "frac34" "\\xC2\\xBE" "frac35" "\\xE2\\x85\\x97" "frac38" "\\xE2\\x85\\x9C" "frac45" "\\xE2\\x85\\x98" "frac56" "\\xE2\\x85\\x9A" "frac58" "\\xE2\\x85\\x9D" "frac78" "\\xE2\\x85\\x9E" "frasl" "\\xE2\\x81\\x84" "frown" "\\xE2\\x8C\\xA2" "fscr" "\\xF0\\x9D\\x92\\xBB" "gE" "\\xE2\\x89\\xA7" "gEl" "\\xE2\\xAA\\x8C" "gacute" "\\xC7\\xB5" "gamma" "\\xCE\\xB3" "gammad" "\\xCF\\x9D" "gap" "\\xE2\\xAA\\x86" "gbreve" "\\xC4\\x9F" "gcirc" "\\xC4\\x9D" "gcy" "\\xD0\\xB3" "gdot" "\\xC4\\xA1" "ge" "\\xE2\\x89\\xA5" "gel" "\\xE2\\x8B\\x9B" "geq" "\\xE2\\x89\\xA5" "geqq" "\\xE2\\x89\\xA7" "geqslant" "\\xE2\\xA9\\xBE" "ges" "\\xE2\\xA9\\xBE" "gescc" "\\xE2\\xAA\\xA9" "gesdot" "\\xE2\\xAA\\x80" "gesdoto" "\\xE2\\xAA\\x82" "gesdotol" "\\xE2\\xAA\\x84" "gesl" "\\xE2\\x8B\\x9B\\xEF\\xB8\\x80" "gesles" "\\xE2\\xAA\\x94" "gfr" "\\xF0\\x9D\\x94\\xA4" "gg" "\\xE2\\x89\\xAB" "ggg" "\\xE2\\x8B\\x99" "gimel" "\\xE2\\x84\\xB7" "gjcy" "\\xD1\\x93" "gl" "\\xE2\\x89\\xB7" "glE" "\\xE2\\xAA\\x92" "gla" "\\xE2\\xAA\\xA5" "glj" "\\xE2\\xAA\\xA4" "gnE" "\\xE2\\x89\\xA9" "gnap" "\\xE2\\xAA\\x8A" "gnapprox" "\\xE2\\xAA\\x8A" "gne" "\\xE2\\xAA\\x88" "gneq" "\\xE2\\xAA\\x88" "gneqq" "\\xE2\\x89\\xA9" "gnsim" "\\xE2\\x8B\\xA7" "gopf" "\\xF0\\x9D\\x95\\x98" "grave" "\\x60" "gscr" "\\xE2\\x84\\x8A" "gsim" "\\xE2\\x89\\xB3" "gsime" "\\xE2\\xAA\\x8E" "gsiml" "\\xE2\\xAA\\x90" "gt" "\\x3E" "gtcc" "\\xE2\\xAA\\xA7" "gtcir" "\\xE2\\xA9\\xBA" "gtdot" "\\xE2\\x8B\\x97" "gtlPar" "\\xE2\\xA6\\x95" "gtquest" "\\xE2\\xA9\\xBC" "gtrapprox" "\\xE2\\xAA\\x86" "gtrarr" "\\xE2\\xA5\\xB8" "gtrdot" "\\xE2\\x8B\\x97" "gtreqless" "\\xE2\\x8B\\x9B" "gtreqqless" "\\xE2\\xAA\\x8C" "gtrless" "\\xE2\\x89\\xB7" "gtrsim" "\\xE2\\x89\\xB3" "gvertneqq" "\\xE2\\x89\\xA9\\xEF\\xB8\\x80" "gvnE" "\\xE2\\x89\\xA9\\xEF\\xB8\\x80" "hArr" "\\xE2\\x87\\x94" "hairsp" "\\xE2\\x80\\x8A" "half" "\\xC2\\xBD" "hamilt" "\\xE2\\x84\\x8B" "hardcy" "\\xD1\\x8A" "harr" "\\xE2\\x86\\x94" "harrcir" "\\xE2\\xA5\\x88" "harrw" "\\xE2\\x86\\xAD" "hbar" "\\xE2\\x84\\x8F" "hcirc" "\\xC4\\xA5" "hearts" "\\xE2\\x99\\xA5" "heartsuit" "\\xE2\\x99\\xA5" "hellip" "\\xE2\\x80\\xA6" "hercon" "\\xE2\\x8A\\xB9" "hfr" "\\xF0\\x9D\\x94\\xA5" "hksearow" "\\xE2\\xA4\\xA5" "hkswarow" "\\xE2\\xA4\\xA6" "hoarr" "\\xE2\\x87\\xBF" "homtht" "\\xE2\\x88\\xBB" "hookleftarrow" "\\xE2\\x86\\xA9" "hookrightarrow" "\\xE2\\x86\\xAA" "hopf" "\\xF0\\x9D\\x95\\x99" "horbar" "\\xE2\\x80\\x95" "hscr" "\\xF0\\x9D\\x92\\xBD" "hslash" "\\xE2\\x84\\x8F" "hstrok" "\\xC4\\xA7" "hybull" "\\xE2\\x81\\x83" "hyphen" "\\xE2\\x80\\x90" "iacute" "\\xC3\\xAD" "ic" "\\xE2\\x81\\xA3" "icirc" "\\xC3\\xAE" "icy" "\\xD0\\xB8" "iecy" "\\xD0\\xB5" "iexcl" "\\xC2\\xA1" "iff" "\\xE2\\x87\\x94" "ifr" "\\xF0\\x9D\\x94\\xA6" "igrave" "\\xC3\\xAC" "ii" "\\xE2\\x85\\x88" "iiiint" "\\xE2\\xA8\\x8C" "iiint" "\\xE2\\x88\\xAD" "iinfin" "\\xE2\\xA7\\x9C" "iiota" "\\xE2\\x84\\xA9" "ijlig" "\\xC4\\xB3" "imacr" "\\xC4\\xAB" "image" "\\xE2\\x84\\x91" "imagline" "\\xE2\\x84\\x90" "imagpart" "\\xE2\\x84\\x91" "imath" "\\xC4\\xB1" "imof" "\\xE2\\x8A\\xB7" "imped" "\\xC6\\xB5" "in" "\\xE2\\x88\\x88" "incare" "\\xE2\\x84\\x85" "infin" "\\xE2\\x88\\x9E" "infintie" "\\xE2\\xA7\\x9D" "inodot" "\\xC4\\xB1" "int" "\\xE2\\x88\\xAB" "intcal" "\\xE2\\x8A\\xBA" "integers" "\\xE2\\x84\\xA4" "intercal" "\\xE2\\x8A\\xBA" "intlarhk" "\\xE2\\xA8\\x97" "intprod" "\\xE2\\xA8\\xBC" "iocy" "\\xD1\\x91" "iogon" "\\xC4\\xAF" "iopf" "\\xF0\\x9D\\x95\\x9A" "iota" "\\xCE\\xB9" "iprod" "\\xE2\\xA8\\xBC" "iquest" "\\xC2\\xBF" "iscr" "\\xF0\\x9D\\x92\\xBE" "isin" "\\xE2\\x88\\x88" "isinE" "\\xE2\\x8B\\xB9" "isindot" "\\xE2\\x8B\\xB5" "isins" "\\xE2\\x8B\\xB4" "isinsv" "\\xE2\\x8B\\xB3" "isinv" "\\xE2\\x88\\x88" "it" "\\xE2\\x81\\xA2" "itilde" "\\xC4\\xA9" "iukcy" "\\xD1\\x96" "iuml" "\\xC3\\xAF" "jcirc" "\\xC4\\xB5" "jcy" "\\xD0\\xB9" "jfr" "\\xF0\\x9D\\x94\\xA7" "jmath" "\\xC8\\xB7" "jopf" "\\xF0\\x9D\\x95\\x9B" "jscr" "\\xF0\\x9D\\x92\\xBF" "jsercy" "\\xD1\\x98" "jukcy" "\\xD1\\x94" "kappa" "\\xCE\\xBA" "kappav" "\\xCF\\xB0" "kcedil" "\\xC4\\xB7" "kcy" "\\xD0\\xBA" "kfr" "\\xF0\\x9D\\x94\\xA8" "kgreen" "\\xC4\\xB8" "khcy" "\\xD1\\x85" "kjcy" "\\xD1\\x9C" "kopf" "\\xF0\\x9D\\x95\\x9C" "kscr" "\\xF0\\x9D\\x93\\x80" "lAarr" "\\xE2\\x87\\x9A" "lArr" "\\xE2\\x87\\x90" "lAtail" "\\xE2\\xA4\\x9B" "lBarr" "\\xE2\\xA4\\x8E" "lE" "\\xE2\\x89\\xA6" "lEg" "\\xE2\\xAA\\x8B" "lHar" "\\xE2\\xA5\\xA2" "lacute" "\\xC4\\xBA" "laemptyv" "\\xE2\\xA6\\xB4" "lagran" "\\xE2\\x84\\x92" "lambda" "\\xCE\\xBB" "lang" "\\xE2\\x9F\\xA8" "langd" "\\xE2\\xA6\\x91" "langle" "\\xE2\\x9F\\xA8" "lap" "\\xE2\\xAA\\x85" "laquo" "\\xC2\\xAB" "larr" "\\xE2\\x86\\x90" "larrb" "\\xE2\\x87\\xA4" "larrbfs" "\\xE2\\xA4\\x9F" "larrfs" "\\xE2\\xA4\\x9D" "larrhk" "\\xE2\\x86\\xA9" "larrlp" "\\xE2\\x86\\xAB" "larrpl" "\\xE2\\xA4\\xB9" "larrsim" "\\xE2\\xA5\\xB3" "larrtl" "\\xE2\\x86\\xA2" "lat" "\\xE2\\xAA\\xAB" "latail" "\\xE2\\xA4\\x99" "late" "\\xE2\\xAA\\xAD" "lates" "\\xE2\\xAA\\xAD\\xEF\\xB8\\x80" "lbarr" "\\xE2\\xA4\\x8C" "lbbrk" "\\xE2\\x9D\\xB2" "lbrace" "\\x7B" "lbrack" "\\x5B" "lbrke" "\\xE2\\xA6\\x8B" "lbrksld" "\\xE2\\xA6\\x8F" "lbrkslu" "\\xE2\\xA6\\x8D" "lcaron" "\\xC4\\xBE" "lcedil" "\\xC4\\xBC" "lceil" "\\xE2\\x8C\\x88" "lcub" "\\x7B" "lcy" "\\xD0\\xBB" "ldca" "\\xE2\\xA4\\xB6" "ldquo" "\\xE2\\x80\\x9C" "ldquor" "\\xE2\\x80\\x9E" "ldrdhar" "\\xE2\\xA5\\xA7" "ldrushar" "\\xE2\\xA5\\x8B" "ldsh" "\\xE2\\x86\\xB2" "le" "\\xE2\\x89\\xA4" "leftarrow" "\\xE2\\x86\\x90" "leftarrowtail" "\\xE2\\x86\\xA2" "leftharpoondown" "\\xE2\\x86\\xBD" "leftharpoonup" "\\xE2\\x86\\xBC" "leftleftarrows" "\\xE2\\x87\\x87" "leftrightarrow" "\\xE2\\x86\\x94" "leftrightarrows" "\\xE2\\x87\\x86" "leftrightharpoons" "\\xE2\\x87\\x8B" "leftrightsquigarrow" "\\xE2\\x86\\xAD" "leftthreetimes" "\\xE2\\x8B\\x8B" "leg" "\\xE2\\x8B\\x9A" "leq" "\\xE2\\x89\\xA4" "leqq" "\\xE2\\x89\\xA6" "leqslant" "\\xE2\\xA9\\xBD" "les" "\\xE2\\xA9\\xBD" "lescc" "\\xE2\\xAA\\xA8" "lesdot" "\\xE2\\xA9\\xBF" "lesdoto" "\\xE2\\xAA\\x81" "lesdotor" "\\xE2\\xAA\\x83" "lesg" "\\xE2\\x8B\\x9A\\xEF\\xB8\\x80" "lesges" "\\xE2\\xAA\\x93" "lessapprox" "\\xE2\\xAA\\x85" "lessdot" "\\xE2\\x8B\\x96" "lesseqgtr" "\\xE2\\x8B\\x9A" "lesseqqgtr" "\\xE2\\xAA\\x8B" "lessgtr" "\\xE2\\x89\\xB6" "lesssim" "\\xE2\\x89\\xB2" "lfisht" "\\xE2\\xA5\\xBC" "lfloor" "\\xE2\\x8C\\x8A" "lfr" "\\xF0\\x9D\\x94\\xA9" "lg" "\\xE2\\x89\\xB6" "lgE" "\\xE2\\xAA\\x91" "lhard" "\\xE2\\x86\\xBD" "lharu" "\\xE2\\x86\\xBC" "lharul" "\\xE2\\xA5\\xAA" "lhblk" "\\xE2\\x96\\x84" "ljcy" "\\xD1\\x99" "ll" "\\xE2\\x89\\xAA" "llarr" "\\xE2\\x87\\x87" "llcorner" "\\xE2\\x8C\\x9E" "llhard" "\\xE2\\xA5\\xAB" "lltri" "\\xE2\\x97\\xBA" "lmidot" "\\xC5\\x80" "lmoust" "\\xE2\\x8E\\xB0" "lmoustache" "\\xE2\\x8E\\xB0" "lnE" "\\xE2\\x89\\xA8" "lnap" "\\xE2\\xAA\\x89" "lnapprox" "\\xE2\\xAA\\x89" "lne" "\\xE2\\xAA\\x87" "lneq" "\\xE2\\xAA\\x87" "lneqq" "\\xE2\\x89\\xA8" "lnsim" "\\xE2\\x8B\\xA6" "loang" "\\xE2\\x9F\\xAC" "loarr" "\\xE2\\x87\\xBD" "lobrk" "\\xE2\\x9F\\xA6" "longleftarrow" "\\xE2\\x9F\\xB5" "longleftrightarrow" "\\xE2\\x9F\\xB7" "longmapsto" "\\xE2\\x9F\\xBC" "longrightarrow" "\\xE2\\x9F\\xB6" "looparrowleft" "\\xE2\\x86\\xAB" "looparrowright" "\\xE2\\x86\\xAC" "lopar" "\\xE2\\xA6\\x85" "lopf" "\\xF0\\x9D\\x95\\x9D" "loplus" "\\xE2\\xA8\\xAD" "lotimes" "\\xE2\\xA8\\xB4" "lowast" "\\xE2\\x88\\x97" "lowbar" "\\x5F" "loz" "\\xE2\\x97\\x8A" "lozenge" "\\xE2\\x97\\x8A" "lozf" "\\xE2\\xA7\\xAB" "lpar" "\\x28" "lparlt" "\\xE2\\xA6\\x93" "lrarr" "\\xE2\\x87\\x86" "lrcorner" "\\xE2\\x8C\\x9F" "lrhar" "\\xE2\\x87\\x8B" "lrhard" "\\xE2\\xA5\\xAD" "lrm" "\\xE2\\x80\\x8E" "lrtri" "\\xE2\\x8A\\xBF" "lsaquo" "\\xE2\\x80\\xB9" "lscr" "\\xF0\\x9D\\x93\\x81" "lsh" "\\xE2\\x86\\xB0" "lsim" "\\xE2\\x89\\xB2" "lsime" "\\xE2\\xAA\\x8D" "lsimg" "\\xE2\\xAA\\x8F" "lsqb" "\\x5B" "lsquo" "\\xE2\\x80\\x98" "lsquor" "\\xE2\\x80\\x9A" "lstrok" "\\xC5\\x82" "lt" "\\x3C" "ltcc" "\\xE2\\xAA\\xA6" "ltcir" "\\xE2\\xA9\\xB9" "ltdot" "\\xE2\\x8B\\x96" "lthree" "\\xE2\\x8B\\x8B" "ltimes" "\\xE2\\x8B\\x89" "ltlarr" "\\xE2\\xA5\\xB6" "ltquest" "\\xE2\\xA9\\xBB" "ltrPar" "\\xE2\\xA6\\x96" "ltri" "\\xE2\\x97\\x83" "ltrie" "\\xE2\\x8A\\xB4" "ltrif" "\\xE2\\x97\\x82" "lurdshar" "\\xE2\\xA5\\x8A" "luruhar" "\\xE2\\xA5\\xA6" "lvertneqq" "\\xE2\\x89\\xA8\\xEF\\xB8\\x80" "lvnE" "\\xE2\\x89\\xA8\\xEF\\xB8\\x80" "mDDot" "\\xE2\\x88\\xBA" "macr" "\\xC2\\xAF" "male" "\\xE2\\x99\\x82" "malt" "\\xE2\\x9C\\xA0" "maltese" "\\xE2\\x9C\\xA0" "map" "\\xE2\\x86\\xA6" "mapsto" "\\xE2\\x86\\xA6" "mapstodown" "\\xE2\\x86\\xA7" "mapstoleft" "\\xE2\\x86\\xA4" "mapstoup" "\\xE2\\x86\\xA5" "marker" "\\xE2\\x96\\xAE" "mcomma" "\\xE2\\xA8\\xA9" "mcy" "\\xD0\\xBC" "mdash" "\\xE2\\x80\\x94" "measuredangle" "\\xE2\\x88\\xA1" "mfr" "\\xF0\\x9D\\x94\\xAA" "mho" "\\xE2\\x84\\xA7" "micro" "\\xC2\\xB5" "mid" "\\xE2\\x88\\xA3" "midast" "\\x2A" "midcir" "\\xE2\\xAB\\xB0" "middot" "\\xC2\\xB7" "minus" "\\xE2\\x88\\x92" "minusb" "\\xE2\\x8A\\x9F" "minusd" "\\xE2\\x88\\xB8" "minusdu" "\\xE2\\xA8\\xAA" "mlcp" "\\xE2\\xAB\\x9B" "mldr" "\\xE2\\x80\\xA6" "mnplus" "\\xE2\\x88\\x93" "models" "\\xE2\\x8A\\xA7" "mopf" "\\xF0\\x9D\\x95\\x9E" "mp" "\\xE2\\x88\\x93" "mscr" "\\xF0\\x9D\\x93\\x82" "mstpos" "\\xE2\\x88\\xBE" "mu" "\\xCE\\xBC" "multimap" "\\xE2\\x8A\\xB8" "mumap" "\\xE2\\x8A\\xB8" "nGg" "\\xE2\\x8B\\x99\\xCC\\xB8" "nGtv" "\\xE2\\x89\\xAB\\xCC\\xB8" "nLeftarrow" "\\xE2\\x87\\x8D" "nLeftrightarrow" "\\xE2\\x87\\x8E" "nLl" "\\xE2\\x8B\\x98\\xCC\\xB8" "nLtv" "\\xE2\\x89\\xAA\\xCC\\xB8" "nRightarrow" "\\xE2\\x87\\x8F" "nVDash" "\\xE2\\x8A\\xAF" "nVdash" "\\xE2\\x8A\\xAE" "nabla" "\\xE2\\x88\\x87" "nacute" "\\xC5\\x84" "nang" "\\xE2\\x88\\xA0\\xE2\\x83\\x92" "nap" "\\xE2\\x89\\x89" "napE" "\\xE2\\xA9\\xB0\\xCC\\xB8" "napid" "\\xE2\\x89\\x8B\\xCC\\xB8" "napos" "\\xC5\\x89" "napprox" "\\xE2\\x89\\x89" "natur" "\\xE2\\x99\\xAE" "natural" "\\xE2\\x99\\xAE" "naturals" "\\xE2\\x84\\x95" "nbsp" "\\xC2\\xA0" "nbump" "\\xE2\\x89\\x8E\\xCC\\xB8" "nbumpe" "\\xE2\\x89\\x8F\\xCC\\xB8" "ncap" "\\xE2\\xA9\\x83" "ncaron" "\\xC5\\x88" "ncedil" "\\xC5\\x86" "ncong" "\\xE2\\x89\\x87" "ncongdot" "\\xE2\\xA9\\xAD\\xCC\\xB8" "ncup" "\\xE2\\xA9\\x82" "ncy" "\\xD0\\xBD" "ndash" "\\xE2\\x80\\x93" "ne" "\\xE2\\x89\\xA0" "neArr" "\\xE2\\x87\\x97" "nearhk" "\\xE2\\xA4\\xA4" "nearr" "\\xE2\\x86\\x97" "nearrow" "\\xE2\\x86\\x97" "nedot" "\\xE2\\x89\\x90\\xCC\\xB8" "nequiv" "\\xE2\\x89\\xA2" "nesear" "\\xE2\\xA4\\xA8" "nesim" "\\xE2\\x89\\x82\\xCC\\xB8" "nexist" "\\xE2\\x88\\x84" "nexists" "\\xE2\\x88\\x84" "nfr" "\\xF0\\x9D\\x94\\xAB" "ngE" "\\xE2\\x89\\xA7\\xCC\\xB8" "nge" "\\xE2\\x89\\xB1" "ngeq" "\\xE2\\x89\\xB1" "ngeqq" "\\xE2\\x89\\xA7\\xCC\\xB8" "ngeqslant" "\\xE2\\xA9\\xBE\\xCC\\xB8" "nges" "\\xE2\\xA9\\xBE\\xCC\\xB8" "ngsim" "\\xE2\\x89\\xB5" "ngt" "\\xE2\\x89\\xAF" "ngtr" "\\xE2\\x89\\xAF" "nhArr" "\\xE2\\x87\\x8E" "nharr" "\\xE2\\x86\\xAE" "nhpar" "\\xE2\\xAB\\xB2" "ni" "\\xE2\\x88\\x8B" "nis" "\\xE2\\x8B\\xBC" "nisd" "\\xE2\\x8B\\xBA" "niv" "\\xE2\\x88\\x8B" "njcy" "\\xD1\\x9A" "nlArr" "\\xE2\\x87\\x8D" "nlE" "\\xE2\\x89\\xA6\\xCC\\xB8" "nlarr" "\\xE2\\x86\\x9A" "nldr" "\\xE2\\x80\\xA5" "nle" "\\xE2\\x89\\xB0" "nleftarrow" "\\xE2\\x86\\x9A" "nleftrightarrow" "\\xE2\\x86\\xAE" "nleq" "\\xE2\\x89\\xB0" "nleqq" "\\xE2\\x89\\xA6\\xCC\\xB8" "nleqslant" "\\xE2\\xA9\\xBD\\xCC\\xB8" "nles" "\\xE2\\xA9\\xBD\\xCC\\xB8" "nless" "\\xE2\\x89\\xAE" "nlsim" "\\xE2\\x89\\xB4" "nlt" "\\xE2\\x89\\xAE" "nltri" "\\xE2\\x8B\\xAA" "nltrie" "\\xE2\\x8B\\xAC" "nmid" "\\xE2\\x88\\xA4" "nopf" "\\xF0\\x9D\\x95\\x9F" "not" "\\xC2\\xAC" "notin" "\\xE2\\x88\\x89" "notinE" "\\xE2\\x8B\\xB9\\xCC\\xB8" "notindot" "\\xE2\\x8B\\xB5\\xCC\\xB8" "notinva" "\\xE2\\x88\\x89" "notinvb" "\\xE2\\x8B\\xB7" "notinvc" "\\xE2\\x8B\\xB6" "notni" "\\xE2\\x88\\x8C" "notniva" "\\xE2\\x88\\x8C" "notnivb" "\\xE2\\x8B\\xBE" "notnivc" "\\xE2\\x8B\\xBD" "npar" "\\xE2\\x88\\xA6" "nparallel" "\\xE2\\x88\\xA6" "nparsl" "\\xE2\\xAB\\xBD\\xE2\\x83\\xA5" "npart" "\\xE2\\x88\\x82\\xCC\\xB8" "npolint" "\\xE2\\xA8\\x94" "npr" "\\xE2\\x8A\\x80" "nprcue" "\\xE2\\x8B\\xA0" "npre" "\\xE2\\xAA\\xAF\\xCC\\xB8" "nprec" "\\xE2\\x8A\\x80" "npreceq" "\\xE2\\xAA\\xAF\\xCC\\xB8" "nrArr" "\\xE2\\x87\\x8F" "nrarr" "\\xE2\\x86\\x9B" "nrarrc" "\\xE2\\xA4\\xB3\\xCC\\xB8" "nrarrw" "\\xE2\\x86\\x9D\\xCC\\xB8" "nrightarrow" "\\xE2\\x86\\x9B" "nrtri" "\\xE2\\x8B\\xAB" "nrtrie" "\\xE2\\x8B\\xAD" "nsc" "\\xE2\\x8A\\x81" "nsccue" "\\xE2\\x8B\\xA1" "nsce" "\\xE2\\xAA\\xB0\\xCC\\xB8" "nscr" "\\xF0\\x9D\\x93\\x83" "nshortmid" "\\xE2\\x88\\xA4" "nshortparallel" "\\xE2\\x88\\xA6" "nsim" "\\xE2\\x89\\x81" "nsime" "\\xE2\\x89\\x84" "nsimeq" "\\xE2\\x89\\x84" "nsmid" "\\xE2\\x88\\xA4" "nspar" "\\xE2\\x88\\xA6" "nsqsube" "\\xE2\\x8B\\xA2" "nsqsupe" "\\xE2\\x8B\\xA3" "nsub" "\\xE2\\x8A\\x84" "nsubE" "\\xE2\\xAB\\x85\\xCC\\xB8" "nsube" "\\xE2\\x8A\\x88" "nsubset" "\\xE2\\x8A\\x82\\xE2\\x83\\x92" "nsubseteq" "\\xE2\\x8A\\x88" "nsubseteqq" "\\xE2\\xAB\\x85\\xCC\\xB8" "nsucc" "\\xE2\\x8A\\x81" "nsucceq" "\\xE2\\xAA\\xB0\\xCC\\xB8" "nsup" "\\xE2\\x8A\\x85" "nsupE" "\\xE2\\xAB\\x86\\xCC\\xB8" "nsupe" "\\xE2\\x8A\\x89" "nsupset" "\\xE2\\x8A\\x83\\xE2\\x83\\x92" "nsupseteq" "\\xE2\\x8A\\x89" "nsupseteqq" "\\xE2\\xAB\\x86\\xCC\\xB8" "ntgl" "\\xE2\\x89\\xB9" "ntilde" "\\xC3\\xB1" "ntlg" "\\xE2\\x89\\xB8" "ntriangleleft" "\\xE2\\x8B\\xAA" "ntrianglelefteq" "\\xE2\\x8B\\xAC" "ntriangleright" "\\xE2\\x8B\\xAB" "ntrianglerighteq" "\\xE2\\x8B\\xAD" "nu" "\\xCE\\xBD" "num" "\\x23" "numero" "\\xE2\\x84\\x96" "numsp" "\\xE2\\x80\\x87" "nvDash" "\\xE2\\x8A\\xAD" "nvHarr" "\\xE2\\xA4\\x84" "nvap" "\\xE2\\x89\\x8D\\xE2\\x83\\x92" "nvdash" "\\xE2\\x8A\\xAC" "nvge" "\\xE2\\x89\\xA5\\xE2\\x83\\x92" "nvgt" "\\x3E\\xE2\\x83\\x92" "nvinfin" "\\xE2\\xA7\\x9E" "nvlArr" "\\xE2\\xA4\\x82" "nvle" "\\xE2\\x89\\xA4\\xE2\\x83\\x92" "nvlt" "\\x3C\\xE2\\x83\\x92" "nvltrie" "\\xE2\\x8A\\xB4\\xE2\\x83\\x92" "nvrArr" "\\xE2\\xA4\\x83" "nvrtrie" "\\xE2\\x8A\\xB5\\xE2\\x83\\x92" "nvsim" "\\xE2\\x88\\xBC\\xE2\\x83\\x92" "nwArr" "\\xE2\\x87\\x96" "nwarhk" "\\xE2\\xA4\\xA3" "nwarr" "\\xE2\\x86\\x96" "nwarrow" "\\xE2\\x86\\x96" "nwnear" "\\xE2\\xA4\\xA7" "oS" "\\xE2\\x93\\x88" "oacute" "\\xC3\\xB3" "oast" "\\xE2\\x8A\\x9B" "ocir" "\\xE2\\x8A\\x9A" "ocirc" "\\xC3\\xB4" "ocy" "\\xD0\\xBE" "odash" "\\xE2\\x8A\\x9D" "odblac" "\\xC5\\x91" "odiv" "\\xE2\\xA8\\xB8" "odot" "\\xE2\\x8A\\x99" "odsold" "\\xE2\\xA6\\xBC" "oelig" "\\xC5\\x93" "ofcir" "\\xE2\\xA6\\xBF" "ofr" "\\xF0\\x9D\\x94\\xAC" "ogon" "\\xCB\\x9B" "ograve" "\\xC3\\xB2" "ogt" "\\xE2\\xA7\\x81" "ohbar" "\\xE2\\xA6\\xB5" "ohm" "\\xCE\\xA9" "oint" "\\xE2\\x88\\xAE" "olarr" "\\xE2\\x86\\xBA" "olcir" "\\xE2\\xA6\\xBE" "olcross" "\\xE2\\xA6\\xBB" "oline" "\\xE2\\x80\\xBE" "olt" "\\xE2\\xA7\\x80" "omacr" "\\xC5\\x8D" "omega" "\\xCF\\x89" "omicron" "\\xCE\\xBF" "omid" "\\xE2\\xA6\\xB6" "ominus" "\\xE2\\x8A\\x96" "oopf" "\\xF0\\x9D\\x95\\xA0" "opar" "\\xE2\\xA6\\xB7" "operp" "\\xE2\\xA6\\xB9" "oplus" "\\xE2\\x8A\\x95" "or" "\\xE2\\x88\\xA8" "orarr" "\\xE2\\x86\\xBB" "ord" "\\xE2\\xA9\\x9D" "order" "\\xE2\\x84\\xB4" "orderof" "\\xE2\\x84\\xB4" "ordf" "\\xC2\\xAA" "ordm" "\\xC2\\xBA" "origof" "\\xE2\\x8A\\xB6" "oror" "\\xE2\\xA9\\x96" "orslope" "\\xE2\\xA9\\x97" "orv" "\\xE2\\xA9\\x9B" "oscr" "\\xE2\\x84\\xB4" "oslash" "\\xC3\\xB8" "osol" "\\xE2\\x8A\\x98" "otilde" "\\xC3\\xB5" "otimes" "\\xE2\\x8A\\x97" "otimesas" "\\xE2\\xA8\\xB6" "ouml" "\\xC3\\xB6" "ovbar" "\\xE2\\x8C\\xBD" "par" "\\xE2\\x88\\xA5" "para" "\\xC2\\xB6" "parallel" "\\xE2\\x88\\xA5" "parsim" "\\xE2\\xAB\\xB3" "parsl" "\\xE2\\xAB\\xBD" "part" "\\xE2\\x88\\x82" "pcy" "\\xD0\\xBF" "percnt" "\\x25" "period" "\\x2E" "permil" "\\xE2\\x80\\xB0" "perp" "\\xE2\\x8A\\xA5" "pertenk" "\\xE2\\x80\\xB1" "pfr" "\\xF0\\x9D\\x94\\xAD" "phi" "\\xCF\\x86" "phiv" "\\xCF\\x95" "phmmat" "\\xE2\\x84\\xB3" "phone" "\\xE2\\x98\\x8E" "pi" "\\xCF\\x80" "pitchfork" "\\xE2\\x8B\\x94" "piv" "\\xCF\\x96" "planck" "\\xE2\\x84\\x8F" "planckh" "\\xE2\\x84\\x8E" "plankv" "\\xE2\\x84\\x8F" "plus" "\\x2B" "plusacir" "\\xE2\\xA8\\xA3" "plusb" "\\xE2\\x8A\\x9E" "pluscir" "\\xE2\\xA8\\xA2" "plusdo" "\\xE2\\x88\\x94" "plusdu" "\\xE2\\xA8\\xA5" "pluse" "\\xE2\\xA9\\xB2" "plusmn" "\\xC2\\xB1" "plussim" "\\xE2\\xA8\\xA6" "plustwo" "\\xE2\\xA8\\xA7" "pm" "\\xC2\\xB1" "pointint" "\\xE2\\xA8\\x95" "popf" "\\xF0\\x9D\\x95\\xA1" "pound" "\\xC2\\xA3" "pr" "\\xE2\\x89\\xBA" "prE" "\\xE2\\xAA\\xB3" "prap" "\\xE2\\xAA\\xB7" "prcue" "\\xE2\\x89\\xBC" "pre" "\\xE2\\xAA\\xAF" "prec" "\\xE2\\x89\\xBA" "precapprox" "\\xE2\\xAA\\xB7" "preccurlyeq" "\\xE2\\x89\\xBC" "preceq" "\\xE2\\xAA\\xAF" "precnapprox" "\\xE2\\xAA\\xB9" "precneqq" "\\xE2\\xAA\\xB5" "precnsim" "\\xE2\\x8B\\xA8" "precsim" "\\xE2\\x89\\xBE" "prime" "\\xE2\\x80\\xB2" "primes" "\\xE2\\x84\\x99" "prnE" "\\xE2\\xAA\\xB5" "prnap" "\\xE2\\xAA\\xB9" "prnsim" "\\xE2\\x8B\\xA8" "prod" "\\xE2\\x88\\x8F" "profalar" "\\xE2\\x8C\\xAE" "profline" "\\xE2\\x8C\\x92" "profsurf" "\\xE2\\x8C\\x93" "prop" "\\xE2\\x88\\x9D" "propto" "\\xE2\\x88\\x9D" "prsim" "\\xE2\\x89\\xBE" "prurel" "\\xE2\\x8A\\xB0" "pscr" "\\xF0\\x9D\\x93\\x85" "psi" "\\xCF\\x88" "puncsp" "\\xE2\\x80\\x88" "qfr" "\\xF0\\x9D\\x94\\xAE" "qint" "\\xE2\\xA8\\x8C" "qopf" "\\xF0\\x9D\\x95\\xA2" "qprime" "\\xE2\\x81\\x97" "qscr" "\\xF0\\x9D\\x93\\x86" "quaternions" "\\xE2\\x84\\x8D" "quatint" "\\xE2\\xA8\\x96" "quest" "\\x3F" "questeq" "\\xE2\\x89\\x9F" "quot" "\\x22" "rAarr" "\\xE2\\x87\\x9B" "rArr" "\\xE2\\x87\\x92" "rAtail" "\\xE2\\xA4\\x9C" "rBarr" "\\xE2\\xA4\\x8F" "rHar" "\\xE2\\xA5\\xA4" "race" "\\xE2\\x88\\xBD\\xCC\\xB1" "racute" "\\xC5\\x95" "radic" "\\xE2\\x88\\x9A" "raemptyv" "\\xE2\\xA6\\xB3" "rang" "\\xE2\\x9F\\xA9" "rangd" "\\xE2\\xA6\\x92" "range" "\\xE2\\xA6\\xA5" "rangle" "\\xE2\\x9F\\xA9" "raquo" "\\xC2\\xBB" "rarr" "\\xE2\\x86\\x92" "rarrap" "\\xE2\\xA5\\xB5" "rarrb" "\\xE2\\x87\\xA5" "rarrbfs" "\\xE2\\xA4\\xA0" "rarrc" "\\xE2\\xA4\\xB3" "rarrfs" "\\xE2\\xA4\\x9E" "rarrhk" "\\xE2\\x86\\xAA" "rarrlp" "\\xE2\\x86\\xAC" "rarrpl" "\\xE2\\xA5\\x85" "rarrsim" "\\xE2\\xA5\\xB4" "rarrtl" "\\xE2\\x86\\xA3" "rarrw" "\\xE2\\x86\\x9D" "ratail" "\\xE2\\xA4\\x9A" "ratio" "\\xE2\\x88\\xB6" "rationals" "\\xE2\\x84\\x9A" "rbarr" "\\xE2\\xA4\\x8D" "rbbrk" "\\xE2\\x9D\\xB3" "rbrace" "\\x7D" "rbrack" "\\x5D" "rbrke" "\\xE2\\xA6\\x8C" "rbrksld" "\\xE2\\xA6\\x8E" "rbrkslu" "\\xE2\\xA6\\x90" "rcaron" "\\xC5\\x99" "rcedil" "\\xC5\\x97" "rceil" "\\xE2\\x8C\\x89" "rcub" "\\x7D" "rcy" "\\xD1\\x80" "rdca" "\\xE2\\xA4\\xB7" "rdldhar" "\\xE2\\xA5\\xA9" "rdquo" "\\xE2\\x80\\x9D" "rdquor" "\\xE2\\x80\\x9D" "rdsh" "\\xE2\\x86\\xB3" "real" "\\xE2\\x84\\x9C" "realine" "\\xE2\\x84\\x9B" "realpart" "\\xE2\\x84\\x9C" "reals" "\\xE2\\x84\\x9D" "rect" "\\xE2\\x96\\xAD" "reg" "\\xC2\\xAE" "rfisht" "\\xE2\\xA5\\xBD" "rfloor" "\\xE2\\x8C\\x8B" "rfr" "\\xF0\\x9D\\x94\\xAF" "rhard" "\\xE2\\x87\\x81" "rharu" "\\xE2\\x87\\x80" "rharul" "\\xE2\\xA5\\xAC" "rho" "\\xCF\\x81" "rhov" "\\xCF\\xB1" "rightarrow" "\\xE2\\x86\\x92" "rightarrowtail" "\\xE2\\x86\\xA3" "rightharpoondown" "\\xE2\\x87\\x81" "rightharpoonup" "\\xE2\\x87\\x80" "rightleftarrows" "\\xE2\\x87\\x84" "rightleftharpoons" "\\xE2\\x87\\x8C" "rightrightarrows" "\\xE2\\x87\\x89" "rightsquigarrow" "\\xE2\\x86\\x9D" "rightthreetimes" "\\xE2\\x8B\\x8C" "ring" "\\xCB\\x9A" "risingdotseq" "\\xE2\\x89\\x93" "rlarr" "\\xE2\\x87\\x84" "rlhar" "\\xE2\\x87\\x8C" "rlm" "\\xE2\\x80\\x8F" "rmoust" "\\xE2\\x8E\\xB1" "rmoustache" "\\xE2\\x8E\\xB1" "rnmid" "\\xE2\\xAB\\xAE" "roang" "\\xE2\\x9F\\xAD" "roarr" "\\xE2\\x87\\xBE" "robrk" "\\xE2\\x9F\\xA7" "ropar" "\\xE2\\xA6\\x86" "ropf" "\\xF0\\x9D\\x95\\xA3" "roplus" "\\xE2\\xA8\\xAE" "rotimes" "\\xE2\\xA8\\xB5" "rpar" "\\x29" "rpargt" "\\xE2\\xA6\\x94" "rppolint" "\\xE2\\xA8\\x92" "rrarr" "\\xE2\\x87\\x89" "rsaquo" "\\xE2\\x80\\xBA" "rscr" "\\xF0\\x9D\\x93\\x87" "rsh" "\\xE2\\x86\\xB1" "rsqb" "\\x5D" "rsquo" "\\xE2\\x80\\x99" "rsquor" "\\xE2\\x80\\x99" "rthree" "\\xE2\\x8B\\x8C" "rtimes" "\\xE2\\x8B\\x8A" "rtri" "\\xE2\\x96\\xB9" "rtrie" "\\xE2\\x8A\\xB5" "rtrif" "\\xE2\\x96\\xB8" "rtriltri" "\\xE2\\xA7\\x8E" "ruluhar" "\\xE2\\xA5\\xA8" "rx" "\\xE2\\x84\\x9E" "sacute" "\\xC5\\x9B" "sbquo" "\\xE2\\x80\\x9A" "sc" "\\xE2\\x89\\xBB" "scE" "\\xE2\\xAA\\xB4" "scap" "\\xE2\\xAA\\xB8" "scaron" "\\xC5\\xA1" "sccue" "\\xE2\\x89\\xBD" "sce" "\\xE2\\xAA\\xB0" "scedil" "\\xC5\\x9F" "scirc" "\\xC5\\x9D" "scnE" "\\xE2\\xAA\\xB6" "scnap" "\\xE2\\xAA\\xBA" "scnsim" "\\xE2\\x8B\\xA9" "scpolint" "\\xE2\\xA8\\x93" "scsim" "\\xE2\\x89\\xBF" "scy" "\\xD1\\x81" "sdot" "\\xE2\\x8B\\x85" "sdotb" "\\xE2\\x8A\\xA1" "sdote" "\\xE2\\xA9\\xA6" "seArr" "\\xE2\\x87\\x98" "searhk" "\\xE2\\xA4\\xA5" "searr" "\\xE2\\x86\\x98" "searrow" "\\xE2\\x86\\x98" "sect" "\\xC2\\xA7" "semi" "\\x3B" "seswar" "\\xE2\\xA4\\xA9" "setminus" "\\xE2\\x88\\x96" "setmn" "\\xE2\\x88\\x96" "sext" "\\xE2\\x9C\\xB6" "sfr" "\\xF0\\x9D\\x94\\xB0" "sfrown" "\\xE2\\x8C\\xA2" "sharp" "\\xE2\\x99\\xAF" "shchcy" "\\xD1\\x89" "shcy" "\\xD1\\x88" "shortmid" "\\xE2\\x88\\xA3" "shortparallel" "\\xE2\\x88\\xA5" "shy" "\\xC2\\xAD" "sigma" "\\xCF\\x83" "sigmaf" "\\xCF\\x82" "sigmav" "\\xCF\\x82" "sim" "\\xE2\\x88\\xBC" "simdot" "\\xE2\\xA9\\xAA" "sime" "\\xE2\\x89\\x83" "simeq" "\\xE2\\x89\\x83" "simg" "\\xE2\\xAA\\x9E" "simgE" "\\xE2\\xAA\\xA0" "siml" "\\xE2\\xAA\\x9D" "simlE" "\\xE2\\xAA\\x9F" "simne" "\\xE2\\x89\\x86" "simplus" "\\xE2\\xA8\\xA4" "simrarr" "\\xE2\\xA5\\xB2" "slarr" "\\xE2\\x86\\x90" "smallsetminus" "\\xE2\\x88\\x96" "smashp" "\\xE2\\xA8\\xB3" "smeparsl" "\\xE2\\xA7\\xA4" "smid" "\\xE2\\x88\\xA3" "smile" "\\xE2\\x8C\\xA3" "smt" "\\xE2\\xAA\\xAA" "smte" "\\xE2\\xAA\\xAC" "smtes" "\\xE2\\xAA\\xAC\\xEF\\xB8\\x80" "softcy" "\\xD1\\x8C" "sol" "\\x2F" "solb" "\\xE2\\xA7\\x84" "solbar" "\\xE2\\x8C\\xBF" "sopf" "\\xF0\\x9D\\x95\\xA4" "spades" "\\xE2\\x99\\xA0" "spadesuit" "\\xE2\\x99\\xA0" "spar" "\\xE2\\x88\\xA5" "sqcap" "\\xE2\\x8A\\x93" "sqcaps" "\\xE2\\x8A\\x93\\xEF\\xB8\\x80" "sqcup" "\\xE2\\x8A\\x94" "sqcups" "\\xE2\\x8A\\x94\\xEF\\xB8\\x80" "sqsub" "\\xE2\\x8A\\x8F" "sqsube" "\\xE2\\x8A\\x91" "sqsubset" "\\xE2\\x8A\\x8F" "sqsubseteq" "\\xE2\\x8A\\x91" "sqsup" "\\xE2\\x8A\\x90" "sqsupe" "\\xE2\\x8A\\x92" "sqsupset" "\\xE2\\x8A\\x90" "sqsupseteq" "\\xE2\\x8A\\x92" "squ" "\\xE2\\x96\\xA1" "square" "\\xE2\\x96\\xA1" "squarf" "\\xE2\\x96\\xAA" "squf" "\\xE2\\x96\\xAA" "srarr" "\\xE2\\x86\\x92" "sscr" "\\xF0\\x9D\\x93\\x88" "ssetmn" "\\xE2\\x88\\x96" "ssmile" "\\xE2\\x8C\\xA3" "sstarf" "\\xE2\\x8B\\x86" "star" "\\xE2\\x98\\x86" "starf" "\\xE2\\x98\\x85" "straightepsilon" "\\xCF\\xB5" "straightphi" "\\xCF\\x95" "strns" "\\xC2\\xAF" "sub" "\\xE2\\x8A\\x82" "subE" "\\xE2\\xAB\\x85" "subdot" "\\xE2\\xAA\\xBD" "sube" "\\xE2\\x8A\\x86" "subedot" "\\xE2\\xAB\\x83" "submult" "\\xE2\\xAB\\x81" "subnE" "\\xE2\\xAB\\x8B" "subne" "\\xE2\\x8A\\x8A" "subplus" "\\xE2\\xAA\\xBF" "subrarr" "\\xE2\\xA5\\xB9" "subset" "\\xE2\\x8A\\x82" "subseteq" "\\xE2\\x8A\\x86" "subseteqq" "\\xE2\\xAB\\x85" "subsetneq" "\\xE2\\x8A\\x8A" "subsetneqq" "\\xE2\\xAB\\x8B" "subsim" "\\xE2\\xAB\\x87" "subsub" "\\xE2\\xAB\\x95" "subsup" "\\xE2\\xAB\\x93" "succ" "\\xE2\\x89\\xBB" "succapprox" "\\xE2\\xAA\\xB8" "succcurlyeq" "\\xE2\\x89\\xBD" "succeq" "\\xE2\\xAA\\xB0" "succnapprox" "\\xE2\\xAA\\xBA" "succneqq" "\\xE2\\xAA\\xB6" "succnsim" "\\xE2\\x8B\\xA9" "succsim" "\\xE2\\x89\\xBF" "sum" "\\xE2\\x88\\x91" "sung" "\\xE2\\x99\\xAA" "sup" "\\xE2\\x8A\\x83" "sup1" "\\xC2\\xB9" "sup2" "\\xC2\\xB2" "sup3" "\\xC2\\xB3" "supE" "\\xE2\\xAB\\x86" "supdot" "\\xE2\\xAA\\xBE" "supdsub" "\\xE2\\xAB\\x98" "supe" "\\xE2\\x8A\\x87" "supedot" "\\xE2\\xAB\\x84" "suphsol" "\\xE2\\x9F\\x89" "suphsub" "\\xE2\\xAB\\x97" "suplarr" "\\xE2\\xA5\\xBB" "supmult" "\\xE2\\xAB\\x82" "supnE" "\\xE2\\xAB\\x8C" "supne" "\\xE2\\x8A\\x8B" "supplus" "\\xE2\\xAB\\x80" "supset" "\\xE2\\x8A\\x83" "supseteq" "\\xE2\\x8A\\x87" "supseteqq" "\\xE2\\xAB\\x86" "supsetneq" "\\xE2\\x8A\\x8B" "supsetneqq" "\\xE2\\xAB\\x8C" "supsim" "\\xE2\\xAB\\x88" "supsub" "\\xE2\\xAB\\x94" "supsup" "\\xE2\\xAB\\x96" "swArr" "\\xE2\\x87\\x99" "swarhk" "\\xE2\\xA4\\xA6" "swarr" "\\xE2\\x86\\x99" "swarrow" "\\xE2\\x86\\x99" "swnwar" "\\xE2\\xA4\\xAA" "szlig" "\\xC3\\x9F" "target" "\\xE2\\x8C\\x96" "tau" "\\xCF\\x84" "tbrk" "\\xE2\\x8E\\xB4" "tcaron" "\\xC5\\xA5" "tcedil" "\\xC5\\xA3" "tcy" "\\xD1\\x82" "tdot" "\\xE2\\x83\\x9B" "telrec" "\\xE2\\x8C\\x95" "tfr" "\\xF0\\x9D\\x94\\xB1" "there4" "\\xE2\\x88\\xB4" "therefore" "\\xE2\\x88\\xB4" "theta" "\\xCE\\xB8" "thetasym" "\\xCF\\x91" "thetav" "\\xCF\\x91" "thickapprox" "\\xE2\\x89\\x88" "thicksim" "\\xE2\\x88\\xBC" "thinsp" "\\xE2\\x80\\x89" "thkap" "\\xE2\\x89\\x88" "thksim" "\\xE2\\x88\\xBC" "thorn" "\\xC3\\xBE" "tilde" "\\xCB\\x9C" "times" "\\xC3\\x97" "timesb" "\\xE2\\x8A\\xA0" "timesbar" "\\xE2\\xA8\\xB1" "timesd" "\\xE2\\xA8\\xB0" "tint" "\\xE2\\x88\\xAD" "toea" "\\xE2\\xA4\\xA8" "top" "\\xE2\\x8A\\xA4" "topbot" "\\xE2\\x8C\\xB6" "topcir" "\\xE2\\xAB\\xB1" "topf" "\\xF0\\x9D\\x95\\xA5" "topfork" "\\xE2\\xAB\\x9A" "tosa" "\\xE2\\xA4\\xA9" "tprime" "\\xE2\\x80\\xB4" "trade" "\\xE2\\x84\\xA2" "triangle" "\\xE2\\x96\\xB5" "triangledown" "\\xE2\\x96\\xBF" "triangleleft" "\\xE2\\x97\\x83" "trianglelefteq" "\\xE2\\x8A\\xB4" "triangleq" "\\xE2\\x89\\x9C" "triangleright" "\\xE2\\x96\\xB9" "trianglerighteq" "\\xE2\\x8A\\xB5" "tridot" "\\xE2\\x97\\xAC" "trie" "\\xE2\\x89\\x9C" "triminus" "\\xE2\\xA8\\xBA" "triplus" "\\xE2\\xA8\\xB9" "trisb" "\\xE2\\xA7\\x8D" "tritime" "\\xE2\\xA8\\xBB" "trpezium" "\\xE2\\x8F\\xA2" "tscr" "\\xF0\\x9D\\x93\\x89" "tscy" "\\xD1\\x86" "tshcy" "\\xD1\\x9B" "tstrok" "\\xC5\\xA7" "twixt" "\\xE2\\x89\\xAC" "twoheadleftarrow" "\\xE2\\x86\\x9E" "twoheadrightarrow" "\\xE2\\x86\\xA0" "uArr" "\\xE2\\x87\\x91" "uHar" "\\xE2\\xA5\\xA3" "uacute" "\\xC3\\xBA" "uarr" "\\xE2\\x86\\x91" "ubrcy" "\\xD1\\x9E" "ubreve" "\\xC5\\xAD" "ucirc" "\\xC3\\xBB" "ucy" "\\xD1\\x83" "udarr" "\\xE2\\x87\\x85" "udblac" "\\xC5\\xB1" "udhar" "\\xE2\\xA5\\xAE" "ufisht" "\\xE2\\xA5\\xBE" "ufr" "\\xF0\\x9D\\x94\\xB2" "ugrave" "\\xC3\\xB9" "uharl" "\\xE2\\x86\\xBF" "uharr" "\\xE2\\x86\\xBE" "uhblk" "\\xE2\\x96\\x80" "ulcorn" "\\xE2\\x8C\\x9C" "ulcorner" "\\xE2\\x8C\\x9C" "ulcrop" "\\xE2\\x8C\\x8F" "ultri" "\\xE2\\x97\\xB8" "umacr" "\\xC5\\xAB" "uml" "\\xC2\\xA8" "uogon" "\\xC5\\xB3" "uopf" "\\xF0\\x9D\\x95\\xA6" "uparrow" "\\xE2\\x86\\x91" "updownarrow" "\\xE2\\x86\\x95" "upharpoonleft" "\\xE2\\x86\\xBF" "upharpoonright" "\\xE2\\x86\\xBE" "uplus" "\\xE2\\x8A\\x8E" "upsi" "\\xCF\\x85" "upsih" "\\xCF\\x92" "upsilon" "\\xCF\\x85" "upuparrows" "\\xE2\\x87\\x88" "urcorn" "\\xE2\\x8C\\x9D" "urcorner" "\\xE2\\x8C\\x9D" "urcrop" "\\xE2\\x8C\\x8E" "uring" "\\xC5\\xAF" "urtri" "\\xE2\\x97\\xB9" "uscr" "\\xF0\\x9D\\x93\\x8A" "utdot" "\\xE2\\x8B\\xB0" "utilde" "\\xC5\\xA9" "utri" "\\xE2\\x96\\xB5" "utrif" "\\xE2\\x96\\xB4" "uuarr" "\\xE2\\x87\\x88" "uuml" "\\xC3\\xBC" "uwangle" "\\xE2\\xA6\\xA7" "vArr" "\\xE2\\x87\\x95" "vBar" "\\xE2\\xAB\\xA8" "vBarv" "\\xE2\\xAB\\xA9" "vDash" "\\xE2\\x8A\\xA8" "vangrt" "\\xE2\\xA6\\x9C" "varepsilon" "\\xCF\\xB5" "varkappa" "\\xCF\\xB0" "varnothing" "\\xE2\\x88\\x85" "varphi" "\\xCF\\x95" "varpi" "\\xCF\\x96" "varpropto" "\\xE2\\x88\\x9D" "varr" "\\xE2\\x86\\x95" "varrho" "\\xCF\\xB1" "varsigma" "\\xCF\\x82" "varsubsetneq" "\\xE2\\x8A\\x8A\\xEF\\xB8\\x80" "varsubsetneqq" "\\xE2\\xAB\\x8B\\xEF\\xB8\\x80" "varsupsetneq" "\\xE2\\x8A\\x8B\\xEF\\xB8\\x80" "varsupsetneqq" "\\xE2\\xAB\\x8C\\xEF\\xB8\\x80" "vartheta" "\\xCF\\x91" "vartriangleleft" "\\xE2\\x8A\\xB2" "vartriangleright" "\\xE2\\x8A\\xB3" "vcy" "\\xD0\\xB2" "vdash" "\\xE2\\x8A\\xA2" "vee" "\\xE2\\x88\\xA8" "veebar" "\\xE2\\x8A\\xBB" "veeeq" "\\xE2\\x89\\x9A" "vellip" "\\xE2\\x8B\\xAE" "verbar" "\\x7C" "vert" "\\x7C" "vfr" "\\xF0\\x9D\\x94\\xB3" "vltri" "\\xE2\\x8A\\xB2" "vnsub" "\\xE2\\x8A\\x82\\xE2\\x83\\x92" "vnsup" "\\xE2\\x8A\\x83\\xE2\\x83\\x92" "vopf" "\\xF0\\x9D\\x95\\xA7" "vprop" "\\xE2\\x88\\x9D" "vrtri" "\\xE2\\x8A\\xB3" "vscr" "\\xF0\\x9D\\x93\\x8B" "vsubnE" "\\xE2\\xAB\\x8B\\xEF\\xB8\\x80" "vsubne" "\\xE2\\x8A\\x8A\\xEF\\xB8\\x80" "vsupnE" "\\xE2\\xAB\\x8C\\xEF\\xB8\\x80" "vsupne" "\\xE2\\x8A\\x8B\\xEF\\xB8\\x80" "vzigzag" "\\xE2\\xA6\\x9A" "wcirc" "\\xC5\\xB5" "wedbar" "\\xE2\\xA9\\x9F" "wedge" "\\xE2\\x88\\xA7" "wedgeq" "\\xE2\\x89\\x99" "weierp" "\\xE2\\x84\\x98" "wfr" "\\xF0\\x9D\\x94\\xB4" "wopf" "\\xF0\\x9D\\x95\\xA8" "wp" "\\xE2\\x84\\x98" "wr" "\\xE2\\x89\\x80" "wreath" "\\xE2\\x89\\x80" "wscr" "\\xF0\\x9D\\x93\\x8C" "xcap" "\\xE2\\x8B\\x82" "xcirc" "\\xE2\\x97\\xAF" "xcup" "\\xE2\\x8B\\x83" "xdtri" "\\xE2\\x96\\xBD" "xfr" "\\xF0\\x9D\\x94\\xB5" "xhArr" "\\xE2\\x9F\\xBA" "xharr" "\\xE2\\x9F\\xB7" "xi" "\\xCE\\xBE" "xlArr" "\\xE2\\x9F\\xB8" "xlarr" "\\xE2\\x9F\\xB5" "xmap" "\\xE2\\x9F\\xBC" "xnis" "\\xE2\\x8B\\xBB" "xodot" "\\xE2\\xA8\\x80" "xopf" "\\xF0\\x9D\\x95\\xA9" "xoplus" "\\xE2\\xA8\\x81" "xotime" "\\xE2\\xA8\\x82" "xrArr" "\\xE2\\x9F\\xB9" "xrarr" "\\xE2\\x9F\\xB6" "xscr" "\\xF0\\x9D\\x93\\x8D" "xsqcup" "\\xE2\\xA8\\x86" "xuplus" "\\xE2\\xA8\\x84" "xutri" "\\xE2\\x96\\xB3" "xvee" "\\xE2\\x8B\\x81" "xwedge" "\\xE2\\x8B\\x80" "yacute" "\\xC3\\xBD" "yacy" "\\xD1\\x8F" "ycirc" "\\xC5\\xB7" "ycy" "\\xD1\\x8B" "yen" "\\xC2\\xA5" "yfr" "\\xF0\\x9D\\x94\\xB6" "yicy" "\\xD1\\x97" "yopf" "\\xF0\\x9D\\x95\\xAA" "yscr" "\\xF0\\x9D\\x93\\x8E" "yucy" "\\xD1\\x8E" "yuml" "\\xC3\\xBF" "zacute" "\\xC5\\xBA" "zcaron" "\\xC5\\xBE" "zcy" "\\xD0\\xB7" "zdot" "\\xC5\\xBC" "zeetrf" "\\xE2\\x84\\xA8" "zeta" "\\xCE\\xB6" "zfr" "\\xF0\\x9D\\x94\\xB7" "zhcy" "\\xD0\\xB6" "zigrarr" "\\xE2\\x87\\x9D" "zopf" "\\xF0\\x9D\\x95\\xAB" "zscr" "\\xF0\\x9D\\x93\\x8F" "zwj" "\\xE2\\x80\\x8D" "zwnj" "\\xE2\\x80\\x8C" } { set html "&$entity;" set doc [dom parse -html $html] set root [$doc documentElement] set body [$root firstChild] if {[toutf8 [$body text]] ne [string tolower $byteseq]} { lappend result $entity [toutf8 [$body text]] [string tolower $byteseq] } $doc delete } set result } "" test html-1.9 {non-existing character entities} { set doc [dom parse -html {&abcdef;}] set root [$doc documentElement] set result [$root text] $doc delete set result } "&abcdef;" test html-1.10 {non-BMP character reference} {Tcl9} { set doc [dom parse -html {𝒞𝒞}] set root [$doc documentElement] set result [$root text] $doc delete set result } "\U1d49e\U1d49e" test html-1.11 {Prematur end of entity reference with overlong repacement} {Tcl9} { set doc [dom parse -html {&nGt}] set root [$doc documentElement] set result [$root text] $doc delete set result } "&nGt" test html-1.12 {Entity reference with overlong repacement} {Tcl9} { set doc [dom parse -html {≫⃒}] set root [$doc documentElement] set result [$root text] $doc delete set result } "\u226B\u20D2" test html-1.13 {Entity reference with overlong repacement} {Tcl9} { set doc [dom parse -html {≫⃒abc≫⃒∡≪⃒≫⃒foobar}] set root [$doc documentElement] set result [$root text] $doc delete set result } "\u226B\u20D2abc\u226B\u20D2\u2221\u226A\u20D2\u226B\u20D2foobar" test html-1.14 {Entity reference with overlong repacement} {Tcl9} { set doc [dom parse -html {≫⃒abc}] set root [$doc documentElement] set result [$root text] $doc delete set result } "\u226B\u20D2abc" test html-2.1 {not closed p tags} { set doc [dom parse -html {

Para 1

Para 2

Para 3 }] set result [$doc asXML -indent none] $doc delete set result } {

Para 1

Para 2

Para 3

} test html-2.2 {HTML parsing} { set doc [dom parse -html {

HTML

}] set result [$doc asXML -indent none] $doc delete set result } {

HTML

} test html-2.3 {HTML parsing} { set doc [dom parse -html {

HTML

}] set result [$doc asXML -indent none] $doc delete set result } {

HTML

} test html-2.4 {HTML parsing} { set doc [dom parse -html {

HTML

}] $doc documentElement root set result [$root nodeName] $doc delete set result } {html} test html-2.5 {HTML parsing} { set doc [dom parse -html {
}] $doc asHTML } {
} test html-2.6 {HTML parsing} { set doc [dom parse -html {
}] $doc asHTML } {
} test html-2.7 {HTML parsing} { set doc [dom parse -html {
}] $doc asHTML } {
} test html-2.8 {HTML parsing} { set doc [dom parse -html {
}] $doc asHTML } {
} test html-2.9 {HTML parsing} {knownBug} { set doc [dom parse -html {x = 1 + 1}] set result [$doc asHTML] $doc delete set result } {<MATH-field>x = 1 + 1</MATH-field>foo}] set result [$doc asHTML] $doc delete set result } {foo} test html-2.11 {HTML parsing} { set doc [dom parse -html {x = 1 + 1}] set result [$doc asHTML] $doc delete set result } {x = 1 + 1} test html-3.1 {Bad data} { set data {line 6 column 17 - Warning: } test html-3.2 {Bad data} { set doc [dom parse -html {}] set result [$doc asHTML] $doc delete set result } {} test html-3.3 {Single root} { set doc [dom parse -html {Sometext}] set result [$doc asXML -indent none] $doc delete set result } {Sometext} test html-3.4 {-forest} { set doc [dom parse -html -forest {Sometext}] set result [$doc asXML -indent none] $doc delete set result } {Sometext} test html-3.5 {-forest} { set doc [dom parse -html -forest {Sometext}] set result [$doc asXML -indent none] $doc delete set result } {Sometext} test html-4.1 {Tag name case normalization} { set doc [dom parse -html {}] set result [$doc asHTML] $doc delete set result } {} test html-4.2 {Tag name case normalization} {knownBug} { set doc [dom parse -html {}] set result [$doc asHTML] $doc delete set result } {} test html-4.3 {Attribute name case normalization} { set doc [dom parse -html {}] set result [$doc asHTML] $doc delete set result } {} test html-4.4 {ID Attribute handling} { set doc [dom parse -html {

}] set result [[$doc getElementById 1] getAttribute id] $doc delete set result } {1} test html-4.5 {-forest} { set doc [dom parse -html -forest {SomeOther}] set result [llength [$doc selectNodes //b]] $doc delete set result } 2 # cleanup ::tcltest::cleanupTests return tdom-0.9.6-src/tests/xslt.test0000644000175000017500000013247615025767703015032 0ustar rolfrolf# Features covered: XSLT transformation # # This file contains a collection of tests for the XSLT engine of # tDOM. It is focused mainly on the tcl interface of the engine and on # verification, that the created result tree behaves as if it would # have been parsed from an according XML source; the vaste majority of # xslt compliance tests are done outside the tcltest framework. # # Tested commands and object commands: # xslt-1.*: xpath Lexer/parser tests # xslt-2.*: xslt method command variants, -parameters option # xslt-3.*: xslt vars, scope, parameters # xslt-4.*: xslt transformations on modified/created from the scratch docs # xslt-5.*: External documents: document(), xsl:import, xsl:include # xslt-6.*: xsl:output # xslt-7.*: tests related to the created result doc # xslt-8.*: Additional xslt rec compliance tests (details not covered by # by the external xslt compliance test suite). # xslt-9.*: xslt transformations that are using scripted xpath functions # # Copyright (c) 2002 - 2005, 2013 Rolf Ade. # # RCS: @(#) $Id$ source [file join [file dir [info script]] loadtdom.tcl] test xslt-1.1 {unicode chars outside of US-ASCII in var name} { set xml [dom parse {}] set xslt [dom parse [tdom::xmlReadFile [file join [pwd] [file dir [info script]] data/xslt_1.xsl]]] set xmlroot [$xml documentElement] $xmlroot xslt $xslt resultDoc set resultroot [$resultDoc documentElement] set result [$resultroot asXML] $xml delete $xslt delete $resultDoc delete set result } {foo} test xslt-1.2 {xpath parse real number} { set xml [dom parse {}] set xslt [dom parse { }] set xmlroot [$xml documentElement] $xmlroot xslt $xslt resultDoc set resultroot [$resultDoc documentElement] set result [$resultroot asXML] $xml delete $xslt delete $resultDoc delete set result } {0.12345} test xslt-1.3 {xpath parse real number} { set xml [dom parse {}] set xslt [dom parse { }] set xmlroot [$xml documentElement] $xmlroot xslt $xslt resultDoc set resultroot [$resultDoc documentElement] set result [$resultroot asXML] $xml delete $xslt delete $resultDoc delete set result } {-0.12345} test xslt-1.4 {pattern IsFQElement with FillNodeList} { set xml [dom parse {}] set xslt [dom parse { }] $xml xslt $xslt resultDoc set result [$resultDoc asXML -indent none] $xslt delete $xml delete $resultDoc delete set result } {m:elem} test xslt-1.5 {space between \$ and varname} { set xml [dom parse {}] set xslt [dom parse { }] set xsltCmd [$xslt toXSLTcmd] set result [catch {set resultDoc [$xsltCmd transform $xml]} errMsg] $xsltCmd delete $xml delete lappend result $errMsg } {1 {Expected variable name}} test xslt-1.6 {space in nodetest node( )} { set xml [dom parse {text}] set xslt [dom parse { }] set xsltCmd [$xslt toXSLTcmd] set resultDoc [$xsltCmd transform $xml] $xsltCmd delete $xml delete set result [$resultDoc asText] $resultDoc delete set result } {3} test xslt-2.1 {xslt top level parameter: use default value} { set xml [dom parse {}] set xslt [dom parse { }] set xmlroot [$xml documentElement] $xmlroot xslt $xslt resultDoc set resultroot [$resultDoc documentElement] set result [$resultroot asXML] $xml delete $xslt delete $resultDoc delete set result } {parameter1Value} test xslt-2.2 {xslt top level parameter: overwrite default value with -parameters} { set xml [dom parse {}] set xslt [dom parse { }] set xmlroot [$xml documentElement] $xmlroot xslt -parameters {parameter1 startValue} $xslt resultDoc set resultroot [$resultDoc documentElement] set result [$resultroot asXML] $xml delete $xslt delete $resultDoc delete set result } {startValue} test xslt-2.3 {xslt top level parameter: overwrite default value with -parameters} { set xml [dom parse -keepEmpties {}] set xslt [dom parse -keepEmpties { }] set xmlroot [$xml documentElement] $xmlroot xslt -parameters {parameter1 startValue} $xslt resultDoc set resultroot [$resultDoc documentElement] set result [$resultroot asXML] $xml delete $xslt delete $resultDoc delete set result } {startValue parameter2Value} test xslt-2.4 {xslt top level parameter: overwrite default value with -parameters} { set xml [dom parse -keepEmpties {}] set xslt [dom parse -keepEmpties { }] set xmlroot [$xml documentElement] $xmlroot xslt -parameters {parameter1 startValue1 parameter2 startValue2} $xslt resultDoc set resultroot [$resultDoc documentElement] set result [$resultroot asXML] $xml delete $xslt delete $resultDoc delete set result } {startValue1 startValue2} test xslt-2.5 {xslt top level parameter: try to set nonexisted param} { set xml [dom parse -keepEmpties {}] set xslt [dom parse -keepEmpties { }] set xmlroot [$xml documentElement] catch {$xmlroot xslt -parameters {nonExistend foo} $xslt resultDoc} errMsg $xml delete $xslt delete set errMsg } {There isn't a parameter named "nonExistend" defined at top level in the stylesheet.} test xslt-2.6 {xslt top level parameter: try to set variable} { set xml [dom parse -keepEmpties {}] set xslt [dom parse -keepEmpties { }] set xmlroot [$xml documentElement] catch {$xmlroot xslt -parameters {variable1 foo} $xslt resultDoc} errMsg $xml delete $xslt delete set errMsg } {"variable1" is defined as variable, not as parameter.} test xslt-2.7 {xslt top level parameter} { set xml [dom parse -keepEmpties {}] set xslt [dom parse -keepEmpties { }] set xmlroot [$xml documentElement] catch {$xmlroot xslt -parameters {parameter2 foo} $xslt resultDoc} errMsg set resultroot [$resultDoc documentElement] set result [$resultroot asXML] $xml delete $xslt delete $resultDoc delete set result } {variable1Value foo} test xslt-2.8 {xslt top level parameter: wrong usage of -parameters option} { set xml [dom parse {}] set xslt [dom parse { }] set xmlroot [$xml documentElement] catch {$xmlroot xslt -parameters $xslt resultDoc} errMsg $xml delete $xslt delete set errMsg } {parameter value missing: the -parameters option needs a list of parameter name and parameter value pairs} test xslt-2.9 {xslt top level parameter: wrong usage of -parameters option} { set xml [dom parse {}] set xslt [dom parse { }] set xmlroot [$xml documentElement] catch {$xmlroot xslt -parameters {foo bar baz} $xslt resultDoc} errMsg $xml delete $xslt delete set errMsg } {parameter value missing: the -parameters option needs a list of parameter name and parameter value pairs} test xslt-2.10 {no resultDoc variable name} { set xml [dom parse {}] set xslt [dom parse { }] set xmlroot [$xml documentElement] set resultDoc [$xmlroot xslt $xslt] set resultroot [$resultDoc documentElement] set result [$resultroot asXML] $xml delete $xslt delete $resultDoc delete set result } {parameter1Value} test xslt-2.11 {xslt top level parameter: set with 'strange' value} { set xml [dom parse {}] set xslt [dom parse { }] set xmlroot [$xml documentElement] $xmlroot xslt -parameters {parameter1 foo\"'<>bar} $xslt resultDoc set resultroot [$resultDoc documentElement] set result [$resultroot asXML] $xml delete $xslt delete $resultDoc delete set result } {foo"'<>bar} # emacs: " test xslt-2.12 {xslt top level parameter: set FQ top-level param} { set xml [dom parse {}] set xslt [dom parse { }] set xmlroot [$xml documentElement] $xmlroot xslt -parameters {foo:parameter1 setValue} $xslt resultDoc set resultroot [$resultDoc documentElement] set result [$resultroot asXML] $xml delete $xslt delete $resultDoc delete set result } {setValue} test xslt-2.13 {xslt top level parameter: set FQ top-level param} { set xml [dom parse {}] set xslt [dom parse { }] set xmlroot [$xml documentElement] $xmlroot xslt -parameters {foo:parameter1 setValue} $xslt resultDoc set resultroot [$resultDoc documentElement] set result [$resultroot asXML] $xml delete $xslt delete $resultDoc delete set result } {setValue} test xslt-2.14 {xslt top level parameter: set FQ top-level param} { set xml [dom parse {}] set xslt [dom parse { }] set xmlroot [$xml documentElement] $xmlroot xslt -parameters {foo:parameter1 setValue} $xslt resultDoc set resultroot [$resultDoc documentElement] set result [$resultroot asXML] $xml delete $xslt delete $resultDoc delete set result } {setValue} test xslt-2.15 {xslt top level parameter:\ try to set nonexisted param with ignore} { set xml [dom parse -keepEmpties {}] set xslt [dom parse -keepEmpties { }] set xmlroot [$xml documentElement] set result [catch {$xmlroot xslt -ignoreUndeclaredParameters\ -parameters {nonExistend foo}\ $xslt resultDoc} errMsg] $resultDoc delete $xml delete $xslt delete set result } {0} test xslt-2.16 {xslt top level parameter: try to set nonexisted param with ignore} { set xml [dom parse -keepEmpties {}] set xslt [dom parse -keepEmpties { }] set xmlroot [$xml documentElement] $xmlroot xslt -ignoreUndeclaredParameters \ -parameters {nonExistend foo parameter2 givenValue} \ $xslt resultDoc set resultroot [$resultDoc documentElement] set result [$resultroot nodeValue] $resultDoc delete $xml delete $xslt delete set result } {parameter1Value givenValue} proc xsltmessagecmd {msg terminate} { global xsltMsgs global terminatingMsg append xsltMsgs "$msg terminate: $terminate " if {$terminate} { set terminatingMsg 1 } else { set terminatingMsg 0 } } test xslt-2.17 {xslt - to less arguments to the method} { set xml [dom parse {}] set result [catch {$xml xslt}] $xml delete set result } {1} test xslt-2.18 {xslt -xsltmessagecmd} { set xml [dom parse -keepEmpties {}] set xslt [dom parse -keepEmpties { some text 1. call 2. call 3. call }] set xmlroot [$xml documentElement] set ::xsltMsgs "" $xmlroot xslt -xsltmessagecmd xsltmessagecmd $xslt resultDoc $resultDoc delete $xml delete $xslt delete set ::xsltMsgs } {1. call terminate: 0 2. call terminate: 0 3. call terminate: 0 } test xslt-2.19 {xslt -xsltmessagecmd} { set xml [dom parse -keepEmpties {}] set xslt [dom parse -keepEmpties { some text 1. call 2. call 3. call }] set xmlroot [$xml documentElement] set ::xsltMsgs "" catch {$xmlroot xslt -xsltmessagecmd xsltmessagecmd $xslt resultDoc} $xml delete $xslt delete set ::terminatingMsg } {1} test xslt-2.20 {xslt top level parameter: use top level param to set a top level var} { set xml [dom parse -keepEmpties {}] set xslt [dom parse -keepEmpties { }] $xml xslt -parameters {sortentity "the parameter value"} $xslt resultDoc set result [$resultDoc asXML -indent none] $resultDoc delete $xml delete $xslt delete set result } {the parameter value} proc xslt-2.21-xsltmsgcmd {msg terminate} { global result if {$msg eq "3"} { return -code break } append result $msg } test xslt-2.21 {xslt -xsltmessagecmd return code break} { set result "" set xml [dom parse {}] set xslt [dom parse { }] catch {$xml xslt -xsltmessagecmd xslt-2.21-xsltmsgcmd $xslt resultDoc} errMsg append result $resultDoc $errMsg $xml delete $xslt delete set result } {12} test xslt-2.22 {xslt -xsltmessagecmd return code break} { set result "" set xml [dom parse {}] set xslt [dom parse { }] set resultDoc "untouched" catch {$xml xslt -ignoreUndeclaredParameters -xsltmessagecmd xslt-2.21-xsltmsgcmd $xslt resultDoc} errMsg append result $resultDoc $xml delete $xslt delete set result } {12} test xslt-2.23 {xslt outputVar} { set result "" set xml [dom parse {}] set xslt [dom parse { }] set resultDoc "untouched" catch {$xml xslt -foo $xslt resultDoc} errMsg append result $resultDoc $xml delete $xslt delete set result } {untouched} test xslt-2.24 {xslt outputVar} { set xml [dom parse {}] set xslt [dom parse { }] set result [catch {$xml xslt -foo $xslt }] $xml delete $xslt delete set result } {1} test xslt-2.25 {xslt outputVar} { set xml [dom parse {}] set xslt [dom parse { Here }] $xml xslt $xslt resultDoc $xml delete $xslt delete set result [$resultDoc asXML -indent none] $resultDoc delete set result } {} test xslt-2.26 {xslt -maxApplyDepth option} { set xml [dom parse {}] set xslt [dom parse { e }] catch {$xml xslt -maxApplyDepth 3 $xslt} errMsg $xml delete $xslt delete set errMsg } "Maximum nested apply templates reached (potential infinite template recursion?)." test xslt-3.1 {xslt variable scope} { set xml [dom parse {}] set xslt [dom parse { }] set xmlroot [$xml documentElement] catch {$xmlroot xslt $xslt resultDoc} errMsg $xml delete $xslt delete set errMsg } {Variable "main" has not been declared.} test xslt-3.2 {xslt error msg of variable redeclaration in one template} { set xml [dom parse {}] set xslt [dom parse { }] catch {$xml xslt $xslt resultDoc} errMsg $xml delete $xslt delete set errMsg } {Variable 'var' is already declared in this template} test xslt-3.3 {use top level var to set a top level var} { set xml [dom parse -keepEmpties {}] set xslt [dom parse -keepEmpties { }] $xml xslt $xslt resultDoc set result [$resultDoc asXML -indent none] $resultDoc delete $xml delete $xslt delete set result } {var1Value} test xslt-4.1 {xslt transformation of a source which was modifed after parsing} { dom parse -baseurl file:///tmp/abc.xml {} doc $doc documentElement root $root appendXML dom parse { } xslDoc $root xslt $xslDoc newDoc set result [$newDoc asXML -indent none] $doc delete $xslDoc delete $newDoc delete set result } {} set xslt { Data stored in the stylesheet } proc 5.1-extref {baseURI systemId publicId} { if {$baseURI != ""} { error "baseURI not empty" } if {$systemId != ""} { error "systemId not empty" } return [list string "" $::xslt] } test xslt-5.1 {xslt document('') with empty baseURI} { dom parse xmldoc dom parse -externalentitycommand 5.1-extref $xslt xsltdoc $xmldoc xslt $xsltdoc resultDoc set result [$resultDoc asXML -indent none] $resultDoc delete $xsltdoc delete $xmldoc delete set result } {Data stored in the stylesheet} proc xslt-5.2 {args} { error "script error in xslt-5.2 external enitity resolver" } set xslt { } test xslt-5.2 {xslt document() with script error in -externalentitycommand} { dom parse xmldoc dom parse -externalentitycommand xslt-5.2 $xslt xsltdoc set result [catch {$xmldoc xslt $xsltdoc resultDoc} errMsg] $xmldoc delete $xsltdoc delete lappend result $errMsg } {1 {script error in xslt-5.2 external enitity resolver}} proc xslt-5.3 {args} { return [list string file://some/base " xmldoc dom parse -externalentitycommand xslt-5.3 $xslt xsltdoc set result [catch {$xmldoc xslt $xsltdoc resultDoc} errMsg] $xmldoc delete $xsltdoc delete lappend result $errMsg } {1 {Error while processing external entity "foo": At line 1 character 15: not well-formed (invalid token)}} proc xslt-5.4 {base systemId publicId} { switch $systemId { "firstlevel" { return [list string file://some/base/first { }] } "secondlevel" { return [list string file://some/base/second " foo } test xslt-5.4 {xslt document() with script error in -externalentitycommand} { dom parse xmldoc dom parse -externalentitycommand xslt-5.4 $xslt xsltdoc set result [catch {$xmldoc xslt $xsltdoc resultDoc} errMsg] $xmldoc delete $xsltdoc delete lappend result $errMsg } {1 {Error while processing external entity "secondlevel": At line 1 character 15: not well-formed (invalid token)}} set xslt { foo } test xslt-5.5 {xsl:import href == ""} { dom parse xmldoc dom parse -externalentitycommand xslt-5.4 $xslt xsltdoc set result [catch {$xmldoc xslt $xsltdoc resultDoc} errMsg] $xmldoc delete $xsltdoc delete lappend result $errMsg } {1 {Recursive import/include: stylesheet tries to access itself.}} set xslt { } test xslt-6.1 {xsl:output} { dom parse xmldoc dom parse $xslt xsltdoc $xmldoc xslt $xsltdoc resultDoc set result [$resultDoc indent] lappend result [$resultDoc omit-xml-declaration] lappend result [$resultDoc encoding] lappend result [$resultDoc mediaType] lappend result [$resultDoc standalone] lappend result [$resultDoc getDefaultOutputMethod] $resultDoc delete $xsltdoc delete $xmldoc delete set result } {1 0 ISO-8859-1 text/foo 1 text} set xslt { } test xslt-7.1 {namespaces in the result doc} { dom parse xmldoc dom parse $xslt xsltdoc $xmldoc xslt $xsltdoc resultDoc set nodes [$resultDoc getElementsByTagNameNS "http://my.uri" element] set result "" foreach node $nodes { lappend result [$node nodeName] } $resultDoc delete $xmldoc delete $xsltdoc delete set result } {my:element} test xslt-7.2 {namespaces in the result doc} { dom parse xmldoc dom parse $xslt xsltdoc $xmldoc xslt $xsltdoc resultDoc set result [$resultDoc asXML -indent none] $resultDoc delete $xmldoc delete $xsltdoc delete set result } {} test xslt-7.3 {namespaces in the result doc} { dom parse xmldoc dom parse $xslt xsltdoc $xmldoc xslt $xsltdoc resultDoc $resultDoc documentElement root set my:element [$root firstChild] set result [${my:element} namespaceURI] $resultDoc delete $xmldoc delete $xsltdoc delete set result } {http://my.uri} set xslt { } test xslt-7.4 {namespaces in the result doc} { dom parse xmldoc dom parse $xslt xsltdoc $xmldoc xslt $xsltdoc resultDoc set nodes [$resultDoc getElementsByTagNameNS "" element] set result "" foreach node $nodes { lappend result [$node nodeName] } $resultDoc delete $xmldoc delete $xsltdoc delete set result } {element} test xslt-7.5 {namespaces in the result doc} { dom parse xmldoc dom parse $xslt xsltdoc $xmldoc xslt $xsltdoc resultDoc set nodes [$resultDoc getElementsByTagName element] set result "" foreach node $nodes { lappend result [$node nodeName] } $resultDoc delete $xmldoc delete $xsltdoc delete set result } {element} set xslt { } test xslt-7.6 {namespaces in the result doc} { dom parse xmldoc dom parse $xslt xsltdoc $xmldoc xslt $xsltdoc resultDoc set nodes [$resultDoc getElementsByTagNameNS "element.uri" *] set result "" foreach node $nodes { lappend result [$node nodeName] } $resultDoc delete $xmldoc delete $xsltdoc delete set result } {element} test xslt-7.7 {parent of the result doc documentElement} { dom parse xmldoc dom parse $xslt xsltdoc $xmldoc xslt $xsltdoc resultDoc set resultRoot [$resultDoc documentElement] set result [$resultRoot parentNode] $resultDoc delete $xmldoc delete $xsltdoc delete set result } {} set xslt { } test xslt-7.8 {namespaces in the result doc} { dom parse xmldoc dom parse $xslt xsltdoc $xmldoc xslt $xsltdoc resultDoc set nodes [$resultDoc getElementsByTagNameNS "http://my.uri" *] set result "" foreach node $nodes { lappend result [$node nodeName] } $resultDoc delete $xmldoc delete $xsltdoc delete set result } {my:element my:foo} set xslt { } test xslt-7.9 {parent of the result doc documentElement} { dom parse xmldoc dom parse $xslt xsltdoc $xmldoc xslt $xsltdoc resultDoc set resultRoot [$resultDoc documentElement] set result [list [$resultDoc asXML -indent none] [$resultRoot parentNode]] $resultDoc delete $xmldoc delete $xsltdoc delete set result } { {}} set xslt { } test xslt-7.10 {parent of the result doc documentElement} { dom parse xmldoc dom parse $xslt xsltdoc $xmldoc xslt $xsltdoc resultDoc set result [list [$resultDoc asXML -indent none]] foreach toplevelNode [$resultDoc childNodes] { lappend result [$toplevelNode parentNode] } $resultDoc delete $xmldoc delete $xsltdoc delete set result } { {} {}} set xslt { } set xml {} test xslt-8.1 {current() not allowed in pattern} { dom parse $xml xmldoc dom parse $xslt xsltdoc catch {$xmldoc xslt $xsltdoc resultDoc} errMsg $xmldoc delete $xsltdoc delete set errMsg } {The 'current' function is not allowed in Pattern. for '*[current() != 'notthis']' Parsed symbols: 0 WCARDNAME 0 000000000 0 * 1 LBRACKET 0 000000000 1 2 FUNCTION 0 000000000 8 current 3 LPAR 0 000000000 9 4 RPAR 0 000000000 10 5 NOTEQ 0 000000000 13 6 LITERAL 0 000000000 23 notthis 7 RBRACKET 0 000000000 24 } set xslt-8.2.xml {
} set xslt-8.2.xsl { } set xslt-8.2.output {
} test xslt-8.2 {namespace handling of copy-of} { dom parse -keepEmpties ${xslt-8.2.xml} xmldoc dom parse -keepEmpties ${xslt-8.2.xsl} xsltdoc $xmldoc xslt $xsltdoc resultDoc $xmldoc delete $xsltdoc delete set result [$resultDoc asXML -indent none] $resultDoc delete set result } ${xslt-8.2.output} test xslt-8.3 {format-number() runding} { set xml { 1.999 1.998 1.997 1.996 1.995 1.994 1.99 1.9 1. } set xslt { } dom parse -keepEmpties $xml xmldoc dom parse -keepEmpties $xslt xsltdoc $xmldoc xslt $xsltdoc resultDoc $xmldoc delete $xsltdoc delete set result [$resultDoc asXML -indent none] $resultDoc delete set result } {2.00 2.00 2.00 2.00 2.00 1.99 1.99 1.90 1.00 } test xslt-8.4 {Erroneous XPath expr as match attribute of a template} { set xmlDoc [dom parse {}] set xslt { } set xsltDoc [dom parse $xslt] set result [catch {$xmlDoc xslt $xsltDoc} errMsg] $xmlDoc delete $xsltDoc delete set result } {1} test xslt-8.5 {Minimal xslt 1.0 stylesheet} { set xmlDoc {} set xsltDoc {} dom parse -keepEmpties $xmlDoc xmldoc dom parse -keepEmpties $xsltDoc xsltdoc $xmldoc xslt $xsltdoc resultDoc set result [$resultDoc asXML -indent none] $xmldoc delete $xsltdoc delete $resultDoc delete set result } {} test xslt-8.6 {Almost minimal xslt 1.0 stylesheet} { set xmlDoc {} set xsltDoc { } dom parse -keepEmpties $xmlDoc xmldoc dom parse -keepEmpties $xsltDoc xsltdoc $xmldoc xslt $xsltdoc resultDoc set result [$resultDoc asXML -indent none] $xmldoc delete $xsltdoc delete $resultDoc delete set result } {} test xslt-8.7 {Minimal xslt 1.0 stylesheet returns text content of doc by default} { set xmlDoc {text} set xsltDoc {} dom parse -keepEmpties $xmlDoc xmldoc dom parse -keepEmpties $xsltDoc xsltdoc $xmldoc xslt $xsltdoc resultDoc set result [$resultDoc asXML -indent none] $xmldoc delete $xsltdoc delete $resultDoc delete set result } {text} test xslt-8.8 {Almost minimal xslt 1.0 stylesheet} { set xmlDoc {text} set xsltDoc { } dom parse -keepEmpties $xmlDoc xmldoc dom parse -keepEmpties $xsltDoc xsltdoc $xmldoc xslt $xsltdoc resultDoc set result [$resultDoc asXML -indent none] $xmldoc delete $xsltdoc delete $resultDoc delete set result } {} test xslt-8.9 {format-number} {knownBug} { set xmlDoc [dom parse ] set xsltDoc [dom parse { }] $xmlDoc xslt $xsltDoc resultDoc set result [$resultDoc asXML -indent none] $xmlDoc delete $xsltDoc delete $resultDoc delete set result 001 } {001} test xslt-8.10 {Namespace axis} { set xmlDoc { foo bar grill } set xsltDoc { } dom parse -keepEmpties $xmlDoc xmldoc dom parse -keepEmpties $xsltDoc xsltdoc $xmldoc xslt $xsltdoc resultDoc set result [$resultDoc asXML -indent none] $xmldoc delete $xsltdoc delete $resultDoc delete set result } { foo.bar } proc ::dom::xpathFunc::xslt-9.1 {ctxNode pos nodeListType nodeList args} { if {[llength $ctxNode] != 2} { error "::dom::xpathFunc::xslt-9.1: expected parent node / attribute \ name list as first argument." } return {string "bar"} } test xslt-9.1 {xslt using scripted xpath function} -setup { set xml {} set xsl { } set xsltDoc [dom parse -keepEmpties $xsl] set xmlDoc [dom parse $xml] } -body { $xmlDoc xslt $xsltDoc resultDoc $resultDoc asXML -indent none } -cleanup { $xsltDoc delete $xmlDoc delete $resultDoc delete } -result {} # Below is code, which replaces the dom cmd with a version, which parses # the xml into a dom tree, then transformations this dom tree with the # xslt identity transformation and returns the result tree of that # transformation. This is used to test, that the result tree of an xslt # transformation could be used as any 'ordinary' tree created with # [dom parse]. It is here, because I didn't want to hold it separated. # It is commented out, because some of the tests in the sourced test files # need line/column or baseURI information, to work correctly, and this # information is not preserved by an xslt identity transformation and # I was up to now too lazy, to trick around this few tests with some # test constraints. # # set identityTransformation [dom parse { # # # # # # }] # rename dom _dom # proc dom {args} { # global identityTransformation # switch [lindex $args 0] { # "parse" { # set resultdoc [uplevel 1 [linsert $args 0 _dom]] # return [$resultdoc xslt $identityTransformation] # } # default { # return [uplevel 1 [linsert $args 0 _dom]] # } # } # } # source [file join [file dir [info script]] i18n.test] # source [file join [file dir [info script]] dom.test] # rename dom {} # rename _dom dom # cleanup ::tcltest::cleanupTests return tdom-0.9.6-src/tests/pullparser.test0000644000175000017500000007302015025767703016216 0ustar rolfrolf# Features covered: Pull parser # # This file contains a collection of tests for the pull parser # interface. # Tested functionalities: # pp-1.*: Basics, interface # pp-2.*: Compare dom / pull parsing # pp-3.*: skip method # pp-4.*: find-element method # pp-5.*: CDATA section handling # pp-6.*: line/column methods # # Copyright (c) 2017-2018 Rolf Ade. source [file join [file dir [info script]] loadtdom.tcl] test pp-1.1 {Create} { tdom::pullparser pp pp delete } {} test pp-1.2 {Invalid create} { catch {tdom::pullparser pp foo} } 1 test pp-1.3 {Reset freshly created parser} { tdom::pullparser pp pp reset pp reset pp delete } {} test pp-1.4 {State after creation} { tdom::pullparser pp set result [pp state] lappend result [pp state] pp delete set result } {READY READY} proc walkDOM {node} { set str "" switch [$node nodeType] { "ELEMENT_NODE" { append str [$node nodeName] # Because the dom builder arranges attributes so that the # xmlns attributes come first we need to ensure a unify # attribute order for comparsion. set attpairs [list] foreach att [$node attributes] { if {[llength $att] == 3} { if {[lindex $att 2] eq ""} { lappend attpairs [list \ xmlns:[lindex $att 0] \ [$node getAttribute xmlns:[lindex $att 0]]] } else { lappend attpairs [list \ [lindex $att 1]:[lindex $att 0] \ [$node getAttribute [lindex $att 1]:[lindex $att 0]]] } } else { lappend attpairs [list $att [$node getAttribute $att]] } } foreach {name value} [lsort -index 0 $attpairs] { append str $name $value } foreach child [$node childNodes] { append str [walkDOM $child] } append str /[$node nodeName] } "TEXT_NODE" { append str [$node nodeValue] } default { # Ignore anything else } } return $str } proc loopPull {} { while {[set state [pp next]] ne "END_DOCUMENT"} { switch $state { "START_TAG" { append pullstr [pp tag] set attpairs [list] foreach {attname attvalue} [pp attributes] { lappend attpairs [list $attname $attvalue] } foreach {name value} [lsort -index 0 $attpairs] { append pullstr $name $value } } "TEXT" { append pullstr [pp text] } "END_TAG" { append pullstr /[pp tag] } } } return $pullstr } proc comparewithDOM {data {inputMethod input}} { if {$inputMethod eq "input"} { dom parse $data doc } elseif {$inputMethod eq "inputchannel"} { dom parse -channel $data doc } else { dom parse -keepEmpties [::tdom::xmlReadFile $data] doc } set domstr [walkDOM [$doc documentElement]] $doc delete tdom::pullparser pp pp $inputMethod $data set pullstr [loopPull] if {$domstr eq $pullstr} { return 1 } else { puts "*** DOM str:" puts $domstr puts "*** Pull str:" puts $pullstr return 0 } pp delete } proc fdata {file} { file join [file dir [info script]] data/$file } test pp-2.1 {dom/pull comparsion: mondial-europe.xml} {longRunning} { comparewithDOM [fdata mondial-europe.xml] inputfile } 1 test pp-2.2 {dom/pull comparsion: books.xml} { comparewithDOM [fdata books.xml] inputfile } 1 test pp-2.3 {dom/pull comparsion: i18n_1.xml} { comparewithDOM [fdata i18n_1.xml] inputfile } 1 test pp-2.4 {dom/pull comparsion: i18n_2.xml} { comparewithDOM [fdata i18n_2.xml] inputfile } 1 test pp-2.5 {dom/pull comparsion: REC-xslt-19991116.xml} {longRunning} { comparewithDOM [fdata REC-xslt-19991116.xml] inputfile } 1 test pp-2.6 {dom/pull comparsion: xslt_1.xsl} { comparewithDOM [fdata xslt_1.xsl] inputfile } 1 test pp-2.7 {dom/pull comparsion} { comparewithDOM {

This specification defines the syntax and semantics of XSLT, which is a language for transforming XML documents into other XML documents.

} } 1 test pp-2.8 {dom/pull comparsion} { comparewithDOM {

(see ), which is referred to in

} } 1 test pp-2.9 {dom/pull comparsion} { comparewithDOM {

This specification defines the syntax and semantics of the XSLT language. A transformation in the XSLT language is expressed as a well-formed XML document conforming

} } 1 proc loopPullE {} { while {[set state [pullparser next]] ne "END_DOCUMENT"} { switch $state { "START_TAG" { append pullstr [pullparser tag] foreach {attname attvalue} [pullparser attributes] { append pullstr $attname $attvalue } } "TEXT" { append pullstr [pullparser text] } "END_TAG" { append pullstr /[pullparser tag] } } } return $pullstr } proc elementstart {name atts} { global expatstr append expatstr $name foreach {attname attvalue} $atts { append expatstr $attname $attvalue } } proc elementend {name} { global expatstr append expatstr /$name } proc cdata {cdata} { global expatstr append expatstr $cdata } proc comparewithExpat {data {inputMethod ""}} { global expatstr set expatstr "" expat pushparser \ -elementstartcommand elementstart \ -elementendcommand elementend \ -characterdatacommand cdata pushparser parse$inputMethod $data tdom::pullparser pullparser pullparser input$inputMethod $data set pullstr [loopPullE] if {$expatstr eq $pullstr} { return 1 } else { puts $expatstr puts $pullstr return 0 } pushparser free pullparser delete } test pp-2.10 {expat/pull comparsion: mondial-europe.xml} {longRunning} { comparewithExpat [fdata mondial-europe.xml] file } 1 test pp-2.11 {expat/pull comparsion: books.xml} { comparewithExpat [fdata books.xml] file } 1 test pp-2.12 {expat/pull comparsion: i18n_1.xml} { comparewithExpat [fdata i18n_1.xml] file } 1 test pp-2.13 {expat/pull comparsion: i18n_2.xml} { comparewithExpat [fdata i18n_2.xml] file } 1 test pp-2.14 {expat/pull comparsion: REC-xslt-19991116.xml} {longRunning} { comparewithExpat [fdata REC-xslt-19991116.xml] file } 1 test pp-2.15 {expat/pull comparsion: xslt_1.xsl} { comparewithExpat [fdata xslt_1.xsl] file } 1 test pp-2.16 {expat/pull comparsion} { comparewithExpat {

This specification defines the syntax and semantics of XSLT, which is a language for transforming XML documents into other XML documents.

} } 1 test pp-2.17 {expat/pull comparsion} { comparewithExpat {

(see ), which is referred to in

} } 1 test pp-2.18 {expat/pull comparsion} { comparewithExpat {

This specification defines the syntax and semantics of the XSLT language. A transformation in the XSLT language is expressed as a well-formed XML document conforming

} } 1 test pp-3.1 {skip} { tdom::pullparser pp pp input set result [pp next] lappend result [pp tag] lappend result [pp skip] lappend result [pp tag] lappend result [pp next] pp delete set result } {START_TAG doc END_TAG doc END_DOCUMENT} test pp-3.1.1 {skip} { tdom::pullparser pp pp input {} set result [pp next] lappend result [pp tag] lappend result [pp next] lappend result [pp tag] lappend result [pp skip] lappend result [pp tag] lappend result [pp next] lappend result [pp tag] lappend result [pp next] pp delete set result } {START_TAG doc START_TAG e END_TAG e END_TAG doc END_DOCUMENT} test pp-3.1.2 {skip} { tdom::pullparser pp pp input {texttext} set result [pp next] lappend result [pp tag] lappend result [pp next] lappend result [pp text] lappend result [pp next] lappend result [pp tag] lappend result [pp skip] lappend result [pp tag] lappend result [pp next] lappend result [pp text] lappend result [pp next] lappend result [pp tag] lappend result [pp next] pp delete set result } {START_TAG doc TEXT text START_TAG e END_TAG e TEXT text END_TAG doc END_DOCUMENT} test pp-3.1.3 {skip} { tdom::pullparser pp pp input {textbarbaztexttext} set result [pp next] lappend result [pp tag] lappend result [pp next] lappend result [pp text] lappend result [pp next] lappend result [pp tag] lappend result [pp skip] lappend result [pp tag] lappend result [pp next] lappend result [pp text] lappend result [pp next] lappend result [pp tag] lappend result [pp next] pp delete set result } {START_TAG doc TEXT text START_TAG e END_TAG e TEXT text END_TAG doc END_DOCUMENT} test pp-3.1.4 {skip} { tdom::pullparser pp pp input set result [pp next] lappend result [pp tag] lappend result [pp skip] lappend result [pp tag] lappend result [pp next] pp delete set result } {START_TAG doc END_TAG doc END_DOCUMENT} test pp-3.1.5 {skip} { tdom::pullparser pp pp input { } set result [pp next] lappend result [pp tag] lappend result [pp skip] lappend result [pp tag] lappend result [pp next] pp delete set result } {START_TAG doc END_TAG doc END_DOCUMENT} test pp-3.1.5 {skip} { tdom::pullparser pp -ignorewhitecdata pp input { } set result [pp next] lappend result [pp tag] lappend result [pp skip] lappend result [pp tag] lappend result [pp next] pp delete set result } {START_TAG doc END_TAG doc END_DOCUMENT} test pp-3.2 {skip} { tdom::pullparser pp pp input {} set result [pp next] lappend result [pp tag] lappend result [pp skip] lappend result [pp tag] lappend result [pp next] pp delete set result } {START_TAG doc END_TAG doc END_DOCUMENT} test pp-3.3 {skip} { tdom::pullparser pp pp input {foo bar} set result [pp next] lappend result [pp tag] lappend result [pp skip] lappend result [pp tag] lappend result [pp next] pp delete set result } {START_TAG doc END_TAG doc END_DOCUMENT} test pp-3.4 {skip} { tdom::pullparser pp pp input {foo barbar} set result [pp next] lappend result [pp tag] lappend result [pp skip] lappend result [pp tag] lappend result [pp next] pp delete set result } {START_TAG doc END_TAG doc END_DOCUMENT} test pp-3.5 {skip} { tdom::pullparser pp pp input {foo barbar} set result [list] while {[set state [pp next]] ne "END_DOCUMENT"} { lappend result $state if {$state eq "START_TAG"} { lappend result [pp tag] if {[pp tag] eq "e"} { pp skip continue } } if {[pp state] eq "END_TAG"} { lappend result [pp tag] } } pp delete set result } {START_TAG doc TEXT START_TAG e START_TAG e START_TAG e END_TAG doc} test pp-3.6 {skip} { tdom::pullparser pp pp input {foo barbarbaz} set result [list] while {[set state [pp next]] ne "END_DOCUMENT"} { lappend result $state if {$state eq "START_TAG"} { lappend result [pp tag] if {[pp tag] eq "e"} { pp skip continue } } if {[pp state] eq "END_TAG"} { lappend result [pp tag] } if {[pp state] eq "TEXT"} { lappend result [pp text] } } pp delete set result } {START_TAG doc TEXT {foo bar} START_TAG e START_TAG e START_TAG e TEXT baz END_TAG doc} test pp-3.7 {skip} { tdom::pullparser pp pp input {foo barbar} set result [pp next] lappend result [pp next]; # TEXT "foo bar" lappend result [pp next]; # START_TAG lappend result [pp tag]; # e lappend result [pp next]; # END_TAG lappend result [pp tag]; # e lappend result [pp next]; # START_TAG lappend result [pp tag]; # e lappend result [catch {pp skip} errMsg] lappend result $errMsg pp delete set result } {START_TAG TEXT START_TAG e END_TAG e START_TAG e 1 {error "mismatched tag" at line 1 column 24}} test pp-3.8 {skip} { tdom::pullparser pp pp input {foo barbar} set result [pp next] lappend result [pp skip] lappend result [pp tag] lappend result [pp next] lappend result [catch {pp next} errMsg] lappend result $errMsg pp delete set result } {START_TAG END_TAG doc END_DOCUMENT 1 {No next event after END_DOCUMENT}} test pp-3.9 {skip} { tdom::pullparser pp pp input {} set result [pp next] lappend result [catch {pp skip}] pp reset pp input {text} lappend result [pp next] lappend result [pp tag] lappend result [pp next] lappend result [pp text] pp delete set result } {START_TAG 1 START_TAG doc TEXT text} test pp-4.1 {find-element} { tdom::pullparser pp pp input {foo barbazgrillhere} set result [pp next] lappend result [pp tag] lappend result [pp next] lappend result [pp tag] lappend result [pp find-element d] lappend result [pp tag] lappend result [pp next] lappend result [pp text] lappend result [pp next] lappend result [pp tag] while {[pp next] ne "END_DOCUMENT"} {} pp delete set result } {START_TAG doc START_TAG a START_TAG d TEXT here END_TAG d} test pp-4.2 {find-element} { tdom::pullparser pp pp input {foo barbazgrill} set result [pp next] lappend result [pp tag] lappend result [pp next] lappend result [pp tag] lappend result [pp find-element d] lappend result [pp tag] lappend result [pp next] lappend result [pp tag] while {[pp next] ne "END_DOCUMENT"} {} pp delete set result } {START_TAG doc START_TAG a START_TAG d END_TAG d} test pp-4.3 {find-element} { tdom::pullparser pp pp input {foo barbazgrillsome} set result [pp next] lappend result [pp tag] lappend result [pp next] lappend result [pp tag] lappend result [pp find-element d] lappend result [pp tag] lappend result [pp next] lappend result [pp tag] while {[pp next] ne "END_DOCUMENT"} {} pp delete set result } {START_TAG doc START_TAG a START_TAG d END_TAG d} test pp-4.4 {find-element} { tdom::pullparser pp pp input {grill} set result [pp next] lappend result [pp tag] lappend result [pp find-element d] lappend result [pp tag] lappend result [pp next] lappend result [pp text] lappend result [pp next] lappend result [pp tag] lappend result [pp next] lappend result [pp tag] while {[pp next] ne "END_DOCUMENT"} {} pp delete set result } {START_TAG doc START_TAG d TEXT grill END_TAG d END_TAG c} test pp-4.5 {find-element} { tdom::pullparser pp pp input {} set result [pp next] lappend result [pp tag] lappend result [pp find-element d] lappend result [pp tag] lappend result [pp next] lappend result [pp tag] lappend result [pp next] lappend result [pp tag] while {[pp next] ne "END_DOCUMENT"} {} pp delete set result } {START_TAG doc START_TAG d END_TAG d END_TAG c} test pp-4.6 {find-element} { tdom::pullparser pp pp input {} set result [pp next] lappend result [pp tag] lappend result [pp find-element d] lappend result [pp tag] lappend result [pp next] lappend result [pp tag] lappend result [pp next] lappend result [pp tag] while {[pp next] ne "END_DOCUMENT"} {} pp delete set result } {START_TAG doc START_TAG d END_TAG d END_TAG c} test pp-4.7 {find-element} { tdom::pullparser pp pp input {} set result [pp next] lappend result [pp tag] lappend result [pp find-element b] lappend result [pp tag] lappend result [pp find-element c] lappend result [pp tag] lappend result [pp find-element a] lappend result [pp tag] while {[pp next] ne "END_DOCUMENT"} {} pp delete set result } {START_TAG doc START_TAG b START_TAG c START_TAG a} test pp-4.8 {find-element} { tdom::pullparser pp pp input {} set result [pp next] lappend result [pp tag] lappend result [pp next] lappend result [pp tag] lappend result [pp find-element b] pp delete set result } {START_TAG doc END_TAG doc END_DOCUMENT} test pp-4.8.1 {find-element} { tdom::pullparser pp pp input {} set result [pp next] lappend result [pp tag] lappend result [pp next] lappend result [pp tag] lappend result [pp find-element b] pp delete set result } {START_TAG doc END_TAG doc END_DOCUMENT} test pp-4.8.2 {find-element} { tdom::pullparser pp pp input { } set result [pp next] lappend result [pp tag] lappend result [pp next] lappend result [pp next] lappend result [pp tag] lappend result [pp find-element b] pp delete set result } {START_TAG doc TEXT END_TAG doc END_DOCUMENT} test pp-4.8.3 {find-element} { tdom::pullparser pp -ignorewhitecdata pp input { } set result [pp next] lappend result [pp tag] lappend result [pp next] lappend result [pp tag] lappend result [pp find-element b] pp delete set result } {START_TAG doc END_TAG doc END_DOCUMENT} test pp-4.9 {find-element} { tdom::pullparser pp pp input {} set result [pp next]; # START_TAG lappend result [pp tag]; # doc lappend result [pp next]; # START_TAG lappend result [pp tag]; # a lappend result [pp find-element b]; # START_TAG lappend result [pp tag]; #b lappend result [pp find-element c]; # START_TAG lappend result [pp tag]; #c lappend result [pp next]; # END_TAG lappend result [pp tag]; # c lappend result [pp find-element a]; # START_TAG lappend result [pp tag]; # a while {[pp next] ne "END_DOCUMENT"} {} pp delete set result } {START_TAG doc START_TAG a START_TAG b START_TAG c END_TAG c START_TAG a} test pp-4.10 {find-element} { tdom::pullparser pp pp input {foobargrillbaz} set result [pp next]; # START_TAG lappend result [pp tag]; # doc lappend result [pp find-element a]; # START_TAG lappend result [pp tag]; # a lappend result [pp next]; # END_TAG lappend result [pp tag]; # a lappend result [pp find-element a]; # START_TAG lappend result [pp tag]; #a lappend result [pp next]; # END_TAG lappend result [pp tag]; # a lappend result [pp next]; # TEXT lappend result [pp text]; # baz lappend result [pp next]; # END_TAG lappend result [pp tag]; # b while {[pp next] ne "END_DOCUMENT"} {} pp delete set result } {START_TAG doc START_TAG a END_TAG a START_TAG a END_TAG a TEXT baz END_TAG b} test pp-4.11 {find-element} { tdom::pullparser pp pp input {foobargrillbaz} set result [pp state] lappend result [pp find-element a]; # START_TAG lappend result [pp tag]; # a lappend result [pp next]; # END_TAG lappend result [pp tag]; # a lappend result [pp find-element a]; # START_TAG lappend result [pp tag]; #a lappend result [pp next]; # END_TAG lappend result [pp tag]; # a lappend result [pp next]; # TEXT lappend result [pp text]; # baz lappend result [pp next]; # END_TAG lappend result [pp tag]; # b while {[pp next] ne "END_DOCUMENT"} {} pp delete set result } {START_DOCUMENT START_TAG a END_TAG a START_TAG a END_TAG a TEXT baz END_TAG b} test pp-4.12 {find-element} { tdom::pullparser pp pp input {foobargrillbaz} set result [pp state] pp find-element a lappend result [pp find-element a]; # START_TAG lappend result [pp tag]; #a lappend result [pp next]; # END_TAG lappend result [pp tag]; # a lappend result [pp next]; # TEXT lappend result [pp text]; # baz lappend result [pp next]; # END_TAG lappend result [pp tag]; # b while {[pp next] ne "END_DOCUMENT"} {} pp delete set result } {START_DOCUMENT START_TAG a END_TAG a TEXT baz END_TAG b} test pp-4.13 {find-element} { tdom::pullparser pp pp input {} set result [pp state] lappend result [pp find-element a] pp delete set result } {START_DOCUMENT END_DOCUMENT} test pp-4.14 {find-element} { tdom::pullparser pp pp input {foo barbar} set result [pp next] lappend result [pp skip] lappend result [pp tag] lappend result [pp find-element b] lappend result [catch {pp next} errMsg] lappend result $errMsg pp delete set result } {START_TAG END_TAG doc END_DOCUMENT 1 {No next event after END_DOCUMENT}} test pp-4.15 {find-element} { tdom::pullparser pp pp input {
} set result [pp next] lappend result [pp tag] for {set i 0} {$i < 3} {incr i} { lappend result [pp find-element -names {a b c}] lappend result [pp tag] } while {[pp next] ne "END_DOCUMENT"} {} pp delete set result } {START_TAG doc START_TAG a START_TAG b START_TAG a} test pp-5.1 {CDATA section} { tdom::pullparser pp pp input {} set result [pp state] lappend result [pp next] lappend result [pp tag] lappend result [pp next] lappend result [pp text] lappend result [pp next] lappend result [pp tag] lappend result [pp next] pp delete set result } {START_DOCUMENT START_TAG doc TEXT { some text } END_TAG doc END_DOCUMENT} test pp-5.2 {CDATA section inside of text} { tdom::pullparser pp pp input {beforeafter} set result [pp state] lappend result [pp next] lappend result [pp tag] lappend result [pp next] lappend result [pp text] lappend result [pp next] lappend result [pp tag] lappend result [pp next] pp delete set result } {START_DOCUMENT START_TAG doc TEXT {before some text after} END_TAG doc END_DOCUMENT} test pp-5.3 {CDATA section after text} { tdom::pullparser pp pp input {before} set result [pp state] lappend result [pp next] lappend result [pp tag] lappend result [pp next] lappend result [pp text] lappend result [pp next] lappend result [pp tag] lappend result [pp next] pp delete set result } {START_DOCUMENT START_TAG doc TEXT {before some text } END_TAG doc END_DOCUMENT} test pp-5.4 {CDATA section before text} { tdom::pullparser pp pp input {after} set result [pp state] lappend result [pp next] lappend result [pp tag] lappend result [pp next] lappend result [pp text] lappend result [pp next] lappend result [pp tag] lappend result [pp next] pp delete set result } {START_DOCUMENT START_TAG doc TEXT { some text after} END_TAG doc END_DOCUMENT} test pp-5.5 {White space only CDATA section inside text} { tdom::pullparser pp pp input {before after} set result [pp state] lappend result [pp next] lappend result [pp tag] lappend result [pp next] lappend result [pp text] lappend result [pp next] lappend result [pp tag] lappend result [pp next] pp delete set result } {START_DOCUMENT START_TAG doc TEXT {before after} END_TAG doc END_DOCUMENT} test pp-5.6 {White space only CDATA section inside text with -ignorewhitecdata} { tdom::pullparser pp -ignorewhitecdata pp input {before after} set result [pp state] lappend result [pp next] lappend result [pp tag] lappend result [pp next] lappend result [pp text] lappend result [pp next] lappend result [pp tag] lappend result [pp next] pp delete set result } {START_DOCUMENT START_TAG doc TEXT {before after} END_TAG doc END_DOCUMENT} test pp-5.6 {White space only CDATA section inside text with -ignorewhitecdata} { tdom::pullparser pp -ignorewhitecdata pp input {before after} set result [pp state] lappend result [pp next] lappend result [pp tag] lappend result [pp next] lappend result [pp text] lappend result [pp next] lappend result [pp tag] lappend result [pp next] pp delete set result } {START_DOCUMENT START_TAG doc TEXT {before after} END_TAG doc END_DOCUMENT} test pp-5.7 {White space only CDATA section inside white space only text w/ -ignorewhitecdata} { tdom::pullparser pp -ignorewhitecdata pp input { } set result [pp state] lappend result [pp next] lappend result [pp tag] lappend result [pp next] lappend result [pp tag] lappend result [pp next] pp delete set result } {START_DOCUMENT START_TAG doc END_TAG doc END_DOCUMENT} test pp-5.8 {White space only CDATA section before text w/ -ignorewhitecdata} { tdom::pullparser pp -ignorewhitecdata pp input { after} set result [pp state] lappend result [pp next] lappend result [pp tag] lappend result [pp next] lappend result [pp text] lappend result [pp next] lappend result [pp tag] lappend result [pp next] pp delete set result } {START_DOCUMENT START_TAG doc TEXT { after} END_TAG doc END_DOCUMENT} test pp-5.9 {Successive CDATA sections} { tdom::pullparser pp pp input { after} set result [pp state] lappend result [pp next] lappend result [pp tag] lappend result [pp next] lappend result [pp text] lappend result [pp next] lappend result [pp tag] lappend result [pp next] pp delete set result } {START_DOCUMENT START_TAG doc TEXT { onetwo after} END_TAG doc END_DOCUMENT} test pp-6.1 {line} { tdom::pullparser pp set result [catch {pp line}] pp input { after} lappend result [pp line] lappend result [pp next] lappend result [pp tag] lappend result [pp line] lappend result [pp next] lappend result [pp text] lappend result [pp next] lappend result [pp tag] lappend result [pp line] lappend result [pp next] lappend result [pp line] pp delete set result } {1 0 START_TAG doc 1 TEXT { onetwo after} END_TAG doc 1 END_DOCUMENT 1} test pp-6.2 {column} { tdom::pullparser pp set result [catch {pp column}] pp input { after} lappend result [pp column] lappend result [pp next] lappend result [pp tag] lappend result [pp column] lappend result [pp next] lappend result [pp text] lappend result [pp next] lappend result [pp tag] lappend result [pp column] lappend result [pp next] lappend result [pp column] pp delete set result } {1 0 START_TAG doc 5 TEXT { onetwo after} END_TAG doc 62 END_DOCUMENT 62} test pp-6.3 {column} { tdom::pullparser pp pp input {foobargrill} set result [list] while {[pp next] ne "END_DOCUMENT"} { if {[pp state] eq "TEXT"} { lappend result [pp text] } else { lappend result [pp tag] lappend result [pp column] } } pp delete set result } {doc 5 foo b 11 bar b 18 grill doc 29} test pp-6.4 {line/column} { tdom::pullparser pp pp input {foo bar grill} set result [list] while {[pp next] ne "END_DOCUMENT"} { if {[pp state] eq "TEXT"} { lappend result [pp text] } else { lappend result [pp tag] lappend result [pp line]/[pp column] } } pp delete set result } {doc 1/5 {foo } b 2/3 {bar } b 3/4 grill doc 3/15} test pp-6.5 {column} { tdom::pullparser pp pp input {foobargrill} set result [list] while {[pp next] ne "END_DOCUMENT"} { if {[pp state] eq "TEXT"} { lappend result [pp text] } else { lappend result [pp tag] lappend result [pp column] } } lappend result [pp column] pp delete set result } {doc 20 foo b 36 bar b 43 grill doc 54 54} test pp-6.6 {line/column after parsing error} { tdom::pullparser pp pp input {an < xml error } pp next set result [catch {pp skip}] lappend result [pp line]/[pp column] pp delete set result } {1 2/9} tdom-0.9.6-src/tests/xmltest.test0000644000175000017500000000243015025767703015522 0ustar rolfrolf# Features covered: Conformance # # This file tests the parser's performance on conformance to the # XML specification. As such it is crude and does not test callback # features. # # Sourcing this file into Tcl runs the tests and generates output # for errors. No output means no errors were found. # # Copyright (c) 1999-2000 Zveno Pty Ltd. # # $Id$ source [file join [file dir [info script]] loadtdom.tcl] proc xmltest {expect dir subdir f} { set ch [open $f] set data [read $ch] close $ch test xmltest-$dir-$subdir-[file rootname [file tail $f]] "Document $dir $subdir [file tail $f]" { set parser [xml::parser xmltest] set code [catch {$parser parse $data}] rename $parser {} set code } $expect } # NB. Uses James Clark's test suite for WFF checking. # Need a framework to test against each file: it's too time- # consuming to setup a test proc for each one. set testDir [file join [pwd] xmltest] # These documents should fail foreach dir {not-wf} { foreach file [glob -nocomplain [file join $testDir $dir sa *.xml]] { xmltest 1 $dir sa $file } } # These documents should pass foreach dir {invalid valid} { foreach file [glob -nocomplain [file join $testDir $dir sa *.xml]] { xmltest 0 $dir sa $file } } # cleanup ::tcltest::cleanupTests return tdom-0.9.6-src/tests/pi.test0000644000175000017500000000263015025767703014434 0ustar rolfrolf# Features covered: Processing Instructions # # This file tests the parser's performance on Processing Instructions. # Sourcing this file into Tcl runs the tests and generates output # for errors. No output means no errors were found. # # Copyright (c) 1998-2000 Zveno Pty Ltd. # # $Id$ source [file join [file dir [info script]] loadtdom.tcl] catch {unset result} proc PI {target data args} { lappend ::result $target $data } test pi-1.1 {PI} { set ::result {} set parser [xml::parser pi-1.1 \ -processinginstructioncommand PI] $parser parse { } $parser free set ::result } {Test {This is a processing instruction}} test pi-1.2 {PI: missing trailing ?} { set ::result {} set parser [xml::parser pi-1.2 \ -processinginstructioncommand PI] set returncode [catch {$parser parse { }} msg] $parser free list $returncode [regexp {error "unclosed token" at.+} $msg] } {1 1} test pi-2.1 {PI with special characters} { set ::result {} set parser [xml::parser pi-2.1 \ -processinginstructioncommand PI] $parser parse { } $parser free set ::result } {Test {[if !VMLRender]}} # cleanup ::tcltest::cleanupTests return tdom-0.9.6-src/tests/tdomcmd.bench0000644000175000017500000000612315025767703015554 0ustar rolfrolf# -*- tcl -*- # # This file contains benchmarks for DOM doc creation with dom and tdom # # (c) 2018 Rolf Ade # # ### ### ### ######### ######### ######### ########################### ## Setting up the environment ... package require tdom # ### ### ### ######### ######### ######### ########################### ## Benchmarks. bench -desc "dom mondial-europe.xml" -iters 20 -ipre { set fd [open ../tests/data/mondial-europe.xml] } -body { set doc [dom parse -channel $fd] } -ipost { close $fd $doc delete } bench -desc "tdom mondial-europe.xml" -iters 20 -ipre { set p [expat] tdom $p enable } -body { $p parsefile ../tests/data/mondial-europe.xml set doc [tdom $p getdoc] } -ipost { $doc delete $p free } bench -desc "tdom mondial-europe.xml / reuse parser" -iters 20 -pre { set p [expat] tdom $p enable } -body { $p parsefile ../tests/data/mondial-europe.xml set doc [tdom $p getdoc] } -ipost { $doc delete $p reset } -post { $p free } bench -desc "dom REC-xslt-19991116.xml" -iters 20 -ipre { set fd [open ../tests/data/REC-xslt-19991116.xml] } -body { set doc [dom parse -channel $fd] } -ipost { close $fd $doc delete } bench -desc "tdom REC-xslt-19991116.xml" -iters 20 -ipre { set p [expat] tdom $p enable } -body { $p parsefile ../tests/data/REC-xslt-19991116.xml set doc [tdom $p getdoc] } -ipost { $doc delete $p free } bench -desc "tdom REC-xslt-19991116.xml / reuse parser" -iters 20 -pre { set p [expat] tdom $p enable } -body { $p parsefile ../tests/data/REC-xslt-19991116.xml set doc [tdom $p getdoc] } -ipost { $doc delete $p reset } -post { $p free } if {![catch {package require tnc}]} { proc extresolver {base systemId publicId} { switch $publicId { "-//W3C//DTD Specification V2.0//EN" { set fd [open [file join [file dir [info script]] \ data/xmlspec-v20.dtd]] set xmlspec [read $fd] close $fd return [list "string" "" $xmlspec] } default { puts stderr "Unexpected systemId '$systemId'" return "" } } } bench -desc "tdom REC-xslt-19991116.xml / tnc " -iters 20 -ipre { set p [expat -externalentitycommand extresolver \ -paramentityparsing always] tdom $p enable tnc $p enable } -body { $p parsefile ../tests/data/REC-xslt-19991116.xml set doc [tdom $p getdoc] } -ipost { $doc delete $p free } bench -desc "tdom REC-xslt-19991116.xml / tnc / reuse parse" -iters 20 -pre { set p [expat -externalentitycommand extresolver \ -paramentityparsing always] tdom $p enable tnc $p enable } -body { $p parsefile ../tests/data/REC-xslt-19991116.xml set doc [tdom $p getdoc] } -ipost { $doc delete $p reset $p configure -paramentityparsing always } -post { $p free } } tdom-0.9.6-src/tests/dom.test0000644000175000017500000022754415025767703014620 0ustar rolfrolf# Features covered: dom command # # This file contains a collection of tests for the dom command of # tDOM. # # dom-1.*: createDocument, createDocumentNS # dom-2.*: parse # dom-3.*: is* methods, clearString # dom-4.*: parse -useForeignDTD # dom-5.*: external entities # dom-6.*: use in slave interpreter # dom-7.*: setNameCheck, setTextCheck # dom-8.*: createDocumentNode, documentNodes # dom-9.*: setObjectCommands # dom-10.*: createNodeCmd # dom-11.*: featureinfo # dom-12.*: -feedbackAfter # dom-13.*: -forest # dom-14.*: command argument parsing # dom-15.*: fromScriptContext # # Copyright (c) 2002, 2003, 2004 Rolf Ade. source [file join [file dir [info script]] loadtdom.tcl] test dom-1.1 {createDocument with root node name not a XML Name} { list [catch {dom createDocument "root node"} msg] $msg } "1 {Invalid root element name 'root node'}" test dom-1.2 {createDocument with root node name not a XML Name} { list [catch {dom createDocument "1root"} msg] $msg } "1 {Invalid root element name '1root'}" test dom-1.3 {createDocument - root name us-ascii} { dom createDocument "root" doc set root [$doc documentElement] set result [$root nodeName] $doc delete set result } "root" test dom-1.4 {createDocument - root name with UTF-8 chars} { dom createDocument "\u00c4\u00d4\u00dc" doc set root [$doc documentElement] set result [$root nodeName] $doc delete set result } "\u00c4\u00d4\u00dc" test dom-1.5 {createDocument with FQ root name} { dom createDocument "foo:bar" doc set root [$doc documentElement] set result [$root nodeName] $doc delete set result } "foo:bar" test dom-1.6 {createDocument with wrong # of args} { list [catch {dom createDocument "root" "http:/foo:bar" doc} msg] $msg } "1 {wrong \# args: should be \"createDocument docElemName ?newObjVar?\"}" test dom-1.7 {createDocumentNS - check root name} { set doc [dom createDocumentNS "http://foo.bar" "root"] set root [$doc documentElement] set result [$root nodeName] $doc delete set result } "root" test dom-1.8 {createDocumentNS - check the NS of the created root} { dom createDocumentNS "http://foo.bar" "root" doc set root [$doc documentElement] set result [$root namespaceURI] $doc delete set result } "http://foo.bar" test dom-1.9 {createDocumentNS with root name not a NCName} { list [catch {dom createDocumentNS "http://foo.bar" "foo bar" doc} msg] $msg } "1 {Invalid root element name 'foo bar'}" test dom-1.10 {createDocumentNS with root name not a NCName} { list [catch {dom createDocumentNS "http://foo.bar" "a:b:c" doc} msg] $msg } "1 {Invalid root element name 'a:b:c'}" test dom-1.11 {createDocumentNS with root name not a NCName} { list [catch {dom createDocumentNS "http://foo.bar" "a b:b" doc} msg] $msg } "1 {Invalid root element name 'a b:b'}" test dom-1.12 {createDocumentNS with root name not a NCName} { list [catch {dom createDocumentNS "http://foo.bar" "a:a b" doc} msg] $msg } "1 {Invalid root element name 'a:a b'}" test dom-1.13 {createDocumentNS - check root name} { set doc [dom createDocumentNS "http://foo.bar" foo:root] set root [$doc documentElement] set result [$root nodeName] $doc delete set result } "foo:root" test dom-1.14 {createDocument - rename the doc cmd} { set doc [dom createDocument root] if {[info commands fooCmd] == "fooCmd"} { rename fooCmd {} } rename $doc fooCmd set result [[fooCmd documentElement] nodeName] fooCmd delete set result } {root} test dom-1.15 {createDocument - rename the doc cmd} { if {[info commands fooCmd] == "fooCmd"} { rename fooCmd {} } set nrOfCommands [llength [info commands]] set doc [dom createDocument root] rename $doc fooCmd fooCmd delete expr {[llength [info commands]] == $nrOfCommands} } {1} test dom-1.16 {createDocumentNS - empty namespace, no prefix} { dom createDocumentNS "" doc doc set result [$doc asXML -indent none] $doc delete set result } {} test dom-1.17 {createDocumentNS - namespace, no prefix} { dom createDocumentNS "uri" doc doc set result [$doc asXML -indent none] $doc delete set result } {} test dom-1.18 {createDocumentNS - namespace, no prefix} { dom createDocumentNS "uri" doc doc set result [$doc selectNodes -namespaces {ns uri} count(/ns:doc)] $doc delete set result } 1 test dom-1.19 {createDocumentNS - namespace, prefix} { dom createDocumentNS "uri" n1:doc doc set result [$doc selectNodes -namespaces {ns uri} count(/ns:doc)] $doc delete set result } 1 test dom-1.20 {createDocumentNS - empty namespace, prefix} { catch {dom createDocumentNS "" n1:doc doc} errMsg set errMsg } {Missing URI in Namespace declaration} test dom-1.21 {Explicit delete of scoped doc with domDoc cmd} {} { dom createDocument test doc domDoc $doc delete unset doc } {} proc dom-1.22 {doc} { $doc delete } test dom-1.22 {Explicit delete of scoped doc in proc call from scope} {} { dom createDocument test doc dom-1.22 $doc unset doc } {} test dom-1.23 {Explicit delete of scoped doc} { dom createDocument test doc $doc delete unset doc } {} test dom-1.24 {Explicit delete of scoped doc} { dom createDocument test doc set result [catch {set doc foo} errMsg] lappend result $errMsg $doc delete unset doc set result } {1 {can't set "doc": var is read-only}} test dom-1.25 {Doc var} { dom parse doc dom parse doc unset doc } {} test dom-1.26 {Doc var} { dom parse doc set result [catch {$doc documentElement doc}] unset doc set result } {1} test dom-2.1 {Don't quash white space at start or end of non white space content} { set doc [dom parse { some content }] set root [$doc documentElement] $root text } { some content } test dom-2.2 {parse doc with various re-declaration of a prefix} { set doc [dom parse { }] set root [$doc documentElement] set result [$root asXML] $doc delete set result } { } test dom-2.3 {parse doc with default NS declaration} { set doc [dom parse { }] set root [$doc documentElement] set result [$root asXML] $doc delete set result } { } test dom-2.4 {parse method: syntax check} { set doc [dom parse -keepEmpties { text }] set result [$doc asXML -indent none] $doc delete set result } { text } test dom-2.5 {parse method: syntax check} { set doc [dom parse -useForeignDTD 0 -keepEmpties { text }] set result [$doc asXML -indent none] $doc delete set result } { text } test dom-2.6 {parse method: syntax check} -setup { set xmlFile [makeFile { } dom.xml] } -body { set fd [open $xmlFile] set doc [dom parse -channel $fd -keepEmpties] close $fd set root [$doc documentElement] set result [$root asXML -indent none] $doc delete set result } -cleanup { removeFile dom.xml } -result { } test dom-2.7 {parse method: syntax check} -setup { set xmlFile [makeFile { } dom.xml] } -body { catch {unset -keepEmpties} set fd [open $xmlFile] set doc [dom parse -channel $fd -keepEmpties] close $fd $doc delete info exists -keepEmpties } -cleanup { removeFile dom.xml } -result 0 test dom-2.8 {parse method: bogus option} -body { set result [catch {set doc [dom parse -bogusOption foo ]} errMsg] lappend result $errMsg } -match regexp -result {1 {bad option "-bogusOption": must be .*}} test dom-2.9 {parse method: bogus option} -setup { set xmlFile [makeFile { } dom.xml] } -body { catch {unset -keepEmpties} set fd [open $xmlFile] set result [catch {set doc [dom parse -channel $fd -bogusOption]} errMsg] close $fd lappend result $errMsg } -cleanup { removeFile dom.xml } -match regexp -result {1 {bad option "-bogusOption": must be .*}} set dom_dtd " " proc extRefResolver {base systemId publicId} { global dom_dtd if {$publicId == "DOMCMDTEST"} { return [list string $base $dom_dtd] } else { return [::tdom::extRefHandler $base $systemId $publicId] } } test dom-2.10 {parse method: -paramentityparsing default is 'always'} { set doc [dom parse -externalentitycommand extRefResolver { }] set root [$doc documentElement] set result [$root @lang] $doc delete set result } {en} test dom-2.11 {parse method: explicit -paramentityparsing always} { set doc [dom parse -externalentitycommand extRefResolver \ -paramentityparsing always { }] set root [$doc documentElement] set result [$root @lang] $doc delete set result } {en} test dom-2.12 {parse method: -paramentityparsing never} { set doc [dom parse -externalentitycommand extRefResolver \ -paramentityparsing never { }] set root [$doc documentElement] set result [catch {set result [$root @lang]} errMsg] $doc delete lappend result $errMsg set result } {1 {Attribute "lang" not found!}} test dom-2.13 {parse method: -paramentityparsing notstandalone} { set doc [dom parse -externalentitycommand extRefResolver \ -paramentityparsing notstandalone { }] set root [$doc documentElement] set result [$root @lang] $doc delete set result } {en} test dom-2.14 {parse method: -paramentityparsing notstandalone} { set doc [dom parse -externalentitycommand extRefResolver \ -paramentityparsing notstandalone \ { }] set root [$doc documentElement] set result [catch {set result [$root @lang]} errMsg] $doc delete lappend result $errMsg set result } {1 {Attribute "lang" not found!}} test dom-2.15 {parse method: -paramentityparsing notstandalone} { set doc [dom parse -externalentitycommand extRefResolver \ -paramentityparsing notstandalone \ { }] set root [$doc documentElement] set result [$root @lang] $doc delete set result } {en} test dom-2.16 {parse method: wrong value arg for -paramentityparsing} { set result [catch {set doc [dom parse -paramentityparsing wrong { }]} errMsg] lappend result $errMsg } {1 {bad value "wrong": must be always, never, or notstandalone}} # The following is syntactically wrong. It's used, to test the # error reporting in external DTDs set dom_dtd "" test dom-2.17 {parse method: test reporting of error in external subset} { set result [catch {set doc [dom parse \ -externalentitycommand extRefResolver { }]} errMsg] lappend result $errMsg } {1 {error "syntax error" in entity "dummysystemID" at line 1 character 20 "", referenced at line 2 character 58}} test dom-2.18 {parse document with nodes before and after the documentElement} { set doc [dom parse { }] set result [$doc asXML -indent none] $doc delete set result } {} test dom-2.19 {parse document - rename docCmd} { set doc [dom parse {foo}] if {[info commands fooCmd] == "fooCmd"} { rename fooCmd {} } rename $doc fooCmd set result [fooCmd asXML -indent none] fooCmd delete set result } {foo} test dom-2.20 {parse - doc with internal subset parsed with -keepEmpties} { set doc [dom parse -keepEmpties { ]> }] $doc documentElement root set result "" foreach node [$root selectNodes /node()] { switch [$node nodeType] { TEXT_NODE { lappend result TEXT_NODE lappend result [string length [$node value]] } COMMENT_NODE { lappend result COMMENT_NODE lappend result [string length [$node value]] } PROCESSING_INSTRUCTION_NODE { lappend result PROCESSING_INSTRUCTION_NODE lappend result [$node target] lappend result [$node data] } ELEMENT_NODE { lappend result ELEMENT_NODE lappend result [$node nodeName] } default { lappend result [$node nodeType] } } } $doc delete set result } {ELEMENT_NODE root} test dom-2.21 {parse - empty CDATA section} { set doc [dom parse {}] set root [$doc documentElement] set result [$root hasChildNodes] $doc delete set result } {0} test dom-2.22 {parse - empty comment section} { set doc [dom parse {}] set root [$doc documentElement] set result [$root hasChildNodes] lappend result [[$root firstChild] nodeValue] $doc delete set result } {1 {}} test dom-2.23 {parse - pi without pivalue} { set doc [dom parse {}] set pi [[$doc documentElement] firstChild] set result [list [$pi nodeName] [$pi nodeValue] [$pi target] [$pi data]] $doc delete set result } {p {} p {}} proc 2.24 {args} { error "2.24 external entitiy resolver script error" } test dom-2.24 {parse - script error in -externalentitycommand} { set result [catch { dom parse -externalentitycommand 2.24 { }} errMsg] lappend result $errMsg } {1 {2.24 external entitiy resolver script error}} test dom-2.25 {White space outside the document element is markup and ignored, even with -keepEmpties} { set doc [dom parse -keepEmpties { }] set result [$doc asXML -indent none] $doc delete set result } { } test dom-2.26 {Not well-formed input} { catch {dom parse {}} } 1 test dom-2.27 {parse -ignorexmlns} { set result [list] set doc [dom parse {}] set root [$doc documentElement] lappend result [$root localName] lappend result [$root namespaceURI] set child [$root firstChild] lappend result [$child localName] lappend result [$child namespaceURI] lappend result [$doc selectNodes count(/doc/child)] $doc delete set doc [dom parse -ignorexmlns {}] set root [$doc documentElement] lappend result [$root nodeName] lappend result [$root namespaceURI] set child [$root firstChild] lappend result [$child nodeName] lappend result [$child namespaceURI] lappend result [$doc selectNodes count(/doc/child)] $doc delete set result } {doc foo.bar child foo.bar 0 doc {} child {} 1} test dom-2.28 {parse document with undeclared xml prefix} { catch {dom parse {}} errMsg string range $errMsg 0 30 } {Namespace prefix is not defined} test dom-2.29 {parse not well-formed document with undeclared xml prefix} { catch {dom parse {}} errMsg string range $errMsg 0 30 } {Namespace prefix is not defined} test dom-2.30 {parse document with undeclared xml prefix} { catch {dom parse {}} errMsg string range $errMsg 0 30 } {Namespace prefix is not defined} proc dom-2.31 {base systemId publicId} { switch $publicId { "e1" { # Not well-formed set data "" } default { error "unknown public ID" } } return [list "string" $base $data] } test dom-2.31 {parse document with undeclared xml prefix} { catch {dom parse -externalentitycommand dom-2.31 \ {]> &e1;} } errMsg string range $errMsg 0 30 } {Namespace prefix is not defined} test dom-2.32 {parse document with undeclared xml prefix and -ignorexmlns} { set doc [dom parse -ignorexmlns {}] set result [[$doc documentElement] nodeName] $doc delete set result } {foo:e} test dom-2.33 {end of options option} { set doc [dom parse -json -- -0.123] set result [$doc asXML -indent none] $doc delete set result } -0.123 test dom-2.33.1 {JSON data starting with a dash (-)} { set doc [dom parse -json -0.123] set result [$doc asXML -indent none] $doc delete set result } -0.123 test dom-2.33.2 {JSON data starting with a dash (-)} { dom parse -json -0.123 doc set result [$doc asXML -indent none] $doc delete set result } -0.123 test dom-2.33.3 {JSON data starting with a dash (-)} { dom parse -json -0.123 -0.123 set result [${-0.123} asXML -indent none] ${-0.123} delete set result } -0.123 test dom-2.34 {XML prefix declaration with empty namespace} { catch {dom parse {}} errMsg set errMsg } {Missing URI in Namespace declaration, referenced at line 1 character 22} test dom-2.35 {-keepCDATA} { set doc [dom parse -keepCDATA {foo format]]> bar }] set result [$doc asXML -indent none] $doc delete set result } {foo format]]> bar } test dom-2.36 {-keepCDATA} { set doc [dom parse -keepCDATA {foo format]]> bar }] set root [$doc documentElement] set result [list] foreach child [$root childNodes] { lappend result [$child nodeType] } $doc delete set result } {TEXT_NODE CDATA_SECTION_NODE TEXT_NODE} test dom-2.37 {-keepCDATA} { set doc [dom parse -keepCDATA {}] set result [list] foreach child [$doc selectNodes doc/e/node()] { lappend result [$child nodeType] } $doc delete set result } {CDATA_SECTION_NODE} test dom-2.38 {-keepCDATA} { set doc [dom parse -keepCDATA {}] set result [list] foreach child [$doc selectNodes doc/e/node()] { lappend result [$child nodeType] } $doc delete set result } {CDATA_SECTION_NODE CDATA_SECTION_NODE} test dom-2.39 {-keepCDATA} { set doc [dom parse -keepCDATA {}] set result [$doc selectNodes count(doc/e/node())] $doc delete set result } 0 test dom-2.40 {-keepCDATA white space only CDATA section} { set doc [dom parse -keepCDATA {}] set result [$doc selectNodes count(doc/e/node())] $doc delete set result } 0 test dom-2.41 {-keepCDATA and -keepEmpties} { set doc [dom parse -keepCDATA -keepEmpties {}] set result [$doc selectNodes count(doc/e/node())] $doc delete set result } 1 test dom-2.42 {namespaces} { set doc [dom parse {
notes
}] $doc delete } {} test dom-2.43 {billion laughs attact proctection options} { set result "" foreach {option value} { -billionLaughsAttackProtectionMaximumAmplification foo -billionLaughsAttackProtectionMaximumAmplification 0 -billionLaughsAttackProtectionMaximumAmplification -2.0 -billionLaughsAttackProtectionMaximumAmplification 23 -billionLaughsAttackProtectionActivationThreshold bar -billionLaughsAttackProtectionActivationThreshold 0 -billionLaughsAttackProtectionActivationThreshold -7 -billionLaughsAttackProtectionActivationThreshold 2000000000 } { lappend result [catch { set doc [dom parse $option $value ] }] if {![lindex $result end]} { $doc delete } } set result } {1 1 1 0 1 1 1 0} test dom-2.44 {attribute order and XML namespace declaration} { set doc [dom parse -simple { foo }] set root [$doc documentElement] set result [$root attributeNames] $doc delete set result } {xmlns:p xmlns foo grill bar} test dom-2.45 {attribute order and XML namespace declaration} { set doc [dom parse { }] set root [$doc documentElement] set result [$root attributeNames] $doc delete set result } {xmlns:p xmlns foo grill bar} test dom-2.46 {parse long string} {64bit Tcl9 longRunning largedata groklargedata} { set str "[string repeat abc 1000000000]" set doc [dom parse $str] set result [string length [$doc selectNodes string(/doc)]] lappend result [string length [$doc selectNodes substring(doc,2999999999)]] lappend result [$doc selectNodes substring(doc,2999999995,3)] $doc delete set result } {3000000000 2 abc} test dom-2.47 {parse chunk ends in multbyte char} { set str "[string repeat \u1D8B 3000]" set doc [dom parse $str] set new [$doc asXML -indent none] $doc delete expr {$str eq $new ? 1 : 0} } 1 test dom-3.1 {isName} { dom isName ":foo" } {1} test dom-3.2 {isName} { dom isName "_foo" } {1} test dom-3.3 {isName} { dom isName "foo:bar:baz" } {1} test dom-3.4 {isName} { dom isName "-foo" } {0} test dom-3.5 {isName} { dom isName ".foo" } {0} test dom-3.6 {isName} { catch {dom isName} } {1} test dom-3.7 {isName} { catch {dom isName foo bar} } {1} # The following character classes are out of XML 1.0 Second Edition rec, # Appendix B (which is following the Unicode standard). set BaseChar { {0x0041 0x005A} {0x0061 0x007A} {0x00C0 0x00D6} {0x00D8 0x00F6} {0x00F8 0x00FF} {0x0100 0x0131} {0x0134 0x013E} {0x0141 0x0148} {0x014A 0x017E} {0x0180 0x01C3} {0x01CD 0x01F0} {0x01F4 0x01F5} {0x01FA 0x0217} {0x0250 0x02A8} {0x02BB 0x02C1} 0x0386 {0x0388 0x038A} 0x038C {0x038E 0x03A1} {0x03A3 0x03CE} {0x03D0 0x03D6} 0x03DA 0x03DC 0x03DE 0x03E0 {0x03E2 0x03F3} {0x0401 0x040C} {0x040E 0x044F} {0x0451 0x045C} {0x045E 0x0481} {0x0490 0x04C4} {0x04C7 0x04C8} {0x04CB 0x04CC} {0x04D0 0x04EB} {0x04EE 0x04F5} {0x04F8 0x04F9} {0x0531 0x0556} 0x0559 {0x0561 0x0586} {0x05D0 0x05EA} {0x05F0 0x05F2} {0x0621 0x063A} {0x0641 0x064A} {0x0671 0x06B7} {0x06BA 0x06BE} {0x06C0 0x06CE} {0x06D0 0x06D3} 0x06D5 {0x06E5 0x06E6} {0x0905 0x0939} 0x093D {0x0958 0x0961} {0x0985 0x098C} {0x098F 0x0990} {0x0993 0x09A8} {0x09AA 0x09B0} 0x09B2 {0x09B6 0x09B9} {0x09DC 0x09DD} {0x09DF 0x09E1} {0x09F0 0x09F1} {0x0A05 0x0A0A} {0x0A0F 0x0A10} {0x0A13 0x0A28} {0x0A2A 0x0A30} {0x0A32 0x0A33} {0x0A35 0x0A36} {0x0A38 0x0A39} {0x0A59 0x0A5C} 0x0A5E {0x0A72 0x0A74} {0x0A85 0x0A8B} 0x0A8D {0x0A8F 0x0A91} {0x0A93 0x0AA8} {0x0AAA 0x0AB0} {0x0AB2 0x0AB3} {0x0AB5 0x0AB9} 0x0ABD 0x0AE0 {0x0B05 0x0B0C} {0x0B0F 0x0B10} {0x0B13 0x0B28} {0x0B2A 0x0B30} {0x0B32 0x0B33} {0x0B36 0x0B39} 0x0B3D {0x0B5C 0x0B5D} {0x0B5F 0x0B61} {0x0B85 0x0B8A} {0x0B8E 0x0B90} {0x0B92 0x0B95} {0x0B99 0x0B9A} 0x0B9C {0x0B9E 0x0B9F} {0x0BA3 0x0BA4} {0x0BA8 0x0BAA} {0x0BAE 0x0BB5} {0x0BB7 0x0BB9} {0x0C05 0x0C0C} {0x0C0E 0x0C10} {0x0C12 0x0C28} {0x0C2A 0x0C33} {0x0C35 0x0C39} {0x0C60 0x0C61} {0x0C85 0x0C8C} {0x0C8E 0x0C90} {0x0C92 0x0CA8} {0x0CAA 0x0CB3} {0x0CB5 0x0CB9} 0x0CDE {0x0CE0 0x0CE1} {0x0D05 0x0D0C} {0x0D0E 0x0D10} {0x0D12 0x0D28} {0x0D2A 0x0D39} {0x0D60 0x0D61} {0x0E01 0x0E2E} 0x0E30 {0x0E32 0x0E33} {0x0E40 0x0E45} {0x0E81 0x0E82} 0x0E84 {0x0E87 0x0E88} 0x0E8A 0x0E8D {0x0E94 0x0E97} {0x0E99 0x0E9F} {0x0EA1 0x0EA3} 0x0EA5 0x0EA7 {0x0EAA 0x0EAB} {0x0EAD 0x0EAE} 0x0EB0 {0x0EB2 0x0EB3} 0x0EBD {0x0EC0 0x0EC4} {0x0F40 0x0F47} {0x0F49 0x0F69} {0x10A0 0x10C5} {0x10D0 0x10F6} 0x1100 {0x1102 0x1103} {0x1105 0x1107} 0x1109 {0x110B 0x110C} {0x110E 0x1112} 0x113C 0x113E 0x1140 0x114C 0x114E 0x1150 {0x1154 0x1155} 0x1159 {0x115F 0x1161} 0x1163 0x1165 0x1167 0x1169 {0x116D 0x116E} {0x1172 0x1173} 0x1175 0x119E 0x11A8 0x11AB {0x11AE 0x11AF} {0x11B7 0x11B8} 0x11BA {0x11BC 0x11C2} 0x11EB 0x11F0 0x11F9 {0x1E00 0x1E9B} {0x1EA0 0x1EF9} {0x1F00 0x1F15} {0x1F18 0x1F1D} {0x1F20 0x1F45} {0x1F48 0x1F4D} {0x1F50 0x1F57} 0x1F59 0x1F5B 0x1F5D {0x1F5F 0x1F7D} {0x1F80 0x1FB4} {0x1FB6 0x1FBC} 0x1FBE {0x1FC2 0x1FC4} {0x1FC6 0x1FCC} {0x1FD0 0x1FD3} {0x1FD6 0x1FDB} {0x1FE0 0x1FEC} {0x1FF2 0x1FF4} {0x1FF6 0x1FFC} 0x2126 {0x212A 0x212B} 0x212E {0x2180 0x2182} {0x3041 0x3094} {0x30A1 0x30FA} {0x3105 0x312C} {0xAC00 0xD7A3} } set Ideographic { {0x4E00 0x9FA5} 0x3007 {0x3021 0x3029} } set CombiningChar { {0x0300 0x0345} {0x0360 0x0361} {0x0483 0x0486} {0x0591 0x05A1} {0x05A3 0x05B9} {0x05BB 0x05BD} 0x05BF {0x05C1 0x05C2} 0x05C4 {0x064B 0x0652} 0x0670 {0x06D6 0x06DC} {0x06DD 0x06DF} {0x06E0 0x06E4} {0x06E7 0x06E8} {0x06EA 0x06ED} {0x0901 0x0903} 0x093C {0x093E 0x094C} 0x094D {0x0951 0x0954} {0x0962 0x0963} {0x0981 0x0983} 0x09BC 0x09BE 0x09BF {0x09C0 0x09C4} {0x09C7 0x09C8} {0x09CB 0x09CD} 0x09D7 {0x09E2 0x09E3} 0x0A02 0x0A3C 0x0A3E 0x0A3F {0x0A40 0x0A42} {0x0A47 0x0A48} {0x0A4B 0x0A4D} {0x0A70 0x0A71} {0x0A81 0x0A83} 0x0ABC {0x0ABE 0x0AC5} {0x0AC7 0x0AC9} {0x0ACB 0x0ACD} {0x0B01 0x0B03} 0x0B3C {0x0B3E 0x0B43} {0x0B47 0x0B48} {0x0B4B 0x0B4D} {0x0B56 0x0B57} {0x0B82 0x0B83} {0x0BBE 0x0BC2} {0x0BC6 0x0BC8} {0x0BCA 0x0BCD} 0x0BD7 {0x0C01 0x0C03} {0x0C3E 0x0C44} {0x0C46 0x0C48} {0x0C4A 0x0C4D} {0x0C55 0x0C56} {0x0C82 0x0C83} {0x0CBE 0x0CC4} {0x0CC6 0x0CC8} {0x0CCA 0x0CCD} {0x0CD5 0x0CD6} {0x0D02 0x0D03} {0x0D3E 0x0D43} {0x0D46 0x0D48} {0x0D4A 0x0D4D} 0x0D57 0x0E31 {0x0E34 0x0E3A} {0x0E47 0x0E4E} 0x0EB1 {0x0EB4 0x0EB9} {0x0EBB 0x0EBC} {0x0EC8 0x0ECD} {0x0F18 0x0F19} 0x0F35 0x0F37 0x0F39 0x0F3E 0x0F3F {0x0F71 0x0F84} {0x0F86 0x0F8B} {0x0F90 0x0F95} 0x0F97 {0x0F99 0x0FAD} {0x0FB1 0x0FB7} 0x0FB9 {0x20D0 0x20DC} 0x20E1 {0x302A 0x302F} 0x3099 0x309A } set Digit { {0x0030 0x0039} {0x0660 0x0669} {0x06F0 0x06F9} {0x0966 0x096F} {0x09E6 0x09EF} {0x0A66 0x0A6F} {0x0AE6 0x0AEF} {0x0B66 0x0B6F} {0x0BE7 0x0BEF} {0x0C66 0x0C6F} {0x0CE6 0x0CEF} {0x0D66 0x0D6F} {0x0E50 0x0E59} {0x0ED0 0x0ED9} {0x0F20 0x0F29} } set Extender { 0x00B7 0x02D0 0x02D1 0x0387 0x0640 0x0E46 0x0EC6 0x3005 {0x3031 0x3035} {0x309D 0x309E} {0x30FC 0x30FE} } proc sortCmd {a b} { if {[lindex $a 0] > [lindex $b 0]} { return 1 } else { return -1 } } # if {$tcl_version < 8.4} { # set nameStartChars [lsort -command sortCmd \ # [concat $BaseChar $Ideographic 0x005F 0x003A]] # } else { # set nameStartChars [lsort -integer -index 0 \ # [concat $BaseChar $Ideographic 0x005F 0x003A]] # } set nameStartChars [lsort -command sortCmd \ [concat $BaseChar $Ideographic 0x005F 0x003A]] # Append stop char needed by the test code to work properly. lappend nameStartChars 0x10000 test dom-3.8 {isName} {longRunning} { set ind 0 set nr 0 while {$nr < 65536} { set range [lindex $nameStartChars $ind] incr ind if {[llength $range] == 2} { foreach {min max} $range break } else { set min $range set max $range } while {$nr < $min} { if {[dom isName [subst \\u[format "%04x" $nr]]] != 0} { error "wrong 'isName' result for name start char #x[format "%04x" $nr] - should be illegal" } incr nr } if {$nr == 0x10000} {break} while {$nr <= $max} { if {[dom isName [subst \\u[format "%04x" $nr]]] != 1} { error "wrong 'isName' result for name start char #x[format "%04x" $nr] - should be legal" } incr nr } } set nr } {65536} set nameChars [lsort -command sortCmd \ [concat $BaseChar $Ideographic $Digit 0x002E 0x002D 0x005F 0x003A \ $CombiningChar $Extender]] # Append stop char needed by the test code to work properly. lappend nameChars 0x10000 test dom-3.9 {isName} {longRunning} { set ind 0 set nr 0 while {$nr < 65536} { set range [lindex $nameChars $ind] incr ind if {[llength $range] == 2} { foreach {min max} $range break } else { set min $range set max $range } while {$nr < $min} { if {[dom isName a[subst \\u[format "%04x" $nr]]] != 0} { error "wrong 'isName' result for name char #x[format "%04x" $nr] - should be illegal" } incr nr } if {$nr == 0x10000} {break} while {$nr <= $max} { if {[dom isName a[subst \\u[format "%04x" $nr]]] != 1} { error "wrong 'isName' result for name char #x[format "%04x" $nr] - should be legal" } incr nr } } set nr } {65536} test dom-3.10 {isNCName} { dom isNCName ":foo" } {0} test dom-3.11 {isNCName} { dom isNCName "_foo" } {1} test dom-3.12 {isNCName} { dom isNCName "foo:bar:baz" } {0} test dom-3.13 {isNCName} { dom isNCName "-foo" } {0} test dom-3.14 {isNCName} { dom isNCName ".foo" } {0} test dom-3.15 {isNCName} { catch {dom isNCName} } {1} test dom-3.16 {isNCName} { catch {dom isNCName foo bar} } {1} test dom-3.17 {isQName} { dom isQName ":foo" } {0} test dom-3.18 {isQName} { dom isQName "_foo" } {1} test dom-3.19 {isQName} { dom isQName "foo:bar:baz" } {0} test dom-3.20 {isQName} { dom isQName "-foo" } {0} test dom-3.21 {isQName} { dom isQName ".foo" } {0} test dom-3.22 {isQName} { dom isQName "foo:bar" } {1} test dom-3.23 {isQName} { catch {dom isQName} } {1} test dom-3.24 {isQName} { catch {dom isQName foo bar} } {1} test dom-3.25 {isQName} { dom isQName "foo bar" } {0} test dom-3.26 {isQName} { dom isQName "woozbiz:" } {0} test dom-3.26.1 {isQName} { dom isQName foo:1 } {0} test dom-3.26.2 {isQName} { dom isQName 1:foo } {0} set XMLChars { 0x9 0xA 0xD {0x20 0xD7FF} {0xE000 0xFFFD} {0x10000 0x10FFFF} } test dom-3.27 {isCharData} {longRunning} { set ind 0 set nr 1 while {$nr < 65536} { set range [lindex $XMLChars $ind] incr ind if {[llength $range] == 2} { foreach {min max} $range break } else { set min $range set max $range } while {$nr < $min} { if {[dom isCharData "a[subst \\u[format "%04x" $nr]]b"] != 0} { error "wrong 'isCharData' result for char #x[format "%04x" $nr] - should be illegal" } incr nr } if {$nr == 0x10000} {break} while {$nr <= $max} { if {[dom isCharData "a[subst \\u[format "%04x" $nr]]b"] != 1} { error "wrong 'isCharData' result for char #x[format "%04x" $nr] - should be legal" } incr nr } } set nr } {65536} test dom-3.28 {isPIName} { dom isPIName "target" } {1} test dom-3.29 {isPIName} { dom isPIName "foo:target" } {1} test dom-3.30 {isPIName} { dom isPIName "Xml" } {0} test dom-3.31 {isComment} { dom isComment "some comment" } {1} test dom-3.32 {isComment} { dom isComment "some invalid -- comment" } {0} test dom-3.33 {isComment} { dom isComment "some invalid comment-" } {0} test dom-3.34 {isCDATA} { dom isCDATA "some ]] CDATA " } {1} test dom-3.35 {isCDATA} { dom isCDATA "some ]]> CDATA " } {0} test dom-3.36 {isCDATA} { dom isCDATA "invalid: ]]>" } {0} test dom-3.37 {isCDATA} { dom isCDATA "valid: ]]> " } {0} test dom-3.38 {isCDATA} { dom isCDATA "\ud7fa\ud7fb\ud7fc\ud7fd\ud7fe\ud7ff]]>" } {0} test dom-3.39 {isPIValue} { dom isPIValue "some processing instruction data" } {1} test dom-3.40 {isPIValue} { dom isPIValue "some invalid ?> processing instruction data" } {0} test dom-3.41 {isPIValue} { dom isPIValue "some invalid processing instruction data?>" } {0} test dom-3.43 {clearString} { set result [list] foreach str { \u0001 a\u0002 \u0003b a\u0004b a\u0004\u0005b a\u0004c\u0005b a\u0004d\u0005\u0006b a\u0004d\u0005\uD800\uD801\uD802_foo_bar \uD800\uD801\uD802_foo_bar_baz\uD802_didum\uDFFF \uD800\uD801\uD802_foo_bar_baz\uD802_didum\uE000 \u0004\u0005\uDABC abc \u00e4\u0004b \u00e4\u0004\u00f6 } { lappend result [dom clearString $str] } set result } [list {} a b ab ab acb adb ad_foo_bar _foo_bar_baz_didum _foo_bar_baz_didum\uE000 {} abc \u00e4b \u00e4\u00f6] test dom-3.44 {clearString -replace} { set result [list] foreach str { \u0001 a\u0002 \u0003b a\u0004b a\u0004\u0005b a\u0004c\u0005b a\u0004d\u0005\u0006b a\u0004d\u0005\uD800\uD801\uD802_foo_bar \uD800\uD801\uD802_foo_bar_baz\uD802_didum\uDFFF \uD800\uD801\uD802_foo_bar_baz\uD802_didum\uE000 \u0004\u0005\uDABC abc \u0004\u0005\u0001 } { lappend result [dom clearString -replace $str] } set result } [list \ufffd a\ufffd \ufffdb a\ufffdb a\ufffd\ufffdb a\ufffdc\ufffdb a\ufffdd\ufffd\ufffdb a\ufffdd\ufffd\ufffd\ufffd\ufffd_foo_bar \ufffd\ufffd\ufffd_foo_bar_baz\ufffd_didum\ufffd \ufffd\ufffd\ufffd_foo_bar_baz\ufffd_didum\uE000 \ufffd\ufffd\ufffd abc \ufffd\ufffd\ufffd] test dom-3.45 {clearString -replace with replacement} { set result [list] foreach str { \u0001 a\u0002 \u0003b a\u0004b a\u0004\u0005b a\u0004c\u0005b a\u0004d\u0005\u0006b a\u0004d\u0005\uD800\uD801\uD802_foo_bar \uD800\uD801\uD802_foo_bar_baz\uD802_didum\uDFFF \uD800\uD801\uD802_foo_bar_baz\uD802_didum\uE000 \u0004\u0005\uDABC abc \u0004\u0005\u0001 } { lappend result [dom clearString -replace some $str] } set result } [list some asome someb asomeb asomesomeb asomecsomeb asomedsomesomeb asomedsomesomesomesome_foo_bar somesomesome_foo_bar_bazsome_didumsome somesomesome_foo_bar_bazsome_didum\uE000 somesomesome abc somesomesome] test dom-3.46 {isHTML5CustomName} { set result [list] foreach str { abc ab-c ab-C -ab \u00E4b-c ab---c ab- ab-\u1d28 a\u00C4-b aA-b a\u00E4-b 0n-foo A-b font-face m\u00B7-. n-\uFDF0 o-\u3000 } { lappend result [dom isHTML5CustomName $str] } set result } {0 1 0 0 0 1 1 1 1 0 1 0 0 0 1 1 0} test dom-4.1 {-useForeignDTD 0} { set doc [dom parse -useForeignDTD 0 {}] $doc delete } {} test dom-4.2 {-useForeignDTD 1 with document with internal subset} {need_uri} { set baseURI [tdom::baseURL [file join [pwd] [file dir [info script]] dom.test]] set ::tdom::useForeignDTD "data/domCmd1.dtd" set doc [dom parse \ -useForeignDTD 1 \ -baseurl $baseURI \ -externalentitycommand ::tdom::extRefHandler { ]> }] set root [$doc documentElement] set result [$root @fixed] $doc delete set result } {toThat} test dom-4.3 {-useForeignDTD 1 with document with internal subset} {need_uri} { set baseURI [tdom::baseURL [file join [pwd] [file dir [info script]] dom.test]] set ::tdom::useForeignDTD "data/domCmd1.dtd" set doc [dom parse \ -useForeignDTD 1 \ -baseurl $baseURI \ -externalentitycommand ::tdom::extRefHandler { ]> }] set root [$doc documentElement] set result [$root @fixed] lappend result [$root @fixed2] $doc delete set result } {toThis toThat} test dom-4.4 {-useForeignDTD 1 with document without document declaration} {need_uri} { set baseURI [tdom::baseURL [file join [pwd] [file dir [info script]] dom.test]] set ::tdom::useForeignDTD "data/domCmd1.dtd" set doc [dom parse \ -useForeignDTD 1 \ -baseurl $baseURI \ -externalentitycommand ::tdom::extRefHandler ] set root [$doc documentElement] set result [$root @fixed] $doc delete set result } {toThis} test dom-4.5 {-useForeignDTD 1 does not overwrite a given external subset} {need_uri} { set baseURI [tdom::baseURL [file join [pwd] [file dir [info script]] dom.test]] set ::tdom::useForeignDTD "data/domCmd1.dtd" set doc [dom parse \ -useForeignDTD 1 \ -baseurl $baseURI \ -externalentitycommand ::tdom::extRefHandler { }] set root [$doc documentElement] set result [$root @fixed] $doc delete set result } {toThat} test dom-4.6 {-useForeignDTD with nonboolean arg} {need_uri} { set result [catch {set doc [dom parse -useForeignDTD foo ]} errMsg] lappend result $errMsg } {1 {expected boolean value but got "foo"}} test dom-5.1 {document with external subset} {need_uri} { set baseURI [tdom::baseURL [file join [pwd] [file dir [info script]] dom.test]] set doc [dom parse \ -baseurl $baseURI \ -externalentitycommand ::tdom::extRefHandler { }] set root [$doc documentElement] set result [$root @fixed] $doc delete set result } {toThat} proc dom-5.2 {myparm base systemId publicId} { set ::dom-5_2 $myparm return [list string dummy ""] } test dom-5.2 {-externalentitycommand} { set ::dom-5_2 "" set doc [dom parse \ -baseurl "dummy" \ -externalentitycommand [list dom-5.2 thisDoc] { }] $doc delete set ::dom-5_2 } {thisDoc} proc dom-5.3 {base systemId publicId} { switch $publicId { "e1" { # Not well-formed set data "" } default { error "unknown public ID" } } return [list "string" $base $data] } test dom-5.3 {-externalentitycommand - nested external entities} -body { set result [catch { dom parse -externalentitycommand dom-5.3 \ { ]> &e1;} } msg] list $result $msg } -result [list 1 {error "not well-formed (invalid token)" in entity "e1.xml" at line 1 character 2 "", referenced at line 4 character 21}] proc dom-5.4 {base systemId publicId} { switch $publicId { "e1" { set data "&e2;" } "e2" { set data "" } default { error "unknown public ID" } } return [list "string" $base $data] } test dom-5.4 {-externalentitycommand - nested external entities} -body { set result [catch { dom parse -externalentitycommand dom-5.4 \ { ]> &e1;} } msg] list $result $msg } -result [list 1 {error "not well-formed (invalid token)" in entity "e2.xml" at line 1 character 2 "", referenced in entity "e1.xml" at line 1 character 4, referenced at line 5 character 21}] proc dom-5.5 {base systemId publicId} { switch $publicId { "e1" { set data "&e2;" } "e2" { set data "&e3;" } "e3" { # Not well-formed set data "" } default { error "unknown public ID" } } return [list "string" $base $data] } test dom-5.5 {-externalentitycommand - nested external entities} -body { set result [catch { dom parse -externalentitycommand dom-5.5 \ { ]> &e1;} } msg] list $result $msg } -result [list 1 {error "not well-formed (invalid token)" in entity "e3.xml" at line 1 character 2 "", referenced in entity "e2.xml" at line 1 character 4, referenced in entity "e1.xml" at line 1 character 4, referenced at line 6 character 21}] proc dom-5.6 {base systemId publicId} { switch $publicId { "e1" { set data [open $::e1] } default { error "unknown public ID" } } lappend ::openChannels $data return [list "channel" $base $data] } test dom-5.6 {-externalentitycommand - nested external entities} -setup { set e1 [makeFile "" e1.xml] set openChannels [list] } -body { set result [catch { dom parse -externalentitycommand dom-5.6 \ { ]> &e1;} } msg] list $result $msg } -cleanup { foreach channel $openChannels {close $channel} removeFile e1.xml } -result [list 1 {error "not well-formed (invalid token)" in entity "e1.xml" at line 1 character 2, referenced at line 4 character 21}] proc dom-5.7 {base systemId publicId} { switch $publicId { "e1" { set data [open $::e1] } "e2" { set data [open $::e2] } default { error "unknown public ID" } } lappend ::openChannels $data return [list "channel" $base $data] } test dom-5.7 {-externalentitycommand - nested external entities} -setup { set e1 [makeFile "&e2;" e1.xml] set e2 [makeFile "" e2.xml] set openChannels [list] } -body { set result [catch { dom parse -externalentitycommand dom-5.7 \ { ]> &e1;} } msg] list $result $msg } -cleanup { foreach channel $openChannels {close $channel} removeFile e1.xml removeFile e2.xml } -result [list 1 {error "not well-formed (invalid token)" in entity "e2.xml" at line 1 character 2, referenced in entity "e1.xml" at line 1 character 4, referenced at line 5 character 21}] proc dom-5.8 {base systemId publicId} { switch $publicId { "e1" { set data [open $::e1] } "e2" { set data [open $::e2] } "e3" { set data [open $::e3] } default { error "unknown public ID" } } lappend ::openChannels $data return [list "channel" $base $data] } test dom-5.8 {-externalentitycommand - nested external entities} -setup { set e1 [makeFile "&e2;" e1.xml] set e2 [makeFile "&e3;" e2.xml] set e3 [makeFile "" e3.xml] set openChannels [list] } -body { set result [catch { dom parse -externalentitycommand dom-5.8 \ { ]> &e1;} } msg] list $result $msg } -cleanup { foreach channel $openChannels {close $channel} removeFile e1.xml removeFile e2.xml removeFile e3.xml } -result [list 1 {error "not well-formed (invalid token)" in entity "e3.xml" at line 1 character 2, referenced in entity "e2.xml" at line 1 character 4, referenced in entity "e1.xml" at line 1 character 4, referenced at line 6 character 21}] test dom-5.9 {Wrong option after -externalentitycommand} -body { set result [catch {dom parse -externalentitycommand ::tdom::extRefHandler \ -useForeignDTD foo}] } -result 1 proc dom-5.9 {args} { return [list string "" {text12more text}] } test dom-5.9 {-externalentitycommand - external entity is a forest} { set doc [dom parse -externalentitycommand dom-5.9 \ {]> &e1;}] set result [$doc asXML -indent none] $doc delete set result } {text12more text} test dom-6.1 {use in slave interpreter} { set slave [interp create] load {} Tdom $slave interp eval $slave { dom parse foo doc $doc documentElement root } interp delete $slave } {} test dom-6.2 {use in slave interpreter} { set slave [interp create] load {} Tdom $slave interp eval $slave { set doc [dom parse foo] set root [$doc documentElement] } interp delete $slave } {} test dom-7.1 {setNameCheck} { set result [dom setNameCheck] lappend result [dom setNameCheck 0] lappend result [dom setNameCheck] # set back to default lappend result [dom setNameCheck 1] set result } {1 0 0 1} set doc [dom createDocument root] # ensure, we've the default dom setNameCheck 1 test dom-7.2 {setNameCheck} { set result [catch {$doc createElement "invalid name"} errMsg] lappend result $errMsg } {1 {Invalid tag name 'invalid name'}} test dom-7.3 {setNameCheck} { catch {$doc createElement "valid:name"} } {0} test dom-7.4 {setNameCheck} { catch {$doc createElement "valid::name"} } {0} test dom-7.5 {setNameCheck} { dom setNameCheck 0 set result [catch {$doc createElement "invalid name"} errMsg] # set back to default dom setNameCheck 1 set result } {0} test dom-7.6 {setNameCheck} { set result [catch {$doc createElementNS "dummyns" "invalid name"} errMsg] lappend result $errMsg } {1 {Invalid full qualified tag name 'invalid name'}} test dom-7.7 {setNameCheck} { catch {$doc createElementNS "dummyns" "valid:name"} } {0} test dom-7.8 {setNameCheck} { set result [catch {$doc createElementNS "dummyns" "invalid::name"} errMsg] lappend result $errMsg } {1 {Invalid full qualified tag name 'invalid::name'}} test dom-7.9 {setNameCheck} { dom setNameCheck 0 set result [catch {$doc createElementNS "dummyns" "invalid name"} errMsg] # set back to default dom setNameCheck 1 set result } {0} test dom-7.10 {setTextCheck} { set result [catch {$doc createComment "valid comment"}] lappend result [catch {$doc createComment "invalid -- comment"}] dom setTextCheck 0 lappend result [catch {$doc createComment "invalid -- comment"}] dom setTextCheck 1 set result } {0 1 0} test dom-7.11 {setTextCheck} { set result [catch {$doc createCDATASection ""}] lappend result [catch {$doc createCDATASection "]]>]]>foo\u0003bar" test dom-7.19 {setTextCheck and appendFromScript - setTextCheck state at create time is crucial} { set doc [dom createDocumentNode] namespace eval nodeCmds { dom createNodeCmd elementNode doc dom createNodeCmd textNode t } dom setTextCheck 0 set result [catch {$doc appendFromScript { nodeCmds::doc { nodeCmds::t "foo\u0003bar" } }} errMsg] dom setTextCheck 1 $doc delete lappend result $errMsg } [list 1 "Invalid text value 'foo\u0003bar'"] test dom-7.19 {setNameCheck / createDocument} { dom setNameCheck 0 dom createDocument "foo bar" doc set result [$doc asXML -indent none] $doc delete dom setNameCheck 1 set result } {} test dom-7.20 {set*Check, setStoreLineColumn and setObjectCommands in child interp} { set storedNameCheck [dom setNameCheck] set storedTextCheck [dom setTextCheck] set storedLineColumn [dom setStoreLineColumn] set storedObjectCommands [dom setObjectCommands] dom setNameCheck 1 dom setTextCheck 1 dom setStoreLineColumn 0 dom setObjectCommands command interp create childinterp load {} Tdom childinterp childinterp eval { dom setNameCheck 0 dom setTextCheck 0 dom setStoreLineColumn 1 } set nrCommands [llength [info commands]] set doc [dom parse {some}] set result [expr {[llength [info commands]] - $nrCommands}] lappend result [catch {$doc createElement "foo bar" node}] lappend result [catch {$doc createTextNode "a\u0001z" textnode}] lappend result [catch {[$doc documentElement] getLine}] lappend result [catch {[$doc documentElement] getColumn}] if {[catch {$doc delete}]} { domDoc $doc delete } childinterp eval { dom setObjectCommands token } dom setNameCheck $storedNameCheck dom setTextCheck $storedTextCheck dom setStoreLineColumn $storedLineColumn dom setObjectCommands $storedObjectCommands lappend result {*}[childinterp eval { set nrCommands [llength [info commands]] set doc [dom parse {some}] set result [expr {[llength [info commands]] - $nrCommands}] lappend result [catch {domDoc $doc createElement "foo bar" node}] lappend result [catch {domDoc $doc createTextNode "a\u0001z" textnode}] lappend result [catch {domNode [domDoc $doc documentElement] getLine}] lappend result [catch {domNode [domDoc $doc documentElement] getColumn}] domDoc $doc delete set result }] interp delete childinterp set result } {1 1 1 1 1 0 0 0 0 0} test dom-8.1 {createDocumentNode} { set result [catch {dom createDocumentNode foo bar}] } {1} test dom-8.2 {createDocumentNode} { set docNode [dom createDocumentNode] set result [$docNode asXML -indent none] $docNode delete set result } {} test dom-8.3 {createDocumentNode} { dom createDocumentNode docNode set result [$docNode asXML -indent none] $docNode delete set result } {} test dom-8.4 {createDocumentNode} { set docNode [dom createDocumentNode] set result [$docNode nodeType] lappend result [$docNode documentElement] $docNode delete set result } {DOCUMENT_NODE {}} test dom-8.5 {createDocumentNode} { set docNode [dom createDocumentNode] set newNode [$docNode createComment "Comment before the document node"] $docNode appendChild $newNode set result [[$docNode documentElement] nodeType] set newNode [$docNode createElement firstChild] $docNode appendChild $newNode lappend result [[$docNode documentElement] nodeName] set newNode [$docNode createElement secondChild] $docNode appendChild $newNode lappend result [[$docNode documentElement] nodeName] $docNode delete set result } {COMMENT_NODE firstChild firstChild} test dom-8.6 {createDocumentNode} { set docNode [dom createDocumentNode] set doc [dom parse {some text}] set root [$doc documentElement] set listRep [$root asList] $doc delete $docNode appendFromList $listRep set result [$docNode asXML -indent none] $docNode delete set result } {some text} test dom-8.7 {createDocumentNode} { dom createDocumentNode docNode dom createDocumentNode docNode $docNode delete set result "" } "" test dom-8.8 {createDocumentNode} { dom createDocumentNode -jsonType ARRAY docNode set result [$docNode jsonType] $docNode delete set result } ARRAY test dom-8.9 {createDocumentNode} { set docNode [dom createDocumentNode -jsonType NUMBER] set result [$docNode jsonType] $docNode delete set result } NUMBER test dom-8.10 {createDocumentNode} { catch {dom createDocumentNode -foo NULL docNode} errMsg set errMsg } {bad option "-foo": must be -jsonType} test dom-8.10 {createDocumentNode} { catch {dom createDocumentNode -foo NULL docNode} errMsg set errMsg } {bad option "-foo": must be -jsonType} test dom-8.11 {createDocumentNode} { catch {dom createDocumentNode -jsonType FOO docNode} errMsg set errMsg } {bad jsonType "FOO": must be NONE, ARRAY, OBJECT, NULL, TRUE, FALSE, STRING, NUMBER, or BOOLEAN} test dom-8.12 {createDocumentNode - method check} { set docNode [dom createDocumentNode] set result [$docNode documentElement] $docNode delete set result } {} test dom-8.13 {createDocumentNode - method check} { set docNode [dom createDocumentNode] set result [$docNode getElementsByTagName foo] $docNode delete set result } {} test dom-8.14 {createDocumentNode - method check} { set docNode [dom createDocumentNode] set result [$docNode getElementsByTagNameNS http://bar.org foo] $docNode delete set result } {} test dom-8.15 {createDocumentNode - method check} { set docNode [dom createDocumentNode] set newElement [$docNode createElement child] set result [$newElement asXML -indent none] $docNode delete set result } {} test dom-8.16 {createDocumentNode - method check} { set docNode [dom createDocumentNode] $docNode delete } {} test dom-8.17 {createDocumentNode - method check} { set docNode [dom createDocumentNode] set node [$docNode createCDATASection ""] set result [$node asXML -indent none] $docNode delete set result } {]]>} test dom-8.18 {createDocumentNode - method check} { set docNode [dom createDocumentNode] set node [$docNode createTextNode "a&b"] set result [$node asXML -indent none] $docNode delete set result } {a&b} test dom-8.19 {createDocumentNode - method check} { set docNode [dom createDocumentNode] set node [$docNode createComment "some comment"] set result [$node asXML -indent none] $docNode delete set result } {} test dom-8.20 {createDocumentNode - method check} { set docNode [dom createDocumentNode] set node [$docNode createProcessingInstruction foo bar] set result [$node asXML -indent none] $docNode delete set result } {} test dom-8.21 {createDocumentNode - method check} { set docNode [dom createDocumentNode] set node [$docNode createElementNS http://foo.org p:bar] $docNode appendChild $node set result [$docNode asXML -indent none] $docNode delete set result } {} test dom-8.22 {createDocumentNode - method check} { set docNode [dom createDocumentNode] set result [$docNode getDefaultOutputMethod] $docNode delete set result } {xml} test dom-8.23 {createDocumentNode - method check} { set docNode [dom createDocumentNode] set result [$docNode asXML -indent none] $docNode delete set result } {} test dom-8.24 {createDocumentNode - method check} { set docNode [dom createDocumentNode] set result [$docNode asHTML] $docNode delete set result } {} test dom-8.25 {createDocumentNode - method check} { set docNode [dom createDocumentNode] set identityTransformation [dom parse { }] set resultdoc [$docNode xslt $identityTransformation] set result [$resultdoc asXML -indent none] $resultdoc delete $identityTransformation delete $docNode delete set result } {} test dom-8.26 {createDocumentNode - method check} { set docNode [dom createDocumentNode] set result "" lappend result [$docNode publicId] $docNode publicId data lappend result [$docNode publicId] $docNode delete set result } {{} data} test dom-8.27 {createDocumentNode - method check} { set docNode [dom createDocumentNode] set result "" lappend result [$docNode systemId] $docNode systemId data lappend result [$docNode systemId] $docNode delete set result } {{} data} test dom-8.28 {createDocumentNode - method check} { set docNode [dom createDocumentNode] set result "" lappend result [$docNode internalSubset] $docNode internalSubset data lappend result [$docNode internalSubset] $docNode delete set result } {{} data} test dom-8.29 {createDocumentNode - method check} { set docNode [dom createDocumentNode] set result [catch {$docNode toXSLTcmd}] $docNode delete set result } {1} test dom-8.30 {createDocumentNode - method check} { set docNode [dom createDocumentNode] set result [$docNode asText] $docNode delete set result } {} test dom-8.31 {createDocumentNode - method check} { set docNode [dom createDocumentNode] $docNode normalize set result [$docNode asXML -indent none] $docNode delete set result } {} test dom-9.1 {setObjectCommands} { dom setObjectCommands } {automatic} test dom-9.2 {setObjectCommands} { dom setObjectCommands automatic } {automatic} test dom-9.3 {setObjectCommands} { set result [catch {dom setObjectCommands foobar} errMsg] lappend result $errMsg } {1 {bad mode value "foobar": must be automatic, command, or token}} test dom-9.4 {setObjectCommands} { set nrOfCmds [llength [info commands]] dom setObjectCommands automatic set docNode [dom createDocumentNode] set result [expr {$nrOfCmds + 1 == [llength [info commands]]}] $docNode delete lappend result [expr {$nrOfCmds == [llength [info commands]]}] dom setObjectCommands token set docNode [dom createDocumentNode] lappend result [expr {$nrOfCmds == [llength [info commands]]}] lappend result [domDoc $docNode hasChildNodes] domDoc $docNode delete lappend result [expr {$nrOfCmds == [llength [info commands]]}] # switch back to default dom setObjectCommands automatic set result } {1 1 1 0 1} test dom-9.5 {setObjectCommands} { dom setObjectCommands token set nrOfCmds [llength [info commands]] set doc [dom parse ] set root [domDoc $doc documentElement] set result [expr {$nrOfCmds == [llength [info commands]]}] dom setObjectCommands command set docCmd [domNode $root ownerDocument] lappend result [expr {$nrOfCmds + 1 == [llength [info commands]]}] $docCmd delete dom setObjectCommands automatic set result } {1 1} test dom-9.6 {node token with result var argument} { dom setObjectCommands token set doc [dom parse ] domDoc $doc documentElement var domNode $var firstChild var domNode $var nextSibling var domDoc $doc delete dom setObjectCommands automatic } {automatic} catch {namespace delete nodeCmds} namespace eval nodeCmds { dom createNodeCmd elementNode e1 dom createNodeCmd elementNode e2 dom createNodeCmd commentNode c dom createNodeCmd textNode t dom createNodeCmd cdataNode cdata dom createNodeCmd piNode pi dom createNodeCmd parserNode parser dom createNodeCmd -tagName foo elementNode bar } test dom-10.1 {createNodeCmd} { llength [info commands nodeCmds::*] } {8} namespace eval nodeCmds { rename e1 {} rename e2 {} rename c {} rename t {} rename cdata {} rename pi {} rename parser {} rename bar {} } test dom-10.2 {createNodeCmd} { llength [info commands nodeCmds::*] } {0} namespace eval nodeCmds { dom createNodeCmd elementNode e1 dom createNodeCmd textNode t } test dom-10.3 {node creating command called outside domNode context} { set result [catch {nodeCmds::t "some text"} errMsg] lappend result $errMsg } {1 {called outside domNode context}} test dom-10.4 {node creating command called outside domNode context} { dom createDocument docRoot doc $doc documentElement root $root appendFromScript { nodeCmds::t "Some text" } set result [list [$doc asXML -indent none]] $doc delete lappend result [catch {nodeCmds::t "Some text"} errMsg] lappend result $errMsg } {{Some text} 1 {called outside domNode context}} test dom-10.5 {node creating command called outside domNode context} { dom createDocument docRoot doc $doc documentElement root $root appendFromScript { nodeCmds::e1 { nodeCmds::t "Some text" } } set result [list [$doc asXML -indent none]] $doc delete lappend result [catch { nodeCmds::e1 { nodeCmds::t "Some text" }} errMsg] lappend result $errMsg } {{Some text} 1 {called outside domNode context}} namespace eval nodeCmds { dom createNodeCmd -tagName foo elementNode bar } test dom-10.6 {createNodeCmd - option -tagName} { set doc [dom createDocumentNode] $doc appendFromScript { nodeCmds::bar {} } set result [$doc asXML -indent none] $doc delete set result } {} namespace delete nodeCmds test dom-11.1 {featureinfo - expatversion} -body { dom featureinfo expatversion } -match regexp -result {expat_.*} test dom-11.2 {featureinfo - invalid arg} -body { catch {dom featureinfo foo} errMsg } -result 1 test dom-11.3 {featureinfo - expatmajorversion} -body { dom featureinfo expatmajorversion } -match regexp -result {(1|2)} test dom-11.4 {featureinfo - dtd} -body { dom featureinfo dtd } -match regexp -result {(0|1)} test dom-11.5 {featureinfo - jsonmaxnesting} { dom featureinfo jsonmaxnesting } 2000 test dom-11.6 {featureinfo - versionhash} { regexp {^[0-9a-fA-F]+$} [dom featureinfo versionhash] } 1 proc ::dom::domParseFeedback {} { return -code break } test dom-12.1 {-feedbackAfter -- cmd returns TCL_BREAK} -body { dom parse -feedbackAfter 1 {} } -result "" proc ::dom::domParseFeedback {} { error "Error in feedback cmd." } test dom-12.2 {-feedbackAfter -- cmd returns TCL_ERROR} -body { set result [catch { dom parse -feedbackAfter 1 {} } msg] list $result $msg } -result [list 1 "Error in feedback cmd."] proc ::dom::domParseFeedback {} { # Update progess dialog, check for cancel etc. return } test dom-12.3 {-feedbackAfter} -body { set doc [dom parse -feedbackAfter 1 {}] $doc selectNodes count(//*) } -result 4 test dom-12.4 {-feedbackAfter and -channel} -setup { set xmlFile [makeFile {} dom.xml] } -body { set fd [open $xmlFile] set doc [dom parse -channel $fd -feedbackAfter 1] close $fd $doc selectNodes count(//*) } -cleanup { removeFile dom.xml } -result 4 proc extRefResolver-12.5 {base systemId publicId} { switch $publicId { "a" { set data "" } "b" { set data "" } default { error "unknown public ID" } } return [list "string" $base $data] } test dom-12.5 {-feedbackAfter and external entities} -body { set doc [dom parse -externalentitycommand extRefResolver-12.5 \ -feedbackAfter 1 { ]> &a;&b;}] $doc selectNodes count(//*) } -result 4 set cancel 0 proc extRefResolver-12.6 {base systemId publicId} { global cancel switch $publicId { "a" { set cancel 1 set data "" } "b" { set data "" } default { error "unknown public ID" } } return [list "string" $base $data] } proc ::dom::domParseFeedback {} { global cancel if {$cancel} { return -code break } } test dom-12.6 {-feedbackAfter and external entities, with cancel} -body { dom parse -externalentitycommand extRefResolver-12.6 \ -feedbackAfter 1 { ]> &a;&b;} } -result "" proc ::dom::domParseFeedback {} { global cancel if {$cancel} { error "Error in feedback cmd." } } test dom-12.7 {-feedbackAfter and external entities, with error} -body { set result [catch {dom parse -externalentitycommand extRefResolver-12.6 \ -feedbackAfter 1 { ]> &a;&b;}} msg] list $result $msg } -result [list 1 "Error in feedback cmd."] test dom-12.8 {-feedbackAfter without -feedbackcmd} -setup { catch {rename ::dom::domParseFeedback ""} } -body { set result [catch {dom parse -feedbackAfter 100 } msg] list $result $msg } -result {1 {If -feedbackAfter is used, -feedbackcmd must also be used.}} proc feedbackcmd-12.9 {} { return -code break } test dom-12.9 {-feedbackAfter with -feedbackcmd -- cmd returns TCL_BREAK} -body { dom parse -feedbackAfter 1 -feedbackcmd feedbackcmd-12.9 \ {} } -result "" proc feedbackcmd-12.10 {} { error "Error in feedback cmd." } test dom-12.10 {-feedbackAfter with -feedbackcmd -- cmd returns TCL_ERROR} -body { set result [catch { dom parse -feedbackAfter 1 -feedbackcmd feedbackcmd-12.10 \ {} } msg] list $result $msg } -result [list 1 "Error in feedback cmd."] proc feedbackcmd-12.11 {} { # Update progess dialog, check for cancel etc. return } test dom-12.11 {-feedbackAfter with -feedbackcmd} -body { set doc [dom parse -feedbackAfter 1 -feedbackcmd feedbackcmd-12.11 \ {}] $doc selectNodes count(//*) } -result 4 test dom-12.12 {-feedbackAfter with -feedbackcmd and -channel} -setup { set xmlFile [makeFile {} dom.xml] } -body { set fd [open $xmlFile] set doc [dom parse -channel $fd -feedbackAfter 1 \ -feedbackcmd feedbackcmd-12.11] close $fd $doc selectNodes count(//*) } -cleanup { removeFile dom.xml } -result 4 test dom-12.13 {-feedbackAfter with -feedbackcmd and external entities} -body { set doc [dom parse -externalentitycommand extRefResolver-12.5 \ -feedbackcmd feedbackcmd-12.11 \ -feedbackAfter 1 { ]> &a;&b;}] $doc selectNodes count(//*) } -result 4 set cancel 0 proc feedbackcmd-12.14 {} { global cancel if {$cancel} { return -code break } } test dom-12.14 {-feedbackAfter with -feedbackcmd and external entities, with cancel} -body { dom parse -externalentitycommand extRefResolver-12.6 \ -feedbackcmd feedbackcmd-12.14 \ -feedbackAfter 1 { ]> &a;&b;} } -result "" set cancel 0 proc feedbackcmd-12.15 {} { global cancel if {$cancel} { error "Error in feedback cmd." } } test dom-12.15 {-feedbackAfter with -feedbackcmd and external entities, with error} -body { set result [catch {dom parse -externalentitycommand extRefResolver-12.6 \ -feedbackcmd feedbackcmd-12.15 \ -feedbackAfter 1 { ]> &a;&b;}} msg] list $result $msg } -result [list 1 "Error in feedback cmd."] proc feedbackcmd-12.16 {} { incr ::feedbackcmd-12.16 } test dom-12.16 {-feedbackcmd setting interp result w/ invalid XML} -body { set ::feedbackcmd-12.16 0 set result [catch {dom parse -feedbackcmd feedbackcmd-12.16 \ -feedbackAfter 1 {< <--Error-- /doc"}] test dom-13.1 {-forest} -body { dom parse -forest {12} doc set result [$doc asXML -indent none] $doc delete set result } -result {12} test dom-13.2 {-forest} -body { catch {dom parse -forest {12}} } -result {1} test dom-13.3 {-forest} -body { dom parse -forest {12some text} doc set result [$doc asXML -indent none] $doc delete set result } -result {12some text} test dom-13.4 {-forest -channel} -setup { set xmlfile [makeFile {12} dom.xml] } -body { set fd [open $xmlfile] set doc [dom parse -channel $fd -forest] close $fd set result [$doc asXML -indent none] $doc delete set result } -cleanup { removeFile dom.xml } -result {12} test dom-13.5 {-forest -channel} -setup { set xmlfile [makeFile {12} dom.xml] } -body { set fd [open $xmlfile] set result [catch {set doc [dom parse -channel $fd -forest]} errMsg] close $fd list $result $errMsg } -cleanup { removeFile dom.xml } -result {1 {error "asynchronous entity" at line 2 character 0}} test dom-13.6 {-forest -channel} -setup { # makeFile appends a newline at end set xmlfile [makeFile {12some text} dom.xml] } -body { set fd [open $xmlfile] set doc [dom parse -channel $fd -forest] close $fd set result [$doc asXML -indent none] $doc delete set result } -cleanup { removeFile dom.xml } -result {12some text } test dom-13.7 {-forest} -body { catch {dom parse -forest {12}} } -result {1} test dom-13.8 {-forest} { set xml {} catch {dom parse $xml} errMsg1 catch {dom parse -forest $xml} errMsg2 expr {$errMsg1 eq $errMsg2} } {1} test dom-13.9 {-forest} { catch {dom parse -forest {}} } 1 test dom-13.10 {-forest} { set xml {
something
something else
} set doc [dom parse -forest $xml] set result "" foreach child [$doc selectNodes /*] { lappend result [$child parentNode] } $doc delete set result } {{} {}} test dom-14.1 {called without arguments} { set result [catch {dom} errMsg] lappend result $errMsg } {1 {wrong # args: should be "dom subcommand ?arg ...?"}} test dom-14.2 {wrong subcommand} -body { catch {dom invalid-method} errMsg set errMsg } -match glob -result {bad method "invalid-method": must be *} test dom-14.3 {Too less arguments to method parse} { catch {dom parse} errMsg set errMsg } {wrong # args: should be "parse ?options? ?data? ?objvar?"} test dom-15.1 {fromScriptContext} { dom createDocument doc doc set root [$doc documentElement] $root appendFromScript { set parent [dom fromScriptContext] } $doc delete expr {$root == $parent} } 1 test dom-15.2 {fromScriptContext} { dom createDocument doc doc set root [$doc documentElement] namespace eval nodeCmds { dom createNodeCmd elementNode e1 } $root appendFromScript { set parent [dom fromScriptContext] nodeCmds::e1 { set ::e1 [dom fromScriptContext] } } set result [expr {$root == $parent && [$root firstChild] == $e1}] $doc delete set result } 1 # cleanup ::tcltest::cleanupTests return tdom-0.9.6-src/tests/pcdata.test0000644000175000017500000000460315025767703015262 0ustar rolfrolf# Features covered: PCDATA # # This file tests the parser's performance on PCDATA. # Sourcing this file into Tcl runs the tests and generates output # for errors. No output means no errors were found. # # Copyright (c) 1998-2000 Zveno Pty Ltd. # # $Id$ source [file join [file dir [info script]] loadtdom.tcl] catch {unset result} proc pcdata data { append ::result $data incr ::pcdataCounter } proc Estart {tagName attrList} { switch -- $tagName { Test { } default { incr ::element } } } proc EStop tagname { } test pcdata-1.1 {Simple PCDATA} { set ::result {} set ::element 0 set ::pcdataCounter 0 catch {rename xml::pcdata-1.1 {}} set parser [xml::parser xml::pcdata-1.1 \ -elementstartcommand Estart \ -elementendcommand EStop \ -characterdatacommand pcdata] $parser parse { This is PCDATA } list $::result $::element } {{This is PCDATA} 0} test pcdata-1.2 {PCDATA section with Tcl specials} { set ::result {} set ::element 0 set ::pcdataCounter 0 catch {rename xml::pcdata-1.2 {}} set parser [xml::parser xml::pcdata-1.2 \ -elementstartcommand Estart \ -elementendcommand EStop \ -characterdatacommand pcdata] $parser parse { Dollar $ backslash \ square brackets [ ] braces { } } list $::result $::element } {{Dollar $ backslash \ square brackets [ ] braces { }} 0} # Requested by Marshall Rose, 20/3/1999 test pcdata-1.3 {PCDATA with no entity expansion} { set ::result {} set ::element 0 set ::pcdataCounter 0 catch {rename xml::pcdata-1.3 {}} set parser [xml::parser xml::pcdata-1.3 \ -elementstartcommand Estart \ -elementendcommand EStop \ -characterdatacommand pcdata] $parser parse { This is <PCDATA> } list $::result $::pcdataCounter } {{This is } 1} test pcdata-1.4 {keep all PCDATA for not white space only PCDATA content} { set ::result {} catch {rename xml::pcdata-1.4 {}} set parser [xml::parser xml::pcdata-1.4 \ -characterdatacommand pcdata \ -ignorewhitecdata 1] $parser parse { some content } set ::result } { some content } foreach parser [info commands pcdata-*] { $parser free } # cleanup ::tcltest::cleanupTests return tdom-0.9.6-src/tests/entity.test0000644000175000017500000001014215025767703015335 0ustar rolfrolf# Features covered: Entities # # This file contains a collection of tests for the different kinds of # entities. # # entity-1.*: parameter entities, character entities # entity-2.*: predefined entities # entity-3.*: -useForeignDTD # entity-4.*: external parsed entities # # Copyright (c) 1999-2000 Zveno Pty Ltd. # Copyright (c) 2000-2004 Rolf Ade # # $Id$ source [file join [file dir [info script]] loadtdom.tcl] proc Start {name attrList args} { incr ::elements } proc pcdata text { append ::result $text } proc EntityRef name { lappend ::references $name append ::result ##entityreference## return {} } test entity-1.1 {parameter entity in document entity} { set ::result {} catch {rename xml::entity-1.1 {}} set parser [xml::parser entity-1.1 \ -characterdatacommand pcdata] $parser parse { ]> %wrong;} set ::result } {%wrong;} test entity-1.2 {character entities in hex} { set ::result {} catch {rename xml::entity-1.2 {}} set parser [xml::parser entity-1.2 \ -characterdatacommand pcdata] $parser parse {A<>$[]} set ::result } {A<>$[]} test entity-1.3 {character entities in decimal} { set ::result {} catch {rename xml::entity-1.3 {}} set parser [xml::parser entity-1.3 \ -characterdatacommand pcdata] $parser parse {A<>$[]} set ::result } {A<>$[]} test entity-1.4 {illegal character entity} { set ::result {} catch {rename xml::entity-1.4 {}} set parser [xml::parser entity-1.4 \ -characterdatacommand pcdata] set err [catch {$parser parse {&#blah;}}] list $err $::result } {1 {}} test entity-2.1 {predefined general entities} { set ::result {} catch {rename xml::entity-2.1 {}} set parser [xml::parser entity-2.1 \ -characterdatacommand pcdata] $parser parse {<>&"'} set ::result } {<>&"'} # emacs: " proc extrefhandler-3 {base args} { global extrefhandlerCalled set extrefhandlerCalled 1 return [list string $base ""] } test entity-3.1 {-useForeignDTD} { set ::extrefhandlerCalled 0 set parser [expat -useForeignDTD 0 \ -externalentitycommand extrefhandler-3 \ -paramentityparsing notstandalone] $parser parse $parser free set ::extrefhandlerCalled } {0} test entity-3.2 {-useForeignDTD} { set ::extrefhandlerCalled 0 set parser [expat -useForeignDTD 1 \ -externalentitycommand extrefhandler-3 \ -paramentityparsing notstandalone] $parser parse $parser free set ::extrefhandlerCalled } {1} test entity-3.3 {-useForeignDTD} { set ::extrefhandlerCalled 0 set parser [expat -useForeignDTD 1 \ -externalentitycommand extrefhandler-3 \ -paramentityparsing notstandalone] $parser parse { ]> } $parser free set ::extrefhandlerCalled } {1} test entity-3.4 {cget -useForeignDTD} { set parser [expat entity-4.4 -useForeignDTD 1] $parser cget -useForeignDTD } 1 proc extrefhandler-4 {args} { global notexistendpath # Search for a not existing file path set base /ae124 set filename 0 set path [file join $base $filename] while {[file exists $path]} { incr filename set path [file join $base $filename] } set notexistendpath $path return [list filename $path $path] } test entity-4.1 {external entity: returned filename dose not exist} -body { set parser [expat -useForeignDTD 1 \ -externalentitycommand extrefhandler-4 \ -paramentityparsing always] set result [catch {$parser parse } errMsg] append result " $errMsg" $parser free set result } -match glob -result {1 error opening file "/ae124/*"} foreach parser [info commands entity-*] { $parser free } # cleanup ::tcltest::cleanupTests return tdom-0.9.6-src/tests/parser.test0000644000175000017500000006714515025767703015334 0ustar rolfrolf# Features covered: Parser functions # # This file tests the parser's basic functions. # # parser-1.*: parser creation # parser-2.*: return code 'break' from callback # parser-3.*: return code 'continue' from callback # parser-4.*: return code 'error' from callback # parser-5.*: parse input from channel # parser-6.*: reuse parser # parser-7.*: parser reset # parser-8.*: parser free # parser-9.*: parser parse # parser-10.*: return code 'return' from callback # parser-11.*: parser input from filename # parser-12.*: parser currentmarkup # parser-13.*: getline/column/byteindex # # Copyright (c) 1999-2000 Zveno Pty Ltd. # Copyright (c) 2002-2024 Rolf Ade # # $Id$ source [file join [file dir [info script]] loadtdom.tcl] proc parray arrayName { upvar #0 $arrayName arr foreach key [lsort [array names $arrayName]] { lappend result $key $arr($key) } return $result } catch {unset count} proc Count {args} { if {![info exists ::count]} { set ::count 1 } else { incr ::count } } catch {unset started} proc Start {name atList args} { array set opts $args array set atts $atList if {![info exists ::started($name)]} { set ::started($name) 1 } else { incr ::started($name) } if {[info exists atts(class)]} { switch $atts(class) { continue { return -code continue } break { return -code break } error { return -code error "error condition in callback" } return { return -code return } default { return -code $atts(class) } } } } catch {unset ended} proc End {name args} { array set opts $args if {![info exists ::ended($name)]} { set ::ended($name) 1 } else { incr ::ended($name) } } proc PI {name args} { return -code $name } catch {unset elList} proc ElStart {name atList args} { array set opts {-empty 0} array set opts $args lappend ::elList start $name $opts(-empty) } proc ElEnd {name args} { array set opts {-empty 0} array set opts $args lappend ::elList end $name $opts(-empty) } test parser-1.1 {parser creation} { set p [::xml::parser] regexp {^xmlparser[0-9]+$} $p } 1 test parser-1.2 {parser creation, only options} { set p [::xml::parser -elementstartcommand Start] regexp {^xmlparser[0-9]+$} $p } 1 test parser-1.3 {parser creation, named} { catch {rename parser-1.3 {}} ::xml::parser parser-1.3 } parser-1.3 test parser-1.4 {parser creation, named with options} { catch {rename parser-1.4 {}} ::xml::parser parser-1.4 -elementstartcommand Start } parser-1.4 test parser-1.5 {parser freeing, wrong nr of args} { set p [expat] if {[set result [catch {$p free wrongarg}]]} { $p free } set result } 1 test parser-1.6 {parser create syntax check} { set result [catch {set parser [expat -paramentityparsing wrong]} errMsg] lappend result $errMsg } {1 {bad value "wrong": must be always, never, or notstandalone}} test parser-1.7 {parser cget syntax} { catch {rename parser-1.7 {}} set parser [expat parser-1.7] set result [catch {$parser cget} errMsg] lappend result $errMsg } {1 {wrong # args: should be "parser-1.7 cget ?-handlerset handlersetname? switch"}} test parser-1.8 {parser cget syntax} { catch {rename parser-1.8 {}} set parser [expat parser-1.8] set result [catch {$parser cget -handlerset -final} errMsg] lappend result $errMsg } {1 {wrong # args: should be "?-handlerset handlersetname? switch"}} test parser-1.9 {parser cget syntax} { catch {rename parser-1.9 {}} set parser [expat parser-1.9] set result [catch {$parser cget -handlerset dontexist -baseurl} errMsg] lappend result $errMsg } {1 {invalid handlerset name: dontexist}} test parser-1.10 {parser cget syntax} { catch {rename parser-1.10 {}} set parser [expat parser-1.10] set result [$parser cget -handlerset default -baseurl] } {} test parser-1.11 {parser cget syntax} { catch {rename parser-1.11 {}} set parser [expat parser-1.11 -baseurl http://foo.org/] set result [$parser cget -handlerset default -baseurl] } {http://foo.org/} test parser-1.12 {parser cget} { catch {rename parser-1.12 {}} set parser [expat parser-1.12] set result [$parser cget -baseurl] } {} proc esh_1_13_1 {args} { incr ::esh_1_13_1 } proc esh_1_13_2 {args} { incr ::esh_1_13_2 } test parser-1.13 {parser configure} { set ::esh_1_13_1 0 set ::esh_1_13_2 0 catch {rename parser-1.13 {}} set p [expat parser-1.13 -elementstartcommand esh_1_13_1] $p configure -elementstartcommand esh_1_13_2 $p parse {
} list $::esh_1_13_1 $::esh_1_13_2 } {0 3} test parser-1.14 {parser get} { catch {rename parser-1.14 {}} set parser [expat parser-1.14] set result [catch {$parser get}] $parser free set result } {1} test parser-1.15 {parser get} { catch {rename parser-1.15 {}} set parser [expat parser-1.15] set result [catch {$parser get foo bar}] $parser free set result } {1} test parser-1.16 {parser get} { catch {rename parser-1.16 {}} set parser [expat parser-1.16] set result [$parser get -currentbytecount] $parser free set result } {0} test parser-1.17 {parser delete} { expat parser-1.17 parser-1.17 delete } {} proc cdh-1.18 {data} { if {[string trim $data] ne ""} { append ::result "cdh:$data" } } proc dh-1.18 {data} { if {[string trim $data] ne ""} { append ::result "dh:$data" } } test parser-1.18 {parser option -noexpand} { catch {rename parser-1.18 {}} set parser [expat parser-1.18] $parser configure \ -noexpand 1 \ -defaultcommand dh-1.18 \ -characterdatacommand cdh-1.18 set result "" $parser parse { ]> foo&xxx;bar} set result } {cdh:foodh:&xxx;cdh:bar} test parser-1.19 {parser option -noexpand} { catch {rename parser-1.19 {}} set parser [expat parser-1.19] $parser configure \ -noexpand 0 \ -defaultcommand dh-1.18 \ -characterdatacommand cdh-1.18 set result "" $parser parse { ]> foo&xxx;bar} set result } {cdh:foothis was the xxx entitybar} test parser-1.20 {parser option -noexpand} { catch {rename parser-1.20 {}} set parser [expat parser-1.20] $parser configure \ -noexpand 1 \ -characterdatacommand cdh-1.18 set result "" $parser parse { ]> foo&xxx;bar} set result } {cdh:foocdh:bar} test parser-1.21 {parser option -noexpand} { catch {rename parser-1.21 {}} set parser [expat parser-1.21] $parser configure \ -noexpand 1 \ -defaultcommand dh-1.18 set result "" $parser parse { ]> foo&xxx;bar} set result } {dh:&xxx;} test parser-1.22 {parser option -noexpand} { catch {rename parser-1.22 {}} set parser [expat parser-1.18] $parser configure \ -noexpand 1 \ -defaultcommand dh-1.18 set result "" $parser parse { ]> foo&xxx;bar} set result } {dh:&xxx;} test parser-1.23 {Unknown option flag} { catch {rename xml::parser-1.23 {}} catch { set parser [xml::parser parser-1.23 \ -elementstartcommand EStart \ -boo] } } 1 test parser-1.24 {Missing option argument} { catch {rename xml::parser-1.24 {}} catch { set parser [xml::parser parser-1.24 \ -elementstartcommand] } } 1 test parser-1.25 {billion laughs attact proctection options} { catch {xml::parser-1.25 delete} xml::parser xml::parser-1.25 set result "" foreach {option value} { -billionLaughsAttackProtectionMaximumAmplification foo -billionLaughsAttackProtectionMaximumAmplification 0 -billionLaughsAttackProtectionMaximumAmplification -2.0 -billionLaughsAttackProtectionMaximumAmplification 23 -billionLaughsAttackProtectionActivationThreshold bar -billionLaughsAttackProtectionActivationThreshold 0 -billionLaughsAttackProtectionActivationThreshold -7 -billionLaughsAttackProtectionActivationThreshold 2000000000 } { lappend result [catch { xml::parser-1.25 configure $option $value }] } xml::parser-1.25 delete set result } {1 1 1 0 1 1 1 0} proc estart-1.26 {name attrs} { lappend ::result "estart-1.26 $name" } proc eend-1.26 {name} { lappend ::result "eend-1.26 $name" } proc cdata-1.26 {cdata} { lappend ::result "cdata-1.26 $cdata" } trace add execution estart-1.26 enter cmdtracer trace add execution eend-1.26 enter cmdtracer trace add execution cdata-1.26 enter cmdtracer proc cmdtracer {args} { lappend ::result "cmdtracer $args" } test parser-1.26 {-fastcall} { catch {xml::parser-1.26} set result "" xml::parser xml::parser-1.26 -final 0 -fastcall 1 xml::parser-1.26 configure -elementstartcommand estart-1.26 \ -elementendcommand eend-1.26 \ -characterdatacommand cdata-1.26 xml::parser-1.26 parse foo xml::parser-1.26 configure -fastcall 0 -final 1 \ -elementstartcommand estart-1.26 \ -elementendcommand eend-1.26 \ -characterdatacommand cdata-1.26 xml::parser-1.26 parse foo
xml::parser-1.26 delete set result } {{estart-1.26 doc} {estart-1.26 a} {cdata-1.26 foo} {eend-1.26 a} {cmdtracer {estart-1.26 a {}} enter} {estart-1.26 a} {cmdtracer {cdata-1.26 foo} enter} {cdata-1.26 foo} {cmdtracer {eend-1.26 a} enter} {eend-1.26 a} {cmdtracer {eend-1.26 doc} enter} {eend-1.26 doc}} test parser-1.26.1 {-fastcall} { catch {xml::parser-1.26} set result "" xml::parser xml::parser-1.26 -final 0 -fastcall 1 xml::parser-1.26 configure -elementstartcommand estart-1.26 \ -elementendcommand eend-1.26 \ -characterdatacommand cdata-1.26 xml::parser-1.26 parse foo xml::parser-1.26 configure -fastcall 0 \ -elementstartcommand estart-1.26 \ -elementendcommand eend-1.26 \ -characterdatacommand cdata-1.26 xml::parser-1.26 parse foo xml::parser-1.26 configure -final 1 xml::parser-1.26 parse "" xml::parser-1.26 delete set result } {{estart-1.26 doc} {estart-1.26 a} {cdata-1.26 foo} {eend-1.26 a} {cmdtracer {estart-1.26 a {}} enter} {estart-1.26 a} {cmdtracer {cdata-1.26 foo} enter} {cdata-1.26 foo} {cmdtracer {eend-1.26 a} enter} {eend-1.26 a} {cmdtracer {eend-1.26 doc} enter} {eend-1.26 doc}} # Test break return code from callback test parser-2.1 {break in callback} { catch {unset ::started} catch {rename parser-2.1 {}} set p [::xml::parser parser-2.1 -elementstartcommand Start] $p parse { Should see this data Should not see this data Should not see this data } set ::started(Element) } 2 test parser-2.2 {break in callback} { catch {unset ::started} catch {rename parser-2.2 {}} set p [::xml::parser parser-2.2 -elementstartcommand Start] $p parse { Should see this data Should see this data Should not see this data } set ::started(Element) } 3 test parser-2.3 {break in callback} { catch {unset ::started} catch {rename parser-2.3 {}} set p [::xml::parser parser-2.3 -elementstartcommand Start] $p parse { Should see this data Should see this data Should not see this data } set ::started(Element) } 3 test parser-3.1 {continue in callback} { catch {unset ::started} catch {rename parser-3.1 {}} set p [::xml::parser parser-3.1 -elementstartcommand Start] $p parse { Should see this data Should not see this data Should see this data } set ::started(Element) } 3 test parser-3.2 {continue in callback} { catch {unset ::started} catch {rename parser-3.2 {}} set p [::xml::parser parser-3.2 -elementstartcommand Start] $p parse { Should see this data Should see this data Should not see this data Should see this data Should see this data } set ::started(Element) } 5 test parser-3.3 {continue in callback} { catch {unset ::started} catch {rename parser-3.3 {}} set p [::xml::parser parser-3.3 -elementstartcommand Start] $p parse { Should see this data Should see this data Should not see this data break will have no effect Should see this data Should see this data } set ::started(Element) } 5 proc esh-3.4 {name attList} { incr ::eshcounter return -code continue } proc eeh-3.4 {name} { incr ::eehcounter } proc cdh-3.4 {data} { incr ::cdhcounter } test parser-3.4 {continue} { set ::eshcounter 0 set ::eehcounter 0 set ::cdhcounter 0 set p [expat -elementstartcommand esh-3.4 -elementendcommand eeh-3.4 \ -characterdatacommand chd-3.4] $p parse {foofoofoo} $p free list $::eshcounter $::eehcounter $::cdhcounter } {1 1 0} proc esh-3.5 {name attList} { incr ::eshcounter2 } proc eeh-3.5 {name} { incr ::eehcounter2 } proc cdh-3.5 {data} { incr ::cdhcounter2 } test parser-3.5 {continue with more than one handlerset} { set ::eshcounter 0 set ::eehcounter 0 set ::cdhcounter 0 set ::eshcounter2 0 set ::eehcounter2 0 set ::cdhcounter2 0 set p [expat -elementstartcommand esh-3.4 -elementendcommand eeh-3.4 \ -characterdatacommand chd-3.4 -handlerset second \ -elementstartcommand esh-3.5 -elementendcommand eeh-3.5 \ -characterdatacommand cdh-3.5] $p parse {foofoofoo} $p free list $::eshcounter $::eehcounter $::cdhcounter \ $::eshcounter2 $::eehcounter2 $::cdhcounter2 } {1 1 0 5 5 3} test parser-4.1 {error in callback} { catch {unset ::started} catch {rename parser-4.1 {}} set p [::xml::parser parser-4.1 -elementstartcommand Start] set errcode [catch {$p parse { Should see this data Should not see this data }} result] list $errcode $::started(Element) } {1 2} test parser-4.2 {error in callback} { catch {unset ::started} catch {rename parser-4.2 {}} set p [::xml::parser parser-4.2 -elementstartcommand Start] set errcode [catch {$p parse { Should see this data Should not see this data }} result] list $::errcode $::started(Element) } {13 2} test parser-5.1 {parse channel input} { catch {unset ::count} catch {rename parser-5.1 {}} set parser [::xml::parser parser-5.1 -elementstartcommand Count] set fd [open [file join [pwd] [file dir [info script]] data/books.xml]] $parser parsechannel $fd close $fd list $::count } {42} proc elementstart {args} { global parser if {![info exists ::count]} { set ::count 1 } else { incr ::count } set fd [open [file join [pwd] [file dir [info script]] data/books.xml]] catch {$parser parsechannel $fd} close $fd } test parser-5.2 {parse channel input with catched try to recursive parsing} { catch {unset ::count} catch {rename parser-5.2 {}} set parser [::xml::parser parser-5.2 -elementstartcommand elementstart] set fd [open [file join [pwd] [file dir [info script]] data/books.xml]] $parser parsechannel $fd close $fd list $::count } {42} test parser-5.3 {parse channel - xml wrong} -setup { set xmlFile [makeFile {} parser.xml] } -body { set fd [open $xmlFile] catch {rename parser-5.3 {}} set parser [::xml::parser parser-5.3 -elementstartcommand elementstart] set result [catch {$parser parsechannel $fd}] close $fd set result } -cleanup { removeFile parser.xml } -result 1 proc elementstart-5.4 {args} { error "Error raised by elementstart-5.4" } test parser-5.4 {parse channel - error raised in handler} { catch {parser-5.4 free} ::xml::parser parser-5.4 -elementstartcommand elementstart-5.4 set file [file join [pwd] [file dir [info script]] data/books.xml] catch {parser-5.4 parsefile $file} errMsg parser-5.4 free set errMsg } "Error raised by elementstart-5.4" test parser-6.1 {reuse parser} { catch {rename parser-6.1 {}} set parser [expat parser-6.1 -baseurl file:///foo/bar] set result [$parser cget -baseurl] $parser parse lappend result [$parser cget -baseurl] $parser configure -baseurl file:///bar/foo lappend result [$parser cget -baseurl] $parser parse lappend result [$parser cget -baseurl] set result } {file:///foo/bar {} file:///bar/foo {}} proc elementstart {args} { global parser $parser reset } test parser-7.1 {parser reset called from within callback proc} { set parser [expat -elementstartcommand elementstart] set result [catch {$parser parse foo} errMsg] lappend result $errMsg $parser free set result } {1 {parser reset not allowed from within callback}} test parser-7.2 {parser reset} { set parser [expat -final 0] $parser parse "" $parser free set result } {1 {} 0 0} proc elementstart {args} { global parser $parser free } test parser-8.1 {parser free called from within callback proc} { set parser [expat -elementstartcommand elementstart] set result [catch {$parser parse foo} errMsg] lappend result $errMsg $parser free set result } {1 {parser delete not allowed from within callback}} proc elementstart {args} { global parser $parser parse {foo bar} } test parser-9.1 {try to use the parser from within one of its callbacks} { set parser [expat -elementstartcommand elementstart] set result [catch {$parser parse foo} errMsg] lappend result $errMsg $parser free set result } {1 {Parser already in use.}} proc calledFromElementstart {args} { global parser $parser parse {foo bar} } proc elementstart {args} { calledFromElementstart } test parser-9.2 {try to use the parser from within one of its callbacks} { set parser [expat -elementstartcommand elementstart] set result [catch {$parser parse foo} errMsg] lappend result $errMsg $parser free set result } {1 {Parser already in use.}} test parser-10.1 {return -code return in callback} { catch {unset ::started} catch {rename parser-10.1 {}} set p [::xml::parser parser-10.1 -elementstartcommand Start] set errcode [catch {$p parse { Should see this data Should not see this data }} result] list $errcode $::started(Element) } {0 2} test parser-10.2 {return -code return in callback} { catch {unset ::started} catch {rename parser-10.2 {}} set p [::xml::parser parser-10.2 -elementstartcommand Start] set errcode [catch {$p parse { Should see this data Should not see this data }} errMsg] set result [list $errcode $::started(Element)] $p reset catch {unset ::started} set errcode [catch {$p parse { Should see this data Should see this data }} errMsg] lappend result $errcode $::started(Element) } {0 2 0 3} test parser-11.1 {parse parsefile} { catch {unset ::count} catch {rename parser-11.1 {}} set parser [::xml::parser parser-11.1 -elementstartcommand Count] set file [file join [pwd] [file dir [info script]] data/books.xml] $parser parsefile $file set ::count } {42} proc elementstart-11.2 {args} { error "Error raised by elementstart-11.2" } test parser-11.2 {parse parsefile - error raised in handler} { catch {parser-11.2 free} ::xml::parser parser-11.2 -elementstartcommand elementstart-11.2 set file [file join [pwd] [file dir [info script]] data/books.xml] catch {parser-11.2 parsefile $file} errMsg parser-11.2 free set errMsg } "Error raised by elementstart-11.2" proc elementstart-12.1 {parser args} { global result append result [$parser currentmarkup] } proc elementend-12.1 {parser args} { global result append result [$parser currentmarkup] } test parser-12.1 {currentmarkup method} { catch {unset result} set result "" set p [expat parser-12.1] $p configure \ -elementstartcommand [list elementstart-12.1 $p] \ -elementendcommand [list elementend-12.1 $p] $p parse {textmore text} $p free set result } {} proc characterdata-12.2 {parser data} { global result append result [$parser currentmarkup] } test parser-12.2 {currentmarkup method} { catch {unset result} set result "" set p [expat parser-12.2] $p configure \ -characterdatacommand [list characterdata-12.2 $p] $p parse {textmore text} $p free set result } {} test parser-12.3 {currentmarkup method} { set p [expat parser-12.3] set result [$p currentmarkup] $p free set result } {} proc elementstart-12.4 {parser handlerset args} { global result append result "$handlerset: [$parser currentmarkup]\n" } proc elementend-12.4 {parser handlerset args} { global result append result "$handlerset: [$parser currentmarkup]\n" } test parser-12.4 {currentmarkup method - multiple handler set} { catch {unset result} set result "" set p [expat parser-12.4] $p configure \ -elementstartcommand [list elementstart-12.4 $p default] \ -elementendcommand [list elementend-12.4 $p default] \ -handlerset "additional" \ -elementstartcommand [list elementstart-12.4 $p "additional"] \ -elementendcommand [list elementend-12.4 $p "additional"] $p parse {textmore text} $p free set result } {default: additional: default: additional: default: additional: default: additional: default: additional: default: additional: } proc elementstart-12.5 {parser args} { global result append result "[$parser currentmarkup]" } test parser-12.5 {currentmarkup method - empty element shortcut -elementstartcommand} { catch {unset result} set result "" set p [expat parser-12.5] $p configure \ -elementstartcommand [list elementstart-12.5 $p] $p parse {} $p free set result } {} proc elementend-12.6 {parser args} { global result if {[$parser currentmarkup] eq ""} { append result "" } append result "[$parser currentmarkup]" } test parser-12.6 {currentmarkup method - empty element shortcut -elementendcommand} { catch {unset result} set result "" set p [expat parser-12.6] $p configure \ -elementendcommand [list elementend-12.6 $p] $p parse {} $p free set result } {} foreach parser [info commands xmlparser*] { $parser free } foreach parser [info commands parser-*] { $parser free } proc elementdeclcommand-12.7 {parser args} { global result append result "elementdeclcommand: [$parser currentmarkup]" } proc entitydeclcommand-12.7 {parser args} { global result append result "entitydeclcommand: [$parser currentmarkup]" } test parser-12.7 {currentmarkup method - not for doctype markup handler} { catch {unset result} set result "" set p [expat parser-12.7] $p configure \ -elementdeclcommand [list elementdeclcommand-12.7 $p] \ -entitydeclcommand [list entitydeclcommand-12.7 $p] $p parse { ' > %xx; ]> This sample shows a &tricky; method.} $p free set result } {elementdeclcommand: entitydeclcommand: entitydeclcommand: } proc pi-12.8 {parser args} { global result append result "pi: [$parser currentmarkup]" } test parser-12.8 {currentmarkup method - processing instruction} { catch {unset result} set result "" set p [expat parser-12.8] $p configure \ -processinginstructioncommand [list pi-12.8 $p] $p parse {} $p free set result } {pi: } proc comment-12.9 {parser args} { global result append result "comment: [$parser currentmarkup]" } test parser-12.9 {currentmarkup method - comment} { catch {unset result} set result "" set p [expat parser-12.9] $p configure \ -commentcommand [list comment-12.9 $p] $p parse {} $p free set result } {comment: } proc gethdl-13 {p args} { global result append result "/[$p get -currentlinenumber].[$p get -currentcolumnnumber]/" } test parser-13.1 {get -current*} { catch {unset result} set result "" set p [expat parser-13.1] $p configure \ -elementstartcommand [list gethdl-13 $p] $p parse { } $p free set result } /1.0//2.8//2.12/ test parser-13.2 {get -current*} { catch {unset result} set result "" set p [expat parser-13.2 -keepTextStart 1] $p configure \ -characterdatacommand [list gethdl-13 $p] $p parse { Hello} $p free set result } /1.6/ # cleanup ::tcltest::cleanupTests return tdom-0.9.6-src/tests/data/0000755000175000017500000000000015025767703014033 5ustar rolfrolftdom-0.9.6-src/tests/data/domCmd1.dtd0000644000175000017500000000005415025767703016013 0ustar rolfrolf tdom-0.9.6-src/tests/data/dtd-6.4.dtd0000644000175000017500000000015215025767703015606 0ustar rolfrolf ]]> ]]> tdom-0.9.6-src/tests/data/xmlspec-v20.dtd0000644000175000017500000014575615025767703016632 0ustar rolfrolf tdom-0.9.6-src/tests/data/REC-xslt-19991116-mod.xml0000644000175000017500000074342615025767703017675 0ustar rolfrolf ]>
XSL Transformations (XSLT) Version 1.0 &LEV;-xslt-&YYYYMMDD; W3C Recommendation &day;&month;&year; http://www.w3.org/TR/&year;/&LEV;-xslt-&YYYYMMDD; XML HTML http://www.w3.org/TR/xslt http://www.w3.org/TR/1999/PR-xslt-19991008 http://www.w3.org/1999/08/WD-xslt-19990813 http://www.w3.org/1999/07/WD-xslt-19990709 http://www.w3.org/TR/1999/WD-xslt-19990421 http://www.w3.org/TR/1998/WD-xsl-19981216 http://www.w3.org/TR/1998/WD-xsl-19980818 James Clark jjc@jclark.com

This document has been reviewed by W3C Members and other interested parties and has been endorsed by the Director as a W3C Recommendation. It is a stable document and may be used as reference material or cited as a normative reference from other documents. W3C's role in making the Recommendation is to draw attention to the specification and to promote its widespread deployment. This enhances the functionality and interoperability of the Web.

The list of known errors in this specification is available at http://www.w3.org/&year;/&MM;/&LEV;-xslt-&YYYYMMDD;-errata.

Comments on this specification may be sent to xsl-editors@w3.org; archives of the comments are available. Public discussion of XSL, including XSL Transformations, takes place on the XSL-List mailing list.

The English version of this specification is the only normative version. However, for translations of this document, see http://www.w3.org/Style/XSL/translations.html.

A list of current W3C Recommendations and other technical documents can be found at http://www.w3.org/TR.

This specification has been produced as part of the W3C Style activity.

This specification defines the syntax and semantics of XSLT, which is a language for transforming XML documents into other XML documents.

XSLT is designed for use as part of XSL, which is a stylesheet language for XML. In addition to XSLT, XSL includes an XML vocabulary for specifying formatting. XSL specifies the styling of an XML document by using XSLT to describe how the document is transformed into another XML document that uses the formatting vocabulary.

XSLT is also designed to be used independently of XSL. However, XSLT is not intended as a completely general-purpose XML transformation language. Rather it is designed primarily for the kinds of transformations that are needed when XSLT is used as part of XSL.

English EBNF See RCS log for revision history.
Introduction

This specification defines the syntax and semantics of the XSLT language. A transformation in the XSLT language is expressed as a well-formed XML document conforming to the Namespaces in XML Recommendation , which may include both elements that are defined by XSLT and elements that are not defined by XSLT. XSLT-defined elements are distinguished by belonging to a specific XML namespace (see ), which is referred to in this specification as the XSLT namespace. Thus this specification is a definition of the syntax and semantics of the XSLT namespace.

A transformation expressed in XSLT describes rules for transforming a source tree into a result tree. The transformation is achieved by associating patterns with templates. A pattern is matched against elements in the source tree. A template is instantiated to create part of the result tree. The result tree is separate from the source tree. The structure of the result tree can be completely different from the structure of the source tree. In constructing the result tree, elements from the source tree can be filtered and reordered, and arbitrary structure can be added.

A transformation expressed in XSLT is called a stylesheet. This is because, in the case when XSLT is transforming into the XSL formatting vocabulary, the transformation functions as a stylesheet.

This document does not specify how an XSLT stylesheet is associated with an XML document. It is recommended that XSL processors support the mechanism described in . When this or any other mechanism yields a sequence of more than one XSLT stylesheet to be applied simultaneously to a XML document, then the effect should be the same as applying a single stylesheet that imports each member of the sequence in order (see ).

A stylesheet contains a set of template rules. A template rule has two parts: a pattern which is matched against nodes in the source tree and a template which can be instantiated to form part of the result tree. This allows a stylesheet to be applicable to a wide class of documents that have similar source tree structures.

A template is instantiated for a particular source element to create part of the result tree. A template can contain elements that specify literal result element structure. A template can also contain elements from the XSLT namespace that are instructions for creating result tree fragments. When a template is instantiated, each instruction is executed and replaced by the result tree fragment that it creates. Instructions can select and process descendant source elements. Processing a descendant element creates a result tree fragment by finding the applicable template rule and instantiating its template. Note that elements are only processed when they have been selected by the execution of an instruction. The result tree is constructed by finding the template rule for the root node and instantiating its template.

In the process of finding the applicable template rule, more than one template rule may have a pattern that matches a given element. However, only one template rule will be applied. The method for deciding which template rule to apply is described in .

A single template by itself has considerable power: it can create structures of arbitrary complexity; it can pull string values out of arbitrary locations in the source tree; it can generate structures that are repeated according to the occurrence of elements in the source tree. For simple transformations where the structure of the result tree is independent of the structure of the source tree, a stylesheet can often consist of only a single template, which functions as a template for the complete result tree. Transformations on XML documents that represent data are often of this kind (see ). XSLT allows a simplified syntax for such stylesheets (see ).

When a template is instantiated, it is always instantiated with respect to a current node and a current node list. The current node is always a member of the current node list. Many operations in XSLT are relative to the current node. Only a few instructions change the current node list or the current node (see and ); during the instantiation of one of these instructions, the current node list changes to a new list of nodes and each member of this new list becomes the current node in turn; after the instantiation of the instruction is complete, the current node and current node list revert to what they were before the instruction was instantiated.

XSLT makes use of the expression language defined by for selecting elements for processing, for conditional processing and for generating text.

XSLT provides two hooks for extending the language, one hook for extending the set of instruction elements used in templates and one hook for extending the set of functions used in XPath expressions. These hooks are both based on XML namespaces. This version of XSLT does not define a mechanism for implementing the hooks. See .

The XSL WG intends to define such a mechanism in a future version of this specification or in a separate specification.

The element syntax summary notation used to describe the syntax of XSLT-defined elements is described in .

The MIME media types text/xml and application/xml should be used for XSLT stylesheets. It is possible that a media type will be registered specifically for XSLT stylesheets; if and when it is, that media type may also be used.

Stylesheet Structure XSLT Namespace

The XSLT namespace has the URI &XSLT.ns;.

The 1999 in the URI indicates the year in which the URI was allocated by the W3C. It does not indicate the version of XSLT being used, which is specified by attributes (see and ).

XSLT processors must use the XML namespaces mechanism to recognize elements and attributes from this namespace. Elements from the XSLT namespace are recognized only in the stylesheet not in the source document. The complete list of XSLT-defined elements is specified in . Vendors must not extend the XSLT namespace with additional elements or attributes. Instead, any extension must be in a separate namespace. Any namespace that is used for additional instruction elements must be identified by means of the extension element mechanism specified in .

This specification uses a prefix of xsl: for referring to elements in the XSLT namespace. However, XSLT stylesheets are free to use any prefix, provided that there is a namespace declaration that binds the prefix to the URI of the XSLT namespace.

An element from the XSLT namespace may have any attribute not from the XSLT namespace, provided that the expanded-name of the attribute has a non-null namespace URI. The presence of such attributes must not change the behavior of XSLT elements and functions defined in this document. Thus, an XSLT processor is always free to ignore such attributes, and must ignore such attributes without giving an error if it does not recognize the namespace URI. Such attributes can provide, for example, unique identifiers, optimization hints, or documentation.

It is an error for an element from the XSLT namespace to have attributes with expanded-names that have null namespace URIs (i.e. attributes with unprefixed names) other than attributes defined for the element in this document.

The conventions used for the names of XSLT elements, attributes and functions are that names are all lower-case, use hyphens to separate words, and use abbreviations only if they already appear in the syntax of a related language such as XML or HTML.

Stylesheet Element

A stylesheet is represented by an xsl:stylesheet element in an XML document. xsl:transform is allowed as a synonym for xsl:stylesheet.

An xsl:stylesheet element must have a version attribute, indicating the version of XSLT that the stylesheet requires. For this version of XSLT, the value should be 1.0. When the value is not equal to 1.0, forwards-compatible processing mode is enabled (see ).

The xsl:stylesheet element may contain the following types of elements:

xsl:import

xsl:include

xsl:strip-space

xsl:preserve-space

xsl:output

xsl:key

xsl:decimal-format

xsl:namespace-alias

xsl:attribute-set

xsl:variable

xsl:param

xsl:template

An element occurring as a child of an xsl:stylesheet element is called a top-level element.

This example shows the structure of a stylesheet. Ellipses (...) indicate where attribute values or content have been omitted. Although this example shows one of each type of allowed element, stylesheets may contain zero or more of each of these elements.

<xsl:stylesheet version="1.0" xmlns:xsl="&XSLT.ns;"> ... ... ... ... ...
]]>

The order in which the children of the xsl:stylesheet element occur is not significant except for xsl:import elements and for error recovery. Users are free to order the elements as they prefer, and stylesheet creation tools need not provide control over the order in which the elements occur.

In addition, the xsl:stylesheet element may contain any element not from the XSLT namespace, provided that the expanded-name of the element has a non-null namespace URI. The presence of such top-level elements must not change the behavior of XSLT elements and functions defined in this document; for example, it would not be permitted for such a top-level element to specify that xsl:apply-templates was to use different rules to resolve conflicts. Thus, an XSLT processor is always free to ignore such top-level elements, and must ignore a top-level element without giving an error if it does not recognize the namespace URI. Such elements can provide, for example,

information used by extension elements or extension functions (see ),

information about what to do with the result tree,

information about how to obtain the source tree,

metadata about the stylesheet,

structured documentation for the stylesheet.

Literal Result Element as Stylesheet

A simplified syntax is allowed for stylesheets that consist of only a single template for the root node. The stylesheet may consist of just a literal result element (see ). Such a stylesheet is equivalent to a stylesheet with an xsl:stylesheet element containing a template rule containing the literal result element; the template rule has a match pattern of /. For example

<html xsl:version="1.0" xmlns:xsl="&XSLT.ns;" xmlns="&XHTML.ns;"> Expense Report Summary

Total Amount:

]]>

has the same meaning as

<xsl:stylesheet version="1.0" xmlns:xsl="&XSLT.ns;" xmlns="&XHTML.ns;"> Expense Report Summary

Total Amount:

]]>

A literal result element that is the document element of a stylesheet must have an xsl:version attribute, which indicates the version of XSLT that the stylesheet requires. For this version of XSLT, the value should be 1.0; the value must be a Number. Other literal result elements may also have an xsl:version attribute. When the xsl:version attribute is not equal to 1.0, forwards-compatible processing mode is enabled (see ).

The allowed content of a literal result element when used as a stylesheet is no different from when it occurs within a stylesheet. Thus, a literal result element used as a stylesheet cannot contain top-level elements.

In some situations, the only way that a system can recognize that an XML document needs to be processed by an XSLT processor as an XSLT stylesheet is by examining the XML document itself. Using the simplified syntax makes this harder.

For example, another XML language (AXL) might also use an axl:version on the document element to indicate that an XML document was an AXL document that required processing by an AXL processor; if a document had both an axl:version attribute and an xsl:version attribute, it would be unclear whether the document should be processed by an XSLT processor or an AXL processor.

Therefore, the simplified syntax should not be used for XSLT stylesheets that may be used in such a situation. This situation can, for example, arise when an XSLT stylesheet is transmitted as a message with a MIME media type of text/xml or application/xml to a recipient that will use the MIME media type to determine how the message is processed.

Qualified Names

The name of an internal XSLT object, specifically a named template (see ), a mode (see ), an attribute set (see ), a key (see ), a decimal-format (see ), a variable or a parameter (see ) is specified as a QName. If it has a prefix, then the prefix is expanded into a URI reference using the namespace declarations in effect on the attribute in which the name occurs. The expanded-name consisting of the local part of the name and the possibly null URI reference is used as the name of the object. The default namespace is not used for unprefixed names.

Forwards-Compatible Processing

An element enables forwards-compatible mode for itself, its attributes, its descendants and their attributes if either it is an xsl:stylesheet element whose version attribute is not equal to 1.0, or it is a literal result element that has an xsl:version attribute whose value is not equal to 1.0, or it is a literal result element that does not have an xsl:version attribute and that is the document element of a stylesheet using the simplified syntax (see ). A literal result element that has an xsl:version attribute whose value is equal to 1.0 disables forwards-compatible mode for itself, its attributes, its descendants and their attributes.

If an element is processed in forwards-compatible mode, then:

if it is a top-level element and XSLT 1.0 does not allow such elements as top-level elements, then the element must be ignored along with its content;

if it is an element in a template and XSLT 1.0 does not allow such elements to occur in templates, then if the element is not instantiated, an error must not be signaled, and if the element is instantiated, the XSLT must perform fallback for the element as specified in ;

if the element has an attribute that XSLT 1.0 does not allow the element to have or if the element has an optional attribute with a value that the XSLT 1.0 does not allow the attribute to have, then the attribute must be ignored.

Thus, any XSLT 1.0 processor must be able to process the following stylesheet without error, although the stylesheet includes elements from the XSLT namespace that are not defined in this specification:

<xsl:stylesheet version="1.1" xmlns:xsl="&XSLT.ns;"> XSLT 1.1 required

Sorry, this stylesheet requires XSLT 1.1.

]]>

If a stylesheet depends crucially on a top-level element introduced by a version of XSL after 1.0, then the stylesheet can use an xsl:message element with terminate="yes" (see ) to ensure that XSLT processors implementing earlier versions of XSL will not silently ignore the top-level element. For example,

<xsl:stylesheet version="1.5" xmlns:xsl="&XSLT.ns;"> Sorry, this stylesheet requires XSLT 1.1. ... ... ]]>

If an expression occurs in an attribute that is processed in forwards-compatible mode, then an XSLT processor must recover from errors in the expression as follows:

if the expression does not match the syntax allowed by the XPath grammar, then an error must not be signaled unless the expression is actually evaluated;

if the expression calls a function with an unprefixed name that is not part of the XSLT library, then an error must not be signaled unless the function is actually called;

if the expression calls a function with a number of arguments that XSLT does not allow or with arguments of types that XSLT does not allow, then an error must not be signaled unless the function is actually called.

Combining Stylesheets

XSLT provides two mechanisms to combine stylesheets:

an inclusion mechanism that allows stylesheets to be combined without changing the semantics of the stylesheets being combined, and an import mechanism that allows stylesheets to override each other. Stylesheet Inclusion

An XSLT stylesheet may include another XSLT stylesheet using an xsl:include element. The xsl:include element has an href attribute whose value is a URI reference identifying the stylesheet to be included. A relative URI is resolved relative to the base URI of the xsl:include element (see ).

The xsl:include element is only allowed as a top-level element.

The inclusion works at the XML tree level. The resource located by the href attribute value is parsed as an XML document, and the children of the xsl:stylesheet element in this document replace the xsl:include element in the including document. The fact that template rules or definitions are included does not affect the way they are processed.

The included stylesheet may use the simplified syntax described in . The included stylesheet is treated the same as the equivalent xsl:stylesheet element.

It is an error if a stylesheet directly or indirectly includes itself.

Including a stylesheet multiple times can cause errors because of duplicate definitions. Such multiple inclusions are less obvious when they are indirect. For example, if stylesheet B includes stylesheet A, stylesheet C includes stylesheet A, and stylesheet D includes both stylesheet B and stylesheet C, then A will be included indirectly by D twice. If all of B, C and D are used as independent stylesheets, then the error can be avoided by separating everything in B other than the inclusion of A into a separate stylesheet B' and changing B to contain just inclusions of B' and A, similarly for C, and then changing D to include A, B', C'.

Stylesheet Import

An XSLT stylesheet may import another XSLT stylesheet using an xsl:import element. Importing a stylesheet is the same as including it (see ) except that definitions and template rules in the importing stylesheet take precedence over template rules and definitions in the imported stylesheet; this is described in more detail below. The xsl:import element has an href attribute whose value is a URI reference identifying the stylesheet to be imported. A relative URI is resolved relative to the base URI of the xsl:import element (see ).

The xsl:import element is only allowed as a top-level element. The xsl:import element children must precede all other element children of an xsl:stylesheet element, including any xsl:include element children. When xsl:include is used to include a stylesheet, any xsl:import elements in the included document are moved up in the including document to after any existing xsl:import elements in the including document.

For example,

<xsl:stylesheet version="1.0" xmlns:xsl="&XSLT.ns;"> italic ]]>

The xsl:stylesheet elements encountered during processing of a stylesheet that contains xsl:import elements are treated as forming an import tree. In the import tree, each xsl:stylesheet element has one import child for each xsl:import element that it contains. Any xsl:include elements are resolved before constructing the import tree. An xsl:stylesheet element in the import tree is defined to have lower import precedence than another xsl:stylesheet element in the import tree if it would be visited before that xsl:stylesheet element in a post-order traversal of the import tree (i.e. a traversal of the import tree in which an xsl:stylesheet element is visited after its import children). Each definition and template rule has import precedence determined by the xsl:stylesheet element that contains it.

For example, suppose

stylesheet A imports stylesheets B and C in that order;

stylesheet B imports stylesheet D;

stylesheet C imports stylesheet E.

Then the order of import precedence (lowest first) is D, B, E, C, A.

Since xsl:import elements are required to occur before any definitions or template rules, an implementation that processes imported stylesheets at the point at which it encounters the xsl:import element will encounter definitions and template rules in increasing order of import precedence.

In general, a definition or template rule with higher import precedence takes precedence over a definition or template rule with lower import precedence. This is defined in detail for each kind of definition and for template rules.

It is an error if a stylesheet directly or indirectly imports itself. Apart from this, the case where a stylesheet with a particular URI is imported in multiple places is not treated specially. The import tree will have a separate xsl:stylesheet for each place that it is imported.

If xsl:apply-imports is used (see ), the behavior may be different from the behavior if the stylesheet had been imported only at the place with the highest import precedence.

Embedding Stylesheets

Normally an XSLT stylesheet is a complete XML document with the xsl:stylesheet element as the document element. However, an XSLT stylesheet may also be embedded in another resource. Two forms of embedding are possible:

the XSLT stylesheet may be textually embedded in a non-XML resource, or the xsl:stylesheet element may occur in an XML document other than as the document element.

To facilitate the second form of embedding, the xsl:stylesheet element is allowed to have an ID attribute that specifies a unique identifier.

In order for such an attribute to be used with the XPath id function, it must actually be declared in the DTD as being an ID.

The following example shows how the xml-stylesheet processing instruction can be used to allow a document to contain its own stylesheet. The URI reference uses a relative URI with a fragment identifier to locate the xsl:stylesheet element:

xmlns:xsl="&XSLT.ns;" xmlns:fo="&XSLFO.ns;"> ... ]]>

A stylesheet that is embedded in the document to which it is to be applied or that may be included or imported into an stylesheet that is so embedded typically needs to contain a template rule that specifies that xsl:stylesheet elements are to be ignored.

Data Model

The data model used by XSLT is the same as that used by XPath with the additions described in this section. XSLT operates on source, result and stylesheet documents using the same data model. Any two XML documents that have the same tree will be treated the same by XSLT.

Processing instructions and comments in the stylesheet are ignored: the stylesheet is treated as if neither processing instruction nodes nor comment nodes were included in the tree that represents the stylesheet.

Root Node Children

The normal restrictions on the children of the root node are relaxed for the result tree. The result tree may have any sequence of nodes as children that would be possible for an element node. In particular, it may have text node children, and any number of element node children. When written out using the XML output method (see ), it is possible that a result tree will not be a well-formed XML document; however, it will always be a well-formed external general parsed entity.

When the source tree is created by parsing a well-formed XML document, the root node of the source tree will automatically satisfy the normal restrictions of having no text node children and exactly one element child. When the source tree is created in some other way, for example by using the DOM, the usual restrictions are relaxed for the source tree as for the result tree.

Base URI

Every node also has an associated URI called its base URI, which is used for resolving attribute values that represent relative URIs into absolute URIs. If an element or processing instruction occurs in an external entity, the base URI of that element or processing instruction is the URI of the external entity; otherwise, the base URI is the base URI of the document. The base URI of the document node is the URI of the document entity. The base URI for a text node, a comment node, an attribute node or a namespace node is the base URI of the parent of the node.

Unparsed Entities

The root node has a mapping that gives the URI for each unparsed entity declared in the document's DTD. The URI is generated from the system identifier and public identifier specified in the entity declaration. The XSLT processor may use the public identifier to generate a URI for the entity instead of the URI specified in the system identifier. If the XSLT processor does not use the public identifier to generate the URI, it must use the system identifier; if the system identifier is a relative URI, it must be resolved into an absolute URI using the URI of the resource containing the entity declaration as the base URI .

Whitespace Stripping

After the tree for a source document or stylesheet document has been constructed, but before it is otherwise processed by XSLT, some text nodes are stripped. A text node is never stripped unless it contains only whitespace characters. Stripping the text node removes the text node from the tree. The stripping process takes as input a set of element names for which whitespace must be preserved. The stripping process is applied to both stylesheets and source documents, but the set of whitespace-preserving element names is determined differently for stylesheets and for source documents.

A text node is preserved if any of the following apply:

The element name of the parent of the text node is in the set of whitespace-preserving element names.

The text node contains at least one non-whitespace character. As in XML, a whitespace character is #x20, #x9, #xD or #xA.

An ancestor element of the text node has an xml:space attribute with a value of preserve, and no closer ancestor element has xml:space with a value of default.

Otherwise, the text node is stripped.

The xml:space attributes are not stripped from the tree.

This implies that if an xml:space attribute is specified on a literal result element, it will be included in the result.

For stylesheets, the set of whitespace-preserving element names consists of just xsl:text.

For source documents, the set of whitespace-preserving element names is specified by xsl:strip-space and xsl:preserve-space top-level elements. These elements each have an elements attribute whose value is a whitespace-separated list of NameTests. Initially, the set of whitespace-preserving element names contains all element names. If an element name matches a NameTest in an xsl:strip-space element, then it is removed from the set of whitespace-preserving element names. If an element name matches a NameTest in an xsl:preserve-space element, then it is added to the set of whitespace-preserving element names. An element matches a NameTest if and only if the NameTest would be true for the element as an XPath node test. Conflicts between matches to xsl:strip-space and xsl:preserve-space elements are resolved the same way as conflicts between template rules (see ). Thus, the applicable match for a particular element name is determined as follows:

First, any match with lower import precedence than another match is ignored.

Next, any match with a NameTest that has a lower default priority than the default priority of the NameTest of another match is ignored.

It is an error if this leaves more than one match. An XSLT processor may signal the error; if it does not signal the error, it must recover by choosing, from amongst the matches that are left, the one that occurs last in the stylesheet.

Expressions

XSLT uses the expression language defined by XPath . Expressions are used in XSLT for a variety of purposes including:

selecting nodes for processing; specifying conditions for different ways of processing a node; generating text to be inserted in the result tree.

An expression must match the XPath production Expr.

Expressions occur as the value of certain attributes on XSLT-defined elements and within curly braces in attribute value templates.

In XSLT, an outermost expression (i.e. an expression that is not part of another expression) gets its context as follows:

the context node comes from the current node

the context position comes from the position of the current node in the current node list; the first position is 1

the context size comes from the size of the current node list

the variable bindings are the bindings in scope on the element which has the attribute in which the expression occurs (see )

the set of namespace declarations are those in scope on the element which has the attribute in which the expression occurs; this includes the implicit declaration of the prefix xml required by the the XML Namespaces Recommendation ; the default namespace (as declared by xmlns) is not part of this set

the function library consists of the core function library together with the additional functions defined in and extension functions as described in ; it is an error for an expression to include a call to any other function

Template Rules Processing Model

A list of source nodes is processed to create a result tree fragment. The result tree is constructed by processing a list containing just the root node. A list of source nodes is processed by appending the result tree structure created by processing each of the members of the list in order. A node is processed by finding all the template rules with patterns that match the node, and choosing the best amongst them; the chosen rule's template is then instantiated with the node as the current node and with the list of source nodes as the current node list. A template typically contains instructions that select an additional list of source nodes for processing. The process of matching, instantiation and selection is continued recursively until no new source nodes are selected for processing.

Implementations are free to process the source document in any way that produces the same result as if it were processed using this processing model.

Patterns

Template rules identify the nodes to which they apply by using a pattern. As well as being used in template rules, patterns are used for numbering (see ) and for declaring keys (see ). A pattern specifies a set of conditions on a node. A node that satisfies the conditions matches the pattern; a node that does not satisfy the conditions does not match the pattern. The syntax for patterns is a subset of the syntax for expressions. In particular, location paths that meet certain restrictions can be used as patterns. An expression that is also a pattern always evaluates to an object of type node-set. A node matches a pattern if the node is a member of the result of evaluating the pattern as an expression with respect to some possible context; the possible contexts are those whose context node is the node being matched or one of its ancestors.

Here are some examples of patterns:

para matches any para element

* matches any element

chapter|appendix matches any chapter element and any appendix element

olist/item matches any item element with an olist parent

appendix//para matches any para element with an appendix ancestor element

/ matches the root node

text() matches any text node

processing-instruction() matches any processing instruction

node() matches any node other than an attribute node and the root node

id("W11") matches the element with unique ID W11

para[1] matches any para element that is the first para child element of its parent

*[position()=1 and self::para] matches any para element that is the first child element of its parent

para[last()=1] matches any para element that is the only para child element of its parent

items/item[position()>1] matches any item element that has a items parent and that is not the first item child of its parent

item[position() mod 2 = 1] would be true for any item element that is an odd-numbered item child of its parent.

div[@class="appendix"]//p matches any p element with a div ancestor element that has a class attribute with value appendix

@class matches any class attribute (not any element that has a class attribute)

@* matches any attribute

A pattern must match the grammar for Pattern. A Pattern is a set of location path patterns separated by |. A location path pattern is a location path whose steps all use only the child or attribute axes. Although patterns must not use the descendant-or-self axis, patterns may use the // operator as well as the / operator. Location path patterns can also start with an id or key function call with a literal argument. Predicates in a pattern can use arbitrary expressions just like predicates in a location path.

Patterns Pattern LocationPathPattern | Pattern '|' LocationPathPattern LocationPathPattern '/' RelativePathPattern? | IdKeyPattern (('/' | '//') RelativePathPattern)? | '//'? RelativePathPattern IdKeyPattern 'id' '(' Literal ')' | 'key' '(' Literal ',' Literal ')' RelativePathPattern StepPattern | RelativePathPattern '/' StepPattern | RelativePathPattern '//' StepPattern StepPattern ChildOrAttributeAxisSpecifier NodeTest Predicate* ChildOrAttributeAxisSpecifier AbbreviatedAxisSpecifier | ('child' | 'attribute') '::'

A pattern is defined to match a node if and only if there is possible context such that when the pattern is evaluated as an expression with that context, the node is a member of the resulting node-set. When a node is being matched, the possible contexts have a context node that is the node being matched or any ancestor of that node, and a context node list containing just the context node.

For example, p matches any p element, because for any p if the expression p is evaluated with the parent of the p element as context the resulting node-set will contain that p element as one of its members.

This matches even a p element that is the document element, since the document root is the parent of the document element.

Although the semantics of patterns are specified indirectly in terms of expression evaluation, it is easy to understand the meaning of a pattern directly without thinking in terms of expression evaluation. In a pattern, | indicates alternatives; a pattern with one or more | separated alternatives matches if any one of the alternative matches. A pattern that consists of a sequence of StepPatterns separated by / or // is matched from right to left. The pattern only matches if the rightmost StepPattern matches and a suitable element matches the rest of the pattern; if the separator is / then only the parent is a suitable element; if the separator is //, then any ancestor is a suitable element. A StepPattern that uses the child axis matches if the NodeTest is true for the node and the node is not an attribute node. A StepPattern that uses the attribute axis matches if the NodeTest is true for the node and the node is an attribute node. When [] is present, then the first PredicateExpr in a StepPattern is evaluated with the node being matched as the context node and the siblings of the context node that match the NodeTest as the context node list, unless the node being matched is an attribute node, in which case the context node list is all the attributes that have the same parent as the attribute being matched and that match the NameTest.

For example

appendix//ulist/item[position()=1]

matches a node if and only if all of the following are true:

the NodeTest item is true for the node and the node is not an attribute; in other words the node is an item element

evaluating the PredicateExpr position()=1 with the node as context node and the siblings of the node that are item elements as the context node list yields true

the node has a parent that matches appendix//ulist; this will be true if the parent is a ulist element that has an appendix ancestor element.

Defining Template Rules

A template rule is specified with the xsl:template element. The match attribute is a Pattern that identifies the source node or nodes to which the rule applies. The match attribute is required unless the xsl:template element has a name attribute (see ). It is an error for the value of the match attribute to contain a VariableReference. The content of the xsl:template element is the template that is instantiated when the template rule is applied.

For example, an XML document might contain:

important point.]]>

The following template rule matches emph elements and produces a fo:inline-sequence formatting object with a font-weight property of bold.

]]>

Examples in this document use the fo: prefix for the namespace &XSLFO.ns;, which is the namespace of the formatting objects defined in .

As described next, the xsl:apply-templates element recursively processes the children of the source element.

Applying Template Rules

This example creates a block for a chapter element and then processes its immediate children.

]]>

In the absence of a select attribute, the xsl:apply-templates instruction processes all of the children of the current node, including text nodes. However, text nodes that have been stripped as specified in will not be processed. If stripping of whitespace nodes has not been enabled for an element, then all whitespace in the content of the element will be processed as text, and thus whitespace between child elements will count in determining the position of a child element as returned by the position function.

A select attribute can be used to process nodes selected by an expression instead of processing all children. The value of the select attribute is an expression. The expression must evaluate to a node-set. The selected set of nodes is processed in document order, unless a sorting specification is present (see ). The following example processes all of the author children of the author-group:

]]>

The following example processes all of the given-names of the authors that are children of author-group:

]]>

This example processes all of the heading descendant elements of the book element.

]]>

It is also possible to process elements that are not descendants of the current node. This example assumes that a department element has group children and employee descendants. It finds an employee's department and then processes the group children of the department.

Employee belongs to group ]]>

Multiple xsl:apply-templates elements can be used within a single template to do simple reordering. The following example creates two HTML tables. The first table is filled with domestic sales while the second table is filled with foreign sales.

]]>

It is possible for there to be two matching descendants where one is a descendant of the other. This case is not treated specially: both descendants will be processed as usual. For example, given a source document

]]>

the rule

]]>

will process both the outer div and inner div elements.

Typically, xsl:apply-templates is used to process only nodes that are descendants of the current node. Such use of xsl:apply-templates cannot result in non-terminating processing loops. However, when xsl:apply-templates is used to process elements that are not descendants of the current node, the possibility arises of non-terminating loops. For example,

]]>

Implementations may be able to detect such loops in some cases, but the possibility exists that a stylesheet may enter a non-terminating loop that an implementation is unable to detect. This may present a denial of service security risk.

Conflict Resolution for Template Rules

It is possible for a source node to match more than one template rule. The template rule to be used is determined as follows:

First, all matching template rules that have lower import precedence than the matching template rule or rules with the highest import precedence are eliminated from consideration.

Next, all matching template rules that have lower priority than the matching template rule or rules with the highest priority are eliminated from consideration. The priority of a template rule is specified by the priority attribute on the template rule. The value of this must be a real number (positive or negative), matching the production Number with an optional leading minus sign (-). The default priority is computed as follows:

If the pattern contains multiple alternatives separated by |, then it is treated equivalently to a set of template rules, one for each alternative.

If the pattern has the form of a QName preceded by a ChildOrAttributeAxisSpecifier or has the form processing-instruction(Literal) preceded by a ChildOrAttributeAxisSpecifier, then the priority is 0.

If the pattern has the form NCName:* preceded by a ChildOrAttributeAxisSpecifier, then the priority is -0.25.

Otherwise, if the pattern consists of just a NodeTest preceded by a ChildOrAttributeAxisSpecifier, then the priority is -0.5.

Otherwise, the priority is 0.5.

Thus, the most common kind of pattern (a pattern that tests for a node with a particular type and a particular expanded-name) has priority 0. The next less specific kind of pattern (a pattern that tests for a node with a particular type and an expanded-name with a particular namespace URI) has priority -0.25. Patterns less specific than this (patterns that just tests for nodes with particular types) have priority -0.5. Patterns more specific than the most common kind of pattern have priority 0.5.

It is an error if this leaves more than one matching template rule. An XSLT processor may signal the error; if it does not signal the error, it must recover by choosing, from amongst the matching template rules that are left, the one that occurs last in the stylesheet.

Overriding Template Rules

A template rule that is being used to override a template rule in an imported stylesheet (see ) can use the xsl:apply-imports element to invoke the overridden template rule.

At any point in the processing of a stylesheet, there is a current template rule. Whenever a template rule is chosen by matching a pattern, the template rule becomes the current template rule for the instantiation of the rule's template. When an xsl:for-each element is instantiated, the current template rule becomes null for the instantiation of the content of the xsl:for-each element.

xsl:apply-imports processes the current node using only template rules that were imported into the stylesheet element containing the current template rule; the node is processed in the current template rule's mode. It is an error if xsl:apply-imports is instantiated when the current template rule is null.

For example, suppose the stylesheet doc.xsl contains a template rule for example elements:

]]>

Another stylesheet could import doc.xsl and modify the treatment of example elements as follows:

]]>

The combined effect would be to transform an example into an element of the form:

...
]]>
Modes

Modes allow an element to be processed multiple times, each time producing a different result.

Both xsl:template and xsl:apply-templates have an optional mode attribute. The value of the mode attribute is a QName, which is expanded as described in . If xsl:template does not have a match attribute, it must not have a mode attribute. If an xsl:apply-templates element has a mode attribute, then it applies only to those template rules from xsl:template elements that have a mode attribute with the same value; if an xsl:apply-templates element does not have a mode attribute, then it applies only to those template rules from xsl:template elements that do not have a mode attribute.

Built-in Template Rules

There is a built-in template rule to allow recursive processing to continue in the absence of a successful pattern match by an explicit template rule in the stylesheet. This template rule applies to both element nodes and the root node. The following shows the equivalent of the built-in template rule:

]]>

There is also a built-in template rule for each mode, which allows recursive processing to continue in the same mode in the absence of a successful pattern match by an explicit template rule in the stylesheet. This template rule applies to both element nodes and the root node. The following shows the equivalent of the built-in template rule for mode m.

<xsl:template match="*|/" mode="m"> <xsl:apply-templates mode="m"/> </xsl:template>

There is also a built-in template rule for text and attribute nodes that copies text through:

]]>

The built-in template rule for processing instructions and comments is to do nothing.

]]>

The built-in template rule for namespace nodes is also to do nothing. There is no pattern that can match a namespace node; so, the built-in template rule is the only template rule that is applied for namespace nodes.

The built-in template rules are treated as if they were imported implicitly before the stylesheet and so have lower import precedence than all other template rules. Thus, the author can override a built-in template rule by including an explicit template rule.

Named Templates

Templates can be invoked by name. An xsl:template element with a name attribute specifies a named template. The value of the name attribute is a QName, which is expanded as described in . If an xsl:template element has a name attribute, it may, but need not, also have a match attribute. An xsl:call-template element invokes a template by name; it has a required name attribute that identifies the template to be invoked. Unlike xsl:apply-templates, xsl:call-template does not change the current node or the current node list.

The match, mode and priority attributes on an xsl:template element do not affect whether the template is invoked by an xsl:call-template element. Similarly, the name attribute on an xsl:template element does not affect whether the template is invoked by an xsl:apply-templates element.

It is an error if a stylesheet contains more than one template with the same name and same import precedence.

Creating the Result Tree

This section describes instructions that directly create nodes in the result tree.

Creating Elements and Attributes Literal Result Elements

In a template, an element in the stylesheet that does not belong to the XSLT namespace and that is not an extension element (see ) is instantiated to create an element node with the same expanded-name. The content of the element is a template, which is instantiated to give the content of the created element node. The created element node will have the attribute nodes that were present on the element node in the stylesheet tree, other than attributes with names in the XSLT namespace.

The created element node will also have a copy of the namespace nodes that were present on the element node in the stylesheet tree with the exception of any namespace node whose string-value is the XSLT namespace URI (&XSLT.ns;), a namespace URI declared as an extension namespace (see ), or a namespace URI designated as an excluded namespace. A namespace URI is designated as an excluded namespace by using an exclude-result-prefixes attribute on an xsl:stylesheet element or an xsl:exclude-result-prefixes attribute on a literal result element. The value of both these attributes is a whitespace-separated list of namespace prefixes. The namespace bound to each of the prefixes is designated as an excluded namespace. It is an error if there is no namespace bound to the prefix on the element bearing the exclude-result-prefixes or xsl:exclude-result-prefixes attribute. The default namespace (as declared by xmlns) may be designated as an excluded namespace by including #default in the list of namespace prefixes. The designation of a namespace as an excluded namespace is effective within the subtree of the stylesheet rooted at the element bearing the exclude-result-prefixes or xsl:exclude-result-prefixes attribute; a subtree rooted at an xsl:stylesheet element does not include any stylesheets imported or included by children of that xsl:stylesheet element.

When a stylesheet uses a namespace declaration only for the purposes of addressing the source tree, specifying the prefix in the exclude-result-prefixes attribute will avoid superfluous namespace declarations in the result tree.

The value of an attribute of a literal result element is interpreted as an attribute value template: it can contain expressions contained in curly braces ({}).

A namespace URI in the stylesheet tree that is being used to specify a namespace URI in the result tree is called a literal namespace URI. This applies to:

the namespace URI in the expanded-name of a literal result element in the stylesheet

the namespace URI in the expanded-name of an attribute specified on a literal result element in the stylesheet

the string-value of a namespace node on a literal result element in the stylesheet

A stylesheet can use the xsl:namespace-alias element to declare that one namespace URI is an alias for another namespace URI. When a literal namespace URI has been declared to be an alias for another namespace URI, then the namespace URI in the result tree will be the namespace URI that the literal namespace URI is an alias for, instead of the literal namespace URI itself. The xsl:namespace-alias element declares that the namespace URI bound to the prefix specified by the stylesheet-prefix attribute is an alias for the namespace URI bound to the prefix specified by the result-prefix attribute. Thus, the stylesheet-prefix attribute specifies the namespace URI that will appear in the stylesheet, and the result-prefix attribute specifies the corresponding namespace URI that will appear in the result tree. The default namespace (as declared by xmlns) may be specified by using #default instead of a prefix. If a namespace URI is declared to be an alias for multiple different namespace URIs, then the declaration with the highest import precedence is used. It is an error if there is more than one such declaration. An XSLT processor may signal the error; if it does not signal the error, it must recover by choosing, from amongst the declarations with the highest import precedence, the one that occurs last in the stylesheet.

When literal result elements are being used to create element, attribute, or namespace nodes that use the XSLT namespace URI, the stylesheet must use an alias. For example, the stylesheet

<xsl:stylesheet version="1.0" xmlns:xsl="&XSLT.ns;" xmlns:fo="&XSLFO.ns;" xmlns:axsl="&XSLTA.ns;"> ]]>

will generate an XSLT stylesheet from a document of the form:

p h1 h2 h3 h4 ]]>

It may be necessary also to use aliases for namespaces other than the XSLT namespace URI. For example, literal result elements belonging to a namespace dealing with digital signatures might cause XSLT stylesheets to be mishandled by general-purpose security software; using an alias for the namespace would avoid the possibility of such mishandling.

Creating Elements with xsl:element

The xsl:element element allows an element to be created with a computed name. The expanded-name of the element to be created is specified by a required name attribute and an optional namespace attribute. The content of the xsl:element element is a template for the attributes and children of the created element.

The name attribute is interpreted as an attribute value template. It is an error if the string that results from instantiating the attribute value template is not a QName. An XSLT processor may signal the error; if it does not signal the error, then it must recover by making the the result of instantiating the xsl:element element be the sequence of nodes created by instantiating the content of the xsl:element element, excluding any initial attribute nodes. If the namespace attribute is not present then the QName is expanded into an expanded-name using the namespace declarations in effect for the xsl:element element, including any default namespace declaration.

If the namespace attribute is present, then it also is interpreted as an attribute value template. The string that results from instantiating the attribute value template should be a URI reference. It is not an error if the string is not a syntactically legal URI reference. If the string is empty, then the expanded-name of the element has a null namespace URI. Otherwise, the string is used as the namespace URI of the expanded-name of the element to be created. The local part of the QName specified by the name attribute is used as the local part of the expanded-name of the element to be created.

XSLT processors may make use of the prefix of the QName specified in the name attribute when selecting the prefix used for outputting the created element as XML; however, they are not required to do so.

Creating Attributes with xsl:attribute

The xsl:attribute element can be used to add attributes to result elements whether created by literal result elements in the stylesheet or by instructions such as xsl:element. The expanded-name of the attribute to be created is specified by a required name attribute and an optional namespace attribute. Instantiating an xsl:attribute element adds an attribute node to the containing result element node. The content of the xsl:attribute element is a template for the value of the created attribute.

The name attribute is interpreted as an attribute value template. It is an error if the string that results from instantiating the attribute value template is not a QName or is the string xmlns. An XSLT processor may signal the error; if it does not signal the error, it must recover by not adding the attribute to the result tree. If the namespace attribute is not present, then the QName is expanded into an expanded-name using the namespace declarations in effect for the xsl:attribute element, not including any default namespace declaration.

If the namespace attribute is present, then it also is interpreted as an attribute value template. The string that results from instantiating it should be a URI reference. It is not an error if the string is not a syntactically legal URI reference. If the string is empty, then the expanded-name of the attribute has a null namespace URI. Otherwise, the string is used as the namespace URI of the expanded-name of the attribute to be created. The local part of the QName specified by the name attribute is used as the local part of the expanded-name of the attribute to be created.

XSLT processors may make use of the prefix of the QName specified in the name attribute when selecting the prefix used for outputting the created attribute as XML; however, they are not required to do so and, if the prefix is xmlns, they must not do so. Thus, although it is not an error to do:

<xsl:attribute name="xmlns:xsl" namespace="whatever">&XSLT.ns;</xsl:attribute>

it will not result in a namespace declaration being output.

Adding an attribute to an element replaces any existing attribute of that element with the same expanded-name.

The following are all errors:

Adding an attribute to an element after children have been added to it; implementations may either signal the error or ignore the attribute.

Adding an attribute to a node that is not an element; implementations may either signal the error or ignore the attribute.

Creating nodes other than text nodes during the instantiation of the content of the xsl:attribute element; implementations may either signal the error or ignore the offending nodes.

When an xsl:attribute contains a text node with a newline, then the XML output must contain a character reference. For example,

x y]]>

will result in the output

(or with any equivalent character reference). The XML output cannot be

This is because XML 1.0 requires newline characters in attribute values to be normalized into spaces but requires character references to newline characters not to be normalized. The attribute values in the data model represent the attribute value after normalization. If a newline occurring in an attribute value in the tree were output as a newline character rather than as character reference, then the attribute value in the tree created by reparsing the XML would contain a space not a newline, which would mean that the tree had not been output correctly.

Named Attribute Sets

The xsl:attribute-set element defines a named set of attributes. The name attribute specifies the name of the attribute set. The value of the name attribute is a QName, which is expanded as described in . The content of the xsl:attribute-set element consists of zero or more xsl:attribute elements that specify the attributes in the set.

Attribute sets are used by specifying a use-attribute-sets attribute on xsl:element, xsl:copy (see ) or xsl:attribute-set elements. The value of the use-attribute-sets attribute is a whitespace-separated list of names of attribute sets. Each name is specified as a QName, which is expanded as described in . Specifying a use-attribute-sets attribute is equivalent to adding xsl:attribute elements for each of the attributes in each of the named attribute sets to the beginning of the content of the element with the use-attribute-sets attribute, in the same order in which the names of the attribute sets are specified in the use-attribute-sets attribute. It is an error if use of use-attribute-sets attributes on xsl:attribute-set elements causes an attribute set to directly or indirectly use itself.

Attribute sets can also be used by specifying an xsl:use-attribute-sets attribute on a literal result element. The value of the xsl:use-attribute-sets attribute is a whitespace-separated list of names of attribute sets. The xsl:use-attribute-sets attribute has the same effect as the use-attribute-sets attribute on xsl:element with the additional rule that attributes specified on the literal result element itself are treated as if they were specified by xsl:attribute elements before any actual xsl:attribute elements but after any xsl:attribute elements implied by the xsl:use-attribute-sets attribute. Thus, for a literal result element, attributes from attribute sets named in an xsl:use-attribute-sets attribute will be added first, in the order listed in the attribute; next, attributes specified on the literal result element will be added; finally, any attributes specified by xsl:attribute elements will be added. Since adding an attribute to an element replaces any existing attribute of that element with the same name, this means that attributes specified in attribute sets can be overridden by attributes specified on the literal result element itself.

The template within each xsl:attribute element in an xsl:attribute-set element is instantiated each time the attribute set is used; it is instantiated using the same current node and current node list as is used for instantiating the element bearing the use-attribute-sets or xsl:use-attribute-sets attribute. However, it is the position in the stylesheet of the xsl:attribute element rather than of the element bearing the use-attribute-sets or xsl:use-attribute-sets attribute that determines which variable bindings are visible (see ); thus, only variables and parameters declared by top-level xsl:variable and xsl:param elements are visible.

The following example creates a named attribute set title-style and uses it in a template rule.

12pt bold ]]>

Multiple definitions of an attribute set with the same expanded-name are merged. An attribute from a definition that has higher import precedence takes precedence over an attribute from a definition that has lower import precedence. It is an error if there are two attribute sets that have the same expanded-name and equal import precedence and that both contain the same attribute, unless there is a definition of the attribute set with higher import precedence that also contains the attribute. An XSLT processor may signal the error; if it does not signal the error, it must recover by choosing from amongst the definitions that specify the attribute that have the highest import precedence the one that was specified last in the stylesheet. Where the attributes in an attribute set were specified is relevant only in merging the attributes into the attribute set; it makes no difference when the attribute set is used.

Creating Text

A template can also contain text nodes. Each text node in a template remaining after whitespace has been stripped as specified in will create a text node with the same string-value in the result tree. Adjacent text nodes in the result tree are automatically merged.

Note that text is processed at the tree level. Thus, markup of &lt; in a template will be represented in the stylesheet tree by a text node that includes the character <. This will create a text node in the result tree that contains a < character, which will be represented by the markup &lt; (or an equivalent character reference) when the result tree is externalized as an XML document (unless output escaping is disabled as described in ).

Literal data characters may also be wrapped in an xsl:text element. This wrapping may change what whitespace characters are stripped (see ) but does not affect how the characters are handled by the XSLT processor thereafter.

The xml:lang and xml:space attributes are not treated specially by XSLT. In particular,

it is the responsibility of the stylesheet author explicitly to generate any xml:lang or xml:space attributes that are needed in the result;

specifying an xml:lang or xml:space attribute on an element in the XSLT namespace will not cause any xml:lang or xml:space attributes to appear in the result.

Creating Processing Instructions

The xsl:processing-instruction element is instantiated to create a processing instruction node. The content of the xsl:processing-instruction element is a template for the string-value of the processing instruction node. The xsl:processing-instruction element has a required name attribute that specifies the name of the processing instruction node. The value of the name attribute is interpreted as an attribute value template.

For example, this

href="book.css" type="text/css"]]>

would create the processing instruction

]]>

It is an error if the string that results from instantiating the name attribute is not both an NCName and a PITarget. An XSLT processor may signal the error; if it does not signal the error, it must recover by not adding the processing instruction to the result tree.

This means that xsl:processing-instruction cannot be used to output an XML declaration. The xsl:output element should be used instead (see ).

It is an error if instantiating the content of xsl:processing-instruction creates nodes other than text nodes. An XSLT processor may signal the error; if it does not signal the error, it must recover by ignoring the offending nodes together with their content.

It is an error if the result of instantiating the content of the xsl:processing-instruction contains the string ?>. An XSLT processor may signal the error; if it does not signal the error, it must recover by inserting a space after any occurrence of ? that is followed by a >.

Creating Comments

The xsl:comment element is instantiated to create a comment node in the result tree. The content of the xsl:comment element is a template for the string-value of the comment node.

For example, this

This file is automatically generated. Do not edit!]]>

would create the comment

]]>

It is an error if instantiating the content of xsl:comment creates nodes other than text nodes. An XSLT processor may signal the error; if it does not signal the error, it must recover by ignoring the offending nodes together with their content.

It is an error if the result of instantiating the content of the xsl:comment contains the string -- or ends with -. An XSLT processor may signal the error; if it does not signal the error, it must recover by inserting a space after any occurrence of - that is followed by another - or that ends the comment.

Copying

The xsl:copy element provides an easy way of copying the current node. Instantiating the xsl:copy element creates a copy of the current node. The namespace nodes of the current node are automatically copied as well, but the attributes and children of the node are not automatically copied. The content of the xsl:copy element is a template for the attributes and children of the created node; the content is instantiated only for nodes of types that can have attributes or children (i.e. root nodes and element nodes).

The xsl:copy element may have a use-attribute-sets attribute (see ). This is used only when copying element nodes.

The root node is treated specially because the root node of the result tree is created implicitly. When the current node is the root node, xsl:copy will not create a root node, but will just use the content template.

For example, the identity transformation can be written using xsl:copy as follows:

]]>

When the current node is an attribute, then if it would be an error to use xsl:attribute to create an attribute with the same name as the current node, then it is also an error to use xsl:copy (see ).

The following example shows how xml:lang attributes can be easily copied through from source to result. If a stylesheet defines the following named template:

]]>

then it can simply do

]]>

instead of

]]>

when it wants to copy the xml:lang attribute.

Computing Generated Text

Within a template, the xsl:value-of element can be used to compute generated text, for example by extracting text from the source tree or by inserting the value of a variable. The xsl:value-of element does this with an expression that is specified as the value of the select attribute. Expressions can also be used inside attribute values of literal result elements by enclosing the expression in curly braces ({}).

Generating Text with xsl:value-of

The xsl:value-of element is instantiated to create a text node in the result tree. The required select attribute is an expression; this expression is evaluated and the resulting object is converted to a string as if by a call to the string function. The string specifies the string-value of the created text node. If the string is empty, no text node will be created. The created text node will be merged with any adjacent text nodes.

The xsl:copy-of element can be used to copy a node-set over to the result tree without converting it to a string. See .

For example, the following creates an HTML paragraph from a person element with given-name and family-name attributes. The paragraph will contain the value of the given-name attribute of the current node followed by a space and the value of the family-name attribute of the current node.

]]>

For another example, the following creates an HTML paragraph from a person element with given-name and family-name children elements. The paragraph will contain the string-value of the first given-name child element of the current node followed by a space and the string-value of the first family-name child element of the current node.

]]>

The following precedes each procedure element with a paragraph containing the security level of the procedure. It assumes that the security level that applies to a procedure is determined by a security attribute on the procedure element or on an ancestor element of the procedure. It also assumes that if more than one such element has a security attribute then the security level is determined by the element that is closest to the procedure.

]]>
Attribute Value Templates

In an attribute value that is interpreted as an attribute value template, such as an attribute of a literal result element, an expression can be used by surrounding the expression with curly braces ({}). The attribute value template is instantiated by replacing the expression together with surrounding curly braces by the result of evaluating the expression and converting the resulting object to a string as if by a call to the string function. Curly braces are not recognized in an attribute value in an XSLT stylesheet unless the attribute is specifically stated to be one that is interpreted as an attribute value template; in an element syntax summary, the value of such attributes is surrounded by curly braces.

Not all attributes are interpreted as attribute value templates. Attributes whose value is an expression or pattern, attributes of top-level elements and attributes that refer to named XSLT objects are not interpreted as attribute value templates. In addition, xmlns attributes are not interpreted as attribute value templates; it would not be conformant with the XML Namespaces Recommendation to do this.

The following example creates an img result element from a photograph element in the source; the value of the src attribute of the img element is computed from the value of the image-dir variable and the string-value of the href child of the photograph element; the value of the width attribute of the img element is computed from the value of the width attribute of the size child of the photograph element:

/images ]]>

With this source

headquarters.jpg ]]>

the result would be

]]>

When an attribute value template is instantiated, a double left or right curly brace outside an expression will be replaced by a single curly brace. It is an error if a right curly brace occurs in an attribute value template outside an expression without being followed by a second right curly brace. A right curly brace inside a Literal in an expression is not recognized as terminating the expression.

Curly braces are not recognized recursively inside expressions. For example:

]]>

is not allowed. Instead, use simply:

]]>
Numbering

The xsl:number element is used to insert a formatted number into the result tree. The number to be inserted may be specified by an expression. The value attribute contains an expression. The expression is evaluated and the resulting object is converted to a number as if by a call to the number function. The number is rounded to an integer and then converted to a string using the attributes specified in ; in this context, the value of each of these attributes is interpreted as an attribute value template. After conversion, the resulting string is inserted in the result tree. For example, the following example numbers a sorted list:

]]>

If no value attribute is specified, then the xsl:number element inserts a number based on the position of the current node in the source tree. The following attributes control how the current node is to be numbered:

The level attribute specifies what levels of the source tree should be considered; it has the values single, multiple or any. The default is single.

The count attribute is a pattern that specifies what nodes should be counted at those levels. If count attribute is not specified, then it defaults to the pattern that matches any node with the same node type as the current node and, if the current node has an expanded-name, with the same expanded-name as the current node.

The from attribute is a pattern that specifies where counting starts.

In addition, the attributes specified in are used for number to string conversion, as in the case when the value attribute is specified.

The xsl:number element first constructs a list of positive integers using the level, count and from attributes:

When level="single", it goes up to the first node in the ancestor-or-self axis that matches the count pattern, and constructs a list of length one containing one plus the number of preceding siblings of that ancestor that match the count pattern. If there is no such ancestor, it constructs an empty list. If the from attribute is specified, then the only ancestors that are searched are those that are descendants of the nearest ancestor that matches the from pattern. Preceding siblings has the same meaning here as with the preceding-sibling axis.

When level="multiple", it constructs a list of all ancestors of the current node in document order followed by the element itself; it then selects from the list those nodes that match the count pattern; it then maps each node in the list to one plus the number of preceding siblings of that node that match the count pattern. If the from attribute is specified, then the only ancestors that are searched are those that are descendants of the nearest ancestor that matches the from pattern. Preceding siblings has the same meaning here as with the preceding-sibling axis.

When level="any", it constructs a list of length one containing the number of nodes that match the count pattern and belong to the set containing the current node and all nodes at any level of the document that are before the current node in document order, excluding any namespace and attribute nodes (in other words the union of the members of the preceding and ancestor-or-self axes). If the from attribute is specified, then only nodes after the first node before the current node that match the from pattern are considered.

The list of numbers is then converted into a string using the attributes specified in ; in this context, the value of each of these attributes is interpreted as an attribute value template. After conversion, the resulting string is inserted in the result tree.

The following would number the items in an ordered list:

. ]]>

The following two rules would number title elements. This is intended for a document that contains a sequence of chapters followed by a sequence of appendices, where both chapters and appendices contain sections, which in turn contain subsections. Chapters are numbered 1, 2, 3; appendices are numbered A, B, C; sections in chapters are numbered 1.1, 1.2, 1.3; sections in appendices are numbered A.1, A.2, A.3.

]]>

The following example numbers notes sequentially within a chapter:

]]>

The following example would number H4 elements in HTML with a three-part label:

. . ]]> Number to String Conversion Attributes

The following attributes are used to control conversion of a list of numbers into a string. The numbers are integers greater than 0. The attributes are all optional.

The main attribute is format. The default value for the format attribute is 1. The format attribute is split into a sequence of tokens where each token is a maximal sequence of alphanumeric characters or a maximal sequence of non-alphanumeric characters. Alphanumeric means any character that has a Unicode category of Nd, Nl, No, Lu, Ll, Lt, Lm or Lo. The alphanumeric tokens (format tokens) specify the format to be used for each number in the list. If the first token is a non-alphanumeric token, then the constructed string will start with that token; if the last token is non-alphanumeric token, then the constructed string will end with that token. Non-alphanumeric tokens that occur between two format tokens are separator tokens that are used to join numbers in the list. The nth format token will be used to format the nth number in the list. If there are more numbers than format tokens, then the last format token will be used to format remaining numbers. If there are no format tokens, then a format token of 1 is used to format all numbers. The format token specifies the string to be used to represent the number 1. Each number after the first will be separated from the preceding number by the separator token preceding the format token used to format that number, or, if there are no separator tokens, then by . (a period character).

Format tokens are a superset of the allowed values for the type attribute for the OL element in HTML 4.0 and are interpreted as follows:

Any token where the last character has a decimal digit value of 1 (as specified in the Unicode character property database), and the Unicode value of preceding characters is one less than the Unicode value of the last character generates a decimal representation of the number where each number is at least as long as the format token. Thus, a format token 1 generates the sequence 1 2 ... 10 11 12 ..., and a format token 01 generates the sequence 01 02 ... 09 10 11 12 ... 99 100 101.

A format token A generates the sequence A B C ... Z AA AB AC....

A format token a generates the sequence a b c ... z aa ab ac....

A format token i generates the sequence i ii iii iv v vi vii viii ix x ....

A format token I generates the sequence I II III IV V VI VII VIII IX X ....

Any other format token indicates a numbering sequence that starts with that token. If an implementation does not support a numbering sequence that starts with that token, it must use a format token of 1.

When numbering with an alphabetic sequence, the lang attribute specifies which language's alphabet is to be used; it has the same range of values as xml:lang ; if no lang value is specified, the language should be determined from the system environment. Implementers should document for which languages they support numbering.

Implementers should not make any assumptions about how numbering works in particular languages and should properly research the languages that they wish to support. The numbering conventions of many languages are very different from English.

The letter-value attribute disambiguates between numbering sequences that use letters. In many languages there are two commonly used numbering sequences that use letters. One numbering sequence assigns numeric values to letters in alphabetic sequence, and the other assigns numeric values to each letter in some other manner traditional in that language. In English, these would correspond to the numbering sequences specified by the format tokens a and i. In some languages, the first member of each sequence is the same, and so the format token alone would be ambiguous. A value of alphabetic specifies the alphabetic sequence; a value of traditional specifies the other sequence. If the letter-value attribute is not specified, then it is implementation-dependent how any ambiguity is resolved.

It is possible for two conforming XSLT processors not to convert a number to exactly the same string. Some XSLT processors may not support some languages. Furthermore, there may be variations possible in the way conversions are performed for any particular language that are not specifiable by the attributes on xsl:number. Future versions of XSLT may provide additional attributes to provide control over these variations. Implementations may also use implementation-specific namespaced attributes on xsl:number for this.

The grouping-separator attribute gives the separator used as a grouping (e.g. thousands) separator in decimal numbering sequences, and the optional grouping-size specifies the size (normally 3) of the grouping. For example, grouping-separator="," and grouping-size="3" would produce numbers of the form 1,000,000. If only one of the grouping-separator and grouping-size attributes is specified, then it is ignored.

Here are some examples of conversion specifications:

format="&#x30A2;" specifies Katakana numbering

format="&#x30A4;" specifies Katakana numbering in the iroha order

format="&#x0E51;" specifies numbering with Thai digits

format="&#x05D0;" letter-value="traditional" specifies traditional Hebrew numbering

format="&#x10D0;" letter-value="traditional" specifies Georgian numbering

format="&#x03B1;" letter-value="traditional" specifies classical Greek numbering

format="&#x0430;" letter-value="traditional" specifies Old Slavic numbering

Repetition

When the result has a known regular structure, it is useful to be able to specify directly the template for selected nodes. The xsl:for-each instruction contains a template, which is instantiated for each node selected by the expression specified by the select attribute. The select attribute is required. The expression must evaluate to a node-set. The template is instantiated with the selected node as the current node, and with a list of all of the selected nodes as the current node list. The nodes are processed in document order, unless a sorting specification is present (see ).

For example, given an XML document with this structure

... ... ... ... ... ... ]]>

the following would create an HTML document containing a table with a row for each customer element

Customers
]]>
Conditional Processing

There are two instructions in XSLT that support conditional processing in a template: xsl:if and xsl:choose. The xsl:if instruction provides simple if-then conditionality; the xsl:choose instruction supports selection of one choice when there are several possibilities.

Conditional Processing with xsl:if

The xsl:if element has a test attribute, which specifies an expression. The content is a template. The expression is evaluated and the resulting object is converted to a boolean as if by a call to the boolean function. If the result is true, then the content template is instantiated; otherwise, nothing is created. In the following example, the names in a group of names are formatted as a comma separated list:

, ]]>

The following colors every other table row yellow:

yellow ]]>
Conditional Processing with xsl:choose

The xsl:choose element selects one among a number of possible alternatives. It consists of a sequence of xsl:when elements followed by an optional xsl:otherwise element. Each xsl:when element has a single attribute, test, which specifies an expression. The content of the xsl:when and xsl:otherwise elements is a template. When an xsl:choose element is processed, each of the xsl:when elements is tested in turn, by evaluating the expression and converting the resulting object to a boolean as if by a call to the boolean function. The content of the first, and only the first, xsl:when element whose test is true is instantiated. If no xsl:when is true, the content of the xsl:otherwise element is instantiated. If no xsl:when element is true, and no xsl:otherwise element is present, nothing is created.

The following example enumerates items in an ordered list using arabic numerals, letters, or roman numerals depending on the depth to which the ordered lists are nested.

. ]]>
Sorting

Sorting is specified by adding xsl:sort elements as children of an xsl:apply-templates or xsl:for-each element. The first xsl:sort child specifies the primary sort key, the second xsl:sort child specifies the secondary sort key and so on. When an xsl:apply-templates or xsl:for-each element has one or more xsl:sort children, then instead of processing the selected nodes in document order, it sorts the nodes according to the specified sort keys and then processes them in sorted order. When used in xsl:for-each, xsl:sort elements must occur first. When a template is instantiated by xsl:apply-templates and xsl:for-each, the current node list list consists of the complete list of nodes being processed in sorted order.

xsl:sort has a select attribute whose value is an expression. For each node to be processed, the expression is evaluated with that node as the current node and with the complete list of nodes being processed in unsorted order as the current node list. The resulting object is converted to a string as if by a call to the string function; this string is used as the sort key for that node. The default value of the select attribute is ., which will cause the string-value of the current node to be used as the sort key.

This string serves as a sort key for the node. The following optional attributes on xsl:sort control how the list of sort keys are sorted; the values of all of these attributes are interpreted as attribute value templates.

order specifies whether the strings should be sorted in ascending or descending order; ascending specifies ascending order; descending specifies descending order; the default is ascending

lang specifies the language of the sort keys; it has the same range of values as xml:lang ; if no lang value is specified, the language should be determined from the system environment

data-type specifies the data type of the strings; the following values are allowed:

text specifies that the sort keys should be sorted lexicographically in the culturally correct manner for the language specified by lang

number specifies that the sort keys should be converted to numbers and then sorted according to the numeric value; the sort key is converted to a number as if by a call to the number function; the lang attribute is ignored

a QName with a prefix is expanded into an expanded-name as described in ; the expanded-name identifies the data-type; the behavior in this case is not specified by this document

The default value is text.

The XSL Working Group plans that future versions of XSLT will leverage XML Schemas to define further values for this attribute.

case-order has the value upper-first or lower-first; this applies when data-type="text", and specifies that upper-case letters should sort before lower-case letters or vice-versa respectively. For example, if lang="en", then A a B b are sorted with case-order="upper-first" and a A b B are sorted with case-order="lower-first". The default value is language dependent.

It is possible for two conforming XSLT processors not to sort exactly the same. Some XSLT processors may not support some languages. Furthermore, there may be variations possible in the sorting of any particular language that are not specified by the attributes on xsl:sort, for example, whether Hiragana or Katakana is sorted first in Japanese. Future versions of XSLT may provide additional attributes to provide control over these variations. Implementations may also use implementation-specific namespaced attributes on xsl:sort for this.

It is recommended that implementers consult for information on internationalized sorting.

The sort must be stable: in the sorted list of nodes, any sub list that has sort keys that all compare equal must be in document order.

For example, suppose an employee database has the form

James Clark ... ]]>

Then a list of employees sorted by name could be generated using:

  • ]]>
    Variables and Parameters

    A variable is a name that may be bound to a value. The value to which a variable is bound (the value of the variable) can be an object of any of the types that can be returned by expressions. There are two elements that can be used to bind variables: xsl:variable and xsl:param. The difference is that the value specified on the xsl:param variable is only a default value for the binding; when the template or stylesheet within which the xsl:param element occurs is invoked, parameters may be passed that are used in place of the default values.

    Both xsl:variable and xsl:param have a required name attribute, which specifies the name of the variable. The value of the name attribute is a QName, which is expanded as described in .

    For any use of these variable-binding elements, there is a region of the stylesheet tree within which the binding is visible; within this region, any binding of the variable that was visible on the variable-binding element itself is hidden. Thus, only the innermost binding of a variable is visible. The set of variable bindings in scope for an expression consists of those bindings that are visible at the point in the stylesheet where the expression occurs.

    Result Tree Fragments

    Variables introduce an additional data-type into the expression language. This additional data type is called result tree fragment. A variable may be bound to a result tree fragment instead of one of the four basic XPath data-types (string, number, boolean, node-set). A result tree fragment represents a fragment of the result tree. A result tree fragment is treated equivalently to a node-set that contains just a single root node. However, the operations permitted on a result tree fragment are a subset of those permitted on a node-set. An operation is permitted on a result tree fragment only if that operation would be permitted on a string (the operation on the string may involve first converting the string to a number or boolean). In particular, it is not permitted to use the /, //, and [] operators on result tree fragments. When a permitted operation is performed on a result tree fragment, it is performed exactly as it would be on the equivalent node-set.

    When a result tree fragment is copied into the result tree (see ), then all the nodes that are children of the root node in the equivalent node-set are added in sequence to the result tree.

    Expressions can only return values of type result tree fragment by referencing variables of type result tree fragment or calling extension functions that return a result tree fragment or getting a system property whose value is a result tree fragment.

    Values of Variables and Parameters

    A variable-binding element can specify the value of the variable in three alternative ways.

    If the variable-binding element has a select attribute, then the value of the attribute must be an expression and the value of the variable is the object that results from evaluating the expression. In this case, the content must be empty.

    If the variable-binding element does not have a select attribute and has non-empty content (i.e. the variable-binding element has one or more child nodes), then the content of the variable-binding element specifies the value. The content of the variable-binding element is a template, which is instantiated to give the value of the variable. The value is a result tree fragment equivalent to a node-set containing just a single root node having as children the sequence of nodes produced by instantiating the template. The base URI of the nodes in the result tree fragment is the base URI of the variable-binding element.

    It is an error if a member of the sequence of nodes created by instantiating the template is an attribute node or a namespace node, since a root node cannot have an attribute node or a namespace node as a child. An XSLT processor may signal the error; if it does not signal the error, it must recover by not adding the attribute node or namespace node.

    If the variable-binding element has empty content and does not have a select attribute, then the value of the variable is an empty string. Thus

    ]]>

    is equivalent to

    ]]>

    When a variable is used to select nodes by position, be careful not to do:

    2 ... ]]>

    This will output the value of the first item element, because the variable n will be bound to a result tree fragment, not a number. Instead, do either

    ... ]]>

    or

    2 ... ]]>

    One convenient way to specify the empty node-set as the default value of a parameter is:

    ]]>
    Using Values of Variables and Parameters with xsl:copy-of

    The xsl:copy-of element can be used to insert a result tree fragment into the result tree, without first converting it to a string as xsl:value-of does (see ). The required select attribute contains an expression. When the result of evaluating the expression is a result tree fragment, the complete fragment is copied into the result tree. When the result is a node-set, all the nodes in the set are copied in document order into the result tree; copying an element node copies the attribute nodes, namespace nodes and children of the element node as well as the element node itself; a root node is copied by copying its children. When the result is neither a node-set nor a result tree fragment, the result is converted to a string and then inserted into the result tree, as with xsl:value-of.

    Top-level Variables and Parameters

    Both xsl:variable and xsl:param are allowed as top-level elements. A top-level variable-binding element declares a global variable that is visible everywhere. A top-level xsl:param element declares a parameter to the stylesheet; XSLT does not define the mechanism by which parameters are passed to the stylesheet. It is an error if a stylesheet contains more than one binding of a top-level variable with the same name and same import precedence. At the top-level, the expression or template specifying the variable value is evaluated with the same context as that used to process the root node of the source document: the current node is the root node of the source document and the current node list is a list containing just the root node of the source document. If the template or expression specifying the value of a global variable x references a global variable y, then the value for y must be computed before the value of x. It is an error if it is impossible to do this for all global variable definitions; in other words, it is an error if the definitions are circular.

    This example declares a global variable para-font-size, which it references in an attribute value template.

    12pt ]]>
    Variables and Parameters within Templates

    As well as being allowed at the top-level, both xsl:variable and xsl:param are also allowed in templates. xsl:variable is allowed anywhere within a template that an instruction is allowed. In this case, the binding is visible for all following siblings and their descendants. Note that the binding is not visible for the xsl:variable element itself. xsl:param is allowed as a child at the beginning of an xsl:template element. In this context, the binding is visible for all following siblings and their descendants. Note that the binding is not visible for the xsl:param element itself.

    A binding shadows another binding if the binding occurs at a point where the other binding is visible, and the bindings have the same name. It is an error if a binding established by an xsl:variable or xsl:param element within a template shadows another binding established by an xsl:variable or xsl:param element also within the template. It is not an error if a binding established by an xsl:variable or xsl:param element in a template shadows another binding established by an xsl:variable or xsl:param top-level element. Thus, the following is an error:

    ]]>

    However, the following is allowed:

    ]]>

    The nearest equivalent in Java to an xsl:variable element in a template is a final local variable declaration with an initializer. For example,

    ]]>

    has similar semantics to

    final Object x = "value";

    XSLT does not provide an equivalent to the Java assignment operator

    x = "value";

    because this would make it harder to create an implementation that processes a document other than in a batch-like way, starting at the beginning and continuing through to the end.

    Passing Parameters to Templates

    Parameters are passed to templates using the xsl:with-param element. The required name attribute specifies the name of the parameter (the variable the value of whose binding is to be replaced). The value of the name attribute is a QName, which is expanded as described in . xsl:with-param is allowed within both xsl:call-template and xsl:apply-templates. The value of the parameter is specified in the same way as for xsl:variable and xsl:param. The current node and current node list used for computing the value specified by xsl:with-param element is the same as that used for the xsl:apply-templates or xsl:call-template element within which it occurs. It is not an error to pass a parameter x to a template that does not have an xsl:param element for x; the parameter is simply ignored.

    This example defines a named template for a numbered-block with an argument to control the format of the number.

    1. a. ]]>
    Additional Functions

    This section describes XSLT-specific additions to the core XPath function library. Some of these additional functions also make use of information specified by top-level elements in the stylesheet; this section also describes these elements.

    Multiple Source Documents

    The document function allows access to XML documents other than the main source document.

    When the document function has exactly one argument and the argument is a node-set, then the result is the union, for each node in the argument node-set, of the result of calling the document function with the first argument being the string-value of the node, and the second argument being a node-set with the node as its only member. When the document function has two arguments and the first argument is a node-set, then the result is the union, for each node in the argument node-set, of the result of calling the document function with the first argument being the string-value of the node, and with the second argument being the second argument passed to the document function.

    When the first argument to the document function is not a node-set, the first argument is converted to a string as if by a call to the string function. This string is treated as a URI reference; the resource identified by the URI is retrieved. The data resulting from the retrieval action is parsed as an XML document and a tree is constructed in accordance with the data model (see ). If there is an error retrieving the resource, then the XSLT processor may signal an error; if it does not signal an error, it must recover by returning an empty node-set. One possible kind of retrieval error is that the XSLT processor does not support the URI scheme used by the URI. An XSLT processor is not required to support any particular URI schemes. The documentation for an XSLT processor should specify which URI schemes the XSLT processor supports.

    If the URI reference does not contain a fragment identifier, then a node-set containing just the root node of the document is returned. If the URI reference does contain a fragment identifier, the function returns a node-set containing the nodes in the tree identified by the fragment identifier of the URI reference. The semantics of the fragment identifier is dependent on the media type of the result of retrieving the URI. If there is an error in processing the fragment identifier, the XSLT processor may signal the error; if it does not signal the error, it must recover by returning an empty node-set. Possible errors include:

    The fragment identifier identifies something that cannot be represented by an XSLT node-set (such as a range of characters within a text node).

    The XSLT processor does not support fragment identifiers for the media-type of the retrieval result. An XSLT processor is not required to support any particular media types. The documentation for an XSLT processor should specify for which media types the XSLT processor supports fragment identifiers.

    The data resulting from the retrieval action is parsed as an XML document regardless of the media type of the retrieval result; if the top-level media type is text, then it is parsed in the same way as if the media type were text/xml; otherwise, it is parsed in the same way as if the media type were application/xml.

    Since there is no top-level xml media type, data with a media type other than text/xml or application/xml may in fact be XML.

    The URI reference may be relative. The base URI (see ) of the node in the second argument node-set that is first in document order is used as the base URI for resolving the relative URI into an absolute URI. If the second argument is omitted, then it defaults to the node in the stylesheet that contains the expression that includes the call to the document function. Note that a zero-length URI reference is a reference to the document relative to which the URI reference is being resolved; thus document("") refers to the root node of the stylesheet; the tree representation of the stylesheet is exactly the same as if the XML document containing the stylesheet was the initial source document.

    Two documents are treated as the same document if they are identified by the same URI. The URI used for the comparison is the absolute URI into which any relative URI was resolved and does not include any fragment identifier. One root node is treated as the same node as another root node if the two nodes are from the same document. Thus, the following expression will always be true:

    generate-id(document("foo.xml"))=generate-id(document("foo.xml"))

    The document function gives rise to the possibility that a node-set may contain nodes from more than one document. With such a node-set, the relative document order of two nodes in the same document is the normal document order defined by XPath . The relative document order of two nodes in different documents is determined by an implementation-dependent ordering of the documents containing the two nodes. There are no constraints on how the implementation orders documents other than that it must do so consistently: an implementation must always use the same order for the same set of documents.

    Keys

    Keys provide a way to work with documents that contain an implicit cross-reference structure. The ID, IDREF and IDREFS attribute types in XML provide a mechanism to allow XML documents to make their cross-reference explicit. XSLT supports this through the XPath id function. However, this mechanism has a number of limitations:

    ID attributes must be declared as such in the DTD. If an ID attribute is declared as an ID attribute only in the external DTD subset, then it will be recognized as an ID attribute only if the XML processor reads the external DTD subset. However, XML does not require XML processors to read the external DTD, and they may well choose not to do so, especially if the document is declared standalone="yes".

    A document can contain only a single set of unique IDs. There cannot be separate independent sets of unique IDs.

    The ID of an element can only be specified in an attribute; it cannot be specified by the content of the element, or by a child element.

    An ID is constrained to be an XML name. For example, it cannot contain spaces.

    An element can have at most one ID.

    At most one element can have a particular ID.

    Because of these limitations XML documents sometimes contain a cross-reference structure that is not explicitly declared by ID/IDREF/IDREFS attributes.

    A key is a triple containing:

    the node which has the key

    the name of the key (an expanded-name)

    the value of the key (a string)

    A stylesheet declares a set of keys for each document using the xsl:key element. When this set of keys contains a member with node x, name y and value z, we say that node x has a key with name y and value z.

    Thus, a key is a kind of generalized ID, which is not subject to the same limitations as an XML ID:

    Keys are declared in the stylesheet using xsl:key elements.

    A key has a name as well as a value; each key name may be thought of as distinguishing a separate, independent space of identifiers.

    The value of a named key for an element may be specified in any convenient place; for example, in an attribute, in a child element or in content. An XPath expression is used to specify where to find the value for a particular named key.

    The value of a key can be an arbitrary string; it is not constrained to be a name.

    There can be multiple keys in a document with the same node, same key name, but different key values.

    There can be multiple keys in a document with the same key name, same key value, but different nodes.

    The xsl:key element is used to declare keys. The name attribute specifies the name of the key. The value of the name attribute is a QName, which is expanded as described in . The match attribute is a Pattern; an xsl:key element gives information about the keys of any node that matches the pattern specified in the match attribute. The use attribute is an expression specifying the values of the key; the expression is evaluated once for each node that matches the pattern. If the result is a node-set, then for each node in the node-set, the node that matches the pattern has a key of the specified name whose value is the string-value of the node in the node-set; otherwise, the result is converted to a string, and the node that matches the pattern has a key of the specified name with value equal to that string. Thus, a node x has a key with name y and value z if and only if there is an xsl:key element such that:

    x matches the pattern specified in the match attribute of the xsl:key element;

    the value of the name attribute of the xsl:key element is equal to y; and

    when the expression specified in the use attribute of the xsl:key element is evaluated with x as the current node and with a node list containing just x as the current node list resulting in an object u, then either z is equal to the result of converting u to a string as if by a call to the string function, or u is a node-set and z is equal to the string-value of one or more of the nodes in u.

    Note also that there may be more than one xsl:key element that matches a given node; all of the matching xsl:key elements are used, even if they do not have the same import precedence.

    It is an error for the value of either the use attribute or the match attribute to contain a VariableReference.

    The key function does for keys what the id function does for IDs. The first argument specifies the name of the key. The value of the argument must be a QName, which is expanded as described in . When the second argument to the key function is of type node-set, then the result is the union of the result of applying the key function to the string value of each of the nodes in the argument node-set. When the second argument to key is of any other type, the argument is converted to a string as if by a call to the string function; it returns a node-set containing the nodes in the same document as the context node that have a value for the named key equal to this string.

    For example, given a declaration

    ]]>

    an expression key("idkey",@ref) will return the same node-set as id(@ref), assuming that the only ID attribute declared in the XML source document is:

    ]]>

    and that the ref attribute of the current node contains no whitespace.

    Suppose a document describing a function library uses a prototype element to define functions

    ]]>

    and a function element to refer to function names

    key]]>

    Then the stylesheet could generate hyperlinks between the references and definitions as follows:

    Function: ...

    ]]>

    The key can be used to retrieve a key from a document other than the document containing the context node. For example, suppose a document contains bibliographic references in the form XSLT]]>, and there is a separate XML document bib.xml containing a bibliographic database with entries in the form:

    ...]]>

    Then the stylesheet could use the following to transform the bibref elements:

    ]]> Number Formatting

    The format-number function converts its first argument to a string using the format pattern string specified by the second argument and the decimal-format named by the third argument, or the default decimal-format, if there is no third argument. The format pattern string is in the syntax specified by the JDK 1.1 DecimalFormat class. The format pattern string is in a localized notation: the decimal-format determines what characters have a special meaning in the pattern (with the exception of the quote character, which is not localized). The format pattern must not contain the currency sign (#x00A4); support for this feature was added after the initial release of JDK 1.1. The decimal-format name must be a QName, which is expanded as described in . It is an error if the stylesheet does not contain a declaration of the decimal-format with the specified expanded-name.

    Implementations are not required to use the JDK 1.1 implementation, nor are implementations required to be implemented in Java.

    Stylesheets can use other facilities in XPath to control rounding.

    The xsl:decimal-format element declares a decimal-format, which controls the interpretation of a format pattern used by the format-number function. If there is a name attribute, then the element declares a named decimal-format; otherwise, it declares the default decimal-format. The value of the name attribute is a QName, which is expanded as described in . It is an error to declare either the default decimal-format or a decimal-format with a given name more than once (even with different import precedence), unless it is declared every time with the same value for all attributes (taking into account any default values).

    The other attributes on xsl:decimal-format correspond to the methods on the JDK 1.1 DecimalFormatSymbols class. For each get/set method pair there is an attribute defined for the xsl:decimal-format element.

    The following attributes both control the interpretation of characters in the format pattern and specify characters that may appear in the result of formatting the number:

    decimal-separator specifies the character used for the decimal sign; the default value is the period character (.)

    grouping-separator specifies the character used as a grouping (e.g. thousands) separator; the default value is the comma character (,)

    percent specifies the character used as a percent sign; the default value is the percent character (%)

    per-mille specifies the character used as a per mille sign; the default value is the Unicode per-mille character (#x2030)

    zero-digit specifies the character used as the digit zero; the default value is the digit zero (0)

    The following attributes control the interpretation of characters in the format pattern:

    digit specifies the character used for a digit in the format pattern; the default value is the number sign character (#)

    pattern-separator specifies the character used to separate positive and negative sub patterns in a pattern; the default value is the semi-colon character (;)

    The following attributes specify characters or strings that may appear in the result of formatting the number:

    infinity specifies the string used to represent infinity; the default value is the string Infinity

    NaN specifies the string used to represent the NaN value; the default value is the string NaN

    minus-sign specifies the character used as the default minus sign; the default value is the hyphen-minus character (-, #x2D)

    Miscellaneous Additional Functions

    The current function returns a node-set that has the current node as its only member. For an outermost expression (an expression not occurring within another expression), the current node is always the same as the context node. Thus,

    ]]>

    means the same as

    ]]>

    However, within square brackets the current node is usually different from the context node. For example,

    ]]>

    will process all item elements that have a glossary parent element and that have a name attribute with value equal to the value of the current node's ref attribute. This is different from

    ]]>

    which means the same as

    ]]>

    and so would process all item elements that have a glossary parent element and that have a name attribute and a ref attribute with the same value.

    It is an error to use the current function in a pattern.

    The unparsed-entity-uri returns the URI of the unparsed entity with the specified name in the same document as the context node (see ). It returns the empty string if there is no such entity.

    The generate-id function returns a string that uniquely identifies the node in the argument node-set that is first in document order. The unique identifier must consist of ASCII alphanumeric characters and must start with an alphabetic character. Thus, the string is syntactically an XML name. An implementation is free to generate an identifier in any convenient way provided that it always generates the same identifier for the same node and that different identifiers are always generated from different nodes. An implementation is under no obligation to generate the same identifiers each time a document is transformed. There is no guarantee that a generated unique identifier will be distinct from any unique IDs specified in the source document. If the argument node-set is empty, the empty string is returned. If the argument is omitted, it defaults to the context node.

    The argument must evaluate to a string that is a QName. The QName is expanded into a name using the namespace declarations in scope for the expression. The system-property function returns an object representing the value of the system property identified by the name. If there is no such system property, the empty string should be returned.

    Implementations must provide the following system properties, which are all in the XSLT namespace:

    xsl:version, a number giving the version of XSLT implemented by the processor; for XSLT processors implementing the version of XSLT specified by this document, this is the number 1.0 xsl:vendor, a string identifying the vendor of the XSLT processor xsl:vendor-url, a string containing a URL identifying the vendor of the XSLT processor; typically this is the host page (home page) of the vendor's Web site.
    Messages

    The xsl:message instruction sends a message in a way that is dependent on the XSLT processor. The content of the xsl:message instruction is a template. The xsl:message is instantiated by instantiating the content to create an XML fragment. This XML fragment is the content of the message.

    An XSLT processor might implement xsl:message by popping up an alert box or by writing to a log file.

    If the terminate attribute has the value yes, then the XSLT processor should terminate processing after sending the message. The default value is no.

    One convenient way to do localization is to put the localized information (message text, etc.) in an XML document, which becomes an additional input file to the stylesheet. For example, suppose messages for a language L are stored in an XML file resources/L.xml in the form:

    A problem was detected. An error was detected. ]]>

    Then a stylesheet could use the following approach to localize messages:

    problem ]]>
    Extensions

    XSLT allows two kinds of extension, extension elements and extension functions.

    This version of XSLT does not provide a mechanism for defining implementations of extensions. Therefore, an XSLT stylesheet that must be portable between XSLT implementations cannot rely on particular extensions being available. XSLT provides mechanisms that allow an XSLT stylesheet to determine whether the XSLT processor by which it is being processed has implementations of particular extensions available, and to specify what should happen if those extensions are not available. If an XSLT stylesheet is careful to make use of these mechanisms, it is possible for it to take advantage of extensions and still work with any XSLT implementation.

    Extension Elements

    The element extension mechanism allows namespaces to be designated as extension namespaces. When a namespace is designated as an extension namespace and an element with a name from that namespace occurs in a template, then the element is treated as an instruction rather than as a literal result element. The namespace determines the semantics of the instruction.

    Since an element that is a child of an xsl:stylesheet element is not occurring in a template, non-XSLT top-level elements are not extension elements as defined here, and nothing in this section applies to them.

    A namespace is designated as an extension namespace by using an extension-element-prefixes attribute on an xsl:stylesheet element or an xsl:extension-element-prefixes attribute on a literal result element or extension element. The value of both these attributes is a whitespace-separated list of namespace prefixes. The namespace bound to each of the prefixes is designated as an extension namespace. It is an error if there is no namespace bound to the prefix on the element bearing the extension-element-prefixes or xsl:extension-element-prefixes attribute. The default namespace (as declared by xmlns) may be designated as an extension namespace by including #default in the list of namespace prefixes. The designation of a namespace as an extension namespace is effective within the subtree of the stylesheet rooted at the element bearing the extension-element-prefixes or xsl:extension-element-prefixes attribute; a subtree rooted at an xsl:stylesheet element does not include any stylesheets imported or included by children of that xsl:stylesheet element.

    If the XSLT processor does not have an implementation of a particular extension element available, then the element-available function must return false for the name of the element. When such an extension element is instantiated, then the XSLT processor must perform fallback for the element as specified in . An XSLT processor must not signal an error merely because a template contains an extension element for which no implementation is available.

    If the XSLT processor has an implementation of a particular extension element available, then the element-available function must return true for the name of the element.

    Extension Functions

    If a FunctionName in a FunctionCall expression is not an NCName (i.e. if it contains a colon), then it is treated as a call to an extension function. The FunctionName is expanded to a name using the namespace declarations from the evaluation context.

    If the XSLT processor does not have an implementation of an extension function of a particular name available, then the function-available function must return false for that name. If such an extension function occurs in an expression and the extension function is actually called, the XSLT processor must signal an error. An XSLT processor must not signal an error merely because an expression contains an extension function for which no implementation is available.

    If the XSLT processor has an implementation of an extension function of a particular name available, then the function-available function must return true for that name. If such an extension is called, then the XSLT processor must call the implementation passing it the function call arguments; the result returned by the implementation is returned as the result of the function call.

    Fallback

    Normally, instantiating an xsl:fallback element does nothing. However, when an XSLT processor performs fallback for an instruction element, if the instruction element has one or more xsl:fallback children, then the content of each of the xsl:fallback children must be instantiated in sequence; otherwise, an error must be signaled. The content of an xsl:fallback element is a template.

    The following functions can be used with the xsl:choose and xsl:if instructions to explicitly control how a stylesheet should behave if particular elements or functions are not available.

    The argument must evaluate to a string that is a QName. The QName is expanded into an expanded-name using the namespace declarations in scope for the expression. The element-available function returns true if and only if the expanded-name is the name of an instruction. If the expanded-name has a namespace URI equal to the XSLT namespace URI, then it refers to an element defined by XSLT. Otherwise, it refers to an extension element. If the expanded-name has a null namespace URI, the element-available function will return false.

    The argument must evaluate to a string that is a QName. The QName is expanded into an expanded-name using the namespace declarations in scope for the expression. The function-available function returns true if and only if the expanded-name is the name of a function in the function library. If the expanded-name has a non-null namespace URI, then it refers to an extension function; otherwise, it refers to a function defined by XPath or XSLT.

    Output

    An XSLT processor may output the result tree as a sequence of bytes, although it is not required to be able to do so (see ). The xsl:output element allows stylesheet authors to specify how they wish the result tree to be output. If an XSLT processor outputs the result tree, it should do so as specified by the xsl:output element; however, it is not required to do so.

    The xsl:output element is only allowed as a top-level element.

    The method attribute on xsl:output identifies the overall method that should be used for outputting the result tree. The value must be a QName. If the QName does not have a prefix, then it identifies a method specified in this document and must be one of xml, html or text. If the QName has a prefix, then the QName is expanded into an expanded-name as described in ; the expanded-name identifies the output method; the behavior in this case is not specified by this document.

    The default for the method attribute is chosen as follows. If

    the root node of the result tree has an element child,

    the expanded-name of the first element child of the root node (i.e. the document element) of the result tree has local part html (in any combination of upper and lower case) and a null namespace URI, and

    any text nodes preceding the first element child of the root node of the result tree contain only whitespace characters,

    then the default output method is html; otherwise, the default output method is xml. The default output method should be used if there are no xsl:output elements or if none of the xsl:output elements specifies a value for the method attribute.

    The other attributes on xsl:output provide parameters for the output method. The following attributes are allowed:

    version specifies the version of the output method

    indent specifies whether the XSLT processor may add additional whitespace when outputting the result tree; the value must be yes or no

    encoding specifies the preferred character encoding that the XSLT processor should use to encode sequences of characters as sequences of bytes; the value of the attribute should be treated case-insensitively; the value must contain only characters in the range #x21 to #x7E (i.e. printable ASCII characters); the value should either be a charset registered with the Internet Assigned Numbers Authority , or start with X-

    media-type specifies the media type (MIME content type) of the data that results from outputting the result tree; the charset parameter should not be specified explicitly; instead, when the top-level media type is text, a charset parameter should be added according to the character encoding actually used by the output method

    doctype-system specifies the system identifier to be used in the document type declaration

    doctype-public specifies the public identifier to be used in the document type declaration

    omit-xml-declaration specifies whether the XSLT processor should output an XML declaration; the value must be yes or no

    standalone specifies whether the XSLT processor should output a standalone document declaration; the value must be yes or no

    cdata-section-elements specifies a list of the names of elements whose text node children should be output using CDATA sections

    The detailed semantics of each attribute will be described separately for each output method for which it is applicable. If the semantics of an attribute are not described for an output method, then it is not applicable to that output method.

    A stylesheet may contain multiple xsl:output elements and may include or import stylesheets that also contain xsl:output elements. All the xsl:output elements occurring in a stylesheet are merged into a single effective xsl:output element. For the cdata-section-elements attribute, the effective value is the union of the specified values. For other attributes, the effective value is the specified value with the highest import precedence. It is an error if there is more than one such value for an attribute. An XSLT processor may signal the error; if it does not signal the error, if should recover by using the value that occurs last in the stylesheet. The values of attributes are defaulted after the xsl:output elements have been merged; different output methods may have different default values for an attribute.

    XML Output Method

    The xml output method outputs the result tree as a well-formed XML external general parsed entity. If the root node of the result tree has a single element node child and no text node children, then the entity should also be a well-formed XML document entity. When the entity is referenced within a trivial XML document wrapper like this

    entity-URI ]> &e;]]>

    where entity-URI is a URI for the entity, then the wrapper document as a whole should be a well-formed XML document conforming to the XML Namespaces Recommendation . In addition, the output should be such that if a new tree was constructed by parsing the wrapper as an XML document as specified in , and then removing the document element, making its children instead be children of the root node, then the new tree would be the same as the result tree, with the following possible exceptions:

    The order of attributes in the two trees may be different.

    The new tree may contain namespace nodes that were not present in the result tree.

    An XSLT processor may need to add namespace declarations in the course of outputting the result tree as XML.

    If the XSLT processor generated a document type declaration because of the doctype-system attribute, then the above requirements apply to the entity with the generated document type declaration removed.

    The version attribute specifies the version of XML to be used for outputting the result tree. If the XSLT processor does not support this version of XML, it should use a version of XML that it does support. The version output in the XML declaration (if an XML declaration is output) should correspond to the version of XML that the processor used for outputting the result tree. The value of the version attribute should match the VersionNum production of the XML Recommendation . The default value is 1.0.

    The encoding attribute specifies the preferred encoding to use for outputting the result tree. XSLT processors are required to respect values of UTF-8 and UTF-16. For other values, if the XSLT processor does not support the specified encoding it may signal an error; if it does not signal an error it should use UTF-8 or UTF-16 instead. The XSLT processor must not use an encoding whose name does not match the EncName production of the XML Recommendation . If no encoding attribute is specified, then the XSLT processor should use either UTF-8 or UTF-16. It is possible that the result tree will contain a character that cannot be represented in the encoding that the XSLT processor is using for output. In this case, if the character occurs in a context where XML recognizes character references (i.e. in the value of an attribute node or text node), then the character should be output as a character reference; otherwise (for example if the character occurs in the name of an element) the XSLT processor should signal an error.

    If the indent attribute has the value yes, then the xml output method may output whitespace in addition to the whitespace in the result tree (possibly based on whitespace stripped from either the source document or the stylesheet) in order to indent the result nicely; if the indent attribute has the value no, it should not output any additional whitespace. The default value is no. The xml output method should use an algorithm to output additional whitespace that ensures that the result if whitespace were to be stripped from the output using the process described in with the set of whitespace-preserving elements consisting of just xsl:text would be the same when additional whitespace is output as when additional whitespace is not output.

    It is usually not safe to use indent="yes" with document types that include element types with mixed content.

    The cdata-section-elements attribute contains a whitespace-separated list of QNames. Each QName is expanded into an expanded-name using the namespace declarations in effect on the xsl:output element in which the QName occurs; if there is a default namespace, it is used for QNames that do not have a prefix. The expansion is performed before the merging of multiple xsl:output elements into a single effective xsl:output element. If the expanded-name of the parent of a text node is a member of the list, then the text node should be output as a CDATA section. For example,

    ]]>

    would cause a literal result element written in the stylesheet as

    <foo>]]>

    or as

    <example><![CDATA[<foo>]]></example>

    to be output as

    <example><![CDATA[<foo>]]></example>

    If the text node contains the sequence of characters ]]>, then the currently open CDATA section should be closed following the ]] and a new CDATA section opened before the >. For example, a literal result element written in the stylesheet as

    <example>]]&gt;</example>

    would be output as

    <example><![CDATA[]]]]><![CDATA[>]]></example>

    If the text node contains a character that is not representable in the character encoding being used to output the result tree, then the currently open CDATA section should be closed before the character, the character should be output using a character reference or entity reference, and a new CDATA section should be opened for any further characters in the text node.

    CDATA sections should not be used except for text nodes that the cdata-section-elements attribute explicitly specifies should be output using CDATA sections.

    The xml output method should output an XML declaration unless the omit-xml-declaration attribute has the value yes. The XML declaration should include both version information and an encoding declaration. If the standalone attribute is specified, it should include a standalone document declaration with the same value as the value as the value of the standalone attribute. Otherwise, it should not include a standalone document declaration; this ensures that it is both a XML declaration (allowed at the beginning of a document entity) and a text declaration (allowed at the beginning of an external general parsed entity).

    If the doctype-system attribute is specified, the xml output method should output a document type declaration immediately before the first element. The name following <!DOCTYPE should be the name of the first element. If doctype-public attribute is also specified, then the xml output method should output PUBLIC followed by the public identifier and then the system identifier; otherwise, it should output SYSTEM followed by the system identifier. The internal subset should be empty. The doctype-public attribute should be ignored unless the doctype-system attribute is specified.

    The media-type attribute is applicable for the xml output method. The default value for the media-type attribute is text/xml.

    HTML Output Method

    The html output method outputs the result tree as HTML; for example,

    <xsl:stylesheet version="1.0" xmlns:xsl="&XSLT.ns;"> ... ]]>

    The version attribute indicates the version of the HTML. The default value is 4.0, which specifies that the result should be output as HTML conforming to the HTML 4.0 Recommendation .

    The html output method should not output an element differently from the xml output method unless the expanded-name of the element has a null namespace URI; an element whose expanded-name has a non-null namespace URI should be output as XML. If the expanded-name of the element has a null namespace URI, but the local part of the expanded-name is not recognized as the name of an HTML element, the element should output in the same way as a non-empty, inline element such as span.

    The html output method should not output an end-tag for empty elements. For HTML 4.0, the empty elements are area, base, basefont, br, col, frame, hr, img, input, isindex, link, meta and param. For example, an element written as <br/> or <br></br> in the stylesheet should be output as <br>.

    The html output method should recognize the names of HTML elements regardless of case. For example, elements named br, BR or Br should all be recognized as the HTML br element and output without an end-tag.

    The html output method should not perform escaping for the content of the script and style elements. For example, a literal result element written in the stylesheet as

    if (a < b) foo()]]>

    or

    ]]>

    should be output as

    if (a < b) foo()]]>

    The html output method should not escape < characters occurring in attribute values.

    If the indent attribute has the value yes, then the html output method may add or remove whitespace as it outputs the result tree, so long as it does not change how an HTML user agent would render the output. The default value is yes.

    The html output method should escape non-ASCII characters in URI attribute values using the method recommended in Section B.2.1 of the HTML 4.0 Recommendation.

    The html output method may output a character using a character entity reference, if one is defined for it in the version of HTML that the output method is using.

    The html output method should terminate processing instructions with > rather than ?>.

    The html output method should output boolean attributes (that is attributes with only a single allowed value that is equal to the name of the attribute) in minimized form. For example, a start-tag written in the stylesheet as

    ]]>

    should be output as

    ]]>

    The html output method should not escape a & character occurring in an attribute value immediately followed by a { character (see Section B.7.1 of the HTML 4.0 Recommendation). For example, a start-tag written in the stylesheet as

    ]]>

    should be output as

    ]]>

    The encoding attribute specifies the preferred encoding to be used. If there is a HEAD element, then the html output method should add a META element immediately after the start-tag of the HEAD element specifying the character encoding actually used. For example,

    ...]]>

    It is possible that the result tree will contain a character that cannot be represented in the encoding that the XSLT processor is using for output. In this case, if the character occurs in a context where HTML recognizes character references, then the character should be output as a character entity reference or decimal numeric character reference; otherwise (for example, in a script or style element or in a comment), the XSLT processor should signal an error.

    If the doctype-public or doctype-system attributes are specified, then the html output method should output a document type declaration immediately before the first element. The name following <!DOCTYPE should be HTML or html. If the doctype-public attribute is specified, then the output method should output PUBLIC followed by the specified public identifier; if the doctype-system attribute is also specified, it should also output the specified system identifier following the public identifier. If the doctype-system attribute is specified but the doctype-public attribute is not specified, then the output method should output SYSTEM followed by the specified system identifier.

    The media-type attribute is applicable for the html output method. The default value is text/html.

    Text Output Method

    The text output method outputs the result tree by outputting the string-value of every text node in the result tree in document order without any escaping.

    The media-type attribute is applicable for the text output method. The default value for the media-type attribute is text/plain.

    The encoding attribute identifies the encoding that the text output method should use to convert sequences of characters to sequences of bytes. The default is system-dependent. If the result tree contains a character that cannot be represented in the encoding that the XSLT processor is using for output, the XSLT processor should signal an error.

    Disabling Output Escaping

    Normally, the xml output method escapes & and < (and possibly other characters) when outputting text nodes. This ensures that the output is well-formed XML. However, it is sometimes convenient to be able to produce output that is almost, but not quite well-formed XML; for example, the output may include ill-formed sections which are intended to be transformed into well-formed XML by a subsequent non-XML aware process. For this reason, XSLT provides a mechanism for disabling output escaping. An xsl:value-of or xsl:text element may have a disable-output-escaping attribute; the allowed values are yes or no; the default is no; if the value is yes, then a text node generated by instantiating the xsl:value-of or xsl:text element should be output without any escaping. For example,

    <]]>

    should generate the single character <.

    It is an error for output escaping to be disabled for a text node that is used for something other than a text node in the result tree. Thus, it is an error to disable output escaping for an xsl:value-of or xsl:text element that is used to generate the string-value of a comment, processing instruction or attribute node; it is also an error to convert a result tree fragment to a number or a string if the result tree fragment contains a text node for which escaping was disabled. In both cases, an XSLT processor may signal the error; if it does not signal the error, it must recover by ignoring the disable-output-escaping attribute.

    The disable-output-escaping attribute may be used with the html output method as well as with the xml output method. The text output method ignores the disable-output-escaping attribute, since it does not perform any output escaping.

    An XSLT processor will only be able to disable output escaping if it controls how the result tree is output. This may not always be the case. For example, the result tree may be used as the source tree for another XSLT transformation instead of being output. An XSLT processor is not required to support disabling output escaping. If an xsl:value-of or xsl:text specifies that output escaping should be disabled and the XSLT processor does not support this, the XSLT processor may signal an error; if it does not signal an error, it must recover by not disabling output escaping.

    If output escaping is disabled for a character that is not representable in the encoding that the XSLT processor is using for output, then the XSLT processor may signal an error; if it does not signal an error, it must recover by not disabling output escaping.

    Since disabling output escaping may not work with all XSLT processors and can result in XML that is not well-formed, it should be used only when there is no alternative.

    Conformance

    A conforming XSLT processor must be able to use a stylesheet to transform a source tree into a result tree as specified in this document. A conforming XSLT processor need not be able to output the result in XML or in any other form.

    Vendors of XSLT processors are strongly encouraged to provide a way to verify that their processor is behaving conformingly by allowing the result tree to be output as XML or by providing access to the result tree through a standard API such as the DOM or SAX.

    A conforming XSLT processor must signal any errors except for those that this document specifically allows an XSLT processor not to signal. A conforming XSLT processor may but need not recover from any errors that it signals.

    A conforming XSLT processor may impose limits on the processing resources consumed by the processing of a stylesheet.

    Notation

    The specification of each XSLT-defined element type is preceded by a summary of its syntax in the form of a model for elements of that element type. The meaning of syntax summary notation is as follows:

    An attribute is required if and only if its name is in bold.

    The string that occurs in the place of an attribute value specifies the allowed values of the attribute. If this is surrounded by curly braces, then the attribute value is treated as an attribute value template, and the string occurring within curly braces specifies the allowed values of the result of instantiating the attribute value template. Alternative allowed values are separated by |. A quoted string indicates a value equal to that specific string. An unquoted, italicized name specifies a particular type of value.

    If the element is allowed not to be empty, then the element contains a comment specifying the allowed content. The allowed content is specified in a similar way to an element type declaration in XML; template means that any mixture of text nodes, literal result elements, extension elements, and XSLT elements from the instruction category is allowed; top-level-elements means that any mixture of XSLT elements from the top-level-element category is allowed.

    The element is prefaced by comments indicating if it belongs to the instruction category or top-level-element category or both. The category of an element just affects whether it is allowed in the content of elements that allow a template or top-level-elements.

    References Normative References World Wide Web Consortium. Extensible Markup Language (XML) 1.0. W3C Recommendation. See http://www.w3.org/TR/1998/REC-xml-19980210 World Wide Web Consortium. Namespaces in XML. W3C Recommendation. See http://www.w3.org/TR/REC-xml-names World Wide Web Consortium. XML Path Language. W3C Recommendation. See http://www.w3.org/TR/xpath Other References World Wide Web Consortium. Cascading Style Sheets, level 2 (CSS2). W3C Recommendation. See http://www.w3.org/TR/1998/REC-CSS2-19980512 International Organization for Standardization, International Electrotechnical Commission. ISO/IEC 10179:1996. Document Style Semantics and Specification Language (DSSSL). International Standard. World Wide Web Consortium. HTML 4.0 specification. W3C Recommendation. See http://www.w3.org/TR/REC-html40 Internet Assigned Numbers Authority. Character Sets. See ftp://ftp.isi.edu/in-notes/iana/assignments/character-sets. N. Freed, J. Postel. IANA Charset Registration Procedures. IETF RFC 2278. See http://www.ietf.org/rfc/rfc2278.txt. E. Whitehead, M. Murata. XML Media Types. IETF RFC 2376. See http://www.ietf.org/rfc/rfc2376.txt. T. Berners-Lee, R. Fielding, and L. Masinter. Uniform Resource Identifiers (URI): Generic Syntax. IETF RFC 2396. See http://www.ietf.org/rfc/rfc2396.txt. Unicode Consortium. Unicode Technical Report #10. Unicode Collation Algorithm. Unicode Technical Report. See http://www.unicode.org/unicode/reports/tr10/index.html. World Wide Web Consortium. XHTML 1.0: The Extensible HyperText Markup Language. W3C Proposed Recommendation. See http://www.w3.org/TR/xhtml1 World Wide Web Consortium. XML Pointer Language (XPointer). W3C Working Draft. See http://www.w3.org/TR/xptr World Wide Web Consortium. Associating stylesheets with XML documents. W3C Recommendation. See http://www.w3.org/TR/xml-stylesheet World Wide Web Consortium. Extensible Stylesheet Language (XSL). W3C Working Draft. See http://www.w3.org/TR/WD-xsl Element Syntax Summary DTD Fragment for XSLT Stylesheets

    This DTD Fragment is not normative because XML 1.0 DTDs do not support XML Namespaces and thus cannot correctly describe the allowed structure of an XSLT stylesheet.

    The following entity can be used to construct a DTD for XSLT stylesheets that create instances of a particular result DTD. Before referencing the entity, the stylesheet DTD must define a result-elements parameter entity listing the allowed result element types. For example:

    ]]>

    Such result elements should be declared to have xsl:use-attribute-sets and xsl:extension-element-prefixes attributes. The following entity declares the result-element-atts parameter for this purpose. The content that XSLT allows for result elements is the same as it allows for the XSLT elements that are declared in the following entity with a content model of %template;. The DTD may use a more restrictive content model than %template; to reflect the constraints of the result DTD.

    The DTD may define the non-xsl-top-level parameter entity to allow additional top-level elements from namespaces other than the XSLT namespace.

    The use of the xsl: prefix in this DTD does not imply that XSLT stylesheets are required to use this prefix. Any of the elements declared in this DTD may have attributes whose name starts with xmlns: or is equal to xmlns in addition to the attributes declared in this DTD.

    &XSLT.ns; ]]>
    Examples Document Example

    This example is a stylesheet for transforming documents that conform to a simple DTD into XHTML . The DTD is:

    ]]>

    The stylesheet is:

    <xsl:stylesheet version="1.0" xmlns:xsl="&XSLT.ns;" xmlns="&XHTML.ns;"> <xsl:value-of select="title"/>

    NOTE:

    ]]>

    With the following input document

    Document Title Chapter Title
    Section Title This is a test. This is a note.
    Another Section Title This is another test. This is another note.
    ]]>

    it would produce the following result

    <?xml version="1.0" encoding="iso-8859-1"?> <html xmlns="&XHTML.ns;"> Document Title

    Document Title

    Chapter Title

    Section Title

    This is a test.

    NOTE: This is a note.

    Another Section Title

    This is another test.

    NOTE: This is another note.

    ]]>
    Data Example

    This is an example of transforming some data represented in XML using three different XSLT stylesheets to produce three different representations of the data, HTML, SVG and VRML.

    The input data is:

    10 9 7 4 3 4 6 -1.5 2 ]]>

    The following stylesheet, which uses the simplified syntax described in , transforms the data into HTML:

    <html xsl:version="1.0" xmlns:xsl="&XSLT.ns;" Sales Results By Division
    Division Revenue Growth Bonus
    color:red
    ]]>

    The HTML output is:

    Sales Results By Division
    DivisionRevenueGrowthBonus
    North1097
    West6-1.52
    South434
    ]]>

    The following stylesheet transforms the data into SVG:

    <xsl:stylesheet version="1.0" xmlns:xsl="&XSLT.ns;" Revenue Division ]]>

    The SVG output is:

    Revenue Division North 10 South 4 West 6 ]]>

    The following stylesheet transforms the data into VRML:

    <xsl:stylesheet version="1.0" xmlns:xsl="&XSLT.ns;"> #VRML V2.0 utf8 # externproto definition of a single bar element EXTERNPROTO bar [ field SFInt32 x field SFInt32 y field SFInt32 z field SFString name ] "http://www.vrml.org/WorkingGroups/dbwork/barProto.wrl" # inline containing the graph axes Inline { url "http://www.vrml.org/WorkingGroups/dbwork/barAxes.wrl" } bar { x y z name "" } ]]>

    The VRML output is:

    Acknowledgements

    The following have contributed to authoring this draft:

    Daniel Lipkin, Saba Jonathan Marsh, Microsoft Henry Thompson, University of Edinburgh Norman Walsh, Arbortext Steve Zilles, Adobe

    This specification was developed and approved for publication by the W3C XSL Working Group (WG). WG approval of this specification does not necessarily imply that all WG members voted for its approval. The current members of the XSL WG are:

    Sharon Adler IBM Co-Chair Anders Berglund IBM Perin Blanchard Novell Scott Boag Lotus Larry Cable Sun Jeff Caruso Bitstream James Clark Peter Danielsen Bell Labs Don Day IBM Stephen Deach Adobe Dwayne Dicks SoftQuad Andrew Greene Bitstream Paul Grosso Arbortext Eduardo Gutentag Sun Juliane Harbarth Software AG Mickey Kimchi Enigma Chris Lilley W3C Chris Maden Exemplary Technologies Jonathan Marsh Microsoft Alex Milowski Lexica Steve Muench Oracle Scott Parnell Xerox Vincent Quint W3C Dan Rapp Novell Gregg Reynolds Datalogics Jonathan Robie Software AG Mark Scardina Oracle Henry Thompson University of Edinburgh Philip Wadler Bell Labs Norman Walsh Arbortext Sanjiva Weerawarana IBM Steve Zilles Adobe Co-Chair
    Changes from Proposed Recommendation

    The following are the changes since the Proposed Recommendation:

    The xsl:version attribute is required on a literal result element used as a stylesheet (see ).

    The data-type attribute on xsl:sort can use a prefixed name to specify a data-type not defined by XSLT (see ).

    Features under Consideration for Future Versions of XSLT

    The following features are under consideration for versions of XSLT after XSLT 1.0:

    a conditional expression;

    support for XML Schema datatypes and archetypes;

    support for something like style rules in the original XSL submission;

    an attribute to control the default namespace for names occurring in XSLT attributes;

    support for entity references;

    support for DTDs in the data model;

    support for notations in the data model;

    a way to get back from an element to the elements that reference it (e.g. by IDREF attributes);

    an easier way to get an ID or key in another document;

    support for regular expressions for matching against any or all of text nodes, attribute values, attribute names, element type names;

    case-insensitive comparisons;

    normalization of strings before comparison, for example for compatibility characters;

    a function string resolve(node-set) function that treats the value of the argument as a relative URI and turns it into an absolute URI using the base URI of the node;

    multiple result documents;

    defaulting the select attribute on xsl:value-of to the current node;

    an attribute on xsl:attribute to control how the attribute value is normalized;

    additional attributes on xsl:sort to provide further control over sorting, such as relative order of scripts;

    a way to put the text of a resource identified by a URI into the result tree;

    allow unions in steps (e.g. foo/(bar|baz));

    allow for result tree fragments all operations that are allowed for node-sets;

    a way to group together consecutive nodes having duplicate subelements or attributes;

    features to make handling of the HTML style attribute more convenient.

    features to make handling of the HTML style attribute more convenient.

    tdom-0.9.6-src/tests/data/i18n_2.xml0000644000175000017500000000027715025767703015563 0ustar rolfrolf german umlauts: tdom-0.9.6-src/tests/data/domCmd2.dtd0000644000175000017500000000005415025767703016014 0ustar rolfrolf tdom-0.9.6-src/tests/data/i18n_1.xml0000644000175000017500000000004215025767703015550 0ustar rolfrolfабвгдежзий tdom-0.9.6-src/tests/data/dtd-6.6.dtd0000644000175000017500000000014415025767703015611 0ustar rolfrolf ]]> tdom-0.9.6-src/tests/data/dtd-6.1.dtd0000644000175000017500000000005215025767703015602 0ustar rolfrolf ]]> tdom-0.9.6-src/tests/data/dtd-6.2.dtd0000644000175000017500000000001715025767703015604 0ustar rolfrolf tdom-0.9.6-src/tests/data/htmlmathml.json0000644000175000017500000014222315025767703017101 0ustar rolfrolf { "characters": { "AElig": "\u00C6", "AMP": "\u0026", "Aacute": "\u00C1", "Abreve": "\u0102", "Acirc": "\u00C2", "Acy": "\u0410", "Afr": "\uD835\uDD04", "Agrave": "\u00C0", "Alpha": "\u0391", "Amacr": "\u0100", "And": "\u2A53", "Aogon": "\u0104", "Aopf": "\uD835\uDD38", "ApplyFunction": "\u2061", "Aring": "\u00C5", "Ascr": "\uD835\uDC9C", "Assign": "\u2254", "Atilde": "\u00C3", "Auml": "\u00C4", "Backslash": "\u2216", "Barv": "\u2AE7", "Barwed": "\u2306", "Bcy": "\u0411", "Because": "\u2235", "Bernoullis": "\u212C", "Beta": "\u0392", "Bfr": "\uD835\uDD05", "Bopf": "\uD835\uDD39", "Breve": "\u02D8", "Bscr": "\u212C", "Bumpeq": "\u224E", "CHcy": "\u0427", "COPY": "\u00A9", "Cacute": "\u0106", "Cap": "\u22D2", "CapitalDifferentialD": "\u2145", "Cayleys": "\u212D", "Ccaron": "\u010C", "Ccedil": "\u00C7", "Ccirc": "\u0108", "Cconint": "\u2230", "Cdot": "\u010A", "Cedilla": "\u00B8", "CenterDot": "\u00B7", "Cfr": "\u212D", "Chi": "\u03A7", "CircleDot": "\u2299", "CircleMinus": "\u2296", "CirclePlus": "\u2295", "CircleTimes": "\u2297", "ClockwiseContourIntegral": "\u2232", "CloseCurlyDoubleQuote": "\u201D", "CloseCurlyQuote": "\u2019", "Colon": "\u2237", "Colone": "\u2A74", "Congruent": "\u2261", "Conint": "\u222F", "ContourIntegral": "\u222E", "Copf": "\u2102", "Coproduct": "\u2210", "CounterClockwiseContourIntegral": "\u2233", "Cross": "\u2A2F", "Cscr": "\uD835\uDC9E", "Cup": "\u22D3", "CupCap": "\u224D", "DD": "\u2145", "DDotrahd": "\u2911", "DJcy": "\u0402", "DScy": "\u0405", "DZcy": "\u040F", "Dagger": "\u2021", "Darr": "\u21A1", "Dashv": "\u2AE4", "Dcaron": "\u010E", "Dcy": "\u0414", "Del": "\u2207", "Delta": "\u0394", "Dfr": "\uD835\uDD07", "DiacriticalAcute": "\u00B4", "DiacriticalDot": "\u02D9", "DiacriticalDoubleAcute": "\u02DD", "DiacriticalGrave": "\u0060", "DiacriticalTilde": "\u02DC", "Diamond": "\u22C4", "DifferentialD": "\u2146", "Dopf": "\uD835\uDD3B", "Dot": "\u00A8", "DotDot": " \u20DC", "DotEqual": "\u2250", "DoubleContourIntegral": "\u222F", "DoubleDot": "\u00A8", "DoubleDownArrow": "\u21D3", "DoubleLeftArrow": "\u21D0", "DoubleLeftRightArrow": "\u21D4", "DoubleLeftTee": "\u2AE4", "DoubleLongLeftArrow": "\u27F8", "DoubleLongLeftRightArrow": "\u27FA", "DoubleLongRightArrow": "\u27F9", "DoubleRightArrow": "\u21D2", "DoubleRightTee": "\u22A8", "DoubleUpArrow": "\u21D1", "DoubleUpDownArrow": "\u21D5", "DoubleVerticalBar": "\u2225", "DownArrow": "\u2193", "DownArrowBar": "\u2913", "DownArrowUpArrow": "\u21F5", "DownBreve": " \u0311", "DownLeftRightVector": "\u2950", "DownLeftTeeVector": "\u295E", "DownLeftVector": "\u21BD", "DownLeftVectorBar": "\u2956", "DownRightTeeVector": "\u295F", "DownRightVector": "\u21C1", "DownRightVectorBar": "\u2957", "DownTee": "\u22A4", "DownTeeArrow": "\u21A7", "Downarrow": "\u21D3", "Dscr": "\uD835\uDC9F", "Dstrok": "\u0110", "ENG": "\u014A", "ETH": "\u00D0", "Eacute": "\u00C9", "Ecaron": "\u011A", "Ecirc": "\u00CA", "Ecy": "\u042D", "Edot": "\u0116", "Efr": "\uD835\uDD08", "Egrave": "\u00C8", "Element": "\u2208", "Emacr": "\u0112", "EmptySmallSquare": "\u25FB", "EmptyVerySmallSquare": "\u25AB", "Eogon": "\u0118", "Eopf": "\uD835\uDD3C", "Epsilon": "\u0395", "Equal": "\u2A75", "EqualTilde": "\u2242", "Equilibrium": "\u21CC", "Escr": "\u2130", "Esim": "\u2A73", "Eta": "\u0397", "Euml": "\u00CB", "Exists": "\u2203", "ExponentialE": "\u2147", "Fcy": "\u0424", "Ffr": "\uD835\uDD09", "FilledSmallSquare": "\u25FC", "FilledVerySmallSquare": "\u25AA", "Fopf": "\uD835\uDD3D", "ForAll": "\u2200", "Fouriertrf": "\u2131", "Fscr": "\u2131", "GJcy": "\u0403", "GT": "\u003E", "Gamma": "\u0393", "Gammad": "\u03DC", "Gbreve": "\u011E", "Gcedil": "\u0122", "Gcirc": "\u011C", "Gcy": "\u0413", "Gdot": "\u0120", "Gfr": "\uD835\uDD0A", "Gg": "\u22D9", "Gopf": "\uD835\uDD3E", "GreaterEqual": "\u2265", "GreaterEqualLess": "\u22DB", "GreaterFullEqual": "\u2267", "GreaterGreater": "\u2AA2", "GreaterLess": "\u2277", "GreaterSlantEqual": "\u2A7E", "GreaterTilde": "\u2273", "Gscr": "\uD835\uDCA2", "Gt": "\u226B", "HARDcy": "\u042A", "Hacek": "\u02C7", "Hat": "\u005E", "Hcirc": "\u0124", "Hfr": "\u210C", "HilbertSpace": "\u210B", "Hopf": "\u210D", "HorizontalLine": "\u2500", "Hscr": "\u210B", "Hstrok": "\u0126", "HumpDownHump": "\u224E", "HumpEqual": "\u224F", "IEcy": "\u0415", "IJlig": "\u0132", "IOcy": "\u0401", "Iacute": "\u00CD", "Icirc": "\u00CE", "Icy": "\u0418", "Idot": "\u0130", "Ifr": "\u2111", "Igrave": "\u00CC", "Im": "\u2111", "Imacr": "\u012A", "ImaginaryI": "\u2148", "Implies": "\u21D2", "Int": "\u222C", "Integral": "\u222B", "Intersection": "\u22C2", "InvisibleComma": "\u2063", "InvisibleTimes": "\u2062", "Iogon": "\u012E", "Iopf": "\uD835\uDD40", "Iota": "\u0399", "Iscr": "\u2110", "Itilde": "\u0128", "Iukcy": "\u0406", "Iuml": "\u00CF", "Jcirc": "\u0134", "Jcy": "\u0419", "Jfr": "\uD835\uDD0D", "Jopf": "\uD835\uDD41", "Jscr": "\uD835\uDCA5", "Jsercy": "\u0408", "Jukcy": "\u0404", "KHcy": "\u0425", "KJcy": "\u040C", "Kappa": "\u039A", "Kcedil": "\u0136", "Kcy": "\u041A", "Kfr": "\uD835\uDD0E", "Kopf": "\uD835\uDD42", "Kscr": "\uD835\uDCA6", "LJcy": "\u0409", "LT": "\u003C", "Lacute": "\u0139", "Lambda": "\u039B", "Lang": "\u27EA", "Laplacetrf": "\u2112", "Larr": "\u219E", "Lcaron": "\u013D", "Lcedil": "\u013B", "Lcy": "\u041B", "LeftAngleBracket": "\u27E8", "LeftArrow": "\u2190", "LeftArrowBar": "\u21E4", "LeftArrowRightArrow": "\u21C6", "LeftCeiling": "\u2308", "LeftDoubleBracket": "\u27E6", "LeftDownTeeVector": "\u2961", "LeftDownVector": "\u21C3", "LeftDownVectorBar": "\u2959", "LeftFloor": "\u230A", "LeftRightArrow": "\u2194", "LeftRightVector": "\u294E", "LeftTee": "\u22A3", "LeftTeeArrow": "\u21A4", "LeftTeeVector": "\u295A", "LeftTriangle": "\u22B2", "LeftTriangleBar": "\u29CF", "LeftTriangleEqual": "\u22B4", "LeftUpDownVector": "\u2951", "LeftUpTeeVector": "\u2960", "LeftUpVector": "\u21BF", "LeftUpVectorBar": "\u2958", "LeftVector": "\u21BC", "LeftVectorBar": "\u2952", "Leftarrow": "\u21D0", "Leftrightarrow": "\u21D4", "LessEqualGreater": "\u22DA", "LessFullEqual": "\u2266", "LessGreater": "\u2276", "LessLess": "\u2AA1", "LessSlantEqual": "\u2A7D", "LessTilde": "\u2272", "Lfr": "\uD835\uDD0F", "Ll": "\u22D8", "Lleftarrow": "\u21DA", "Lmidot": "\u013F", "LongLeftArrow": "\u27F5", "LongLeftRightArrow": "\u27F7", "LongRightArrow": "\u27F6", "Longleftarrow": "\u27F8", "Longleftrightarrow": "\u27FA", "Longrightarrow": "\u27F9", "Lopf": "\uD835\uDD43", "LowerLeftArrow": "\u2199", "LowerRightArrow": "\u2198", "Lscr": "\u2112", "Lsh": "\u21B0", "Lstrok": "\u0141", "Lt": "\u226A", "Map": "\u2905", "Mcy": "\u041C", "MediumSpace": "\u205F", "Mellintrf": "\u2133", "Mfr": "\uD835\uDD10", "MinusPlus": "\u2213", "Mopf": "\uD835\uDD44", "Mscr": "\u2133", "Mu": "\u039C", "NJcy": "\u040A", "Nacute": "\u0143", "Ncaron": "\u0147", "Ncedil": "\u0145", "Ncy": "\u041D", "NegativeMediumSpace": "\u200B", "NegativeThickSpace": "\u200B", "NegativeThinSpace": "\u200B", "NegativeVeryThinSpace": "\u200B", "NestedGreaterGreater": "\u226B", "NestedLessLess": "\u226A", "NewLine": "\u000A", "Nfr": "\uD835\uDD11", "NoBreak": "\u2060", "NonBreakingSpace": "\u00A0", "Nopf": "\u2115", "Not": "\u2AEC", "NotCongruent": "\u2262", "NotCupCap": "\u226D", "NotDoubleVerticalBar": "\u2226", "NotElement": "\u2209", "NotEqual": "\u2260", "NotEqualTilde": "\u2242\u0338", "NotExists": "\u2204", "NotGreater": "\u226F", "NotGreaterEqual": "\u2271", "NotGreaterFullEqual": "\u2267\u0338", "NotGreaterGreater": "\u226B\u0338", "NotGreaterLess": "\u2279", "NotGreaterSlantEqual": "\u2A7E\u0338", "NotGreaterTilde": "\u2275", "NotHumpDownHump": "\u224E\u0338", "NotHumpEqual": "\u224F\u0338", "NotLeftTriangle": "\u22EA", "NotLeftTriangleBar": "\u29CF\u0338", "NotLeftTriangleEqual": "\u22EC", "NotLess": "\u226E", "NotLessEqual": "\u2270", "NotLessGreater": "\u2278", "NotLessLess": "\u226A\u0338", "NotLessSlantEqual": "\u2A7D\u0338", "NotLessTilde": "\u2274", "NotNestedGreaterGreater": "\u2AA2\u0338", "NotNestedLessLess": "\u2AA1\u0338", "NotPrecedes": "\u2280", "NotPrecedesEqual": "\u2AAF\u0338", "NotPrecedesSlantEqual": "\u22E0", "NotReverseElement": "\u220C", "NotRightTriangle": "\u22EB", "NotRightTriangleBar": "\u29D0\u0338", "NotRightTriangleEqual": "\u22ED", "NotSquareSubset": "\u228F\u0338", "NotSquareSubsetEqual": "\u22E2", "NotSquareSuperset": "\u2290\u0338", "NotSquareSupersetEqual": "\u22E3", "NotSubset": "\u2282\u20D2", "NotSubsetEqual": "\u2288", "NotSucceeds": "\u2281", "NotSucceedsEqual": "\u2AB0\u0338", "NotSucceedsSlantEqual": "\u22E1", "NotSucceedsTilde": "\u227F\u0338", "NotSuperset": "\u2283\u20D2", "NotSupersetEqual": "\u2289", "NotTilde": "\u2241", "NotTildeEqual": "\u2244", "NotTildeFullEqual": "\u2247", "NotTildeTilde": "\u2249", "NotVerticalBar": "\u2224", "Nscr": "\uD835\uDCA9", "Ntilde": "\u00D1", "Nu": "\u039D", "OElig": "\u0152", "Oacute": "\u00D3", "Ocirc": "\u00D4", "Ocy": "\u041E", "Odblac": "\u0150", "Ofr": "\uD835\uDD12", "Ograve": "\u00D2", "Omacr": "\u014C", "Omega": "\u03A9", "Omicron": "\u039F", "Oopf": "\uD835\uDD46", "OpenCurlyDoubleQuote": "\u201C", "OpenCurlyQuote": "\u2018", "Or": "\u2A54", "Oscr": "\uD835\uDCAA", "Oslash": "\u00D8", "Otilde": "\u00D5", "Otimes": "\u2A37", "Ouml": "\u00D6", "OverBar": "\u203E", "OverBrace": "\u23DE", "OverBracket": "\u23B4", "OverParenthesis": "\u23DC", "PartialD": "\u2202", "Pcy": "\u041F", "Pfr": "\uD835\uDD13", "Phi": "\u03A6", "Pi": "\u03A0", "PlusMinus": "\u00B1", "Poincareplane": "\u210C", "Popf": "\u2119", "Pr": "\u2ABB", "Precedes": "\u227A", "PrecedesEqual": "\u2AAF", "PrecedesSlantEqual": "\u227C", "PrecedesTilde": "\u227E", "Prime": "\u2033", "Product": "\u220F", "Proportion": "\u2237", "Proportional": "\u221D", "Pscr": "\uD835\uDCAB", "Psi": "\u03A8", "QUOT": "\u0022", "Qfr": "\uD835\uDD14", "Qopf": "\u211A", "Qscr": "\uD835\uDCAC", "RBarr": "\u2910", "REG": "\u00AE", "Racute": "\u0154", "Rang": "\u27EB", "Rarr": "\u21A0", "Rarrtl": "\u2916", "Rcaron": "\u0158", "Rcedil": "\u0156", "Rcy": "\u0420", "Re": "\u211C", "ReverseElement": "\u220B", "ReverseEquilibrium": "\u21CB", "ReverseUpEquilibrium": "\u296F", "Rfr": "\u211C", "Rho": "\u03A1", "RightAngleBracket": "\u27E9", "RightArrow": "\u2192", "RightArrowBar": "\u21E5", "RightArrowLeftArrow": "\u21C4", "RightCeiling": "\u2309", "RightDoubleBracket": "\u27E7", "RightDownTeeVector": "\u295D", "RightDownVector": "\u21C2", "RightDownVectorBar": "\u2955", "RightFloor": "\u230B", "RightTee": "\u22A2", "RightTeeArrow": "\u21A6", "RightTeeVector": "\u295B", "RightTriangle": "\u22B3", "RightTriangleBar": "\u29D0", "RightTriangleEqual": "\u22B5", "RightUpDownVector": "\u294F", "RightUpTeeVector": "\u295C", "RightUpVector": "\u21BE", "RightUpVectorBar": "\u2954", "RightVector": "\u21C0", "RightVectorBar": "\u2953", "Rightarrow": "\u21D2", "Ropf": "\u211D", "RoundImplies": "\u2970", "Rrightarrow": "\u21DB", "Rscr": "\u211B", "Rsh": "\u21B1", "RuleDelayed": "\u29F4", "SHCHcy": "\u0429", "SHcy": "\u0428", "SOFTcy": "\u042C", "Sacute": "\u015A", "Sc": "\u2ABC", "Scaron": "\u0160", "Scedil": "\u015E", "Scirc": "\u015C", "Scy": "\u0421", "Sfr": "\uD835\uDD16", "ShortDownArrow": "\u2193", "ShortLeftArrow": "\u2190", "ShortRightArrow": "\u2192", "ShortUpArrow": "\u2191", "Sigma": "\u03A3", "SmallCircle": "\u2218", "Sopf": "\uD835\uDD4A", "Sqrt": "\u221A", "Square": "\u25A1", "SquareIntersection": "\u2293", "SquareSubset": "\u228F", "SquareSubsetEqual": "\u2291", "SquareSuperset": "\u2290", "SquareSupersetEqual": "\u2292", "SquareUnion": "\u2294", "Sscr": "\uD835\uDCAE", "Star": "\u22C6", "Sub": "\u22D0", "Subset": "\u22D0", "SubsetEqual": "\u2286", "Succeeds": "\u227B", "SucceedsEqual": "\u2AB0", "SucceedsSlantEqual": "\u227D", "SucceedsTilde": "\u227F", "SuchThat": "\u220B", "Sum": "\u2211", "Sup": "\u22D1", "Superset": "\u2283", "SupersetEqual": "\u2287", "Supset": "\u22D1", "THORN": "\u00DE", "TRADE": "\u2122", "TSHcy": "\u040B", "TScy": "\u0426", "Tab": "\u0009", "Tau": "\u03A4", "Tcaron": "\u0164", "Tcedil": "\u0162", "Tcy": "\u0422", "Tfr": "\uD835\uDD17", "Therefore": "\u2234", "Theta": "\u0398", "ThickSpace": "\u205F\u200A", "ThinSpace": "\u2009", "Tilde": "\u223C", "TildeEqual": "\u2243", "TildeFullEqual": "\u2245", "TildeTilde": "\u2248", "Topf": "\uD835\uDD4B", "TripleDot": " \u20DB", "Tscr": "\uD835\uDCAF", "Tstrok": "\u0166", "Uacute": "\u00DA", "Uarr": "\u219F", "Uarrocir": "\u2949", "Ubrcy": "\u040E", "Ubreve": "\u016C", "Ucirc": "\u00DB", "Ucy": "\u0423", "Udblac": "\u0170", "Ufr": "\uD835\uDD18", "Ugrave": "\u00D9", "Umacr": "\u016A", "UnderBar": "\u005F", "UnderBrace": "\u23DF", "UnderBracket": "\u23B5", "UnderParenthesis": "\u23DD", "Union": "\u22C3", "UnionPlus": "\u228E", "Uogon": "\u0172", "Uopf": "\uD835\uDD4C", "UpArrow": "\u2191", "UpArrowBar": "\u2912", "UpArrowDownArrow": "\u21C5", "UpDownArrow": "\u2195", "UpEquilibrium": "\u296E", "UpTee": "\u22A5", "UpTeeArrow": "\u21A5", "Uparrow": "\u21D1", "Updownarrow": "\u21D5", "UpperLeftArrow": "\u2196", "UpperRightArrow": "\u2197", "Upsi": "\u03D2", "Upsilon": "\u03A5", "Uring": "\u016E", "Uscr": "\uD835\uDCB0", "Utilde": "\u0168", "Uuml": "\u00DC", "VDash": "\u22AB", "Vbar": "\u2AEB", "Vcy": "\u0412", "Vdash": "\u22A9", "Vdashl": "\u2AE6", "Vee": "\u22C1", "Verbar": "\u2016", "Vert": "\u2016", "VerticalBar": "\u2223", "VerticalLine": "\u007C", "VerticalSeparator": "\u2758", "VerticalTilde": "\u2240", "VeryThinSpace": "\u200A", "Vfr": "\uD835\uDD19", "Vopf": "\uD835\uDD4D", "Vscr": "\uD835\uDCB1", "Vvdash": "\u22AA", "Wcirc": "\u0174", "Wedge": "\u22C0", "Wfr": "\uD835\uDD1A", "Wopf": "\uD835\uDD4E", "Wscr": "\uD835\uDCB2", "Xfr": "\uD835\uDD1B", "Xi": "\u039E", "Xopf": "\uD835\uDD4F", "Xscr": "\uD835\uDCB3", "YAcy": "\u042F", "YIcy": "\u0407", "YUcy": "\u042E", "Yacute": "\u00DD", "Ycirc": "\u0176", "Ycy": "\u042B", "Yfr": "\uD835\uDD1C", "Yopf": "\uD835\uDD50", "Yscr": "\uD835\uDCB4", "Yuml": "\u0178", "ZHcy": "\u0416", "Zacute": "\u0179", "Zcaron": "\u017D", "Zcy": "\u0417", "Zdot": "\u017B", "ZeroWidthSpace": "\u200B", "Zeta": "\u0396", "Zfr": "\u2128", "Zopf": "\u2124", "Zscr": "\uD835\uDCB5", "aacute": "\u00E1", "abreve": "\u0103", "ac": "\u223E", "acE": "\u223E\u0333", "acd": "\u223F", "acirc": "\u00E2", "acute": "\u00B4", "acy": "\u0430", "aelig": "\u00E6", "af": "\u2061", "afr": "\uD835\uDD1E", "agrave": "\u00E0", "alefsym": "\u2135", "aleph": "\u2135", "alpha": "\u03B1", "amacr": "\u0101", "amalg": "\u2A3F", "amp": "\u0026", "and": "\u2227", "andand": "\u2A55", "andd": "\u2A5C", "andslope": "\u2A58", "andv": "\u2A5A", "ang": "\u2220", "ange": "\u29A4", "angle": "\u2220", "angmsd": "\u2221", "angmsdaa": "\u29A8", "angmsdab": "\u29A9", "angmsdac": "\u29AA", "angmsdad": "\u29AB", "angmsdae": "\u29AC", "angmsdaf": "\u29AD", "angmsdag": "\u29AE", "angmsdah": "\u29AF", "angrt": "\u221F", "angrtvb": "\u22BE", "angrtvbd": "\u299D", "angsph": "\u2222", "angst": "\u00C5", "angzarr": "\u237C", "aogon": "\u0105", "aopf": "\uD835\uDD52", "ap": "\u2248", "apE": "\u2A70", "apacir": "\u2A6F", "ape": "\u224A", "apid": "\u224B", "apos": "\u0027", "approx": "\u2248", "approxeq": "\u224A", "aring": "\u00E5", "ascr": "\uD835\uDCB6", "ast": "\u002A", "asymp": "\u2248", "asympeq": "\u224D", "atilde": "\u00E3", "auml": "\u00E4", "awconint": "\u2233", "awint": "\u2A11", "bNot": "\u2AED", "backcong": "\u224C", "backepsilon": "\u03F6", "backprime": "\u2035", "backsim": "\u223D", "backsimeq": "\u22CD", "barvee": "\u22BD", "barwed": "\u2305", "barwedge": "\u2305", "bbrk": "\u23B5", "bbrktbrk": "\u23B6", "bcong": "\u224C", "bcy": "\u0431", "bdquo": "\u201E", "becaus": "\u2235", "because": "\u2235", "bemptyv": "\u29B0", "bepsi": "\u03F6", "bernou": "\u212C", "beta": "\u03B2", "beth": "\u2136", "between": "\u226C", "bfr": "\uD835\uDD1F", "bigcap": "\u22C2", "bigcirc": "\u25EF", "bigcup": "\u22C3", "bigodot": "\u2A00", "bigoplus": "\u2A01", "bigotimes": "\u2A02", "bigsqcup": "\u2A06", "bigstar": "\u2605", "bigtriangledown": "\u25BD", "bigtriangleup": "\u25B3", "biguplus": "\u2A04", "bigvee": "\u22C1", "bigwedge": "\u22C0", "bkarow": "\u290D", "blacklozenge": "\u29EB", "blacksquare": "\u25AA", "blacktriangle": "\u25B4", "blacktriangledown": "\u25BE", "blacktriangleleft": "\u25C2", "blacktriangleright": "\u25B8", "blank": "\u2423", "blk12": "\u2592", "blk14": "\u2591", "blk34": "\u2593", "block": "\u2588", "bne": "\u003D\u20E5", "bnequiv": "\u2261\u20E5", "bnot": "\u2310", "bopf": "\uD835\uDD53", "bot": "\u22A5", "bottom": "\u22A5", "bowtie": "\u22C8", "boxDL": "\u2557", "boxDR": "\u2554", "boxDl": "\u2556", "boxDr": "\u2553", "boxH": "\u2550", "boxHD": "\u2566", "boxHU": "\u2569", "boxHd": "\u2564", "boxHu": "\u2567", "boxUL": "\u255D", "boxUR": "\u255A", "boxUl": "\u255C", "boxUr": "\u2559", "boxV": "\u2551", "boxVH": "\u256C", "boxVL": "\u2563", "boxVR": "\u2560", "boxVh": "\u256B", "boxVl": "\u2562", "boxVr": "\u255F", "boxbox": "\u29C9", "boxdL": "\u2555", "boxdR": "\u2552", "boxdl": "\u2510", "boxdr": "\u250C", "boxh": "\u2500", "boxhD": "\u2565", "boxhU": "\u2568", "boxhd": "\u252C", "boxhu": "\u2534", "boxminus": "\u229F", "boxplus": "\u229E", "boxtimes": "\u22A0", "boxuL": "\u255B", "boxuR": "\u2558", "boxul": "\u2518", "boxur": "\u2514", "boxv": "\u2502", "boxvH": "\u256A", "boxvL": "\u2561", "boxvR": "\u255E", "boxvh": "\u253C", "boxvl": "\u2524", "boxvr": "\u251C", "bprime": "\u2035", "breve": "\u02D8", "brvbar": "\u00A6", "bscr": "\uD835\uDCB7", "bsemi": "\u204F", "bsim": "\u223D", "bsime": "\u22CD", "bsol": "\u005C", "bsolb": "\u29C5", "bsolhsub": "\u27C8", "bull": "\u2022", "bullet": "\u2022", "bump": "\u224E", "bumpE": "\u2AAE", "bumpe": "\u224F", "bumpeq": "\u224F", "cacute": "\u0107", "cap": "\u2229", "capand": "\u2A44", "capbrcup": "\u2A49", "capcap": "\u2A4B", "capcup": "\u2A47", "capdot": "\u2A40", "caps": "\u2229\uFE00", "caret": "\u2041", "caron": "\u02C7", "ccaps": "\u2A4D", "ccaron": "\u010D", "ccedil": "\u00E7", "ccirc": "\u0109", "ccups": "\u2A4C", "ccupssm": "\u2A50", "cdot": "\u010B", "cedil": "\u00B8", "cemptyv": "\u29B2", "cent": "\u00A2", "centerdot": "\u00B7", "cfr": "\uD835\uDD20", "chcy": "\u0447", "check": "\u2713", "checkmark": "\u2713", "chi": "\u03C7", "cir": "\u25CB", "cirE": "\u29C3", "circ": "\u02C6", "circeq": "\u2257", "circlearrowleft": "\u21BA", "circlearrowright": "\u21BB", "circledR": "\u00AE", "circledS": "\u24C8", "circledast": "\u229B", "circledcirc": "\u229A", "circleddash": "\u229D", "cire": "\u2257", "cirfnint": "\u2A10", "cirmid": "\u2AEF", "cirscir": "\u29C2", "clubs": "\u2663", "clubsuit": "\u2663", "colon": "\u003A", "colone": "\u2254", "coloneq": "\u2254", "comma": "\u002C", "commat": "\u0040", "comp": "\u2201", "compfn": "\u2218", "complement": "\u2201", "complexes": "\u2102", "cong": "\u2245", "congdot": "\u2A6D", "conint": "\u222E", "copf": "\uD835\uDD54", "coprod": "\u2210", "copy": "\u00A9", "copysr": "\u2117", "crarr": "\u21B5", "cross": "\u2717", "cscr": "\uD835\uDCB8", "csub": "\u2ACF", "csube": "\u2AD1", "csup": "\u2AD0", "csupe": "\u2AD2", "ctdot": "\u22EF", "cudarrl": "\u2938", "cudarrr": "\u2935", "cuepr": "\u22DE", "cuesc": "\u22DF", "cularr": "\u21B6", "cularrp": "\u293D", "cup": "\u222A", "cupbrcap": "\u2A48", "cupcap": "\u2A46", "cupcup": "\u2A4A", "cupdot": "\u228D", "cupor": "\u2A45", "cups": "\u222A\uFE00", "curarr": "\u21B7", "curarrm": "\u293C", "curlyeqprec": "\u22DE", "curlyeqsucc": "\u22DF", "curlyvee": "\u22CE", "curlywedge": "\u22CF", "curren": "\u00A4", "curvearrowleft": "\u21B6", "curvearrowright": "\u21B7", "cuvee": "\u22CE", "cuwed": "\u22CF", "cwconint": "\u2232", "cwint": "\u2231", "cylcty": "\u232D", "dArr": "\u21D3", "dHar": "\u2965", "dagger": "\u2020", "daleth": "\u2138", "darr": "\u2193", "dash": "\u2010", "dashv": "\u22A3", "dbkarow": "\u290F", "dblac": "\u02DD", "dcaron": "\u010F", "dcy": "\u0434", "dd": "\u2146", "ddagger": "\u2021", "ddarr": "\u21CA", "ddotseq": "\u2A77", "deg": "\u00B0", "delta": "\u03B4", "demptyv": "\u29B1", "dfisht": "\u297F", "dfr": "\uD835\uDD21", "dharl": "\u21C3", "dharr": "\u21C2", "diam": "\u22C4", "diamond": "\u22C4", "diamondsuit": "\u2666", "diams": "\u2666", "die": "\u00A8", "digamma": "\u03DD", "disin": "\u22F2", "div": "\u00F7", "divide": "\u00F7", "divideontimes": "\u22C7", "divonx": "\u22C7", "djcy": "\u0452", "dlcorn": "\u231E", "dlcrop": "\u230D", "dollar": "\u0024", "dopf": "\uD835\uDD55", "dot": "\u02D9", "doteq": "\u2250", "doteqdot": "\u2251", "dotminus": "\u2238", "dotplus": "\u2214", "dotsquare": "\u22A1", "doublebarwedge": "\u2306", "downarrow": "\u2193", "downdownarrows": "\u21CA", "downharpoonleft": "\u21C3", "downharpoonright": "\u21C2", "drbkarow": "\u2910", "drcorn": "\u231F", "drcrop": "\u230C", "dscr": "\uD835\uDCB9", "dscy": "\u0455", "dsol": "\u29F6", "dstrok": "\u0111", "dtdot": "\u22F1", "dtri": "\u25BF", "dtrif": "\u25BE", "duarr": "\u21F5", "duhar": "\u296F", "dwangle": "\u29A6", "dzcy": "\u045F", "dzigrarr": "\u27FF", "eDDot": "\u2A77", "eDot": "\u2251", "eacute": "\u00E9", "easter": "\u2A6E", "ecaron": "\u011B", "ecir": "\u2256", "ecirc": "\u00EA", "ecolon": "\u2255", "ecy": "\u044D", "edot": "\u0117", "ee": "\u2147", "efDot": "\u2252", "efr": "\uD835\uDD22", "eg": "\u2A9A", "egrave": "\u00E8", "egs": "\u2A96", "egsdot": "\u2A98", "el": "\u2A99", "elinters": "\u23E7", "ell": "\u2113", "els": "\u2A95", "elsdot": "\u2A97", "emacr": "\u0113", "empty": "\u2205", "emptyset": "\u2205", "emptyv": "\u2205", "emsp": "\u2003", "emsp13": "\u2004", "emsp14": "\u2005", "eng": "\u014B", "ensp": "\u2002", "eogon": "\u0119", "eopf": "\uD835\uDD56", "epar": "\u22D5", "eparsl": "\u29E3", "eplus": "\u2A71", "epsi": "\u03B5", "epsilon": "\u03B5", "epsiv": "\u03F5", "eqcirc": "\u2256", "eqcolon": "\u2255", "eqsim": "\u2242", "eqslantgtr": "\u2A96", "eqslantless": "\u2A95", "equals": "\u003D", "equest": "\u225F", "equiv": "\u2261", "equivDD": "\u2A78", "eqvparsl": "\u29E5", "erDot": "\u2253", "erarr": "\u2971", "escr": "\u212F", "esdot": "\u2250", "esim": "\u2242", "eta": "\u03B7", "eth": "\u00F0", "euml": "\u00EB", "euro": "\u20AC", "excl": "\u0021", "exist": "\u2203", "expectation": "\u2130", "exponentiale": "\u2147", "fallingdotseq": "\u2252", "fcy": "\u0444", "female": "\u2640", "ffilig": "\uFB03", "fflig": "\uFB00", "ffllig": "\uFB04", "ffr": "\uD835\uDD23", "filig": "\uFB01", "fjlig": "\u0066\u006A", "flat": "\u266D", "fllig": "\uFB02", "fltns": "\u25B1", "fnof": "\u0192", "fopf": "\uD835\uDD57", "forall": "\u2200", "fork": "\u22D4", "forkv": "\u2AD9", "fpartint": "\u2A0D", "frac12": "\u00BD", "frac13": "\u2153", "frac14": "\u00BC", "frac15": "\u2155", "frac16": "\u2159", "frac18": "\u215B", "frac23": "\u2154", "frac25": "\u2156", "frac34": "\u00BE", "frac35": "\u2157", "frac38": "\u215C", "frac45": "\u2158", "frac56": "\u215A", "frac58": "\u215D", "frac78": "\u215E", "frasl": "\u2044", "frown": "\u2322", "fscr": "\uD835\uDCBB", "gE": "\u2267", "gEl": "\u2A8C", "gacute": "\u01F5", "gamma": "\u03B3", "gammad": "\u03DD", "gap": "\u2A86", "gbreve": "\u011F", "gcirc": "\u011D", "gcy": "\u0433", "gdot": "\u0121", "ge": "\u2265", "gel": "\u22DB", "geq": "\u2265", "geqq": "\u2267", "geqslant": "\u2A7E", "ges": "\u2A7E", "gescc": "\u2AA9", "gesdot": "\u2A80", "gesdoto": "\u2A82", "gesdotol": "\u2A84", "gesl": "\u22DB\uFE00", "gesles": "\u2A94", "gfr": "\uD835\uDD24", "gg": "\u226B", "ggg": "\u22D9", "gimel": "\u2137", "gjcy": "\u0453", "gl": "\u2277", "glE": "\u2A92", "gla": "\u2AA5", "glj": "\u2AA4", "gnE": "\u2269", "gnap": "\u2A8A", "gnapprox": "\u2A8A", "gne": "\u2A88", "gneq": "\u2A88", "gneqq": "\u2269", "gnsim": "\u22E7", "gopf": "\uD835\uDD58", "grave": "\u0060", "gscr": "\u210A", "gsim": "\u2273", "gsime": "\u2A8E", "gsiml": "\u2A90", "gt": "\u003E", "gtcc": "\u2AA7", "gtcir": "\u2A7A", "gtdot": "\u22D7", "gtlPar": "\u2995", "gtquest": "\u2A7C", "gtrapprox": "\u2A86", "gtrarr": "\u2978", "gtrdot": "\u22D7", "gtreqless": "\u22DB", "gtreqqless": "\u2A8C", "gtrless": "\u2277", "gtrsim": "\u2273", "gvertneqq": "\u2269\uFE00", "gvnE": "\u2269\uFE00", "hArr": "\u21D4", "hairsp": "\u200A", "half": "\u00BD", "hamilt": "\u210B", "hardcy": "\u044A", "harr": "\u2194", "harrcir": "\u2948", "harrw": "\u21AD", "hbar": "\u210F", "hcirc": "\u0125", "hearts": "\u2665", "heartsuit": "\u2665", "hellip": "\u2026", "hercon": "\u22B9", "hfr": "\uD835\uDD25", "hksearow": "\u2925", "hkswarow": "\u2926", "hoarr": "\u21FF", "homtht": "\u223B", "hookleftarrow": "\u21A9", "hookrightarrow": "\u21AA", "hopf": "\uD835\uDD59", "horbar": "\u2015", "hscr": "\uD835\uDCBD", "hslash": "\u210F", "hstrok": "\u0127", "hybull": "\u2043", "hyphen": "\u2010", "iacute": "\u00ED", "ic": "\u2063", "icirc": "\u00EE", "icy": "\u0438", "iecy": "\u0435", "iexcl": "\u00A1", "iff": "\u21D4", "ifr": "\uD835\uDD26", "igrave": "\u00EC", "ii": "\u2148", "iiiint": "\u2A0C", "iiint": "\u222D", "iinfin": "\u29DC", "iiota": "\u2129", "ijlig": "\u0133", "imacr": "\u012B", "image": "\u2111", "imagline": "\u2110", "imagpart": "\u2111", "imath": "\u0131", "imof": "\u22B7", "imped": "\u01B5", "in": "\u2208", "incare": "\u2105", "infin": "\u221E", "infintie": "\u29DD", "inodot": "\u0131", "int": "\u222B", "intcal": "\u22BA", "integers": "\u2124", "intercal": "\u22BA", "intlarhk": "\u2A17", "intprod": "\u2A3C", "iocy": "\u0451", "iogon": "\u012F", "iopf": "\uD835\uDD5A", "iota": "\u03B9", "iprod": "\u2A3C", "iquest": "\u00BF", "iscr": "\uD835\uDCBE", "isin": "\u2208", "isinE": "\u22F9", "isindot": "\u22F5", "isins": "\u22F4", "isinsv": "\u22F3", "isinv": "\u2208", "it": "\u2062", "itilde": "\u0129", "iukcy": "\u0456", "iuml": "\u00EF", "jcirc": "\u0135", "jcy": "\u0439", "jfr": "\uD835\uDD27", "jmath": "\u0237", "jopf": "\uD835\uDD5B", "jscr": "\uD835\uDCBF", "jsercy": "\u0458", "jukcy": "\u0454", "kappa": "\u03BA", "kappav": "\u03F0", "kcedil": "\u0137", "kcy": "\u043A", "kfr": "\uD835\uDD28", "kgreen": "\u0138", "khcy": "\u0445", "kjcy": "\u045C", "kopf": "\uD835\uDD5C", "kscr": "\uD835\uDCC0", "lAarr": "\u21DA", "lArr": "\u21D0", "lAtail": "\u291B", "lBarr": "\u290E", "lE": "\u2266", "lEg": "\u2A8B", "lHar": "\u2962", "lacute": "\u013A", "laemptyv": "\u29B4", "lagran": "\u2112", "lambda": "\u03BB", "lang": "\u27E8", "langd": "\u2991", "langle": "\u27E8", "lap": "\u2A85", "laquo": "\u00AB", "larr": "\u2190", "larrb": "\u21E4", "larrbfs": "\u291F", "larrfs": "\u291D", "larrhk": "\u21A9", "larrlp": "\u21AB", "larrpl": "\u2939", "larrsim": "\u2973", "larrtl": "\u21A2", "lat": "\u2AAB", "latail": "\u2919", "late": "\u2AAD", "lates": "\u2AAD\uFE00", "lbarr": "\u290C", "lbbrk": "\u2772", "lbrace": "\u007B", "lbrack": "\u005B", "lbrke": "\u298B", "lbrksld": "\u298F", "lbrkslu": "\u298D", "lcaron": "\u013E", "lcedil": "\u013C", "lceil": "\u2308", "lcub": "\u007B", "lcy": "\u043B", "ldca": "\u2936", "ldquo": "\u201C", "ldquor": "\u201E", "ldrdhar": "\u2967", "ldrushar": "\u294B", "ldsh": "\u21B2", "le": "\u2264", "leftarrow": "\u2190", "leftarrowtail": "\u21A2", "leftharpoondown": "\u21BD", "leftharpoonup": "\u21BC", "leftleftarrows": "\u21C7", "leftrightarrow": "\u2194", "leftrightarrows": "\u21C6", "leftrightharpoons": "\u21CB", "leftrightsquigarrow": "\u21AD", "leftthreetimes": "\u22CB", "leg": "\u22DA", "leq": "\u2264", "leqq": "\u2266", "leqslant": "\u2A7D", "les": "\u2A7D", "lescc": "\u2AA8", "lesdot": "\u2A7F", "lesdoto": "\u2A81", "lesdotor": "\u2A83", "lesg": "\u22DA\uFE00", "lesges": "\u2A93", "lessapprox": "\u2A85", "lessdot": "\u22D6", "lesseqgtr": "\u22DA", "lesseqqgtr": "\u2A8B", "lessgtr": "\u2276", "lesssim": "\u2272", "lfisht": "\u297C", "lfloor": "\u230A", "lfr": "\uD835\uDD29", "lg": "\u2276", "lgE": "\u2A91", "lhard": "\u21BD", "lharu": "\u21BC", "lharul": "\u296A", "lhblk": "\u2584", "ljcy": "\u0459", "ll": "\u226A", "llarr": "\u21C7", "llcorner": "\u231E", "llhard": "\u296B", "lltri": "\u25FA", "lmidot": "\u0140", "lmoust": "\u23B0", "lmoustache": "\u23B0", "lnE": "\u2268", "lnap": "\u2A89", "lnapprox": "\u2A89", "lne": "\u2A87", "lneq": "\u2A87", "lneqq": "\u2268", "lnsim": "\u22E6", "loang": "\u27EC", "loarr": "\u21FD", "lobrk": "\u27E6", "longleftarrow": "\u27F5", "longleftrightarrow": "\u27F7", "longmapsto": "\u27FC", "longrightarrow": "\u27F6", "looparrowleft": "\u21AB", "looparrowright": "\u21AC", "lopar": "\u2985", "lopf": "\uD835\uDD5D", "loplus": "\u2A2D", "lotimes": "\u2A34", "lowast": "\u2217", "lowbar": "\u005F", "loz": "\u25CA", "lozenge": "\u25CA", "lozf": "\u29EB", "lpar": "\u0028", "lparlt": "\u2993", "lrarr": "\u21C6", "lrcorner": "\u231F", "lrhar": "\u21CB", "lrhard": "\u296D", "lrm": "\u200E", "lrtri": "\u22BF", "lsaquo": "\u2039", "lscr": "\uD835\uDCC1", "lsh": "\u21B0", "lsim": "\u2272", "lsime": "\u2A8D", "lsimg": "\u2A8F", "lsqb": "\u005B", "lsquo": "\u2018", "lsquor": "\u201A", "lstrok": "\u0142", "lt": "\u003C", "ltcc": "\u2AA6", "ltcir": "\u2A79", "ltdot": "\u22D6", "lthree": "\u22CB", "ltimes": "\u22C9", "ltlarr": "\u2976", "ltquest": "\u2A7B", "ltrPar": "\u2996", "ltri": "\u25C3", "ltrie": "\u22B4", "ltrif": "\u25C2", "lurdshar": "\u294A", "luruhar": "\u2966", "lvertneqq": "\u2268\uFE00", "lvnE": "\u2268\uFE00", "mDDot": "\u223A", "macr": "\u00AF", "male": "\u2642", "malt": "\u2720", "maltese": "\u2720", "map": "\u21A6", "mapsto": "\u21A6", "mapstodown": "\u21A7", "mapstoleft": "\u21A4", "mapstoup": "\u21A5", "marker": "\u25AE", "mcomma": "\u2A29", "mcy": "\u043C", "mdash": "\u2014", "measuredangle": "\u2221", "mfr": "\uD835\uDD2A", "mho": "\u2127", "micro": "\u00B5", "mid": "\u2223", "midast": "\u002A", "midcir": "\u2AF0", "middot": "\u00B7", "minus": "\u2212", "minusb": "\u229F", "minusd": "\u2238", "minusdu": "\u2A2A", "mlcp": "\u2ADB", "mldr": "\u2026", "mnplus": "\u2213", "models": "\u22A7", "mopf": "\uD835\uDD5E", "mp": "\u2213", "mscr": "\uD835\uDCC2", "mstpos": "\u223E", "mu": "\u03BC", "multimap": "\u22B8", "mumap": "\u22B8", "nGg": "\u22D9\u0338", "nGt": "\u226B\u20D2", "nGtv": "\u226B\u0338", "nLeftarrow": "\u21CD", "nLeftrightarrow": "\u21CE", "nLl": "\u22D8\u0338", "nLt": "\u226A\u20D2", "nLtv": "\u226A\u0338", "nRightarrow": "\u21CF", "nVDash": "\u22AF", "nVdash": "\u22AE", "nabla": "\u2207", "nacute": "\u0144", "nang": "\u2220\u20D2", "nap": "\u2249", "napE": "\u2A70\u0338", "napid": "\u224B\u0338", "napos": "\u0149", "napprox": "\u2249", "natur": "\u266E", "natural": "\u266E", "naturals": "\u2115", "nbsp": "\u00A0", "nbump": "\u224E\u0338", "nbumpe": "\u224F\u0338", "ncap": "\u2A43", "ncaron": "\u0148", "ncedil": "\u0146", "ncong": "\u2247", "ncongdot": "\u2A6D\u0338", "ncup": "\u2A42", "ncy": "\u043D", "ndash": "\u2013", "ne": "\u2260", "neArr": "\u21D7", "nearhk": "\u2924", "nearr": "\u2197", "nearrow": "\u2197", "nedot": "\u2250\u0338", "nequiv": "\u2262", "nesear": "\u2928", "nesim": "\u2242\u0338", "nexist": "\u2204", "nexists": "\u2204", "nfr": "\uD835\uDD2B", "ngE": "\u2267\u0338", "nge": "\u2271", "ngeq": "\u2271", "ngeqq": "\u2267\u0338", "ngeqslant": "\u2A7E\u0338", "nges": "\u2A7E\u0338", "ngsim": "\u2275", "ngt": "\u226F", "ngtr": "\u226F", "nhArr": "\u21CE", "nharr": "\u21AE", "nhpar": "\u2AF2", "ni": "\u220B", "nis": "\u22FC", "nisd": "\u22FA", "niv": "\u220B", "njcy": "\u045A", "nlArr": "\u21CD", "nlE": "\u2266\u0338", "nlarr": "\u219A", "nldr": "\u2025", "nle": "\u2270", "nleftarrow": "\u219A", "nleftrightarrow": "\u21AE", "nleq": "\u2270", "nleqq": "\u2266\u0338", "nleqslant": "\u2A7D\u0338", "nles": "\u2A7D\u0338", "nless": "\u226E", "nlsim": "\u2274", "nlt": "\u226E", "nltri": "\u22EA", "nltrie": "\u22EC", "nmid": "\u2224", "nopf": "\uD835\uDD5F", "not": "\u00AC", "notin": "\u2209", "notinE": "\u22F9\u0338", "notindot": "\u22F5\u0338", "notinva": "\u2209", "notinvb": "\u22F7", "notinvc": "\u22F6", "notni": "\u220C", "notniva": "\u220C", "notnivb": "\u22FE", "notnivc": "\u22FD", "npar": "\u2226", "nparallel": "\u2226", "nparsl": "\u2AFD\u20E5", "npart": "\u2202\u0338", "npolint": "\u2A14", "npr": "\u2280", "nprcue": "\u22E0", "npre": "\u2AAF\u0338", "nprec": "\u2280", "npreceq": "\u2AAF\u0338", "nrArr": "\u21CF", "nrarr": "\u219B", "nrarrc": "\u2933\u0338", "nrarrw": "\u219D\u0338", "nrightarrow": "\u219B", "nrtri": "\u22EB", "nrtrie": "\u22ED", "nsc": "\u2281", "nsccue": "\u22E1", "nsce": "\u2AB0\u0338", "nscr": "\uD835\uDCC3", "nshortmid": "\u2224", "nshortparallel": "\u2226", "nsim": "\u2241", "nsime": "\u2244", "nsimeq": "\u2244", "nsmid": "\u2224", "nspar": "\u2226", "nsqsube": "\u22E2", "nsqsupe": "\u22E3", "nsub": "\u2284", "nsubE": "\u2AC5\u0338", "nsube": "\u2288", "nsubset": "\u2282\u20D2", "nsubseteq": "\u2288", "nsubseteqq": "\u2AC5\u0338", "nsucc": "\u2281", "nsucceq": "\u2AB0\u0338", "nsup": "\u2285", "nsupE": "\u2AC6\u0338", "nsupe": "\u2289", "nsupset": "\u2283\u20D2", "nsupseteq": "\u2289", "nsupseteqq": "\u2AC6\u0338", "ntgl": "\u2279", "ntilde": "\u00F1", "ntlg": "\u2278", "ntriangleleft": "\u22EA", "ntrianglelefteq": "\u22EC", "ntriangleright": "\u22EB", "ntrianglerighteq": "\u22ED", "nu": "\u03BD", "num": "\u0023", "numero": "\u2116", "numsp": "\u2007", "nvDash": "\u22AD", "nvHarr": "\u2904", "nvap": "\u224D\u20D2", "nvdash": "\u22AC", "nvge": "\u2265\u20D2", "nvgt": "\u003E\u20D2", "nvinfin": "\u29DE", "nvlArr": "\u2902", "nvle": "\u2264\u20D2", "nvlt": "\u003C\u20D2", "nvltrie": "\u22B4\u20D2", "nvrArr": "\u2903", "nvrtrie": "\u22B5\u20D2", "nvsim": "\u223C\u20D2", "nwArr": "\u21D6", "nwarhk": "\u2923", "nwarr": "\u2196", "nwarrow": "\u2196", "nwnear": "\u2927", "oS": "\u24C8", "oacute": "\u00F3", "oast": "\u229B", "ocir": "\u229A", "ocirc": "\u00F4", "ocy": "\u043E", "odash": "\u229D", "odblac": "\u0151", "odiv": "\u2A38", "odot": "\u2299", "odsold": "\u29BC", "oelig": "\u0153", "ofcir": "\u29BF", "ofr": "\uD835\uDD2C", "ogon": "\u02DB", "ograve": "\u00F2", "ogt": "\u29C1", "ohbar": "\u29B5", "ohm": "\u03A9", "oint": "\u222E", "olarr": "\u21BA", "olcir": "\u29BE", "olcross": "\u29BB", "oline": "\u203E", "olt": "\u29C0", "omacr": "\u014D", "omega": "\u03C9", "omicron": "\u03BF", "omid": "\u29B6", "ominus": "\u2296", "oopf": "\uD835\uDD60", "opar": "\u29B7", "operp": "\u29B9", "oplus": "\u2295", "or": "\u2228", "orarr": "\u21BB", "ord": "\u2A5D", "order": "\u2134", "orderof": "\u2134", "ordf": "\u00AA", "ordm": "\u00BA", "origof": "\u22B6", "oror": "\u2A56", "orslope": "\u2A57", "orv": "\u2A5B", "oscr": "\u2134", "oslash": "\u00F8", "osol": "\u2298", "otilde": "\u00F5", "otimes": "\u2297", "otimesas": "\u2A36", "ouml": "\u00F6", "ovbar": "\u233D", "par": "\u2225", "para": "\u00B6", "parallel": "\u2225", "parsim": "\u2AF3", "parsl": "\u2AFD", "part": "\u2202", "pcy": "\u043F", "percnt": "\u0025", "period": "\u002E", "permil": "\u2030", "perp": "\u22A5", "pertenk": "\u2031", "pfr": "\uD835\uDD2D", "phi": "\u03C6", "phiv": "\u03D5", "phmmat": "\u2133", "phone": "\u260E", "pi": "\u03C0", "pitchfork": "\u22D4", "piv": "\u03D6", "planck": "\u210F", "planckh": "\u210E", "plankv": "\u210F", "plus": "\u002B", "plusacir": "\u2A23", "plusb": "\u229E", "pluscir": "\u2A22", "plusdo": "\u2214", "plusdu": "\u2A25", "pluse": "\u2A72", "plusmn": "\u00B1", "plussim": "\u2A26", "plustwo": "\u2A27", "pm": "\u00B1", "pointint": "\u2A15", "popf": "\uD835\uDD61", "pound": "\u00A3", "pr": "\u227A", "prE": "\u2AB3", "prap": "\u2AB7", "prcue": "\u227C", "pre": "\u2AAF", "prec": "\u227A", "precapprox": "\u2AB7", "preccurlyeq": "\u227C", "preceq": "\u2AAF", "precnapprox": "\u2AB9", "precneqq": "\u2AB5", "precnsim": "\u22E8", "precsim": "\u227E", "prime": "\u2032", "primes": "\u2119", "prnE": "\u2AB5", "prnap": "\u2AB9", "prnsim": "\u22E8", "prod": "\u220F", "profalar": "\u232E", "profline": "\u2312", "profsurf": "\u2313", "prop": "\u221D", "propto": "\u221D", "prsim": "\u227E", "prurel": "\u22B0", "pscr": "\uD835\uDCC5", "psi": "\u03C8", "puncsp": "\u2008", "qfr": "\uD835\uDD2E", "qint": "\u2A0C", "qopf": "\uD835\uDD62", "qprime": "\u2057", "qscr": "\uD835\uDCC6", "quaternions": "\u210D", "quatint": "\u2A16", "quest": "\u003F", "questeq": "\u225F", "quot": "\u0022", "rAarr": "\u21DB", "rArr": "\u21D2", "rAtail": "\u291C", "rBarr": "\u290F", "rHar": "\u2964", "race": "\u223D\u0331", "racute": "\u0155", "radic": "\u221A", "raemptyv": "\u29B3", "rang": "\u27E9", "rangd": "\u2992", "range": "\u29A5", "rangle": "\u27E9", "raquo": "\u00BB", "rarr": "\u2192", "rarrap": "\u2975", "rarrb": "\u21E5", "rarrbfs": "\u2920", "rarrc": "\u2933", "rarrfs": "\u291E", "rarrhk": "\u21AA", "rarrlp": "\u21AC", "rarrpl": "\u2945", "rarrsim": "\u2974", "rarrtl": "\u21A3", "rarrw": "\u219D", "ratail": "\u291A", "ratio": "\u2236", "rationals": "\u211A", "rbarr": "\u290D", "rbbrk": "\u2773", "rbrace": "\u007D", "rbrack": "\u005D", "rbrke": "\u298C", "rbrksld": "\u298E", "rbrkslu": "\u2990", "rcaron": "\u0159", "rcedil": "\u0157", "rceil": "\u2309", "rcub": "\u007D", "rcy": "\u0440", "rdca": "\u2937", "rdldhar": "\u2969", "rdquo": "\u201D", "rdquor": "\u201D", "rdsh": "\u21B3", "real": "\u211C", "realine": "\u211B", "realpart": "\u211C", "reals": "\u211D", "rect": "\u25AD", "reg": "\u00AE", "rfisht": "\u297D", "rfloor": "\u230B", "rfr": "\uD835\uDD2F", "rhard": "\u21C1", "rharu": "\u21C0", "rharul": "\u296C", "rho": "\u03C1", "rhov": "\u03F1", "rightarrow": "\u2192", "rightarrowtail": "\u21A3", "rightharpoondown": "\u21C1", "rightharpoonup": "\u21C0", "rightleftarrows": "\u21C4", "rightleftharpoons": "\u21CC", "rightrightarrows": "\u21C9", "rightsquigarrow": "\u219D", "rightthreetimes": "\u22CC", "ring": "\u02DA", "risingdotseq": "\u2253", "rlarr": "\u21C4", "rlhar": "\u21CC", "rlm": "\u200F", "rmoust": "\u23B1", "rmoustache": "\u23B1", "rnmid": "\u2AEE", "roang": "\u27ED", "roarr": "\u21FE", "robrk": "\u27E7", "ropar": "\u2986", "ropf": "\uD835\uDD63", "roplus": "\u2A2E", "rotimes": "\u2A35", "rpar": "\u0029", "rpargt": "\u2994", "rppolint": "\u2A12", "rrarr": "\u21C9", "rsaquo": "\u203A", "rscr": "\uD835\uDCC7", "rsh": "\u21B1", "rsqb": "\u005D", "rsquo": "\u2019", "rsquor": "\u2019", "rthree": "\u22CC", "rtimes": "\u22CA", "rtri": "\u25B9", "rtrie": "\u22B5", "rtrif": "\u25B8", "rtriltri": "\u29CE", "ruluhar": "\u2968", "rx": "\u211E", "sacute": "\u015B", "sbquo": "\u201A", "sc": "\u227B", "scE": "\u2AB4", "scap": "\u2AB8", "scaron": "\u0161", "sccue": "\u227D", "sce": "\u2AB0", "scedil": "\u015F", "scirc": "\u015D", "scnE": "\u2AB6", "scnap": "\u2ABA", "scnsim": "\u22E9", "scpolint": "\u2A13", "scsim": "\u227F", "scy": "\u0441", "sdot": "\u22C5", "sdotb": "\u22A1", "sdote": "\u2A66", "seArr": "\u21D8", "searhk": "\u2925", "searr": "\u2198", "searrow": "\u2198", "sect": "\u00A7", "semi": "\u003B", "seswar": "\u2929", "setminus": "\u2216", "setmn": "\u2216", "sext": "\u2736", "sfr": "\uD835\uDD30", "sfrown": "\u2322", "sharp": "\u266F", "shchcy": "\u0449", "shcy": "\u0448", "shortmid": "\u2223", "shortparallel": "\u2225", "shy": "\u00AD", "sigma": "\u03C3", "sigmaf": "\u03C2", "sigmav": "\u03C2", "sim": "\u223C", "simdot": "\u2A6A", "sime": "\u2243", "simeq": "\u2243", "simg": "\u2A9E", "simgE": "\u2AA0", "siml": "\u2A9D", "simlE": "\u2A9F", "simne": "\u2246", "simplus": "\u2A24", "simrarr": "\u2972", "slarr": "\u2190", "smallsetminus": "\u2216", "smashp": "\u2A33", "smeparsl": "\u29E4", "smid": "\u2223", "smile": "\u2323", "smt": "\u2AAA", "smte": "\u2AAC", "smtes": "\u2AAC\uFE00", "softcy": "\u044C", "sol": "\u002F", "solb": "\u29C4", "solbar": "\u233F", "sopf": "\uD835\uDD64", "spades": "\u2660", "spadesuit": "\u2660", "spar": "\u2225", "sqcap": "\u2293", "sqcaps": "\u2293\uFE00", "sqcup": "\u2294", "sqcups": "\u2294\uFE00", "sqsub": "\u228F", "sqsube": "\u2291", "sqsubset": "\u228F", "sqsubseteq": "\u2291", "sqsup": "\u2290", "sqsupe": "\u2292", "sqsupset": "\u2290", "sqsupseteq": "\u2292", "squ": "\u25A1", "square": "\u25A1", "squarf": "\u25AA", "squf": "\u25AA", "srarr": "\u2192", "sscr": "\uD835\uDCC8", "ssetmn": "\u2216", "ssmile": "\u2323", "sstarf": "\u22C6", "star": "\u2606", "starf": "\u2605", "straightepsilon": "\u03F5", "straightphi": "\u03D5", "strns": "\u00AF", "sub": "\u2282", "subE": "\u2AC5", "subdot": "\u2ABD", "sube": "\u2286", "subedot": "\u2AC3", "submult": "\u2AC1", "subnE": "\u2ACB", "subne": "\u228A", "subplus": "\u2ABF", "subrarr": "\u2979", "subset": "\u2282", "subseteq": "\u2286", "subseteqq": "\u2AC5", "subsetneq": "\u228A", "subsetneqq": "\u2ACB", "subsim": "\u2AC7", "subsub": "\u2AD5", "subsup": "\u2AD3", "succ": "\u227B", "succapprox": "\u2AB8", "succcurlyeq": "\u227D", "succeq": "\u2AB0", "succnapprox": "\u2ABA", "succneqq": "\u2AB6", "succnsim": "\u22E9", "succsim": "\u227F", "sum": "\u2211", "sung": "\u266A", "sup": "\u2283", "sup1": "\u00B9", "sup2": "\u00B2", "sup3": "\u00B3", "supE": "\u2AC6", "supdot": "\u2ABE", "supdsub": "\u2AD8", "supe": "\u2287", "supedot": "\u2AC4", "suphsol": "\u27C9", "suphsub": "\u2AD7", "suplarr": "\u297B", "supmult": "\u2AC2", "supnE": "\u2ACC", "supne": "\u228B", "supplus": "\u2AC0", "supset": "\u2283", "supseteq": "\u2287", "supseteqq": "\u2AC6", "supsetneq": "\u228B", "supsetneqq": "\u2ACC", "supsim": "\u2AC8", "supsub": "\u2AD4", "supsup": "\u2AD6", "swArr": "\u21D9", "swarhk": "\u2926", "swarr": "\u2199", "swarrow": "\u2199", "swnwar": "\u292A", "szlig": "\u00DF", "target": "\u2316", "tau": "\u03C4", "tbrk": "\u23B4", "tcaron": "\u0165", "tcedil": "\u0163", "tcy": "\u0442", "tdot": " \u20DB", "telrec": "\u2315", "tfr": "\uD835\uDD31", "there4": "\u2234", "therefore": "\u2234", "theta": "\u03B8", "thetasym": "\u03D1", "thetav": "\u03D1", "thickapprox": "\u2248", "thicksim": "\u223C", "thinsp": "\u2009", "thkap": "\u2248", "thksim": "\u223C", "thorn": "\u00FE", "tilde": "\u02DC", "times": "\u00D7", "timesb": "\u22A0", "timesbar": "\u2A31", "timesd": "\u2A30", "tint": "\u222D", "toea": "\u2928", "top": "\u22A4", "topbot": "\u2336", "topcir": "\u2AF1", "topf": "\uD835\uDD65", "topfork": "\u2ADA", "tosa": "\u2929", "tprime": "\u2034", "trade": "\u2122", "triangle": "\u25B5", "triangledown": "\u25BF", "triangleleft": "\u25C3", "trianglelefteq": "\u22B4", "triangleq": "\u225C", "triangleright": "\u25B9", "trianglerighteq": "\u22B5", "tridot": "\u25EC", "trie": "\u225C", "triminus": "\u2A3A", "triplus": "\u2A39", "trisb": "\u29CD", "tritime": "\u2A3B", "trpezium": "\u23E2", "tscr": "\uD835\uDCC9", "tscy": "\u0446", "tshcy": "\u045B", "tstrok": "\u0167", "twixt": "\u226C", "twoheadleftarrow": "\u219E", "twoheadrightarrow": "\u21A0", "uArr": "\u21D1", "uHar": "\u2963", "uacute": "\u00FA", "uarr": "\u2191", "ubrcy": "\u045E", "ubreve": "\u016D", "ucirc": "\u00FB", "ucy": "\u0443", "udarr": "\u21C5", "udblac": "\u0171", "udhar": "\u296E", "ufisht": "\u297E", "ufr": "\uD835\uDD32", "ugrave": "\u00F9", "uharl": "\u21BF", "uharr": "\u21BE", "uhblk": "\u2580", "ulcorn": "\u231C", "ulcorner": "\u231C", "ulcrop": "\u230F", "ultri": "\u25F8", "umacr": "\u016B", "uml": "\u00A8", "uogon": "\u0173", "uopf": "\uD835\uDD66", "uparrow": "\u2191", "updownarrow": "\u2195", "upharpoonleft": "\u21BF", "upharpoonright": "\u21BE", "uplus": "\u228E", "upsi": "\u03C5", "upsih": "\u03D2", "upsilon": "\u03C5", "upuparrows": "\u21C8", "urcorn": "\u231D", "urcorner": "\u231D", "urcrop": "\u230E", "uring": "\u016F", "urtri": "\u25F9", "uscr": "\uD835\uDCCA", "utdot": "\u22F0", "utilde": "\u0169", "utri": "\u25B5", "utrif": "\u25B4", "uuarr": "\u21C8", "uuml": "\u00FC", "uwangle": "\u29A7", "vArr": "\u21D5", "vBar": "\u2AE8", "vBarv": "\u2AE9", "vDash": "\u22A8", "vangrt": "\u299C", "varepsilon": "\u03F5", "varkappa": "\u03F0", "varnothing": "\u2205", "varphi": "\u03D5", "varpi": "\u03D6", "varpropto": "\u221D", "varr": "\u2195", "varrho": "\u03F1", "varsigma": "\u03C2", "varsubsetneq": "\u228A\uFE00", "varsubsetneqq": "\u2ACB\uFE00", "varsupsetneq": "\u228B\uFE00", "varsupsetneqq": "\u2ACC\uFE00", "vartheta": "\u03D1", "vartriangleleft": "\u22B2", "vartriangleright": "\u22B3", "vcy": "\u0432", "vdash": "\u22A2", "vee": "\u2228", "veebar": "\u22BB", "veeeq": "\u225A", "vellip": "\u22EE", "verbar": "\u007C", "vert": "\u007C", "vfr": "\uD835\uDD33", "vltri": "\u22B2", "vnsub": "\u2282\u20D2", "vnsup": "\u2283\u20D2", "vopf": "\uD835\uDD67", "vprop": "\u221D", "vrtri": "\u22B3", "vscr": "\uD835\uDCCB", "vsubnE": "\u2ACB\uFE00", "vsubne": "\u228A\uFE00", "vsupnE": "\u2ACC\uFE00", "vsupne": "\u228B\uFE00", "vzigzag": "\u299A", "wcirc": "\u0175", "wedbar": "\u2A5F", "wedge": "\u2227", "wedgeq": "\u2259", "weierp": "\u2118", "wfr": "\uD835\uDD34", "wopf": "\uD835\uDD68", "wp": "\u2118", "wr": "\u2240", "wreath": "\u2240", "wscr": "\uD835\uDCCC", "xcap": "\u22C2", "xcirc": "\u25EF", "xcup": "\u22C3", "xdtri": "\u25BD", "xfr": "\uD835\uDD35", "xhArr": "\u27FA", "xharr": "\u27F7", "xi": "\u03BE", "xlArr": "\u27F8", "xlarr": "\u27F5", "xmap": "\u27FC", "xnis": "\u22FB", "xodot": "\u2A00", "xopf": "\uD835\uDD69", "xoplus": "\u2A01", "xotime": "\u2A02", "xrArr": "\u27F9", "xrarr": "\u27F6", "xscr": "\uD835\uDCCD", "xsqcup": "\u2A06", "xuplus": "\u2A04", "xutri": "\u25B3", "xvee": "\u22C1", "xwedge": "\u22C0", "yacute": "\u00FD", "yacy": "\u044F", "ycirc": "\u0177", "ycy": "\u044B", "yen": "\u00A5", "yfr": "\uD835\uDD36", "yicy": "\u0457", "yopf": "\uD835\uDD6A", "yscr": "\uD835\uDCCE", "yucy": "\u044E", "yuml": "\u00FF", "zacute": "\u017A", "zcaron": "\u017E", "zcy": "\u0437", "zdot": "\u017C", "zeetrf": "\u2128", "zeta": "\u03B6", "zfr": "\uD835\uDD37", "zhcy": "\u0436", "zigrarr": "\u21DD", "zopf": "\uD835\uDD6B", "zscr": "\uD835\uDCCF", "zwj": "\u200D", "zwnj": "\u200C" }, "optional-;": ["AElig", "AMP", "Aacute", "Acirc", "Agrave", "Aring", "Atilde", "Auml", "COPY", "Ccedil", "ETH", "Eacute", "Ecirc", "Egrave", "Euml", "GT", "Iacute", "Icirc", "Igrave", "Iuml", "LT", "Ntilde", "Oacute", "Ocirc", "Ograve", "Oslash", "Otilde", "Ouml", "QUOT", "REG", "THORN", "Uacute", "Ucirc", "Ugrave", "Uuml", "Yacute", "aacute", "acirc", "acute", "aelig", "agrave", "amp", "aring", "atilde", "auml", "ccedil", "cedil", "copy", "curren", "deg", "divide", "eacute", "ecirc", "egrave", "eth", "euml", "frac12", "frac14", "frac34", "gt", "iacute", "icirc", "iexcl", "igrave", "iquest", "iuml", "laquo", "lt", "macr", "micro", "middot", "nbsp", "not", "ntilde", "oacute", "ocirc", "ograve", "ordf", "ordm", "oslash", "otilde", "ouml", "para", "plusmn", "pound", "quot", "raquo", "reg", "sect", "shy", "sup1", "sup2", "sup3", "szlig", "thorn", "times", "uacute", "ucirc", "ugrave", "uml", "uuml", "yacute", "yen", "yuml"] } tdom-0.9.6-src/tests/data/dtd-5.1.dtd0000644000175000017500000000003215025767703015577 0ustar rolfrolf tdom-0.9.6-src/tests/data/dtd-6.3.dtd0000644000175000017500000000002015025767703015577 0ustar rolfrolf tdom-0.9.6-src/tests/data/books.xml0000644000175000017500000000361615025767703015700 0ustar rolfrolf Seven Years in Trenton Joe Bob Trenton Literary Review Honorable Mention 12 History of Trenton Mary Bob Selected Short Stories of Mary Bob 55 Tracking Trenton 2.50 Trenton Today, Trenton Tomorrow Toni Bob B.A. Ph.D. Pulizer Still in Trenton Trenton Forever 6.50

    It was a dark and stormy night.

    But then all nights in Trenton seem dark and stormy to someone who has gone through what I have.

    Trenton misery
    Who's Who in Trenton Robert Bob
    tdom-0.9.6-src/tests/data/xslt_1.xsl0000644000175000017500000000042215025767703015773 0ustar rolfrolf tdom-0.9.6-src/tests/data/dtd-5.2.dtd0000644000175000017500000000007215025767703015604 0ustar rolfrolf tdom-0.9.6-src/tests/data/mondial-europe.xml0000644000175000017500000132414015025767703017502 0ustar rolfrolf Albania AL 28750 3249136 1.34 49.2 4100 55 16 28 11 1912 emerging democracy 100 3 95 70 10 20 282 151 287 Tirane 10.7 46.2 192000 Shkoder 19.2 42.2 62000 Durres 19.3 41.2 60000 Vlore 19.3 40.3 56000 Elbasan 20.1 41.1 53000 Korce 20.5 40.4 52000 Greece GR 131940 10538594 0.42 7.4 101700 11.8 22.2 66 8.1 01 01 1829 parliamentary republic 100 98 1.3 98 282 228 494 206 Anatoliki Makedhonia kai Thraki 14157 574308 Attiki 3808 3522769 Athens 23.7167 37.9667 885737 Dhytiki Ellas 11350 702027 Dhytiki Makedhonia 9451 292751 Ionioi Nisoi 2307 191003 Ipiros 9203 339210 Kedriki Makedhonia 19147 1729581 Kriti 8336 537183 Notion Aiyaion 5286 262522 Peloponnisos 15490 605663 Sterea Ellas 15549 578876 Thessalia 14037 731030 Voreion Aiyaion 3836 189541 Macedonia MK 25333 2104035 0.46 29.7 1900 24 44 32 14.8 17 09 1991 emerging democracy 100 22 2 65 4 3 30 67 21 70 3 3 151 228 221 148 Skopje Serbia and Montenegro YU 102350 10614558 20600 20 11 04 1992 republic 100 63 14 6 4 19 4 1 65 5 95 287 221 151 527 266 318 476 Belgrade 20.4667 44.8 1407073 Andorra AND 450 72766 2.96 2.2 1000 parliamentary democracy that retains as its heads of state a coprincipality 100 6 61 30 100 60 65 Andorra la Vella 1.3 42.3 15600 France F 547030 58317450 0.34 5.3 1173000 2.4 26.5 71.1 1.7 republic 100 1 1 90 2 100 60 623 451 488 573 620 73 4.4 Alsace 8280 1624000 Strasbourg 7.76667 48.5833 252338 Mulhouse 108357 Aquitaine 41309 2796000 Bordeaux -0.4 44.51 210336 Auvergne 26013 1321000 Clermont Ferrand 3.4 45.5 136181 Basse Normandie 17589 1391000 Caen -0.2 49.3 112846 Bretagne 27209 2796000 Rennes -1.4 48.1 197536 Brest 147956 Bourgogne 31582 1609000 Dijon 5.2 47.2 146703 Centre 39151 2371000 Orleans 1.5 47.5 105111 Tours 129509 Champagne Ardenne 25606 1348000 Reims 180620 Chalons sur Marne Corse 8680 250000 Ajaccio 8.4 41.4 53500 Franche Comte 16202 1097000 Besancon 6.2 47.1 113828 Haute Normandie 12318 1737000 Rouen 1.5 49.3 102723 Le Havre 195854 Ile de France 12011 10660000 Paris 2.48333 48.8167 2152423 Boulogne Billancourt 101743 Languedoc Rousillon 27376 2115000 Montpellier 3.5 43.3 207996 Nimes 128471 Perpignan 105983 Limousin 16942 723000 Limoges 1.2 45.5 133464 Lorraine 23547 2306000 Metz 119594 Nancy 6.1 48.4 99351 Midi Pyrenees 45349 2431000 Toulouse 1.2 43.4 358688 Nord Pas de Calais 12413 3965000 Lille 3.3 50.37 172142 Pays de la Loire 32082 3059000 Nantes -1.56667 47.25 244995 Angers 141404 Le Mans 145502 Picardie 19399 1811000 Amiens 2.19 49.55 131872 Poitou Charentes 25809 1595000 Poitiers 0.2 46.4 79300 Provence Cote dAzur 31400 4258000 Marseille 5.2 43.2 800550 Nice 7.26667 43.7 342439 Toulon 167619 Aix en Provence 123842 Rhone Alpes 43698 5351000 Lyon 4.78333 45.7 415487 Grenoble 150758 Saint Etienne 199396 Villeurbanne 116872 Spain E 504750 39181114 0.16 6.3 565000 3.6 33.6 62.8 4.3 01 01 1492 parliamentary monarchy 100 100 99 null 17 7 2 65 623 1214 Andalusia 87600 7053043 Sevilla 714148 Almeria 167361 Cadiz -6.2 36.3 155438 Cordoba 315948 Granada 271180 Huelva 145049 Malaga 531443 Jerez de la Frontera 190390 Jaen 112772 Algeciras 103787 Aragon 47720 1183576 Zaragoza 606620 Asturias 10604 1083388 Oviedo 201712 Gijon 269644 Balearic Islands 4992 736865 Palma de Mallorca 322008 Basque Country 7235 2075561 Vitoria Gasteiz 214148 Bilbao 371876 Donostia 177929 Canary Islands 7447 1534897 Santa Cruz de Tenerife 203929 Las Palmas de Gran Canaria 371787 La Laguna 125183 Cantabria 5321 526090 Santander 194822 Castile and Leon 94224 2504371 Valladolid 336917 Albacete 141179 Burgos 166251 Leon 147311 Salamanca 167382 Castile La Mancha 79462 1656179 Toledo Catalonia 32113 6090107 Barcelona 2.15 41.4 1630867 Lleida 114234 Tarragona 114630 Hospitalet de Llobregat 266242 Badalona 219340 Sabadell 189006 Terrassa 161428 Santa Coloma de Gramanet 131764 Baracaldo 103594 Mataro 102117 Estremadura 41635 1050590 Badajoz 130153 Merida Galicia 29574 2720761 La Coruna 255087 Vigo 288573 Orense 108547 Santiago de Compostella Madrid 8028 5034548 Madrid -3.68333 40.4167 3041101 Mostoles 199141 Leganes 178162 Alcala de Henares 166250 Fuenlabrada 158212 Getafe 144368 Alcorcon 142165 Murcia 11314 1070401 Murcia 341531 Cartagena 179659 Navarre 10391 523614 Pamplona 182465 Rioja 5045 263437 Logrono 124823 Valencia 23255 3909047 Valencia -0.383333 39.4667 764293 Alacant 274964 Elx 191305 Castellon de la Plana 139094 Austria A 83850 8023244 0.41 6.2 152000 2 34 64 2.3 12 11 1918 federal republic 100 99.4 0.2 0.3 85 6 100 362 784 366 430 37 91 324 164 Burgenland 3965 273000 Eisenstadt 16 48 10102 Carinthia 9533 559000 Klagenfurt 14.21 46.38 87321 Vorarlberg 2601 341000 Bregenz 9.45 47.3 Vienna 415 1583000 Vienna 16.3667 48.25 1583000 Upper Austria 11979 1373000 Linz 14.18 48.18 203000 Tyrol 12647 649000 Innsbruck 11.22 47.17 118000 Styria 16386 1203000 Graz 15.26 47.4 238000 Salzburg 7154 501000 Salzburg 13.2 47.49 144000 Lower Austria 19170 1507000 St. Polten 15.38 48.13 51102 Czech Republic CZ 78703 10321120 -0.03 8.4 106200 5.8 40.7 53.5 9.1 01 01 1993 parliamentary democracy 100 0.5 0.6 0.3 0.2 94.4 3 39.2 4.6 3 362 646 214 658 Jihocesky 11345 702000 Ceske Budejovice 174000 Jihomoravsky 15028 2059000 Brno 393000 Zlin 198000 Severocesky 7819 1190000 Liberec 160000 Usti nad Labem Severomoravsky 11067 1976000 Ostrava 332000 Olomouc 225000 Praha 11490 2329000 Prague 14.4167 50.0833 1215000 Vychodocesky 11240 1240000 Hradec Kralove 164000 Pardubice 163000 Zapadocesky 10875 869000 Plzen 175000 Germany D 356910 83536115 0.67 6 1452200 1 34.2 64.8 18 01 1871 federal republic 100 0.4 2.3 95.1 0.7 0.4 37 45 100 451 784 646 334 456 167 138 577 68 Baden Wurttemberg 35742 10272069 Stuttgart 9.1 48.7 588482 Mannheim 8.46667 49.5667 316223 Karlsruhe 277011 Freiburg im Breisgau 198496 Heidelberg 138964 Heilbronn 122253 Pforzheim 117960 Ulm 115123 Reutlingen 107782 Bayern 70546 11921944 Munich 11.5667 48.15 1244676 Nurnberg 495845 Augsburg 262110 Oberhausen 225443 Wurzburg 127946 Regensburg 125608 Ingolstadt 110910 Furth 107799 Erlangen 101450 Berlin 889 3472009 Berlin 13.3 52.45 3472009 Brandenburg 29480 2536747 Potsdam 138268 Cottbus 125643 Bremen 404 680000 Bremen 8.5 53.7 549182 Bremerhaven 130847 Hamburg 755 1705872 Hamburg 9.96667 53.55 1705872 Hessen 21115 5980693 Wiesbaden 8.17 50.07 266081 Frankfurt am Main 652412 Kassel 201789 Darmstadt 139063 Offenbach am Main 116482 Mecklenburg Vorpommern 23170 1832298 Schwerin 118291 Rostock 232634 Niedersachsen 47609 7715363 Hannover 9.66667 52.4 525763 Braunschweig 254130 Osnabruck 168050 Oldenburg 149691 Gottingen 127519 Wolfsburg 126965 Salzgitter 117842 Hildesheim 106095 Nordrhein Westfalen 34077 17816079 Dusseldorf 572638 Koln 963817 Essen 617955 Dortmund 600918 Duisburg 536106 Bochum 401129 Wuppertal 383776 Bielefeld 324067 Gelsenkirchen 293542 Bonn 293072 Monchengladbach 266073 Munster 264887 Krefeld 249662 Aachen 247113 Hagen 213747 Hamm 184020 Herne 180029 Mulheim an der Ruhr 176513 Solingen 165973 Leverkusen 161832 Neuss 148870 Paderborn 131513 Recklinghausen 127139 Remscheid 123069 Bottrop 119669 Siegen 111541 Moers 107011 Witten 105423 Bergisch Gladbach 105122 Rheinland Pfalz 19851 3951573 Mainz 8.1 50 184627 Ludwigshafen 167883 Koblenz 109550 Kaiserslautern 101910 Saarland 2570 1084201 Saarbrucken 6.6 49.1 189012 Sachsen 18412 4584345 Dresden 474443 Leipzig 481121 Chemnitz 274162 Zwickau 104921 Sachsen Anhalt 20446 2759213 Magdeburg 265379 Halle 290051 Schleswig Holstein 15738 2708392 Kiel 10.7 54.2 246586 Lubeck 216854 Thuringen 16171 2517776 Erfurt 213472 Gera 126035 Jena 102204 Hungary H 93030 10002541 -0.68 12.3 72500 7.3 37.5 55.2 28.3 01 01 1001 republic 100 2 2.6 4 89.9 0.8 0.7 67.5 5 20 98.2 151 366 515 102 103 329 443 Baranya 4487 417100 Bacs Kiskun 8363 540800 Kecskemet 105000 Bekes 5632 404000 Bekescaba Borsod Abauj Zemplen 7248 749100 Csongrad 4263 437600 Hodmezovasarhely Fejer 4374 422500 Szekesfehervar 109000 Gyor Sopron 4012 426800 Hajdu Bihar 6212 549700 Heves 3637 330200 Eger Komarom Esztergom 2250 312900 Tatabanya Nograd 2544 222700 Salgotarjan Pest 6394 957900 Somogy 6035 340000 Kaposvar Szabolcs Szatmar 5938 563500 Nyiregyhaza 115000 Szolnok 5608 420900 Szolnok Tolna 3702 251000 Szekszard Vas 3337 273900 Szombathely Veszprem 4689 378300 Veszprem Zala 3786 302600 Zalaegerszeg Budapest (munic.) 525 2008500 Budapest 19.0333 47.5167 2016000 Debrecen (munic.) 446 217300 Debrecen 216000 Gyor (munic.) 175 130600 Gyor 130000 Miskolc (munic.) 224 191000 Miskolc 192000 Pecs (munic.) 113 171600 Pecs 171000 Szeged (munic.) 145 178500 Szeged 178000 Italy I 301230 57460274 0.13 6.9 1088600 2.9 31.6 65.5 5.4 17 03 1861 republic 100 98 488 430 235 740 3.2 39 Piemonte 25399 4307000 Novara 103349 Turin 7.39 45.5 991870 Valle dAosta 3262 118000 Aosta 7.22 45.45 Lombardia 23857 8901000 Bergamo 117886 Brescia 196766 Milan 9.28333 45.45 1432184 Monza 123188 Trentino Alto Adige 13618 904000 Bolzano 100380 Trento 102124 Veneto 18364 4415000 Padova 218186 Verona 258946 Vicenza 109333 Venice 12.2 45.27 317837 Friuli Venezia Giulia 7845 1193000 Trieste 231047 Liguria 5418 1663000 La Spezia 103008 Genua 8.58 44.25 701032 Emilia Romagna 22123 3924000 Bologna 11.22 44.3 411803 Ferrara 140600 Modena 177501 Parma 173991 Piacenza 103536 Ravenna 136724 Reggio nellEmilia 131880 Rimini 130896 Toscana 22992 3528000 Livorno 171265 Pisa 101500 Firenze 11.17 43.48 408403 Prato 166688 Umbria 8456 819000 Perugia 12.2 43.1 150576 Terni 109809 Marche 9693 1438000 Ancona 13.28 43.38 103268 Lazio 17203 5185000 Rome 12.6 41.8 2791354 Latina 103630 Abruzzo 10794 1263000 Pescara 128553 LAquila 13.2 42.24 Molise 4438 332000 Campobasso 14.5 41.5 Campania 13595 5709000 Salerno 151374 Napoli 14.15 40.5 1206013 Torre del Greco 102647 Puglia 19348 4066000 Bari 16.5 41.8 353032 Foggia 159541 Lecce 102344 Taranto 244033 Basilicata 9992 611000 Potenza 15.47 40.4 Calabria 15080 2080000 Catanzaro 16.35 38.55 103802 Cosenza 104483 Messina 274846 Reggio di Calabria 178496 Sicilia 25709 5025000 Palermo 13.2 38.1 734238 Catania 364176 Siracusa 125444 Sardegna 24090 1657000 Cagliari 9.5 39.15 211719 Sassari 120011 Liechtenstein FL 160 31122 1.08 5.3 630 5.4 23 01 1719 hereditary constitutional monarchy 100 5 95 87.3 8.3 37 41 Vaduz 9.3 47.08 27714 Slovakia SK 48845 5374362 0.34 10.7 39000 6.7 47.6 45.7 7.5 01 01 1993 parliamentary democracy 100 0.1 0.1 1.5 10.7 1 85.7 0.3 0.3 60.3 8.4 4.1 91 215 515 444 90 Bratislava Slovenia SLO 20256 1951443 -0.27 7.3 22600 5.3 39.9 54.8 8 25 06 1991 emerging democracy 100 2 91 1 3 1 96 91 7 324 102 235 546 Ljubljana Switzerland CH 41290 7207060 0.59 5.4 158500 3 33.5 63.5 1.8 federal republic 100 47.6 44.3 18 65 12 1 573 164 334 740 41 AG 1403 528887 Aarau AR 242 54104 Herisau AI 172 14750 Appenzell BL 517 252331 Liestal BS 37 195759 Basel 172768 BE 5960 941952 Bern 7.3 46.6 134393 Biel 53308 FR 1670 224552 Fribourg GE 282 395466 Geneva 6.9 46.12 167697 GL 685 39410 Glarus GR 7105 185063 Chur JU 836 69188 Delemont LU 1493 340536 Luzern 59811 NE 803 165258 Neuchatel NW 276 36466 Stans OW 490 31310 Sarnen SG 2025 442350 Sankt Gallen 74106 SH 298 74035 Schaffhausen SZ 908 122409 Schwyz SO 790 239264 Solothurn TG 990 223372 Frauenfeld TI 2812 305199 Bellinzona UR 1076 35876 Altdorf VS 5224 271291 Sion VD 3211 605677 Lausanne 123149 ZG 238 92392 Zug ZH 1728 1175457 Zurich 343106 Winterthur 86340 Belarus BY 207600 10415973 0.2 13.4 49200 21 49 30 244 25 08 1991 republic 100 4.1 2.9 13.2 77.9 60 141 502 605 891 959 Minsk 27.55 53.9 1540000 Latvia LV 64100 2468982 -1.39 21.2 14700 9 31 60 20 06 09 1991 republic 100 2.3 3.4 33.8 4.5 51.8 141 453 217 267 Riga 14.1 57 900000 Lithuania LT 65200 3646041 -0.35 17 13300 20 42 38 35 06 09 1991 republic 100 7.7 8.6 1.5 80.1 502 453 91 227 Vilnius 25.3 54.4 566000 Poland PL 312683 38642565 0.14 12.4 226700 7 38 55 21.6 11 11 1918 democratic state 100 1.3 97.6 0.6 0.5 95 100 658 456 444 605 91 428 206 Warszwaskie 3788 2421000 Warsaw 21.0333 52.2167 1655000 Bialskopodlaskie 5348 306700 Biala Podlaska Bialostockie 10055 697000 Bialystok 268000 Bielskie 3704 911500 Bielsko Biala 180000 Bydgoskie 10349 1120300 Bydgoszcz 380000 Chelmskie 3866 248500 Chelm Ciechanowskie 6362 431400 Ciechanow Czestochowskie 6182 748000 Czestochowa 258000 Elblaskie 6103 483200 Elblag 125000 Gdanskie 7394 1445000 Gdansk 465000 Gdynia 251000 Gorzowskie 8484 505600 Gorzow Wielkopolski 123000 Gorzow Wielkopolskie Jeleniogorskie 4379 519200 Jelenia Gora Kaliskie 6512 715600 Kalisz 106000 Katowickie 6650 4013200 Katowice 367000 Sosnowiec 259000 Bytom 230000 Gliwice 216000 Zabrze 203000 Tychy 190000 Ruda Slaska 170000 Rybnik 143000 Chorzow 133000 Wodzilaw Slaski 111000 Kieleckie 9211 1127700 Kielce 213000 Koninskie 5139 472400 Konin Koszalinskie 8470 513700 Koszalin 108000 Krakowskie 3254 1238100 Krakow 19.95 50.0667 748000 Krosnienskie 5702 500700 Krosno Legnickie 4037 521500 Legnica 104000 Leszczynskie 4154 391500 Leszno Lubelskie 6792 1022600 Lublin 350000 Lomzynskie 6684 349000 Lomza Lodzkie 1523 1132400 Lodz 852000 Nowosadeckie 5576 709500 Nowy Sacz Olsztynskie 12327 761300 Olsztyn 161000 Opolskie 8535 1023800 Opole 128000 Ostroleckie 6498 400500 Ostroleka Pilskie 8205 485700 Pila Piotrkowskie 6266 644200 Piottrkow Trybunalski Plockie 5117 518600 Plock 122000 Poznanskie 8151 1344200 Poznan 589000 Przemyskie 4437 409600 Przemysl Radomskie 7294 755500 Radom 226000 Rzeszowskie 4397 734100 Rzeszow 151000 Siedleckie 8499 655300 Siedlce Sieradzkie 4869 408700 Sieradz Skierniewickie 3960 421700 Skierniewice Slupskie 7453 419300 Slupsk Suwalskie 10490 477100 Suwalki Szczecinskie 9982 979500 Szczecin 412000 Tarnobrzeskie 6283 604300 Tarnobrzeg Tarnowskie 4151 678400 Tarnow 120000 Torunskie 5348 662600 Torun 201000 Grudziadz 101000 Walbrzyskie 4168 740000 Walbrzych 141000 Wloclawskie 4402 430800 Wloclawek 121000 Wroclawskie 6287 1132800 Wroclaw 642000 Zamojskie 6980 490800 Zamosc Zielonogorskie 8868 664700 Zielona Gora 113000 Ukraine UA 603700 50864009 -0.4 22.5 174600 31 43 26 9 01 12 1991 republic 100 73 22 1 103 90 891 428 1576 531 939 Cherkaska 20900 1530900 Cherkasy 297000 Chernihivska 31900 938600 Chernihiv 301000 Chernivetska 8100 1405800 Chernivtsi 257000 Dnipropetrovska 31900 3908700 Dnipropetrovsk 1187000 Kryvyy Rih 717000 Dniprodzerzhynsk 284000 Donetska 26500 5346700 Donetsk 1117000 Mariupol 520000 Makiyivka 427000 Horlivka 338000 Ivano Frankivska 13900 1442900 Ivano Frankivsk 220000 Kharkivska 31400 3194800 Kharkiv 36.2333 50 1618000 Khersonska 28500 1258700 Kherson 361000 Khmelnytska 20600 1520600 Khmelnytskyy 241000 Kyyivska 28900 4589800 Kiev 30.5 50.45 2616000 Kirovohradska 24600 1245300 Kirovohrad 274000 Luhanska 26700 2871100 Luhansk 501000 Lvivska 21800 2764400 Lviv 798000 Mykolayivska 24600 1342400 Mykolayiv 508000 Odeska 33300 2635300 Odesa 30.7333 46.4833 1106000 Poltavska 28800 1756900 Poltava 317000 Kremenchuk 238000 Rivnenska 20100 1176800 Rivne 233000 Sumska 23800 1430200 Sumy 296000 Ternopilska 13800 1175100 Ternopil 212000 Vinnytska 26500 1914400 Vinnytsya 379000 Volynska 20200 1069000 Lutsk 204000 Zakarpatska 12800 1265900 Uzhhorod Zaporizka 27200 2099600 Zaporizhzhya 891000 Zhytomyrska 29900 1510700 Zhytomyr 296000 Krym 27000 2549800 Simferopol 349000 Sevastopol 361000 Russia R 17075200 148178487 -0.07 24.7 796000 6 41 53 7 24 08 1991 federation 20 3 81.5 0.8 3.8 1.2 0.9 0.7 100 959 217 227 206 1576 290 1313 167 Rep. of Karelia 172400 785000 Petrozavodsk 280000 Rep. of Komi 415900 1185500 Syktyvkar 229000 Ukhta 106000 Vorkuta 104000 Arkhangelskaya oblast 587400 1520800 Arkhangelsk 40.5333 64.55 374000 Severodvinsk 241000 Vologodskaya oblast 145700 1349800 Vologda 299000 Cherepovets 320000 Murmanskaya oblast 144900 1048000 Murmansk 407000 Kaliningradskaya oblast 15100 932200 Kaliningrad 20.5 54.7167 419000 Sankt Peterburg 0 4801500 Sankt Peterburg 4838000 Leningradskaya oblast 85900 1675900 Kolpino 143000 Novgorodskaya oblast 55300 742600 Novgorod 233000 Pskovskaya oblast 55300 832300 Pskov 207000 Velikiye Luki 116000 Bryanskaya oblast 34900 1479700 Bryansk 462000 Vladimirskaya oblast 29000 1644700 Vladimir 339000 Kovrov 162000 Murom 126000 Ivanovskaya oblast 23900 1266400 Ivanovo 474000 Kineshma 103000 Kaluzhskaya oblast 29900 1097300 Kaluga 347000 Obninsk 108000 Kostromskaya oblast 60100 805700 Kostroma 285000 Moskva 0 8664400 Moscow 37.6667 55.7667 8717000 Moskovskaya oblast 47000 6596600 Podolsk 202000 Zelenograd 191000 Lyubertsy 166000 Kolomna 154000 Mytishchi 152000 Elektrostal 150000 Serpukhov 139000 Balashikha 136000 Khimki 134000 Odintsovo 129000 Orekhovo Zuyevo 126000 Noginsk 119000 Shchyolkovo 108000 Orlovskaya oblast 24700 914000 Orel 348000 Ryazanskaya oblast 39600 1325300 Ryazan 536000 Smolenskaya oblast 49800 1172400 Smolensk 355000 Tverskaya oblast 84100 1650600 Tver 455000 Tulskaya oblast 25700 1814500 Tula 532000 Novomoskovsk 144000 Yaroslavskaya oblast 36400 1451400 Yaroslavl 629000 Rybinsk 248000 Rep. of Mariy El 23200 766300 Yoshkar Ola 251000 Rep. of Mordovia 26200 955800 Saransk 320000 Chuvash Republic 18300 1360800 Cheboksary 450000 Novocheboksarsk 123000 Kirovskaya oblast 120800 1634500 Kirov 464000 Nizhegorodskaya oblast 74800 3726400 Nizhniy Novgorod 1383000 Dzerzhinsk 285000 Arzamas 112000 Belgorodskaya oblast 27100 1469100 Belgorod 322000 Stary Oskol 198000 Voronezhskaya oblast 52400 2503800 Voronezh 908000 Kurskaya oblast 29800 1346900 Kursk 442000 Lipetskaya oblast 24100 1250200 Lipetsk 474000 Yelets 119000 Tambovskaya oblast 34300 1310600 Tambov 316000 Michurinsk 108000 Rep. of Kalmykiya 76100 318500 Elista Rep. of Tatarstan 68000 3760500 Kazan 1085000 Naberezhnye Chelny 526000 Nizhnekamsk 210000 Almetyevsk 138000 Zelenodolysk 101000 Astrakhanskaya oblast 44100 1028900 Astrakhan 486000 Volgogradskaya oblast 113900 2703700 Volgograd 44.5167 48.7 1003000 Volzhsky 288000 Kamyshin 128000 Penzenskaya oblast 43200 1562300 Penza 534000 Kuznetsk 100000 Samarskaya oblast 53600 3311500 Samara 1184000 Tolyatti 702000 Syzran 177000 Novokuybyshevsk 115000 Saratovskaya oblast 100200 2739500 Saratov 895000 Balakovo 206000 Engels 186000 Ulyanovskaya oblast 37300 1495200 Simbirsk 678000 Dimitrovgrad 135000 Rostovskaya oblast 100800 4426400 Rostov na Donu 1026000 Taganrog 292000 Shakhty 230000 Novocherkassk 190000 Volgodonsk 183000 Novoshakhtinsk 107000 Rostov no Donu Rep. of Bashkortostan 143600 4096600 Ufa 1094000 Sterlitamak 259000 Salavat 156000 Oktyabrsky 110000 Udmurt Republic 42100 1639100 Izhevsk 654000 Sarapul 109000 Glazov 107000 Votkinsk 104000 Orenburgskaya oblast 124000 2228600 Orenburg 532000 Orsk 275000 Novotroitsk 110000 Permskaya oblast 160600 3009400 Perm 1032000 Berezniki 184000 Solikamsk 108000 Rep. of Adygeya 7600 450500 Maykop 165000 Rep. of Dagestan 50300 2097500 Makhachkala 339000 Rep. of Ingushetiya 3750 299700 Nazran Kabardino Balkar Rep. 12500 789900 Nalchik 239000 Karachayevo Cherkessk Rep. 14100 436300 Cherkessk 119000 Rep. of North Ossetiya 8000 662600 Vladikavkaz 312000 Chechen Rep. 12300 865100 Grozny 364000 Krasnodarsky kray 76000 5043900 Krasnodar 646000 Sochi 355000 Novorossiysk 202000 Armavir 164000 Stavropolsky kray 66500 2667000 Stavropol 342000 Pyatigorsk 133000 Nevinnomyssk 131000 Kislovodsk 120000 Neftekamsk 117000 Kurganskaya oblast 71000 1112200 Kurgan 363000 Sverdlovskaya oblast 194300 4686300 Yekaterinburg 1280000 Nizhniy Tagil 409000 Kamensk Uralskiy 197000 Pervouralsk 137000 Serov 100000 Chelyabinskaya oblast 87900 3688700 Chelyabinsk 1086000 Magnitogorsk 427000 Zlatoust 203000 Miass 167000 Rep. of Altay 92600 201600 Gorno Altaysk Altayskiy kray 169100 2690100 Barnaul 596000 Biysk 228000 Rubtsovsk 170000 Kemerovskaya oblast 95500 3063500 Kemerovo 503000 Novokuznetsk 572000 Prokopyevsk 253000 Leninsk Kuznetskiy 121000 Kiselyovsk 116000 Mezhdurechensk 105000 Anzhero Sudzhensk 101000 Novosibirskaya oblast 178200 2748600 Novosibirsk 1369000 Omskaya oblast 139700 2176400 Omsk 1163000 Tomskaya oblast 316900 1077600 Tomsk 470000 Tyumenskaya oblast 1435200 3169900 Tyumen 494000 Surgut 263000 Nizhnevartovsk 238000 Rep. of Buryatiya 351300 1052500 Ulan Ude 366000 Rep. of Tyva 170500 309700 Kyzyl Rep. of Khakassiya 61900 585800 Abakan 161000 Krasnoyarskiy kray 2339700 3105900 Krasnoyarsk 92.95 56.0167 869000 Norilsk 159000 Achinsk 123000 Kansk 109000 Irkutskaya oblast 767900 2795200 Irkutsk 585000 Angarsk 267000 Bratsk 257000 Ust Ilimsk 110000 Usolye Sibirskoye 106000 Chitinskaya oblast 431500 1295000 Chita 322000 Rep. of Sakha 3103200 1022800 Yakutsk 192000 Yevreyskaya avt. oblast 36000 209900 Birobidzhan Chukotsky ao 737700 90500 Anadyr Primorsky kray 165900 2255400 Vladivostok 131.917 43.1167 632000 Nakhodka 163000 Ussuriysk 162000 Khabarovskiy kray 752600 1571200 Khabarovsk 618000 Komsomolsk na Amure 309000 Amurskaya oblast 363700 1037800 Blagoveshchensk 214000 Kamchatskaya oblast 472300 411100 Petropavlovsk Kamchatsky 210000 Magadanskaya oblast 461400 258200 Magadan 128000 Sakhalinskaya oblast 87100 647800 Yuzhno Sakhalinsk 160000 Belgium B 30510 10170241 0.33 6.4 197000 2 28 70 1.6 04 10 1830 constitutional monarchy 100 55 33 75 25 32 1 56 620 167 148 450 Antwerp 2867 1610695 Antwerp 4.23 51.1 459072 Brabant 3358 2253794 Brussels 4.35 50.8 951580 East Flanders 2982 1340056 Ghent 3.5 51.4 227483 Hainaut 3787 1283252 Charleroi 206491 Mons 3.6 50.3 90720 Liege 3862 1006081 Liege 5.5 50.5 192393 Limburg 2422 755593 Hasselt 5.2 50.7 65348 Luxembourg 4441 234664 Arlon 5.5 49.4 23150 Namur 3665 426305 Namur 4.5 50.3 105014 West Flanders 3134 1111557 Bruges 116273 Brugge 2.08 51.1 117799 Luxembourg L 2586 415870 1.57 4.7 10000 1.4 33.7 64.9 3.6 constitutional monarchy 100 97 3 73 138 148 Luxembourg 6.08 49.4 76600 Netherlands NL 37330 15568034 0.56 4.9 301900 3.4 26.9 69.7 2.25 01 01 1579 constitutional monarchy 100 96 3 34 25 100 577 450 Groningen 2344 557995 Groningen 210708 Friesland 3361 609579 Leeuwarden Drenthe 2652 454864 Assen Overijssel 3337 1050389 Enschede 254480 Zwolle Flevoland 1425 262325 Lelystad Gelderland 4995 1864732 Arnhem 314159 Nijmegen 249490 Utrecht 1356 1063460 Utrecht 547070 Noord Holland 265978 2463611 Amsterdam 4.91667 52.3833 1101407 Haarlem 212631 Zaanstreek 147917 Velsen 134973 Hilversum 102023 Zuid Holland 2859 3325064 s Gravenhage 694249 Rotterdam 1078747 Dordrecht 213963 Leiden 194935 Zeeland 1791 365846 Middelburg Noord Brabant 4938 2276207 s Hertogenbosch 199127 Eindhoven 395612 Tilburg 237958 Breda 166616 Limburg 2167 1130050 Maastricht 164701 Heerlen 270952 Geleen 186011 Bosnia and Herzegovina BIH 51233 2656240 -2.84 43.2 1000 01 04 1992 emerging democracy 100 40 38 22 40 4 31 15 99 527 932 Sarajevo Croatia HR 56538 5004112 0.58 10.2 20100 12.7 30.6 56.7 3.7 25 06 1991 parliamentary democracy 100 12 0.5 0.9 78 0.5 0.4 11.1 76.5 1.2 96 266 329 546 932 Zagreb Bulgaria BG 110910 8612757 0.46 15.7 43200 12 36 52 35 22 09 1908 emerging democracy 100 2.5 2.6 0.2 8.5 85.3 0.3 13 0.8 0.5 85 0.2 100 494 148 318 608 240 Sofia 23.3333 42.7 1300000 Romania RO 237500 21657162 -1.21 23.2 105700 19.6 36.3 44.1 25 01 01 1881 republic 100 0.4 1.6 8.9 89.1 6 6 70 476 443 531 608 450 Alba 6231 428000 Alba Iulia Arad 7652 507000 Arad 191000 Arges 6801 678000 Pitesti 162000 Bacau 6606 731000 Bacau 193000 Bihor 7535 660000 Oradea 225000 Bistrita Nasaud 5305 328000 Bistrita Botosani 4965 468000 Botosani Braila 4724 404000 Braila 243000 Brasov 5351 695000 Brasov 353000 Bucuresti 1521 2319000 Bucharest 26.1 44.4167 2037000 Buzau 6072 524000 Buzau 145000 Calarasi 5075 351000 Calarasi Caras Severin 8503 408000 Resita Cluj 6650 743000 Cluj Napoca 318000 Constanta 7055 737000 Constanta 316000 Covasha 3705 238000 Sfintu Gheorghe Dimbovita 4035 570000 Tirgoviste Dolj 7413 772000 Craiova 300000 Galati 4425 642000 Galati 307000 Giurgiu 3810 325000 Giurgiu Gorj 5641 388000 Tirgu Jiu Harghita 6610 363000 Miercurea Ciuc Hunedoara 7016 567000 Deva Ialomita 4449 309000 Slobozia Iasi 5469 810000 Iasi 330000 Maramures 6215 556000 Baia Mare 150000 Mehedinti 4900 329000 Drobeta Turnu Severin Mures 6696 621000 Tirgu Mures 165000 Neamt 5890 580000 Piatra Neamt Olt 5507 535000 Slatina Prahova 4694 877000 Ploiesti Salaj 3850 269000 Zalau Satu Mare 4405 417000 Satu Mare 137000 Sibiu 5422 509000 Sibiu 184000 Suceava 8555 699000 Suceava Teleorman 5760 504000 Alexandria Timis 8692 726000 Timisoara 333000 Tulcea 8430 275000 Tulcea Vaslui 5297 468000 Vaslui Vilcea 5705 430000 Rimnicu Vilcea Vrancea 4863 394000 Focsani Turkey TR 780580 62484478 1.67 43.2 345700 15.5 33.2 51.3 94 29 10 1923 republican parliamentary democracy 32 80 20 99.8 206 240 Adana 17253 1934907 Adana 35.3 36.9833 1047300 Osmaniye 138000 Adiyaman 7614 513131 Adiyaman 128000 Afyon 14230 739223 Afyon Agri 11376 437093 Agri Aksaray 7626 326399 Aksaray Amasya 5520 357191 Amasya Ankara 25706 3236626 Ankara 32.8833 39.95 2782200 Antalya 20591 1132211 Antalya 497200 Artvin 7436 212833 Artvin Aydin 8007 824816 Aydin 121200 Balikesir 14292 973314 Balikesir 187600 Batman 4694 344669 Batman 182800 Bayburt 3652 107330 Bayburt Bilecik 4307 175526 Bilecik Bingol 8125 250966 Bingol Bitlis 6707 330115 Bitlis Bolu 11051 536869 Bolu Burdur 6887 254899 Burdur Bursa 11043 1603137 Bursa 996600 Canakkale 9737 432263 Canakkale Cankiri 8454 279129 Cankiri Corum 12820 609863 Corum Denizli 11868 750882 Denizli 234500 Diyarbakir 15355 1094996 Diyarbakir 448300 Edirne 6276 404599 Edirne 115500 Elazig 9153 498225 Elazig 222800 Erzincan 11903 299251 Erzincan Erzurum 25066 848201 Erzurum 250100 Eskisehir 13652 641057 Eskisehir 451000 Gaziantep 7642 1140594 Gaziantep 716000 Giresun 6934 499087 Giresun Gumushane 6575 169375 Gumushane Hakkari 7121 172479 Hakkari Hatay 5403 1109754 Iskenderun 156800 Antakya 137200 Icel 15853 1266995 Mersin 523000 Tarsus 225000 Isparta 8933 434771 Isparta 120900 Istanbul 5712 7309190 Istanbul 28.8333 40.9667 7615500 Izmir 11973 2694770 Izmir 27.1667 38.4333 1985300 Karaman 9163 217536 Karaman Karamanmaras 14327 892952 Karaman Maras 242200 Kars 18557 662155 Kars Kastamonu 13108 423611 Kastamonu Kayseri 16917 943484 Kayseri 454000 Kirikkale 4365 349396 Kirikkale 170300 Kirklareli 6550 309512 Kirklareli Kirsehir 6570 256862 Kirsehir Kocaeli 3626 936163 Izmit 275800 Kocaeli 256882 Gebze 237300 Adapazari 186000 Konya 38257 1750303 Konya 576000 Kutahya 11875 578020 Kutahya 140700 Malatya 12313 702055 Malatya 319700 Manisa 13810 1154418 Manisa 187500 Mardin 8891 557727 Mardin Mugla 13338 562809 Mugla Mus 8196 376543 Mus Nevsehir 5467 289509 Nevsehir Nigde 7312 305861 Nigde Ordu 6001 830105 Ordu 121300 Rize 3920 348776 Rize Sakarya 4817 683061 Sakarya Samsun 9579 1158400 Samsun 326900 Sanliurfa 18584 1001455 Urfa 357900 Siirt 5406 243435 Siirt Sinop 5862 265153 Sinop Sirnak 7172 262006 Sirnak Sivas 28488 767481 Sivas 240100 Tekirdag 6218 468842 Tekirdag Tokat 9958 719251 Tokat Trabzon 4685 795849 Trabzon 145400 Tunceli 7774 133143 Tunceli Usak 5341 290283 Usak 119900 Van 19069 637433 Van 194600 Yozgat 14123 579150 Yozgat Zonguldak 8629 1073560 Zonguldak 115900 Karabuk 113900 Denmark DK 43070 5249632 0.38 4.8 112800 3 23.5 73.5 2.4 constitutional monarchy 100 91 2 68 Copenhagen 12.55 55.6833 1358540 Aarhus 10.1 56.1 194345 Odense 10.2 55.3 136803 Aalborg 10 57 113865 Esbjerg 8.3 55.3 70975 Randers 10 56.3 55780 Estonia EW 45100 1459428 -1.13 17.4 12300 10 37 53 29 06 09 1991 republic 100 3.2 30.3 1.8 1.1 61.5 267 290 Tallinn 25 59.3 478000 Finland SF 337030 5105230 0.1 4.9 92400 4.6 28 67.4 2 06 12 1917 republic 100 1 89 6.3 93.5 1313 729 586 Aland 23000 Mariehamn 19.5 60.1 9500 Haeme 662000 Haemeenlinna 24.3 61 42000 Tampere 23.5 61.3 170097 Lahti 25.2 60.5 94234 Kuopio 252000 Kuopio 27.4 62.5 78571 Kymi 345000 Kotka 26.5 60.3 58345 Lappeenrenta 26.5 60.5 53922 Lappia 195000 Rovaniemi 24.4 66.3 31000 Mikkeli 209000 Mikkeli 27.2 61.4 28000 Suomi 242000 Jyvaeskylae 25.2 62.1 65511 Pohjols-Karjala 177000 Joensuu 29.5 62.4 44000 Oulu 415000 Oulu 25.2 65.3 97898 Turku-Pori 702000 Turku 22.1 60.3 161292 Pori 21.2 61.3 77763 Uusimaa 1119000 Helsinki 24.95 60.1667 487428 Espoo 24.3 60.2 160480 Vaasa 430000 Vaasa 21.3 63 54275 Norway N 324220 4383807 0.48 4.9 106200 2.9 34.7 62.4 2.5 26 10 1905 constitutional monarchy 100 87.8 3.8 100 167 729 1619 Oslo 449337 Oslo 10.7333 59.9333 449337 Akershus 393217 Oestfold 234941 Moss 10.4 59.3 24517 Hedmark 186355 Hamar 11.5 60.5 15685 Oppland 181791 Lillehammer 10.3 61.1 22118 Buskerud 219967 Drammen 10.1 59.4 50855 Vestfold 191600 Toensberg 10.2 59.2 8984 Telemark 162547 Skien 9.4 59.1 47010 Aust Agder 94688 Arendal 8.4 58.3 12174 Vest Agder 140232 Kristiansand 8 58.1 62640 Rogaland 323365 Stavanger 5.5 59 95089 Hordaland 399702 Bergen 5.2 60.2 207916 Sogn og Fjordane 106116 Hermannsverk 6.5 61.1 706 Moere og Romsdal 237290 Molde 7.1 62.5 21448 Soer Trondelag 246824 Trondheim 10.2 63.3 134426 Nord Trondelag 126692 Steinkjer 11.3 64 20480 Nordland 242268 Bodoe 14.2 67.2 34479 Svolvaer 14.3 68.2 4500 Narvik 17.3 68.3 18754 Troms 146736 Tromsoe 19 69.4 48109 Finnmark 75667 Vadsoe 29.5 70.5 5961 Hammerfest 23.4 70.4 7089 Sweden S 449964 8900954 0.56 4.5 177300 2 27 71 2.6 constitutional monarchy 100 12 1.5 94 1 100 586 1619 Ĭvsborg 11395 444259 Vanersborg Blekinge 2941 151168 Karlskrona 15.3 56.1 59007 Gavleborg 18191 289339 Gavle Goteborg och Bohus 5141 742550 Goteborg 449189 Gotland 3140 57383 Visby 18.2 57.3 20000 Halland 5454 257874 Halmstad 13 56.4 77601 Jamtland 49443 136009 Ostersund Jonkoping 9944 309738 Jonkoping 115429 Kalmar 11170 241883 Kalmar 16.3 56.4 54554 Kopparberg 28194 290388 Falun 15.3 60.3 51900 Kristianstad 6087 291468 Kristianstad 14 56 69941 Kronoberg 8458 178612 Vaxjo Malmohus 4938 786757 Malmo 245699 Helsingborg 114339 Norrbotten 98913 264834 Lulea Orebro 8519 273608 Orebro 119635 Ostergotland 10562 406100 Linkoping 131370 Norrkoping 123795 Skaraborg 7937 278162 Mariestad 13.5 58.4 24255 Sodermanland 6060 256818 Nykoping Stockholm 6488 1654511 Stockholm 18.0667 59.35 711119 Uppsala 6989 273918 Uppsala 17.4 59.5 183472 Varmland 17584 284187 Karlstad 13.3 59.3 74669 Vasterbotten 55401 253835 Umea Vasternorrland 21678 261280 Harnosand Vastmanland 6302 259438 Vasteras 123728 Monaco MC 1.9 31719 0.59 6.9 788 01 01 1419 constitutional monarchy 100 47 16 16 95 4.4 Monaco 7.2 43.7 1234 Holy See V 0.44 840 11 02 1929 monarchical sacerdotal state 100 100 3.2 Vatican City 12.3 41.5 392 Iceland IS 103000 270292 0.83 4.3 5000 9.6 22.1 68.3 2.5 17 06 1944 republic 100 100 96 3 100 Reykjavik 21.9333 64.1333 84000 Keflavik -22.5 64 6600 Hafnarfjoerdur -22 64 12000 Akureyri 18.3 65.4 13000 Ireland IRL 70280 3566833 -0.22 6.4 54600 6.8 35.3 57.9 2.8 06 12 1921 republic 100 93 3 Dublin -6.35 53.3667 502337 San Marino RSM 60 24521 0.82 5.5 380 5.5 01 01 0301 republic 100 100 100 39 San Marino 12.2 43.5 4416 Malta M 320 375576 1.01 6.9 4400 5 21 09 1964 parliamentary democracy 100 98 Valletta 14.2 35.08 9302 Moldova MD 33700 4463847 0.18 47.6 10400 33 36 31 24 27 08 1991 republic 100 13.8 13 1.5 2 3.5 64.5 1.5 98.5 null 939 450 Chisinau 28.1 47.2 663000 Portugal P 92080 9865114 0.02 7.6 116200 6 35.8 58.2 4.6 01 01 1140 republic 100 97 1 100 1214 Aveiro 2808 656000 Beja 10225 167900 Braga 2673 746100 Braga 63033 Braganca 6608 158300 Castelo Branco 6675 214700 Coimbra 3947 427600 Coimbra 74616 Evora 7393 173500 Faro 4960 340100 Guarda 5518 187800 Leiria 3515 427800 Lisbon 2761 2063800 Lisbon -9.13333 38.7167 807937 Amadora 95518 Barreiro 50863 Almada 42607 Portalegre 6065 134300 Porto 2395 1622300 Porto 327368 Vila Nova de Gaia 62468 Santarem 6747 442700 Setubal 5064 713700 Setubal 77885 Viana do Castelo 2255 248700 Vila Real 4328 237100 Viseu 5007 401000 Azores, The 2247 236700 Madeira 794 253000 Funchal 44111 United Kingdom GB 244820 58489975 0.22 6.4 1138400 1.7 27.7 70.6 3.1 01 01 1801 constitutional monarchy 100 81.5 2.4 1.9 9.6 1.8 360 Avon 1346 962000 Bristol 399200 Bedfordshire 1235 534300 Bedford 137300 Luton 178600 Berkshire 1259 752500 Reading 137700 Wokingham 142900 Newbury 141000 Windsor 136700 Slough 103500 Bracknell 101900 Buckinghamshire 1883 640200 Aylesbury 151600 Milton Keynes 184400 Wycombe 161400 Cambridgeshire 3409 669900 Cambridge 113800 Peterborough 156400 Huntingdon 148800 Cheshire 2329 966500 Chester 120800 Warrington 185000 Macclesfield 151400 Crewe 109500 Cleveland 583 557500 Middlesbrough 145800 Stockton on Tees 177800 Cornwall _ Isles of Scilly 3564 475200 Truro Cumbria 6810 489700 Carlisle 102900 Derbyshire 2631 938800 Derby 230500 Sutton in Ashfield 109800 Chesterfield 101200 Matlock Devon 6711 1040000 Plymouth 255800 Exeter 105100 Dorset 2654 662900 Bournemouth 159900 Poole 137200 Dorchester Durham 2436 604300 Darlington 100200 Durham East Sussex 1795 716500 Brighton 154400 Lewes Essex 3672 1548800 Chelmsford 155700 Southend on Sea 167500 Basildon 161700 Colchester 149100 Braintree 121800 Epping Forest 118200 Gloucestershire 2643 538800 Cheltenham 106700 Stroud 105400 Gloucester 104800 Glouchester Greater London 1579 6803100 London 0 51.4833 6967500 Greater Manchester 1287 2561600 Manchester 431100 Wigan 310000 Stockport 291400 Bolton 265200 Salford 230700 Tameside 221800 Oldham 220400 Trafford 218100 Rochdale 207100 Bury 181400 Hampshire 3777 1578700 Winchester 100500 Southampton 211700 Portsmouth 189100 Basingstoke 146500 Havant 117500 Eastleigh 109600 Fareham 101000 Hereford and Worcester 3927 696000 Worcester Hertfordshire 1634 989500 Saint Albans 127700 Hertford Humberside 3512 874400 Kingston upon Hull 269100 Beverley 115800 Hull Isle of Wight 381 126600 Kent 3731 1538800 Maidstone 138500 Rochester upon Medway 148200 Canterbury 132400 Swale 117200 Sevenoaks 109400 Dover 106100 Tonbridge 102100 Tunbridge Wells 101800 Lancashire 3064 1408300 Preston 132200 Blackpool 153600 Blackburn 139500 Lancaster 133600 Leicestershire 2553 890800 Leicester 293400 Leichester Lincolnshire 5915 592600 Lincoln Merseyside 652 1441100 Liverpool 474000 Wiral 331100 Sefton 292400 Saint Helens 180200 Knowsley 155300 Norfolk 5368 759400 Norwich 128100 Kings Lynn 131600 Northamptonshire 2367 587100 Northampton 187200 Northumberland 5032 307100 North Yorkshire 8309 720900 Harrogate 146500 Scarborough 108700 York 104000 Northallerton Nottinghamshire 2164 1015500 Nottingham 282400 Newark on Trent 104400 Mansfield 102100 Oxfordshire 2608 597700 Oxford 132000 Shropshire 3490 412500 Shrewsbury Somerset 3451 469400 Taunton South Yorkshire 1560 1292700 Barnsley 226500 Sheffield 530100 Doncaster 292500 Rotherham 256300 Staffordshire 2716 1047400 Stafford 121500 Stoke on Trent 254200 Newcastle under Lyme 123000 Suffolk 3797 661900 Ipswich 114800 Surrey 1679 1035500 Guildford 126200 Reigate 118800 Elmbridge 117300 Kingston Tyne and Wear 540 1125600 Sunderland 292200 Newcastle upon Tyne 283600 Gateshead 202400 Newcastle Warwickshire 1981 489900 Warwick 118600 Nuneaton 118500 Stratford on Avon 108600 West Midlands 899 2619000 Birmingham -1.93333 52.4833 1008400 Dudley 312200 Coventry 302500 Walsall 263900 Wolverhampton 245100 Solihull 202000 West Bromwich 154500 West Sussex 1989 713600 Chichester 102500 Horsham 112300 West Yorkshire 2039 2066200 Wakefield 317300 Leeds 724400 Bradford 481700 Kirklees 386900 Huddersfield 148500 Wiltshire 3480 575100 Salisbury 109800 Trowbridge Borders 4698 105700 Newtown St. Boswells Central 2700 273400 Stirling Dumfries and Galloway 6425 147800 Dumfries Fife 1319 352100 Glenrothes Grampian 8752 532500 Aberdeen 219100 Highland 26137 207500 Inverness Lothian 1770 758600 Edinburgh -3.18333 55.9167 447600 Strathclyde 13773 2287800 Glasgow -4.28333 55.8667 674800 Renfrew 201700 Tayside 7643 395000 Dundee 167600 Island Areas (munic.) 5566 72000 Island Areas Aberconwy and Colwyn 1130 110700 Colwyn Bay Anglesey 719 68500 Llangefni Blaenau Gwent 109 73300 Ebbw Vale Bridgend 246 130900 Bridgend Caerphilly 279 171000 Ystrad Fawr Cardiff 139 306600 Cardiff -3.16667 51.4667 300000 Carmarthenshire 2398 169000 Carmarthen Ceredigion 1797 69700 Aberystwyth Denbighshire 844 91300 Ruthin Flintshire 437 145300 Mold Gwynedd 2548 117000 Caernarfon Merthyr Tydfil 111 59500 Merthyr Tydfil Monmouthshire 851 84200 Cwmbran Neath and Port Talbot 441 140100 Port Talbot Newport 191 137400 Newport 137000 Pembrokeshire 1590 113600 Haverfordwest Powys 5204 121800 Llandrindod Wells Rhondda Cynon Taff 424 239000 Rhondda Swansea 378 230900 Swansea 189300 Torfaen 126 90600 Pontypool Vale of Glamorgan 337 119200 Rhymney Valley 104300 Barry Wrexham 499 123500 Wrexham Northern Ireland 14120 1594400 Belfast -5.91667 54.6 297100 Cyprus CY 9250 744609 1.11 8.4 7800 5.6 24.9 69.5 16 08 1960 republic 100 18 78 Nicosia 33.2 35.4 161100 Europe 9562488 Agency for Cultural and Technical Cooperation ACCT 21 03 1970 Bank for International Settlements BIS 20 01 1930 Benelux Economic Union Benelux 03 02 1958 Central European Initiative CEI 27 07 1991 Commonwealth C 31 12 1931 Commonwealth of Independent States CIS 08 12 1991 Council of Europe CE 05 05 1949 Customs Cooperation Council CCC 15 12 1950 Economic Commission for Europe ECE 28 03 1947 European Bank for Reconstruction and Development EBRD 15 04 1991 European Free Trade Association EFTA 04 01 1960 European Investment Bank EIB 25 03 1957 European Organization for Nuclear Research CERN 01 07 1953 European Space Agency ESA 31 07 1973 European Union EU 07 02 1992 Food and Agriculture Organization FAO 16 10 1945 Franc Zone FZ 20 12 1945 Group of 10 G-10 01 10 1962 International Atomic Energy Agency IAEA 26 10 1956 International Chamber of Commerce ICC 01 01 1919 International Confederation of Free Trade Unions ICFTU 01 12 1949 International Criminal Police Organization Interpol 13 06 1956 International Energy Agency IEA 15 11 1974 International Federation of Red Cross and Red Crescent Societies IFRCS 05 05 1919 International Fund for Agricultural Development IFAD 01 11 1974 International Labor Organization ILO 11 04 1919 International Maritime Organization IMO 17 03 1958 International Mobile Satellite Organization Inmarsat 03 09 1976 International Olympic Committee IOC 23 06 1894 International Organization for Migration IOM 05 12 1951 International Organization for Standardization ISO 01 02 1947 International Red Cross and Red Crescent Movement ICRM 01 01 1928 International Telecommunication Union ITU 09 12 1932 Nordic Council NC 16 03 1952 Nordic Investment Bank NIB 04 12 1975 North Atlantic Cooperation Council ANC 08 11 1991 North Atlantic Treaty Organization NATO 17 09 1949 Nuclear Suppliers Group NSG Organization for Economic Cooperation and Development OECD 14 12 1960 Organization for Security and Cooperation in Europe OSCE 01 01 1995 United Nations Conference on Trade and Development UNCTAD 30 12 1964 United Nations Educational, Scientific, and Cultural Organization UNESCO 16 11 1945 United Nations Industrial Development Organization UNIDO 17 11 1966 United Nations Office of the High Commissioner for Refugees UNHCR 03 12 1949 United Nations Relief and Works Agency for Palestine Refugees in the Near East UNRWA 08 12 1949 Universal Postal Union UPU 09 10 1874 Western European Union WEU 23 10 1954 World Confederation of Labor WCL 19 06 1920 World Federation of Trade Unions WFTU 03 10 1945 World Health Organization WHO 22 07 1946 World Intellectual Property Organization WIPO 14 07 1967 World Meteorological Organization WMO 11 10 1947 World Tourism Organization WToO 02 01 1975 Jezerce 19.4 42.3 2694 Korab 20.3 41.4 2751 Kebnekaise 18.3 67.5 2114 Sarektjokko 17.4 67.3 2090 Portefjaellen 17.4 67.1 2021 Tarrekaise 17.3 67 1850 Sulitjelma 16.2 67.1 1914 Galdhoeppig 8 61.4 2469 Jostedalsbre 5.5 61.4 2083 Glittertind 8.1 61.4 2452 Joekul 7.2 60.3 1876 Snoehetta 9 62.1 2286 Elbrus 42.26 43.21 5642 Kasbek 44.31 42.42 5033 Bjelucha 86.4 49.48 4506 Oeraefajoekull -17 64.1 2119 Snoefell -15.2 64.5 1833 Haltiatunturi 21.4 67 1328 Feldberg 7.5 47.5 1493 Grosser Arber 13 49.1 1456 Zugspitze 11.1 47.3 2963 Grossglockner 12.5 47 3797 Montblanc 6 45 4807 776 Seine North Sea 200 2850 Donau Black Sea 2211 1020 Western Dwina Baltic Sea 459 1068 Weichsel 2201 Dnepr 346 Thames 1364 Kura Caspian Sea 424200 1010 Loire Atlantic Ocean 9219 650 Garonne 812 Rhone Mediterranean Sea 5121 477 Weser 1144 Elbe 1320 Rhein Bodensee 538.5 347 Klaraelv Vaenern 5546 435 Moldau 93 Goetaaelv Umeaelv Ounasjoki 520 Kemijoki Oulujoki 169 Kokemaeenjoki 740 Northern Dwina Arctic Ocean 5220 4130 Jenissej 3531 Volga 74 Neva White Drin Drin 133 Black Drin 230 Thjorsa 206 Joekulsa a Fjoellum Norwegian Sea 3860 Oesterdalaelv 520 Dalaelv Vaesterdalaelv 375 Torneaelv 598 Gloma 4400 Lena 3680 Ob 2918 Amur 1809 Petschora 2513 Kolyma 1636 Chatanga 688 Bija 306 Katun 4248 Irtysch 1591 Tobol 2450 Ischim 560 Schilka 1620 Argun 708 Ingoda 1032 Onon 200 Ajan-Jurjach 300 Kulu 605 Grosser Jenissej 680 Kleiner Jenissej 562 Suchona 574 Jug 1480 Oka 1870 Don Sea of Azov 100 2428 Ural 292 Werra 218 Fulda Pacific Ocean 11034 Irish Sea 272 Sea of Japan 4036 Maelaren 1140 Vaettern 1900 Lake Kalla 900 Lake Saima 1460 Paeijaenne 1090 Lake Ori 200 Mjoesen 368 Lake Naesi 250 Lake Skutari 300 Ozero Baikal 31500 Lake Prespa 285 Lake Ohrid 367 Ozero Ladoga 18400 Ozero Onega 9610 Ozero Taimyr 4560 Ozero Chanka 4400 Ozero Pskovskoje 3550 Ozero Tschany 2500 Inari 1085 Lago di Garda 370 Arresee 40.2 Lac Leman 581 Lago Maggiore 216 Lago di Como 146 tdom-0.9.6-src/tests/data/data1.xml0000644000175000017500000000002415025767703015543 0ustar rolfrolfa😎c tdom-0.9.6-src/tests/data/REC-xslt-19991116.xml0000644000175000017500000074325215025767703017115 0ustar rolfrolf ]>
    XSL Transformations (XSLT) Version 1.0 &LEV;-xslt-&YYYYMMDD; W3C Recommendation &day;&month;&year; http://www.w3.org/TR/&year;/&LEV;-xslt-&YYYYMMDD; XML HTML http://www.w3.org/TR/xslt http://www.w3.org/TR/1999/PR-xslt-19991008 http://www.w3.org/1999/08/WD-xslt-19990813 http://www.w3.org/1999/07/WD-xslt-19990709 http://www.w3.org/TR/1999/WD-xslt-19990421 http://www.w3.org/TR/1998/WD-xsl-19981216 http://www.w3.org/TR/1998/WD-xsl-19980818 James Clark jjc@jclark.com

    This document has been reviewed by W3C Members and other interested parties and has been endorsed by the Director as a W3C Recommendation. It is a stable document and may be used as reference material or cited as a normative reference from other documents. W3C's role in making the Recommendation is to draw attention to the specification and to promote its widespread deployment. This enhances the functionality and interoperability of the Web.

    The list of known errors in this specification is available at http://www.w3.org/&year;/&MM;/&LEV;-xslt-&YYYYMMDD;-errata.

    Comments on this specification may be sent to xsl-editors@w3.org; archives of the comments are available. Public discussion of XSL, including XSL Transformations, takes place on the XSL-List mailing list.

    The English version of this specification is the only normative version. However, for translations of this document, see http://www.w3.org/Style/XSL/translations.html.

    A list of current W3C Recommendations and other technical documents can be found at http://www.w3.org/TR.

    This specification has been produced as part of the W3C Style activity.

    This specification defines the syntax and semantics of XSLT, which is a language for transforming XML documents into other XML documents.

    XSLT is designed for use as part of XSL, which is a stylesheet language for XML. In addition to XSLT, XSL includes an XML vocabulary for specifying formatting. XSL specifies the styling of an XML document by using XSLT to describe how the document is transformed into another XML document that uses the formatting vocabulary.

    XSLT is also designed to be used independently of XSL. However, XSLT is not intended as a completely general-purpose XML transformation language. Rather it is designed primarily for the kinds of transformations that are needed when XSLT is used as part of XSL.

    English EBNF See RCS log for revision history.
    Introduction

    This specification defines the syntax and semantics of the XSLT language. A transformation in the XSLT language is expressed as a well-formed XML document conforming to the Namespaces in XML Recommendation , which may include both elements that are defined by XSLT and elements that are not defined by XSLT. XSLT-defined elements are distinguished by belonging to a specific XML namespace (see ), which is referred to in this specification as the XSLT namespace. Thus this specification is a definition of the syntax and semantics of the XSLT namespace.

    A transformation expressed in XSLT describes rules for transforming a source tree into a result tree. The transformation is achieved by associating patterns with templates. A pattern is matched against elements in the source tree. A template is instantiated to create part of the result tree. The result tree is separate from the source tree. The structure of the result tree can be completely different from the structure of the source tree. In constructing the result tree, elements from the source tree can be filtered and reordered, and arbitrary structure can be added.

    A transformation expressed in XSLT is called a stylesheet. This is because, in the case when XSLT is transforming into the XSL formatting vocabulary, the transformation functions as a stylesheet.

    This document does not specify how an XSLT stylesheet is associated with an XML document. It is recommended that XSL processors support the mechanism described in . When this or any other mechanism yields a sequence of more than one XSLT stylesheet to be applied simultaneously to a XML document, then the effect should be the same as applying a single stylesheet that imports each member of the sequence in order (see ).

    A stylesheet contains a set of template rules. A template rule has two parts: a pattern which is matched against nodes in the source tree and a template which can be instantiated to form part of the result tree. This allows a stylesheet to be applicable to a wide class of documents that have similar source tree structures.

    A template is instantiated for a particular source element to create part of the result tree. A template can contain elements that specify literal result element structure. A template can also contain elements from the XSLT namespace that are instructions for creating result tree fragments. When a template is instantiated, each instruction is executed and replaced by the result tree fragment that it creates. Instructions can select and process descendant source elements. Processing a descendant element creates a result tree fragment by finding the applicable template rule and instantiating its template. Note that elements are only processed when they have been selected by the execution of an instruction. The result tree is constructed by finding the template rule for the root node and instantiating its template.

    In the process of finding the applicable template rule, more than one template rule may have a pattern that matches a given element. However, only one template rule will be applied. The method for deciding which template rule to apply is described in .

    A single template by itself has considerable power: it can create structures of arbitrary complexity; it can pull string values out of arbitrary locations in the source tree; it can generate structures that are repeated according to the occurrence of elements in the source tree. For simple transformations where the structure of the result tree is independent of the structure of the source tree, a stylesheet can often consist of only a single template, which functions as a template for the complete result tree. Transformations on XML documents that represent data are often of this kind (see ). XSLT allows a simplified syntax for such stylesheets (see ).

    When a template is instantiated, it is always instantiated with respect to a current node and a current node list. The current node is always a member of the current node list. Many operations in XSLT are relative to the current node. Only a few instructions change the current node list or the current node (see and ); during the instantiation of one of these instructions, the current node list changes to a new list of nodes and each member of this new list becomes the current node in turn; after the instantiation of the instruction is complete, the current node and current node list revert to what they were before the instruction was instantiated.

    XSLT makes use of the expression language defined by for selecting elements for processing, for conditional processing and for generating text.

    XSLT provides two hooks for extending the language, one hook for extending the set of instruction elements used in templates and one hook for extending the set of functions used in XPath expressions. These hooks are both based on XML namespaces. This version of XSLT does not define a mechanism for implementing the hooks. See .

    The XSL WG intends to define such a mechanism in a future version of this specification or in a separate specification.

    The element syntax summary notation used to describe the syntax of XSLT-defined elements is described in .

    The MIME media types text/xml and application/xml should be used for XSLT stylesheets. It is possible that a media type will be registered specifically for XSLT stylesheets; if and when it is, that media type may also be used.

    Stylesheet Structure XSLT Namespace

    The XSLT namespace has the URI &XSLT.ns;.

    The 1999 in the URI indicates the year in which the URI was allocated by the W3C. It does not indicate the version of XSLT being used, which is specified by attributes (see and ).

    XSLT processors must use the XML namespaces mechanism to recognize elements and attributes from this namespace. Elements from the XSLT namespace are recognized only in the stylesheet not in the source document. The complete list of XSLT-defined elements is specified in . Vendors must not extend the XSLT namespace with additional elements or attributes. Instead, any extension must be in a separate namespace. Any namespace that is used for additional instruction elements must be identified by means of the extension element mechanism specified in .

    This specification uses a prefix of xsl: for referring to elements in the XSLT namespace. However, XSLT stylesheets are free to use any prefix, provided that there is a namespace declaration that binds the prefix to the URI of the XSLT namespace.

    An element from the XSLT namespace may have any attribute not from the XSLT namespace, provided that the expanded-name of the attribute has a non-null namespace URI. The presence of such attributes must not change the behavior of XSLT elements and functions defined in this document. Thus, an XSLT processor is always free to ignore such attributes, and must ignore such attributes without giving an error if it does not recognize the namespace URI. Such attributes can provide, for example, unique identifiers, optimization hints, or documentation.

    It is an error for an element from the XSLT namespace to have attributes with expanded-names that have null namespace URIs (i.e. attributes with unprefixed names) other than attributes defined for the element in this document.

    The conventions used for the names of XSLT elements, attributes and functions are that names are all lower-case, use hyphens to separate words, and use abbreviations only if they already appear in the syntax of a related language such as XML or HTML.

    Stylesheet Element

    A stylesheet is represented by an xsl:stylesheet element in an XML document. xsl:transform is allowed as a synonym for xsl:stylesheet.

    An xsl:stylesheet element must have a version attribute, indicating the version of XSLT that the stylesheet requires. For this version of XSLT, the value should be 1.0. When the value is not equal to 1.0, forwards-compatible processing mode is enabled (see ).

    The xsl:stylesheet element may contain the following types of elements:

    xsl:import

    xsl:include

    xsl:strip-space

    xsl:preserve-space

    xsl:output

    xsl:key

    xsl:decimal-format

    xsl:namespace-alias

    xsl:attribute-set

    xsl:variable

    xsl:param

    xsl:template

    An element occurring as a child of an xsl:stylesheet element is called a top-level element.

    This example shows the structure of a stylesheet. Ellipses (...) indicate where attribute values or content have been omitted. Although this example shows one of each type of allowed element, stylesheets may contain zero or more of each of these elements.

    <xsl:stylesheet version="1.0" xmlns:xsl="&XSLT.ns;"> ... ... ... ... ... ]]>

    The order in which the children of the xsl:stylesheet element occur is not significant except for xsl:import elements and for error recovery. Users are free to order the elements as they prefer, and stylesheet creation tools need not provide control over the order in which the elements occur.

    In addition, the xsl:stylesheet element may contain any element not from the XSLT namespace, provided that the expanded-name of the element has a non-null namespace URI. The presence of such top-level elements must not change the behavior of XSLT elements and functions defined in this document; for example, it would not be permitted for such a top-level element to specify that xsl:apply-templates was to use different rules to resolve conflicts. Thus, an XSLT processor is always free to ignore such top-level elements, and must ignore a top-level element without giving an error if it does not recognize the namespace URI. Such elements can provide, for example,

    information used by extension elements or extension functions (see ),

    information about what to do with the result tree,

    information about how to obtain the source tree,

    metadata about the stylesheet,

    structured documentation for the stylesheet.

    Literal Result Element as Stylesheet

    A simplified syntax is allowed for stylesheets that consist of only a single template for the root node. The stylesheet may consist of just a literal result element (see ). Such a stylesheet is equivalent to a stylesheet with an xsl:stylesheet element containing a template rule containing the literal result element; the template rule has a match pattern of /. For example

    <html xsl:version="1.0" xmlns:xsl="&XSLT.ns;" xmlns="&XHTML.ns;"> Expense Report Summary

    Total Amount:

    ]]>

    has the same meaning as

    <xsl:stylesheet version="1.0" xmlns:xsl="&XSLT.ns;" xmlns="&XHTML.ns;"> Expense Report Summary

    Total Amount:

    ]]>

    A literal result element that is the document element of a stylesheet must have an xsl:version attribute, which indicates the version of XSLT that the stylesheet requires. For this version of XSLT, the value should be 1.0; the value must be a Number. Other literal result elements may also have an xsl:version attribute. When the xsl:version attribute is not equal to 1.0, forwards-compatible processing mode is enabled (see ).

    The allowed content of a literal result element when used as a stylesheet is no different from when it occurs within a stylesheet. Thus, a literal result element used as a stylesheet cannot contain top-level elements.

    In some situations, the only way that a system can recognize that an XML document needs to be processed by an XSLT processor as an XSLT stylesheet is by examining the XML document itself. Using the simplified syntax makes this harder.

    For example, another XML language (AXL) might also use an axl:version on the document element to indicate that an XML document was an AXL document that required processing by an AXL processor; if a document had both an axl:version attribute and an xsl:version attribute, it would be unclear whether the document should be processed by an XSLT processor or an AXL processor.

    Therefore, the simplified syntax should not be used for XSLT stylesheets that may be used in such a situation. This situation can, for example, arise when an XSLT stylesheet is transmitted as a message with a MIME media type of text/xml or application/xml to a recipient that will use the MIME media type to determine how the message is processed.

    Qualified Names

    The name of an internal XSLT object, specifically a named template (see ), a mode (see ), an attribute set (see ), a key (see ), a decimal-format (see ), a variable or a parameter (see ) is specified as a QName. If it has a prefix, then the prefix is expanded into a URI reference using the namespace declarations in effect on the attribute in which the name occurs. The expanded-name consisting of the local part of the name and the possibly null URI reference is used as the name of the object. The default namespace is not used for unprefixed names.

    Forwards-Compatible Processing

    An element enables forwards-compatible mode for itself, its attributes, its descendants and their attributes if either it is an xsl:stylesheet element whose version attribute is not equal to 1.0, or it is a literal result element that has an xsl:version attribute whose value is not equal to 1.0, or it is a literal result element that does not have an xsl:version attribute and that is the document element of a stylesheet using the simplified syntax (see ). A literal result element that has an xsl:version attribute whose value is equal to 1.0 disables forwards-compatible mode for itself, its attributes, its descendants and their attributes.

    If an element is processed in forwards-compatible mode, then:

    if it is a top-level element and XSLT 1.0 does not allow such elements as top-level elements, then the element must be ignored along with its content;

    if it is an element in a template and XSLT 1.0 does not allow such elements to occur in templates, then if the element is not instantiated, an error must not be signaled, and if the element is instantiated, the XSLT must perform fallback for the element as specified in ;

    if the element has an attribute that XSLT 1.0 does not allow the element to have or if the element has an optional attribute with a value that the XSLT 1.0 does not allow the attribute to have, then the attribute must be ignored.

    Thus, any XSLT 1.0 processor must be able to process the following stylesheet without error, although the stylesheet includes elements from the XSLT namespace that are not defined in this specification:

    <xsl:stylesheet version="1.1" xmlns:xsl="&XSLT.ns;"> XSLT 1.1 required

    Sorry, this stylesheet requires XSLT 1.1.

    ]]>

    If a stylesheet depends crucially on a top-level element introduced by a version of XSL after 1.0, then the stylesheet can use an xsl:message element with terminate="yes" (see ) to ensure that XSLT processors implementing earlier versions of XSL will not silently ignore the top-level element. For example,

    <xsl:stylesheet version="1.5" xmlns:xsl="&XSLT.ns;"> Sorry, this stylesheet requires XSLT 1.1. ... ... ]]>

    If an expression occurs in an attribute that is processed in forwards-compatible mode, then an XSLT processor must recover from errors in the expression as follows:

    if the expression does not match the syntax allowed by the XPath grammar, then an error must not be signaled unless the expression is actually evaluated;

    if the expression calls a function with an unprefixed name that is not part of the XSLT library, then an error must not be signaled unless the function is actually called;

    if the expression calls a function with a number of arguments that XSLT does not allow or with arguments of types that XSLT does not allow, then an error must not be signaled unless the function is actually called.

    Combining Stylesheets

    XSLT provides two mechanisms to combine stylesheets:

    an inclusion mechanism that allows stylesheets to be combined without changing the semantics of the stylesheets being combined, and an import mechanism that allows stylesheets to override each other. Stylesheet Inclusion

    An XSLT stylesheet may include another XSLT stylesheet using an xsl:include element. The xsl:include element has an href attribute whose value is a URI reference identifying the stylesheet to be included. A relative URI is resolved relative to the base URI of the xsl:include element (see ).

    The xsl:include element is only allowed as a top-level element.

    The inclusion works at the XML tree level. The resource located by the href attribute value is parsed as an XML document, and the children of the xsl:stylesheet element in this document replace the xsl:include element in the including document. The fact that template rules or definitions are included does not affect the way they are processed.

    The included stylesheet may use the simplified syntax described in . The included stylesheet is treated the same as the equivalent xsl:stylesheet element.

    It is an error if a stylesheet directly or indirectly includes itself.

    Including a stylesheet multiple times can cause errors because of duplicate definitions. Such multiple inclusions are less obvious when they are indirect. For example, if stylesheet B includes stylesheet A, stylesheet C includes stylesheet A, and stylesheet D includes both stylesheet B and stylesheet C, then A will be included indirectly by D twice. If all of B, C and D are used as independent stylesheets, then the error can be avoided by separating everything in B other than the inclusion of A into a separate stylesheet B' and changing B to contain just inclusions of B' and A, similarly for C, and then changing D to include A, B', C'.

    Stylesheet Import

    An XSLT stylesheet may import another XSLT stylesheet using an xsl:import element. Importing a stylesheet is the same as including it (see ) except that definitions and template rules in the importing stylesheet take precedence over template rules and definitions in the imported stylesheet; this is described in more detail below. The xsl:import element has an href attribute whose value is a URI reference identifying the stylesheet to be imported. A relative URI is resolved relative to the base URI of the xsl:import element (see ).

    The xsl:import element is only allowed as a top-level element. The xsl:import element children must precede all other element children of an xsl:stylesheet element, including any xsl:include element children. When xsl:include is used to include a stylesheet, any xsl:import elements in the included document are moved up in the including document to after any existing xsl:import elements in the including document.

    For example,

    <xsl:stylesheet version="1.0" xmlns:xsl="&XSLT.ns;"> italic ]]>

    The xsl:stylesheet elements encountered during processing of a stylesheet that contains xsl:import elements are treated as forming an import tree. In the import tree, each xsl:stylesheet element has one import child for each xsl:import element that it contains. Any xsl:include elements are resolved before constructing the import tree. An xsl:stylesheet element in the import tree is defined to have lower import precedence than another xsl:stylesheet element in the import tree if it would be visited before that xsl:stylesheet element in a post-order traversal of the import tree (i.e. a traversal of the import tree in which an xsl:stylesheet element is visited after its import children). Each definition and template rule has import precedence determined by the xsl:stylesheet element that contains it.

    For example, suppose

    stylesheet A imports stylesheets B and C in that order;

    stylesheet B imports stylesheet D;

    stylesheet C imports stylesheet E.

    Then the order of import precedence (lowest first) is D, B, E, C, A.

    Since xsl:import elements are required to occur before any definitions or template rules, an implementation that processes imported stylesheets at the point at which it encounters the xsl:import element will encounter definitions and template rules in increasing order of import precedence.

    In general, a definition or template rule with higher import precedence takes precedence over a definition or template rule with lower import precedence. This is defined in detail for each kind of definition and for template rules.

    It is an error if a stylesheet directly or indirectly imports itself. Apart from this, the case where a stylesheet with a particular URI is imported in multiple places is not treated specially. The import tree will have a separate xsl:stylesheet for each place that it is imported.

    If xsl:apply-imports is used (see ), the behavior may be different from the behavior if the stylesheet had been imported only at the place with the highest import precedence.

    Embedding Stylesheets

    Normally an XSLT stylesheet is a complete XML document with the xsl:stylesheet element as the document element. However, an XSLT stylesheet may also be embedded in another resource. Two forms of embedding are possible:

    the XSLT stylesheet may be textually embedded in a non-XML resource, or the xsl:stylesheet element may occur in an XML document other than as the document element.

    To facilitate the second form of embedding, the xsl:stylesheet element is allowed to have an ID attribute that specifies a unique identifier.

    In order for such an attribute to be used with the XPath id function, it must actually be declared in the DTD as being an ID.

    The following example shows how the xml-stylesheet processing instruction can be used to allow a document to contain its own stylesheet. The URI reference uses a relative URI with a fragment identifier to locate the xsl:stylesheet element:

    xmlns:xsl="&XSLT.ns;" xmlns:fo="&XSLFO.ns;"> ... ]]>

    A stylesheet that is embedded in the document to which it is to be applied or that may be included or imported into an stylesheet that is so embedded typically needs to contain a template rule that specifies that xsl:stylesheet elements are to be ignored.

    Data Model

    The data model used by XSLT is the same as that used by XPath with the additions described in this section. XSLT operates on source, result and stylesheet documents using the same data model. Any two XML documents that have the same tree will be treated the same by XSLT.

    Processing instructions and comments in the stylesheet are ignored: the stylesheet is treated as if neither processing instruction nodes nor comment nodes were included in the tree that represents the stylesheet.

    Root Node Children

    The normal restrictions on the children of the root node are relaxed for the result tree. The result tree may have any sequence of nodes as children that would be possible for an element node. In particular, it may have text node children, and any number of element node children. When written out using the XML output method (see ), it is possible that a result tree will not be a well-formed XML document; however, it will always be a well-formed external general parsed entity.

    When the source tree is created by parsing a well-formed XML document, the root node of the source tree will automatically satisfy the normal restrictions of having no text node children and exactly one element child. When the source tree is created in some other way, for example by using the DOM, the usual restrictions are relaxed for the source tree as for the result tree.

    Base URI

    Every node also has an associated URI called its base URI, which is used for resolving attribute values that represent relative URIs into absolute URIs. If an element or processing instruction occurs in an external entity, the base URI of that element or processing instruction is the URI of the external entity; otherwise, the base URI is the base URI of the document. The base URI of the document node is the URI of the document entity. The base URI for a text node, a comment node, an attribute node or a namespace node is the base URI of the parent of the node.

    Unparsed Entities

    The root node has a mapping that gives the URI for each unparsed entity declared in the document's DTD. The URI is generated from the system identifier and public identifier specified in the entity declaration. The XSLT processor may use the public identifier to generate a URI for the entity instead of the URI specified in the system identifier. If the XSLT processor does not use the public identifier to generate the URI, it must use the system identifier; if the system identifier is a relative URI, it must be resolved into an absolute URI using the URI of the resource containing the entity declaration as the base URI .

    Whitespace Stripping

    After the tree for a source document or stylesheet document has been constructed, but before it is otherwise processed by XSLT, some text nodes are stripped. A text node is never stripped unless it contains only whitespace characters. Stripping the text node removes the text node from the tree. The stripping process takes as input a set of element names for which whitespace must be preserved. The stripping process is applied to both stylesheets and source documents, but the set of whitespace-preserving element names is determined differently for stylesheets and for source documents.

    A text node is preserved if any of the following apply:

    The element name of the parent of the text node is in the set of whitespace-preserving element names.

    The text node contains at least one non-whitespace character. As in XML, a whitespace character is #x20, #x9, #xD or #xA.

    An ancestor element of the text node has an xml:space attribute with a value of preserve, and no closer ancestor element has xml:space with a value of default.

    Otherwise, the text node is stripped.

    The xml:space attributes are not stripped from the tree.

    This implies that if an xml:space attribute is specified on a literal result element, it will be included in the result.

    For stylesheets, the set of whitespace-preserving element names consists of just xsl:text.

    For source documents, the set of whitespace-preserving element names is specified by xsl:strip-space and xsl:preserve-space top-level elements. These elements each have an elements attribute whose value is a whitespace-separated list of NameTests. Initially, the set of whitespace-preserving element names contains all element names. If an element name matches a NameTest in an xsl:strip-space element, then it is removed from the set of whitespace-preserving element names. If an element name matches a NameTest in an xsl:preserve-space element, then it is added to the set of whitespace-preserving element names. An element matches a NameTest if and only if the NameTest would be true for the element as an XPath node test. Conflicts between matches to xsl:strip-space and xsl:preserve-space elements are resolved the same way as conflicts between template rules (see ). Thus, the applicable match for a particular element name is determined as follows:

    First, any match with lower import precedence than another match is ignored.

    Next, any match with a NameTest that has a lower default priority than the default priority of the NameTest of another match is ignored.

    It is an error if this leaves more than one match. An XSLT processor may signal the error; if it does not signal the error, it must recover by choosing, from amongst the matches that are left, the one that occurs last in the stylesheet.

    Expressions

    XSLT uses the expression language defined by XPath . Expressions are used in XSLT for a variety of purposes including:

    selecting nodes for processing; specifying conditions for different ways of processing a node; generating text to be inserted in the result tree.

    An expression must match the XPath production Expr.

    Expressions occur as the value of certain attributes on XSLT-defined elements and within curly braces in attribute value templates.

    In XSLT, an outermost expression (i.e. an expression that is not part of another expression) gets its context as follows:

    the context node comes from the current node

    the context position comes from the position of the current node in the current node list; the first position is 1

    the context size comes from the size of the current node list

    the variable bindings are the bindings in scope on the element which has the attribute in which the expression occurs (see )

    the set of namespace declarations are those in scope on the element which has the attribute in which the expression occurs; this includes the implicit declaration of the prefix xml required by the the XML Namespaces Recommendation ; the default namespace (as declared by xmlns) is not part of this set

    the function library consists of the core function library together with the additional functions defined in and extension functions as described in ; it is an error for an expression to include a call to any other function

    Template Rules Processing Model

    A list of source nodes is processed to create a result tree fragment. The result tree is constructed by processing a list containing just the root node. A list of source nodes is processed by appending the result tree structure created by processing each of the members of the list in order. A node is processed by finding all the template rules with patterns that match the node, and choosing the best amongst them; the chosen rule's template is then instantiated with the node as the current node and with the list of source nodes as the current node list. A template typically contains instructions that select an additional list of source nodes for processing. The process of matching, instantiation and selection is continued recursively until no new source nodes are selected for processing.

    Implementations are free to process the source document in any way that produces the same result as if it were processed using this processing model.

    Patterns

    Template rules identify the nodes to which they apply by using a pattern. As well as being used in template rules, patterns are used for numbering (see ) and for declaring keys (see ). A pattern specifies a set of conditions on a node. A node that satisfies the conditions matches the pattern; a node that does not satisfy the conditions does not match the pattern. The syntax for patterns is a subset of the syntax for expressions. In particular, location paths that meet certain restrictions can be used as patterns. An expression that is also a pattern always evaluates to an object of type node-set. A node matches a pattern if the node is a member of the result of evaluating the pattern as an expression with respect to some possible context; the possible contexts are those whose context node is the node being matched or one of its ancestors.

    Here are some examples of patterns:

    para matches any para element

    * matches any element

    chapter|appendix matches any chapter element and any appendix element

    olist/item matches any item element with an olist parent

    appendix//para matches any para element with an appendix ancestor element

    / matches the root node

    text() matches any text node

    processing-instruction() matches any processing instruction

    node() matches any node other than an attribute node and the root node

    id("W11") matches the element with unique ID W11

    para[1] matches any para element that is the first para child element of its parent

    *[position()=1 and self::para] matches any para element that is the first child element of its parent

    para[last()=1] matches any para element that is the only para child element of its parent

    items/item[position()>1] matches any item element that has a items parent and that is not the first item child of its parent

    item[position() mod 2 = 1] would be true for any item element that is an odd-numbered item child of its parent.

    div[@class="appendix"]//p matches any p element with a div ancestor element that has a class attribute with value appendix

    @class matches any class attribute (not any element that has a class attribute)

    @* matches any attribute

    A pattern must match the grammar for Pattern. A Pattern is a set of location path patterns separated by |. A location path pattern is a location path whose steps all use only the child or attribute axes. Although patterns must not use the descendant-or-self axis, patterns may use the // operator as well as the / operator. Location path patterns can also start with an id or key function call with a literal argument. Predicates in a pattern can use arbitrary expressions just like predicates in a location path.

    Patterns Pattern LocationPathPattern | Pattern '|' LocationPathPattern LocationPathPattern '/' RelativePathPattern? | IdKeyPattern (('/' | '//') RelativePathPattern)? | '//'? RelativePathPattern IdKeyPattern 'id' '(' Literal ')' | 'key' '(' Literal ',' Literal ')' RelativePathPattern StepPattern | RelativePathPattern '/' StepPattern | RelativePathPattern '//' StepPattern StepPattern ChildOrAttributeAxisSpecifier NodeTest Predicate* ChildOrAttributeAxisSpecifier AbbreviatedAxisSpecifier | ('child' | 'attribute') '::'

    A pattern is defined to match a node if and only if there is possible context such that when the pattern is evaluated as an expression with that context, the node is a member of the resulting node-set. When a node is being matched, the possible contexts have a context node that is the node being matched or any ancestor of that node, and a context node list containing just the context node.

    For example, p matches any p element, because for any p if the expression p is evaluated with the parent of the p element as context the resulting node-set will contain that p element as one of its members.

    This matches even a p element that is the document element, since the document root is the parent of the document element.

    Although the semantics of patterns are specified indirectly in terms of expression evaluation, it is easy to understand the meaning of a pattern directly without thinking in terms of expression evaluation. In a pattern, | indicates alternatives; a pattern with one or more | separated alternatives matches if any one of the alternative matches. A pattern that consists of a sequence of StepPatterns separated by / or // is matched from right to left. The pattern only matches if the rightmost StepPattern matches and a suitable element matches the rest of the pattern; if the separator is / then only the parent is a suitable element; if the separator is //, then any ancestor is a suitable element. A StepPattern that uses the child axis matches if the NodeTest is true for the node and the node is not an attribute node. A StepPattern that uses the attribute axis matches if the NodeTest is true for the node and the node is an attribute node. When [] is present, then the first PredicateExpr in a StepPattern is evaluated with the node being matched as the context node and the siblings of the context node that match the NodeTest as the context node list, unless the node being matched is an attribute node, in which case the context node list is all the attributes that have the same parent as the attribute being matched and that match the NameTest.

    For example

    appendix//ulist/item[position()=1]

    matches a node if and only if all of the following are true:

    the NodeTest item is true for the node and the node is not an attribute; in other words the node is an item element

    evaluating the PredicateExpr position()=1 with the node as context node and the siblings of the node that are item elements as the context node list yields true

    the node has a parent that matches appendix//ulist; this will be true if the parent is a ulist element that has an appendix ancestor element.

    Defining Template Rules

    A template rule is specified with the xsl:template element. The match attribute is a Pattern that identifies the source node or nodes to which the rule applies. The match attribute is required unless the xsl:template element has a name attribute (see ). It is an error for the value of the match attribute to contain a VariableReference. The content of the xsl:template element is the template that is instantiated when the template rule is applied.

    For example, an XML document might contain:

    important point.]]>

    The following template rule matches emph elements and produces a fo:inline-sequence formatting object with a font-weight property of bold.

    ]]>

    Examples in this document use the fo: prefix for the namespace &XSLFO.ns;, which is the namespace of the formatting objects defined in .

    As described next, the xsl:apply-templates element recursively processes the children of the source element.

    Applying Template Rules

    This example creates a block for a chapter element and then processes its immediate children.

    ]]>

    In the absence of a select attribute, the xsl:apply-templates instruction processes all of the children of the current node, including text nodes. However, text nodes that have been stripped as specified in will not be processed. If stripping of whitespace nodes has not been enabled for an element, then all whitespace in the content of the element will be processed as text, and thus whitespace between child elements will count in determining the position of a child element as returned by the position function.

    A select attribute can be used to process nodes selected by an expression instead of processing all children. The value of the select attribute is an expression. The expression must evaluate to a node-set. The selected set of nodes is processed in document order, unless a sorting specification is present (see ). The following example processes all of the author children of the author-group:

    ]]>

    The following example processes all of the given-names of the authors that are children of author-group:

    ]]>

    This example processes all of the heading descendant elements of the book element.

    ]]>

    It is also possible to process elements that are not descendants of the current node. This example assumes that a department element has group children and employee descendants. It finds an employee's department and then processes the group children of the department.

    Employee belongs to group ]]>

    Multiple xsl:apply-templates elements can be used within a single template to do simple reordering. The following example creates two HTML tables. The first table is filled with domestic sales while the second table is filled with foreign sales.

    ]]>

    It is possible for there to be two matching descendants where one is a descendant of the other. This case is not treated specially: both descendants will be processed as usual. For example, given a source document

    ]]>

    the rule

    ]]>

    will process both the outer div and inner div elements.

    Typically, xsl:apply-templates is used to process only nodes that are descendants of the current node. Such use of xsl:apply-templates cannot result in non-terminating processing loops. However, when xsl:apply-templates is used to process elements that are not descendants of the current node, the possibility arises of non-terminating loops. For example,

    ]]>

    Implementations may be able to detect such loops in some cases, but the possibility exists that a stylesheet may enter a non-terminating loop that an implementation is unable to detect. This may present a denial of service security risk.

    Conflict Resolution for Template Rules

    It is possible for a source node to match more than one template rule. The template rule to be used is determined as follows:

    First, all matching template rules that have lower import precedence than the matching template rule or rules with the highest import precedence are eliminated from consideration.

    Next, all matching template rules that have lower priority than the matching template rule or rules with the highest priority are eliminated from consideration. The priority of a template rule is specified by the priority attribute on the template rule. The value of this must be a real number (positive or negative), matching the production Number with an optional leading minus sign (-). The default priority is computed as follows:

    If the pattern contains multiple alternatives separated by |, then it is treated equivalently to a set of template rules, one for each alternative.

    If the pattern has the form of a QName preceded by a ChildOrAttributeAxisSpecifier or has the form processing-instruction(Literal) preceded by a ChildOrAttributeAxisSpecifier, then the priority is 0.

    If the pattern has the form NCName:* preceded by a ChildOrAttributeAxisSpecifier, then the priority is -0.25.

    Otherwise, if the pattern consists of just a NodeTest preceded by a ChildOrAttributeAxisSpecifier, then the priority is -0.5.

    Otherwise, the priority is 0.5.

    Thus, the most common kind of pattern (a pattern that tests for a node with a particular type and a particular expanded-name) has priority 0. The next less specific kind of pattern (a pattern that tests for a node with a particular type and an expanded-name with a particular namespace URI) has priority -0.25. Patterns less specific than this (patterns that just tests for nodes with particular types) have priority -0.5. Patterns more specific than the most common kind of pattern have priority 0.5.

    It is an error if this leaves more than one matching template rule. An XSLT processor may signal the error; if it does not signal the error, it must recover by choosing, from amongst the matching template rules that are left, the one that occurs last in the stylesheet.

    Overriding Template Rules

    A template rule that is being used to override a template rule in an imported stylesheet (see ) can use the xsl:apply-imports element to invoke the overridden template rule.

    At any point in the processing of a stylesheet, there is a current template rule. Whenever a template rule is chosen by matching a pattern, the template rule becomes the current template rule for the instantiation of the rule's template. When an xsl:for-each element is instantiated, the current template rule becomes null for the instantiation of the content of the xsl:for-each element.

    xsl:apply-imports processes the current node using only template rules that were imported into the stylesheet element containing the current template rule; the node is processed in the current template rule's mode. It is an error if xsl:apply-imports is instantiated when the current template rule is null.

    For example, suppose the stylesheet doc.xsl contains a template rule for example elements:

    ]]>

    Another stylesheet could import doc.xsl and modify the treatment of example elements as follows:

    ]]>

    The combined effect would be to transform an example into an element of the form:

    ...
    ]]>
    Modes

    Modes allow an element to be processed multiple times, each time producing a different result.

    Both xsl:template and xsl:apply-templates have an optional mode attribute. The value of the mode attribute is a QName, which is expanded as described in . If xsl:template does not have a match attribute, it must not have a mode attribute. If an xsl:apply-templates element has a mode attribute, then it applies only to those template rules from xsl:template elements that have a mode attribute with the same value; if an xsl:apply-templates element does not have a mode attribute, then it applies only to those template rules from xsl:template elements that do not have a mode attribute.

    Built-in Template Rules

    There is a built-in template rule to allow recursive processing to continue in the absence of a successful pattern match by an explicit template rule in the stylesheet. This template rule applies to both element nodes and the root node. The following shows the equivalent of the built-in template rule:

    ]]>

    There is also a built-in template rule for each mode, which allows recursive processing to continue in the same mode in the absence of a successful pattern match by an explicit template rule in the stylesheet. This template rule applies to both element nodes and the root node. The following shows the equivalent of the built-in template rule for mode m.

    <xsl:template match="*|/" mode="m"> <xsl:apply-templates mode="m"/> </xsl:template>

    There is also a built-in template rule for text and attribute nodes that copies text through:

    ]]>

    The built-in template rule for processing instructions and comments is to do nothing.

    ]]>

    The built-in template rule for namespace nodes is also to do nothing. There is no pattern that can match a namespace node; so, the built-in template rule is the only template rule that is applied for namespace nodes.

    The built-in template rules are treated as if they were imported implicitly before the stylesheet and so have lower import precedence than all other template rules. Thus, the author can override a built-in template rule by including an explicit template rule.

    Named Templates

    Templates can be invoked by name. An xsl:template element with a name attribute specifies a named template. The value of the name attribute is a QName, which is expanded as described in . If an xsl:template element has a name attribute, it may, but need not, also have a match attribute. An xsl:call-template element invokes a template by name; it has a required name attribute that identifies the template to be invoked. Unlike xsl:apply-templates, xsl:call-template does not change the current node or the current node list.

    The match, mode and priority attributes on an xsl:template element do not affect whether the template is invoked by an xsl:call-template element. Similarly, the name attribute on an xsl:template element does not affect whether the template is invoked by an xsl:apply-templates element.

    It is an error if a stylesheet contains more than one template with the same name and same import precedence.

    Creating the Result Tree

    This section describes instructions that directly create nodes in the result tree.

    Creating Elements and Attributes Literal Result Elements

    In a template, an element in the stylesheet that does not belong to the XSLT namespace and that is not an extension element (see ) is instantiated to create an element node with the same expanded-name. The content of the element is a template, which is instantiated to give the content of the created element node. The created element node will have the attribute nodes that were present on the element node in the stylesheet tree, other than attributes with names in the XSLT namespace.

    The created element node will also have a copy of the namespace nodes that were present on the element node in the stylesheet tree with the exception of any namespace node whose string-value is the XSLT namespace URI (&XSLT.ns;), a namespace URI declared as an extension namespace (see ), or a namespace URI designated as an excluded namespace. A namespace URI is designated as an excluded namespace by using an exclude-result-prefixes attribute on an xsl:stylesheet element or an xsl:exclude-result-prefixes attribute on a literal result element. The value of both these attributes is a whitespace-separated list of namespace prefixes. The namespace bound to each of the prefixes is designated as an excluded namespace. It is an error if there is no namespace bound to the prefix on the element bearing the exclude-result-prefixes or xsl:exclude-result-prefixes attribute. The default namespace (as declared by xmlns) may be designated as an excluded namespace by including #default in the list of namespace prefixes. The designation of a namespace as an excluded namespace is effective within the subtree of the stylesheet rooted at the element bearing the exclude-result-prefixes or xsl:exclude-result-prefixes attribute; a subtree rooted at an xsl:stylesheet element does not include any stylesheets imported or included by children of that xsl:stylesheet element.

    When a stylesheet uses a namespace declaration only for the purposes of addressing the source tree, specifying the prefix in the exclude-result-prefixes attribute will avoid superfluous namespace declarations in the result tree.

    The value of an attribute of a literal result element is interpreted as an attribute value template: it can contain expressions contained in curly braces ({}).

    A namespace URI in the stylesheet tree that is being used to specify a namespace URI in the result tree is called a literal namespace URI. This applies to:

    the namespace URI in the expanded-name of a literal result element in the stylesheet

    the namespace URI in the expanded-name of an attribute specified on a literal result element in the stylesheet

    the string-value of a namespace node on a literal result element in the stylesheet

    A stylesheet can use the xsl:namespace-alias element to declare that one namespace URI is an alias for another namespace URI. When a literal namespace URI has been declared to be an alias for another namespace URI, then the namespace URI in the result tree will be the namespace URI that the literal namespace URI is an alias for, instead of the literal namespace URI itself. The xsl:namespace-alias element declares that the namespace URI bound to the prefix specified by the stylesheet-prefix attribute is an alias for the namespace URI bound to the prefix specified by the result-prefix attribute. Thus, the stylesheet-prefix attribute specifies the namespace URI that will appear in the stylesheet, and the result-prefix attribute specifies the corresponding namespace URI that will appear in the result tree. The default namespace (as declared by xmlns) may be specified by using #default instead of a prefix. If a namespace URI is declared to be an alias for multiple different namespace URIs, then the declaration with the highest import precedence is used. It is an error if there is more than one such declaration. An XSLT processor may signal the error; if it does not signal the error, it must recover by choosing, from amongst the declarations with the highest import precedence, the one that occurs last in the stylesheet.

    When literal result elements are being used to create element, attribute, or namespace nodes that use the XSLT namespace URI, the stylesheet must use an alias. For example, the stylesheet

    <xsl:stylesheet version="1.0" xmlns:xsl="&XSLT.ns;" xmlns:fo="&XSLFO.ns;" xmlns:axsl="&XSLTA.ns;"> ]]>

    will generate an XSLT stylesheet from a document of the form:

    p h1 h2 h3 h4 ]]>

    It may be necessary also to use aliases for namespaces other than the XSLT namespace URI. For example, literal result elements belonging to a namespace dealing with digital signatures might cause XSLT stylesheets to be mishandled by general-purpose security software; using an alias for the namespace would avoid the possibility of such mishandling.

    Creating Elements with xsl:element

    The xsl:element element allows an element to be created with a computed name. The expanded-name of the element to be created is specified by a required name attribute and an optional namespace attribute. The content of the xsl:element element is a template for the attributes and children of the created element.

    The name attribute is interpreted as an attribute value template. It is an error if the string that results from instantiating the attribute value template is not a QName. An XSLT processor may signal the error; if it does not signal the error, then it must recover by making the the result of instantiating the xsl:element element be the sequence of nodes created by instantiating the content of the xsl:element element, excluding any initial attribute nodes. If the namespace attribute is not present then the QName is expanded into an expanded-name using the namespace declarations in effect for the xsl:element element, including any default namespace declaration.

    If the namespace attribute is present, then it also is interpreted as an attribute value template. The string that results from instantiating the attribute value template should be a URI reference. It is not an error if the string is not a syntactically legal URI reference. If the string is empty, then the expanded-name of the element has a null namespace URI. Otherwise, the string is used as the namespace URI of the expanded-name of the element to be created. The local part of the QName specified by the name attribute is used as the local part of the expanded-name of the element to be created.

    XSLT processors may make use of the prefix of the QName specified in the name attribute when selecting the prefix used for outputting the created element as XML; however, they are not required to do so.

    Creating Attributes with xsl:attribute

    The xsl:attribute element can be used to add attributes to result elements whether created by literal result elements in the stylesheet or by instructions such as xsl:element. The expanded-name of the attribute to be created is specified by a required name attribute and an optional namespace attribute. Instantiating an xsl:attribute element adds an attribute node to the containing result element node. The content of the xsl:attribute element is a template for the value of the created attribute.

    The name attribute is interpreted as an attribute value template. It is an error if the string that results from instantiating the attribute value template is not a QName or is the string xmlns. An XSLT processor may signal the error; if it does not signal the error, it must recover by not adding the attribute to the result tree. If the namespace attribute is not present, then the QName is expanded into an expanded-name using the namespace declarations in effect for the xsl:attribute element, not including any default namespace declaration.

    If the namespace attribute is present, then it also is interpreted as an attribute value template. The string that results from instantiating it should be a URI reference. It is not an error if the string is not a syntactically legal URI reference. If the string is empty, then the expanded-name of the attribute has a null namespace URI. Otherwise, the string is used as the namespace URI of the expanded-name of the attribute to be created. The local part of the QName specified by the name attribute is used as the local part of the expanded-name of the attribute to be created.

    XSLT processors may make use of the prefix of the QName specified in the name attribute when selecting the prefix used for outputting the created attribute as XML; however, they are not required to do so and, if the prefix is xmlns, they must not do so. Thus, although it is not an error to do:

    <xsl:attribute name="xmlns:xsl" namespace="whatever">&XSLT.ns;</xsl:attribute>

    it will not result in a namespace declaration being output.

    Adding an attribute to an element replaces any existing attribute of that element with the same expanded-name.

    The following are all errors:

    Adding an attribute to an element after children have been added to it; implementations may either signal the error or ignore the attribute.

    Adding an attribute to a node that is not an element; implementations may either signal the error or ignore the attribute.

    Creating nodes other than text nodes during the instantiation of the content of the xsl:attribute element; implementations may either signal the error or ignore the offending nodes.

    When an xsl:attribute contains a text node with a newline, then the XML output must contain a character reference. For example,

    x y]]>

    will result in the output

    (or with any equivalent character reference). The XML output cannot be

    This is because XML 1.0 requires newline characters in attribute values to be normalized into spaces but requires character references to newline characters not to be normalized. The attribute values in the data model represent the attribute value after normalization. If a newline occurring in an attribute value in the tree were output as a newline character rather than as character reference, then the attribute value in the tree created by reparsing the XML would contain a space not a newline, which would mean that the tree had not been output correctly.

    Named Attribute Sets

    The xsl:attribute-set element defines a named set of attributes. The name attribute specifies the name of the attribute set. The value of the name attribute is a QName, which is expanded as described in . The content of the xsl:attribute-set element consists of zero or more xsl:attribute elements that specify the attributes in the set.

    Attribute sets are used by specifying a use-attribute-sets attribute on xsl:element, xsl:copy (see ) or xsl:attribute-set elements. The value of the use-attribute-sets attribute is a whitespace-separated list of names of attribute sets. Each name is specified as a QName, which is expanded as described in . Specifying a use-attribute-sets attribute is equivalent to adding xsl:attribute elements for each of the attributes in each of the named attribute sets to the beginning of the content of the element with the use-attribute-sets attribute, in the same order in which the names of the attribute sets are specified in the use-attribute-sets attribute. It is an error if use of use-attribute-sets attributes on xsl:attribute-set elements causes an attribute set to directly or indirectly use itself.

    Attribute sets can also be used by specifying an xsl:use-attribute-sets attribute on a literal result element. The value of the xsl:use-attribute-sets attribute is a whitespace-separated list of names of attribute sets. The xsl:use-attribute-sets attribute has the same effect as the use-attribute-sets attribute on xsl:element with the additional rule that attributes specified on the literal result element itself are treated as if they were specified by xsl:attribute elements before any actual xsl:attribute elements but after any xsl:attribute elements implied by the xsl:use-attribute-sets attribute. Thus, for a literal result element, attributes from attribute sets named in an xsl:use-attribute-sets attribute will be added first, in the order listed in the attribute; next, attributes specified on the literal result element will be added; finally, any attributes specified by xsl:attribute elements will be added. Since adding an attribute to an element replaces any existing attribute of that element with the same name, this means that attributes specified in attribute sets can be overridden by attributes specified on the literal result element itself.

    The template within each xsl:attribute element in an xsl:attribute-set element is instantiated each time the attribute set is used; it is instantiated using the same current node and current node list as is used for instantiating the element bearing the use-attribute-sets or xsl:use-attribute-sets attribute. However, it is the position in the stylesheet of the xsl:attribute element rather than of the element bearing the use-attribute-sets or xsl:use-attribute-sets attribute that determines which variable bindings are visible (see ); thus, only variables and parameters declared by top-level xsl:variable and xsl:param elements are visible.

    The following example creates a named attribute set title-style and uses it in a template rule.

    12pt bold ]]>

    Multiple definitions of an attribute set with the same expanded-name are merged. An attribute from a definition that has higher import precedence takes precedence over an attribute from a definition that has lower import precedence. It is an error if there are two attribute sets that have the same expanded-name and equal import precedence and that both contain the same attribute, unless there is a definition of the attribute set with higher import precedence that also contains the attribute. An XSLT processor may signal the error; if it does not signal the error, it must recover by choosing from amongst the definitions that specify the attribute that have the highest import precedence the one that was specified last in the stylesheet. Where the attributes in an attribute set were specified is relevant only in merging the attributes into the attribute set; it makes no difference when the attribute set is used.

    Creating Text

    A template can also contain text nodes. Each text node in a template remaining after whitespace has been stripped as specified in will create a text node with the same string-value in the result tree. Adjacent text nodes in the result tree are automatically merged.

    Note that text is processed at the tree level. Thus, markup of &lt; in a template will be represented in the stylesheet tree by a text node that includes the character <. This will create a text node in the result tree that contains a < character, which will be represented by the markup &lt; (or an equivalent character reference) when the result tree is externalized as an XML document (unless output escaping is disabled as described in ).

    Literal data characters may also be wrapped in an xsl:text element. This wrapping may change what whitespace characters are stripped (see ) but does not affect how the characters are handled by the XSLT processor thereafter.

    The xml:lang and xml:space attributes are not treated specially by XSLT. In particular,

    it is the responsibility of the stylesheet author explicitly to generate any xml:lang or xml:space attributes that are needed in the result;

    specifying an xml:lang or xml:space attribute on an element in the XSLT namespace will not cause any xml:lang or xml:space attributes to appear in the result.

    Creating Processing Instructions

    The xsl:processing-instruction element is instantiated to create a processing instruction node. The content of the xsl:processing-instruction element is a template for the string-value of the processing instruction node. The xsl:processing-instruction element has a required name attribute that specifies the name of the processing instruction node. The value of the name attribute is interpreted as an attribute value template.

    For example, this

    href="book.css" type="text/css"]]>

    would create the processing instruction

    ]]>

    It is an error if the string that results from instantiating the name attribute is not both an NCName and a PITarget. An XSLT processor may signal the error; if it does not signal the error, it must recover by not adding the processing instruction to the result tree.

    This means that xsl:processing-instruction cannot be used to output an XML declaration. The xsl:output element should be used instead (see ).

    It is an error if instantiating the content of xsl:processing-instruction creates nodes other than text nodes. An XSLT processor may signal the error; if it does not signal the error, it must recover by ignoring the offending nodes together with their content.

    It is an error if the result of instantiating the content of the xsl:processing-instruction contains the string ?>. An XSLT processor may signal the error; if it does not signal the error, it must recover by inserting a space after any occurrence of ? that is followed by a >.

    Creating Comments

    The xsl:comment element is instantiated to create a comment node in the result tree. The content of the xsl:comment element is a template for the string-value of the comment node.

    For example, this

    This file is automatically generated. Do not edit!]]>

    would create the comment

    ]]>

    It is an error if instantiating the content of xsl:comment creates nodes other than text nodes. An XSLT processor may signal the error; if it does not signal the error, it must recover by ignoring the offending nodes together with their content.

    It is an error if the result of instantiating the content of the xsl:comment contains the string -- or ends with -. An XSLT processor may signal the error; if it does not signal the error, it must recover by inserting a space after any occurrence of - that is followed by another - or that ends the comment.

    Copying

    The xsl:copy element provides an easy way of copying the current node. Instantiating the xsl:copy element creates a copy of the current node. The namespace nodes of the current node are automatically copied as well, but the attributes and children of the node are not automatically copied. The content of the xsl:copy element is a template for the attributes and children of the created node; the content is instantiated only for nodes of types that can have attributes or children (i.e. root nodes and element nodes).

    The xsl:copy element may have a use-attribute-sets attribute (see ). This is used only when copying element nodes.

    The root node is treated specially because the root node of the result tree is created implicitly. When the current node is the root node, xsl:copy will not create a root node, but will just use the content template.

    For example, the identity transformation can be written using xsl:copy as follows:

    ]]>

    When the current node is an attribute, then if it would be an error to use xsl:attribute to create an attribute with the same name as the current node, then it is also an error to use xsl:copy (see ).

    The following example shows how xml:lang attributes can be easily copied through from source to result. If a stylesheet defines the following named template:

    ]]>

    then it can simply do

    ]]>

    instead of

    ]]>

    when it wants to copy the xml:lang attribute.

    Computing Generated Text

    Within a template, the xsl:value-of element can be used to compute generated text, for example by extracting text from the source tree or by inserting the value of a variable. The xsl:value-of element does this with an expression that is specified as the value of the select attribute. Expressions can also be used inside attribute values of literal result elements by enclosing the expression in curly braces ({}).

    Generating Text with xsl:value-of

    The xsl:value-of element is instantiated to create a text node in the result tree. The required select attribute is an expression; this expression is evaluated and the resulting object is converted to a string as if by a call to the string function. The string specifies the string-value of the created text node. If the string is empty, no text node will be created. The created text node will be merged with any adjacent text nodes.

    The xsl:copy-of element can be used to copy a node-set over to the result tree without converting it to a string. See .

    For example, the following creates an HTML paragraph from a person element with given-name and family-name attributes. The paragraph will contain the value of the given-name attribute of the current node followed by a space and the value of the family-name attribute of the current node.

    ]]>

    For another example, the following creates an HTML paragraph from a person element with given-name and family-name children elements. The paragraph will contain the string-value of the first given-name child element of the current node followed by a space and the string-value of the first family-name child element of the current node.

    ]]>

    The following precedes each procedure element with a paragraph containing the security level of the procedure. It assumes that the security level that applies to a procedure is determined by a security attribute on the procedure element or on an ancestor element of the procedure. It also assumes that if more than one such element has a security attribute then the security level is determined by the element that is closest to the procedure.

    ]]>
    Attribute Value Templates

    In an attribute value that is interpreted as an attribute value template, such as an attribute of a literal result element, an expression can be used by surrounding the expression with curly braces ({}). The attribute value template is instantiated by replacing the expression together with surrounding curly braces by the result of evaluating the expression and converting the resulting object to a string as if by a call to the string function. Curly braces are not recognized in an attribute value in an XSLT stylesheet unless the attribute is specifically stated to be one that is interpreted as an attribute value template; in an element syntax summary, the value of such attributes is surrounded by curly braces.

    Not all attributes are interpreted as attribute value templates. Attributes whose value is an expression or pattern, attributes of top-level elements and attributes that refer to named XSLT objects are not interpreted as attribute value templates. In addition, xmlns attributes are not interpreted as attribute value templates; it would not be conformant with the XML Namespaces Recommendation to do this.

    The following example creates an img result element from a photograph element in the source; the value of the src attribute of the img element is computed from the value of the image-dir variable and the string-value of the href child of the photograph element; the value of the width attribute of the img element is computed from the value of the width attribute of the size child of the photograph element:

    /images ]]>

    With this source

    headquarters.jpg ]]>

    the result would be

    ]]>

    When an attribute value template is instantiated, a double left or right curly brace outside an expression will be replaced by a single curly brace. It is an error if a right curly brace occurs in an attribute value template outside an expression without being followed by a second right curly brace. A right curly brace inside a Literal in an expression is not recognized as terminating the expression.

    Curly braces are not recognized recursively inside expressions. For example:

    ]]>

    is not allowed. Instead, use simply:

    ]]>
    Numbering

    The xsl:number element is used to insert a formatted number into the result tree. The number to be inserted may be specified by an expression. The value attribute contains an expression. The expression is evaluated and the resulting object is converted to a number as if by a call to the number function. The number is rounded to an integer and then converted to a string using the attributes specified in ; in this context, the value of each of these attributes is interpreted as an attribute value template. After conversion, the resulting string is inserted in the result tree. For example, the following example numbers a sorted list:

    ]]>

    If no value attribute is specified, then the xsl:number element inserts a number based on the position of the current node in the source tree. The following attributes control how the current node is to be numbered:

    The level attribute specifies what levels of the source tree should be considered; it has the values single, multiple or any. The default is single.

    The count attribute is a pattern that specifies what nodes should be counted at those levels. If count attribute is not specified, then it defaults to the pattern that matches any node with the same node type as the current node and, if the current node has an expanded-name, with the same expanded-name as the current node.

    The from attribute is a pattern that specifies where counting starts.

    In addition, the attributes specified in are used for number to string conversion, as in the case when the value attribute is specified.

    The xsl:number element first constructs a list of positive integers using the level, count and from attributes:

    When level="single", it goes up to the first node in the ancestor-or-self axis that matches the count pattern, and constructs a list of length one containing one plus the number of preceding siblings of that ancestor that match the count pattern. If there is no such ancestor, it constructs an empty list. If the from attribute is specified, then the only ancestors that are searched are those that are descendants of the nearest ancestor that matches the from pattern. Preceding siblings has the same meaning here as with the preceding-sibling axis.

    When level="multiple", it constructs a list of all ancestors of the current node in document order followed by the element itself; it then selects from the list those nodes that match the count pattern; it then maps each node in the list to one plus the number of preceding siblings of that node that match the count pattern. If the from attribute is specified, then the only ancestors that are searched are those that are descendants of the nearest ancestor that matches the from pattern. Preceding siblings has the same meaning here as with the preceding-sibling axis.

    When level="any", it constructs a list of length one containing the number of nodes that match the count pattern and belong to the set containing the current node and all nodes at any level of the document that are before the current node in document order, excluding any namespace and attribute nodes (in other words the union of the members of the preceding and ancestor-or-self axes). If the from attribute is specified, then only nodes after the first node before the current node that match the from pattern are considered.

    The list of numbers is then converted into a string using the attributes specified in ; in this context, the value of each of these attributes is interpreted as an attribute value template. After conversion, the resulting string is inserted in the result tree.

    The following would number the items in an ordered list:

    . ]]>

    The following two rules would number title elements. This is intended for a document that contains a sequence of chapters followed by a sequence of appendices, where both chapters and appendices contain sections, which in turn contain subsections. Chapters are numbered 1, 2, 3; appendices are numbered A, B, C; sections in chapters are numbered 1.1, 1.2, 1.3; sections in appendices are numbered A.1, A.2, A.3.

    ]]>

    The following example numbers notes sequentially within a chapter:

    ]]>

    The following example would number H4 elements in HTML with a three-part label:

    . . ]]> Number to String Conversion Attributes

    The following attributes are used to control conversion of a list of numbers into a string. The numbers are integers greater than 0. The attributes are all optional.

    The main attribute is format. The default value for the format attribute is 1. The format attribute is split into a sequence of tokens where each token is a maximal sequence of alphanumeric characters or a maximal sequence of non-alphanumeric characters. Alphanumeric means any character that has a Unicode category of Nd, Nl, No, Lu, Ll, Lt, Lm or Lo. The alphanumeric tokens (format tokens) specify the format to be used for each number in the list. If the first token is a non-alphanumeric token, then the constructed string will start with that token; if the last token is non-alphanumeric token, then the constructed string will end with that token. Non-alphanumeric tokens that occur between two format tokens are separator tokens that are used to join numbers in the list. The nth format token will be used to format the nth number in the list. If there are more numbers than format tokens, then the last format token will be used to format remaining numbers. If there are no format tokens, then a format token of 1 is used to format all numbers. The format token specifies the string to be used to represent the number 1. Each number after the first will be separated from the preceding number by the separator token preceding the format token used to format that number, or, if there are no separator tokens, then by . (a period character).

    Format tokens are a superset of the allowed values for the type attribute for the OL element in HTML 4.0 and are interpreted as follows:

    Any token where the last character has a decimal digit value of 1 (as specified in the Unicode character property database), and the Unicode value of preceding characters is one less than the Unicode value of the last character generates a decimal representation of the number where each number is at least as long as the format token. Thus, a format token 1 generates the sequence 1 2 ... 10 11 12 ..., and a format token 01 generates the sequence 01 02 ... 09 10 11 12 ... 99 100 101.

    A format token A generates the sequence A B C ... Z AA AB AC....

    A format token a generates the sequence a b c ... z aa ab ac....

    A format token i generates the sequence i ii iii iv v vi vii viii ix x ....

    A format token I generates the sequence I II III IV V VI VII VIII IX X ....

    Any other format token indicates a numbering sequence that starts with that token. If an implementation does not support a numbering sequence that starts with that token, it must use a format token of 1.

    When numbering with an alphabetic sequence, the lang attribute specifies which language's alphabet is to be used; it has the same range of values as xml:lang ; if no lang value is specified, the language should be determined from the system environment. Implementers should document for which languages they support numbering.

    Implementers should not make any assumptions about how numbering works in particular languages and should properly research the languages that they wish to support. The numbering conventions of many languages are very different from English.

    The letter-value attribute disambiguates between numbering sequences that use letters. In many languages there are two commonly used numbering sequences that use letters. One numbering sequence assigns numeric values to letters in alphabetic sequence, and the other assigns numeric values to each letter in some other manner traditional in that language. In English, these would correspond to the numbering sequences specified by the format tokens a and i. In some languages, the first member of each sequence is the same, and so the format token alone would be ambiguous. A value of alphabetic specifies the alphabetic sequence; a value of traditional specifies the other sequence. If the letter-value attribute is not specified, then it is implementation-dependent how any ambiguity is resolved.

    It is possible for two conforming XSLT processors not to convert a number to exactly the same string. Some XSLT processors may not support some languages. Furthermore, there may be variations possible in the way conversions are performed for any particular language that are not specifiable by the attributes on xsl:number. Future versions of XSLT may provide additional attributes to provide control over these variations. Implementations may also use implementation-specific namespaced attributes on xsl:number for this.

    The grouping-separator attribute gives the separator used as a grouping (e.g. thousands) separator in decimal numbering sequences, and the optional grouping-size specifies the size (normally 3) of the grouping. For example, grouping-separator="," and grouping-size="3" would produce numbers of the form 1,000,000. If only one of the grouping-separator and grouping-size attributes is specified, then it is ignored.

    Here are some examples of conversion specifications:

    format="&#x30A2;" specifies Katakana numbering

    format="&#x30A4;" specifies Katakana numbering in the iroha order

    format="&#x0E51;" specifies numbering with Thai digits

    format="&#x05D0;" letter-value="traditional" specifies traditional Hebrew numbering

    format="&#x10D0;" letter-value="traditional" specifies Georgian numbering

    format="&#x03B1;" letter-value="traditional" specifies classical Greek numbering

    format="&#x0430;" letter-value="traditional" specifies Old Slavic numbering

    Repetition

    When the result has a known regular structure, it is useful to be able to specify directly the template for selected nodes. The xsl:for-each instruction contains a template, which is instantiated for each node selected by the expression specified by the select attribute. The select attribute is required. The expression must evaluate to a node-set. The template is instantiated with the selected node as the current node, and with a list of all of the selected nodes as the current node list. The nodes are processed in document order, unless a sorting specification is present (see ).

    For example, given an XML document with this structure

    ... ... ... ... ... ... ]]>

    the following would create an HTML document containing a table with a row for each customer element

    Customers
    ]]>
    Conditional Processing

    There are two instructions in XSLT that support conditional processing in a template: xsl:if and xsl:choose. The xsl:if instruction provides simple if-then conditionality; the xsl:choose instruction supports selection of one choice when there are several possibilities.

    Conditional Processing with xsl:if

    The xsl:if element has a test attribute, which specifies an expression. The content is a template. The expression is evaluated and the resulting object is converted to a boolean as if by a call to the boolean function. If the result is true, then the content template is instantiated; otherwise, nothing is created. In the following example, the names in a group of names are formatted as a comma separated list:

    , ]]>

    The following colors every other table row yellow:

    yellow ]]>
    Conditional Processing with xsl:choose

    The xsl:choose element selects one among a number of possible alternatives. It consists of a sequence of xsl:when elements followed by an optional xsl:otherwise element. Each xsl:when element has a single attribute, test, which specifies an expression. The content of the xsl:when and xsl:otherwise elements is a template. When an xsl:choose element is processed, each of the xsl:when elements is tested in turn, by evaluating the expression and converting the resulting object to a boolean as if by a call to the boolean function. The content of the first, and only the first, xsl:when element whose test is true is instantiated. If no xsl:when is true, the content of the xsl:otherwise element is instantiated. If no xsl:when element is true, and no xsl:otherwise element is present, nothing is created.

    The following example enumerates items in an ordered list using arabic numerals, letters, or roman numerals depending on the depth to which the ordered lists are nested.

    . ]]>
    Sorting

    Sorting is specified by adding xsl:sort elements as children of an xsl:apply-templates or xsl:for-each element. The first xsl:sort child specifies the primary sort key, the second xsl:sort child specifies the secondary sort key and so on. When an xsl:apply-templates or xsl:for-each element has one or more xsl:sort children, then instead of processing the selected nodes in document order, it sorts the nodes according to the specified sort keys and then processes them in sorted order. When used in xsl:for-each, xsl:sort elements must occur first. When a template is instantiated by xsl:apply-templates and xsl:for-each, the current node list list consists of the complete list of nodes being processed in sorted order.

    xsl:sort has a select attribute whose value is an expression. For each node to be processed, the expression is evaluated with that node as the current node and with the complete list of nodes being processed in unsorted order as the current node list. The resulting object is converted to a string as if by a call to the string function; this string is used as the sort key for that node. The default value of the select attribute is ., which will cause the string-value of the current node to be used as the sort key.

    This string serves as a sort key for the node. The following optional attributes on xsl:sort control how the list of sort keys are sorted; the values of all of these attributes are interpreted as attribute value templates.

    order specifies whether the strings should be sorted in ascending or descending order; ascending specifies ascending order; descending specifies descending order; the default is ascending

    lang specifies the language of the sort keys; it has the same range of values as xml:lang ; if no lang value is specified, the language should be determined from the system environment

    data-type specifies the data type of the strings; the following values are allowed:

    text specifies that the sort keys should be sorted lexicographically in the culturally correct manner for the language specified by lang

    number specifies that the sort keys should be converted to numbers and then sorted according to the numeric value; the sort key is converted to a number as if by a call to the number function; the lang attribute is ignored

    a QName with a prefix is expanded into an expanded-name as described in ; the expanded-name identifies the data-type; the behavior in this case is not specified by this document

    The default value is text.

    The XSL Working Group plans that future versions of XSLT will leverage XML Schemas to define further values for this attribute.

    case-order has the value upper-first or lower-first; this applies when data-type="text", and specifies that upper-case letters should sort before lower-case letters or vice-versa respectively. For example, if lang="en", then A a B b are sorted with case-order="upper-first" and a A b B are sorted with case-order="lower-first". The default value is language dependent.

    It is possible for two conforming XSLT processors not to sort exactly the same. Some XSLT processors may not support some languages. Furthermore, there may be variations possible in the sorting of any particular language that are not specified by the attributes on xsl:sort, for example, whether Hiragana or Katakana is sorted first in Japanese. Future versions of XSLT may provide additional attributes to provide control over these variations. Implementations may also use implementation-specific namespaced attributes on xsl:sort for this.

    It is recommended that implementers consult for information on internationalized sorting.

    The sort must be stable: in the sorted list of nodes, any sub list that has sort keys that all compare equal must be in document order.

    For example, suppose an employee database has the form

    James Clark ... ]]>

    Then a list of employees sorted by name could be generated using:

  • ]]>
    Variables and Parameters

    A variable is a name that may be bound to a value. The value to which a variable is bound (the value of the variable) can be an object of any of the types that can be returned by expressions. There are two elements that can be used to bind variables: xsl:variable and xsl:param. The difference is that the value specified on the xsl:param variable is only a default value for the binding; when the template or stylesheet within which the xsl:param element occurs is invoked, parameters may be passed that are used in place of the default values.

    Both xsl:variable and xsl:param have a required name attribute, which specifies the name of the variable. The value of the name attribute is a QName, which is expanded as described in .

    For any use of these variable-binding elements, there is a region of the stylesheet tree within which the binding is visible; within this region, any binding of the variable that was visible on the variable-binding element itself is hidden. Thus, only the innermost binding of a variable is visible. The set of variable bindings in scope for an expression consists of those bindings that are visible at the point in the stylesheet where the expression occurs.

    Result Tree Fragments

    Variables introduce an additional data-type into the expression language. This additional data type is called result tree fragment. A variable may be bound to a result tree fragment instead of one of the four basic XPath data-types (string, number, boolean, node-set). A result tree fragment represents a fragment of the result tree. A result tree fragment is treated equivalently to a node-set that contains just a single root node. However, the operations permitted on a result tree fragment are a subset of those permitted on a node-set. An operation is permitted on a result tree fragment only if that operation would be permitted on a string (the operation on the string may involve first converting the string to a number or boolean). In particular, it is not permitted to use the /, //, and [] operators on result tree fragments. When a permitted operation is performed on a result tree fragment, it is performed exactly as it would be on the equivalent node-set.

    When a result tree fragment is copied into the result tree (see ), then all the nodes that are children of the root node in the equivalent node-set are added in sequence to the result tree.

    Expressions can only return values of type result tree fragment by referencing variables of type result tree fragment or calling extension functions that return a result tree fragment or getting a system property whose value is a result tree fragment.

    Values of Variables and Parameters

    A variable-binding element can specify the value of the variable in three alternative ways.

    If the variable-binding element has a select attribute, then the value of the attribute must be an expression and the value of the variable is the object that results from evaluating the expression. In this case, the content must be empty.

    If the variable-binding element does not have a select attribute and has non-empty content (i.e. the variable-binding element has one or more child nodes), then the content of the variable-binding element specifies the value. The content of the variable-binding element is a template, which is instantiated to give the value of the variable. The value is a result tree fragment equivalent to a node-set containing just a single root node having as children the sequence of nodes produced by instantiating the template. The base URI of the nodes in the result tree fragment is the base URI of the variable-binding element.

    It is an error if a member of the sequence of nodes created by instantiating the template is an attribute node or a namespace node, since a root node cannot have an attribute node or a namespace node as a child. An XSLT processor may signal the error; if it does not signal the error, it must recover by not adding the attribute node or namespace node.

    If the variable-binding element has empty content and does not have a select attribute, then the value of the variable is an empty string. Thus

    ]]>

    is equivalent to

    ]]>

    When a variable is used to select nodes by position, be careful not to do:

    2 ... ]]>

    This will output the value of the first item element, because the variable n will be bound to a result tree fragment, not a number. Instead, do either

    ... ]]>

    or

    2 ... ]]>

    One convenient way to specify the empty node-set as the default value of a parameter is:

    ]]>
    Using Values of Variables and Parameters with xsl:copy-of

    The xsl:copy-of element can be used to insert a result tree fragment into the result tree, without first converting it to a string as xsl:value-of does (see ). The required select attribute contains an expression. When the result of evaluating the expression is a result tree fragment, the complete fragment is copied into the result tree. When the result is a node-set, all the nodes in the set are copied in document order into the result tree; copying an element node copies the attribute nodes, namespace nodes and children of the element node as well as the element node itself; a root node is copied by copying its children. When the result is neither a node-set nor a result tree fragment, the result is converted to a string and then inserted into the result tree, as with xsl:value-of.

    Top-level Variables and Parameters

    Both xsl:variable and xsl:param are allowed as top-level elements. A top-level variable-binding element declares a global variable that is visible everywhere. A top-level xsl:param element declares a parameter to the stylesheet; XSLT does not define the mechanism by which parameters are passed to the stylesheet. It is an error if a stylesheet contains more than one binding of a top-level variable with the same name and same import precedence. At the top-level, the expression or template specifying the variable value is evaluated with the same context as that used to process the root node of the source document: the current node is the root node of the source document and the current node list is a list containing just the root node of the source document. If the template or expression specifying the value of a global variable x references a global variable y, then the value for y must be computed before the value of x. It is an error if it is impossible to do this for all global variable definitions; in other words, it is an error if the definitions are circular.

    This example declares a global variable para-font-size, which it references in an attribute value template.

    12pt ]]>
    Variables and Parameters within Templates

    As well as being allowed at the top-level, both xsl:variable and xsl:param are also allowed in templates. xsl:variable is allowed anywhere within a template that an instruction is allowed. In this case, the binding is visible for all following siblings and their descendants. Note that the binding is not visible for the xsl:variable element itself. xsl:param is allowed as a child at the beginning of an xsl:template element. In this context, the binding is visible for all following siblings and their descendants. Note that the binding is not visible for the xsl:param element itself.

    A binding shadows another binding if the binding occurs at a point where the other binding is visible, and the bindings have the same name. It is an error if a binding established by an xsl:variable or xsl:param element within a template shadows another binding established by an xsl:variable or xsl:param element also within the template. It is not an error if a binding established by an xsl:variable or xsl:param element in a template shadows another binding established by an xsl:variable or xsl:param top-level element. Thus, the following is an error:

    ]]>

    However, the following is allowed:

    ]]>

    The nearest equivalent in Java to an xsl:variable element in a template is a final local variable declaration with an initializer. For example,

    ]]>

    has similar semantics to

    final Object x = "value";

    XSLT does not provide an equivalent to the Java assignment operator

    x = "value";

    because this would make it harder to create an implementation that processes a document other than in a batch-like way, starting at the beginning and continuing through to the end.

    Passing Parameters to Templates

    Parameters are passed to templates using the xsl:with-param element. The required name attribute specifies the name of the parameter (the variable the value of whose binding is to be replaced). The value of the name attribute is a QName, which is expanded as described in . xsl:with-param is allowed within both xsl:call-template and xsl:apply-templates. The value of the parameter is specified in the same way as for xsl:variable and xsl:param. The current node and current node list used for computing the value specified by xsl:with-param element is the same as that used for the xsl:apply-templates or xsl:call-template element within which it occurs. It is not an error to pass a parameter x to a template that does not have an xsl:param element for x; the parameter is simply ignored.

    This example defines a named template for a numbered-block with an argument to control the format of the number.

    1. a. ]]>
    Additional Functions

    This section describes XSLT-specific additions to the core XPath function library. Some of these additional functions also make use of information specified by top-level elements in the stylesheet; this section also describes these elements.

    Multiple Source Documents

    The document function allows access to XML documents other than the main source document.

    When the document function has exactly one argument and the argument is a node-set, then the result is the union, for each node in the argument node-set, of the result of calling the document function with the first argument being the string-value of the node, and the second argument being a node-set with the node as its only member. When the document function has two arguments and the first argument is a node-set, then the result is the union, for each node in the argument node-set, of the result of calling the document function with the first argument being the string-value of the node, and with the second argument being the second argument passed to the document function.

    When the first argument to the document function is not a node-set, the first argument is converted to a string as if by a call to the string function. This string is treated as a URI reference; the resource identified by the URI is retrieved. The data resulting from the retrieval action is parsed as an XML document and a tree is constructed in accordance with the data model (see ). If there is an error retrieving the resource, then the XSLT processor may signal an error; if it does not signal an error, it must recover by returning an empty node-set. One possible kind of retrieval error is that the XSLT processor does not support the URI scheme used by the URI. An XSLT processor is not required to support any particular URI schemes. The documentation for an XSLT processor should specify which URI schemes the XSLT processor supports.

    If the URI reference does not contain a fragment identifier, then a node-set containing just the root node of the document is returned. If the URI reference does contain a fragment identifier, the function returns a node-set containing the nodes in the tree identified by the fragment identifier of the URI reference. The semantics of the fragment identifier is dependent on the media type of the result of retrieving the URI. If there is an error in processing the fragment identifier, the XSLT processor may signal the error; if it does not signal the error, it must recover by returning an empty node-set. Possible errors include:

    The fragment identifier identifies something that cannot be represented by an XSLT node-set (such as a range of characters within a text node).

    The XSLT processor does not support fragment identifiers for the media-type of the retrieval result. An XSLT processor is not required to support any particular media types. The documentation for an XSLT processor should specify for which media types the XSLT processor supports fragment identifiers.

    The data resulting from the retrieval action is parsed as an XML document regardless of the media type of the retrieval result; if the top-level media type is text, then it is parsed in the same way as if the media type were text/xml; otherwise, it is parsed in the same way as if the media type were application/xml.

    Since there is no top-level xml media type, data with a media type other than text/xml or application/xml may in fact be XML.

    The URI reference may be relative. The base URI (see ) of the node in the second argument node-set that is first in document order is used as the base URI for resolving the relative URI into an absolute URI. If the second argument is omitted, then it defaults to the node in the stylesheet that contains the expression that includes the call to the document function. Note that a zero-length URI reference is a reference to the document relative to which the URI reference is being resolved; thus document("") refers to the root node of the stylesheet; the tree representation of the stylesheet is exactly the same as if the XML document containing the stylesheet was the initial source document.

    Two documents are treated as the same document if they are identified by the same URI. The URI used for the comparison is the absolute URI into which any relative URI was resolved and does not include any fragment identifier. One root node is treated as the same node as another root node if the two nodes are from the same document. Thus, the following expression will always be true:

    generate-id(document("foo.xml"))=generate-id(document("foo.xml"))

    The document function gives rise to the possibility that a node-set may contain nodes from more than one document. With such a node-set, the relative document order of two nodes in the same document is the normal document order defined by XPath . The relative document order of two nodes in different documents is determined by an implementation-dependent ordering of the documents containing the two nodes. There are no constraints on how the implementation orders documents other than that it must do so consistently: an implementation must always use the same order for the same set of documents.

    Keys

    Keys provide a way to work with documents that contain an implicit cross-reference structure. The ID, IDREF and IDREFS attribute types in XML provide a mechanism to allow XML documents to make their cross-reference explicit. XSLT supports this through the XPath id function. However, this mechanism has a number of limitations:

    ID attributes must be declared as such in the DTD. If an ID attribute is declared as an ID attribute only in the external DTD subset, then it will be recognized as an ID attribute only if the XML processor reads the external DTD subset. However, XML does not require XML processors to read the external DTD, and they may well choose not to do so, especially if the document is declared standalone="yes".

    A document can contain only a single set of unique IDs. There cannot be separate independent sets of unique IDs.

    The ID of an element can only be specified in an attribute; it cannot be specified by the content of the element, or by a child element.

    An ID is constrained to be an XML name. For example, it cannot contain spaces.

    An element can have at most one ID.

    At most one element can have a particular ID.

    Because of these limitations XML documents sometimes contain a cross-reference structure that is not explicitly declared by ID/IDREF/IDREFS attributes.

    A key is a triple containing:

    the node which has the key

    the name of the key (an expanded-name)

    the value of the key (a string)

    A stylesheet declares a set of keys for each document using the xsl:key element. When this set of keys contains a member with node x, name y and value z, we say that node x has a key with name y and value z.

    Thus, a key is a kind of generalized ID, which is not subject to the same limitations as an XML ID:

    Keys are declared in the stylesheet using xsl:key elements.

    A key has a name as well as a value; each key name may be thought of as distinguishing a separate, independent space of identifiers.

    The value of a named key for an element may be specified in any convenient place; for example, in an attribute, in a child element or in content. An XPath expression is used to specify where to find the value for a particular named key.

    The value of a key can be an arbitrary string; it is not constrained to be a name.

    There can be multiple keys in a document with the same node, same key name, but different key values.

    There can be multiple keys in a document with the same key name, same key value, but different nodes.

    The xsl:key element is used to declare keys. The name attribute specifies the name of the key. The value of the name attribute is a QName, which is expanded as described in . The match attribute is a Pattern; an xsl:key element gives information about the keys of any node that matches the pattern specified in the match attribute. The use attribute is an expression specifying the values of the key; the expression is evaluated once for each node that matches the pattern. If the result is a node-set, then for each node in the node-set, the node that matches the pattern has a key of the specified name whose value is the string-value of the node in the node-set; otherwise, the result is converted to a string, and the node that matches the pattern has a key of the specified name with value equal to that string. Thus, a node x has a key with name y and value z if and only if there is an xsl:key element such that:

    x matches the pattern specified in the match attribute of the xsl:key element;

    the value of the name attribute of the xsl:key element is equal to y; and

    when the expression specified in the use attribute of the xsl:key element is evaluated with x as the current node and with a node list containing just x as the current node list resulting in an object u, then either z is equal to the result of converting u to a string as if by a call to the string function, or u is a node-set and z is equal to the string-value of one or more of the nodes in u.

    Note also that there may be more than one xsl:key element that matches a given node; all of the matching xsl:key elements are used, even if they do not have the same import precedence.

    It is an error for the value of either the use attribute or the match attribute to contain a VariableReference.

    The key function does for keys what the id function does for IDs. The first argument specifies the name of the key. The value of the argument must be a QName, which is expanded as described in . When the second argument to the key function is of type node-set, then the result is the union of the result of applying the key function to the string value of each of the nodes in the argument node-set. When the second argument to key is of any other type, the argument is converted to a string as if by a call to the string function; it returns a node-set containing the nodes in the same document as the context node that have a value for the named key equal to this string.

    For example, given a declaration

    ]]>

    an expression key("idkey",@ref) will return the same node-set as id(@ref), assuming that the only ID attribute declared in the XML source document is:

    ]]>

    and that the ref attribute of the current node contains no whitespace.

    Suppose a document describing a function library uses a prototype element to define functions

    ]]>

    and a function element to refer to function names

    key]]>

    Then the stylesheet could generate hyperlinks between the references and definitions as follows:

    Function: ...

    ]]>

    The key can be used to retrieve a key from a document other than the document containing the context node. For example, suppose a document contains bibliographic references in the form XSLT]]>, and there is a separate XML document bib.xml containing a bibliographic database with entries in the form:

    ...]]>

    Then the stylesheet could use the following to transform the bibref elements:

    ]]>
    Number Formatting

    The format-number function converts its first argument to a string using the format pattern string specified by the second argument and the decimal-format named by the third argument, or the default decimal-format, if there is no third argument. The format pattern string is in the syntax specified by the JDK 1.1 DecimalFormat class. The format pattern string is in a localized notation: the decimal-format determines what characters have a special meaning in the pattern (with the exception of the quote character, which is not localized). The format pattern must not contain the currency sign (#x00A4); support for this feature was added after the initial release of JDK 1.1. The decimal-format name must be a QName, which is expanded as described in . It is an error if the stylesheet does not contain a declaration of the decimal-format with the specified expanded-name.

    Implementations are not required to use the JDK 1.1 implementation, nor are implementations required to be implemented in Java.

    Stylesheets can use other facilities in XPath to control rounding.

    The xsl:decimal-format element declares a decimal-format, which controls the interpretation of a format pattern used by the format-number function. If there is a name attribute, then the element declares a named decimal-format; otherwise, it declares the default decimal-format. The value of the name attribute is a QName, which is expanded as described in . It is an error to declare either the default decimal-format or a decimal-format with a given name more than once (even with different import precedence), unless it is declared every time with the same value for all attributes (taking into account any default values).

    The other attributes on xsl:decimal-format correspond to the methods on the JDK 1.1 DecimalFormatSymbols class. For each get/set method pair there is an attribute defined for the xsl:decimal-format element.

    The following attributes both control the interpretation of characters in the format pattern and specify characters that may appear in the result of formatting the number:

    decimal-separator specifies the character used for the decimal sign; the default value is the period character (.)

    grouping-separator specifies the character used as a grouping (e.g. thousands) separator; the default value is the comma character (,)

    percent specifies the character used as a percent sign; the default value is the percent character (%)

    per-mille specifies the character used as a per mille sign; the default value is the Unicode per-mille character (#x2030)

    zero-digit specifies the character used as the digit zero; the default value is the digit zero (0)

    The following attributes control the interpretation of characters in the format pattern:

    digit specifies the character used for a digit in the format pattern; the default value is the number sign character (#)

    pattern-separator specifies the character used to separate positive and negative sub patterns in a pattern; the default value is the semi-colon character (;)

    The following attributes specify characters or strings that may appear in the result of formatting the number:

    infinity specifies the string used to represent infinity; the default value is the string Infinity

    NaN specifies the string used to represent the NaN value; the default value is the string NaN

    minus-sign specifies the character used as the default minus sign; the default value is the hyphen-minus character (-, #x2D)

    Miscellaneous Additional Functions

    The current function returns a node-set that has the current node as its only member. For an outermost expression (an expression not occurring within another expression), the current node is always the same as the context node. Thus,

    ]]>

    means the same as

    ]]>

    However, within square brackets the current node is usually different from the context node. For example,

    ]]>

    will process all item elements that have a glossary parent element and that have a name attribute with value equal to the value of the current node's ref attribute. This is different from

    ]]>

    which means the same as

    ]]>

    and so would process all item elements that have a glossary parent element and that have a name attribute and a ref attribute with the same value.

    It is an error to use the current function in a pattern.

    The unparsed-entity-uri returns the URI of the unparsed entity with the specified name in the same document as the context node (see ). It returns the empty string if there is no such entity.

    The generate-id function returns a string that uniquely identifies the node in the argument node-set that is first in document order. The unique identifier must consist of ASCII alphanumeric characters and must start with an alphabetic character. Thus, the string is syntactically an XML name. An implementation is free to generate an identifier in any convenient way provided that it always generates the same identifier for the same node and that different identifiers are always generated from different nodes. An implementation is under no obligation to generate the same identifiers each time a document is transformed. There is no guarantee that a generated unique identifier will be distinct from any unique IDs specified in the source document. If the argument node-set is empty, the empty string is returned. If the argument is omitted, it defaults to the context node.

    The argument must evaluate to a string that is a QName. The QName is expanded into a name using the namespace declarations in scope for the expression. The system-property function returns an object representing the value of the system property identified by the name. If there is no such system property, the empty string should be returned.

    Implementations must provide the following system properties, which are all in the XSLT namespace:

    xsl:version, a number giving the version of XSLT implemented by the processor; for XSLT processors implementing the version of XSLT specified by this document, this is the number 1.0 xsl:vendor, a string identifying the vendor of the XSLT processor xsl:vendor-url, a string containing a URL identifying the vendor of the XSLT processor; typically this is the host page (home page) of the vendor's Web site.
    Messages

    The xsl:message instruction sends a message in a way that is dependent on the XSLT processor. The content of the xsl:message instruction is a template. The xsl:message is instantiated by instantiating the content to create an XML fragment. This XML fragment is the content of the message.

    An XSLT processor might implement xsl:message by popping up an alert box or by writing to a log file.

    If the terminate attribute has the value yes, then the XSLT processor should terminate processing after sending the message. The default value is no.

    One convenient way to do localization is to put the localized information (message text, etc.) in an XML document, which becomes an additional input file to the stylesheet. For example, suppose messages for a language L are stored in an XML file resources/L.xml in the form:

    A problem was detected. An error was detected. ]]>

    Then a stylesheet could use the following approach to localize messages:

    problem ]]>
    Extensions

    XSLT allows two kinds of extension, extension elements and extension functions.

    This version of XSLT does not provide a mechanism for defining implementations of extensions. Therefore, an XSLT stylesheet that must be portable between XSLT implementations cannot rely on particular extensions being available. XSLT provides mechanisms that allow an XSLT stylesheet to determine whether the XSLT processor by which it is being processed has implementations of particular extensions available, and to specify what should happen if those extensions are not available. If an XSLT stylesheet is careful to make use of these mechanisms, it is possible for it to take advantage of extensions and still work with any XSLT implementation.

    Extension Elements

    The element extension mechanism allows namespaces to be designated as extension namespaces. When a namespace is designated as an extension namespace and an element with a name from that namespace occurs in a template, then the element is treated as an instruction rather than as a literal result element. The namespace determines the semantics of the instruction.

    Since an element that is a child of an xsl:stylesheet element is not occurring in a template, non-XSLT top-level elements are not extension elements as defined here, and nothing in this section applies to them.

    A namespace is designated as an extension namespace by using an extension-element-prefixes attribute on an xsl:stylesheet element or an xsl:extension-element-prefixes attribute on a literal result element or extension element. The value of both these attributes is a whitespace-separated list of namespace prefixes. The namespace bound to each of the prefixes is designated as an extension namespace. It is an error if there is no namespace bound to the prefix on the element bearing the extension-element-prefixes or xsl:extension-element-prefixes attribute. The default namespace (as declared by xmlns) may be designated as an extension namespace by including #default in the list of namespace prefixes. The designation of a namespace as an extension namespace is effective within the subtree of the stylesheet rooted at the element bearing the extension-element-prefixes or xsl:extension-element-prefixes attribute; a subtree rooted at an xsl:stylesheet element does not include any stylesheets imported or included by children of that xsl:stylesheet element.

    If the XSLT processor does not have an implementation of a particular extension element available, then the element-available function must return false for the name of the element. When such an extension element is instantiated, then the XSLT processor must perform fallback for the element as specified in . An XSLT processor must not signal an error merely because a template contains an extension element for which no implementation is available.

    If the XSLT processor has an implementation of a particular extension element available, then the element-available function must return true for the name of the element.

    Extension Functions

    If a FunctionName in a FunctionCall expression is not an NCName (i.e. if it contains a colon), then it is treated as a call to an extension function. The FunctionName is expanded to a name using the namespace declarations from the evaluation context.

    If the XSLT processor does not have an implementation of an extension function of a particular name available, then the function-available function must return false for that name. If such an extension function occurs in an expression and the extension function is actually called, the XSLT processor must signal an error. An XSLT processor must not signal an error merely because an expression contains an extension function for which no implementation is available.

    If the XSLT processor has an implementation of an extension function of a particular name available, then the function-available function must return true for that name. If such an extension is called, then the XSLT processor must call the implementation passing it the function call arguments; the result returned by the implementation is returned as the result of the function call.

    Fallback

    Normally, instantiating an xsl:fallback element does nothing. However, when an XSLT processor performs fallback for an instruction element, if the instruction element has one or more xsl:fallback children, then the content of each of the xsl:fallback children must be instantiated in sequence; otherwise, an error must be signaled. The content of an xsl:fallback element is a template.

    The following functions can be used with the xsl:choose and xsl:if instructions to explicitly control how a stylesheet should behave if particular elements or functions are not available.

    The argument must evaluate to a string that is a QName. The QName is expanded into an expanded-name using the namespace declarations in scope for the expression. The element-available function returns true if and only if the expanded-name is the name of an instruction. If the expanded-name has a namespace URI equal to the XSLT namespace URI, then it refers to an element defined by XSLT. Otherwise, it refers to an extension element. If the expanded-name has a null namespace URI, the element-available function will return false.

    The argument must evaluate to a string that is a QName. The QName is expanded into an expanded-name using the namespace declarations in scope for the expression. The function-available function returns true if and only if the expanded-name is the name of a function in the function library. If the expanded-name has a non-null namespace URI, then it refers to an extension function; otherwise, it refers to a function defined by XPath or XSLT.

    Output

    An XSLT processor may output the result tree as a sequence of bytes, although it is not required to be able to do so (see ). The xsl:output element allows stylesheet authors to specify how they wish the result tree to be output. If an XSLT processor outputs the result tree, it should do so as specified by the xsl:output element; however, it is not required to do so.

    The xsl:output element is only allowed as a top-level element.

    The method attribute on xsl:output identifies the overall method that should be used for outputting the result tree. The value must be a QName. If the QName does not have a prefix, then it identifies a method specified in this document and must be one of xml, html or text. If the QName has a prefix, then the QName is expanded into an expanded-name as described in ; the expanded-name identifies the output method; the behavior in this case is not specified by this document.

    The default for the method attribute is chosen as follows. If

    the root node of the result tree has an element child,

    the expanded-name of the first element child of the root node (i.e. the document element) of the result tree has local part html (in any combination of upper and lower case) and a null namespace URI, and

    any text nodes preceding the first element child of the root node of the result tree contain only whitespace characters,

    then the default output method is html; otherwise, the default output method is xml. The default output method should be used if there are no xsl:output elements or if none of the xsl:output elements specifies a value for the method attribute.

    The other attributes on xsl:output provide parameters for the output method. The following attributes are allowed:

    version specifies the version of the output method

    indent specifies whether the XSLT processor may add additional whitespace when outputting the result tree; the value must be yes or no

    encoding specifies the preferred character encoding that the XSLT processor should use to encode sequences of characters as sequences of bytes; the value of the attribute should be treated case-insensitively; the value must contain only characters in the range #x21 to #x7E (i.e. printable ASCII characters); the value should either be a charset registered with the Internet Assigned Numbers Authority , or start with X-

    media-type specifies the media type (MIME content type) of the data that results from outputting the result tree; the charset parameter should not be specified explicitly; instead, when the top-level media type is text, a charset parameter should be added according to the character encoding actually used by the output method

    doctype-system specifies the system identifier to be used in the document type declaration

    doctype-public specifies the public identifier to be used in the document type declaration

    omit-xml-declaration specifies whether the XSLT processor should output an XML declaration; the value must be yes or no

    standalone specifies whether the XSLT processor should output a standalone document declaration; the value must be yes or no

    cdata-section-elements specifies a list of the names of elements whose text node children should be output using CDATA sections

    The detailed semantics of each attribute will be described separately for each output method for which it is applicable. If the semantics of an attribute are not described for an output method, then it is not applicable to that output method.

    A stylesheet may contain multiple xsl:output elements and may include or import stylesheets that also contain xsl:output elements. All the xsl:output elements occurring in a stylesheet are merged into a single effective xsl:output element. For the cdata-section-elements attribute, the effective value is the union of the specified values. For other attributes, the effective value is the specified value with the highest import precedence. It is an error if there is more than one such value for an attribute. An XSLT processor may signal the error; if it does not signal the error, if should recover by using the value that occurs last in the stylesheet. The values of attributes are defaulted after the xsl:output elements have been merged; different output methods may have different default values for an attribute.

    XML Output Method

    The xml output method outputs the result tree as a well-formed XML external general parsed entity. If the root node of the result tree has a single element node child and no text node children, then the entity should also be a well-formed XML document entity. When the entity is referenced within a trivial XML document wrapper like this

    entity-URI ]> &e;]]>

    where entity-URI is a URI for the entity, then the wrapper document as a whole should be a well-formed XML document conforming to the XML Namespaces Recommendation . In addition, the output should be such that if a new tree was constructed by parsing the wrapper as an XML document as specified in , and then removing the document element, making its children instead be children of the root node, then the new tree would be the same as the result tree, with the following possible exceptions:

    The order of attributes in the two trees may be different.

    The new tree may contain namespace nodes that were not present in the result tree.

    An XSLT processor may need to add namespace declarations in the course of outputting the result tree as XML.

    If the XSLT processor generated a document type declaration because of the doctype-system attribute, then the above requirements apply to the entity with the generated document type declaration removed.

    The version attribute specifies the version of XML to be used for outputting the result tree. If the XSLT processor does not support this version of XML, it should use a version of XML that it does support. The version output in the XML declaration (if an XML declaration is output) should correspond to the version of XML that the processor used for outputting the result tree. The value of the version attribute should match the VersionNum production of the XML Recommendation . The default value is 1.0.

    The encoding attribute specifies the preferred encoding to use for outputting the result tree. XSLT processors are required to respect values of UTF-8 and UTF-16. For other values, if the XSLT processor does not support the specified encoding it may signal an error; if it does not signal an error it should use UTF-8 or UTF-16 instead. The XSLT processor must not use an encoding whose name does not match the EncName production of the XML Recommendation . If no encoding attribute is specified, then the XSLT processor should use either UTF-8 or UTF-16. It is possible that the result tree will contain a character that cannot be represented in the encoding that the XSLT processor is using for output. In this case, if the character occurs in a context where XML recognizes character references (i.e. in the value of an attribute node or text node), then the character should be output as a character reference; otherwise (for example if the character occurs in the name of an element) the XSLT processor should signal an error.

    If the indent attribute has the value yes, then the xml output method may output whitespace in addition to the whitespace in the result tree (possibly based on whitespace stripped from either the source document or the stylesheet) in order to indent the result nicely; if the indent attribute has the value no, it should not output any additional whitespace. The default value is no. The xml output method should use an algorithm to output additional whitespace that ensures that the result if whitespace were to be stripped from the output using the process described in with the set of whitespace-preserving elements consisting of just xsl:text would be the same when additional whitespace is output as when additional whitespace is not output.

    It is usually not safe to use indent="yes" with document types that include element types with mixed content.

    The cdata-section-elements attribute contains a whitespace-separated list of QNames. Each QName is expanded into an expanded-name using the namespace declarations in effect on the xsl:output element in which the QName occurs; if there is a default namespace, it is used for QNames that do not have a prefix. The expansion is performed before the merging of multiple xsl:output elements into a single effective xsl:output element. If the expanded-name of the parent of a text node is a member of the list, then the text node should be output as a CDATA section. For example,

    ]]>

    would cause a literal result element written in the stylesheet as

    <foo>]]>

    or as

    <example><![CDATA[<foo>]]></example>

    to be output as

    <example><![CDATA[<foo>]]></example>

    If the text node contains the sequence of characters ]]>, then the currently open CDATA section should be closed following the ]] and a new CDATA section opened before the >. For example, a literal result element written in the stylesheet as

    <example>]]&gt;</example>

    would be output as

    <example><![CDATA[]]]]><![CDATA[>]]></example>

    If the text node contains a character that is not representable in the character encoding being used to output the result tree, then the currently open CDATA section should be closed before the character, the character should be output using a character reference or entity reference, and a new CDATA section should be opened for any further characters in the text node.

    CDATA sections should not be used except for text nodes that the cdata-section-elements attribute explicitly specifies should be output using CDATA sections.

    The xml output method should output an XML declaration unless the omit-xml-declaration attribute has the value yes. The XML declaration should include both version information and an encoding declaration. If the standalone attribute is specified, it should include a standalone document declaration with the same value as the value as the value of the standalone attribute. Otherwise, it should not include a standalone document declaration; this ensures that it is both a XML declaration (allowed at the beginning of a document entity) and a text declaration (allowed at the beginning of an external general parsed entity).

    If the doctype-system attribute is specified, the xml output method should output a document type declaration immediately before the first element. The name following <!DOCTYPE should be the name of the first element. If doctype-public attribute is also specified, then the xml output method should output PUBLIC followed by the public identifier and then the system identifier; otherwise, it should output SYSTEM followed by the system identifier. The internal subset should be empty. The doctype-public attribute should be ignored unless the doctype-system attribute is specified.

    The media-type attribute is applicable for the xml output method. The default value for the media-type attribute is text/xml.

    HTML Output Method

    The html output method outputs the result tree as HTML; for example,

    <xsl:stylesheet version="1.0" xmlns:xsl="&XSLT.ns;"> ... ]]>

    The version attribute indicates the version of the HTML. The default value is 4.0, which specifies that the result should be output as HTML conforming to the HTML 4.0 Recommendation .

    The html output method should not output an element differently from the xml output method unless the expanded-name of the element has a null namespace URI; an element whose expanded-name has a non-null namespace URI should be output as XML. If the expanded-name of the element has a null namespace URI, but the local part of the expanded-name is not recognized as the name of an HTML element, the element should output in the same way as a non-empty, inline element such as span.

    The html output method should not output an end-tag for empty elements. For HTML 4.0, the empty elements are area, base, basefont, br, col, frame, hr, img, input, isindex, link, meta and param. For example, an element written as <br/> or <br></br> in the stylesheet should be output as <br>.

    The html output method should recognize the names of HTML elements regardless of case. For example, elements named br, BR or Br should all be recognized as the HTML br element and output without an end-tag.

    The html output method should not perform escaping for the content of the script and style elements. For example, a literal result element written in the stylesheet as

    if (a < b) foo()]]>

    or

    ]]>

    should be output as

    if (a < b) foo()]]>

    The html output method should not escape < characters occurring in attribute values.

    If the indent attribute has the value yes, then the html output method may add or remove whitespace as it outputs the result tree, so long as it does not change how an HTML user agent would render the output. The default value is yes.

    The html output method should escape non-ASCII characters in URI attribute values using the method recommended in Section B.2.1 of the HTML 4.0 Recommendation.

    The html output method may output a character using a character entity reference, if one is defined for it in the version of HTML that the output method is using.

    The html output method should terminate processing instructions with > rather than ?>.

    The html output method should output boolean attributes (that is attributes with only a single allowed value that is equal to the name of the attribute) in minimized form. For example, a start-tag written in the stylesheet as

    ]]>

    should be output as

    ]]>

    The html output method should not escape a & character occurring in an attribute value immediately followed by a { character (see Section B.7.1 of the HTML 4.0 Recommendation). For example, a start-tag written in the stylesheet as

    ]]>

    should be output as

    ]]>

    The encoding attribute specifies the preferred encoding to be used. If there is a HEAD element, then the html output method should add a META element immediately after the start-tag of the HEAD element specifying the character encoding actually used. For example,

    ...]]>

    It is possible that the result tree will contain a character that cannot be represented in the encoding that the XSLT processor is using for output. In this case, if the character occurs in a context where HTML recognizes character references, then the character should be output as a character entity reference or decimal numeric character reference; otherwise (for example, in a script or style element or in a comment), the XSLT processor should signal an error.

    If the doctype-public or doctype-system attributes are specified, then the html output method should output a document type declaration immediately before the first element. The name following <!DOCTYPE should be HTML or html. If the doctype-public attribute is specified, then the output method should output PUBLIC followed by the specified public identifier; if the doctype-system attribute is also specified, it should also output the specified system identifier following the public identifier. If the doctype-system attribute is specified but the doctype-public attribute is not specified, then the output method should output SYSTEM followed by the specified system identifier.

    The media-type attribute is applicable for the html output method. The default value is text/html.

    Text Output Method

    The text output method outputs the result tree by outputting the string-value of every text node in the result tree in document order without any escaping.

    The media-type attribute is applicable for the text output method. The default value for the media-type attribute is text/plain.

    The encoding attribute identifies the encoding that the text output method should use to convert sequences of characters to sequences of bytes. The default is system-dependent. If the result tree contains a character that cannot be represented in the encoding that the XSLT processor is using for output, the XSLT processor should signal an error.

    Disabling Output Escaping

    Normally, the xml output method escapes & and < (and possibly other characters) when outputting text nodes. This ensures that the output is well-formed XML. However, it is sometimes convenient to be able to produce output that is almost, but not quite well-formed XML; for example, the output may include ill-formed sections which are intended to be transformed into well-formed XML by a subsequent non-XML aware process. For this reason, XSLT provides a mechanism for disabling output escaping. An xsl:value-of or xsl:text element may have a disable-output-escaping attribute; the allowed values are yes or no; the default is no; if the value is yes, then a text node generated by instantiating the xsl:value-of or xsl:text element should be output without any escaping. For example,

    <]]>

    should generate the single character <.

    It is an error for output escaping to be disabled for a text node that is used for something other than a text node in the result tree. Thus, it is an error to disable output escaping for an xsl:value-of or xsl:text element that is used to generate the string-value of a comment, processing instruction or attribute node; it is also an error to convert a result tree fragment to a number or a string if the result tree fragment contains a text node for which escaping was disabled. In both cases, an XSLT processor may signal the error; if it does not signal the error, it must recover by ignoring the disable-output-escaping attribute.

    The disable-output-escaping attribute may be used with the html output method as well as with the xml output method. The text output method ignores the disable-output-escaping attribute, since it does not perform any output escaping.

    An XSLT processor will only be able to disable output escaping if it controls how the result tree is output. This may not always be the case. For example, the result tree may be used as the source tree for another XSLT transformation instead of being output. An XSLT processor is not required to support disabling output escaping. If an xsl:value-of or xsl:text specifies that output escaping should be disabled and the XSLT processor does not support this, the XSLT processor may signal an error; if it does not signal an error, it must recover by not disabling output escaping.

    If output escaping is disabled for a character that is not representable in the encoding that the XSLT processor is using for output, then the XSLT processor may signal an error; if it does not signal an error, it must recover by not disabling output escaping.

    Since disabling output escaping may not work with all XSLT processors and can result in XML that is not well-formed, it should be used only when there is no alternative.

    Conformance

    A conforming XSLT processor must be able to use a stylesheet to transform a source tree into a result tree as specified in this document. A conforming XSLT processor need not be able to output the result in XML or in any other form.

    Vendors of XSLT processors are strongly encouraged to provide a way to verify that their processor is behaving conformingly by allowing the result tree to be output as XML or by providing access to the result tree through a standard API such as the DOM or SAX.

    A conforming XSLT processor must signal any errors except for those that this document specifically allows an XSLT processor not to signal. A conforming XSLT processor may but need not recover from any errors that it signals.

    A conforming XSLT processor may impose limits on the processing resources consumed by the processing of a stylesheet.

    Notation

    The specification of each XSLT-defined element type is preceded by a summary of its syntax in the form of a model for elements of that element type. The meaning of syntax summary notation is as follows:

    An attribute is required if and only if its name is in bold.

    The string that occurs in the place of an attribute value specifies the allowed values of the attribute. If this is surrounded by curly braces, then the attribute value is treated as an attribute value template, and the string occurring within curly braces specifies the allowed values of the result of instantiating the attribute value template. Alternative allowed values are separated by |. A quoted string indicates a value equal to that specific string. An unquoted, italicized name specifies a particular type of value.

    If the element is allowed not to be empty, then the element contains a comment specifying the allowed content. The allowed content is specified in a similar way to an element type declaration in XML; template means that any mixture of text nodes, literal result elements, extension elements, and XSLT elements from the instruction category is allowed; top-level-elements means that any mixture of XSLT elements from the top-level-element category is allowed.

    The element is prefaced by comments indicating if it belongs to the instruction category or top-level-element category or both. The category of an element just affects whether it is allowed in the content of elements that allow a template or top-level-elements.

    References Normative References World Wide Web Consortium. Extensible Markup Language (XML) 1.0. W3C Recommendation. See http://www.w3.org/TR/1998/REC-xml-19980210 World Wide Web Consortium. Namespaces in XML. W3C Recommendation. See http://www.w3.org/TR/REC-xml-names World Wide Web Consortium. XML Path Language. W3C Recommendation. See http://www.w3.org/TR/xpath Other References World Wide Web Consortium. Cascading Style Sheets, level 2 (CSS2). W3C Recommendation. See http://www.w3.org/TR/1998/REC-CSS2-19980512 International Organization for Standardization, International Electrotechnical Commission. ISO/IEC 10179:1996. Document Style Semantics and Specification Language (DSSSL). International Standard. World Wide Web Consortium. HTML 4.0 specification. W3C Recommendation. See http://www.w3.org/TR/REC-html40 Internet Assigned Numbers Authority. Character Sets. See ftp://ftp.isi.edu/in-notes/iana/assignments/character-sets. N. Freed, J. Postel. IANA Charset Registration Procedures. IETF RFC 2278. See http://www.ietf.org/rfc/rfc2278.txt. E. Whitehead, M. Murata. XML Media Types. IETF RFC 2376. See http://www.ietf.org/rfc/rfc2376.txt. T. Berners-Lee, R. Fielding, and L. Masinter. Uniform Resource Identifiers (URI): Generic Syntax. IETF RFC 2396. See http://www.ietf.org/rfc/rfc2396.txt. Unicode Consortium. Unicode Technical Report #10. Unicode Collation Algorithm. Unicode Technical Report. See http://www.unicode.org/unicode/reports/tr10/index.html. World Wide Web Consortium. XHTML 1.0: The Extensible HyperText Markup Language. W3C Proposed Recommendation. See http://www.w3.org/TR/xhtml1 World Wide Web Consortium. XML Pointer Language (XPointer). W3C Working Draft. See http://www.w3.org/TR/xptr World Wide Web Consortium. Associating stylesheets with XML documents. W3C Recommendation. See http://www.w3.org/TR/xml-stylesheet World Wide Web Consortium. Extensible Stylesheet Language (XSL). W3C Working Draft. See http://www.w3.org/TR/WD-xsl Element Syntax Summary DTD Fragment for XSLT Stylesheets

    This DTD Fragment is not normative because XML 1.0 DTDs do not support XML Namespaces and thus cannot correctly describe the allowed structure of an XSLT stylesheet.

    The following entity can be used to construct a DTD for XSLT stylesheets that create instances of a particular result DTD. Before referencing the entity, the stylesheet DTD must define a result-elements parameter entity listing the allowed result element types. For example:

    ]]>

    Such result elements should be declared to have xsl:use-attribute-sets and xsl:extension-element-prefixes attributes. The following entity declares the result-element-atts parameter for this purpose. The content that XSLT allows for result elements is the same as it allows for the XSLT elements that are declared in the following entity with a content model of %template;. The DTD may use a more restrictive content model than %template; to reflect the constraints of the result DTD.

    The DTD may define the non-xsl-top-level parameter entity to allow additional top-level elements from namespaces other than the XSLT namespace.

    The use of the xsl: prefix in this DTD does not imply that XSLT stylesheets are required to use this prefix. Any of the elements declared in this DTD may have attributes whose name starts with xmlns: or is equal to xmlns in addition to the attributes declared in this DTD.

    &XSLT.ns; ]]>
    Examples Document Example

    This example is a stylesheet for transforming documents that conform to a simple DTD into XHTML . The DTD is:

    ]]>

    The stylesheet is:

    <xsl:stylesheet version="1.0" xmlns:xsl="&XSLT.ns;" xmlns="&XHTML.ns;"> <xsl:value-of select="title"/>

    NOTE:

    ]]>

    With the following input document

    Document Title Chapter Title
    Section Title This is a test. This is a note.
    Another Section Title This is another test. This is another note.
    ]]>

    it would produce the following result

    <?xml version="1.0" encoding="iso-8859-1"?> <html xmlns="&XHTML.ns;"> Document Title

    Document Title

    Chapter Title

    Section Title

    This is a test.

    NOTE: This is a note.

    Another Section Title

    This is another test.

    NOTE: This is another note.

    ]]>
    Data Example

    This is an example of transforming some data represented in XML using three different XSLT stylesheets to produce three different representations of the data, HTML, SVG and VRML.

    The input data is:

    10 9 7 4 3 4 6 -1.5 2 ]]>

    The following stylesheet, which uses the simplified syntax described in , transforms the data into HTML:

    <html xsl:version="1.0" xmlns:xsl="&XSLT.ns;" Sales Results By Division
    Division Revenue Growth Bonus
    color:red
    ]]>

    The HTML output is:

    Sales Results By Division
    DivisionRevenueGrowthBonus
    North1097
    West6-1.52
    South434
    ]]>

    The following stylesheet transforms the data into SVG:

    <xsl:stylesheet version="1.0" xmlns:xsl="&XSLT.ns;" Revenue Division ]]>

    The SVG output is:

    Revenue Division North 10 South 4 West 6 ]]>

    The following stylesheet transforms the data into VRML:

    <xsl:stylesheet version="1.0" xmlns:xsl="&XSLT.ns;"> #VRML V2.0 utf8 # externproto definition of a single bar element EXTERNPROTO bar [ field SFInt32 x field SFInt32 y field SFInt32 z field SFString name ] "http://www.vrml.org/WorkingGroups/dbwork/barProto.wrl" # inline containing the graph axes Inline { url "http://www.vrml.org/WorkingGroups/dbwork/barAxes.wrl" } bar { x y z name "" } ]]>

    The VRML output is:

    Acknowledgements

    The following have contributed to authoring this draft:

    Daniel Lipkin, Saba Jonathan Marsh, Microsoft Henry Thompson, University of Edinburgh Norman Walsh, Arbortext Steve Zilles, Adobe

    This specification was developed and approved for publication by the W3C XSL Working Group (WG). WG approval of this specification does not necessarily imply that all WG members voted for its approval. The current members of the XSL WG are:

    Sharon Adler IBM Co-Chair Anders Berglund IBM Perin Blanchard Novell Scott Boag Lotus Larry Cable Sun Jeff Caruso Bitstream James Clark Peter Danielsen Bell Labs Don Day IBM Stephen Deach Adobe Dwayne Dicks SoftQuad Andrew Greene Bitstream Paul Grosso Arbortext Eduardo Gutentag Sun Juliane Harbarth Software AG Mickey Kimchi Enigma Chris Lilley W3C Chris Maden Exemplary Technologies Jonathan Marsh Microsoft Alex Milowski Lexica Steve Muench Oracle Scott Parnell Xerox Vincent Quint W3C Dan Rapp Novell Gregg Reynolds Datalogics Jonathan Robie Software AG Mark Scardina Oracle Henry Thompson University of Edinburgh Philip Wadler Bell Labs Norman Walsh Arbortext Sanjiva Weerawarana IBM Steve Zilles Adobe Co-Chair
    Changes from Proposed Recommendation

    The following are the changes since the Proposed Recommendation:

    The xsl:version attribute is required on a literal result element used as a stylesheet (see ).

    The data-type attribute on xsl:sort can use a prefixed name to specify a data-type not defined by XSLT (see ).

    Features under Consideration for Future Versions of XSLT

    The following features are under consideration for versions of XSLT after XSLT 1.0:

    a conditional expression;

    support for XML Schema datatypes and archetypes;

    support for something like style rules in the original XSL submission;

    an attribute to control the default namespace for names occurring in XSLT attributes;

    support for entity references;

    support for DTDs in the data model;

    support for notations in the data model;

    a way to get back from an element to the elements that reference it (e.g. by IDREF attributes);

    an easier way to get an ID or key in another document;

    support for regular expressions for matching against any or all of text nodes, attribute values, attribute names, element type names;

    case-insensitive comparisons;

    normalization of strings before comparison, for example for compatibility characters;

    a function string resolve(node-set) function that treats the value of the argument as a relative URI and turns it into an absolute URI using the base URI of the node;

    multiple result documents;

    defaulting the select attribute on xsl:value-of to the current node;

    an attribute on xsl:attribute to control how the attribute value is normalized;

    additional attributes on xsl:sort to provide further control over sorting, such as relative order of scripts;

    a way to put the text of a resource identified by a URI into the result tree;

    allow unions in steps (e.g. foo/(bar|baz));

    allow for result tree fragments all operations that are allowed for node-sets;

    a way to group together consecutive nodes having duplicate subelements or attributes;

    features to make handling of the HTML style attribute more convenient.

    tdom-0.9.6-src/tests/data/dtd-6.5.dtd0000644000175000017500000000013715025767703015612 0ustar rolfrolf ]]> tdom-0.9.6-src/tests/domNode.test0000644000175000017500000034743615025767703015431 0ustar rolfrolf# Features covered: domNode command and nodeObj commands # # This file contains a collection of tests for the two interfaces to # DOM nodes, the token interface (the domNode command) and the tcl # command interface ([$nodeObj method ...]). # # domNode-1.*: domNode command syntax # domNode-2.*: selectNodes # domNode-3.*: documentElement # domNode-4.*: setAttributeNS # domNode-5.*: removeChild # domNode-6.*: appendChild # domNode-7.*: getElementsByTagName # domNode-8.*: getElementsByTagNameNS # domNode-9.*: nodeValue # domNode-10.*: setAttribute, again setAttributeNS # domNode-11.*: disableOutputEscaping # domNode-12.*: cloneNode # domNode-13.*: appendFromScript # domNode-14.*: appendFromList # domNode-15.*: delete # domNode-16.*: getAttribute # domNode-17.*: nodeType # domNode-18.*: attributes, attributeNames # domNode-19.*: removeAttribute, removeAttributeNS # domNode-20.*: parentNode # domNode-21.*: hasChildNodes # domNode-22.*: localName, prefix # domNode-23.*: replaceChild # domNode-24.*: getLine, getColumn, getByteIndex # domNode-25.*: hasAttribute, hasAttributeNS # domNode-26.*: appendXML # domNode-27.*: target, data # domNode-28.*: getAttributeNS # domNode-29.*: ownerDocument # domNode-30.*: precedes # domNode-31.*: insertBefore # domNode-32.*: asText # domNode-33.*: insertBeforeFromScript # domNode-34.*: getBaseURI # domNode-35.*: objCmd traces # domNode-36.*: nodeName # domNode-37.*: baseURI # domNode-38.*: toXPath # domNode-39.*: text # domNode-999.* Misc Tests # # Copyright (c) 2002 - 2005 Rolf Ade. # # RCS: @(#) $Id$ source [file join [file dir [info script]] loadtdom.tcl] if {[join [lrange [split [package present Tcl] .] 0 1] .] <= 8.4} { testConstraint threaded [info exists tcl_platform(threaded)] } else { testConstraint threaded [expr {[info exists tcl_platform(threaded)] || [package vsatisfies [package present Tcl] 9.0-]}] } test domNode-1.1 {too less arguments to nodecmd} { set doc [dom createDocument "root"] set root [$doc documentElement] set result [catch {$root}] $doc delete set result } {1} test domNode-1.2 {too less arguments to domNode token} { set doc [dom createDocument "root"] set root [$doc documentElement] set result [catch {domNode $root}] $doc delete set result } {1} test domNode-1.3 {too less arguments to domNode command} { catch {domNode} } {1} test domNode-1.4 {rename of domNodeObj cmd} {knownBug} { set doc [dom createDocument "root"] set root [$doc documentElement] rename $root my_domNode set result [llength [info commands my_domNode]] $doc delete lappend result [llength [info commands my_domNode]] catch {my_domNode nodeName} errMsg lappend result $errMsg } {1 0} test domNode-1.5 {domNode command: invalid token} { set xml {12} set doc [dom parse $xml] set root [domDoc $doc documentElement] set invalidToken [domNode $root firstChild] lappend invalidToken foo set result [catch {domNode $invalidToken selectNodes string(.)}] $doc delete set result } {1} test domNode-1.6 {domNode command: invalid token} { set xml {12} set doc [dom parse $xml] set root [domDoc $doc documentElement] set invalidToken [domNode $root firstChild] append invalidToken "\n" set result [catch {domNode $invalidToken selectNodes string(.)}] $doc delete set result } {1} proc domNode-1.7-traceproc {args} { error "error in nodeObjVar trace" } test domNode-1.7 {error in trace on nodeObjVar} { set xml {12} set doc [dom parse $xml] set root [$doc documentElement] trace add variable resultVar write domNode-1.7-traceproc set result [catch {$root firstChild resultVar} errMsg] lappend result $errMsg trace remove variable resultVar write domNode-1.7-traceproc $doc delete set result } {1 {can't set "resultVar": error in nodeObjVar trace}} test domNode-1.8 {cmd argument parsing} { set result [catch {domNode} errMsg] lappend result $errMsg catch {domNode foo} errMsg lappend result $errMsg } {1 {wrong # args: should be "domNode nodetoken subcommand ?arg ...?"} {wrong # args: should be "domNode nodetoken subcommand ?arg ...?"}} test domNode-1.9 {cmd argument parsing} { set storedMode [dom setObjectCommands] dom setObjectCommands token set doc [dom parse {}] set root [domDoc $doc documentElement] catch {domNode $root} result domDoc $doc delete dom setObjectCommands $storedMode set result } {wrong # args: should be "domNode nodetoken subcommand ?arg ...?"} test domNode-1.10 {cmd argument parsing} -body { set doc [dom parse {}] set root [$doc documentElement] catch {$root} result $doc delete set result } -match regexp -result {wrong # args: should be "domNode[^ ]+ subcommand \?arg ...\?"} test domNode-1.11 {cmd argument parsing} -body { set storedMode [dom setObjectCommands] dom setObjectCommands token set doc [dom parse {}] set root [domDoc $doc documentElement] catch {domNode $root invalid-method} result domDoc $doc delete dom setObjectCommands $storedMode set result } -match glob -result {bad method "invalid-method": must be *} test domNode-1.12 {cmd argument parsing} -body { set doc [dom parse {}] set root [$doc documentElement] catch {$root invalid-method} result $doc delete set result } -match glob -result {bad method "invalid-method": must be *} set doc [dom parse { }] set root [$doc documentElement] test domNode-2.1 {selectNodes - -namespace option: syntax} { set result [catch {$root selectNodes -namespaces elem1ns:elem1} errMsg] lappend result $errMsg } {1 {The "-namespaces" option requires a 'prefix namespace' pairs list as argument}} test domNode-2.2 {selectNodes - -namespace option} { set result [$root selectNodes -namespaces {} elem1] } {} test domNode-2.3 {selectNodes - -namespaces option} { set node [$root selectNodes -namespaces {my elem1NS} my:elem1] set result [list] lappend result [$node localName] [$node namespaceURI] } {elem1 elem1NS} test domNode-2.4 {selectNodes - -namespaces option} { set node [$root selectNodes -namespaces {my elem1NS my elem2NS} my:*] set result [list] lappend result [$node localName] [$node namespaceURI] } {elem1 elem1NS} test domNode-2.5 {selectNodes - -namespaces option} { set nsDef [list this elem2NS same elem2NS] set node [$root selectNodes -namespaces $nsDef {this:*|same:*}] set result [llength $node] lappend result [$node localName] [$node namespaceURI] } {1 elem2 elem2NS} test domNode-2.6 {selectNodes - -namespaces option} { set nsDef1 [list foo elem2NS bar elem2NS] set nsDef2 [list this elem2NS same elem2NS] set node [$root selectNodes -namespaces $nsDef1 \ -namespaces $nsDef2 {this:*|same:*}] set result [llength $node] lappend result [$node localName] [$node namespaceURI] } {1 elem2 elem2NS} test domNode-2.7 {selectNodes - -namespaces option} { set result [catch {$root selectNodes -namespaces elem1ns:elem1 typevar} errMsg] lappend result $errMsg } {1 {The "-namespaces" option requires a 'prefix namespace' pairs list as argument}} test domNode-2.8 {selectNodes - -namespaces option} { set nsDef1 [list foo elem2NS bar elem2NS] set nsDef2 [list this elem2NS same elem2NS] set node [$root selectNodes -namespaces $nsDef1 \ -namespaces $nsDef2 {this:*|same:*} typevar] set result [llength $node] lappend result [$node localName] [$node namespaceURI] $typevar } {1 elem2 elem2NS nodes} $doc delete set doc [dom parse { }] $doc documentElement root test domNode-2.9 {selectNodes - -cache option} { set result [catch {$root selectNodes -cache child} errMsg] lappend result $errMsg } {1 {expected boolean value but got "child"}} test domNode-2.10 {selectNodes - -cache option} { for {set x 0} {$x < 5} {incr x} { set nodes [$root selectNodes -cache 1 {child[2]}] } for {set x 0} {$x < 5} {incr x} { set otherNodes [$root selectNodes -cache 0 {child[2]}] } string equal $nodes $otherNodes } {1} test domNode-2.11 {selectNodes - -cache option} { set r1 [catch {$root selectNodes}] set r2 [catch {$root selectNodes -cache 1}] set r3 [catch {$root selectNodes -cache 0}] set r4 [catch {$root selectNodes ""}] set r5 [catch {$root selectNodes -cache 1 ""}] set r6 [catch {$root selectNodes -cache 0 ""}] list $r1 $r2 $r3 $r4 $r5 $r6 } {1 1 1 1 1 1} test domNode-2.12 {selectNodes - -cache option} { # Second usage of an invalid XPath expr with -cache 1 # See 97c0994ae4 catch {$root selectNodes -cache 1 "/foo bar"} catch {$root selectNodes -cache 1 "/foo bar"} } 1 $doc delete test domNode-2.13 {selectNodes - -cache option with invalid value} { set doc [dom parse {

    foo

    }] set root [$doc documentElement] set result [catch {$root selectNodes \ -namespaces {xhtml http://www.w3.org/1999/xhtml} \ -cache nonboolean \ string(xhtml:body/xhtml:p)}] $doc delete set result } 1 test domNode-2.14 {selectNodes -namespaces and -list with invalid xpath list} { set doc [dom parse {

    foo

    }] set root [$doc documentElement] set result [catch {$root selectNodes \ -namespaces {xhtml http://www.w3.org/1999/xhtml} \ -list \ "\{xhtml:body string(xhtml:p)"}] $doc delete set result } 1 test domNode-2.15 {selectNodes -namespaces and -list with empty xpaths list} { set doc [dom parse {

    foo

    }] set root [$doc documentElement] set result [$root selectNodes \ -namespaces {xhtml http://www.w3.org/1999/xhtml} \ -list \ {}] $doc delete set result } "" test domNode-2.16 {selectNodes -namespaces and -list} { set doc [dom parse {

    foo

    }] set root [$doc documentElement] set result [$root selectNodes \ -namespaces {xhtml http://www.w3.org/1999/xhtml} \ -list \ {xhtml:body string(xhtml:p)}] $doc delete set result } foo test domNode-2.17 {selectNodes -namespaces and -list with first XPath expr invalid} { set doc [dom parse {

    foo

    }] set root [$doc documentElement] set result [catch {$root selectNodes \ -namespaces {xhtml http://www.w3.org/1999/xhtml} \ -list \ {xhtml::body string(xhtml:p)}}] $doc delete set result } 1 test domNode-2.18 {selectNodes -namespaces and -list with second XPath expr invalid} { set doc [dom parse {

    foo

    }] set root [$doc documentElement] set result [catch {$root selectNodes \ -namespaces {xhtml http://www.w3.org/1999/xhtml} \ -list \ {xhtml:body string(xhtml:p}}] $doc delete set result } 1 test domNode-3.1 {repetitived documentElement with objVar, then delete} { dom createDocument "root" doc $doc documentElement root $doc delete dom createDocument "\u00c4\u00d4\u00dc" doc $doc documentElement root set result [$root nodeName] $doc delete set result } "\u00c4\u00d4\u00dc" test domNode-3.2 {repetitived documentElement, then delete} { set doc [dom createDocument "root"] $doc documentElement root $doc delete set doc [dom createDocument "\u00c4\u00d4\u00dc"] $doc documentElement root set result [$root nodeName] $doc delete set result } "\u00c4\u00d4\u00dc" test domNode-3.3 {repetitived documentElement, then delete} { set doc [dom createDocument "root"] set root [$doc documentElement] $doc delete set doc [dom createDocument "\u00c4\u00d4\u00dc"] set root [$doc documentElement] set result [$root nodeName] $doc delete set result } "\u00c4\u00d4\u00dc" test domNode-4.1 {create nodes with same prefix, different uri's} { dom createDocumentNS "uri1" "p:a" doc set root [$doc documentElement] set node1 [$doc createElementNS "uri2" "p:b"] $root appendChild $node1 set node2 [$doc createElementNS "uri1" "p:c"] $node1 appendChild $node2 set result [$root asXML] $doc delete set result } { } test domNode-4.3 {setAttribute} { dom createDocumentNS "uri1" "p:root" doc set root [$doc documentElement] $root setAttribute attr1 attr1Value set result [$root asXML] $doc delete set result } { } test domNode-4.5 {setAttributeNS} { dom createDocument "root" doc set root [$doc documentElement] $root setAttributeNS "" xmlns:p uri $root setAttributeNS uri p:attr attrValue set result [$root asXML] $doc delete set result } { } test domNode-4.6 {setAttributeNS} { dom createDocument "root" doc set root [$doc documentElement] $root setAttributeNS uri p:attr attrValue $root setAttributeNS "" xmlns:p uri set result [$root asXML] $doc delete set result } { } test domNode-4.7 {setAttributeNS} { dom createDocument "root" doc set root [$doc documentElement] $root setAttributeNS uri p:attr1 attrValue set result [$root getAttributeNS uri attr1] $doc delete set result } {attrValue} test domNode-4.8 {setAttributeNS} { dom createDocument "root" doc set root [$doc documentElement] $root setAttributeNS "" xmlns:p uri $root setAttributeNS uri p:attr1 attrValue set result [$root getAttributeNS uri attr1] $doc delete set result } {attrValue} test domNode-4.9 {setAttributeNS} { dom createDocument "root" doc set root [$doc documentElement] $root setAttributeNS uri p:attr1 attrValue set result [$root attributes *] $doc delete set result } {{attr1 p uri}} test domNode-4.10 {setAttributeNS} { dom createDocument "root" doc set root [$doc documentElement] set result [catch {$root setAttributeNS {} p:attr1 attrValue}] $doc delete set result } {1} test domNode-4.11 {setAttributeNS} { dom createDocument "root" doc set root [$doc documentElement] set result [catch {$root setAttributeNS uri attr1 attrValue}] $doc delete set result } {1} test domNode-4.12 {setAttributeNS - special prefix "xml"} { dom createDocument "root" doc set root [$doc documentElement] $root setAttributeNS "" xml:attr1 attrValue set result [$root attributes *] $doc delete set result } {{attr1 xml http://www.w3.org/XML/1998/namespace}} test domNode-4.13 {setAttributeNS} { dom createDocument "root" doc set root [$doc documentElement] $root setAttributeNS uri p:attr1 attrValue $root setAttributeNS uri o:attr1 newValue set result [$root attributes *] $doc delete set result } {{attr1 p uri}} test domNode-4.14 {setAttributeNS} { dom createDocument "root" doc set root [$doc documentElement] $root setAttributeNS uri p:attr1 attrValue $root setAttributeNS uri o:attr1 newValue set result [$root getAttributeNS uri attr1] $doc delete set result } {newValue} test domNode-4.15 {setAttributeNS - use as setAttribute} { dom createDocument "root" doc set root [$doc documentElement] $root setAttributeNS "" attr1 attrValue set result [$root attributes *] $doc delete set result } {attr1} test domNode-4.16 {setAttributeNS - set multiple Attributes at once} { set doc [dom createDocumentNS uri1 "p1:root"] set root [$doc documentElement] $root setAttributeNS "" xmlns:p2 uri2 $root setAttributeNS uri1 p1:a1 1 uri1 p1:a2 2 uri2 p2:a3 3 "" a4 4 set result [$root asXML] $doc delete set result } { } test domNode-4.17 {setAttributeNS - set multiple Attribute with NS atts undermixed at once} { set doc [dom createDocumentNS uri1 "p1:root"] set root [$doc documentElement] $root setAttributeNS "" xmlns:p2 uri2 $root setAttributeNS uri1 p1:a1 1 "" xmlns uri3 uri1 p1:a2 2 "" xmlns:p4 uri4 uri4 p4:a1 a1 uri2 p2:a3 3 "" a4 4 set result [$root asXML] $doc delete set result } { } test domNode-4.18 {setAttributeNS - prefixed attribute name with empty namespace} { set doc [dom createDocument "root"] set root [$doc documentElement] catch {$root setAttributeNS "" ns:att attvalue} errMsg $doc delete set errMsg } {For all prefixed attributes with prefixes other than 'xml' or 'xmlns' you have to provide a namespace URI} test domNode-5.1 {removeChild} { dom parse {} doc $doc documentElement root $root removeChild [$root firstChild] set result [$doc asXML -indent none] $doc delete set result } {} test domNode-5.2 {removeChild - child to remove is not a child of node} { dom parse {} doc $doc documentElement root set one [$root firstChild] set two [$root lastChild] set result [catch {$one removeChild $two} errMsg] lappend result $errMsg $doc delete set result } {1 NOT_FOUND_ERR} test domNode-5.3 {removeChild - child to remove is not a child of node} { dom parse {} doc $doc documentElement root set newNode [$doc createElement new] set result [catch {$root removeChild $newNode} errMsg] lappend result $errMsg $doc delete set result } {1 NOT_FOUND_ERR} test domNode-6.1 {appendChild insert FQ Element} { set doc [dom parse {}] set root [$doc documentElement] set newNode [$doc createElementNS uri2 p:foo] $root appendChild $newNode set result [$root asXML] $doc delete set result } { } test domNode-6.2 {appendChild} { set doc [dom createDocument XMI] set root [$doc documentElement] set A1tag [$doc createElement "A1"] set A2subtag [$doc createElement "A2sub"] set A2tag [$doc createElement "A2"] $A2tag appendChild $A2subtag set Atag [$doc createElement "A"] $Atag appendChild $A1tag $Atag appendChild $A2tag set Btag [$doc createElement "B"] $Btag appendChild $Atag set Ctag [$doc createElement "C"] set result 0 if {$root == "[$doc documentElement]"} {set result 1} $doc delete set result } {1} test domNode-6.3 {appendChild} { dom parse {} doc $doc documentElement root $root appendChild [$root firstChild] set result [$doc asXML -indent none] $doc delete set result } {} test domNode-6.4 {appendChild} { dom parse {} doc $doc documentElement root $root appendChild [$root lastChild] set result [$doc asXML -indent none] $doc delete set result } {} test domNode-6.5 {appendChild} { dom parse {} doc $doc documentElement root $root appendChild [lindex [$root childNodes] 1] set result [$doc asXML -indent none] $doc delete set result } {} test domNode-6.6 {appendChild} { dom parse {} doc $doc documentElement root set node [$root appendChild [$root firstChild]] catch {unset result} lappend result [[$node parentNode] nodeName] while {$node != ""} { lappend result [$node nodeName] set node [$node previousSibling] } $doc delete set result } {root one three two} test domNode-6.7 {appendChild} { dom parse {} doc $doc documentElement root set node [$root appendChild [$root lastChild]] catch {unset result} lappend result [[$node parentNode] nodeName] while {$node != ""} { lappend result [$node nodeName] set node [$node previousSibling] } $doc delete set result } {root three two one} test domNode-6.8 {appendChild} { dom parse {} doc $doc documentElement root set node [$root appendChild [lindex [$root childNodes] 1]] catch {unset result} lappend result [[$node parentNode] nodeName] while {$node != ""} { lappend result [$node nodeName] set node [$node previousSibling] } $doc delete set result } {root two three one} test domNode-6.9 {appendChild} { dom parse {} doc $doc documentElement root $root appendChild [$root firstChild] catch {unset result} set node [$root firstChild] while {$node != ""} { lappend result [$node nodeName] set node [$node nextSibling] } $doc delete set result } {two three one} test domNode-6.10 {appendChild} { dom parse {} doc $doc documentElement root $root appendChild [$root lastChild] catch {unset result} set node [$root firstChild] while {$node != ""} { lappend result [$node nodeName] set node [$node nextSibling] } $doc delete set result } {one two three} test domNode-6.11 {appendChild} { dom parse {} doc $doc documentElement root $root appendChild [lindex [$root childNodes] 1] catch {unset result} set node [$root firstChild] while {$node != ""} { lappend result [$node nodeName] set node [$node nextSibling] } $doc delete set result } {one three two} test domNode-6.12 {appendChild} { dom parse {} doc $doc documentElement root set one [$root firstChild] $one appendChild [$root lastChild] set result [$doc asXML -indent none] $doc delete set result } {} test domNode-6.13 {appendChild} { dom parse {} doc $doc documentElement root set one [$root firstChild] set result [catch {$one appendChild $root} errMsg] lappend result $errMsg $doc delete set result } {1 HIERARCHY_REQUEST_ERR} test domNode-6.14 {appendChild} { dom parse {} doc $doc documentElement root set one [$root firstChild] set result [catch {$one appendChild $one} errMsg] lappend result $errMsg $doc delete set result } {1 HIERARCHY_REQUEST_ERR} test domNode-6.15 {appendChild} -setup { set fileList {} foreach {name content} { a "..." b "..." } { lappend fileList [makeFile $content $name] } } -body { set docs {} foreach rf $fileList { set doc [dom parse -baseurl [tdom::baseURL $rf] \ -externalentitycommand ::tdom::extRefHandler \ -keepEmpties \ [tdom::xmlReadFile $rf] ] lappend docs $doc } set resultDoc [dom createDocument new_report] set root [$resultDoc documentElement] foreach doc $docs { $root appendChild [$doc documentElement] } set result [$resultDoc asXML -indent none] foreach doc $docs { $doc delete } $resultDoc delete set result } -cleanup { removeFile a removeFile b } -result {......} test domNode-6.16 {appendChild} -setup { dom parse {} doc1 $doc1 documentElement root1 dom parse {} doc2 $doc2 documentElement root2 } -body { $root1 appendChild [$root2 cloneNode -deep] $root1 asXML -indent none } -cleanup { $doc1 delete $doc2 delete } -result {} test domNode-6.17 {appendChild} -setup { dom parse {} doc1 $doc1 documentElement root1 dom parse {} doc2 $doc2 documentElement root2 } -body { $root1 appendChild [$root2 cloneNode -deep] $root1 asXML -indent none } -cleanup { $doc1 delete $doc2 delete } -result {} set doc [dom parse {}] set root [$doc documentElement] test domNode-7.1 {getElementsByTagName - doc method} { llength [$doc getElementsByTagName a] } {2} test domNode-7.2 {getElementsByTagName - doc method} { llength [$doc getElementsByTagName c] } {1} test domNode-7.3 {getElementsByTagName - doc method} { llength [$doc getElementsByTagName foo] } {0} test domNode-7.4 {getElementsByTagName - node method} { llength [$root getElementsByTagName a] } {2} test domNode-7.5 {getElementsByTagName - node method} { llength [$root getElementsByTagName c] } {1} test domNode-7.6 {getElementsByTagName - node method} { llength [$root getElementsByTagName foo] } {0} test domNode-7.7 {getElementsByTagName - node method '*' wildcard} { llength [$root getElementsByTagName *] } {7} test domNode-7.8 {getElementsByTagName - doc method '*' wildcard} { llength [$doc getElementsByTagName *] } {8} test domNode-7.9 {getElementsByTagName - node method tcl glob style} { llength [$root getElementsByTagName foo*] } {2} test domNode-7.9 {getElementsByTagName - node method tcl glob style} { llength [$root getElementsByTagName *oo*] } {3} test domNode-7.10 {getElementsByTagName - doc method tcl glob style} { llength [$doc getElementsByTagName foo*] } {2} test domNode-7.11 {getElementsByTagName - doc method tcl glob style} { llength [$doc getElementsByTagName *oo*] } {4} test domNode-7.12 {getElementsByTagName - doc method empty result} { $doc getElementsByTagName noSuchANodeName } {} test domNode-7.13 {getElementsByTagName - node method empty result} { $root getElementsByTagName noSuchANodeName } {} test domNode-7.14 {getElementsByTagName - doc method: doc order of result} { set nodes [$doc getElementsByTagName *] set result "" foreach node $nodes { append result "[$node nodeName] " } set result } {root foobar barfoo foobaz a b a c } test domNode-7.15 {getElementsByTagName - node method: doc order of result} { set nodes [$root getElementsByTagName *] set result "" foreach node $nodes { append result "[$node nodeName] " } set result } {foobar barfoo foobaz a b a c } $doc delete set doc [dom parse { mixed content important more content again important }] set root [$doc documentElement] test domNode-7.16 {getElementsByTagName - node method mixed content} { llength [$doc getElementsByTagName elem] } {1} test domNode-7.17 {getElementsByTagName - node method mixed content} { llength [$root getElementsByTagName elem] } {1} test domNode-7.18 {getElementsByTagName - doc method mixed content} { llength [$doc getElementsByTagName b] } {3} test domNode-7.19 {getElementsByTagName - node method mixed content} { llength [$root getElementsByTagName b] } {3} test domNode-7.20 {getElementsByTagName - not a element node} { set textnode [$root selectNodes {descendant::text()[1]}] catch {$textnode getElementsByTagName b} errMsg set errMsg } {Node must be an element node.} $doc delete set doc [dom parse { IBM }] set root [$doc documentElement] test domNode-8.1 {getElementsByTagNameNS - root method} { [$root getElementsByTagNameNS "http://www.stock.org/stock" GetStockPrice] nodeName } {m:GetStockPrice} test domNode-8.2 {getElementsByTagNameNS - root method} { [$root getElementsByTagNameNS "*" GetStockPrice] nodeName } {m:GetStockPrice} test domNode-8.3 {getElementsByTagNameNS - root method} { llength [$root getElementsByTagNameNS "http://www.stock.org/stock" *] } {2} test domNode-8.4 {getElementsByTagNameNS - doc method} { [$doc getElementsByTagNameNS "http://www.stock.org/stock" GetStockPrice] nodeName } {m:GetStockPrice} test domNode-8.5 {getElementsByTagNameNS - doc method} { [$doc getElementsByTagNameNS "*" GetStockPrice] nodeName } {m:GetStockPrice} test domNode-8.6 {getElementsByTagNameNS - doc method} { llength [$doc getElementsByTagNameNS "http://www.stock.org/stock" *] } {2} $doc delete set doc [dom parse { mixed content important more content again important }] set root [$doc documentElement] test domNode-8.7 {getElementsByTagNameNS - doc method pathologic XML} { llength [$doc getElementsByTagNameNS "firstp" pathologic] } {2} test domNode-8.8 {getElementsByTagNameNS - doc method pathologic XML} { llength [$doc getElementsByTagNameNS "secondp" pathologic] } {1} test domNode-8.9 {getElementsByTagNameNS - doc method pathologic XML} { llength [$doc getElementsByTagNameNS "*" pathologic] } {3} test domNode-8.10 {getElementsByTagNameNS - node method pathologic XML} { llength [$root getElementsByTagNameNS "firstp" pathologic] } {2} test domNode-8.11 {getElementsByTagNameNS - node method pathologic XML} { llength [$root getElementsByTagNameNS "secondp" pathologic] } {1} test domNode-8.12 {getElementsByTagNameNS - node method pathologic XML} { llength [$root getElementsByTagNameNS "*" pathologic] } {3} test domNode-8.13 {getElementsByTagNameNS - doc method} { llength [$doc getElementsByTagNameNS "NS1" elem] } {1} test domNode-8.14 {getElementsByTagNameNS - doc method} { llength [$doc getElementsByTagNameNS "NS2" elem] } {1} test domNode-8.15 {getElementsByTagNameNS - doc method} { llength [$doc getElementsByTagNameNS "*" elem] } {3} test domNode-8.16 {getElementsByTagNameNS - node method} { llength [$root getElementsByTagNameNS "NS1" elem] } {1} test domNode-8.17 {getElementsByTagNameNS - node method} { llength [$root getElementsByTagNameNS "NS2" elem] } {1} test domNode-8.18 {getElementsByTagNameNS - node method} { llength [$root getElementsByTagNameNS "*" elem] } {3} test domNode-8.19 {getElementsByTagNameNS - doc method empty namespace} { set nodes [$doc getElementsByTagNameNS "" *] set result "" foreach node $nodes { append result "[$node nodeName] " } set result } {root elem b b } test domNode-8.19 {getElementsByTagNameNS - node method empty namespace} { set nodes [$root getElementsByTagNameNS "" *] set result "" foreach node $nodes { append result "[$node nodeName] " } set result } {elem b b } test domNode-8.20 {getElementsByTagNameNS - not a element node} { set textnode [$root selectNodes {descendant::text()[1]}] catch {$textnode getElementsByTagName b} errMsg set errMsg } {Node must be an element node.} $doc delete set doc [dom parse { }] set root [$doc documentElement] test domNode-8.21 {getElementsByTagNameNS - unset default NS} { set nodes [$root getElementsByTagNameNS "" *] set result "" foreach node $nodes { append result "[$node nodeName] " } set result } {elem1 elem3 } test domNode-8.22 {getElementsByTagName - unset default NS} { set nodes [$root getElementsByTagName *] set result "" foreach node $nodes { append result "[$node nodeName] " } set result } {elem1 elem2 elem3 } test domNode-8.23 {getElementsByTagNameNS - unset default NS} { set nodes [$root getElementsByTagNameNS * *] set result "" foreach node $nodes { append result "[$node nodeName] " } set result } {elem1 elem2 elem3 } test domNode-8.24 {getElementsByTagNameNS - unset default NS} { set nodes [$doc getElementsByTagNameNS * *] set result "" foreach node $nodes { append result "[$node nodeName] " } set result } {root elem1 elem2 elem3 } test domNode-8.25 {getElementsByTagNameNS - unset default NS} { set nodes [$root getElementsByTagNameNS "" *] set result "" foreach node $nodes { append result "[$node nodeName] " } set result } {elem1 elem3 } test domNode-8.26 {getElementsByTagNameNS - unset default NS} { set nodes [$doc getElementsByTagNameNS "" *] set result "" foreach node $nodes { append result "[$node nodeName] " } set result } {elem1 elem3 } $doc delete set doc [dom parse { text node}] set root [$doc documentElement] test domNode-9.1 {nodeValue - TEXT_NODE} { [$root firstChild] nodeValue } {text node} test domNode-9.2 {nodeValue - COMMENT_NODE} { set firstChild [$root firstChild] set commentNode [$firstChild nextSibling] $commentNode nodeValue } {comment node} test domNode-9.3 {nodeValue - PROCESSING_INSTRUCTION_NODE} { [$root lastChild] nodeValue } {PI node} test domNode-9.4 {nodeValue - CDATA_SECTION_NODE} { set cdNode [$doc createCDATASection "cdata section node"] $root appendChild $cdNode [$root lastChild] nodeValue } {cdata section node} test domNode-9.5 {nodeValue with set - TEXT_NODE} { set result [[$root firstChild] nodeValue "new text value"] append result "/" [[$root firstChild] nodeValue] } {text node/new text value} test domNode-9.6 {nodeValue with set - COMMENT_NODE} { set textNode [$root firstChild] set node [$textNode nextSibling] set result [$node nodeValue "new comment text"] append result "/" [$commentNode nodeValue] } {comment node/new comment text} test domNode-9.7 {nodeValue - PROCESSING_INSTRUCTION_NODE does not allow setting} { set piNode [$root selectNodes processing-instruction('mytarget')] catch {$piNode nodeValue "new pi value"} } {1} test domNode-9.8 {nodeValue - CDATA_SECTION_NODE} { set result [[$root lastChild] nodeValue "new text"] append result "/" [[$root lastChild] nodeValue] } {cdata section node/new text} $doc delete test domNode-9.9 {nodeValue - invalid new value} { set doc [dom parse text] $doc documentElement root set result [catch {[$root firstChild] nodeValue "ab\u0003\u0003cd"} \ errMsg] $doc delete lappend result $errMsg } [list 1 "Invalid text value 'ab\u0003\u0003cd'"] set doc [dom parse ] set root [$doc documentElement] test domNode-10.1 {setAttribute - set multiple attributes at once} { $root setAttribute a1 1 a2 2 a3 3 a4 4 a5 5 a6 6 a7 7 a8 8 $root asXML -indent none } {} $doc delete set doc [dom parse {&}] set root [$doc documentElement] set textnode [$root firstChild] test domNode-11.1 {disableOutputEscaping} { $textnode disableOutputEscaping } {0} test domNode-11.2 {disableOutputEscaping} { $textnode disableOutputEscaping 1 } {0} test domNode-11.3 {disableOutputEscaping} { $textnode disableOutputEscaping } {1} test domNode-11.4 {disableOutputEscaping} { $root asXML -indent none } {&} $doc delete test domNode-11.5 {disableOutputEscaping} { set doc [dom createDocument root] set textnode [$doc createTextNode "

    some important text

    "] $textnode disableOutputEscaping 1 set root [$doc documentElement] $root appendChild $textnode set result [$root asXML -indent none] $doc delete set result } {

    some important text

    } test domNode-11.6 {disableOutputEscaping} { set doc [dom createDocument root] set textnode [$doc createTextNode "

    some important text

    "] $textnode disableOutputEscaping 1 set root [$doc documentElement] $root appendChild $textnode set textnode [$doc createTextNode "&"] $root appendChild $textnode set result [$root asXML -indent none] $doc delete set result } {

    some important text

    &
    } test domNode-11.7 {disableOutputEscaping} { set doc [dom createDocument root] set root [$doc documentElement] set textnode [$doc createTextNode "&"] $root appendChild $textnode set textnode [$doc createTextNode "

    some important text

    "] $textnode disableOutputEscaping 1 $root appendChild $textnode set result [$root asXML -indent none] $doc delete set result } {&

    some important text

    } test domNode-12.1 {cloneNode} { set doc [dom parse {}] set root [$doc documentElement] set newNode [$root cloneNode] $root appendChild $newNode set result [$root asXML -indent none] $doc delete set result } {} test domNode-12.2 {cloneNode} { set doc [dom parse {text}] set root [$doc documentElement] set newNode [$root cloneNode] $root appendChild $newNode set result [$root asXML -indent none] $doc delete set result } {text} test domNode-12.3 {cloneNode} { set doc [dom parse {text}] set root [$doc documentElement] set newNode [[$root firstChild] cloneNode] $root appendChild $newNode set result [$root asXML -indent none] $doc delete set result } {text} test domNode-12.4 {cloneNode} { set doc [dom parse {text}] set root [$doc documentElement] set newNode [[$root selectNodes {node()[2]}] cloneNode] $root appendChild $newNode set result [$root asXML -indent none] $doc delete set result } {texttext} test domNode-12.5 {cloneNode} { set doc [dom parse {text}] set root [$doc documentElement] set newNode [[$root selectNodes {node()[3]}] cloneNode] $root appendChild $newNode set result [$root asXML -indent none] $doc delete set result } {text} test domNode-12.5 {cloneNode} { set doc [dom parse {text}] set root [$doc documentElement] set newNode [[$root lastChild] cloneNode] $root appendChild $newNode set result [$root asXML -indent none] $doc delete set result } {text} test domNode-12.6 {cloneNode -deep} { set doc [dom parse {
    text}] set root [$doc documentElement] set result [[[$root firstChild] cloneNode -deep] asXML -indent none] $doc delete set result } {text} test domNode-12.7 {cloneNode -deep} { set doc [dom parse {text}] set root [$doc documentElement] $root appendChild [[$root firstChild] cloneNode -deep] set result [$root asXML -indent none] $doc delete set result } {texttext} test domNode-12.8 {cloneNode -deep} { set doc [dom parse {text}] set root [$doc documentElement] set removedNode [$root removeChild [$root firstChild]] $root appendChild [[$root firstChild] cloneNode -deep] set result [$root asXML -indent none] $doc delete set result } {texttext} test domNode-12.9 {cloneNode -deep} { set doc [dom parse {text}] set root [$doc documentElement] set removedNode [$root removeChild [$root firstChild]] $root appendChild [[$root firstChild] cloneNode -deep] unset result lappend result [$removedNode nextSibling] lappend result [$removedNode previousSibling] $doc delete set result } {{} {}} test domNode-12.10 {cloneNode -deep} { set doc [dom parse {text}] set root [$doc documentElement] $root removeChild [$root firstChild] set removedNode [$root removeChild [$root firstChild]] $root appendChild [[$root firstChild] cloneNode -deep] unset result lappend result [[$removedNode nextSibling] nodeName] lappend result [$removedNode previousSibling] $doc delete set result } {y {}} test domNode-12.11 {cloneNode -deep w/ disableOutputEscaping} { dom parse "" doc $doc createTextNode "a b" textnode $textnode disableOutputEscaping 1 $doc documentElement root $root firstChild td $td appendChild $textnode $root appendChild [$td cloneNode -deep] set result [$doc asXML -indent none] $doc delete set result } {a ba b} namespace eval nodeCmds { dom createNodeCmd elementNode e1 dom createNodeCmd elementNode e2 dom createNodeCmd commentNode c dom createNodeCmd textNode t dom createNodeCmd cdataNode cdata dom createNodeCmd piNode pi dom createNodeCmd parserNode parser dom createNodeCmd -notempty elementNode e3 dom createNodeCmd -notempty elementNode e4 } test domNode-13.1 {appendFromScript - elementNode} { set doc [dom createDocument root] set root [$doc documentElement] $root appendFromScript nodeCmds::e1 set result [$root asXML -indent none] $doc delete set result } {} test domNode-13.2 {appendFromScript - elementNode} { set doc [dom createDocument root] set root [$doc documentElement] namespace eval nodeCmds { $::root appendFromScript { e1 e2 } } set result [$root asXML -indent none] $doc delete set result } {} test domNode-13.3 {appendFromScript - elementNode} { set doc [dom createDocument root] set root [$doc documentElement] namespace eval nodeCmds { $::root appendFromScript { e1 { e2 { e1 } } e2 } } set result [$root asXML -indent none] $doc delete set result } {} test domNode-13.4 {appendFromScript - elementNode with attributes as options} { set doc [dom createDocument root] set root [$doc documentElement] namespace eval nodeCmds { $::root appendFromScript { e1 -attr1 attr1Value -attr2 "attr 2 Value" } } set result [$root asXML -indent none] $doc delete set result } {} test domNode-13.5 {appendFromScript - elementNode with attributes as list} { set doc [dom createDocument root] set root [$doc documentElement] set attlist [list -a1 "some & value" -a2 "another attvalue"] namespace eval nodeCmds { $::root appendFromScript { e1 $::attlist {} } } set result [$root asXML -indent none] $doc delete set result } {} test domNode-13.6 {appendFromScript - textnode, commentnode, cdatanode, pinode} { set doc [dom createDocument root] set root [$doc documentElement] namespace eval nodeCmds { $::root appendFromScript { t foo c "my comment" cdata {&"<>;} ;# emacs: " pi mypi "some pi data" } } set result [$root asXML -indent none] $doc delete set result } {foo;]]>} # emacs: " test domNode-13.7 {appendFromScript - textnode} { set doc [dom createDocument root] set root [$doc documentElement] namespace eval nodeCmds { $::root appendFromScript { t "

    Some important stuff

    " } } set result [$root asXML -indent none] $doc delete set result } {<p>Some <b>important</b> stuff</p>} test domNode-13.8 {appendFromScript - textnode with -disableOutputEscaping} { set doc [dom createDocument root] set root [$doc documentElement] namespace eval nodeCmds { $::root appendFromScript { t -disableOutputEscaping "

    Some important stuff

    " } } set result [$root asXML -indent none] $doc delete set result } {

    Some important stuff

    } test domNode-13.9 {appendFromScript while fragment list isn't empty} { set doc [dom parse text] set root [$doc documentElement] $root removeChild [$root firstChild] $root appendFromScript { nodeCmds::t "another text" } set result [llength [$root childNodes]] $doc delete set result } {1} test domNode-13.10 {appendFromScript - tcl error inside the script} { set doc [dom createDocument root] set root [$doc documentElement] set result [catch {$root appendFromScript { nodeCmds::e1 nodeCmds::e1 { # This is intentionally wrong set foo 1 + 1 } }}] lappend result [$doc asXML -indent none] $doc delete set result } {1 } test domNode-13.11 {appendFromScript - tcl error inside the script} { set doc [dom parse ] set root [$doc documentElement] set result [catch {$root appendFromScript { nodeCmds::e1 { nodeCmds::e2 { t foo } nodeCmds::e2 -attr attrvalue { nodeCmds::e2 -attr1 attrvalue attr2 attrvalue { t bar } } } nodeCmds::e1 { # This is intentionally wrong set foo 1 + 1 } }}] lappend result [$doc asXML -indent none] $doc delete set result } {1 } test domNode-13.12 {appendFromScript - node isn't ELEMENT_NODE} { dom parse text doc $doc documentElement root $root firstChild textNode set result [catch {$textNode appendFromScript { nodeCmds::e1 }} errMsg] lappend result $errMsg lappend result [$doc asXML -indent none] $doc delete set result } {1 {NOT_AN_ELEMENT : can't append nodes} text} test domNode-13.13 {createNodeCmd elementNode with invalide tag name} { set result [catch {dom createNodeCmd elementNode \ [list invalid name]} errMsg] lappend result $errMsg } {1 {Invalid tag name 'invalid name'}} namespace eval nodeCmds::thisCmds { } test domNode-13.14 {qualified nodeCmd name} { namespace eval nodeCmds { dom createNodeCmd elementNode thisCmds::thisE } set result [llength [info commands nodeCmds::thisE]] lappend result [llength [info commands nodeCmds::thisCmds::thisE]] set doc [dom createDocument root] set root [$doc documentElement] namespace eval nodeCmds { $::root appendFromScript { thisCmds::thisE } } lappend result [$doc asXML -indent none] $doc delete set result } {0 1 } set nsname "tricky nsname" namespace eval nodeCmds::$nsname { } test domNode-13.15 {qualified nodeCmds name} { namespace eval nodeCmds { dom createNodeCmd elementNode ${::nsname}::thisE } set result [llength [info commands nodeCmds::thisE]] lappend result [llength [info commands nodeCmds::${nsname}::thisE]] set doc [dom createDocument root] set root [$doc documentElement] namespace eval nodeCmds { $::root appendFromScript { ${::nsname}::thisE } } lappend result [$doc asXML -indent none] $doc delete set result } {0 1 } test domNode-13.16 {Invalid attribute name} { set doc [dom createDocument root] set root [$doc documentElement] set result [catch { namespace eval nodeCmds { $::root appendFromScript { e1 att1 att1Value "invalid attname" value {} } } } errMsg] lappend result $errMsg $doc delete set result } {1 {Invalid attribute name 'invalid attname'}} test domNode-13.17 {Invalid attribute value} { set doc [dom createDocument root] set root [$doc documentElement] set result [catch { namespace eval nodeCmds { $::root appendFromScript { e1 att1 att1Value att2 "invalid \u0003 value" {} } } } errMsg] lappend result $errMsg $doc delete set result } [list 1 "Invalid attribute value 'invalid \u0003 value'"] dom setNameCheck 0 namespace eval nodeCmds { dom createNodeCmd elementNode e1 } dom setNameCheck 1 test domNode-13.18 {Invalid attribute name - check disabled} { set doc [dom createDocument root] set root [$doc documentElement] set result [catch { namespace eval nodeCmds { $::root appendFromScript { e1 att1 att1Value "invalid attname" value {} } } }] $doc delete set result } {0} dom setTextCheck 0 namespace eval nodeCmds { dom createNodeCmd elementNode e1 } dom setTextCheck 1 test domNode-13.19 {Invalid attribute value - check disabled} { set doc [dom createDocument root] set root [$doc documentElement] set result [catch { namespace eval nodeCmds { $::root appendFromScript { e1 att1 att1Value att2 "invalid \u0003 value" {} } } }] $doc delete set result } 0 dom setTextCheck 0 dom setNameCheck 0 namespace eval nodeCmds { dom createNodeCmd elementNode e1 } dom setTextCheck 1 dom setNameCheck 1 test domNode-13.20 {Invalid att name, invalid att value, checks disabled} { set doc [dom createDocument root] set root [$doc documentElement] set result [catch { namespace eval nodeCmds { $::root appendFromScript { e1 att1 att1Value "invalid attName" "invalid \u0003 value" {} } } }] $doc delete set result } 0 namespace eval nodeCmds { dom createNodeCmd elementNode e1 } test domNode-13.21 {Invalid comment value} { set doc [dom createDocument root] set root [$doc documentElement] set result [catch { namespace eval nodeCmds { $::root appendFromScript { c "invalid -- comment" } } } errMsg] lappend result $errMsg $doc delete set result } {1 {Invalid comment value 'invalid -- comment'}} test domNode-13.22 {Invalid CDATA section value} { set doc [dom createDocument root] set root [$doc documentElement] set result [catch { namespace eval nodeCmds { $::root appendFromScript { cdata "invalid comment ]]>" } } } errMsg] lappend result $errMsg $doc delete set result } {1 {Invalid CDATA section value 'invalid comment ]]>'}} test domNode-13.23 {Invalid text node} { set doc [dom createDocument root] set root [$doc documentElement] set result [catch { namespace eval nodeCmds { $::root appendFromScript { t "invalid text \u0004" } } } errMsg] lappend result $errMsg $doc delete set result } [list 1 "Invalid text value 'invalid text \u0004'"] test domNode-13.24 {Invalid processing instruction} { set doc [dom createDocument root] set root [$doc documentElement] set result [catch { namespace eval nodeCmds { $::root appendFromScript { pi Xml "data" } } } errMsg] lappend result $errMsg $doc delete set result } [list 1 "Invalid processing instruction name 'Xml'"] test domNode-13.25 {Invalid processing instruction} { set doc [dom createDocument root] set root [$doc documentElement] set result [catch { namespace eval nodeCmds { $::root appendFromScript { pi Xmll "data ?>" } } } errMsg] lappend result $errMsg $doc delete set result } [list 1 "Invalid processing instruction value 'data ?>'"] test domNode-13.26 {appendFromScript with default namespace in scope} { set doc [dom parse {}] set root [$doc documentElement] namespace eval nodeCmds { $::root appendFromScript { e1 } } set result [$doc asXML -indent none] $doc delete set result } {} test domNode-13.27 {delete doc in appendFromScript script} { set doc [dom createDocument doc] set root [$doc documentElement] set result "" $root appendFromScript { ::nodeCmds::e1 { ::nodeCmds::e1 { $doc delete } } lappend result [info commands $doc] ::nodeCmds::e1 } lappend result [info commands $doc] } {{} {}} proc domNode-13.28 {} { dom createDocument doc doc set root [$doc documentElement] $root appendFromScript { ::nodeCmds::e1 { $doc delete } } info commands $doc } test domNode-13.28 {delete doc in appendFromScript script} { domNode-13.28 } {} test domNode-13.29 {tdom::fsinsertNode} { set doc [dom createDocument doc] set root [$doc documentElement] $root appendFromScript { ::nodeCmds::e1 { tdom::fsinsertNode [$doc createElement some] } } set result [$doc asXML -indent none] $doc delete set result } {} test domNode-13.30 {tdom::fsnewNode} { set doc [dom createDocument doc] set root [$doc documentElement] $root appendFromScript { tdom::fsnewNode e1 { tdom::fsinsertNode [$doc createElement some] } } set result [$doc asXML -indent none] $doc delete set result } {} test domNode-13.31 {tdom::fsnewNode} { set doc [dom createDocument doc] set root [$doc documentElement] $root appendFromScript { tdom::fsnewNode e1 { tdom::fsnewNode some att1 "att1 value" { ::nodeCmds::e1 } } } set result [$doc asXML -indent none] $doc delete set result } {} test domNode-13.32 {tdom::fsnewNode} { set doc [dom createDocument doc] set root [$doc documentElement] $root appendFromScript { tdom::fsnewNode e1 { tdom::fsnewNode some {att1 "att1 value"} { ::nodeCmds::e1 } } } set result [$doc asXML -indent none] $doc delete set result } {} test domNode-13.33 {tdom::fsnewNode} { set doc [dom createDocument doc] set root [$doc documentElement] $root appendFromScript { tdom::fsnewNode e1 { tdom::fsnewNode some {-att1 "att1 value" -att2 "att2 value"} { ::nodeCmds::e1 } } } set result [$doc asXML -indent none] $doc delete set result } {} test domNode-13.34 {-notempty} { set doc [dom createDocument doc] set root [$doc documentElement] $root appendFromScript { ::nodeCmds::e3 } set result [$doc asXML -indent none] $doc delete set result } {} test domNode-13.35 {-notempty} { set doc [dom parse {}] set root [$doc documentElement] $root insertBeforeFromScript { ::nodeCmds::e3 } [$root lastChild] set result [$doc asXML -indent none] $doc delete set result } {} test domNode-13.36 {-notempty} { set doc [dom createDocument doc] set root [$doc documentElement] $root appendFromScript { ::nodeCmds::e3 { ::nodeCmds::e4 ::nodeCmds::e3 } } set result [$doc asXML -indent none] $doc delete set result } {} test domNode-13.37 {-notempty} { set doc [dom parse {}] set root [$doc documentElement] $root insertBeforeFromScript { ::nodeCmds::e3 { ::nodeCmds::e3 ::nodeCmds::e4 } } [$root lastChild] set result [$doc asXML -indent none] $doc delete set result } {} test domNode-13.38 {-notempty} { set doc [dom createDocument doc] set root [$doc documentElement] $root appendFromScript { ::nodeCmds::e3 { ::nodeCmds::e4 ::nodeCmds::e3 {::nodeCmds::t foo} } } set result [$doc asXML -indent none] $doc delete set result } {foo} test domNode-13.39 {-notempty} { set doc [dom parse {}] set root [$doc documentElement] $root insertBeforeFromScript { ::nodeCmds::e3 { ::nodeCmds::e3 ::nodeCmds::e4 {::nodeCmds::t bar} } } [$root lastChild] set result [$doc asXML -indent none] $doc delete set result } {bar} test domNode-13.40 {fsnewNode -notempty} { set doc [dom parse ] set e [[$doc documentElement] firstChild] $e appendFromScript { tdom::fsnewNode -notempty echild att1 att1value } set result [$doc asXML -indent none] $doc delete set result } {} test domNode-13.41 {fsnewNode -notempty} { set doc [dom parse ] set e [[$doc documentElement] firstChild] $e appendFromScript { tdom::fsnewNode -notempty echild att1 att1value { ::nodeCmds::t bar } } set result [$doc asXML -indent none] $doc delete set result } {bar} test domNode-13.42 {fsnewNode -notempty} { set doc [dom parse ] set e [[$doc documentElement] firstChild] $e appendFromScript { tdom::fsnewNode -notempty echild att1 att1value { # Do something else but don't create nodes set sum [expr {1+2}] } } set result [$doc asXML -indent none] $doc delete set result } {} test domNode-14.1 {appendFromList} { set doc [dom createDocument root] set root [$doc documentElement] set errMsg "" set result [catch {$root appendFromList {a b}} errMsg] lappend result $errMsg $doc delete set result } {1 {invalid element node list format!}} test domNode-14.2 {appendFromList} { set doc [dom createDocument root] set root [$doc documentElement] set errMsg "" set result [catch {$root appendFromList {a b c}} errMsg] lappend result $errMsg $doc delete set result } {1 {invalid attributes list format!}} test domNode-14.3 {appendFromList} { set doc [dom createDocument root] set root [$doc documentElement] $root appendFromList {a {} {}} set result [$root asXML -indent none] $doc delete set result } {
    } test domNode-14.4 {appendFromList} { set doc [dom createDocument root] set root [$doc documentElement] $root appendFromList {#text "foo bar"} set result [$root asXML -indent none] $doc delete set result } {foo bar} test domNode-14.5 {appendFromList} { set doc [dom parse {texttext}] set elm [$doc documentElement] set elmList [$elm asList] $doc delete set doc [dom createDocument root] set root [$doc documentElement] $root appendFromList $elmList set result [$root asXML -indent none] $doc delete set result } {texttext
    } set doc [dom parse {text}] set docElem [$doc documentElement] test domNode-14.6 {asList of tree with comment nodes} { $docElem asList } [list elem {} [list [list \#comment " comment "] [list \#text text] [list child [list a v] [list [list \#comment comment]]]]] test domNode-14.7 {asList on a comment} { set commentNode [$docElem firstChild] $commentNode asList } [list \#comment " comment "] test domNode-14.8 {asList on a comment} { set commentNode [$docElem selectNodes {(//comment())[2]}] $commentNode asList } [list \#comment comment] test domNode-14.9 {appendFromList with comment nodes in the list} { set list [$docElem asList] set newDoc [dom createDocument newDoc] set newDocRoot [$newDoc documentElement] $newDocRoot appendFromList $list set result [$newDoc asXML -indent none] $newDoc delete set result } {text} $doc delete set doc [dom parse {text}] set docElem [$doc documentElement] test domNode->14.10 {asList of tree with PI nodes} { $docElem asList } [list elem {} [list [list \#pi myPI value] [list \#text text] [list child [list a v] [list [list \#pi myPI1 "the value"]]]]] test domNode->14.11 {asList on a PI} { set piNode [$docElem firstChild] $piNode asList } [list \#pi myPI value] test domNode->14.12 {asList on a PI} { set piNode [$docElem selectNodes {(//processing-instruction())[2]}] $piNode asList } [list \#pi myPI1 "the value"] test domNode-14.13 {appendFromList with comment node in the list} { set list [$docElem asList] set newDoc [dom createDocument newDoc] set newDocRoot [$newDoc documentElement] $newDocRoot appendFromList $list set result [$newDoc asXML -indent none] $newDoc delete set result } {text} $doc delete test domNode-14.14 {appendFromList - invalid tagname} { set doc [dom createDocument root] set root [$doc documentElement] set errMsg "" set result [catch {$root appendFromList {{invalid tagname} {} {}}} errMsg] lappend result $errMsg $doc delete set result } {1 {Invalid tag name 'invalid tagname'}} test domNode-14.15 {appendFromList - invalid processing instruction name} { set doc [dom createDocument root] set root [$doc documentElement] set errMsg "" set result [catch {$root appendFromList {\#pi "invalid pi name" piValue}} errMsg] lappend result $errMsg $doc delete set result } {1 {Invalid processing instruction name 'invalid pi name'}} set xml { text node text text text text } test domNode-15.1 {delete - text nodes} { set doc [dom parse $xml] set root [$doc documentElement] foreach node [$root selectNodes text()] { $node delete } set result [llength [$root childNodes]] $doc delete set result } {5} test domNode-15.2 {delete - comment nodes} { set doc [dom parse -keepEmpties $xml] set root [$doc documentElement] foreach node [$root selectNodes comment()] { $node delete } set result [llength [$root childNodes]] $doc delete set result } {6} test domNode-15.3 {delete - pi nodes} { set doc [dom parse -keepEmpties $xml] set root [$doc documentElement] foreach node [$root selectNodes processing-instruction()] { $node delete } set result [llength [$root childNodes]] $doc delete set result } {7} test domNode-15.4 {delete - pi nodes} { set doc [dom parse -keepEmpties $xml] set root [$doc documentElement] foreach node [$root selectNodes node()] { $node delete } set result [llength [$root childNodes]] $doc delete set result } {0} test domNode-15.5 {delete - threaded} -constraints { threaded } -setup { set xml { one two three } set doc [dom parse $xml] dom attachDocument $doc doc_ $doc documentElement root } -body { foreach node [$root selectNodes {//attr1 | //attr2}] { [$node firstChild] delete } set result "" } -cleanup { dom detachDocument $doc dom detachDocument $doc_ } -result "" test domNode-15.6 {delete - threaded} -constraints { threaded } -setup { set xml {
    } set doc [dom parse $xml] dom attachDocument $doc doc_ $doc documentElement root } -body { foreach node [$root selectNodes a] { $node delete } set result "" } -cleanup { dom detachDocument $doc dom detachDocument $doc_ } -result "" set doc [dom parse {}] set root [$doc documentElement] test domNode-16.1 {getAttribute} { $root getAttribute attr1 } {bingbaz} test domNode-16.2 {getAttribute} { $root getAttribute attr2 } {ab & zu} test domNode-16.3 {getAttribute} { $root getAttribute attr3 } {} test domNode-16.4 {getAttribute with default} { $root getAttribute attr1 "default not needed, because attr1 exists" } {bingbaz} test domNode-16.5 {getAttribute with default} { $root getAttribute notPresent "expect this given default value" } {expect this given default value} test domNode-16.6 {getAttribute - attr dosen't exists and no default} { catch {$root getAttribute notPresent} } {1} test domNode-16.7 {getAttribute shortcut} { $root @attr1 } {bingbaz} test domNode-16.8 {getAttribute shortcut} { $root @attr2 } {ab & zu} test domNode-16.9 {getAttribute shortcut} { $root @attr3 } {} test domNode-16.10 {getAttribute shortcut with default} { $root @attr1 "default not needed, because attr1 exists" } {bingbaz} test domNode-16.11 {getAttribute shortcut with default} { $root @notPresent "expect this given default value" } {expect this given default value} test domNode-16.12 {getAttribute shortcut - attr dosen't exists and no default} { catch {$root @notPresent} } {1} $doc delete set doc [dom parse {}] set root [$doc documentElement] test domNode-16.13 {getAttribute} { $root getAttribute xmlns } {uri2} test domNode-16.14 {getAttribute} { $root getAttribute xmlns:foo } {http://tdom.org/ns1} $doc delete set xml { text node text text text text } set doc [dom parse -keepEmpties $xml] set root [$doc documentElement] test domNode-17.1 {nodeType} { unset result foreach node [$root childNodes] { lappend result [$node nodeType] } set result } {TEXT_NODE ELEMENT_NODE COMMENT_NODE TEXT_NODE ELEMENT_NODE COMMENT_NODE PROCESSING_INSTRUCTION_NODE TEXT_NODE} test domNode-17.2 {nodeType} { set CDATAnode [$doc createCDATASection "a CDATA section"] $root insertBefore $CDATAnode [$root firstChild] [$root firstChild] nodeType } {CDATA_SECTION_NODE} $doc delete set doc [dom parse { text child}] set root [$doc documentElement] test domNode-18.1 {attributes} { $root attributes } {{foo foo {}} attr1 attr2 attr3 {attr1 foo http://tdom.org/ns} worble2} test domNode-18.2 {attributes} { $root attributes * } {{foo foo {}} attr1 attr2 attr3 {attr1 foo http://tdom.org/ns} worble2} test domNode-18.3 {attributes} { $root attributes attr* } {attr1 attr2 attr3} test domNode-18.4 {attributes} { $root attributes *2* } {attr2 worble2} test domNode-18.5 {attributes} { $root attributes worble2 } {worble2} test domNode-18.6 {attributes} { $root attributes *brab* } {} test domNode-18.7 {attributes} { [$root firstChild] attributes } {} test domNode-18.1.1 {attributeNames} { $root attributeNames } {xmlns:foo attr1 attr2 attr3 foo:attr1 worble2} test domNode-18.2.1 {attributeNames} { $root attributeNames * } {xmlns:foo attr1 attr2 attr3 foo:attr1 worble2} test domNode-18.3.1 {attributeNames} { $root attributeNames attr* } {attr1 attr2 attr3} test domNode-18.4.1 {attributeNames} { $root attributeNames *2* } {attr2 worble2} test domNode-18.5.1 {attributeNames} { $root attributeNames worble2 } {worble2} test domNode-18.6.1 {attributeNames} { $root attributeNames *brab* } {} test domNode-18.7.1 {attributeNames} { [$root firstChild] attributeNames } {} # Hmmm. This two following tests are mostly there to document the # behavior of the method, as it is. It may debatable if they should # behave this way. The optional attribute name pattern is a tDOM # DOM extension there is nothing in the rec, which could help to argue. # Therefore, it's the way, it is. test domNode-18.8 {attributes} { $root attributes *tdom* } {} test domNode-18.9 {attributes} { $root attributes foo* } {{attr1 foo http://tdom.org/ns}} test domNode-18.9.1 {attributeNames} { $root attributeNames foo:* } {foo:attr1} $doc delete set doc [dom parse {}] set root [$doc documentElement] test domNode-18.10 {attributes} { $root attributes } {{foo foo {}} {xmlns {} {}} attr1 {attr1 foo http://tdom.org/ns1} worble2} $doc delete set doc [dom parse { text child}] set root [$doc documentElement] test domNode-19.1 {removeAttribute} { $root removeAttribute attr1 $root attributes attr1 } {} $doc delete set doc [dom parse { text child}] set root [$doc documentElement] test domNode-19.2 {removeAttribute} { catch {$root removeAttribute attr1} errMsg set errMsg } {can't remove attribute 'attr1'} test domNode-19.3 {removeAttribute} { catch {$root removeAttribute} } {1} test domNode-19.4 {removeAttribute} { catch {$root removeAttribute attr2 attr3} } {1} test domNode-19.5 {removeAttributeNS} { $root removeAttributeNS http://tdom.org/ns attr1 $root hasAttributeNS http://tdom.org/ns attr1 } {0} test domNode-19.6 {removeAttributeNS} { catch {$root removeAttributeNS http://tdom.org attr1} } {1} test domNode-19.7 {removeAttributeNS} { catch {$root removeAttributeNS http://tdom.org/bar thisatt} } {0} $doc delete set doc [dom parse ] set root [$doc documentElement] test domNode-20.1 {parentNode} { $root parentNode } {} test domNode-20.2 {parentNode} { $root parentNode var set var } {} test domNode-20.3 {parentNode} { set child [$root firstChild] [$child parentNode] nodeName } {root} test domNode-20.4 {parentNode} { set child [$root firstChild] $root removeChild $child $child parentNode } {} $doc delete set doc [dom parse {text}] set root [$doc documentElement] test domNode-21.1 {hasChildNodes} { $root hasChildNodes } {1} test domNode-21.2 {hasChildNodes} { set node [$root firstChild] $node hasChildNodes } {0} test domNode-21.3 {hasChildNodes} { set node [$root lastChild] $node hasChildNodes } {1} $doc delete set doc [dom parse { text}] set root [$doc documentElement] test domNode-22.1 {localName} { $root localName } {} test domNode-22.2 {localName} { [$root firstChild] localName } {e1} test domNode-22.3 {localName} { set node [$root firstChild] [$node firstChild] localName } {e2} test domNode-22.4 {localName} { catch {[$root lastChild] localName} errMsg set errMsg } {} test domNode-22.5 {prefix} { [$root firstChild] prefix } {p1} test domNode-22.6 {prefix} { set node [$root firstChild] [$node firstChild] prefix } {} test domNode-22.7 {prefix} { $root prefix } {} $doc delete test domNode-23.1 {replaceChild} { set doc [dom parse {text}] set root [$doc documentElement] set removedNode [$root removeChild [$root firstChild]] $root replaceChild $removedNode [$root firstChild] set result [$root asXML -indent none] $doc delete set result } {} test domNode-23.2 {replaceChild} { set doc [dom parse {text}] set root [$doc documentElement] $root replaceChild [$root lastChild] [$root firstChild] set result [$root asXML -indent none] $doc delete set result } {text} test domNode-23.3 {replaceChild} { set doc [dom parse {text}] set root [$doc documentElement] set e1 [$root firstChild] set e2 [$root lastChild] $e2 replaceChild $e1 [$e2 firstChild] set result [$root asXML -indent none] $doc delete set result } {} test domNode-23.4 {replaceChild} { set doc [dom parse {}] set root [$doc documentElement] set childNodes [$root childNodes] for {set i 1} {$i < 4} {incr i} { $root removeChild [lindex $childNodes $i] } $root replaceChild [lindex $childNodes 1] [$root firstChild] set result [$root asXML -indent none] $doc delete set result } {} test domNode-23.5 {replaceChild} { set doc [dom parse {}] set root [$doc documentElement] set childNodes [$root childNodes] for {set i 1} {$i < 4} {incr i} { $root removeChild [lindex $childNodes $i] } $root replaceChild [lindex $childNodes 2] [$root firstChild] set result [$root asXML -indent none] $doc delete set result } {} test domNode-23.6 {replaceChild} { set doc [dom parse {}] set root [$doc documentElement] set childNodes [$root childNodes] for {set i 1} {$i < 4} {incr i} { $root removeChild [lindex $childNodes $i] } $root replaceChild [lindex $childNodes 3] [$root firstChild] set result [$root asXML -indent none] $doc delete set result } {} test domNode-23.7 {replaceChild} { set doc [dom parse {}] set root [$doc documentElement] set childNodes [$root childNodes] for {set i 1} {$i < 4} {incr i} { $root removeChild [lindex $childNodes $i] } foreach child $childNodes { $root replaceChild $child [$root firstChild] } set result [$root asXML -indent none] $doc delete set result } {} test domNode-24.1 {getLine} { set doc [dom parse ] set root [$doc documentElement] set result [catch {$root getLine}] $doc delete set result } {1} test domNode-24.1.1 {getColumn} { set doc [dom parse ] set root [$doc documentElement] set result [catch {$root getColumn} errMsg] $doc delete lappend result $errMsg } {1 {no line/column information available!}} test domNode-24.1.2 {getByteIndex} { set doc [dom parse ] set root [$doc documentElement] set result [catch {$root getByteIndex} errMsg] $doc delete lappend result $errMsg } {1 {no position information available!}} dom setStoreLineColumn 1 set doc [dom parse { }] set root [$doc documentElement] dom setStoreLineColumn 0 test domNode-24.2 {getLine} { $root getLine } {1} test domNode-24.3 {getColumn} { $root getColumn } {0} test domNode-24.4 {getLine} { [$root firstChild] getLine } {2} test domNode-24.5 {getLine getColumn} { set node [$root selectNodes //e2] set result [$node getLine].[$node getColumn] } {2.4} test domNode-24.6 {getByteIndex} { set node [$root selectNodes //e2] set result [$node getByteIndex] } {11} $doc delete dom setStoreLineColumn 1 test domNode-24.7 {getLine etc text node} { set doc [dom parse { Hello}] set root [$doc documentElement] set node [$root firstChild] set result [$node getLine].[$node getColumn] $doc delete set result } {1.6} test domNode-24.8 {getLine etc cdatasection node} { set doc [dom parse -keepCDATA {}] set root [$doc documentElement] set node [$root firstChild] set result [$node getLine].[$node getColumn] $doc delete set result } {1.6} test domNode-24.8.1 {getLine etc cdatasection node without -keepCDATA} { set doc [dom parse {}] set root [$doc documentElement] set node [$root firstChild] set result [$node getLine].[$node getColumn] $doc delete set result } {1.15} test domNode-24.9 {getLine etc pi node} { set doc [dom parse { }] set root [$doc documentElement] set node [$root firstChild] set result [$node getLine].[$node getColumn] $doc delete set result } {1.6} test domNode-24.10 {getLine etc comment node} { set doc [dom parse { }] set root [$doc documentElement] set node [$root firstChild] set result [$node getLine].[$node getColumn] $doc delete set result } {2.8} test domNode-24.11 {getLine etc multple text/CDATA nodes} { set doc [dom parse -keepCDATA { text}] set root [$doc documentElement] set e1 [$root firstChild] set node [$e1 firstChild] set result [$node getLine].[$node getColumn] $doc delete set result } {2.12} test domNode-24.12 {getLine etc multple text/CDATA nodes} { set doc [dom parse -keepCDATA { textmore text}] set root [$doc documentElement] set e1 [$root firstChild] set node [$e1 firstChild] set result [$node getLine].[$node getColumn]/ set node [$node nextSibling] append result [$node getLine].[$node getColumn]/ set node [$node nextSibling] append result [$node getLine].[$node getColumn] $doc delete set result } {2.12/2.16/3.20} dom setStoreLineColumn 0 set doc [dom parse { text child}] set root [$doc documentElement] test domNode-25.1 {hasAttribute} { $root hasAttribute attr3 } 1 test domNode-25.2 {hasAttribute} { $root hasAttribute attr4 } 0 test domNode-25.3 {hasAttributeNS} { $root hasAttributeNS http://tdom.org/ns attr1 } 1 test domNode-25.4 {hasAttributeNS} { $root hasAttributeNS http://tdom.org attr1 } 0 $doc delete test domNode-26.1 {appendXML} { set doc [dom createDocument root] set root [$doc documentElement] $root appendXML "text" set result [$root asXML -indent none] $doc delete set result } {text} test domNode-26.2 {appendXML} { set doc [dom parse ] set root [$doc documentElement] $root appendXML "text" set result [$root asXML -indent none] $doc delete set result } {text} set doc [dom parse { }] set root [$doc documentElement] test domNode-27.1 {target, data} { set piNode [$root selectNodes /processing-instruction()] set result [$piNode target].[$piNode data] } {piBeforeRoot.do this} test domNode-27.2 {target, data} { set piNodes [$root selectNodes processing-instruction()] set result "" foreach piNode $piNodes { set result "$result [$piNode target].[$piNode data]" } set result } { pi1.my & data pi2.data} $doc delete test domNode-28.1 {getAttributeNS} { set doc [dom parse { }] set root [$doc documentElement] set result [$root getAttributeNS "ns1" attr1] $doc delete set result } {p:attr1Value} test domNode-28.2 {getAttributeNS - default value} { set doc [dom parse { }] set root [$doc documentElement] set result [$root getAttributeNS "not" attr1 "default"] $doc delete set result } {default} test domNode-28.3 {getAttributeNS - default value} { set doc [dom parse { }] set root [$doc documentElement] set result [$root getAttributeNS "not" notexisting "some default"] $doc delete set result } {some default} test domNode-28.4 {getAttributeNS - default value} { set doc [dom parse { }] set root [$doc documentElement] set result [$root getAttributeNS "ns1" notexisting "some other default"] $doc delete set result } {some other default} proc domAppendChild {parent name} { $parent ownerDocument doc $doc createElement $name node $parent appendChild $node } test domNode-29.1 {ownerDocument} { dom createDocument document doc set root [$doc documentElement] domAppendChild $root foo1 domAppendChild $root foo2 set result [$doc asXML -indent none] $doc delete set result } {} set doc [dom parse {text}] set root [$doc documentElement] test domNode-30.1 {precedes} { catch {$root precedes} } {1} test domNode-30.2 {precedes} { set firstChild [$root firstChild] catch {$root start $firstChild foo} } {1} test domNode-30.3 {precedes} { set result [catch {$root precedes notaNode} errMsg] lappend result $errMsg } {1 {Parameter "notaNode" is not a domNode.}} test domNode-30.4 {precedes} { set firstChild [$root firstChild] $root precedes $firstChild } {1} test domNode-30.5 {precedes} { set firstChild [$root firstChild] $root precedes $firstChild } {1} test domNode-30.6 {precedes} { set firstChild [$root firstChild] $firstChild precedes $root } {0} test domNode-30.7 {precedes} { set firstChild [$root firstChild] $firstChild precedes $firstChild } {0} test domNode-30.8 {precedes} { set doc1 [dom parse ] set root1 [$doc1 documentElement] set result [catch {$root precedes $root1} errMsg] lappend result $errMsg $doc1 delete set result } {1 {Cannot compare the relative order of nodes out of different documents.}} test domNode-30.9 {precedes} { set firstChild [$root firstChild] set newNode [$doc createElement newNode] $root insertBefore $newNode $firstChild $newNode precedes $firstChild } {1} test domNode-30.10 {precedes} { set newNode [$doc createTextNode "new text node"] set result [catch {$root precedes $newNode} errMsg] lappend result $errMsg } {1 {Cannot compare the relative order of a node with a node out of the fragment list.}} $doc delete dom parse {} doc $doc documentElement root set e [$root selectNodes //e] set eee [$root selectNodes //eee] test domNode-30.11 {precedes} { $e precedes $eee } {1} test domNode-30.12 {precedes} { $eee precedes $e } {0} $doc delete test domNode-31.1 {insertBefore - syntax check} { set doc [dom parse ] set root [$doc documentElement] set result [catch {$root insertBefore}] $doc delete set result } {1} test domNode-31.2 {insertBefore - syntax check} { set doc [dom parse
    ] set root [$doc documentElement] set result [catch {$root insertBefore [$root firstChild]}] $doc delete set result } {1} test domNode-31.3 {insertBefore - tries to insert node as child of node} { set doc [dom parse ] set root [$doc documentElement] catch {$root insertBefore $root [$root lastChild]} errMsg $doc delete set errMsg } {HIERARCHY_REQUEST_ERR} test domNode-31.4 {insertBefore - refnode invalide} { set doc [dom parse ] set root [$doc documentElement] set newElement [$doc createElement new] catch {$root insertBefore $newElement $root} errMsg $doc delete set errMsg } {NOT_FOUND_ERR} # Prior to dom.c r1.63 insertBefore leaks the node to insert, if the refnode # isn't valid. test domNode-31.5 {insertBefore - refnode invalide} { set doc [dom parse ] set root [$doc documentElement] set oneChild [$root firstChild] set twoChild [$root lastChild] catch {$oneChild insertBefore [$oneChild firstChild] $root} errMsg set result [list $errMsg [llength [$oneChild childNodes]]] $doc delete set result } {NOT_FOUND_ERR 1} test domNode-31.6 {insertBefore - refnode and new node to insert are the same} { dom parse doc $doc documentElement root $root firstChild firstChild $root insertBefore $firstChild $firstChild set result [$doc asXML -indent none] $doc delete set result } {} test domNode-31.7 {insertBefore - insert a sibling of node} { dom parse {} doc set root [$doc documentElement] $root firstChild a $root lastChild b $a insertBefore $b [$a firstChild] set result [$doc asXML -indent none] $doc delete set result } {} test domNode-31.8 {insertBefore - new node is node} { dom parse doc $doc documentElement root $root firstChild firstChild catch {$root insertBefore $root $firstChild} errMsg $doc delete set errMsg } {HIERARCHY_REQUEST_ERR} test domNode-31.9 {insertBefore tries to insert a parent of node as child} { set doc [dom parse ] set root [$doc documentElement] $root firstChild a catch {$a insertBefore $root [$a firstChild]} errMsg $doc delete set errMsg } {HIERARCHY_REQUEST_ERR} test domNode-31.10 {insertBefore - node to insert is a sibling of ref node} { set doc [dom parse ] $doc documentElement root $root firstChild a $a insertBefore [$a lastChild] [$a firstChild] set result [$doc asXML -indent none] $doc delete set result } {} test domNode-31.11 {insertBefore - node to insert is a sibling of ref node} { set doc [dom parse ] $doc documentElement root $root firstChild a $a insertBefore [$a lastChild] [$a firstChild] catch {unset result} set node [$a firstChild] while {$node != ""} { lappend result [$node nodeName] set node [$node nextSibling] } $doc delete set result } {two one} test domNode-31.12 {insertBefore - node to insert is a sibling of ref node} { set doc [dom parse ] $doc documentElement root $root firstChild a $a insertBefore [$a lastChild] [$a firstChild] catch {unset result} set node [$a lastChild] while {$node != ""} { lappend result [$node nodeName] set node [$node previousSibling] } $doc delete set result } {one two} test domNode-31.13 {insertBefore - node to insert is a sibling of ref node} { set doc [dom parse ] $doc documentElement root $root firstChild a $a insertBefore [$a firstChild] [$a lastChild] set result [$doc asXML -indent none] $doc delete set result } {} test domNode-31.14 {insertBefore - node to insert is a sibling of ref node} { set doc [dom parse ] $doc documentElement root $root firstChild a $a insertBefore [$a firstChild] [$a lastChild] catch {unset result} set node [$a firstChild] while {$node != ""} { lappend result [$node nodeName] set node [$node nextSibling] } $doc delete set result } {one two} test domNode-31.15 {insertBefore - node to insert is a sibling of ref node} { set doc [dom parse ] $doc documentElement root $root firstChild a $a insertBefore [$a firstChild] [$a lastChild] catch {unset result} set node [$a lastChild] while {$node != ""} { lappend result [$node nodeName] set node [$node previousSibling] } $doc delete set result } {two one} test domNode-31.16 {insertBefore - empty ref node} { dom parse doc $doc documentElement root $doc createElement new newNode $root insertBefore $newNode "" set result [$doc asXML -indent none] $doc delete set result } {} test domNode-31.17 {insertBefore - empty ref node} { dom parse doc $doc documentElement root $doc createElement new newNode $root insertBefore $newNode "" set result [$doc asXML -indent none] $doc delete set result } {} test domNode-31.18 {insertBefore - try to insert the root node of the doc} { dom parse doc $doc documentElement root catch {$root insertBefore [$root selectNodes /] [$root firstChild]} errMsg $doc delete set errMsg } {HIERARCHY_REQUEST_ERR} test domNode-31.19 {insertBefore - empty ref node} { dom parse doc $doc documentElement root $root insertBefore [$root firstChild] "" set result [$doc asXML -indent none] $doc delete set result } {} test domNode-31.20 {insertBefore - empty ref node} { dom parse doc $doc documentElement root $root insertBefore [$root firstChild] "" catch {unset result} set node [$root firstChild] while {$node != ""} { lappend result [$node nodeName] set node [$node nextSibling] } $doc delete set result } {b c a} test domNode-31.21 {insertBefore - empty ref node} { dom parse doc $doc documentElement root $root insertBefore [$root firstChild] "" catch {unset result} set node [$root lastChild] while {$node != ""} { lappend result [$node nodeName] set node [$node previousSibling] } $doc delete set result } {a c b} test domNode-31.22 {insertBefore - empty ref node} { dom parse doc $doc documentElement root $root insertBefore [$root lastChild] "" set result [$doc asXML -indent none] $doc delete set result } {} test domNode-31.23 {insertBefore - empty ref node} { dom parse doc $doc documentElement root $root insertBefore [$root lastChild] "" catch {unset result} set node [$root firstChild] while {$node != ""} { lappend result [$node nodeName] set node [$node nextSibling] } $doc delete set result } {a b c} test domNode-31.24 {insertBefore - empty ref node} { dom parse doc $doc documentElement root $root insertBefore [$root lastChild] "" catch {unset result} set node [$root lastChild] while {$node != ""} { lappend result [$node nodeName] set node [$node previousSibling] } $doc delete set result } {c b a} test domNode-31.25 {insertBefore - empty ref node} { dom parse doc $doc documentElement root $root insertBefore [$root selectNodes {*[2]}] "" set result [$doc asXML -indent none] $doc delete set result } {} test domNode-31.26 {insertBefore - empty ref node} { dom parse doc $doc documentElement root $root insertBefore [$root selectNodes {*[2]}] "" catch {unset result} set node [$root firstChild] while {$node != ""} { lappend result [$node nodeName] set node [$node nextSibling] } $doc delete set result } {a c b} test domNode-31.27 {insertBefore - empty ref node} { dom parse doc $doc documentElement root $root insertBefore [$root selectNodes {*[2]}] "" catch {unset result} set node [$root lastChild] while {$node != ""} { lappend result [$node nodeName] set node [$node previousSibling] } $doc delete set result } {b c a} test domNode-31.28 {insertBefore - empty ref node} { dom parse doc $doc documentElement root $root firstChild a $root lastChild b $a insertBefore $b "" set result [$doc asXML -indent none] $doc delete set result } {} test domNode-31.29 {insertBefore - ref node is a node out of the fragment list} { dom parse {} doc $doc documentElement root set newNode [$doc createElement new] set result [catch {$root insertBefore [$root lastChild] $newNode} errMsg] lappend result $errMsg $doc delete set result } {1 NOT_FOUND_ERR} test domNode-31.30 {insertBefore - ref node not a node child, equal to new node} { dom parse {} doc $doc documentElement root set newNode [$doc createElement new] set result [catch {$root insertBefore $newNode $newNode} errMsg] lappend result $errMsg $doc delete set result } {1 NOT_FOUND_ERR} test domNode-32.1 {asText - syntax check} { dom parse doc $doc documentElement root set result [catch {$root asText foo}] $doc delete set result } {1} test domNode-32.2 {asText} { dom parse { pcdata foo bar grill } doc $doc documentElement root set result [$root asText] $doc delete set result } {pcdata foo bar grill} test domNode-32.3 {asText} { dom parse -keepEmpties \ {pcdata Hello, world!]]> more pcdata} doc $doc documentElement root set result [$root asText] $doc delete set result } {pcdata Hello, world! more pcdata} test domNode-32.4 {asText} { dom parse {pcdata} doc $doc documentElement root set newCDATAnode \ [$doc createCDATASection "Hello, world!"] $root appendChild $newCDATAnode set result [$root asText] $doc delete set result } {pcdata} set xml { some text } dom parse $xml doc $doc documentElement root test domNode-32.5 {asText} { $root asText } {some text} test domNode-32.6 {asText} { set result {} foreach child [$root childNodes] { lappend result [$child asText] } set result } {{some text} { A comment } {this is the testPI data }} $doc delete dom parse -keepEmpties $xml doc $doc documentElement root test domNode-32.7 {asText} { $root asText } { some text } $doc delete # The tests in domNode-33.* also uses the nodeCmds created for the # domNode-13.* tests. test domNode-33.1 {insertBeforeFromScript} { set doc [dom parse {}] $doc documentElement root $root insertBeforeFromScript { nodeCmds::e1 } [$root firstChild] set result [$doc asXML -indent none] $doc delete set result } {} test domNode-33.2 {insertBeforeFromScript} { set doc [dom parse {}] $doc documentElement root $root insertBeforeFromScript { nodeCmds::e1 } {} set result [$doc asXML -indent none] $doc delete set result } {} test domNode-33.3 {insertBeforeFromScript - error in the script} { set doc [dom parse {}] $doc documentElement root set result [catch {$root insertBeforeFromScript { nodeCmds::e1 nodeCmds::e1 { # This is intentionally wrong set foo 1 + 1 } } [$root firstChild]}] lappend result [$doc asXML -indent none] $doc delete set result } {1 } test domNode-33.4 {insertBeforeFromScript - insert more then one node} { set doc [dom parse {}] $doc documentElement root namespace eval nodeCmds { $::root insertBeforeFromScript { e1 e2 { t new } e1 } [lindex [$::root childNodes] 1] } set result [$doc asXML -indent none] $doc delete set result } {new} test domNode-33.5 {insertBeforeFromScript - insert more then one node} { set doc [dom parse {}] $doc documentElement root namespace eval nodeCmds { $::root insertBeforeFromScript { e1 e2 { t new } e1 } [lindex [$::root childNodes] 1] } set result "" foreach node [$root childNodes] { append result "[$node nodeName] " } $doc delete set result } {foo e1 e2 e1 bar grill } test domNode-33.6 {insertBeforeFromScript - insert more then one node} { set doc [dom parse {}] $doc documentElement root namespace eval nodeCmds { $::root insertBeforeFromScript { e1 e2 { t new } e1 } [lindex [$::root childNodes] 1] } set result "" set node [$root lastChild] while {$node != ""} { append result "[$node nodeName] " set node [$node previousSibling] } $doc delete set result } {grill bar e1 e2 e1 foo } test domNode-33.7 {insertBeforeFromScript - error in script} { set doc [dom parse {}] $doc documentElement root catch {namespace eval nodeCmds { $::root insertBeforeFromScript { e1 e2 { t new } e1 this is wrong } [lindex [$::root childNodes] 2] }} set result [$doc asXML -indent none] $doc delete set result } {} test domNode-33.8 {insertBeforeFromScript - wrong reference node} { set doc [dom parse {}] $doc documentElement root set result [catch {$root insertBeforeFromScript { nodeCmds::e1 } $root} errMsg] lappend result $errMsg $doc delete set result } {1 NOT_FOUND_ERR} test domNode-34.1 {getBaseURI} {need_uri} { makeFile domNode-34.1-e1.xml [file join [file dir [info script]] data] makeFile domNode-34.1-e2.xml [file join [file dir [info script]] data] set baseURI [tdom::baseURL [file join [pwd] [file dir [info script]] dom.test]] set doc [dom parse \ -baseurl $baseURI \ -externalentitycommand ::tdom::extRefHandler { ]> &a; &b; }] $doc documentElement root set result 1 foreach child [$root childNodes] { lappend baseURIs [$child getBaseURI] } if {([lindex $baseURIs 0] == [lindex $baseURIs 1]) || ([lindex $baseURIs 0] == [lindex $baseURIs 2]) || ([lindex $baseURIs 1] == [lindex $baseURIs 2]) || ([lindex $baseURIs 2] != [$root getBaseURI])} { set result 0 } $doc delete set result } {1} test domNode-34.2 {getBaseURI} {need_uri} { makeFile domNode-34.1-e1.xml [file join [file dir [info script]] data] makeFile domNode-34.1-e2.xml [file join [file dir [info script]] data] set baseURI [tdom::baseURL [file join [pwd] [file dir [info script]] dom.test]] set doc [dom parse \ -baseurl $baseURI \ -externalentitycommand ::tdom::extRefHandler { ]> &a; &b; }] $doc delete set doc [dom parse \ -baseurl $baseURI \ -externalentitycommand ::tdom::extRefHandler { ]> &a; &b; }] $doc documentElement root set result 1 foreach child [$root childNodes] { lappend baseURIs [$child getBaseURI] } if {([lindex $baseURIs 0] == [lindex $baseURIs 1]) || ([lindex $baseURIs 0] == [lindex $baseURIs 2]) || ([lindex $baseURIs 1] == [lindex $baseURIs 2]) || ([lindex $baseURIs 2] != [$root getBaseURI])} { set result 0 } $doc delete set result } {1} proc 35.1 {doc} { $doc documentElement root } test domNode-35.1 {objCmd traces} { for {set x 0} {$x < 1} {incr x} { set doc [dom parse {}] $doc documentElement root 35.1 $doc $doc delete } } {} proc 35.2.2 {doc} { $doc documentElement root } proc 35.2.1 {doc} { $doc documentElement root 35.2.2 $doc return $root } # test domNode-35.2 {objCmd traces} { # set doc [dom parse {}] # set rootCmdName [35.2.1 $doc] # set result [info commands $rootCmdName] # $doc delete # set result # } {} proc 35.3.2 {doc} { $doc documentElement root $doc delete } proc 35.3.1 {doc} { $doc documentElement root 35.3.2 $doc return $root } test domNode-35.3 {objCmd traces} { set doc [dom parse {}] set rootCmdName [35.3.1 $doc] set result [info commands $rootCmdName] set result } {} test domNode-36.1 {nodeName} { set doc [dom parse ] set cdataNode [$doc createCDATASection foo] set result [$cdataNode nodeName] $doc delete set result } \#cdata-section test domNode-36.2 {nodeName} { set doc [dom parse ] set commentNode [$doc createComment foo] set result [$commentNode nodeName] $doc delete set result } \#comment test domNode-36.3 {nodeName} { set doc [dom parse ] set piNode [$doc createProcessingInstruction p "p value"] set result [$piNode nodeName] $doc delete set result } p proc 37.1 {base system public} { return [list string file://this/that \ "External general parsed entity. Text and elements at\ toplevel mixed and so on"] } test domNode-37.1 {baseURI} { set doc [dom parse \ -baseurl "file://foo" \ -externalentitycommand 37.1 -keepEmpties { ]> &a;}] set root [$doc documentElement] set result [$root baseURI] foreach node [$root childNodes] { lappend result [expr {"file://this/that" == [$node baseURI]}] } $doc delete set result } {file://foo 0 1 1 1 1 0} test domNode-37.2 {baseURI} { set doc [dom parse \ -baseurl "file://foo" \ -externalentitycommand 37.1 -keepEmpties { ]> &a;}] set root [$doc documentElement] $root insertBefore [$root lastChild] [$root firstChild] set result {} foreach node [$root childNodes] { lappend result [$node baseURI] } $doc delete set result } {file://foo file://this/that file://this/that file://this/that} test domNode-37.3 {baseURI} { set doc [dom parse \ -baseurl "file://foo" \ -externalentitycommand 37.1 -keepEmpties { ]> &a;}] set root [$doc documentElement] $root appendChild [$root firstChild] set result {} foreach node [$root childNodes] { lappend result [$node baseURI] } $doc delete set result } {file://this/that file://this/that file://this/that file://foo} proc 37.4 {base systemId publicId} { switch $systemId { "a.xml" { return [list string file://base/2 "&b;"] } "b.xml" { return [list string file://base/3 ""] } default { error "error in text script" } } } test domNode-37.4 {baseURI} { set doc [dom parse \ -baseurl "file://base/1" \ -externalentitycommand 37.4 { ]> &a;}] set root [$doc documentElement] set result [$root baseURI] set rootchild [$root firstChild] lappend result [$rootchild baseURI] set rootchildchild [$rootchild firstChild] lappend result [$rootchildchild baseURI] lappend result [[$rootchildchild firstChild] baseURI] lappend result [[$rootchildchild nextSibling] baseURI] lappend result [[$rootchild nextSibling] baseURI] $doc delete set result } {file://base/1 file://base/2 file://base/3 file://base/3 file://base/2 file://base/1} proc 37.5 {base systemId publicId} { switch $systemId { "a.xml" { return [list string file://base/2 "&b;"] } "b.xml" { return [list string file://base/3 ""] } default { error "error in text script" } } } test domNode-37.5 {baseURI} { set doc [dom parse \ -baseurl "file://base/1" \ -externalentitycommand 37.5 { ]> &a;}] set result {} set node [$doc documentElement] while {$node != ""} { lappend result [$node baseURI] set node [$node firstChild] } $doc delete set result } {file://base/1 file://base/1 file://base/1 file://base/2 file://base/2 file://base/3 file://base/3 file://base/3} proc 37.6 {base systemId publicId} { switch $systemId { "a.xml" { return [list string file://base/2 "text"] } default { error "error in text script" } } } test domNode-37.6 {baseURI} { set doc [dom parse \ -baseurl "file://base/1" \ -externalentitycommand 37.6 { ]> &a;}] set result {} set root [$doc documentElement] foreach child [$root childNodes] { lappend result [$child baseURI] } $doc delete set result } {file://base/2 file://base/2 file://base/2 file://base/1} proc 37.7 {base systemId publicId} { switch $systemId { "a.xml" { return [list string file://base/2 "text - base2"] } default { error "error in text script" } } } test domNode-37.7 {baseURI} { set doc [dom parse \ -baseurl "file://base/1" \ -externalentitycommand 37.7 { ]> &a;text - base 1}] set result {} set root [$doc documentElement] foreach child [$root childNodes] { lappend result [$child baseURI] } $doc delete set result } {file://base/2 file://base/2 file://base/2 file://base/1 file://base/1} test domNode-38.1 {toXPath - comment node} { set doc [dom parse { foo}] set root [$doc documentElement] set result {} foreach comment [$root selectNodes comment()] { lappend result [$comment toXPath] } $doc delete set result } {/root/comment()} test domNode-38.2 {toXPath - top level comment} { set doc [dom parse { foo}] set result {} foreach toplevelcomment [$doc selectNodes /comment()] { lappend result [$toplevelcomment toXPath] } $doc delete set result } [list {/comment()[1]} {/comment()[2]} {/comment()[3]}] test domNode-38.3 {toXPath - syntax} -setup { set doc [dom parse ] set root [$doc documentElement] } -body { catch {$root toXPath foo bar} errMsg set errMsg } -cleanup { $doc delete } -match regexp -result {wrong # args: should be "domNode(0x)?[[:xdigit:]]+ toXPath \?-legacy\?"} test domNode-38.4 {toXPath - default xml namespace} -setup { set doc [dom parse {}] $doc selectNodesNamespaces {foo foo} set root [$doc documentElement] set foo1 [$root selectNodes foo:foo] set xfo1 [$foo1 toXPath] } -body { expr {$foo1 == [[$foo1 ownerDocument] selectNodes [$foo1 toXPath]]} } -cleanup { $doc delete } -result 1 test domNode-38.5 {toXPath - default xml namespace} -setup { set doc [dom parse { some text }] set root [$doc documentElement] $doc selectNodesNamespaces {foo foo} set foo2 [$root selectNodes {foo:foo[2]}] } -body { expr {$foo2 == [[$foo2 ownerDocument] selectNodes [$foo2 toXPath]]} } -cleanup { $doc delete } -result 1 test domNode-38.6 {toXPath - xml namespace} -setup { set doc [dom parse { some text }] set root [$doc documentElement] $doc selectNodesNamespaces {foo foo} set foo2 [$root selectNodes {foo:foo[2]}] } -body { expr {$foo2 == [[$foo2 ownerDocument] selectNodes [$foo2 toXPath]]} } -cleanup { $doc delete } -result 1 test domNode-38.7 {toXPath - pathological xml namespace} -setup { set doc [dom parse { some text }] set root [$doc documentElement] $doc selectNodesNamespaces {foo foo} set foo2 [$root selectNodes {foo:foo[2]}] } -body { expr {$foo2 == [[$foo2 ownerDocument] selectNodes [$foo2 toXPath]]} } -cleanup { $doc delete } -result 1 test domNode-38.8 {toXPath - pathological xml namespace} -setup { set doc [dom parse { text some text text }] } -body { set result "" foreach node [$doc selectNodes //node()] { if {$node != [[$node ownerDocument] selectNodes [$node toXPath]]} { set result [$node toXPath] break } } set result } -cleanup { $doc delete } -result "" test domNode-38.9 {toXPath - really long element name} -constraints { knownBug } -setup { set doc [dom parse "<[string repeat abc 100]/>"] set root [$doc documentElement] set firstChild [$root firstChild] } -body { $firstChild toXPath } -cleanup { $doc delete } -result "/doc/[string repeat abc 100]" test domNode-39.1 {text} { set doc [dom parse {text bold more text}] $doc documentElement root set result [$root text] $doc delete set result } {text more text} test domNode-40.1 {laststring} { set doc [dom parse {foobar}] $doc documentElement root set result [$root selectNodes string(e)] lappend result [$root selectNodes laststring(e)] lappend result [$root selectNodes laststring(dontExists)] $doc delete set result } {foo bar {}} test domNode-999.1 {move nodes from one doc to another} { set doc1 [dom parse {}] set doc2 [dom parse {text}] set root1 [$doc1 documentElement] set root2 [$doc2 documentElement] $root1 appendChild [$root2 firstChild] set textNode [[$root1 firstChild] firstChild] if {[$textNode ownerDocument] == $doc1} {set result 1} else {set result 0} $doc1 delete $doc2 delete set result } {1} test domNode-999.2 {node references should not change even after renumbering} { dom parse {} doc set root [$doc documentElement] set oldNode [lindex [$root childNodes] 1] dom parse {} tempDoc set tempNode [$tempDoc documentElement] $oldNode appendChild $tempNode set childList1 [$root childNodes] $root selectNodes {//child[@name='a']} set childList2 [$root childNodes] if {$childList1 == $childList2} { set result 1 } else { set result 0 } $doc delete $tempDoc delete set result } {1} # cleanup ::tcltest::cleanupTests return tdom-0.9.6-src/tests/domnamespace.test0000644000175000017500000004340315025767703016463 0ustar rolfrolf# Features covered: Namespace related DOM actions. # # This file contains a collection of tests for some namespace related # actions. # # domnamespace-1.*: misc tests # domnamespace-2.*: moving namespaced nodes from one document to another # domnamespace-3.*: moving namespaced nodes within a document # domnamespace-4.*: createNodeCmd and namespaces # # Copyright (c) 2002 Rolf Ade. # # RCS: @(#) $Id$ source [file join [file dir [info script]] loadtdom.tcl] test domnamespace-1.1 {multiple definition of the same namespace (same prefix/uri)} { set ch [open [file join [pwd] [file dir [info script]] data/REC-xslt-19991116.xml]] fconfigure $ch -encoding iso8859-1 set doc [dom parse -channel $ch] set root [$doc documentElement] set nodes [$root selectNodes //e:element-syntax] $doc delete llength $nodes } {35} test domnamespace-1.2 {more than 128 different namespaces in one doc} { set doc [dom parse { }] $doc documentElement root set result [[$root firstChild] namespace] lappend result [[$root lastChild] namespace] $doc delete set result } {n0 n129} test domnamespace-2.1 {moving namespaced nodes between documents} { set doc1 [dom parse {}] set root1 [$doc1 documentElement] set doc2 [dom parse {}] set root2 [$doc2 documentElement] $root2 appendChild [$root1 firstChild] set result [$root2 asXML -indent none] $doc1 delete $doc2 delete set result } {} test domnamespace-2.2 {moving namespaced nodes between documents} { set doc1 [dom parse {}] set root1 [$doc1 documentElement] set doc2 [dom parse {}] set root2 [$doc2 documentElement] set node [$root1 removeChild [$root1 firstChild]] $root2 appendChild $node set result [$root2 asXML -indent none] $doc1 delete $doc2 delete set result } {} test domnamespace-2.3 {moving namespaced nodes between documents} { set doc1 [dom parse {}] set root1 [$doc1 documentElement] set doc2 [dom parse {}] set root2 [$doc2 documentElement] set node [$root1 removeChild [$root1 firstChild]] $root2 appendChild $node set result [$root2 asXML -indent none] $doc1 delete $doc2 delete set result } {} test domnamespace-2.4 {moving namespaced nodes between documents} { set doc1 [dom parse {}] set root1 [$doc1 documentElement] set doc2 [dom parse {}] set root2 [$doc2 documentElement] set node [$root1 removeChild [$root1 firstChild]] $root2 appendChild $node set result [$root2 asXML -indent none] $doc1 delete $doc2 delete set result } {} test domnamespace-2.5 {moving namespaced nodes between documents} { set doc1 [dom parse {}] set root1 [$doc1 documentElement] set doc2 [dom parse {}] set root2 [$doc2 documentElement] set node [$root1 removeChild [$root1 firstChild]] $root2 appendChild $node set result [llength [$root2 getElementsByTagNameNS "" *]] $doc1 delete $doc2 delete set result } {2} test domnamespace-2.6 {moving namespaced nodes between documents} { set doc1 [dom parse {}] set root1 [$doc1 documentElement] set doc2 [dom parse {}] set root2 [$doc2 documentElement] set node [$root1 removeChild [$root1 firstChild]] $root2 appendChild $node set result [$root2 asXML -indent none] $doc1 delete $doc2 delete set result } {} test domnamespace-2.7 {moving namespaced nodes between documents} { set doc1 [dom parse {}] set root1 [$doc1 documentElement] set doc2 [dom parse {}] set root2 [$doc2 documentElement] $root2 appendChild [[$root1 firstChild] cloneNode -deep] set result [$root2 asXML -indent none] $doc1 delete $doc2 delete set result } {} test domnamespace-2.8 {moving namespaced nodes between documents} { set doc1 [dom parse {}] set root1 [$doc1 documentElement] set doc2 [dom parse {}] set root2 [$doc2 documentElement] $root2 appendChild [$root1 firstChild] set result [$root2 asXML -indent none] $doc1 delete $doc2 delete set result } {} test domnamespace-2.9 {moving namespaced nodes between documents} { set doc1 [dom parse {}] set root1 [$doc1 documentElement] set doc2 [dom parse {}] set root2 [$doc2 documentElement] $root2 appendChild [$root1 firstChild] set result [$root2 asXML -indent none] $doc1 delete $doc2 delete set result } {} test domnamespace-2.10 {moving nodes with attributes between documents} { set doc1 [dom parse {}] set root1 [$doc1 documentElement] set doc2 [dom parse {}] set root2 [$doc2 documentElement] set node [$root1 removeChild [$root1 firstChild]] $root2 appendChild $node set result [$root2 asXML -indent none] $doc1 delete $doc2 delete set result } {} test domnamespace-2.11 {moving nodes with namespaced attributes between documents} { set doc1 [dom parse {}] set root1 [$doc1 documentElement] set doc2 [dom parse {}] set root2 [$doc2 documentElement] set node [$root1 removeChild [$root1 firstChild]] $root2 appendChild $node set result [$root2 asXML -indent none] $doc1 delete $doc2 delete set result } {} test domnamespace-2.12 {moving nodes with namespaced attributes between documents} { set doc1 [dom parse {}] set root1 [$doc1 documentElement] set doc2 [dom parse {}] set root2 [$doc2 documentElement] set node [$root1 removeChild [$root1 firstChild]] $root2 appendChild $node $root2 setAttributeNS "" "xmlns:p" "foo" set result [$root2 selectNodes {//@p:*}] $doc1 delete $doc2 delete set result } {{p:b c}} test domnamespace-2.13 {moving nodes with namespaced attributes between documents} { set doc1 [dom parse {}] set root1 [$doc1 documentElement] set doc2 [dom parse {}] set root2 [$doc2 documentElement] set node [$root1 removeChild [$root1 firstChild]] $root2 setAttributeNS "" "xmlns:p" "foo" $root2 appendChild $node set result [$root2 asXML -indent none] $doc1 delete $doc2 delete set result } {} test domnamespace-2.14 {moving nodes with namespaced attributes between documents} { set doc1 [dom parse {}] set root1 [$doc1 documentElement] set doc2 [dom parse {}] set root2 [$doc2 documentElement] set node [$root1 removeChild [$root1 firstChild]] [$root2 firstChild] appendChild $node set result [$root2 asXML -indent none] $doc1 delete $doc2 delete set result } {} test domnamespace-2.15 {moving nodes with namespaced attributes between documents} { set doc1 [dom parse {}] set root1 [$doc1 documentElement] set doc2 [dom parse {}] set root2 [$doc2 documentElement] set node [$root1 removeChild [$root1 firstChild]] [$root2 firstChild] appendChild $node set nodes [$doc2 getElementsByTagNameNS "NS1" *] catch {unset result} foreach node $nodes { lappend result [$node nodeName] } $doc1 delete $doc2 delete set result } {doc1elem a} test domnamespace-2.16 {It is not recommended to create attributes that look like namespace declarations} { set doc [[dom parse {}] documentElement] set child [[dom parse {}] documentElement] $child setAttribute xmlns "foo" $doc appendChild $child $doc asXML -indent none } {} test domnamespace-2.17 {It is not recommended to create xml namespace declarations} { set doc [[dom parse {}] documentElement] set child [[dom parse {}] documentElement] $child setAttributeNS "" xmlns "foo" $doc appendChild $child $doc asXML -indent none } {} test domnamespace-3.1 {moving namespaced nodes within a document} { set doc [dom parse {}] set root [$doc documentElement] set nodeToMove [$doc selectNodes {/doc/node()[1]/node()[1]}] set newParent [$doc selectNodes {/doc/node()[2]}] $newParent appendChild $nodeToMove set result [$doc asXML -indent none] $doc delete set result } {} namespace eval nodeCmds { dom createNodeCmd -namespace foo.bar elementNode ns1:e1 dom createNodeCmd -namespace foo.bar elementNode e1 dom createNodeCmd textNode t dom createNodeCmd -tagName e1 elementNode e1NoNS } test domnamespace-4.1 {createNodeCmd and namespace} { dom createDocument doc doc $doc documentElement root $root appendFromScript { nodeCmds::ns1:e1 {nodeCmds::t "this"} } set result [$doc asXML -indent none] $doc delete set result } {this} test domnamespace-4.2 {createNodeCmd and namespace} { dom createDocumentNS foo.bar ns1:doc doc $doc documentElement root $root appendFromScript { nodeCmds::ns1:e1 {nodeCmds::t "this"} } set result [$doc asXML -indent none] $doc delete set result } {this} test domnamespace-4.3 {createNodeCmd and namespace} { dom createDocumentNS foo.bar doc doc $doc documentElement root $root appendFromScript { nodeCmds::ns1:e1 {nodeCmds::t "this"} } set result [$doc asXML -indent none] $doc delete set result } {this} test domnamespace-4.4 {createNodeCmd and namespace} { dom createDocumentNS foo.bar doc doc $doc documentElement root $root appendFromScript { nodeCmds::e1 { nodeCmds::e1NoNS att attValue {nodeCmds::t "this"} } } set result [$doc asXML -indent none] $doc delete set result } {this} test domnamespace-4.5 {createNodeCmd and namespace} { dom createDocumentNS foo.bar doc doc $doc documentElement root $root appendFromScript { nodeCmds::e1 { nodeCmds::e1NoNS att attValue {nodeCmds::t "this"} } } set result [$doc selectNodes -namespaces {fb foo.bar} string(/fb:doc/fb:e1/e1/@att)] $doc delete set result } {attValue} test domnamespace-4.6 {createNodeCmd and namespace} { set xml { } dom parse $xml doc $doc selectNodesNamespaces {w http://schemas.openxmlformats.org/wordprocessingml/2006/main} set result [$doc selectNodes -list {/w:styles/w:style string(@w:styleId)}] $doc delete set result } {Normal Heading} namespace eval nodeCmds { set w http://schemas.openxmlformats.org/wordprocessingml/2006/main dom createNodeCmd -namespace $w elementNode w:style dom createNodeCmd -namespace $w -noNamespacedAttributes elementNode w:stylenna } test domnamespace-4.7 {createNodeCmd and namespace} { dom createDocumentNS http://schemas.openxmlformats.org/wordprocessingml/2006/main w:styles doc $doc documentElement root $root appendFromScript { nodeCmds::w:style w:type paragraph w:styleId Normal nodeCmds::w:style w:type paragraph w:styleId Heading } $doc selectNodesNamespaces {w http://schemas.openxmlformats.org/wordprocessingml/2006/main} set result [$doc selectNodes -list {/w:styles/w:style string(@w:styleId)}] $doc delete set result } {Normal Heading} test domnamespace-4.8 {createNodeCmd and namespace} { dom createDocumentNS http://schemas.openxmlformats.org/wordprocessingml/2006/main w:styles doc $doc documentElement root $doc selectNodesNamespaces { w http://schemas.openxmlformats.org/wordprocessingml/2006/main t http://schemas.openxmlformats.org/wordprocessingml/2006/main } $root appendFromScript { nodeCmds::w:style t:type paragraph t:styleId Normal nodeCmds::w:style w:type paragraph w:styleId Heading } set result [$doc selectNodes -list {/w:styles/w:style string(@w:styleId)}] $doc delete set result } {Normal Heading} test domnamespace-4.9 {createNodeCmd and namespace} { dom createDocumentNS http://schemas.openxmlformats.org/wordprocessingml/2006/main w:styles doc $doc documentElement root $root appendFromScript { nodeCmds::w:style w:type paragraph w:styleId Normal xml:space preserve nodeCmds::w:style w:type paragraph w:styleId Heading } set result [$root selectNodes -list {w:style string(@w:styleId)}] $doc delete set result } {Normal Heading} test domnamespace-4.9.1 {createNodeCmd and namespace} { dom createDocumentNS http://schemas.openxmlformats.org/wordprocessingml/2006/main w:styles doc $doc documentElement root $root appendFromScript { nodeCmds::w:style {w:type paragraph w:styleId Normal xml:space preserve} {} nodeCmds::w:style {w:type paragraph w:styleId Heading} {} } set result [$root selectNodes -list {w:style string(@w:styleId)}] $doc delete set result } {Normal Heading} test domnamespace-4.10 {createNodeCmd and namespace} { dom createDocumentNS http://schemas.openxmlformats.org/wordprocessingml/2006/main w:styles doc $doc documentElement root $root appendFromScript { nodeCmds::w:stylenna w:styleId Normal } set result [$root selectNodes -list {w:stylenna string(@w:styleId)}] $doc delete set result } {{}} # cleanup ::tcltest::cleanupTests return tdom-0.9.6-src/tests/domDoc.test0000644000175000017500000017213415025767703015240 0ustar rolfrolf# Features covered: domDoc and docObj command # # This file contains a collection of tests for the two interfaces to # DOM docs, the token interface (the domDoc command) and the tcl # command interface ([$docObj method ...]). # # domDoc-1.*: asXML, asHTML # domDoc-2.*: publicId, systemId # domDoc-3.*: toXSLTcmd # domDoc-4.*: asText # domDoc-5.*: normalize # domDoc-6.*: nodetype # domDoc-7.*: insertBefore # domDoc-8.*: insertBeforeFromScript # domDoc-9.*: replaceChild # domDoc-10.*: getElementById # domDoc-11.*: firstChild # domDoc-12.*: lastChild # domDoc-13.*: appendChild # domDoc-14.*: removeChild # domDoc-15.*: hasChildNodes # domDoc-16.*: childNodes # domDoc-17.*: ownerDocument # domDoc-18.*: appendFromList # domDoc-19.*: appendXML # domDoc-20.*: selectNodes # domDoc-21.*: baseURI # domDoc-22.*: appendFromScript # domDoc-23.*: getElementsByTagNameNS # domDoc-24.*: cdataSectionElements # domDoc-25.*: selectNodesNamespaces # domDoc-26.*: fragments list # domDoc-27.*: deleteXPathCache # domDoc-28.*: createElementNS # domDoc-29.*: asCanonicalXML # domDoc-30.*: command argument parsing # # Copyright (c) 2004 - 2007 Rolf Ade. source [file join [file dir [info script]] loadtdom.tcl] test domDoc-1.1 {asXML -escapeNonASCII} { set doc [dom parse [tdom::xmlReadFile \ [file join [file dir [info script]] data/i18n_1.xml]]] set result [$doc asXML -escapeNonASCII] $doc delete set result } {абвгдежзий } test domDoc-1.2 {asXML -escapeNonASCII; comments and PI's are not altered} { set doc [dom parse [tdom::xmlReadFile \ [file join [file dir [info script]] data/i18n_2.xml]]] set result [$doc asXML -indent none -escapeNonASCII] $doc delete set result } " german umlauts: äöüß " test domDoc-1.3 {asHTML -escapeNonASCII -htmlEntities} { set doc [dom parse {äü„‟†}] set result [$doc asHTML -escapeNonASCII -htmlEntities] $doc delete set result } {äü„‟†} test domDoc-1.3.1 {asHTML -htmlEntities} { set doc [dom parse -html {&}] set result [$doc asHTML -htmlEntities] $doc delete set result } {&} test domDoc-1.3.2 {asHTML -htmlEntities} { set doc [dom parse -html "\u205F\u200A"] set result [$doc asHTML -htmlEntities] $doc delete set doc [dom parse -html "\u205F"] append result [$doc asHTML -htmlEntities] $doc delete set doc [dom parse -html "\u200A"] append result [$doc asHTML -htmlEntities] $doc delete set result } {    } test domDoc-1.3.3 {asHTML -htmlEntities} { set doc [dom parse -html "fj"] set result [$doc asHTML -htmlEntities] $doc delete set result } {fj} test domDoc-1.3.4 {asHTML -htmlEntities} { set doc [dom parse -html "≪̸≪≪⃒\u226A\u20D2"] set result [$doc asHTML -htmlEntities] $doc delete set result } {≪̸≪≪⃒≪⃒} test domDoc-1.3.3 {asHTML -htmlEntities} { set doc [dom parse -html "𝕫"] set result [$doc asHTML -htmlEntities] $doc delete set result } {𝕫} set doc [dom parse ] test domDoc-1.4 {asXML -doctypeDeclaration} { $doc asXML -doctypeDeclaration 1 } { } test domDoc-1.5 {asXML -doctypeDeclaration without boolean value (error)} { set errMsg "" catch {$doc asXML -doctypeDeclaration} errMsg set errMsg } {-doctypeDeclaration must have a boolean value as argument} test domDoc-1.6 {asXML -doctypeDeclaration 0} { $doc asXML -doctypeDeclaration 0 } { } $doc delete test domDoc-1.7 {asXML -doctypeDeclaration} { set doc [dom parse {}] set result [$doc asXML -doctypeDeclaration 1] $doc delete set result } { } test domDoc-1.8 {asXML -doctypeDeclaration} { set doc [dom parse {}] set result [$doc asXML -doctypeDeclaration 1] $doc delete set result } { } test domDoc-1.9 {asXML -doctypeDeclaration} { set doc [dom parse {}] set result [$doc asXML -doctypeDeclaration true] $doc delete set result } { } test domDoc-1.10 {asXML - unknown option} { set doc [dom parse {}] set errMsg "" catch {$doc asXML -fooOption 1} errMsg $doc delete set errMsg } {bad option "-fooOption": must be -indent, -channel, -escapeNonASCII, -doctypeDeclaration, -xmlDeclaration, -encString, -escapeAllQuot, -indentAttrs, -nogtescape, -noEmptyElementTag, -escapeCR, or -escapeTab} test domDoc-1.11 {asXML - non boolean value to -doctypeDeclaration} { set doc [dom parse {}] set errMsg "" catch {$doc asXML -doctypeDeclaration foo} errMsg $doc delete set errMsg } {expected boolean value but got "foo"} test domDoc-1.12 {asXML - shortened option} { set doc [dom parse {}] set result [$doc asXML -doctype 1] $doc delete set result } { } test domDoc-1.13 {asHTML -doctypeDeclaration} { set doc [dom createDocument HTML] set result [$doc asHTML -doctypeDeclaration 1] $doc delete set result } { } test domDoc-1.14 {asHTML -doctypeDeclaration} { set doc [dom parse {

    boo

    }] set result [$doc asHTML -doctypeDeclaration 1] $doc delete set result } {

    boo

    } test domDoc-1.15 {asXML - processing-instruction without pi value} { set doc [dom parse {}] set result [$doc asXML -indent none] $doc delete set result } {} test domDoc-1.16 {asXML - processing-instruction without pi value} { set doc [dom parse {}] set result [$doc asXML -indent none] $doc delete set result } {} test domDoc-1.17 {asHTML - content of script/style tags} { set doc [dom parse { }] set result [$doc asHTML] $doc delete set result } { } test domDoc-1.18 {asXML -escapeAllQuot} { set doc [dom parse {This is "strange"}] set result [$doc asXML -escapeAllQuot] $doc delete set result } {This is "strange" } test domDoc-1.19 {asXML -escapeAllQuot} { set doc [dom parse {This is "strange"}] set result [$doc asXML] $doc delete set result } {This is "strange" } test domDoc-1.20 {asXML - indentation of comments} { set doc [dom parse { }] set result [$doc asXML -indent 4] $doc delete set result } { } test domDoc-1.21 {asXML -indentAttrs} { set doc [dom parse {}] set result [$doc asXML -indentAttrs 4] $doc delete set result } { } test domDoc-1.22 {asXML} { set doc [dom createDocument doc] set result [$doc asXML] $doc delete set result } { } test domDoc-1.23 {asXML -xmlDeclaration} { set doc [dom createDocument doc] set result [$doc asXML -xmlDeclaration 1] $doc delete set result } { } test domDoc-1.23 {asXML -xmlDeclaration} { set doc [dom createDocument doc] set result [$doc asXML -xmlDeclaration 1] $doc delete set result } { } test domDoc-1.24 {asXML just -encString without -xmlDeclaration} { set doc [dom createDocument doc] set result [$doc asXML -encString foo] $doc delete set result } { } test domDoc-1.25 {asXML -xmlDeclaration -encString} { set doc [dom createDocument doc] set result [$doc asXML -xmlDeclaration 1 -encString foo] $doc delete set result } { } test domDoc-1.26 {asXML -xmlDeclaration, encoding set by encoding method} { set doc [dom createDocument doc] $doc encoding "foo" set result [$doc asXML -xmlDeclaration 1] $doc delete set result } { } test domDoc-1.27 {asXML -xmlDeclaration -encString} { set doc [dom createDocument doc] set result [catch { [$doc asXML -xmlDeclaration 1 -encString foo \ -encString bar -wrongOption] }] $doc delete set result } 1 test domDoc-1.28 {asXML -xmlDeclaration not xml compliant -encString} { set doc [dom createDocument doc] set result [$doc asXML -xmlDeclaration 1 -encString 1\u2345] $doc delete set result } [subst -nocommands -novariables { }] test domDoc-1.29 {asXML -nogtescape} { set doc [dom parse {>}] set result [$doc asXML -nogtescape -indent none] $doc delete set result } {>} test domDoc-1.30 {asXML -noEmptyElementTag} { set doc [dom parse {}] set result [$doc asXML -noEmptyElementTag -indent none] $doc delete set result } {} test domDoc-1.31 {asXML '"' in attribute value} { # emacs: " set doc [dom createDocument doc] set root [$doc documentElement] $root setAttribute attr "foo\"bar" set result [$doc asXML -indent none] $doc delete set result } {} test domDoc-1.32 {asXML -indent tabs} { set doc [dom parse {
    }] set result [$doc asXML -indent tabs] $doc delete set result } "\n\t\n\t\t\n\t\n\n" test domDoc-1.33 {asXML -indent tabs} { set doc [dom parse {}] set result [$doc asXML -indent tabs] $doc delete set result } "\n\t\n\t\t\n\t\n\t\n\t\t\n\t\t\t\n\t\t\n\t\n\t\n\n" test domDoc-1.34 {asXML -indent tabs -noEmptyElementTag} { set doc [dom parse {}] set result [$doc asXML -indent tabs -noEmptyElementTag] $doc delete set result } "\n\t\n\t\t\n\t\n\t\n\t\t\n\t\t\t\n\t\t\n\t\n\t\n\n" test domDoc-1.35 {asXML -indent tabs -indentAttrs tabs} { set doc [dom parse {}] set result [$doc asXML -indent tabs -indentAttrs tabs] $doc delete set result } "\n\t\n\t\t\n\t\n\t\n\t\t\n\t\t\t\n\t\t\n\t\n\t\n\n" test domDoc-1.36 {asXML -indent tabs -indentAttrs } { set doc [dom parse {}] set result [$doc asXML -indent tabs -indentAttrs 2] $doc delete set result } "\n\t\n\t\t\n\t\n\t\n\t\t\n\t\t\t\n\t\t\n\t\n\t\n\n" test domDoc-1.37 {asHTML -onlyContents} { set doc [dom parse {

    boo

    }] set result [[$doc documentElement] asHTML -onlyContents] $doc delete set result } {

    boo

    } test domDoc-1.38 {asHTML -breakLines} { set doc [dom parse {

    boo

    }] set result [$doc asHTML -breakLines] $doc delete set result } {

    boo

    } set doc [dom parse ] test domDoc-2.1 {publicId - no publicId there} { $doc publicId } {} test domDoc-2.2 {systemId - no systemId there} { $doc systemId } {} $doc delete set doc [dom parse {}] test domDoc-2.3 {publicId from parsed document} { $doc publicId } {-//foo//DTD bar x.y//EN} test domDoc-2.4 {systemId from parsed document} { $doc systemId } {file:///boo.baz} $doc delete set doc [dom parse {}] test domDoc-2.5 {publicId but document has only SYSTEM} { $doc publicId } {} test domDoc-2.6 {systemId, document has only SYSTEM} { $doc systemId } {file:///boo.baz} test domDoc-2.7 {publicId - set public identifier} { set result [$doc publicId "file:///woo.hoo"] append result " [$doc publicId]" } { file:///woo.hoo} test domDoc-2.8 {publicId - set public identifier} { $doc publicId "http://www.tdom.org" $doc asXML -indent no -doctypeDeclaration 1 } { } test domDoc-2.9 {systemId - set system identifier} { set result [$doc systemId "file:///woo.hoo"] append result " [$doc systemId]" } {file:///boo.baz file:///woo.hoo} test domDoc-2.10 {systemId - set system identifier} { $doc systemId "file:///whooze.moo" $doc asXML -indent no -doctypeDeclaration 1 } { } test domDoc-2.11 {publicId - set to empty string} { $doc publicId "" $doc asXML -indent no -doctypeDeclaration 1 } { } test domDoc-2.12 {systemId - set to empty string} { $doc systemId "" $doc asXML -indent no -doctypeDeclaration 1 } { } $doc delete set doc [dom parse ] set xslt1 { } test domDoc-3.1 {toXSLTcmd} { set xslt [dom parse -keepEmpties $xslt1] set xsltCmd [$xslt toXSLTcmd] $xsltCmd -parameters {param2 newValue param3 "this Value"} $doc resultDoc set result [$resultDoc asXML -indent none] $resultDoc delete $xsltCmd -parameters {param1 "that Value"} $doc resultDoc append result [$resultDoc asXML -indent none] $resultDoc delete $xsltCmd -parameters {param3 "another" param1 "and this"} $doc resultDoc append result [$resultDoc asXML -indent none] $resultDoc delete rename $xsltCmd {} set result } {param1Default newValue this Value that Value param2Default param3Default and this param2Default another } set xslt2 { dummy result This is from xsl:message } proc msgCmd1 {msg terminate} { global result append result "msgCmd1: $msg " } proc msgCmd2 {msg terminate} { global result append result "msgCmd2: $msg" } test domDoc-3.2 {toXSLTcmd} { set xslt [dom parse -keepEmpties $xslt2] set xsltCmd [$xslt toXSLTcmd] set result "" $xsltCmd -xsltmessagecmd msgCmd1 $doc resultDoc $resultDoc delete $xsltCmd -xsltmessagecmd msgCmd2 $doc resultDoc $resultDoc delete rename $xsltCmd {} set result } {msgCmd1: This is from xsl:message msgCmd2: This is from xsl:message} test domDoc-3.3 {toXSLTcmd} { set xslt [dom parse -keepEmpties $xslt1] set xsltCmd [$xslt toXSLTcmd] set result [catch {$xsltCmd -bogusOption foo $doc resultDoc} errMsg] lappend result $errMsg lappend result [catch {$xsltCmd $doc resultDoc}] lappend result [$resultDoc asXML -indent none] $resultDoc delete rename $xsltCmd {} set result } {1 {bad option "-bogusOption": must be -parameters, -ignoreUndeclaredParameters, -maxApplyDepth, or -xsltmessagecmd} 0 {param1Default param2Default param3Default }} test domDoc-3.4 {toXSLTcmd} { set xslt [dom parse -keepEmpties $xslt1] set xsltCmd [$xslt toXSLTcmd] set result [catch {$xsltCmd -xsltmessagecmd msgCmd1} errMsg] rename $xsltCmd {} lappend result $errMsg } {1 {wrong # args: should be "?-parameters parameterList? ?-ignoreUndeclaredParameters? ?-maxApplyDepth int? ?-xsltmessagecmd cmd? ?objVar?"}} test domDoc-3.5 {toXSLTcmd} { set xslt [dom parse -keepEmpties $xslt1] set xsltCmd [$xslt toXSLTcmd] set result [catch {$xsltCmd $doc resultDoc bogus} errMsg] rename $xsltCmd {} lappend result $errMsg } {1 {wrong # args: should be "?-parameters parameterList? ?-ignoreUndeclaredParameters? ?-maxApplyDepth int? ?-xsltmessagecmd cmd? ?objVar?"}} test domDoc-3.6 {toXSLTcmd} { set xslt [dom parse -keepEmpties $xslt1] set xsltCmd [$xslt toXSLTcmd] set result [catch {$xsltCmd -parameters {param1 foo} -parameters {param2 foo} $doc resultDoc} errMsg] rename $xsltCmd {} lappend result $errMsg } {1 {only one -parameters option allowed}} test domDoc-3.7 {toXSLTcmd} { set xslt [dom parse -keepEmpties $xslt1] set xsltCmd [$xslt toXSLTcmd] set result [catch {$xsltCmd}] $xsltCmd delete set result } {1} test domDoc-3.8 {toXSLTcmd} { set xslt [dom parse -keepEmpties $xslt1] set xsltCmd [$xslt toXSLTcmd] set result [catch {$xsltCmd delete bogus}] $xsltCmd delete set result } {1} test domDoc-3.9 {toXSLTcmd} { set xslt [dom parse -keepEmpties $xslt1] set xsltCmd [$xslt toXSLTcmd] set result [catch {$xsltCmd transform} errMsg] $xsltCmd delete set result } {1} test domDoc-3.10 {toXSLTcmd} { set xslt [dom parse -keepEmpties $xslt1] set xsltCmd [$xslt toXSLTcmd] $xsltCmd transform $doc resultDoc set result [$resultDoc asXML -indent none] $resultDoc delete $xsltCmd delete set result } {param1Default param2Default param3Default } set xslt3 { mixed element this is more text } test domDoc-3.11 {toXSLTcmd} { set xslt [dom parse -keepEmpties $xslt3] set xsltCmd [$xslt toXSLTcmd] set result [list] for {set x 0} {$x < 2} {incr x} { $xsltCmd $doc resultDoc lappend result [lsort [$resultDoc cdataSectionElements *]] lappend result [$resultDoc asXML -indent none] $resultDoc delete } $xsltCmd delete set result } {{b bar doc foo} {} {b bar doc foo} {}} $doc delete test domDoc-4.1 {asText - syntax check} { dom parse doc set result [catch {$doc asText foo}] $doc delete set result } {1} test domDoc-4.2 {asText} { dom parse {pcdata foo bar grill} doc set result [$doc asText] $doc delete set result } {pcdata foo bar grill} test domDoc-4.3 {asText} { dom parse {pcdata Hello, world!]]> more pcdata} doc set result [$doc asText] $doc delete set result } {pcdata Hello, world! more pcdata} test domDoc-4.4 {asText} { dom parse {pcdata} doc $doc documentElement root set newCDATAnode \ [$doc createCDATASection "Hello, world!"] $root appendChild $newCDATAnode set result [$doc asText] $doc delete set result } {pcdata} test domDoc-4.5 {asText} { dom parse {encoded chars: > < & " '} doc set result [$doc asText] $doc delete set result } {encoded chars: > < & " '} # emacs: " test domDoc-5.1 {normalize} { set doc [dom parse text] $doc documentElement root set cdataNode [$doc createCDATASection "cdata section text"] set child [$root firstChild] $child appendChild $cdataNode $doc normalize set result [llength [$child childNodes]] lappend result [[$child firstChild] data] $doc delete set result } {2 text} test domDoc-5.2 {normalize} { set doc [dom parse text] $doc documentElement root set cdataNode [$doc createCDATASection "cdata section text"] set child [$root firstChild] $child appendChild $cdataNode $doc normalize -forXPath set result [llength [$child childNodes]] lappend result [[$child firstChild] data] $doc delete set result } {1 {textcdata section text}} test domDoc-5.3 {normalize} { set doc [dom parse ] $doc documentElement root set cdataNode [$doc createCDATASection "cdata section text"] set textNode [$doc createTextNode text] set child [$root firstChild] $child appendChild $cdataNode $child appendChild $textNode set result [llength [$child childNodes]] $doc normalize -forXPath lappend result [llength [$child childNodes]] lappend result [[$child firstChild] data] $doc delete set result } {2 1 {cdata section texttext}} test domDoc-5.4 {normalize} { set doc [dom parse ] $doc documentElement root set cdataNode [$doc createCDATASection "cdata section text"] set child [$root firstChild] $child appendChild $cdataNode $doc normalize set result [$cdataNode nodeType] $doc normalize -forXPath lappend result [$cdataNode nodeType] $doc delete set result } {CDATA_SECTION_NODE TEXT_NODE} test domDoc-5.5 {normalize} { set doc [dom parse ] $doc documentElement root set textNode [$doc createTextNode ""] set child [$root firstChild] $child appendChild $textNode set result [llength [$child childNodes]] $doc normalize lappend result [llength [$child childNodes]] $doc delete set result } {1 0} test domDoc-5.6 {normalize} { set doc [dom parse ] $doc documentElement root set cdataNode [$doc createCDATASection ""] set child [$root firstChild] $child appendChild $cdataNode $doc normalize set result [llength [$child childNodes]] $doc normalize -forXPath lappend result [llength [$child childNodes]] $doc delete set result } {1 0} test domDoc-6.1 {nodeType} { set doc [dom parse ] set result [$doc nodeType] $doc delete set result } {DOCUMENT_NODE} test domDoc-6.2 {nodeType} { set doc [dom parse ] set result [catch {$doc nodeType foo}] $doc delete set result } {1} test domDoc-7.1 {insertBefore} { set doc [dom parse {}] set root [$doc documentElement] set newPI [$doc createProcessingInstruction myPI pivalue] $doc insertBefore $newPI $root set result [$doc asXML -indent none] $doc delete set result } {} test domDoc-7.2 {insertBefore} { set doc [dom parse {}] set newPI [$doc createProcessingInstruction myPI pivalue] $doc insertBefore $newPI "" set result [$doc asXML -indent none] $doc delete set result } {} test domDoc-7.3 {insertBefore} { set doc [dom parse {}] set newPI [$doc createProcessingInstruction myPI pivalue] set root [$doc documentElement] set child [$root firstChild] set result [catch {$doc insertBefore $newPI $child} errMsg] lappend result $errMsg $doc delete set result } {1 NOT_FOUND_ERR} namespace eval nodeCmds { dom createNodeCmd elementNode e1 dom createNodeCmd elementNode e2 dom createNodeCmd commentNode c dom createNodeCmd textNode t dom createNodeCmd cdataNode cdata dom createNodeCmd piNode pi dom createNodeCmd parserNode parser } test domDoc-8.1 {insertBeforeFromScript} { set doc [dom parse {}] $doc documentElement root $doc insertBeforeFromScript { nodeCmds::e1 } $root set result [$doc asXML -indent none] $doc delete set result } {} test domDoc-8.2 {insertBeforeFromScript} { set doc [dom parse {}] $doc insertBeforeFromScript { nodeCmds::e1 } "" set result [$doc asXML -indent none] $doc delete set result } {} test domDoc-8.3 {insertBeforeFromScript} { set doc [dom parse {}] $doc documentElement root set result [catch {$root insertBeforeFromScript { nodeCmds::e1 nodeCmds::e1 { # This is intentionally wrong set foo 1 + 1 } } $root}] lappend result [$doc asXML -indent none] $doc delete set result } {1 } test domDoc-9.1 {replaceChild} { set doc [dom parse {}] set root [$doc documentElement] set newNode [$doc createElement newNode] $doc replaceChild $newNode $root set result [$doc asXML -indent none] lappend result [[$doc documentElement] nodeName] $doc delete set result } { newNode} set getElementByIdSetup { set doc [dom parse { ]> }] } test domDoc-10.1 {getElementById} -setup $getElementByIdSetup -body { set result [[$doc getElementById "4a"] @name] lappend result [$doc getElementById "dontexists"] } -cleanup { $doc delete } -result {that {}} test domDoc-10.2 {getElementById - only IDs at parsing time will be found} \ -setup $getElementByIdSetup -body { set root [$doc documentElement] set elemNode [$root selectNodes {elem[3]}] if {[$elemNode hasAttribute id]} { error "error in the test code" } $elemNode setAttribute id "new" $doc getElementById "new" } -cleanup { $doc delete } -result {} test domDoc-10.3 {getElementById} -setup $getElementByIdSetup -body { set root [$doc documentElement] set elemNode [$root selectNodes {elem[2]}] if {![$elemNode hasAttribute id]} { error "error in the test code" } $elemNode setAttribute id "new" [$doc getElementById "new"] getAttribute name } -cleanup { $doc delete } -result that test domDoc-10.4 {getElementById} -setup $getElementByIdSetup -body { set root [$doc documentElement] set elemNode [$root selectNodes {elem[2]}] if {![$elemNode hasAttribute id]} { error "error in the test code" } $root removeChild $elemNode [$doc getElementById "4a"] getAttribute name } -cleanup { $doc delete } -result that test domDoc-10.5 {getElementById} -setup $getElementByIdSetup -body { set root [$doc documentElement] set elemNode [$root selectNodes {elem[2]}] if {![$elemNode hasAttribute id]} { error "error in the test code" } $elemNode removeAttribute id $doc getElementById "4a" } -cleanup { $doc delete } -result {} test domDoc-11.1 {firstChild} { set doc [dom createDocumentNode] set result [$doc firstChild] $doc delete set result } {} test domDoc-11.2 {firstChild} { set doc [dom parse ] set result [[$doc firstChild] nodeName] $doc delete set result } {root} test domDoc-11.3 {firstChild} { set doc [dom parse {}] set result [[$doc firstChild] nodeName] $doc delete set result } {beforeRoot} test domDoc-11.4 {firstChild} { set doc [dom parse {}] set node [$doc firstChild] set newNode [$doc createElement newNode] $doc insertBefore $newNode $node set result [[$doc firstChild] nodeName] $doc delete set result } {newNode} test domDoc-11.5 {Delete top level node} { set doc [dom parse {}] [$doc firstChild] delete set result [$doc asXML -indent none] $doc delete set result } {} test domDoc-11.6 {Delete top level node} { set doc [dom parse {}] [$doc documentElement] delete set result [$doc asXML -indent none] $doc delete set result } {} test domDoc-12.1 {lastChild} { set doc [dom createDocumentNode] set result [$doc lastChild] $doc delete set result } {} test domDoc-12.2 {lastChild} { set doc [dom parse ] set result [[$doc lastChild] nodeName] $doc delete set result } {root} test domDoc-12.3 {lastChild} { set doc [dom parse {}] set result [[$doc lastChild] nodeName] $doc delete set result } {afterRoot} test domDoc-12.4 {lastChild} { set doc [dom parse {}] set newNode [$doc createElement newNode] $doc appendChild $newNode set result [[$doc lastChild] nodeName] lappend result [[$doc lastChild] parentNode] $doc delete set result } {newNode {}} test domDoc-13.1 {appendChild} { set doc [dom parse {}] set newNode [$doc createElement newNode] $doc appendChild $newNode set newNode [$doc createComment "a comment"] $doc appendChild $newNode set newNode [$doc createProcessingInstruction this that] $doc appendChild $newNode set newNode [$doc createTextNode "text"] $doc appendChild $newNode set result [$doc asXML -indent none] $doc delete set result } {text} test domDoc-13.2 {appendChild} { set doc [dom createDocumentNode] set newNode [$doc createElement newNode] $doc appendChild $newNode set result [[$doc documentElement] nodeName] $doc delete set result } {newNode} test domDoc-13.3 {appendChild} { set doc [dom createDocumentNode] set newNode [$doc createElement newNode] $doc appendChild $newNode set result [[$doc documentElement] parentNode] $doc delete set result } {} test domDoc-14.1 {removeChild} { set doc [dom parse {}] $doc removeChild [$doc firstChild] set result [$doc documentElement] $doc delete set result } {} test domDoc-14.2 {removeChild} { set doc [dom parse {}] $doc removeChild [$doc firstChild] set result [$doc asXML -indent none] $doc delete set result } {} test domDoc-14.3 {removeChild} { set doc [dom createDocumentNode] set result [catch {$doc removeChild [$doc firstChild]}] $doc delete set result } {1} test domDoc-15.1 {hasChildNodes} { set doc [dom createDocumentNode] set result [$doc hasChildNodes] set newNode [$doc createElement newNode] $doc appendChild $newNode lappend result [$doc hasChildNodes] $doc delete set result } {0 1} test domDoc-16.1 {childNodes} { set doc [dom parse {}] set result {} foreach node [$doc childNodes] { lappend result [$node nodeName] } $doc delete set result } {beforeRoot root afterRoot} test domDoc-17.1 {ownerDocument} { set doc [dom parse ] set result [expr {$doc == [$doc ownerDocument]}] $doc delete set result } {1} test domDoc-18.1 {appendFromList} { set doc [dom createDocumentNode] $doc appendFromList {elem {} {}} set node [$doc documentElement] set result [list [$node nodeName] [$node parentNode]] $doc delete set result } {elem {}} test domDoc-19.1 {appendXML} { set doc [dom createDocumentNode] $doc appendXML footext set result [$doc asXML -indent none] $doc delete set result } {footext} test domDoc-19.2 {appendXML} { set doc [dom createDocumentNode] $doc appendXML footext set result [[$doc documentElement] nodeName] lappend result [[$doc documentElement] parentNode] lappend result [expr {$doc == [[$doc documentElement] ownerDocument]}] $doc delete set result } {test {} 1} test domDoc-19.3 {appendXML} { set doc [dom createDocument foo] $doc appendXML footext set result [[$doc documentElement] nodeName] set result [$doc asXML -indent none] $doc delete set result } {footext} test domDoc-19.4 {appendXML XML namespaces} { dom createDocumentNS ns:a docroot doc $doc documentElement root $root setAttributeNS "" xmlns:b "ns:b" "" xmlns:c "ns:c" $root appendXML {John} $doc selectNodesNamespaces "a ns:a b ns:b c ns:c" set name [$doc selectNodes string(a:docroot/c:person/c:name)] $doc delete set name } {John} test domDoc-19.5 {appendXML XML namespaces} { dom createDocumentNS ns:a docroot doc $doc documentElement root $root setAttributeNS "" xmlns:b "ns:b" "" xmlns:c "ns:c" $root appendXML {John} $doc selectNodesNamespaces "a ns:a b ns:b c ns:c" set name [$doc selectNodes string(a:docroot/c:person/a:name)] $doc delete set name } {John} test domDoc-19.6 {appendXML XML namespaces} { dom createDocumentNS ns:c docroot doc $doc documentElement root $root setAttributeNS "" xmlns:b "ns:b" "" xmlns:a "ns:a" $root appendXML {Eve} $doc selectNodesNamespaces "a ns:a b ns:b c ns:c" set name [$doc selectNodes string(c:docroot/c:person/c:name)] $doc delete set name } {Eve} test domDoc-19.7 {appendXML XML namespaces} { dom createDocument docroot doc $doc documentElement root $root setAttributeNS "" xmlns:b "ns:b" "" xmlns:c "ns:c" $root appendXML {Eve} $doc selectNodesNamespaces "foo ns:c" set name [$doc selectNodes string(docroot/foo:person/foo:name)] $doc delete set name } {Eve} test domDoc-20.1 {selectNodes} { set doc [dom parse {}] set result [[$doc selectNodes {root/child[2]}] getAttribute id] $doc delete set result } {2} test domDoc-20.2 {selectNodes} { set doc [dom parse {}] set result [[$doc selectNodes {/root/child[2]}] getAttribute id] $doc delete set result } {2} test domDoc-20.3 {selectNodes} { set doc [dom parse {}] set result [list] foreach node [$doc selectNodes *] { lappend result [$node nodeName] } set result } {root} test domDoc-20.4 {selectNodes} { set doc [dom parse {}] set result [list] foreach node [$doc selectNodes node()] { lappend result [$node nodeType] } set result } {COMMENT_NODE ELEMENT_NODE PROCESSING_INSTRUCTION_NODE} test domDoc-20.5 {selectNodes with -namespaces option} { set doc [dom createDocumentNS "http://tdom.org" tdom:doc] set node [$doc selectNodes \ -namespaces {tdom http://tdom.org} \ tdom:doc] set result [$node nodeName] set node [$doc selectNodes \ -namespaces {myPrefix http://tdom.org} \ myPrefix:doc] lappend result [$node nodeName] lappend result [$doc selectNodes -namespaces {} doc typeVar] lappend result $typeVar $doc delete set result } [list tdom:doc tdom:doc "" empty] test domDoc-20.6 {selectNodes with -namespaces option} { set doc [dom createDocumentNS "http://tdom.org" tdom:doc] set node [$doc selectNodes \ -namespaces {foo bar} \ -namespaces {a b c d} \ -namespaces {tdom http://tdom.org} \ tdom:doc] set result [$node nodeName] set node [$doc selectNodes \ -namespaces {myPrefix http://tdom.org} \ myPrefix:doc] lappend result [$node nodeName] lappend result [$doc selectNodes -namespaces {} doc typeVar] lappend result $typeVar $doc delete set result } [list tdom:doc tdom:doc "" empty] test domDoc-20.7 {selectNodes with -namespaces option} { set doc [dom createDocumentNS "http://tdom.org" tdom:doc] catch {set node [$doc selectNodes \ -namespaces {foo bar} \ -namespaces {a b c d} \ -namespaces {wrong_not_pair} \ tdom:doc]} errMsg $doc delete set errMsg } {The "-namespaces" option requires a 'prefix namespace' pairs list as argument} test domDoc-20.8 {selectNodes with -list option} { set doc [dom parse { one two three four }] set result [$doc selectNodes -list { doc/product/descshort string() }] $doc delete set result } {one two {three four}} test domDoc-20.9 {selectNodes - type result} { set doc [dom parse { one }] set result "" lappend result [$doc selectNodes {string(doc/product[1]/descshort)} typeVar] lappend result $typeVar lappend result [$doc selectNodes {string(doc/product[2]/descshort)} typeVar] lappend result $typeVar lappend result [$doc selectNodes {string(doc/product[3]/descshort)} typeVar] lappend result $typeVar $doc delete set result } {one string {} string {} string} test domDoc-20.10 {selectNodes with -list option} { set doc [dom parse { one two three four }] set result [$doc selectNodes -list { doc/product/descshort string() } typeVar] $doc delete lappend result $typeVar } {one two {three four} string} test domDoc-20.11 {selectNodes with -list option} { set doc [dom parse { one two three four }] set result [$doc selectNodes -list { doc/product/dontexists string() } typeVar] $doc delete list $result $typeVar } {{} empty} test domDoc-21.1 {baseURI} { set doc [dom createDocumentNode] set result [$doc baseURI] $doc delete set result } {} test domDoc-21.2 {baseURI} { set doc [dom parse -baseurl file://foo ] set result [$doc baseURI] $doc baseURI http://that.this lappend result [$doc baseURI] $doc delete set result } {file://foo http://that.this} namespace eval nodeCmds { dom createNodeCmd elementNode e1 dom createNodeCmd elementNode e2 dom createNodeCmd commentNode c dom createNodeCmd textNode t dom createNodeCmd cdataNode cdata dom createNodeCmd piNode pi dom createNodeCmd parserNode parser } test domDoc-22.1 {appendFromScript} { set doc [dom createDocumentNode] $doc appendFromScript nodeCmds::e1 set result [$doc asXML -indent none] lappend result [[$doc documentElement] nodeName] $doc delete set result } { e1} test domDoc-22.2 {appendFromScript} { set doc [dom parse ] $doc appendFromScript { nodeCmds::e1 nodeCmds::e2 } # namespace eval nodeCmds { # $doc appendFromScript { # e1 # e2 # } # } set result [$doc asXML -indent none] foreach node [$doc selectNodes *] { lappend result [$node parentNode] lappend result [expr {$doc == [$node ownerDocument]}] } $doc delete set result } { {} 1 {} 1 {} 1} test domDoc-22.3 {appendFromScript} { set doc [dom createDocumentNode] set nrOfNodeCmdsBefore [info commands domNode*] $doc appendFromScript { nodeCmds::e1 } $doc delete set nrOfNodeCmdsAfter [info commands domNode*] expr {$nrOfNodeCmdsBefore == $nrOfNodeCmdsAfter} } {1} test domDoc-22.4 {nodeCmd called outside of *FromScript context} { dom createNodeCmd elementNode e catch e } 1 test domDoc-22.5 {nodeCmd use in child interp while in nodeCmd context} { set doc [dom createDocument this] set root [$doc documentElement] dom createNodeCmd elementNode thise dom createNodeCmd textNode t interp create childinterp load {} Tdom childinterp childinterp eval { dom createNodeCmd elementNode childe dom createNodeCmd textNode t } set result [catch {$root appendFromScript { thise { childinterp eval { childe { t "other" } } t "some" } }}] $doc delete interp delete childinterp set result } {1} test domDoc-22.6 {nodeCmd use in child interp while in nodeCmd context} { set doc [dom createDocument this] set root [$doc documentElement] dom createNodeCmd elementNode thise dom createNodeCmd textNode t interp create childinterp load {} Tdom childinterp childinterp eval { dom createNodeCmd elementNode childe dom createNodeCmd textNode t set doc [dom createDocument child] set root [$doc documentElement] } $root appendFromScript { thise { childinterp eval { $root appendFromScript { childe { t "other" } } } t "some" } } set result [$doc asXML -indent none] append result [childinterp eval {$doc asXML -indent none}] $doc delete interp delete childinterp set result } {someother} test domDoc-23.1 {getElementsByTagNameNS} { dom createNodeCmd elementNode child set doc [dom createDocument root] $doc documentElement root $root appendFromScript { for {set x 0} {$x < 250} {incr x} { child [list xmlns ns$x] {} } } set xml [$doc asXML] $doc delete set doc [dom parse $xml] set result 1 for {set x 0} {$x < 250} {incr x} { set nodes [$doc getElementsByTagNameNS ns$x *] if {[llength $nodes] != 1} { set result 0 } } $doc delete set result } {1} test domDoc-24.1 {cdataSectionElements} { set doc [dom parse {Some Text}] set result [catch {$doc cdataSectionElements} errMsg] lappend result $errMsg $doc delete set result } {1 {wrong # args: should be " cdataSectionElements ?URI:?localname ?boolean?"}} test domDoc-24.2 {cdataSectionElements} { set doc [dom parse {Some Text}] set result [catch {$doc cdataSectionElements foo bar grill} errMsg] lappend result $errMsg $doc delete set result } {1 {wrong # args: should be " cdataSectionElements ?URI:?localname ?boolean?"}} test domDoc-24.3 {cdataSectionElements} { set doc [dom parse {Some Text}] set result [catch {$doc cdataSectionElements root foo} errMsg] lappend result $errMsg $doc delete set result } {1 {expected boolean value but got "foo"}} test domDoc-24.4 {cdataSectionElements} { set doc [dom parse {Some Text}] set result [$doc cdataSectionElements root] $doc delete set result } {0} test domDoc-24.5 {cdataSectionElements} { set doc [dom parse {Some Text}] set result [$doc cdataSectionElements root 0] lappend result [$doc cdataSectionElements root 1] lappend result [$doc cdataSectionElements root 0] $doc delete set result } {0 1 0} test domDoc-24.6 {cdataSectionElements} { set doc [dom parse {Some Text}] set result [$doc cdataSectionElements root 1] lappend result [$doc asXML -indent none] $doc delete set result } {1 {}} test domDoc-24.7 {cdataSectionElements} { set doc [dom parse {<foo>}] foreach element {foo root bar grill} { $doc cdataSectionElements $element 1 } set result [$doc asXML -indent none] $doc delete set result } {]]>} test domDoc-24.8 {cdataSectionElements} { set doc [dom parse {text ]}] $doc cdataSectionElements root 1 set result [$doc asXML -indent none] $doc delete set result } {} test domDoc-24.9 {cdataSectionElements} { set doc [dom parse {text ]]}] $doc cdataSectionElements root 1 set result [$doc asXML -indent none] $doc delete set result } {} test domDoc-24.10 {cdataSectionElements} { set doc [dom parse {text ]]>}] $doc cdataSectionElements root 1 set result [$doc asXML -indent none] $doc delete set result } {]]>} test domDoc-24.11 {cdataSectionElements} { set doc [dom parse {text ]]> text]]>text}] $doc cdataSectionElements root 1 set result [$doc asXML -indent none] $doc delete set result } { text]]]]>text]]>} test domDoc-24.12 {cdataSectionElements} { set doc [dom parse {text}] $doc cdataSectionElements http://foo.bar:root 1 set result [$doc asXML -indent none] $doc delete set result } {} test domDoc-24.13 {cdataSectionElements} { set doc [dom parse {text}] set result [$doc cdataSectionElements ""] $doc delete set result } {0} test domDoc-24.14 {cdataSectionElements} { set doc [dom parse {text}] set result [$doc cdataSectionElements *] $doc delete set result } {} test domDoc-24.15 {cdataSectionElements} { set doc [dom parse {text}] foreach elem {foo bar grill root http://www.foo.org:baz} { $doc cdataSectionElements $elem 1 } foreach elem {foo grill} { $doc cdataSectionElements $elem 0 } set result [lsort [$doc cdataSectionElements *]] $doc delete set result } {bar http://www.foo.org:baz root} test domDoc-24.16 {cdataSectionElements} { set doc [dom parse {some text}] $doc documentElement root set node [$root firstChild] $doc cdataSectionElements child 1 set result [$node asXML -indent none] $doc delete set result } {} test domDoc-24.17 {cdataSectionElements} { set doc [dom parse {some text more text text again}] $doc cdataSectionElements child 1 set result [$doc asXML -indent none] $doc delete set result } {more text} test domDoc-25.1 {selectNodesNamespaces} { set doc [dom createDocument foo] set result [$doc selectNodesNamespaces] $doc delete set result } {} test domDoc-25.2 {selectNodesNamespaces} { set doc [dom createDocument foo] set result [list [$doc selectNodesNamespaces] \ [$doc selectNodesNamespaces {}] \ [$doc selectNodesNamespaces]] $doc delete set result } {{} {} {}} test domDoc-25.3 {selectNodesNamespaces} { set doc [dom createDocument foo] set result [list [$doc selectNodesNamespaces] \ [$doc selectNodesNamespaces {prefix http://foo.org/uri}] \ [$doc selectNodesNamespaces] \ [$doc selectNodesNamespaces {}]] $doc delete set result } {{} {prefix http://foo.org/uri} {prefix http://foo.org/uri} {}} test domDoc-25.4 {selectNodesNamespaces} { set doc [dom createDocument foo] set result [catch {$doc selectNodesNamespaces wrong} errMsg] lappend result $errMsg $doc delete set result } {1 {The optional argument to selectNodesNamespaces must be a 'prefix namespace' pairs list}} test domDoc-25.5 {selectNodesNamespaces} { set doc [dom parse { }] $doc selectNodesNamespaces {default1 rootdefaultNS} set node [$doc selectNodes default1:root] set result [list [$node prefix] [$node localName]] $doc delete set result } {{} root} test domDoc-25.6 {selectNodesNamespaces} { set doc [dom parse { }] $doc selectNodesNamespaces {default2 elem1NS default1 rootdefaultNS} set node [$doc selectNodes default1:root/default2:elem1] set result [list [$node prefix] [$node localName]] set node [$doc selectNodes default1:root/default2:elem1/default2:elem11] lappend result [$node nodeName] [$node namespaceURI] $doc delete set result } {{} elem1 elem11 elem1NS} test domDoc-25.7 {selectNodesNamespaces} { set doc [dom parse { }] $doc selectNodesNamespaces {default2 elem1NS default1 rootdefaultNS} set node [$doc selectNodes default1:root/default2:elem1] set result [list [$node prefix] [$node localName]] set node [$doc selectNodes default1:root/default2:elem1/elem11] lappend result [$node nodeName] [$node namespaceURI] $doc delete set result } {{} elem1 elem11 {}} test domDoc-25.7.1 {selectNodesNamespaces} { set doc [dom parse { }] $doc documentElement root $root firstChild elem1 $doc createElement elem11 elem11 $elem1 appendChild $elem11 $doc selectNodesNamespaces {default2 elem1NS default1 rootdefaultNS} set node [$doc selectNodes default1:root/default2:elem1] set result [list [$node prefix] [$node localName]] set node [$doc selectNodes default1:root/default2:elem1/elem11] lappend result [$node nodeName] [$node namespaceURI] $doc delete set result } {{} elem1 elem11 {}} test domDoc-25.8 {selectNodesNamespaces} { set doc [dom parse { }] $doc selectNodesNamespaces {default2 elem1NS default1 rootdefaultNS} set result [catch {set node [$doc selectNodes \ -namespaces { dflt1 elem1NS dflt2 rootdefaultNS } \ default1:root/dflt1:elem1/elem11]} errMsg] lappend result $errMsg $doc delete set result } {1 {Prefix doesn't resolve}} test domDoc-25.9 {selectNodesNamespaces} { set doc [dom parse { }] $doc selectNodesNamespaces {default2 elem1NS default1 rootdefaultNS} set node [$doc selectNodes default1:root/default2:elem1] set result [list [$node prefix] [$node localName]] set node [$doc selectNodes \ -namespaces {dflt1 elem1NS dflt2 rootdefaultNS} \ dflt2:root/dflt1:elem1/elem11] lappend result [$node nodeName] [$node namespaceURI] $doc delete set result } {{} elem1 elem11 {}} test domDoc-26.1 {Fragment list} { set doc [dom parse { text1text2text3}] $doc removeChild [$doc firstChild] $doc documentElement root for {set i 1} {$i < 4} {incr i} { set removedNode$i [$root removeChild [$root firstChild]] } $removedNode2 delete $root appendChild $removedNode3 $root appendChild $removedNode1 set result [$doc asXML -indent none] $doc delete set result } {text3text1} test domDoc-27.1 {deleteXPathCache} { set doc [dom createDocument doc] set result [list] lappend result [$doc deleteXPathCache foo/bar] $doc selectNodes -cache 1 2+2 lappend result [$doc deleteXPathCache foo/bar] lappend result [$doc deleteXPathCache 2+2] lappend result [$doc deleteXPathCache] $doc selectNodes -cache 1 2+2 $doc delete set result } {{} {} {} {}} test domDoc-28.1 {createElementNS} { set doc [dom createDocument doc] set newElem [$doc createElementNS uri ns:e] $doc documentElement root $root appendChild $newElem set result [$doc asXML -indent none] $doc delete set result } {} test domDoc-28.2 {createElementNS} { set doc [dom createDocument doc] set newElem [$doc createElementNS uri ns:e] $newElem setAttributeNS uri ns:att value $doc documentElement root $root appendChild $newElem set result [$doc selectNodes -namespaces {ns uri} string(/doc/ns:e/@ns:att)] $doc delete set result } {value} test domDoc-28.3 {createElementNS} { set doc [dom createDocument doc] catch {$doc createElementNS "" e} errMsg $doc delete set errMsg } {Missing URI in Namespace declaration} test domDoc-29.1 {asCanonicalXML} { set doc [dom parse -keepEmpties { Hello, world! }] set result [$doc asCanonicalXML] $doc delete set result } { Hello, world! } test domDoc-29.2 {asCanonicalXML} { set doc [dom parse -keepEmpties { Hello, world! }] set result [$doc asCanonicalXML -comments 1] $doc delete set result } { Hello, world! } test domDoc-29.3 {asCanonicalXML} { set doc [dom parse -keepEmpties { A B A B A B C }] set result [$doc asCanonicalXML] $doc delete set result } { A B A B A B C } test domDoc-29.5 {asCanonicalXML} { set doc [dom parse -keepEmpties {]> }] set result [$doc asCanonicalXML] $doc delete set result } { } test domDoc-29.6 {asCanonicalXML} { set doc [dom parse -keepEmpties { ]> First line Second line 2 "0" && value<"10" ?"valid":"error"]]> valid }] set result [$doc asCanonicalXML] $doc delete set result } { First line Second line 2 value>"0" && value<"10" ?"valid":"error" valid } proc 29.7 {base system public} { switch $system { "world.txt" { return [list "string" "" "world"] } "earth.gif" { return [list "string" "" ""] } default { error "unexpected system URL '$system'" } } } test domDoc-29.7 {asCanonicalXML} { set doc [dom parse -externalentitycommand 29.7 -keepEmpties { ]> &ent1;, &ent2;! }] set result [$doc asCanonicalXML] $doc delete set result } { Hello, world! } test domDoc-29.8 {asCanonicalXML} { set doc [dom parse -keepEmpties { ©}] set result [$doc asCanonicalXML] $doc delete set result } "\u00A9" test domDoc-30.1 {cmd argument parsing} { set result [catch {domDoc} errMsg] lappend result $errMsg catch {domDoc foo} errMsg lappend result $errMsg } {1 {wrong # args: should be "domDoc doctoken subcommand ?arg ...?"} {wrong # args: should be "domDoc doctoken subcommand ?arg ...?"}} test domDoc-30.2 {cmd argument parsing} { set storedMode [dom setObjectCommands] dom setObjectCommands token set doc [dom parse {}] catch {domDoc $doc} result domDoc $doc delete dom setObjectCommands $storedMode set result } {wrong # args: should be "domDoc doctoken subcommand ?arg ...?"} test domDoc-30.3 {cmd argument parsing} -body { set doc [dom parse {}] catch {$doc} result $doc delete set result } -match regexp -result {wrong # args: should be "domDoc[^ ]+ subcommand \?arg ...\?"} test domDoc-30.4 {cmd argument parsing} -body { set storedMode [dom setObjectCommands] dom setObjectCommands token set doc [dom parse {}] catch {domDoc $doc invalid-method} result domDoc $doc delete dom setObjectCommands $storedMode set result } -match glob -result {bad method "invalid-method": must be *} test domDoc-30.5 {cmd argument parsing} -body { set doc [dom parse {}] catch {$doc invalid-method} result $doc delete set result } -match glob -result {bad method "invalid-method": must be *} # test domDoc-29.9 {asCanonicalXML} { # set doc [dom parse -keepEmpties {}] # set result [$doc asCanonicalXML] # $doc delete # set result # } {} # cleanup ::tcltest::cleanupTests return tdom-0.9.6-src/pkgIndex.tcl.in0000644000175000017500000000064115025767703014643 0ustar rolfrolf# # Tcl package index file # if {[package vsatisfies [package provide Tcl] 9.0-]} { package ifneeded @PACKAGE_NAME@ @PACKAGE_VERSION@ \ "[list load [file join $dir @PKG_LIB_FILE9@]]; [list source [file join $dir tdom.tcl]]" } else { package ifneeded @PACKAGE_NAME@ @PACKAGE_VERSION@ \ "[list load [file join $dir @PKG_LIB_FILE8@]]; [list source [file join $dir tdom.tcl]]" } tdom-0.9.6-src/.fossil-settings/0000755000175000017500000000000015025767703015173 5ustar rolfrolftdom-0.9.6-src/.fossil-settings/ignore-glob0000644000175000017500000000017015025767703017320 0ustar rolfrolf*/win/Debug* */win/Release* */win/version*.vc */win/nmakehlp.exe */win/nmakehlp.obj */win/nmakehlp.out */win/_junk.pch tdom-0.9.6-src/.fossil-settings/manifest0000644000175000017500000000000315025767703016715 0ustar rolfrolfon tdom-0.9.6-src/.fossil-settings/manifest.no-warn0000644000175000017500000000000015025767703020272 0ustar rolfrolftdom-0.9.6-src/.fossil-settings/crlf-glob0000644000175000017500000000000615025767703016761 0ustar rolfrolf*.vc tdom-0.9.6-src/manifest0000644000175000017500000004735115025767703013523 0ustar rolfrolfC Silenced\san\sunwarranted\scompiler\swarning. D 2025-06-22T11:57:55.485 F .fossil-settings/crlf-glob 3fc81610a0f32c43d5830d2e2b08d1a0cbfb74f5 F .fossil-settings/ignore-glob bdfbbdd88f6c9099755206650cd164eb37aca373 F .fossil-settings/manifest a09a968bf05a50058f3ad50132730b719bc39e76 F .fossil-settings/manifest.no-warn da39a3ee5e6b4b0d3255bfef95601890afd80709 F CHANGES 2b32e159f7bd49b7acb6a4707b6047ba845f309c48183005574baa06178cd6a9 F ChangeLog 9b60ec8bfbae84e4f1a97aaee24be00ccea212b7 F LICENSE 7c00b00fe8e88c48498a54c103dd7df03faeeb039c783279d5fb54dfca307b77 F MPL_2.0.html 326b847674d6f5846c5b260fb437372e21232c23e3911f3a94f766a62459126c F Makefile.in 8752adb175f09928e5ed7d1b27f145691491ee10413ad0679028f013a56bb1bc F README.AOL 80ae877757122817d25588f0ce22cc33ca1119d08fa4e446d6032bffabc3d5f4 F README.md 796da47e9110460cffe54ed194b966c237c1e6aa9e85ca702632e05c016d4d23 F aclocal.m4 5d1a079a02416ab1653487c02261ecf7b7a3c2b7 F apps/toschema.tcl d9cb806e8f1a10ee9a6d6e8b3bd5944124a12001a086b5bc8511b6e92f9af620 F apps/xslt.tcl 5e5b959e926828ae4e145b45678132ab624767f77f1362d125f32a2bdb88fb7d F configure b39a12e2c0a0caa1db28fc1250bfdab1a110ccaf5f95f9e9c2be7ed27c470127 x F configure.ac 3419719d2e64e4f38fcf362b98b02da874a4d27e25aa943a53b10a988aad2afe F doc/INDEX.MAP f93457c791c96b711048a2a9f4ecf98ef5475c4220611c415f26654d9062c6bf F doc/README 706bce83708ba3eb9a81452364ab445c79e63ace F doc/category-index.html accaaafe7a78cdeb049a78a3bb70a09fea74253412541d297b977fa965810d57 F doc/dom.html cee5dccdc0e42057992df5175fbbb672675510b2f4f5150610580dc7a7fd0545 F doc/dom.n 57411563693fbeb4470a9987a4faec8b30947cf7f24eb17ad764cf4c30da6d0b F doc/dom.xml 0005fffba663ef2aabc9a4319ee8ff9e5a241882501dedf244135ae394e0869b F doc/domDoc.html 4bfb6ca4d655e8276aa1ec772450e2dc8f4f4a5ff182cbbff95d67579c63a5ec F doc/domDoc.n e6a096be1d924465b005718228ccc212c81da2d678ee4abcc5805585c66f0b6f F doc/domDoc.xml 0f02b326fae96fa07567195a4276d1b10586445fb1dca27f6a6f34b18160448e F doc/domNode.html a0b16ba8f6aceeaf35f5f66109cd753cac430aeb72aa1249dd6d7a5568126d14 F doc/domNode.n a179fc0819ae012a6d4a3005de8164490edb0e0f6c7b5b5e5cc2164d33ba6ea1 F doc/domNode.xml 800e4a95f2d41c55da096b72c84d3659b7fd4a7d73e9903707c03e0c236eea73 F doc/expat.html 11beb7f63ba8a33eca588ae1c7c89f352d62834152f93bd14497b070ad6b81a4 F doc/expat.n 4bafabf8790fbfde99904f0498f74ebb9fafa3d6adf48f349cb1858e3ccc528f F doc/expat.xml 3fabc575f8af185bca350a4ce5e452e1ec084f8e2c1182ee637f3eb2f7b43b9d F doc/expatapi.html 7b3467af8fb48953e2474209ba25218b221e559cb3b1273a58ffc683d0068e53 F doc/expatapi.n 593e3175e9e797498c597b11eafc34327f00a1f6790fddbe9d2f1046c658d722 F doc/expatapi.xml 167fca5f81a6eea40a63384c7264288358e5b67ab7d8196711f9649f8c335523 F doc/index.html 54db3de127231251c4fbce931fd28ac633f83fd35c6f9c273157d4133d33170f F doc/keyword-index.html f085a75d35a16082e6564cca76c33ea66837e871cfbad997bb95ee3f86a991b4 F doc/manpage.css 3b4ec1d641048933a7e6bffc659de9519030a959 F doc/pullparser.html 41575ceab09859b89f40971de60f298ff32d129626da0410dc66525aea6930fd F doc/pullparser.n 4d47099aa552d6513b1a269247acd69df6488014d5bf0f51525187a875fd39e7 F doc/pullparser.xml 30132bb8d2afe3b3ab568da3145dcde6f090197be86bee74f8d028b83fdcfe8f F doc/schema.html fc132254ab537d1d564179a9cb4b027048e465e991a4cf1d359a18cd07673f2b F doc/schema.n 3dc3dc75460049d526cf3febe149d49bcbc214cba65317445f7f65656033b3b7 F doc/schema.xml ce6bcb358119735e9ca419f111707c2132142ee1f733bda683e2fe3b630c97aa F doc/tDOM.xml 8dce7f28c848d7a7b1a8e0360b0f65e1f0b7c8d97ddbdafeaacf079b6e9bc034 F doc/tdomcmd.html 4b954693f3994714c2b9bbe54d298b1330924a2b518e43029949e264e6bc7834 F doc/tdomcmd.n c06a5ff035f16a2a52636b69d9ebe6ba84ff5101922ed27b551146c4d61d6cda F doc/tdomcmd.xml fafa21389acf83585785f6cd7507cf71bf8fffcf48477137c020459acc1ebc53 F doc/tmml.dtd 63259dc9f69f9104f1515be445b85b195a1fb990 F doc/tmml.options 8a76115c6e9725e8dae55b3005e8ba9878023bbd F doc/tmml.rnc 65a2a69ac3347b19aa57e70bb127a4923f5dfc95 F doc/tmml.schema 0d252aeabfec23f7844bcac9029e93b32a5bc508dbd1d5533ceb0182ebd07c13 F doc/tnc.html af944e60c9df37798ce1d0bcd123000a9f3635935f94d19f911e26bf7de70a71 F doc/tnc.n 0e8fa5f4ba1f8f3763ca8357ee7968fb6f0496e4 F doc/tnc.xml f6d0115fbfac8393343b46e6fd1bba50deba17bc F doc/xpathFunc.html 10ec64ef64042fcd19860cb53ba521e53cbca8d7b018e5bda1d6f37587de8d75 F doc/xpathFunc.n 657b9386850e4be45ec77e9c41fa9268cf6a091cf3097318c0fbc53b6809c67e F doc/xpathFunc.xml 8578b7d782db4b538e74b45d8525d23eeeca51eb5f3988b232ebfd508cafd91f F expat/COPYING 4bbcf48425c66c7d34308cddc54362d15a9cb85f9c850f510301e9d88bdd4b73 F expat/Changes 67fbff312ef0867c20482950855031a9c556f2baaa8e7b7f694a9bd536b04cc9 F expat/VERSION 859804a67acced5601ba5cdf0be33448a557080b09abff82e56d6366e21cfae6 F expat/ascii.h e8752c5f09c75d1c5b6eaf50d359c8b2b173d5243ccb2f468b858e35d36d04c3 F expat/asciitab.h 7e665d7c5c93a5cd7f182a64dccd2a0771842d00f58706f99cc28e4554ddf9da F expat/expat.h 2f67b2a068a269f55950b37700d85c5fe27c992fa224fcbd7bd12fe951a9d9d7 F expat/expat_external.h 22207c9c718f4a09ada2847842290117f178ecb9bdc1f0d6d4dc4cb8632b80b7 F expat/iasciitab.h de065bf25c951d50bf37f238c113b4c6b89d406592061bd67dcff5816e501459 F expat/internal.h fa42bbfa567b40e66ee0912509ca7e761279c0452c2599f2071ff222b628ca33 F expat/latin1tab.h 2be294b7300ab6c6298ae7bb852778dcfd666a99dec3c779a7cca3826f76a260 F expat/nametab.h 30cd38454c40812806f55053f58791c8b1db8ce293d83e10b5d31ed517add4a9 F expat/siphash.h bc0f8bd627bf7d94895ad804d785cce28836bd97c59bf3fd68c2ce1e34e69c3c F expat/utf8tab.h 2f04b270d7c0d005f203477515a1a054e7538e1ed013cb48ecd4a4e2489b208b F expat/winconfig.h 047bdb572a458710a71517f96c00e69b24d952bedbbf6894ffeec45b97221ccd F expat/xmlparse.c d8a36b244261245b02576b14d5ffe7fc44b6597e493dcb75d65456b9d0a34ab5 F expat/xmlrole.c cc9e5f37e88a115d8de2d2278798e76ef8732fe9571a38d858eef87b43cfe767 F expat/xmlrole.h 9212092e0ed62049175171ac81207aa8f8ac6ed79f3df5dde1206c6879d789f1 F expat/xmltok.c f8c21c747a60dc6501accffd2f4538a8c8f5024937afc53112694b8fa1df19a6 F expat/xmltok.h 2d5bcb73ce07a5c1178bf18c11646c6e47b05227dabaa322a882a51ff9ddfe3a F expat/xmltok_impl.c 33ecbcf27e1aeaa187a44dd20f12ad72755816b9c9e47dd3c76eecc60267c462 F expat/xmltok_impl.h 4aacd280def9b42097ad6136e714babb066df12736926473eab3886db8875dce F expat/xmltok_ns.c 13964b8b88a42b67b3273829e3ffa2a2de96ef1621c57cfcfabb6c97d69c4717 F extensions/example/Makefile.in 74af47e4786c4a89ba4a0df8655b474314c5c4902b4a65b98049d71183078a2a F extensions/example/aclocal.m4 4d6d980ca968b21ba6f8745304357edc44493e65 F extensions/example/configure efb0392d880434d3891efeeb51841dd64c4ef2aef43a357c7a0d3fc3fb280607 x F extensions/example/configure.in 68a3a3201a8a8b6ba56b40ba5feee1072b03dede F extensions/example/example.c d866b87b725b6897decaae13152ddf4479b8d8e01bfe225deaca983bee7cefab F extensions/example/exampletest.tcl 555d6982f352083a759a40178d99f8d4efcea63d29215a4c1b998285c5fb7ea6 F extensions/example/install-sh b087e5c4b92820c60bffb74acc1d9c2d40d80b8f x F extensions/example/pkgIndex.tcl.in e6cc33c6f45df109209f4d8412cf2d5ea434e34e F extensions/example/tcl.m4 9404ac273b962ddaf946d3170c5183e55d0984b3 F extensions/schemadtx/Makefile.in 74af47e4786c4a89ba4a0df8655b474314c5c4902b4a65b98049d71183078a2a F extensions/schemadtx/aclocal.m4 4d6d980ca968b21ba6f8745304357edc44493e65 F extensions/schemadtx/configure fa5552c28b938b5b4733bc03390502e9ecf0a26b1995b596b63533058013da57 x F extensions/schemadtx/configure.ac f7523142dbb77cde51d4333393d5dd8c1fd92ad995358a9723ecb1fc3739346f F extensions/schemadtx/pkgIndex.tcl.in 93156e39702854530db4e84803b1812b2d472449ac47358344810a29c56530a7 F extensions/schemadtx/schemadtx.c f63bcf5b442c37c7d57c7828ada18a19dffa1fa2c956452a2ecf034f24ca26b0 F extensions/schemadtx/tests/all.tcl 01c5540732680c9bc11b36f8b44fb7be2cd4621de7d536d97e72d88ed03102e7 F extensions/schemadtx/tests/loadschemadtx.tcl 3b669926e01801833d6caaf55e748ae92291438014d116ff10fbc658e678e603 F extensions/schemadtx/tests/schemadtx.test 6c36dec706e91edd4a05ddad059a3276dcbf6d4f71d60fe0a91d21ae8e6ad684 F extensions/schemadtx/win/makefile.vc 1377e9de79e06c7c90bb9414f8f11daa2a9f119e77a7a229c121dbe118133d6e F extensions/schemadtx/win/nmakehlp.c 194ae7c24886245c679cb4c9ea7e6daaaebb5fcd F extensions/schemadtx/win/rules-ext.vc e788fcfc1e69b11946e18b8f67e0870b3bd38913 F extensions/schemadtx/win/rules.vc 8157e2a811cf5e93683d6b0fbf5d91d153aa4535 F extensions/schemadtx/win/targets.vc 79dea1c6a94a94e6ed8bae9e0195149b25a69923 F extensions/tdomhtml/CONFIG 7a3703be0e018ead9b6558ce6d82f356620dbfd8 F extensions/tdomhtml/Makefile.in 1008fe906a0b7150e5b83f69e43a231886821db7 F extensions/tdomhtml/configure 47edbb79649c148c4c439b93a329e70e647e1225aa35236bbc5643c9e3484190 x F extensions/tdomhtml/configure.in 22c8425b9c44c0583ccbadaf3ea3cc7185987ceb F extensions/tdomhtml/doc/tdomhtml.n da39a3ee5e6b4b0d3255bfef95601890afd80709 F extensions/tdomhtml/doc/tdomhtml.tmml da39a3ee5e6b4b0d3255bfef95601890afd80709 F extensions/tdomhtml/install-sh b087e5c4b92820c60bffb74acc1d9c2d40d80b8f x F extensions/tdomhtml/pkgIndex.tcl.in 2612d2a8fd5a213a1379ad5570c229d82810dcb5 F extensions/tdomhtml/tdomhtml.tcl 6901a0fb8db80954dd635e181934b9e3ba3a1864551155f3d5c01355ddbf0a45 F extensions/tdomhtml/win/makefile.vc a6ba491c8f63a88c607c443e7a80f1369cb3c40c F extensions/tnc/Makefile.in c7f74cda510a493a7c1539f1db9118be38b9482b57d4f9b51618c9aaf38c4a9a F extensions/tnc/aclocal.m4 4d6d980ca968b21ba6f8745304357edc44493e65 F extensions/tnc/configure e4340f98323fdc8e4abba3bd37ea02405455aacc4c8bf8ffa7731e3399b79dbf x F extensions/tnc/configure.ac 4fd59a3f8af1b8ff8db46c2fb007e692e43a55088d00ad0b4d8b5328f8888d10 F extensions/tnc/install-sh bdd5e293591621ae60d9824d86a4b1c5f22c3d00 x F extensions/tnc/pkgIndex.tcl.in 5c4022af93826a1d4f13f6105e86600d20b914b8bc9a0f48c0d98b3108b00a06 F extensions/tnc/test.tcl 545cdec17e6702cef9f79184fdf1ce0166b8c412 F extensions/tnc/tests/all.tcl 845c9dab65c294c3570f69cc731d6fef62efbd03 F extensions/tnc/tests/loadtnc.tcl c9b49c87af627263d40dcfbdd005bfddbc2a6ab5c8636d25618034c724e91c71 F extensions/tnc/tests/tnc.test 689eb32d186e04de0b0809333ad39f8a23ec1467fa545b790e7959ed7b09556c F extensions/tnc/tnc.c 48ad58bc421cd51e29e30890d4fb8707dbb4dfe56c88dfae0e52f30f8b8fa03a F extensions/tnc/win/makefile.vc d39ba2e6180a84a4d31415b9996577d88e5dd18c2cb50748afd179f9c0546421 F extensions/tnc/win/nmakehlp.c 194ae7c24886245c679cb4c9ea7e6daaaebb5fcd F extensions/tnc/win/rules-ext.vc 3c02944b3199014d35de617a1c146d0944af16395870da423374fb013ef57ecf F extensions/tnc/win/rules.vc afa89d3b334f5958efc447c985949447a9b05f6c891c7e1e8c0423ed226e89dc F extensions/tnc/win/targets.vc 3627f336071161bfb6bbaea40465b731e42f4ad750189a967e58b1ce40b4eb0b F generic/HTML5ent.inc c122e35eb1be8e325f8846080bbccc166978cfe7136e850d7e8aa477824d2b8f F generic/aolstub.cpp 0a4cd5a84d820496ca10237e934b8b4ccac8f827 F generic/datatypes.c fdc99296910358a175c37f5f669f47e482b0de1afc609e995c8585fb009cf68a F generic/datatypes.h 3e41d07bcf50cf6959b6e14416dfcb0d7b5aafc65683322978ec185c2a259332 F generic/dom.c 34ece24a9eec903161a21f47c23d9f6999abf100b6d9ca5ca77cdac01e0a1a09 F generic/dom.h 8288c21274aec439ec063ae6171325924c2da42aa1f231bca9c6970609ad7424 F generic/domalloc.c ce41b8a16e855ee3a3db1d4b797f835a77f1f9260f24db4cb7dc73a07ee4670b F generic/domalloc.h 961f83bb46dec27dbcf36ed430ed81b1f485a1fdfaa2f7df8b60bbcf861d0fe3 F generic/domhtml.c 4882beb464824469703ee62221806ef353161ff09dc963514c61decabf60cdde F generic/domhtml.h cb031185e99066889bec37b32239ab0f932d673a5701c94429902b2332ff3784 F generic/domhtml5.c 53c3f44545864e51ddd6022e6de71c24bc5768ec009e5447c7a5e7bed556c6be F generic/domhtml5.h 5cca562a556e7662f2dce222640c32abb2777146 F generic/domjson.c ee631e7ad15d092ff288b750e1ff53a8656ce5bf256804afdbf7311e2b131503 F generic/domjson.h 52906f5917d93c9225cbcf99dbd0cc37e1f2b6b75c41b0e4ce57c74fa5616dfe F generic/domlock.c 60f6c6f4dc95d6525f77cd589a07f6ec78f2068b12821067c5a075a2740abacb F generic/domxpath.c 30f5ceaced4484141ce50561003fb74f839ccdbade6bc79a12871b694e8b30ce F generic/domxpath.h a98836ef133283a20855968b76821042bce16b57b664689a15c017e3fecdae2f F generic/domxslt.c 27648bd8cf52de3745c44741b592e0fe9c1e82b017a05e51531f8b230852e8b3 F generic/domxslt.h aeaf957ee38a9e7564bd9f1bed1781de108767df476a0d0776615988d8f04e0f F generic/expat_config.h 560c148d431f87fc99ae8553cf998f0d01b0db82 F generic/nodecmd.c 92751187e49009fbef55d7b97b00e6522c2e34c6b435eb134e7bce9ba7ba511f F generic/nodecmd.h e9311269bd2f762cf419126ab0b7bc4951c6830a95aa82fe323c209292cde361 F generic/schema.c fc5ca4010cdca4737741ddd733b6e3dcd74e7010ffbb68edeeefa181fa2367af F generic/schema.h 5e20a348c3f98724e9c118760c8d9fcd661ae8f27d21652d90ab49492d001c75 F generic/tcldom.c 2aed8b2d00f94abf9b3258c4bbc97a7a840330328b3210cfb4e78b742ba17573 F generic/tcldom.h d8a198375e823af7d95b78f2ef695ac84b3f6d50232ab33ad82fcaa2502ea5e7 F generic/tclexpat.c d61eb77f556adfdc9aa459b255119d2e0e3cdef29032aa08bc37a18044cfd1c5 F generic/tclexpat.h 3844441852af770876f2de9b7444a0445e9c5c7f1fd5cc3a50e7455538d4e912 F generic/tclpull.c 8f7b6cca2519e19aeb68fff50c16238b4a68ed86b1db2c5927452f9e8d936629 F generic/tclpull.h 8e1aac98bdad497c669c901494939eecd6c2f57ea51c4f5d4dac502db48527d4 F generic/tdom.decls e41c101c51f9a988ef799442e6082283ac21a28ed1105b21b228a4913c13eb95 F generic/tdom.h 0ce348a4e4ae4c5a5e11d02ca2079ce2e8f1f705aecceb83c8d29b3ec80e5617 F generic/tdomDecls.h 93563f54a18aa836498d4e44587e42561518e59c6ba68c356ead6a715fad6f40 F generic/tdomStubInit.c e68ec41b2430f23300e37c584a043bcfc6f2cdf38d9f1e97059366ba4ed42e17 F generic/tdomStubLib.c 4a055f9c974246a9f7dd99de1a7686d1a96be8f02be699fdf4a760fdc813eb45 F generic/tdominit.c 925c91ddc69f9eda3f8eabe73b3f9d6260a4c4503b11e09c563964f7718849bd F generic/xmlsimple.c 019e8c4e0d55bb2c0cc3c020ab2c8191740bf1589cd23f8b0d6e7377bbd7353b F generic/xmlsimple.h 6cbbc9208bcaec273624fd5e24aff3de07ef98d1da3be4576f3e6d4951516054 F lib/tdom.tcl cd3bdc7a05ea9c6d0d17fd12d68e72c92e64f501106ec74c19e85ac963ade570 F macosx/README 75fe1f6617f6cb7e4480cff5367b5c26fcd8dd207e2321f35dceebafccf4c99c F pkgIndex.tcl.in 2c2ecfb3b4176ae61af4445e022b34bb9071efdbf0446c2aa2d0f6cfcce3f120 F tclconfig/README.txt 22e2b8305785370b08ef9c18aa62408f5fe972655f3a4fbb0dc55bc8beb60e67 F tclconfig/install-sh 2182b3705d92e25753411e2c28cf788c69e35a48fbb8aa332e342dfc6b95b80d x F tclconfig/tcl.m4 284faa1d9cf66c1efb42817beb5c8a63626fb35bf903993d4f11fde75677cc1a F tdom.m4 24fab1aa28c28e3d9a69b2c29af894aabd22d0cc6c68ecf27bcd626488194476 F tdomConfig.sh.in 1f2f873de2a2a84a93949372767a78c56ee72e0700a156b87a2769884ad5ccf1 F tests/JSONTestSuite.tcl 907228f9bd31855951b9033df74c9c15778765af F tests/OASIS-suite.tcl f695f8fa1102461b7c308ed6d87664ba866970fbb3695f2e07ea0b70321c2ddc F tests/all-bench.tcl 1444cd15eb49d934cb08f75f59b244363372dd23cff13470f5b14580cc33ca47 F tests/all.tcl 14e2ccb0550ad38328f58ad79b3353e6cc110779ed94ce21ecdd42853be0637a F tests/attribute.test 53ac8fb043e79b638c8c6f5e7da848f6103552d6 F tests/cdata.test 5a1dc3bee6353700186d12f0d11b15914849c6be F tests/comment.test ff9d1abbbcde4d3532bf93b1eb7e819997fa8178 F tests/data/REC-xslt-19991116-mod.xml f49602be921b5e3f24bf11fd3ce5cefd86d5afa94889a4071ed6638a65d2b64d F tests/data/REC-xslt-19991116.xml 037d39caac3e4cc8964848a7b0eb9a4b385520606a635e1f54f2aff9802b5fd4 F tests/data/books.xml 0b1ae696b2bbc1035303f5637a6ef67f041d0b9e F tests/data/data1.xml 0f44f6ade4a2b91ae129882601790af23f1485ee51f894ca5b05d5296eb0b7cc F tests/data/domCmd1.dtd 2031a36d155dfac8f0a5ef3be69958d250f5459e F tests/data/domCmd2.dtd 42200fe458c04d2072e71d8fa00ade2cb1c59878 F tests/data/dtd-5.1.dtd 8f16a5c1ff5181e7136cd0d0f1255ae269c38e3c F tests/data/dtd-5.2.dtd 6a2dbcda86b1729c9789c40ea2d592fff9434939 F tests/data/dtd-6.1.dtd 705abb4c198575b4035af700a2943710318e3c83 F tests/data/dtd-6.2.dtd 2dc65db913747dc331f974383c2ca488cca78bed F tests/data/dtd-6.3.dtd 1a368d162a607f43d30a53932378678c6bb39c09 F tests/data/dtd-6.4.dtd 86c52ff258b73e9530a36452a21fa8b62d380f15 F tests/data/dtd-6.5.dtd 961850932623ee218b1cc2cbf544662a9942f2ce F tests/data/dtd-6.6.dtd a1036539ff132635da3e368604b59651a47909e4 F tests/data/htmlmathml.json 00ab0ff0335a64464df1b11c62e7a228cde203505e366094276c89638171dd3b F tests/data/i18n_1.xml 7b4282addd307b17940fffd818de016ca64311fa F tests/data/i18n_2.xml 4dc16d8ee2337fbd30061dd1159f6c49b2d0a52c F tests/data/mondial-europe.xml 61790f95c676755667358b6ddfc46eb8cc3f470b F tests/data/xmlspec-v20.dtd dcb796f8ff379dad58487ed43d12775eed7d6d0ead4658e461f7a731d86a5293 F tests/data/xslt_1.xsl e96e4c1f0cd3467141815c97fe917333b09e8de9 F tests/decls.test 06d0ba0cbc18e26a1524cb17a6ef9adf2a0fc864 F tests/doctype.test 015c514bd8919467c1074dc3068a527abb3988b5 F tests/dom.bench 5446ce379127b8d5700f18a5a0848e580313d0d7 F tests/dom.test a7a7498fa64608860607dd94ad314ebb295efaeaaf32caab3bf6b606003599b5 F tests/domDoc.test 095f2df0dda3afb96574c585b292b5ae061d0134ae78bd31a58dedda002a6fa5 F tests/domNode.bench 3d457513be7908bab88ac0e23e1864f7341e3090 F tests/domNode.test 843287a57fe1a58e327fcf3c8b94892d7553e14b3cb6920c5a7d3a3c93cb94f8 F tests/domjson.test daed40bb982a77e19cdf161026593bef0c020949938f87213e83fb1e10a64559 F tests/domnamespace.test 6fe1a86eed6906a51c2a2751f1d531642f6aedbae42a644a61cd9851a1c3ad1a F tests/element.test 4c5f0094543ee9167f86748e2d667347f57eb911 F tests/entity.test 065c6c1af854db838faf9ad56151342eee478f8501a5f65778a144b106108574 F tests/html5reader.test 05b49514f3aed62b6b8fe4e55af24ed3a4e3168a2bd3b94e454d3752a8d12d1f F tests/htmlreader.test 1a7d62ad1bfd1066349b1115a8e7a561befb3d97fcd207cf312b7f56a4a871bf F tests/i18n.test 421e3998480ed5ce9420f4b596c384b8d5261e7fb4b33c0a7c12ef126d476939 F tests/loadtdom.tcl 4c09719b09c09b5a7cbc584ae7856a5df3abd44b843ac78fe8f6c4042e476af0 F tests/namespace.test 0a13b2bf59bb088525ca7b64d0b2bce6a349c627ca3dd1c17a4cc969d16fe57c F tests/parser.test 87eed84aec743e2ac02959a7276cd715bb764c2f479f566a69fb243ff2d72f5e F tests/pcdata.test d24772594d762437300d6a48231f0eb16553855a F tests/pi.test 22a24ce658e1c84b05b986c0b2e010c5a94076fe F tests/pullparser.test 4ca2b332ec1eb31efb294b9e6556a58148a1d28a3c3d1cbb6800dc19f3887b79 F tests/pushpull.bench 664e8f512917537d96c4b71933d4d9a6da65fc6fe85bd7c459483830dc7d2faf F tests/schema.test bc98d97f924b20ab3e120af65bef4030d79272c347d962f7092640c5a3c15813 F tests/stackedhdl.test a3efca3d0f095cfdeddc3e67734b9d79567b0fd1 F tests/tdomcmd.bench b07448ed4de08ccaa9734cf3fe15c695fd7066c993da58ff48d465747940e417 F tests/tdomcmd.test 425a031cd0696280faac1458815f75fb44e6ebf950891192df9bccdcfd7f4ac8 F tests/xmlsimple.test 147a3b6826f6e6175fc8ed1a657253e7db587be61a4d8d4d3892db83722796f7 F tests/xmltest.test f8598eb3ee6a35248af7193d229a1fccd2061109 F tests/xpath.bench a8a90cbce1e276d05c6ff2c54ef04ffb3166c16e4094a543c694256ea4d68355 F tests/xpath.test b6cb33a57daf18c14e61f792ed0db31b96882ad354390dd9bfdb7506fcf90701 F tests/xslt.test 84b53c3c28e0d9ad6f2f202c84e540a1d7cf8556874ffa5748ad81cae7cdf216 F unix/CONFIG 431b82a51451df40e38261b91e1a37060797ef655e8f981fab761de59f1e01e9 F unix/speed-check.sh 7a8d91e7edf1cdc9bcfad5f28e1a068cb2843d05e49d8bd89d9b30a46511497d F unix/tclAppInit.c cd5fa5bcb9f4648e9bf7108727b99e20cd02c33713df359efb1da298715940b9 F win/README d480e01bbb3f480184671f66b4025d7e94e5a6fccb603d6559f6ad92d398d919 F win/config.h 560c148d431f87fc99ae8553cf998f0d01b0db82 F win/makefile.vc 305808a83bed1240b802508262365381ffb73e452f8e2150054b0bd60cb7fe25 F win/nmakehlp.c 01a0e9f85df9d23d735cbc7b5ec99d2c45868ebf976d0842650721d0184e362e F win/pkgIndex.tcl 7d8e06a34f36dcf48426710316a6595e49157187ef9b9e9c6e2e98f19df1c989 F win/rules-ext.vc 50db9d785c66e5b35a5573717ce96340b0bc54ed5659cdb2209ae11fe2cdfe60 F win/rules.vc 728ea60a25fb20cf141eab51977090b69f6c68ca43f66adde9437dc1c009e40b F win/targets.vc 3627f336071161bfb6bbaea40465b731e42f4ad750189a967e58b1ce40b4eb0b F win/tdom.rc 1463128845bffe1fdf24ab99f562727830855516 F xe/README 91626be10fa0b48c38184bb73b09eea074008fb082559eaf5c0fb8bb83997903 F xe/xe 075a1f1c4a5758222c52a4688f9fe22dc3d925e366316cf50d84501c9ca3fdb1 x F xe/xe-input fb58cbefe5e3acceb9567a165ef7e655ad08b44e F xe/xe.bat 8622c5a70666a58d2316df568354c70593848098 P 7bcde5ef58966d98bc8efc30740132d670e270497657c85a541d7269340ec6f5 R bed25eac9673eef6e215729865e4374f U rolf Z c2119f585327713a782a72cfabb631de # Remove this line to create a well-formed Fossil manifest. tdom-0.9.6-src/tclconfig/0000755000175000017500000000000015025767703013730 5ustar rolfrolftdom-0.9.6-src/tclconfig/tcl.m40000644000175000017500000040514215025767703014762 0ustar rolfrolf# tcl.m4 -- # # This file provides a set of autoconf macros to help TEA-enable # a Tcl extension. # # Copyright (c) 1999-2000 Ajuba Solutions. # Copyright (c) 2002-2005 ActiveState Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. AC_PREREQ([2.69]) # Possible values for key variables defined: # # TEA_WINDOWINGSYSTEM - win32 aqua x11 (mirrors 'tk windowingsystem') # TEA_PLATFORM - windows unix # TEA_TK_EXTENSION - True if this is a Tk extension # #------------------------------------------------------------------------ # TEA_PATH_TCLCONFIG -- # # Locate the tclConfig.sh file and perform a sanity check on # the Tcl compile flags # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --with-tcl=... # # Defines the following vars: # TCL_BIN_DIR Full path to the directory containing # the tclConfig.sh file #------------------------------------------------------------------------ AC_DEFUN([TEA_PATH_TCLCONFIG], [ dnl TEA specific: Make sure we are initialized AC_REQUIRE([TEA_INIT]) # # Ok, lets find the tcl configuration # First, look for one uninstalled. # the alternative search directory is invoked by --with-tcl # if test x"${no_tcl}" = x ; then # we reset no_tcl in case something fails here no_tcl=true AC_ARG_WITH(tcl, AS_HELP_STRING([--with-tcl], [directory containing tcl configuration (tclConfig.sh)]), [with_tclconfig="${withval}"]) AC_ARG_WITH(tcl8, AS_HELP_STRING([--with-tcl8], [Compile for Tcl8 in Tcl9 environment]), [with_tcl8="${withval}"]) AC_MSG_CHECKING([for Tcl configuration]) AC_CACHE_VAL(ac_cv_c_tclconfig,[ # First check to see if --with-tcl was specified. if test x"${with_tclconfig}" != x ; then case "${with_tclconfig}" in */tclConfig.sh ) if test -f "${with_tclconfig}"; then AC_MSG_WARN([--with-tcl argument should refer to directory containing tclConfig.sh, not to tclConfig.sh itself]) with_tclconfig="`echo "${with_tclconfig}" | sed 's!/tclConfig\.sh$!!'`" fi ;; esac if test -f "${with_tclconfig}/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd "${with_tclconfig}"; pwd)`" else AC_MSG_ERROR([${with_tclconfig} directory doesn't contain tclConfig.sh]) fi fi # then check for a private Tcl installation if test x"${ac_cv_c_tclconfig}" = x ; then for i in \ ../tcl \ `ls -dr ../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../tcl[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../tcl[[8-9]].[[0-9]]* 2>/dev/null` \ ../../tcl \ `ls -dr ../../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../../tcl[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../tcl[[8-9]].[[0-9]]* 2>/dev/null` \ ../../../tcl \ `ls -dr ../../../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../../../tcl[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../../tcl[[8-9]].[[0-9]]* 2>/dev/null` ; do if test "${TEA_PLATFORM}" = "windows" \ -a -f "$i/win/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/win; pwd)`" break fi if test -f "$i/unix/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/unix; pwd)`" break fi done fi # on Darwin, check in Framework installation locations if test "`uname -s`" = "Darwin" -a x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d ~/Library/Frameworks 2>/dev/null` \ `ls -d /Library/Frameworks 2>/dev/null` \ `ls -d /Network/Library/Frameworks 2>/dev/null` \ `ls -d /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/Library/Frameworks/Tcl.framework 2>/dev/null` \ `ls -d /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/Network/Library/Frameworks/Tcl.framework 2>/dev/null` \ `ls -d /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/Tcl.framework 2>/dev/null` \ ; do if test -f "$i/Tcl.framework/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/Tcl.framework; pwd)`" break fi done fi # TEA specific: on Windows, check in common installation locations if test "${TEA_PLATFORM}" = "windows" \ -a x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d C:/Tcl/lib 2>/dev/null` \ `ls -d C:/Progra~1/Tcl/lib 2>/dev/null` \ ; do if test -f "$i/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i; pwd)`" break fi done fi # check in a few common install locations if test x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d ${libdir} 2>/dev/null` \ `ls -d ${exec_prefix}/lib 2>/dev/null` \ `ls -d ${prefix}/lib 2>/dev/null` \ `ls -d /usr/local/lib 2>/dev/null` \ `ls -d /usr/contrib/lib 2>/dev/null` \ `ls -d /usr/pkg/lib 2>/dev/null` \ `ls -d /usr/lib 2>/dev/null` \ `ls -d /usr/lib64 2>/dev/null` \ `ls -d /usr/lib/tcl9.0 2>/dev/null` \ `ls -d /usr/lib/tcl8.7 2>/dev/null` \ `ls -d /usr/lib/tcl8.6 2>/dev/null` \ `ls -d /usr/lib/tcl8.5 2>/dev/null` \ `ls -d /usr/local/lib/tcl9.0 2>/dev/null` \ `ls -d /usr/local/lib/tcl8.7 2>/dev/null` \ `ls -d /usr/local/lib/tcl8.6 2>/dev/null` \ `ls -d /usr/local/lib/tcl8.5 2>/dev/null` \ `ls -d /usr/local/lib/tcl/tcl9.0 2>/dev/null` \ `ls -d /usr/local/lib/tcl/tcl8.7 2>/dev/null` \ `ls -d /usr/local/lib/tcl/tcl8.6 2>/dev/null` \ `ls -d /usr/local/lib/tcl/tcl8.5 2>/dev/null` \ ; do if test -f "$i/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i; pwd)`" break fi done fi # check in a few other private locations if test x"${ac_cv_c_tclconfig}" = x ; then for i in \ ${srcdir}/../tcl \ `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]]* 2>/dev/null` ; do if test "${TEA_PLATFORM}" = "windows" \ -a -f "$i/win/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/win; pwd)`" break fi if test -f "$i/unix/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/unix; pwd)`" break fi done fi ]) if test x"${ac_cv_c_tclconfig}" = x ; then TCL_BIN_DIR="# no Tcl configs found" AC_MSG_ERROR([Can't find Tcl configuration definitions. Use --with-tcl to specify a directory containing tclConfig.sh]) else no_tcl= TCL_BIN_DIR="${ac_cv_c_tclconfig}" AC_MSG_RESULT([found ${TCL_BIN_DIR}/tclConfig.sh]) fi fi ]) #------------------------------------------------------------------------ # TEA_PATH_TKCONFIG -- # # Locate the tkConfig.sh file # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --with-tk=... # # Defines the following vars: # TK_BIN_DIR Full path to the directory containing # the tkConfig.sh file #------------------------------------------------------------------------ AC_DEFUN([TEA_PATH_TKCONFIG], [ # # Ok, lets find the tk configuration # First, look for one uninstalled. # the alternative search directory is invoked by --with-tk # if test x"${no_tk}" = x ; then # we reset no_tk in case something fails here no_tk=true AC_ARG_WITH(tk, AS_HELP_STRING([--with-tk], [directory containing tk configuration (tkConfig.sh)]), [with_tkconfig="${withval}"]) AC_MSG_CHECKING([for Tk configuration]) AC_CACHE_VAL(ac_cv_c_tkconfig,[ # First check to see if --with-tkconfig was specified. if test x"${with_tkconfig}" != x ; then case "${with_tkconfig}" in */tkConfig.sh ) if test -f "${with_tkconfig}"; then AC_MSG_WARN([--with-tk argument should refer to directory containing tkConfig.sh, not to tkConfig.sh itself]) with_tkconfig="`echo "${with_tkconfig}" | sed 's!/tkConfig\.sh$!!'`" fi ;; esac if test -f "${with_tkconfig}/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd "${with_tkconfig}"; pwd)`" else AC_MSG_ERROR([${with_tkconfig} directory doesn't contain tkConfig.sh]) fi fi # then check for a private Tk library if test x"${ac_cv_c_tkconfig}" = x ; then for i in \ ../tk \ `ls -dr ../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../tk[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../tk[[8-9]].[[0-9]]* 2>/dev/null` \ ../../tk \ `ls -dr ../../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../../tk[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../tk[[8-9]].[[0-9]]* 2>/dev/null` \ ../../../tk \ `ls -dr ../../../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../../../tk[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../../tk[[8-9]].[[0-9]]* 2>/dev/null` ; do if test "${TEA_PLATFORM}" = "windows" \ -a -f "$i/win/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i/win; pwd)`" break fi if test -f "$i/unix/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i/unix; pwd)`" break fi done fi # on Darwin, check in Framework installation locations if test "`uname -s`" = "Darwin" -a x"${ac_cv_c_tkconfig}" = x ; then for i in `ls -d ~/Library/Frameworks 2>/dev/null` \ `ls -d /Library/Frameworks 2>/dev/null` \ `ls -d /Network/Library/Frameworks 2>/dev/null` \ ; do if test -f "$i/Tk.framework/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i/Tk.framework; pwd)`" break fi done fi # check in a few common install locations if test x"${ac_cv_c_tkconfig}" = x ; then for i in `ls -d ${libdir} 2>/dev/null` \ `ls -d ${exec_prefix}/lib 2>/dev/null` \ `ls -d ${prefix}/lib 2>/dev/null` \ `ls -d /usr/local/lib 2>/dev/null` \ `ls -d /usr/contrib/lib 2>/dev/null` \ `ls -d /usr/pkg/lib 2>/dev/null` \ `ls -d /usr/lib/tk9.0 2>/dev/null` \ `ls -d /usr/lib/tk8.7 2>/dev/null` \ `ls -d /usr/lib/tk8.6 2>/dev/null` \ `ls -d /usr/lib/tk8.5 2>/dev/null` \ `ls -d /usr/lib 2>/dev/null` \ `ls -d /usr/lib64 2>/dev/null` \ `ls -d /usr/local/lib/tk9.0 2>/dev/null` \ `ls -d /usr/local/lib/tk8.7 2>/dev/null` \ `ls -d /usr/local/lib/tk8.6 2>/dev/null` \ `ls -d /usr/local/lib/tk8.5 2>/dev/null` \ `ls -d /usr/local/lib/tcl/tk9.0 2>/dev/null` \ `ls -d /usr/local/lib/tcl/tk8.7 2>/dev/null` \ `ls -d /usr/local/lib/tcl/tk8.6 2>/dev/null` \ `ls -d /usr/local/lib/tcl/tk8.5 2>/dev/null` \ ; do if test -f "$i/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i; pwd)`" break fi done fi # TEA specific: on Windows, check in common installation locations if test "${TEA_PLATFORM}" = "windows" \ -a x"${ac_cv_c_tkconfig}" = x ; then for i in `ls -d C:/Tcl/lib 2>/dev/null` \ `ls -d C:/Progra~1/Tcl/lib 2>/dev/null` \ ; do if test -f "$i/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i; pwd)`" break fi done fi # check in a few other private locations if test x"${ac_cv_c_tkconfig}" = x ; then for i in \ ${srcdir}/../tk \ `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]]* 2>/dev/null` ; do if test "${TEA_PLATFORM}" = "windows" \ -a -f "$i/win/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i/win; pwd)`" break fi if test -f "$i/unix/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i/unix; pwd)`" break fi done fi ]) if test x"${ac_cv_c_tkconfig}" = x ; then TK_BIN_DIR="# no Tk configs found" AC_MSG_ERROR([Can't find Tk configuration definitions. Use --with-tk to specify a directory containing tkConfig.sh]) else no_tk= TK_BIN_DIR="${ac_cv_c_tkconfig}" AC_MSG_RESULT([found ${TK_BIN_DIR}/tkConfig.sh]) fi fi ]) #------------------------------------------------------------------------ # TEA_LOAD_TCLCONFIG -- # # Load the tclConfig.sh file # # Arguments: # # Requires the following vars to be set: # TCL_BIN_DIR # # Results: # # Substitutes the following vars: # TCL_BIN_DIR # TCL_SRC_DIR # TCL_LIB_FILE # TCL_ZIP_FILE # TCL_ZIPFS_SUPPORT #------------------------------------------------------------------------ AC_DEFUN([TEA_LOAD_TCLCONFIG], [ AC_MSG_CHECKING([for existence of ${TCL_BIN_DIR}/tclConfig.sh]) if test -f "${TCL_BIN_DIR}/tclConfig.sh" ; then AC_MSG_RESULT([loading]) . "${TCL_BIN_DIR}/tclConfig.sh" else AC_MSG_RESULT([could not find ${TCL_BIN_DIR}/tclConfig.sh]) fi # If the TCL_BIN_DIR is the build directory (not the install directory), # then set the common variable name to the value of the build variables. # For example, the variable TCL_LIB_SPEC will be set to the value # of TCL_BUILD_LIB_SPEC. An extension should make use of TCL_LIB_SPEC # instead of TCL_BUILD_LIB_SPEC since it will work with both an # installed and uninstalled version of Tcl. if test -f "${TCL_BIN_DIR}/Makefile" ; then TCL_LIB_SPEC="${TCL_BUILD_LIB_SPEC}" TCL_STUB_LIB_SPEC="${TCL_BUILD_STUB_LIB_SPEC}" TCL_STUB_LIB_PATH="${TCL_BUILD_STUB_LIB_PATH}" elif test "`uname -s`" = "Darwin"; then # If Tcl was built as a framework, attempt to use the libraries # from the framework at the given location so that linking works # against Tcl.framework installed in an arbitrary location. case ${TCL_DEFS} in *TCL_FRAMEWORK*) if test -f "${TCL_BIN_DIR}/${TCL_LIB_FILE}"; then for i in "`cd "${TCL_BIN_DIR}"; pwd`" \ "`cd "${TCL_BIN_DIR}"/../..; pwd`"; do if test "`basename "$i"`" = "${TCL_LIB_FILE}.framework"; then TCL_LIB_SPEC="-F`dirname "$i" | sed -e 's/ /\\\\ /g'` -framework ${TCL_LIB_FILE}" break fi done fi if test -f "${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}"; then TCL_STUB_LIB_SPEC="-L`echo "${TCL_BIN_DIR}" | sed -e 's/ /\\\\ /g'` ${TCL_STUB_LIB_FLAG}" TCL_STUB_LIB_PATH="${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}" fi ;; esac fi AC_SUBST(TCL_VERSION) AC_SUBST(TCL_PATCH_LEVEL) AC_SUBST(TCL_BIN_DIR) AC_SUBST(TCL_SRC_DIR) AC_SUBST(TCL_LIB_FILE) AC_SUBST(TCL_LIB_FLAG) AC_SUBST(TCL_LIB_SPEC) AC_SUBST(TCL_STUB_LIB_FILE) AC_SUBST(TCL_STUB_LIB_FLAG) AC_SUBST(TCL_STUB_LIB_SPEC) AC_MSG_CHECKING([platform]) hold_cc=$CC; CC="$TCL_CC" AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[ #ifdef _WIN32 #error win32 #endif ]])],[ # first test we've already retrieved platform (cross-compile), fallback to unix otherwise: TEA_PLATFORM="${TEA_PLATFORM-unix}" CYGPATH=echo ],[ TEA_PLATFORM="windows" AC_CHECK_PROG(CYGPATH, cygpath, cygpath -m, echo) ]) CC=$hold_cc AC_MSG_RESULT($TEA_PLATFORM) # The BUILD_$pkg is to define the correct extern storage class # handling when making this package AC_DEFINE_UNQUOTED(BUILD_${PACKAGE_NAME}, [], [Building extension source?]) # Do this here as we have fully defined TEA_PLATFORM now if test "${TEA_PLATFORM}" = "windows" ; then EXEEXT=".exe" CLEANFILES="$CLEANFILES *.lib *.dll *.pdb *.exp" fi # TEA specific: AC_SUBST(CLEANFILES) AC_SUBST(TCL_LIBS) AC_SUBST(TCL_DEFS) AC_SUBST(TCL_EXTRA_CFLAGS) AC_SUBST(TCL_LD_FLAGS) AC_SUBST(TCL_SHLIB_LD_LIBS) ]) #------------------------------------------------------------------------ # TEA_LOAD_TKCONFIG -- # # Load the tkConfig.sh file # # Arguments: # # Requires the following vars to be set: # TK_BIN_DIR # # Results: # # Sets the following vars that should be in tkConfig.sh: # TK_BIN_DIR #------------------------------------------------------------------------ AC_DEFUN([TEA_LOAD_TKCONFIG], [ AC_MSG_CHECKING([for existence of ${TK_BIN_DIR}/tkConfig.sh]) if test -f "${TK_BIN_DIR}/tkConfig.sh" ; then AC_MSG_RESULT([loading]) . "${TK_BIN_DIR}/tkConfig.sh" else AC_MSG_RESULT([could not find ${TK_BIN_DIR}/tkConfig.sh]) fi # If the TK_BIN_DIR is the build directory (not the install directory), # then set the common variable name to the value of the build variables. # For example, the variable TK_LIB_SPEC will be set to the value # of TK_BUILD_LIB_SPEC. An extension should make use of TK_LIB_SPEC # instead of TK_BUILD_LIB_SPEC since it will work with both an # installed and uninstalled version of Tcl. if test -f "${TK_BIN_DIR}/Makefile" ; then TK_LIB_SPEC="${TK_BUILD_LIB_SPEC}" TK_STUB_LIB_SPEC="${TK_BUILD_STUB_LIB_SPEC}" TK_STUB_LIB_PATH="${TK_BUILD_STUB_LIB_PATH}" elif test "`uname -s`" = "Darwin"; then # If Tk was built as a framework, attempt to use the libraries # from the framework at the given location so that linking works # against Tk.framework installed in an arbitrary location. case ${TK_DEFS} in *TK_FRAMEWORK*) if test -f "${TK_BIN_DIR}/${TK_LIB_FILE}"; then for i in "`cd "${TK_BIN_DIR}"; pwd`" \ "`cd "${TK_BIN_DIR}"/../..; pwd`"; do if test "`basename "$i"`" = "${TK_LIB_FILE}.framework"; then TK_LIB_SPEC="-F`dirname "$i" | sed -e 's/ /\\\\ /g'` -framework ${TK_LIB_FILE}" break fi done fi if test -f "${TK_BIN_DIR}/${TK_STUB_LIB_FILE}"; then TK_STUB_LIB_SPEC="-L` echo "${TK_BIN_DIR}" | sed -e 's/ /\\\\ /g'` ${TK_STUB_LIB_FLAG}" TK_STUB_LIB_PATH="${TK_BIN_DIR}/${TK_STUB_LIB_FILE}" fi ;; esac fi # TEA specific: Ensure windowingsystem is defined if test "${TEA_PLATFORM}" = "unix" ; then case ${TK_DEFS} in *MAC_OSX_TK*) AC_DEFINE(MAC_OSX_TK, 1, [Are we building against Mac OS X TkAqua?]) TEA_WINDOWINGSYSTEM="aqua" ;; *) TEA_WINDOWINGSYSTEM="x11" ;; esac elif test "${TEA_PLATFORM}" = "windows" ; then TEA_WINDOWINGSYSTEM="win32" fi AC_SUBST(TK_VERSION) AC_SUBST(TK_BIN_DIR) AC_SUBST(TK_SRC_DIR) AC_SUBST(TK_LIB_FILE) AC_SUBST(TK_LIB_FLAG) AC_SUBST(TK_LIB_SPEC) AC_SUBST(TK_STUB_LIB_FILE) AC_SUBST(TK_STUB_LIB_FLAG) AC_SUBST(TK_STUB_LIB_SPEC) # TEA specific: AC_SUBST(TK_LIBS) AC_SUBST(TK_XINCLUDES) ]) #------------------------------------------------------------------------ # TEA_PROG_TCLSH # Determine the fully qualified path name of the tclsh executable # in the Tcl build directory or the tclsh installed in a bin # directory. This macro will correctly determine the name # of the tclsh executable even if tclsh has not yet been # built in the build directory. The tclsh found is always # associated with a tclConfig.sh file. This tclsh should be used # only for running extension test cases. It should never be # or generation of files (like pkgIndex.tcl) at build time. # # Arguments: # none # # Results: # Substitutes the following vars: # TCLSH_PROG #------------------------------------------------------------------------ AC_DEFUN([TEA_PROG_TCLSH], [ AC_MSG_CHECKING([for tclsh]) if test -f "${TCL_BIN_DIR}/Makefile" ; then # tclConfig.sh is in Tcl build directory if test "${TEA_PLATFORM}" = "windows"; then if test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${EXEEXT}" ; then TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${EXEEXT}" elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}s${EXEEXT}" ; then TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}s${EXEEXT}" elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}t${EXEEXT}" ; then TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}t${EXEEXT}" elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}st${EXEEXT}" ; then TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}st${EXEEXT}" fi else TCLSH_PROG="${TCL_BIN_DIR}/tclsh" fi else # tclConfig.sh is in install location if test "${TEA_PLATFORM}" = "windows"; then TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${EXEEXT}" else TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION}" fi list="`ls -d ${TCL_BIN_DIR}/../bin 2>/dev/null` \ `ls -d ${TCL_BIN_DIR}/.. 2>/dev/null` \ `ls -d ${TCL_PREFIX}/bin 2>/dev/null`" for i in $list ; do if test -f "$i/${TCLSH_PROG}" ; then REAL_TCL_BIN_DIR="`cd "$i"; pwd`/" break fi done TCLSH_PROG="${REAL_TCL_BIN_DIR}${TCLSH_PROG}" fi AC_MSG_RESULT([${TCLSH_PROG}]) AC_SUBST(TCLSH_PROG) ]) #------------------------------------------------------------------------ # TEA_PROG_WISH # Determine the fully qualified path name of the wish executable # in the Tk build directory or the wish installed in a bin # directory. This macro will correctly determine the name # of the wish executable even if wish has not yet been # built in the build directory. The wish found is always # associated with a tkConfig.sh file. This wish should be used # only for running extension test cases. It should never be # or generation of files (like pkgIndex.tcl) at build time. # # Arguments: # none # # Results: # Substitutes the following vars: # WISH_PROG #------------------------------------------------------------------------ AC_DEFUN([TEA_PROG_WISH], [ AC_MSG_CHECKING([for wish]) if test -f "${TK_BIN_DIR}/Makefile" ; then # tkConfig.sh is in Tk build directory if test "${TEA_PLATFORM}" = "windows"; then if test -f "${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${EXEEXT}" ; then WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${EXEEXT}" elif test -f "${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}s${EXEEXT}" ; then WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}$s{EXEEXT}" elif test -f "${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}t${EXEEXT}" ; then WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}t${EXEEXT}" elif test -f "${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}st${EXEEXT}" ; then WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}st${EXEEXT}" fi else WISH_PROG="${TK_BIN_DIR}/wish" fi else # tkConfig.sh is in install location if test "${TEA_PLATFORM}" = "windows"; then WISH_PROG="wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${EXEEXT}" else WISH_PROG="wish${TK_MAJOR_VERSION}.${TK_MINOR_VERSION}" fi list="`ls -d ${TK_BIN_DIR}/../bin 2>/dev/null` \ `ls -d ${TK_BIN_DIR}/.. 2>/dev/null` \ `ls -d ${TK_PREFIX}/bin 2>/dev/null`" for i in $list ; do if test -f "$i/${WISH_PROG}" ; then REAL_TK_BIN_DIR="`cd "$i"; pwd`/" break fi done WISH_PROG="${REAL_TK_BIN_DIR}${WISH_PROG}" fi AC_MSG_RESULT([${WISH_PROG}]) AC_SUBST(WISH_PROG) ]) #------------------------------------------------------------------------ # TEA_ENABLE_SHARED -- # # Allows the building of shared libraries # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --enable-shared=yes|no # --enable-stubs=yes|no # # Defines the following vars: # STATIC_BUILD Used for building import/export libraries # on Windows. # # Sets the following vars: # SHARED_BUILD Value of 1 or 0 # STUBS_BUILD Value if 1 or 0 # USE_TCL_STUBS Value true: if SHARED_BUILD or --enable-stubs # USE_TCLOO_STUBS Value true: if SHARED_BUILD or --enable-stubs # USE_TK_STUBS Value true: if SHARED_BUILD or --enable-stubs # AND TEA_WINDOWING_SYSTEM != "" #------------------------------------------------------------------------ AC_DEFUN([TEA_ENABLE_SHARED], [ AC_MSG_CHECKING([how to build libraries]) AC_ARG_ENABLE(shared, AS_HELP_STRING([--enable-shared], [build and link with shared libraries (default: on)]), [shared_ok=$enableval], [shared_ok=yes]) if test "${enable_shared+set}" = set; then enableval="$enable_shared" shared_ok=$enableval else shared_ok=yes fi AC_ARG_ENABLE(stubs, AS_HELP_STRING([--enable-stubs], [build and link with stub libraries. Always true for shared builds (default: on)]), [stubs_ok=$enableval], [stubs_ok=yes]) if test "${enable_stubs+set}" = set; then enableval="$enable_stubs" stubs_ok=$enableval else stubs_ok=yes fi # Stubs are always enabled for shared builds if test "$shared_ok" = "yes" ; then AC_MSG_RESULT([shared]) SHARED_BUILD=1 STUBS_BUILD=1 else AC_MSG_RESULT([static]) SHARED_BUILD=0 AC_DEFINE(STATIC_BUILD, 1, [This a static build]) if test "$stubs_ok" = "yes" ; then STUBS_BUILD=1 else STUBS_BUILD=0 fi fi if test "${STUBS_BUILD}" = "1" ; then AC_DEFINE(USE_TCL_STUBS, 1, [Use Tcl stubs]) AC_DEFINE(USE_TCLOO_STUBS, 1, [Use TclOO stubs]) if test "${TEA_WINDOWINGSYSTEM}" != ""; then AC_DEFINE(USE_TK_STUBS, 1, [Use Tk stubs]) fi fi AC_SUBST(SHARED_BUILD) AC_SUBST(STUBS_BUILD) ]) #------------------------------------------------------------------------ # TEA_ENABLE_THREADS -- # # Specify if thread support should be enabled. If "yes" is specified # as an arg (optional), threads are enabled by default, "no" means # threads are disabled. "yes" is the default. # # TCL_THREADS is checked so that if you are compiling an extension # against a threaded core, your extension must be compiled threaded # as well. # # Note that it is legal to have a thread enabled extension run in a # threaded or non-threaded Tcl core, but a non-threaded extension may # only run in a non-threaded Tcl core. # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --enable-threads # # Sets the following vars: # THREADS_LIBS Thread library(s) # # Defines the following vars: # TCL_THREADS # _REENTRANT # _THREAD_SAFE #------------------------------------------------------------------------ AC_DEFUN([TEA_ENABLE_THREADS], [ AC_ARG_ENABLE(threads, AS_HELP_STRING([--enable-threads], [build with threads (default: on)]), [tcl_ok=$enableval], [tcl_ok=yes]) if test "${enable_threads+set}" = set; then enableval="$enable_threads" tcl_ok=$enableval else tcl_ok=yes fi if test "$tcl_ok" = "yes" -o "${TCL_THREADS}" = 1; then TCL_THREADS=1 if test "${TEA_PLATFORM}" != "windows" ; then # We are always OK on Windows, so check what this platform wants: # USE_THREAD_ALLOC tells us to try the special thread-based # allocator that significantly reduces lock contention AC_DEFINE(USE_THREAD_ALLOC, 1, [Do we want to use the threaded memory allocator?]) AC_DEFINE(_REENTRANT, 1, [Do we want the reentrant OS API?]) if test "`uname -s`" = "SunOS" ; then AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1, [Do we really want to follow the standard? Yes we do!]) fi AC_DEFINE(_THREAD_SAFE, 1, [Do we want the thread-safe OS API?]) AC_CHECK_LIB(pthread,pthread_mutex_init,tcl_ok=yes,tcl_ok=no) if test "$tcl_ok" = "no"; then # Check a little harder for __pthread_mutex_init in the same # library, as some systems hide it there until pthread.h is # defined. We could alternatively do an AC_TRY_COMPILE with # pthread.h, but that will work with libpthread really doesn't # exist, like AIX 4.2. [Bug: 4359] AC_CHECK_LIB(pthread, __pthread_mutex_init, tcl_ok=yes, tcl_ok=no) fi if test "$tcl_ok" = "yes"; then # The space is needed THREADS_LIBS=" -lpthread" else AC_CHECK_LIB(pthreads, pthread_mutex_init, tcl_ok=yes, tcl_ok=no) if test "$tcl_ok" = "yes"; then # The space is needed THREADS_LIBS=" -lpthreads" else AC_CHECK_LIB(c, pthread_mutex_init, tcl_ok=yes, tcl_ok=no) if test "$tcl_ok" = "no"; then AC_CHECK_LIB(c_r, pthread_mutex_init, tcl_ok=yes, tcl_ok=no) if test "$tcl_ok" = "yes"; then # The space is needed THREADS_LIBS=" -pthread" else TCL_THREADS=0 AC_MSG_WARN([Do not know how to find pthread lib on your system - thread support disabled]) fi fi fi fi fi else TCL_THREADS=0 fi # Do checking message here to not mess up interleaved configure output AC_MSG_CHECKING([for building with threads]) if test "${TCL_THREADS}" = 1; then AC_DEFINE(TCL_THREADS, 1, [Are we building with threads enabled?]) AC_MSG_RESULT([yes (default)]) else AC_MSG_RESULT([no]) fi # TCL_THREADS sanity checking. See if our request for building with # threads is the same as the way Tcl was built. If not, warn the user. case ${TCL_DEFS} in *THREADS=1*) if test "${TCL_THREADS}" = "0"; then AC_MSG_WARN([ Building ${PACKAGE_NAME} without threads enabled, but building against Tcl that IS thread-enabled. It is recommended to use --enable-threads.]) fi ;; esac AC_SUBST(TCL_THREADS) ]) #------------------------------------------------------------------------ # TEA_ENABLE_SYMBOLS -- # # Specify if debugging symbols should be used. # Memory (TCL_MEM_DEBUG) debugging can also be enabled. # # Arguments: # none # # TEA varies from core Tcl in that C|LDFLAGS_DEFAULT receives # the value of C|LDFLAGS_OPTIMIZE|DEBUG already substituted. # Requires the following vars to be set in the Makefile: # CFLAGS_DEFAULT # LDFLAGS_DEFAULT # # Results: # # Adds the following arguments to configure: # --enable-symbols # # Defines the following vars: # CFLAGS_DEFAULT Sets to $(CFLAGS_DEBUG) if true # Sets to "$(CFLAGS_OPTIMIZE) -DNDEBUG" if false # LDFLAGS_DEFAULT Sets to $(LDFLAGS_DEBUG) if true # Sets to $(LDFLAGS_OPTIMIZE) if false #------------------------------------------------------------------------ AC_DEFUN([TEA_ENABLE_SYMBOLS], [ dnl TEA specific: Make sure we are initialized AC_REQUIRE([TEA_CONFIG_CFLAGS]) AC_MSG_CHECKING([for build with symbols]) AC_ARG_ENABLE(symbols, AS_HELP_STRING([--enable-symbols], [build with debugging symbols (default: off)]), [tcl_ok=$enableval], [tcl_ok=no]) if test "$tcl_ok" = "no"; then CFLAGS_DEFAULT="${CFLAGS_OPTIMIZE} -DNDEBUG" LDFLAGS_DEFAULT="${LDFLAGS_OPTIMIZE}" AC_MSG_RESULT([no]) AC_DEFINE(TCL_CFG_OPTIMIZED, 1, [Is this an optimized build?]) else CFLAGS_DEFAULT="${CFLAGS_DEBUG}" LDFLAGS_DEFAULT="${LDFLAGS_DEBUG}" if test "$tcl_ok" = "yes"; then AC_MSG_RESULT([yes (standard debugging)]) fi fi AC_SUBST(CFLAGS_DEFAULT) AC_SUBST(LDFLAGS_DEFAULT) if test "$tcl_ok" = "mem" -o "$tcl_ok" = "all"; then AC_DEFINE(TCL_MEM_DEBUG, 1, [Is memory debugging enabled?]) fi if test "$tcl_ok" != "yes" -a "$tcl_ok" != "no"; then if test "$tcl_ok" = "all"; then AC_MSG_RESULT([enabled symbols mem debugging]) else AC_MSG_RESULT([enabled $tcl_ok debugging]) fi fi ]) #------------------------------------------------------------------------ # TEA_ENABLE_LANGINFO -- # # Allows use of modern nl_langinfo check for better l10n. # This is only relevant for Unix. # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --enable-langinfo=yes|no (default is yes) # # Defines the following vars: # HAVE_LANGINFO Triggers use of nl_langinfo if defined. #------------------------------------------------------------------------ AC_DEFUN([TEA_ENABLE_LANGINFO], [ AC_ARG_ENABLE(langinfo, AS_HELP_STRING([--enable-langinfo], [use nl_langinfo if possible to determine encoding at startup, otherwise use old heuristic (default: on)]), [langinfo_ok=$enableval], [langinfo_ok=yes]) HAVE_LANGINFO=0 if test "$langinfo_ok" = "yes"; then AC_CHECK_HEADER(langinfo.h,[langinfo_ok=yes],[langinfo_ok=no]) fi AC_MSG_CHECKING([whether to use nl_langinfo]) if test "$langinfo_ok" = "yes"; then AC_CACHE_VAL(tcl_cv_langinfo_h, [ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[nl_langinfo(CODESET);]])], [tcl_cv_langinfo_h=yes],[tcl_cv_langinfo_h=no])]) AC_MSG_RESULT([$tcl_cv_langinfo_h]) if test $tcl_cv_langinfo_h = yes; then AC_DEFINE(HAVE_LANGINFO, 1, [Do we have nl_langinfo()?]) fi else AC_MSG_RESULT([$langinfo_ok]) fi ]) #-------------------------------------------------------------------- # TEA_CONFIG_SYSTEM # # Determine what the system is (some things cannot be easily checked # on a feature-driven basis, alas). This can usually be done via the # "uname" command. # # Arguments: # none # # Results: # Defines the following var: # # system - System/platform/version identification code. # #-------------------------------------------------------------------- AC_DEFUN([TEA_CONFIG_SYSTEM], [ AC_CACHE_CHECK([system version], tcl_cv_sys_version, [ # TEA specific: if test "${TEA_PLATFORM}" = "windows" ; then tcl_cv_sys_version=windows else tcl_cv_sys_version=`uname -s`-`uname -r` if test "$?" -ne 0 ; then AC_MSG_WARN([can't find uname command]) tcl_cv_sys_version=unknown else if test "`uname -s`" = "AIX" ; then tcl_cv_sys_version=AIX-`uname -v`.`uname -r` fi if test "`uname -s`" = "NetBSD" -a -f /etc/debian_version ; then tcl_cv_sys_version=NetBSD-Debian fi fi fi ]) system=$tcl_cv_sys_version ]) #-------------------------------------------------------------------- # TEA_CONFIG_CFLAGS # # Try to determine the proper flags to pass to the compiler # for building shared libraries and other such nonsense. # # Arguments: # none # # Results: # # Defines and substitutes the following vars: # # DL_OBJS, DL_LIBS - removed for TEA, only needed by core. # LDFLAGS - Flags to pass to the compiler when linking object # files into an executable application binary such # as tclsh. # LD_SEARCH_FLAGS-Flags to pass to ld, such as "-R /usr/local/tcl/lib", # that tell the run-time dynamic linker where to look # for shared libraries such as libtcl.so. Depends on # the variable LIB_RUNTIME_DIR in the Makefile. Could # be the same as CC_SEARCH_FLAGS if ${CC} is used to link. # CC_SEARCH_FLAGS-Flags to pass to ${CC}, such as "-Wl,-rpath,/usr/local/tcl/lib", # that tell the run-time dynamic linker where to look # for shared libraries such as libtcl.so. Depends on # the variable LIB_RUNTIME_DIR in the Makefile. # SHLIB_CFLAGS - Flags to pass to cc when compiling the components # of a shared library (may request position-independent # code, among other things). # SHLIB_LD - Base command to use for combining object files # into a shared library. # SHLIB_LD_LIBS - Dependent libraries for the linker to scan when # creating shared libraries. This symbol typically # goes at the end of the "ld" commands that build # shared libraries. The value of the symbol defaults to # "${LIBS}" if all of the dependent libraries should # be specified when creating a shared library. If # dependent libraries should not be specified (as on # SunOS 4.x, where they cause the link to fail, or in # general if Tcl and Tk aren't themselves shared # libraries), then this symbol has an empty string # as its value. # SHLIB_SUFFIX - Suffix to use for the names of dynamically loadable # extensions. An empty string means we don't know how # to use shared libraries on this platform. # LIB_SUFFIX - Specifies everything that comes after the "libfoo" # in a static or shared library name, using the $PACKAGE_VERSION variable # to put the version in the right place. This is used # by platforms that need non-standard library names. # Examples: ${PACKAGE_VERSION}.so.1.1 on NetBSD, since it needs # to have a version after the .so, and ${PACKAGE_VERSION}.a # on AIX, since a shared library needs to have # a .a extension whereas shared objects for loadable # extensions have a .so extension. Defaults to # ${PACKAGE_VERSION}${SHLIB_SUFFIX}. # CFLAGS_DEBUG - # Flags used when running the compiler in debug mode # CFLAGS_OPTIMIZE - # Flags used when running the compiler in optimize mode # CFLAGS - Additional CFLAGS added as necessary (usually 64-bit) #-------------------------------------------------------------------- AC_DEFUN([TEA_CONFIG_CFLAGS], [ dnl TEA specific: Make sure we are initialized AC_REQUIRE([TEA_INIT]) # Step 0.a: Enable 64 bit support? AC_MSG_CHECKING([if 64bit support is requested]) AC_ARG_ENABLE(64bit, AS_HELP_STRING([--enable-64bit], [enable 64bit support (default: off)]), [do64bit=$enableval], [do64bit=no]) AC_MSG_RESULT([$do64bit]) # Step 0.b: Enable Solaris 64 bit VIS support? AC_MSG_CHECKING([if 64bit Sparc VIS support is requested]) AC_ARG_ENABLE(64bit-vis, AS_HELP_STRING([--enable-64bit-vis], [enable 64bit Sparc VIS support (default: off)]), [do64bitVIS=$enableval], [do64bitVIS=no]) AC_MSG_RESULT([$do64bitVIS]) # Force 64bit on with VIS AS_IF([test "$do64bitVIS" = "yes"], [do64bit=yes]) # Step 0.c: Check if visibility support is available. Do this here so # that platform specific alternatives can be used below if this fails. AC_CACHE_CHECK([if compiler supports visibility "hidden"], tcl_cv_cc_visibility_hidden, [ hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -Werror" AC_LINK_IFELSE([AC_LANG_PROGRAM([[ extern __attribute__((__visibility__("hidden"))) void f(void); void f(void) {}]], [[f();]])],[tcl_cv_cc_visibility_hidden=yes], [tcl_cv_cc_visibility_hidden=no]) CFLAGS=$hold_cflags]) AS_IF([test $tcl_cv_cc_visibility_hidden = yes], [ AC_DEFINE(MODULE_SCOPE, [extern __attribute__((__visibility__("hidden")))], [Compiler support for module scope symbols]) AC_DEFINE(HAVE_HIDDEN, [1], [Compiler support for module scope symbols]) ]) # Step 0.d: Disable -rpath support? AC_MSG_CHECKING([if rpath support is requested]) AC_ARG_ENABLE(rpath, AS_HELP_STRING([--disable-rpath], [disable rpath support (default: on)]), [doRpath=$enableval], [doRpath=yes]) AC_MSG_RESULT([$doRpath]) # Set the variable "system" to hold the name and version number # for the system. TEA_CONFIG_SYSTEM # Require ranlib early so we can override it in special cases below. AC_REQUIRE([AC_PROG_RANLIB]) # Set configuration options based on system name and version. # This is similar to Tcl's unix/tcl.m4 except that we've added a # "windows" case and removed some core-only vars. do64bit_ok=no # default to '{$LIBS}' and set to "" on per-platform necessary basis SHLIB_LD_LIBS='${LIBS}' # When ld needs options to work in 64-bit mode, put them in # LDFLAGS_ARCH so they eventually end up in LDFLAGS even if [load] # is disabled by the user. [Bug 1016796] LDFLAGS_ARCH="" UNSHARED_LIB_SUFFIX="" # TEA specific: use PACKAGE_VERSION instead of VERSION TCL_TRIM_DOTS='`echo ${PACKAGE_VERSION} | tr -d .`' ECHO_VERSION='`echo ${PACKAGE_VERSION}`' TCL_LIB_VERSIONS_OK=ok CFLAGS_DEBUG=-g AS_IF([test "$GCC" = yes], [ CFLAGS_OPTIMIZE=-O2 CFLAGS_WARNING="-Wall" ], [ CFLAGS_OPTIMIZE=-O CFLAGS_WARNING="" ]) AC_CHECK_TOOL(AR, ar) STLIB_LD='${AR} cr' LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH" AS_IF([test "x$SHLIB_VERSION" = x],[SHLIB_VERSION=""],[SHLIB_VERSION=".$SHLIB_VERSION"]) case $system in # TEA specific: windows) MACHINE="X86" if test "$do64bit" != "no" ; then case "$do64bit" in amd64|x64|yes) MACHINE="AMD64" ; # default to AMD64 64-bit build ;; arm64|aarch64) MACHINE="ARM64" ;; ia64) MACHINE="IA64" ;; esac fi if test "$GCC" != "yes" ; then if test "${SHARED_BUILD}" = "0" ; then runtime=-MT else runtime=-MD fi case "x`echo \${VisualStudioVersion}`" in x1[[4-9]]*) lflags="${lflags} -nodefaultlib:libucrt.lib" TEA_ADD_LIBS([ucrt.lib]) ;; *) ;; esac if test "$do64bit" != "no" ; then CC="cl.exe" RC="rc.exe" lflags="${lflags} -nologo -MACHINE:${MACHINE} " LINKBIN="link.exe" CFLAGS_DEBUG="-nologo -Zi -Od -W3 ${runtime}d" CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}" # Avoid 'unresolved external symbol __security_cookie' # errors, c.f. http://support.microsoft.com/?id=894573 TEA_ADD_LIBS([bufferoverflowU.lib]) else RC="rc" lflags="${lflags} -nologo" LINKBIN="link" CFLAGS_DEBUG="-nologo -Z7 -Od -W3 -WX ${runtime}d" CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}" fi fi if test "$GCC" = "yes"; then # mingw gcc mode AC_CHECK_TOOL(RC, windres) CFLAGS_DEBUG="-g" CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" SHLIB_LD='${CC} -shared' UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' LDFLAGS_CONSOLE="-wl,--subsystem,console ${lflags}" LDFLAGS_WINDOW="-wl,--subsystem,windows ${lflags}" AC_CACHE_CHECK(for cross-compile version of gcc, ac_cv_cross, AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #ifdef _WIN32 #error cross-compiler #endif ]], [[]])], [ac_cv_cross=yes], [ac_cv_cross=no]) ) if test "$ac_cv_cross" = "yes"; then case "$do64bit" in amd64|x64|yes) CC="x86_64-w64-mingw32-${CC}" LD="x86_64-w64-mingw32-ld" AR="x86_64-w64-mingw32-ar" RANLIB="x86_64-w64-mingw32-ranlib" RC="x86_64-w64-mingw32-windres" ;; arm64|aarch64) CC="aarch64-w64-mingw32-clang" LD="aarch64-w64-mingw32-ld" AR="aarch64-w64-mingw32-ar" RANLIB="aarch64-w64-mingw32-ranlib" RC="aarch64-w64-mingw32-windres" ;; *) CC="i686-w64-mingw32-${CC}" LD="i686-w64-mingw32-ld" AR="i686-w64-mingw32-ar" RANLIB="i686-w64-mingw32-ranlib" RC="i686-w64-mingw32-windres" ;; esac fi else SHLIB_LD="${LINKBIN} -dll ${lflags}" # link -lib only works when -lib is the first arg STLIB_LD="${LINKBIN} -lib ${lflags}" UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.lib' PATHTYPE=-w # For information on what debugtype is most useful, see: # http://msdn.microsoft.com/library/en-us/dnvc60/html/gendepdebug.asp # and also # http://msdn2.microsoft.com/en-us/library/y0zzbyt4%28VS.80%29.aspx # This essentially turns it all on. LDFLAGS_DEBUG="-debug -debugtype:cv" LDFLAGS_OPTIMIZE="-release" LDFLAGS_CONSOLE="-link -subsystem:console ${lflags}" LDFLAGS_WINDOW="-link -subsystem:windows ${lflags}" fi SHLIB_SUFFIX=".dll" SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.dll' TCL_LIB_VERSIONS_OK=nodots ;; AIX-*) AS_IF([test "$GCC" != "yes"], [ # AIX requires the _r compiler when gcc isn't being used case "${CC}" in *_r|*_r\ *) # ok ... ;; *) # Make sure only first arg gets _r CC=`echo "$CC" | sed -e 's/^\([[^ ]]*\)/\1_r/'` ;; esac AC_MSG_RESULT([Using $CC for compiling with threads]) ]) LIBS="$LIBS -lc" SHLIB_CFLAGS="" SHLIB_SUFFIX=".so" LD_LIBRARY_PATH_VAR="LIBPATH" # Check to enable 64-bit flags for compiler/linker AS_IF([test "$do64bit" = yes], [ AS_IF([test "$GCC" = yes], [ AC_MSG_WARN([64bit mode not supported with GCC on $system]) ], [ do64bit_ok=yes CFLAGS="$CFLAGS -q64" LDFLAGS_ARCH="-q64" RANLIB="${RANLIB} -X64" AR="${AR} -X64" SHLIB_LD_FLAGS="-b64" ]) ]) AS_IF([test "`uname -m`" = ia64], [ # AIX-5 uses ELF style dynamic libraries on IA-64, but not PPC SHLIB_LD="/usr/ccs/bin/ld -G -z text" AS_IF([test "$GCC" = yes], [ CC_SEARCH_FLAGS='"-Wl,-R,${LIB_RUNTIME_DIR}"' ], [ CC_SEARCH_FLAGS='"-R${LIB_RUNTIME_DIR}"' ]) LD_SEARCH_FLAGS='-R "${LIB_RUNTIME_DIR}"' ], [ AS_IF([test "$GCC" = yes], [ SHLIB_LD='${CC} -shared -Wl,-bexpall' ], [ SHLIB_LD="/bin/ld -bhalt:4 -bM:SRE -bexpall -H512 -T512 -bnoentry" LDFLAGS="$LDFLAGS -brtl" ]) SHLIB_LD="${SHLIB_LD} ${SHLIB_LD_FLAGS}" CC_SEARCH_FLAGS='"-L${LIB_RUNTIME_DIR}"' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ]) ;; BeOS*) SHLIB_CFLAGS="-fPIC" SHLIB_LD='${CC} -nostart' SHLIB_SUFFIX=".so" #----------------------------------------------------------- # Check for inet_ntoa in -lbind, for BeOS (which also needs # -lsocket, even if the network functions are in -lnet which # is always linked to, for compatibility. #----------------------------------------------------------- AC_CHECK_LIB(bind, inet_ntoa, [LIBS="$LIBS -lbind -lsocket"]) ;; BSD/OS-2.1*|BSD/OS-3*) SHLIB_CFLAGS="" SHLIB_LD="shlicc -r" SHLIB_SUFFIX=".so" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; BSD/OS-4.*) SHLIB_CFLAGS="-export-dynamic -fPIC" SHLIB_LD='${CC} -shared' SHLIB_SUFFIX=".so" LDFLAGS="$LDFLAGS -export-dynamic" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; CYGWIN_*) SHLIB_CFLAGS="" SHLIB_LD='${CC} -shared' SHLIB_SUFFIX=".dll" SHLIB_LD_LIBS="${SHLIB_LD_LIBS} -Wl,--out-implib,\$[@].a" EXEEXT=".exe" do64bit_ok=yes CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; dgux*) SHLIB_CFLAGS="-K PIC" SHLIB_LD='${CC} -G' SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; Haiku*) LDFLAGS="$LDFLAGS -Wl,--export-dynamic" SHLIB_CFLAGS="-fPIC" SHLIB_SUFFIX=".so" SHLIB_LD='${CC} ${CFLAGS} ${LDFLAGS} -shared' AC_CHECK_LIB(network, inet_ntoa, [LIBS="$LIBS -lnetwork"]) ;; HP-UX-*.11.*) # Use updated header definitions where possible AC_DEFINE(_XOPEN_SOURCE_EXTENDED, 1, [Do we want to use the XOPEN network library?]) # TEA specific: Needed by Tcl, but not most extensions #AC_DEFINE(_XOPEN_SOURCE, 1, [Do we want to use the XOPEN network library?]) #LIBS="$LIBS -lxnet" # Use the XOPEN network library AS_IF([test "`uname -m`" = ia64], [ SHLIB_SUFFIX=".so" ], [ SHLIB_SUFFIX=".sl" ]) AC_CHECK_LIB(dld, shl_load, tcl_ok=yes, tcl_ok=no) AS_IF([test "$tcl_ok" = yes], [ SHLIB_CFLAGS="+z" SHLIB_LD="ld -b" LDFLAGS="$LDFLAGS -Wl,-E" CC_SEARCH_FLAGS='"-Wl,+s,+b,${LIB_RUNTIME_DIR}:."' LD_SEARCH_FLAGS='+s +b "${LIB_RUNTIME_DIR}:."' LD_LIBRARY_PATH_VAR="SHLIB_PATH" ]) AS_IF([test "$GCC" = yes], [ SHLIB_LD='${CC} -shared' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ], [ CFLAGS="$CFLAGS -z" ]) # Check to enable 64-bit flags for compiler/linker AS_IF([test "$do64bit" = "yes"], [ AS_IF([test "$GCC" = yes], [ case `${CC} -dumpmachine` in hppa64*) # 64-bit gcc in use. Fix flags for GNU ld. do64bit_ok=yes SHLIB_LD='${CC} -shared' AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"']) LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ;; *) AC_MSG_WARN([64bit mode not supported with GCC on $system]) ;; esac ], [ do64bit_ok=yes CFLAGS="$CFLAGS +DD64" LDFLAGS_ARCH="+DD64" ]) ]) ;; HP-UX-*.08.*|HP-UX-*.09.*|HP-UX-*.10.*) SHLIB_SUFFIX=".sl" AC_CHECK_LIB(dld, shl_load, tcl_ok=yes, tcl_ok=no) AS_IF([test "$tcl_ok" = yes], [ SHLIB_CFLAGS="+z" SHLIB_LD="ld -b" SHLIB_LD_LIBS="" LDFLAGS="$LDFLAGS -Wl,-E" CC_SEARCH_FLAGS='"-Wl,+s,+b,${LIB_RUNTIME_DIR}:."' LD_SEARCH_FLAGS='+s +b "${LIB_RUNTIME_DIR}:."' LD_LIBRARY_PATH_VAR="SHLIB_PATH" ]) ;; IRIX-5.*) SHLIB_CFLAGS="" SHLIB_LD="ld -shared -rdata_shared" SHLIB_SUFFIX=".so" AC_LIBOBJ(mkstemp) AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"' LD_SEARCH_FLAGS='-rpath "${LIB_RUNTIME_DIR}"']) ;; IRIX-6.*) SHLIB_CFLAGS="" SHLIB_LD="ld -n32 -shared -rdata_shared" SHLIB_SUFFIX=".so" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"' LD_SEARCH_FLAGS='-rpath "${LIB_RUNTIME_DIR}"']) AS_IF([test "$GCC" = yes], [ CFLAGS="$CFLAGS -mabi=n32" LDFLAGS="$LDFLAGS -mabi=n32" ], [ case $system in IRIX-6.3) # Use to build 6.2 compatible binaries on 6.3. CFLAGS="$CFLAGS -n32 -D_OLD_TERMIOS" ;; *) CFLAGS="$CFLAGS -n32" ;; esac LDFLAGS="$LDFLAGS -n32" ]) ;; IRIX64-6.*) SHLIB_CFLAGS="" SHLIB_LD="ld -n32 -shared -rdata_shared" SHLIB_SUFFIX=".so" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"' LD_SEARCH_FLAGS='-rpath "${LIB_RUNTIME_DIR}"']) # Check to enable 64-bit flags for compiler/linker AS_IF([test "$do64bit" = yes], [ AS_IF([test "$GCC" = yes], [ AC_MSG_WARN([64bit mode not supported by gcc]) ], [ do64bit_ok=yes SHLIB_LD="ld -64 -shared -rdata_shared" CFLAGS="$CFLAGS -64" LDFLAGS_ARCH="-64" ]) ]) ;; Linux*|GNU*|NetBSD-Debian|DragonFly-*|FreeBSD-*) SHLIB_CFLAGS="-fPIC" SHLIB_SUFFIX=".so" # TEA specific: CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS SHLIB_LD='${CC} ${CFLAGS} ${LDFLAGS_DEFAULT} -shared' LDFLAGS="$LDFLAGS -Wl,--export-dynamic" case $system in DragonFly-*|FreeBSD-*) AS_IF([test "${TCL_THREADS}" = "1"], [ # The -pthread needs to go in the LDFLAGS, not LIBS LIBS=`echo $LIBS | sed s/-pthread//` CFLAGS="$CFLAGS $PTHREAD_CFLAGS" LDFLAGS="$LDFLAGS $PTHREAD_LIBS"]) ;; esac AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"']) LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} AS_IF([test "`uname -m`" = "alpha"], [CFLAGS="$CFLAGS -mieee"]) AS_IF([test $do64bit = yes], [ AC_CACHE_CHECK([if compiler accepts -m64 flag], tcl_cv_cc_m64, [ hold_cflags=$CFLAGS CFLAGS="$CFLAGS -m64" AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[]])], [tcl_cv_cc_m64=yes],[tcl_cv_cc_m64=no]) CFLAGS=$hold_cflags]) AS_IF([test $tcl_cv_cc_m64 = yes], [ CFLAGS="$CFLAGS -m64" do64bit_ok=yes ]) ]) # The combo of gcc + glibc has a bug related to inlining of # functions like strtod(). The -fno-builtin flag should address # this problem but it does not work. The -fno-inline flag is kind # of overkill but it works. Disable inlining only when one of the # files in compat/*.c is being linked in. AS_IF([test x"${USE_COMPAT}" != x],[CFLAGS="$CFLAGS -fno-inline"]) ;; Lynx*) SHLIB_CFLAGS="-fPIC" SHLIB_SUFFIX=".so" CFLAGS_OPTIMIZE=-02 SHLIB_LD='${CC} -shared' LD_FLAGS="-Wl,--export-dynamic" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"' LD_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"']) ;; OpenBSD-*) arch=`arch -s` case "$arch" in alpha|sparc64) SHLIB_CFLAGS="-fPIC" ;; *) SHLIB_CFLAGS="-fpic" ;; esac SHLIB_LD='${CC} ${SHLIB_CFLAGS} -shared' SHLIB_SUFFIX=".so" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"']) LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so${SHLIB_VERSION}' LDFLAGS="$LDFLAGS -Wl,-export-dynamic" CFLAGS_OPTIMIZE="-O2" # On OpenBSD: Compile with -pthread # Don't link with -lpthread LIBS=`echo $LIBS | sed s/-lpthread//` CFLAGS="$CFLAGS -pthread" # OpenBSD doesn't do version numbers with dots. UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' TCL_LIB_VERSIONS_OK=nodots ;; NetBSD-*) # NetBSD has ELF and can use 'cc -shared' to build shared libs SHLIB_CFLAGS="-fPIC" SHLIB_LD='${CC} ${SHLIB_CFLAGS} -shared' SHLIB_SUFFIX=".so" LDFLAGS="$LDFLAGS -export-dynamic" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"']) LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} # The -pthread needs to go in the CFLAGS, not LIBS LIBS=`echo $LIBS | sed s/-pthread//` CFLAGS="$CFLAGS -pthread" LDFLAGS="$LDFLAGS -pthread" ;; Darwin-*) CFLAGS_OPTIMIZE="-Os" SHLIB_CFLAGS="-fno-common" # To avoid discrepancies between what headers configure sees during # preprocessing tests and compiling tests, move any -isysroot and # -mmacosx-version-min flags from CFLAGS to CPPFLAGS: CPPFLAGS="${CPPFLAGS} `echo " ${CFLAGS}" | \ awk 'BEGIN {FS=" +-";ORS=" "}; {for (i=2;i<=NF;i++) \ if ([$]i~/^(isysroot|mmacosx-version-min)/) print "-"[$]i}'`" CFLAGS="`echo " ${CFLAGS}" | \ awk 'BEGIN {FS=" +-";ORS=" "}; {for (i=2;i<=NF;i++) \ if (!([$]i~/^(isysroot|mmacosx-version-min)/)) print "-"[$]i}'`" AS_IF([test $do64bit = yes], [ case `arch` in ppc) AC_CACHE_CHECK([if compiler accepts -arch ppc64 flag], tcl_cv_cc_arch_ppc64, [ hold_cflags=$CFLAGS CFLAGS="$CFLAGS -arch ppc64 -mpowerpc64 -mcpu=G5" AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[]])], [tcl_cv_cc_arch_ppc64=yes],[tcl_cv_cc_arch_ppc64=no]) CFLAGS=$hold_cflags]) AS_IF([test $tcl_cv_cc_arch_ppc64 = yes], [ CFLAGS="$CFLAGS -arch ppc64 -mpowerpc64 -mcpu=G5" do64bit_ok=yes ]);; i386) AC_CACHE_CHECK([if compiler accepts -arch x86_64 flag], tcl_cv_cc_arch_x86_64, [ hold_cflags=$CFLAGS CFLAGS="$CFLAGS -arch x86_64" AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[]])], [tcl_cv_cc_arch_x86_64=yes],[tcl_cv_cc_arch_x86_64=no]) CFLAGS=$hold_cflags]) AS_IF([test $tcl_cv_cc_arch_x86_64 = yes], [ CFLAGS="$CFLAGS -arch x86_64" do64bit_ok=yes ]);; *) AC_MSG_WARN([Don't know how enable 64-bit on architecture `arch`]);; esac ], [ # Check for combined 32-bit and 64-bit fat build AS_IF([echo "$CFLAGS " |grep -E -q -- '-arch (ppc64|x86_64) ' \ && echo "$CFLAGS " |grep -E -q -- '-arch (ppc|i386) '], [ fat_32_64=yes]) ]) # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS SHLIB_LD='${CC} -dynamiclib ${CFLAGS} ${LDFLAGS_DEFAULT}' AC_CACHE_CHECK([if ld accepts -single_module flag], tcl_cv_ld_single_module, [ hold_ldflags=$LDFLAGS LDFLAGS="$LDFLAGS -dynamiclib -Wl,-single_module" AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[int i;]])], [tcl_cv_ld_single_module=yes],[tcl_cv_ld_single_module=no]) LDFLAGS=$hold_ldflags]) AS_IF([test $tcl_cv_ld_single_module = yes], [ SHLIB_LD="${SHLIB_LD} -Wl,-single_module" ]) # TEA specific: link shlib with current and compatibility version flags vers=`echo ${PACKAGE_VERSION} | sed -e 's/^\([[0-9]]\{1,5\}\)\(\(\.[[0-9]]\{1,3\}\)\{0,2\}\).*$/\1\2/p' -e d` SHLIB_LD="${SHLIB_LD} -current_version ${vers:-0} -compatibility_version ${vers:-0}" SHLIB_SUFFIX=".dylib" LDFLAGS="$LDFLAGS -headerpad_max_install_names" AC_CACHE_CHECK([if ld accepts -search_paths_first flag], tcl_cv_ld_search_paths_first, [ hold_ldflags=$LDFLAGS LDFLAGS="$LDFLAGS -Wl,-search_paths_first" AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[int i;]])], [tcl_cv_ld_search_paths_first=yes],[tcl_cv_ld_search_paths_first=no]) LDFLAGS=$hold_ldflags]) AS_IF([test $tcl_cv_ld_search_paths_first = yes], [ LDFLAGS="$LDFLAGS -Wl,-search_paths_first" ]) AS_IF([test "$tcl_cv_cc_visibility_hidden" != yes], [ AC_DEFINE(MODULE_SCOPE, [__private_extern__], [Compiler support for module scope symbols]) tcl_cv_cc_visibility_hidden=yes ]) CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" LD_LIBRARY_PATH_VAR="DYLD_LIBRARY_PATH" # TEA specific: for combined 32 & 64 bit fat builds of Tk # extensions, verify that 64-bit build is possible. AS_IF([test "$fat_32_64" = yes && test -n "${TK_BIN_DIR}"], [ AS_IF([test "${TEA_WINDOWINGSYSTEM}" = x11], [ AC_CACHE_CHECK([for 64-bit X11], tcl_cv_lib_x11_64, [ for v in CFLAGS CPPFLAGS LDFLAGS; do eval 'hold_'$v'="$'$v'";'$v'="`echo "$'$v' "|sed -e "s/-arch ppc / /g" -e "s/-arch i386 / /g"`"' done CPPFLAGS="$CPPFLAGS -I/usr/X11R6/include" LDFLAGS="$LDFLAGS -L/usr/X11R6/lib -lX11" AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[XrmInitialize();]])], [tcl_cv_lib_x11_64=yes],[tcl_cv_lib_x11_64=no]) for v in CFLAGS CPPFLAGS LDFLAGS; do eval $v'="$hold_'$v'"' done]) ]) AS_IF([test "${TEA_WINDOWINGSYSTEM}" = aqua], [ AC_CACHE_CHECK([for 64-bit Tk], tcl_cv_lib_tk_64, [ for v in CFLAGS CPPFLAGS LDFLAGS; do eval 'hold_'$v'="$'$v'";'$v'="`echo "$'$v' "|sed -e "s/-arch ppc / /g" -e "s/-arch i386 / /g"`"' done CPPFLAGS="$CPPFLAGS -DUSE_TCL_STUBS=1 -DUSE_TK_STUBS=1 ${TCL_INCLUDES} ${TK_INCLUDES}" LDFLAGS="$LDFLAGS ${TCL_STUB_LIB_SPEC} ${TK_STUB_LIB_SPEC}" AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[Tk_InitStubs(NULL, "", 0);]])], [tcl_cv_lib_tk_64=yes],[tcl_cv_lib_tk_64=no]) for v in CFLAGS CPPFLAGS LDFLAGS; do eval $v'="$hold_'$v'"' done]) ]) # remove 64-bit arch flags from CFLAGS et al. if configuration # does not support 64-bit. AS_IF([test "$tcl_cv_lib_tk_64" = no -o "$tcl_cv_lib_x11_64" = no], [ AC_MSG_NOTICE([Removing 64-bit architectures from compiler & linker flags]) for v in CFLAGS CPPFLAGS LDFLAGS; do eval $v'="`echo "$'$v' "|sed -e "s/-arch ppc64 / /g" -e "s/-arch x86_64 / /g"`"' done]) ]) ;; OS/390-*) CFLAGS_OPTIMIZE="" # Optimizer is buggy AC_DEFINE(_OE_SOCKETS, 1, # needed in sys/socket.h [Should OS/390 do the right thing with sockets?]) ;; OSF1-V*) # Digital OSF/1 SHLIB_CFLAGS="" AS_IF([test "$SHARED_BUILD" = 1], [ SHLIB_LD='ld -shared -expect_unresolved "*"' ], [ SHLIB_LD='ld -non_shared -expect_unresolved "*"' ]) SHLIB_SUFFIX=".so" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}']) AS_IF([test "$GCC" = yes], [CFLAGS="$CFLAGS -mieee"], [ CFLAGS="$CFLAGS -DHAVE_TZSET -std1 -ieee"]) # see pthread_intro(3) for pthread support on osf1, k.furukawa CFLAGS="$CFLAGS -DHAVE_PTHREAD_ATTR_SETSTACKSIZE" CFLAGS="$CFLAGS -DTCL_THREAD_STACK_MIN=PTHREAD_STACK_MIN*64" LIBS=`echo $LIBS | sed s/-lpthreads//` AS_IF([test "$GCC" = yes], [ LIBS="$LIBS -lpthread -lmach -lexc" ], [ CFLAGS="$CFLAGS -pthread" LDFLAGS="$LDFLAGS -pthread" ]) ;; QNX-6*) # QNX RTP # This may work for all QNX, but it was only reported for v6. SHLIB_CFLAGS="-fPIC" SHLIB_LD="ld -Bshareable -x" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; SCO_SV-3.2*) AS_IF([test "$GCC" = yes], [ SHLIB_CFLAGS="-fPIC -melf" LDFLAGS="$LDFLAGS -melf -Wl,-Bexport" ], [ SHLIB_CFLAGS="-Kpic -belf" LDFLAGS="$LDFLAGS -belf -Wl,-Bexport" ]) SHLIB_LD="ld -G" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; SunOS-5.[[0-6]]) # Careful to not let 5.10+ fall into this case # Note: If _REENTRANT isn't defined, then Solaris # won't define thread-safe library routines. AC_DEFINE(_REENTRANT, 1, [Do we want the reentrant OS API?]) AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1, [Do we really want to follow the standard? Yes we do!]) SHLIB_CFLAGS="-KPIC" SHLIB_SUFFIX=".so" AS_IF([test "$GCC" = yes], [ SHLIB_LD='${CC} -shared' CC_SEARCH_FLAGS='"-Wl,-R,${LIB_RUNTIME_DIR}"' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ], [ SHLIB_LD="/usr/ccs/bin/ld -G -z text" CC_SEARCH_FLAGS='-R "${LIB_RUNTIME_DIR}"' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ]) ;; SunOS-5*) # Note: If _REENTRANT isn't defined, then Solaris # won't define thread-safe library routines. AC_DEFINE(_REENTRANT, 1, [Do we want the reentrant OS API?]) AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1, [Do we really want to follow the standard? Yes we do!]) SHLIB_CFLAGS="-KPIC" # Check to enable 64-bit flags for compiler/linker AS_IF([test "$do64bit" = yes], [ arch=`isainfo` AS_IF([test "$arch" = "sparcv9 sparc"], [ AS_IF([test "$GCC" = yes], [ AS_IF([test "`${CC} -dumpversion | awk -F. '{print [$]1}'`" -lt 3], [ AC_MSG_WARN([64bit mode not supported with GCC < 3.2 on $system]) ], [ do64bit_ok=yes CFLAGS="$CFLAGS -m64 -mcpu=v9" LDFLAGS="$LDFLAGS -m64 -mcpu=v9" SHLIB_CFLAGS="-fPIC" ]) ], [ do64bit_ok=yes AS_IF([test "$do64bitVIS" = yes], [ CFLAGS="$CFLAGS -xarch=v9a" LDFLAGS_ARCH="-xarch=v9a" ], [ CFLAGS="$CFLAGS -xarch=v9" LDFLAGS_ARCH="-xarch=v9" ]) # Solaris 64 uses this as well #LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH_64" ]) ], [AS_IF([test "$arch" = "amd64 i386"], [ AS_IF([test "$GCC" = yes], [ case $system in SunOS-5.1[[1-9]]*|SunOS-5.[[2-9]][[0-9]]*) do64bit_ok=yes CFLAGS="$CFLAGS -m64" LDFLAGS="$LDFLAGS -m64";; *) AC_MSG_WARN([64bit mode not supported with GCC on $system]);; esac ], [ do64bit_ok=yes case $system in SunOS-5.1[[1-9]]*|SunOS-5.[[2-9]][[0-9]]*) CFLAGS="$CFLAGS -m64" LDFLAGS="$LDFLAGS -m64";; *) CFLAGS="$CFLAGS -xarch=amd64" LDFLAGS="$LDFLAGS -xarch=amd64";; esac ]) ], [AC_MSG_WARN([64bit mode not supported for $arch])])]) ]) SHLIB_SUFFIX=".so" AS_IF([test "$GCC" = yes], [ SHLIB_LD='${CC} -shared' CC_SEARCH_FLAGS='"-Wl,-R,${LIB_RUNTIME_DIR}"' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} AS_IF([test "$do64bit_ok" = yes], [ AS_IF([test "$arch" = "sparcv9 sparc"], [ # We need to specify -static-libgcc or we need to # add the path to the sparv9 libgcc. # JH: static-libgcc is necessary for core Tcl, but may # not be necessary for extensions. SHLIB_LD="$SHLIB_LD -m64 -mcpu=v9 -static-libgcc" # for finding sparcv9 libgcc, get the regular libgcc # path, remove so name and append 'sparcv9' #v9gcclibdir="`gcc -print-file-name=libgcc_s.so` | ..." #CC_SEARCH_FLAGS="${CC_SEARCH_FLAGS},-R,$v9gcclibdir" ], [AS_IF([test "$arch" = "amd64 i386"], [ # JH: static-libgcc is necessary for core Tcl, but may # not be necessary for extensions. SHLIB_LD="$SHLIB_LD -m64 -static-libgcc" ])]) ]) ], [ case $system in SunOS-5.[[1-9]][[0-9]]*) # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS SHLIB_LD='${CC} -G -z text ${LDFLAGS_DEFAULT}';; *) SHLIB_LD='/usr/ccs/bin/ld -G -z text';; esac CC_SEARCH_FLAGS='"-Wl,-R,${LIB_RUNTIME_DIR}"' LD_SEARCH_FLAGS='-R "${LIB_RUNTIME_DIR}"' ]) ;; UNIX_SV* | UnixWare-5*) SHLIB_CFLAGS="-KPIC" SHLIB_LD='${CC} -G' SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" # Some UNIX_SV* systems (unixware 1.1.2 for example) have linkers # that don't grok the -Bexport option. Test that it does. AC_CACHE_CHECK([for ld accepts -Bexport flag], tcl_cv_ld_Bexport, [ hold_ldflags=$LDFLAGS LDFLAGS="$LDFLAGS -Wl,-Bexport" AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[int i;]])], [tcl_cv_ld_Bexport=yes],[tcl_cv_ld_Bexport=no]) LDFLAGS=$hold_ldflags]) AS_IF([test $tcl_cv_ld_Bexport = yes], [ LDFLAGS="$LDFLAGS -Wl,-Bexport" ]) CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; esac AS_IF([test "$do64bit" = yes -a "$do64bit_ok" = no], [ AC_MSG_WARN([64bit support being disabled -- don't know magic for this platform]) ]) dnl # Add any CPPFLAGS set in the environment to our CFLAGS, but delay doing so dnl # until the end of configure, as configure's compile and link tests use dnl # both CPPFLAGS and CFLAGS (unlike our compile and link) but configure's dnl # preprocessing tests use only CPPFLAGS. AC_CONFIG_COMMANDS_PRE([CFLAGS="${CFLAGS} ${CPPFLAGS}"; CPPFLAGS=""]) # Add in the arch flags late to ensure it wasn't removed. # Not necessary in TEA, but this is aligned with core LDFLAGS="$LDFLAGS $LDFLAGS_ARCH" # If we're running gcc, then change the C flags for compiling shared # libraries to the right flags for gcc, instead of those for the # standard manufacturer compiler. AS_IF([test "$GCC" = yes], [ case $system in AIX-*) ;; BSD/OS*) ;; CYGWIN_*|MINGW32_*|MINGW64_*|MSYS_*) ;; IRIX*) ;; NetBSD-*|DragonFly-*|FreeBSD-*|OpenBSD-*) ;; Darwin-*) ;; SCO_SV-3.2*) ;; windows) ;; *) SHLIB_CFLAGS="-fPIC" ;; esac]) AS_IF([test "$tcl_cv_cc_visibility_hidden" != yes], [ AC_DEFINE(MODULE_SCOPE, [extern], [No Compiler support for module scope symbols]) ]) AS_IF([test "$SHARED_LIB_SUFFIX" = ""], [ # TEA specific: use PACKAGE_VERSION instead of VERSION SHARED_LIB_SUFFIX='${PACKAGE_VERSION}${SHLIB_SUFFIX}']) AS_IF([test "$UNSHARED_LIB_SUFFIX" = ""], [ # TEA specific: use PACKAGE_VERSION instead of VERSION UNSHARED_LIB_SUFFIX='${PACKAGE_VERSION}.a']) if test "${GCC}" = "yes" -a ${SHLIB_SUFFIX} = ".dll"; then AC_CACHE_CHECK(for SEH support in compiler, tcl_cv_seh, AC_RUN_IFELSE([AC_LANG_SOURCE([[ #define WIN32_LEAN_AND_MEAN #include #undef WIN32_LEAN_AND_MEAN int main(int argc, char** argv) { int a, b = 0; __try { a = 666 / b; } __except (EXCEPTION_EXECUTE_HANDLER) { return 0; } return 1; } ]])], [tcl_cv_seh=yes], [tcl_cv_seh=no], [tcl_cv_seh=no]) ) if test "$tcl_cv_seh" = "no" ; then AC_DEFINE(HAVE_NO_SEH, 1, [Defined when mingw does not support SEH]) fi # # Check to see if the excpt.h include file provided contains the # definition for EXCEPTION_DISPOSITION; if not, which is the case # with Cygwin's version as of 2002-04-10, define it to be int, # sufficient for getting the current code to work. # AC_CACHE_CHECK(for EXCEPTION_DISPOSITION support in include files, tcl_cv_eh_disposition, AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ # define WIN32_LEAN_AND_MEAN # include # undef WIN32_LEAN_AND_MEAN ]], [[ EXCEPTION_DISPOSITION x; ]])], [tcl_cv_eh_disposition=yes], [tcl_cv_eh_disposition=no]) ) if test "$tcl_cv_eh_disposition" = "no" ; then AC_DEFINE(EXCEPTION_DISPOSITION, int, [Defined when cygwin/mingw does not support EXCEPTION DISPOSITION]) fi # Check to see if winnt.h defines CHAR, SHORT, and LONG # even if VOID has already been #defined. The win32api # used by mingw and cygwin is known to do this. AC_CACHE_CHECK(for winnt.h that ignores VOID define, tcl_cv_winnt_ignore_void, AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #define VOID void #define WIN32_LEAN_AND_MEAN #include #undef WIN32_LEAN_AND_MEAN ]], [[ CHAR c; SHORT s; LONG l; ]])], [tcl_cv_winnt_ignore_void=yes], [tcl_cv_winnt_ignore_void=no]) ) if test "$tcl_cv_winnt_ignore_void" = "yes" ; then AC_DEFINE(HAVE_WINNT_IGNORE_VOID, 1, [Defined when cygwin/mingw ignores VOID define in winnt.h]) fi fi # See if the compiler supports casting to a union type. # This is used to stop gcc from printing a compiler # warning when initializing a union member. AC_CACHE_CHECK(for cast to union support, tcl_cv_cast_to_union, AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[ union foo { int i; double d; }; union foo f = (union foo) (int) 0; ]])], [tcl_cv_cast_to_union=yes], [tcl_cv_cast_to_union=no]) ) if test "$tcl_cv_cast_to_union" = "yes"; then AC_DEFINE(HAVE_CAST_TO_UNION, 1, [Defined when compiler supports casting to union type.]) fi AC_CHECK_HEADER(stdbool.h, [AC_DEFINE(HAVE_STDBOOL_H, 1, [Do we have ?])],) AC_SUBST(CFLAGS_DEBUG) AC_SUBST(CFLAGS_OPTIMIZE) AC_SUBST(CFLAGS_WARNING) AC_SUBST(LDFLAGS_DEBUG) AC_SUBST(LDFLAGS_OPTIMIZE) AC_SUBST(STLIB_LD) AC_SUBST(SHLIB_LD) AC_SUBST(SHLIB_LD_LIBS) AC_SUBST(SHLIB_CFLAGS) AC_SUBST(LD_LIBRARY_PATH_VAR) # These must be called after we do the basic CFLAGS checks and # verify any possible 64-bit or similar switches are necessary TEA_TCL_EARLY_FLAGS TEA_TCL_64BIT_FLAGS ]) #-------------------------------------------------------------------- # TEA_SERIAL_PORT # # Determine which interface to use to talk to the serial port. # Note that #include lines must begin in leftmost column for # some compilers to recognize them as preprocessor directives, # and some build environments have stdin not pointing at a # pseudo-terminal (usually /dev/null instead.) # # Arguments: # none # # Results: # # Defines only one of the following vars: # HAVE_SYS_MODEM_H # USE_TERMIOS # USE_TERMIO # USE_SGTTY #-------------------------------------------------------------------- AC_DEFUN([TEA_SERIAL_PORT], [ AC_CHECK_HEADERS(sys/modem.h) AC_CACHE_CHECK([termios vs. termio vs. sgtty], tcl_cv_api_serial, [ AC_RUN_IFELSE([AC_LANG_SOURCE([[ #include int main() { struct termios t; if (tcgetattr(0, &t) == 0) { cfsetospeed(&t, 0); t.c_cflag |= PARENB | PARODD | CSIZE | CSTOPB; return 0; } return 1; }]])],[tcl_cv_api_serial=termios],[tcl_cv_api_serial=no],[tcl_cv_api_serial=no]) if test $tcl_cv_api_serial = no ; then AC_RUN_IFELSE([AC_LANG_SOURCE([[ #include int main() { struct termio t; if (ioctl(0, TCGETA, &t) == 0) { t.c_cflag |= CBAUD | PARENB | PARODD | CSIZE | CSTOPB; return 0; } return 1; }]])],[tcl_cv_api_serial=termio],[tcl_cv_api_serial=no],[tcl_cv_api_serial=no]) fi if test $tcl_cv_api_serial = no ; then AC_RUN_IFELSE([AC_LANG_SOURCE([[ #include int main() { struct sgttyb t; if (ioctl(0, TIOCGETP, &t) == 0) { t.sg_ospeed = 0; t.sg_flags |= ODDP | EVENP | RAW; return 0; } return 1; }]])],[tcl_cv_api_serial=sgtty],[tcl_cv_api_serial=no],[tcl_cv_api_serial=no]) fi if test $tcl_cv_api_serial = no ; then AC_RUN_IFELSE([AC_LANG_SOURCE([[ #include #include int main() { struct termios t; if (tcgetattr(0, &t) == 0 || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { cfsetospeed(&t, 0); t.c_cflag |= PARENB | PARODD | CSIZE | CSTOPB; return 0; } return 1; }]])],[tcl_cv_api_serial=termios],[tcl_cv_api_serial=no],[tcl_cv_api_serial=no]) fi if test $tcl_cv_api_serial = no; then AC_RUN_IFELSE([AC_LANG_SOURCE([[ #include #include int main() { struct termio t; if (ioctl(0, TCGETA, &t) == 0 || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { t.c_cflag |= CBAUD | PARENB | PARODD | CSIZE | CSTOPB; return 0; } return 1; }]])],[tcl_cv_api_serial=termio],[tcl_cv_api_serial=no],[tcl_cv_api_serial=no]) fi if test $tcl_cv_api_serial = no; then AC_RUN_IFELSE([AC_LANG_SOURCE([[ #include #include int main() { struct sgttyb t; if (ioctl(0, TIOCGETP, &t) == 0 || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { t.sg_ospeed = 0; t.sg_flags |= ODDP | EVENP | RAW; return 0; } return 1; }]])],[tcl_cv_api_serial=sgtty],[tcl_cv_api_serial=none],[tcl_cv_api_serial=none]) fi]) case $tcl_cv_api_serial in termios) AC_DEFINE(USE_TERMIOS, 1, [Use the termios API for serial lines]);; termio) AC_DEFINE(USE_TERMIO, 1, [Use the termio API for serial lines]);; sgtty) AC_DEFINE(USE_SGTTY, 1, [Use the sgtty API for serial lines]);; esac ]) #-------------------------------------------------------------------- # TEA_PATH_X # # Locate the X11 header files and the X11 library archive. Try # the ac_path_x macro first, but if it doesn't find the X stuff # (e.g. because there's no xmkmf program) then check through # a list of possible directories. Under some conditions the # autoconf macro will return an include directory that contains # no include files, so double-check its result just to be safe. # # This should be called after TEA_CONFIG_CFLAGS as setting the # LIBS line can confuse some configure macro magic. # # Arguments: # none # # Results: # # Sets the following vars: # XINCLUDES # XLIBSW # PKG_LIBS (appends to) #-------------------------------------------------------------------- AC_DEFUN([TEA_PATH_X], [ if test "${TEA_WINDOWINGSYSTEM}" = "x11" ; then TEA_PATH_UNIX_X fi ]) AC_DEFUN([TEA_PATH_UNIX_X], [ AC_PATH_X not_really_there="" if test "$no_x" = ""; then if test "$x_includes" = ""; then AC_PREPROC_IFELSE([AC_LANG_SOURCE([[#include ]])],[],[not_really_there="yes"]) else if test ! -r $x_includes/X11/Xlib.h; then not_really_there="yes" fi fi fi if test "$no_x" = "yes" -o "$not_really_there" = "yes"; then AC_MSG_CHECKING([for X11 header files]) found_xincludes="no" AC_PREPROC_IFELSE([AC_LANG_SOURCE([[#include ]])],[found_xincludes="yes"],[found_xincludes="no"]) if test "$found_xincludes" = "no"; then dirs="/usr/unsupported/include /usr/local/include /usr/X386/include /usr/X11R6/include /usr/X11R5/include /usr/include/X11R5 /usr/include/X11R4 /usr/openwin/include /usr/X11/include /usr/sww/include" for i in $dirs ; do if test -r $i/X11/Xlib.h; then AC_MSG_RESULT([$i]) XINCLUDES=" -I$i" found_xincludes="yes" break fi done fi else if test "$x_includes" != ""; then XINCLUDES="-I$x_includes" found_xincludes="yes" fi fi if test "$found_xincludes" = "no"; then AC_MSG_RESULT([couldn't find any!]) fi if test "$no_x" = yes; then AC_MSG_CHECKING([for X11 libraries]) XLIBSW=nope dirs="/usr/unsupported/lib /usr/local/lib /usr/X386/lib /usr/X11R6/lib /usr/X11R5/lib /usr/lib/X11R5 /usr/lib/X11R4 /usr/openwin/lib /usr/X11/lib /usr/sww/X11/lib" for i in $dirs ; do if test -r $i/libX11.a -o -r $i/libX11.so -o -r $i/libX11.sl -o -r $i/libX11.dylib; then AC_MSG_RESULT([$i]) XLIBSW="-L$i -lX11" x_libraries="$i" break fi done else if test "$x_libraries" = ""; then XLIBSW=-lX11 else XLIBSW="-L$x_libraries -lX11" fi fi if test "$XLIBSW" = nope ; then AC_CHECK_LIB(Xwindow, XCreateWindow, XLIBSW=-lXwindow) fi if test "$XLIBSW" = nope ; then AC_MSG_RESULT([could not find any! Using -lX11.]) XLIBSW=-lX11 fi # TEA specific: if test x"${XLIBSW}" != x ; then PKG_LIBS="${PKG_LIBS} ${XLIBSW}" fi ]) #-------------------------------------------------------------------- # TEA_BLOCKING_STYLE # # The statements below check for systems where POSIX-style # non-blocking I/O (O_NONBLOCK) doesn't work or is unimplemented. # On these systems (mostly older ones), use the old BSD-style # FIONBIO approach instead. # # Arguments: # none # # Results: # # Defines some of the following vars: # HAVE_SYS_IOCTL_H # HAVE_SYS_FILIO_H # USE_FIONBIO # O_NONBLOCK #-------------------------------------------------------------------- AC_DEFUN([TEA_BLOCKING_STYLE], [ AC_CHECK_HEADERS(sys/ioctl.h) AC_CHECK_HEADERS(sys/filio.h) TEA_CONFIG_SYSTEM AC_MSG_CHECKING([FIONBIO vs. O_NONBLOCK for nonblocking I/O]) case $system in OSF*) AC_DEFINE(USE_FIONBIO, 1, [Should we use FIONBIO?]) AC_MSG_RESULT([FIONBIO]) ;; *) AC_MSG_RESULT([O_NONBLOCK]) ;; esac ]) #-------------------------------------------------------------------- # TEA_TIME_HANDLER # # Checks how the system deals with time.h, what time structures # are used on the system, and what fields the structures have. # # Arguments: # none # # Results: # # Defines some of the following vars: # USE_DELTA_FOR_TZ # HAVE_TM_GMTOFF # HAVE_TM_TZADJ # HAVE_TIMEZONE_VAR # #-------------------------------------------------------------------- AC_DEFUN([TEA_TIME_HANDLER], [ AC_CHECK_HEADERS(sys/time.h) AC_HEADER_TIME AC_STRUCT_TIMEZONE AC_CHECK_FUNCS(gmtime_r localtime_r mktime) AC_CACHE_CHECK([tm_tzadj in struct tm], tcl_cv_member_tm_tzadj, [ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[struct tm tm; (void)tm.tm_tzadj;]])], [tcl_cv_member_tm_tzadj=yes], [tcl_cv_member_tm_tzadj=no])]) if test $tcl_cv_member_tm_tzadj = yes ; then AC_DEFINE(HAVE_TM_TZADJ, 1, [Should we use the tm_tzadj field of struct tm?]) fi AC_CACHE_CHECK([tm_gmtoff in struct tm], tcl_cv_member_tm_gmtoff, [ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[struct tm tm; (void)tm.tm_gmtoff;]])], [tcl_cv_member_tm_gmtoff=yes], [tcl_cv_member_tm_gmtoff=no])]) if test $tcl_cv_member_tm_gmtoff = yes ; then AC_DEFINE(HAVE_TM_GMTOFF, 1, [Should we use the tm_gmtoff field of struct tm?]) fi # # Its important to include time.h in this check, as some systems # (like convex) have timezone functions, etc. # AC_CACHE_CHECK([long timezone variable], tcl_cv_timezone_long, [ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include #include ]], [[extern long timezone; timezone += 1; exit (0);]])], [tcl_cv_timezone_long=yes], [tcl_cv_timezone_long=no])]) if test $tcl_cv_timezone_long = yes ; then AC_DEFINE(HAVE_TIMEZONE_VAR, 1, [Should we use the global timezone variable?]) else # # On some systems (eg IRIX 6.2), timezone is a time_t and not a long. # AC_CACHE_CHECK([time_t timezone variable], tcl_cv_timezone_time, [ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include #include ]], [[extern time_t timezone; timezone += 1; exit (0);]])], [tcl_cv_timezone_time=yes], [tcl_cv_timezone_time=no])]) if test $tcl_cv_timezone_time = yes ; then AC_DEFINE(HAVE_TIMEZONE_VAR, 1, [Should we use the global timezone variable?]) fi fi ]) #-------------------------------------------------------------------- # TEA_BUGGY_STRTOD # # Under Solaris 2.4, strtod returns the wrong value for the # terminating character under some conditions. Check for this # and if the problem exists use a substitute procedure # "fixstrtod" (provided by Tcl) that corrects the error. # Also, on Compaq's Tru64 Unix 5.0, # strtod(" ") returns 0.0 instead of a failure to convert. # # Arguments: # none # # Results: # # Might defines some of the following vars: # strtod (=fixstrtod) #-------------------------------------------------------------------- AC_DEFUN([TEA_BUGGY_STRTOD], [ AC_CHECK_FUNC(strtod, tcl_strtod=1, tcl_strtod=0) if test "$tcl_strtod" = 1; then AC_CACHE_CHECK([for Solaris2.4/Tru64 strtod bugs], tcl_cv_strtod_buggy,[ AC_RUN_IFELSE([AC_LANG_SOURCE([[ #include extern double strtod(); int main() { char *infString="Inf", *nanString="NaN", *spaceString=" "; char *term; double value; value = strtod(infString, &term); if ((term != infString) && (term[-1] == 0)) { exit(1); } value = strtod(nanString, &term); if ((term != nanString) && (term[-1] == 0)) { exit(1); } value = strtod(spaceString, &term); if (term == (spaceString+1)) { exit(1); } exit(0); }]])], [tcl_cv_strtod_buggy=ok], [tcl_cv_strtod_buggy=buggy], [tcl_cv_strtod_buggy=buggy])]) if test "$tcl_cv_strtod_buggy" = buggy; then AC_LIBOBJ([fixstrtod]) USE_COMPAT=1 AC_DEFINE(strtod, fixstrtod, [Do we want to use the strtod() in compat?]) fi fi ]) #-------------------------------------------------------------------- # TEA_TCL_LINK_LIBS # # Search for the libraries needed to link the Tcl shell. # Things like the math library (-lm), socket stuff (-lsocket vs. # -lnsl), zlib (-lz) and libtommath (-ltommath) are dealt with here. # # Arguments: # None. # # Results: # # Might append to the following vars: # LIBS # MATH_LIBS # # Might define the following vars: # HAVE_NET_ERRNO_H # #-------------------------------------------------------------------- AC_DEFUN([TEA_TCL_LINK_LIBS], [ #-------------------------------------------------------------------- # On a few very rare systems, all of the libm.a stuff is # already in libc.a. Set compiler flags accordingly. #-------------------------------------------------------------------- AC_CHECK_FUNC(sin, MATH_LIBS="", MATH_LIBS="-lm") #-------------------------------------------------------------------- # Interactive UNIX requires -linet instead of -lsocket, plus it # needs net/errno.h to define the socket-related error codes. #-------------------------------------------------------------------- AC_CHECK_LIB(inet, main, [LIBS="$LIBS -linet"]) AC_CHECK_HEADER(net/errno.h, [ AC_DEFINE(HAVE_NET_ERRNO_H, 1, [Do we have ?])]) #-------------------------------------------------------------------- # Check for the existence of the -lsocket and -lnsl libraries. # The order here is important, so that they end up in the right # order in the command line generated by make. Here are some # special considerations: # 1. Use "connect" and "accept" to check for -lsocket, and # "gethostbyname" to check for -lnsl. # 2. Use each function name only once: can't redo a check because # autoconf caches the results of the last check and won't redo it. # 3. Use -lnsl and -lsocket only if they supply procedures that # aren't already present in the normal libraries. This is because # IRIX 5.2 has libraries, but they aren't needed and they're # bogus: they goof up name resolution if used. # 4. On some SVR4 systems, can't use -lsocket without -lnsl too. # To get around this problem, check for both libraries together # if -lsocket doesn't work by itself. #-------------------------------------------------------------------- tcl_checkBoth=0 AC_CHECK_FUNC(connect, tcl_checkSocket=0, tcl_checkSocket=1) if test "$tcl_checkSocket" = 1; then AC_CHECK_FUNC(setsockopt, , [AC_CHECK_LIB(socket, setsockopt, LIBS="$LIBS -lsocket", tcl_checkBoth=1)]) fi if test "$tcl_checkBoth" = 1; then tk_oldLibs=$LIBS LIBS="$LIBS -lsocket -lnsl" AC_CHECK_FUNC(accept, tcl_checkNsl=0, [LIBS=$tk_oldLibs]) fi AC_CHECK_FUNC(gethostbyname, , [AC_CHECK_LIB(nsl, gethostbyname, [LIBS="$LIBS -lnsl"])]) AC_CHECK_FUNC(mp_log_u32, , [AC_CHECK_LIB(tommath, mp_log_u32, [LIBS="$LIBS -ltommath"])]) AC_CHECK_FUNC(deflateSetHeader, , [AC_CHECK_LIB(z, deflateSetHeader, [LIBS="$LIBS -lz"])]) ]) #-------------------------------------------------------------------- # TEA_TCL_EARLY_FLAGS # # Check for what flags are needed to be passed so the correct OS # features are available. # # Arguments: # None # # Results: # # Might define the following vars: # _ISOC99_SOURCE # _FILE_OFFSET_BITS # #-------------------------------------------------------------------- AC_DEFUN([TEA_TCL_EARLY_FLAG],[ AC_CACHE_VAL([tcl_cv_flag_]translit($1,[A-Z],[a-z]), AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[$2]], [[$3]])], [tcl_cv_flag_]translit($1,[A-Z],[a-z])=no,[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[[#define ]$1[ ]m4_default([$4],[1])[ ]$2]], [[$3]])], [tcl_cv_flag_]translit($1,[A-Z],[a-z])=yes, [tcl_cv_flag_]translit($1,[A-Z],[a-z])=no)])) if test ["x${tcl_cv_flag_]translit($1,[A-Z],[a-z])[}" = "xyes"] ; then AC_DEFINE($1, m4_default([$4],[1]), [Add the ]$1[ flag when building]) tcl_flags="$tcl_flags $1" fi ]) AC_DEFUN([TEA_TCL_EARLY_FLAGS],[ AC_MSG_CHECKING([for required early compiler flags]) tcl_flags="" TEA_TCL_EARLY_FLAG(_ISOC99_SOURCE,[#include ], [char *p = (char *)strtoll; char *q = (char *)strtoull;]) if test "${TCL_MAJOR_VERSION}" -ne 8 ; then TEA_TCL_EARLY_FLAG(_FILE_OFFSET_BITS,[#include ], [switch (0) { case 0: case (sizeof(off_t)==sizeof(long long)): ; }],64) fi if test "x${tcl_flags}" = "x" ; then AC_MSG_RESULT([none]) else AC_MSG_RESULT([${tcl_flags}]) fi ]) #-------------------------------------------------------------------- # TEA_TCL_64BIT_FLAGS # # Check for what is defined in the way of 64-bit features. # # Arguments: # None # # Results: # # Might define the following vars: # TCL_WIDE_INT_IS_LONG # TCL_WIDE_INT_TYPE # HAVE_STRUCT_DIRENT64, HAVE_DIR64 # HAVE_STRUCT_STAT64 # HAVE_TYPE_OFF64_T # _TIME_BITS # #-------------------------------------------------------------------- AC_DEFUN([TEA_TCL_64BIT_FLAGS], [ AC_MSG_CHECKING([for 64-bit integer type]) AC_CACHE_VAL(tcl_cv_type_64bit,[ tcl_cv_type_64bit=none # See if the compiler knows natively about __int64 AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[__int64 value = (__int64) 0;]])], [tcl_type_64bit=__int64],[tcl_type_64bit="long long"]) # See if we could use long anyway Note that we substitute in the # type that is our current guess for a 64-bit type inside this check # program, so it should be modified only carefully... AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[switch (0) { case 1: case (sizeof(${tcl_type_64bit})==sizeof(long)): ; }]])],[tcl_cv_type_64bit=${tcl_type_64bit}],[])]) if test "${tcl_cv_type_64bit}" = none ; then AC_DEFINE(TCL_WIDE_INT_IS_LONG, 1, [Do 'long' and 'long long' have the same size (64-bit)?]) AC_MSG_RESULT([yes]) elif test "${tcl_cv_type_64bit}" = "__int64" \ -a "${TEA_PLATFORM}" = "windows" ; then # TEA specific: We actually want to use the default tcl.h checks in # this case to handle both TCL_WIDE_INT_TYPE and TCL_LL_MODIFIER* AC_MSG_RESULT([using Tcl header defaults]) else AC_DEFINE_UNQUOTED(TCL_WIDE_INT_TYPE,${tcl_cv_type_64bit}, [What type should be used to define wide integers?]) AC_MSG_RESULT([${tcl_cv_type_64bit}]) # Now check for auxiliary declarations if test "${TCL_MAJOR_VERSION}" -ne 8 ; then AC_CACHE_CHECK([for 64-bit time_t], tcl_cv_time_t_64,[ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[switch (0) {case 0: case (sizeof(time_t)==sizeof(long long)): ;}]])], [tcl_cv_time_t_64=yes],[tcl_cv_time_t_64=no])]) if test "x${tcl_cv_time_t_64}" = "xno" ; then # Note that _TIME_BITS=64 requires _FILE_OFFSET_BITS=64 # which SC_TCL_EARLY_FLAGS has defined if necessary. AC_CACHE_CHECK([if _TIME_BITS=64 enables 64-bit time_t], tcl_cv__time_bits,[ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#define _TIME_BITS 64 #include ]], [[switch (0) {case 0: case (sizeof(time_t)==sizeof(long long)): ;}]])], [tcl_cv__time_bits=yes],[tcl_cv__time_bits=no])]) if test "x${tcl_cv__time_bits}" = "xyes" ; then AC_DEFINE(_TIME_BITS, 64, [_TIME_BITS=64 enables 64-bit time_t.]) fi fi fi AC_CACHE_CHECK([for struct dirent64], tcl_cv_struct_dirent64,[ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include #include ]], [[struct dirent64 p;]])], [tcl_cv_struct_dirent64=yes],[tcl_cv_struct_dirent64=no])]) if test "x${tcl_cv_struct_dirent64}" = "xyes" ; then AC_DEFINE(HAVE_STRUCT_DIRENT64, 1, [Is 'struct dirent64' in ?]) fi AC_CACHE_CHECK([for DIR64], tcl_cv_DIR64,[ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include #include ]], [[struct dirent64 *p; DIR64 d = opendir64("."); p = readdir64(d); rewinddir64(d); closedir64(d);]])], [tcl_cv_DIR64=yes], [tcl_cv_DIR64=no])]) if test "x${tcl_cv_DIR64}" = "xyes" ; then AC_DEFINE(HAVE_DIR64, 1, [Is 'DIR64' in ?]) fi AC_CACHE_CHECK([for struct stat64], tcl_cv_struct_stat64,[ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[struct stat64 p; ]])], [tcl_cv_struct_stat64=yes], [tcl_cv_struct_stat64=no])]) if test "x${tcl_cv_struct_stat64}" = "xyes" ; then AC_DEFINE(HAVE_STRUCT_STAT64, 1, [Is 'struct stat64' in ?]) fi AC_CHECK_FUNCS(open64 lseek64) AC_MSG_CHECKING([for off64_t]) AC_CACHE_VAL(tcl_cv_type_off64_t,[ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[off64_t offset; ]])], [tcl_cv_type_off64_t=yes], [tcl_cv_type_off64_t=no])]) dnl Define HAVE_TYPE_OFF64_T only when the off64_t type and the dnl functions lseek64 and open64 are defined. if test "x${tcl_cv_type_off64_t}" = "xyes" && \ test "x${ac_cv_func_lseek64}" = "xyes" && \ test "x${ac_cv_func_open64}" = "xyes" ; then AC_DEFINE(HAVE_TYPE_OFF64_T, 1, [Is off64_t in ?]) AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi fi ]) ## ## Here ends the standard Tcl configuration bits and starts the ## TEA specific functions ## #------------------------------------------------------------------------ # TEA_INIT -- # # Init various Tcl Extension Architecture (TEA) variables. # This should be the first called TEA_* macro. # # Arguments: # none # # Results: # # Defines and substs the following vars: # CYGPATH # EXEEXT # Defines only: # TEA_VERSION # TEA_INITED # TEA_PLATFORM (windows or unix) # # "cygpath" is used on windows to generate native path names for include # files. These variables should only be used with the compiler and linker # since they generate native path names. # # EXEEXT # Select the executable extension based on the host type. This # is a lightweight replacement for AC_EXEEXT that doesn't require # a compiler. #------------------------------------------------------------------------ AC_DEFUN([TEA_INIT], [ TEA_VERSION="3.13" AC_MSG_CHECKING([TEA configuration]) if test x"${PACKAGE_NAME}" = x ; then AC_MSG_ERROR([ The PACKAGE_NAME variable must be defined by your TEA configure.ac]) fi AC_MSG_RESULT([ok (TEA ${TEA_VERSION})]) # If the user did not set CFLAGS, set it now to keep macros # like AC_PROG_CC and AC_TRY_COMPILE from adding "-g -O2". if test "${CFLAGS+set}" != "set" ; then CFLAGS="" fi case "`uname -s`" in *win32*|*WIN32*|*MINGW32_*|*MINGW64_*|*MSYS_*) AC_CHECK_PROG(CYGPATH, cygpath, cygpath -m, echo) EXEEXT=".exe" TEA_PLATFORM="windows" ;; *CYGWIN_*) EXEEXT=".exe" # CYGPATH and TEA_PLATFORM are determined later in LOAD_TCLCONFIG ;; *) CYGPATH=echo # Maybe we are cross-compiling.... case ${host_alias} in *mingw32*) EXEEXT=".exe" TEA_PLATFORM="windows" ;; *) EXEEXT="" TEA_PLATFORM="unix" ;; esac ;; esac # Check if exec_prefix is set. If not use fall back to prefix. # Note when adjusted, so that TEA_PREFIX can correct for this. # This is needed for recursive configures, since autoconf propagates # $prefix, but not $exec_prefix (doh!). if test x$exec_prefix = xNONE ; then exec_prefix_default=yes exec_prefix=$prefix fi AC_MSG_NOTICE([configuring ${PACKAGE_NAME} ${PACKAGE_VERSION}]) AC_SUBST(EXEEXT) AC_SUBST(CYGPATH) # This package name must be replaced statically for AC_SUBST to work AC_SUBST(PKG_LIB_FILE) AC_SUBST(PKG_LIB_FILE8) AC_SUBST(PKG_LIB_FILE9) # We AC_SUBST these here to ensure they are subst'ed, # in case the user doesn't call TEA_ADD_... AC_SUBST(PKG_STUB_SOURCES) AC_SUBST(PKG_STUB_OBJECTS) AC_SUBST(PKG_TCL_SOURCES) AC_SUBST(PKG_HEADERS) AC_SUBST(PKG_INCLUDES) AC_SUBST(PKG_LIBS) AC_SUBST(PKG_CFLAGS) # Configure the installer. TEA_INSTALLER ]) #------------------------------------------------------------------------ # TEA_ADD_SOURCES -- # # Specify one or more source files. Users should check for # the right platform before adding to their list. # It is not important to specify the directory, as long as it is # in the generic, win or unix subdirectory of $(srcdir). # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_SOURCES # PKG_OBJECTS #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_SOURCES], [ vars="$@" for i in $vars; do case $i in [\$]*) # allow $-var names PKG_SOURCES="$PKG_SOURCES $i" PKG_OBJECTS="$PKG_OBJECTS $i" ;; *) # check for existence - allows for generic/win/unix VPATH # To add more dirs here (like 'src'), you have to update VPATH # in Makefile.in as well if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/generic/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ -a ! -f "${srcdir}/macosx/$i" \ ; then AC_MSG_ERROR([could not find source file '$i']) fi PKG_SOURCES="$PKG_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[[^.]]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[[^.]]*$//'`.\${OBJEXT}" fi PKG_OBJECTS="$PKG_OBJECTS $j" ;; esac done AC_SUBST(PKG_SOURCES) AC_SUBST(PKG_OBJECTS) ]) #------------------------------------------------------------------------ # TEA_ADD_STUB_SOURCES -- # # Specify one or more source files. Users should check for # the right platform before adding to their list. # It is not important to specify the directory, as long as it is # in the generic, win or unix subdirectory of $(srcdir). # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_STUB_SOURCES # PKG_STUB_OBJECTS #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_STUB_SOURCES], [ vars="$@" for i in $vars; do # check for existence - allows for generic/win/unix VPATH if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/generic/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ -a ! -f "${srcdir}/macosx/$i" \ ; then AC_MSG_ERROR([could not find stub source file '$i']) fi PKG_STUB_SOURCES="$PKG_STUB_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[[^.]]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[[^.]]*$//'`.\${OBJEXT}" fi PKG_STUB_OBJECTS="$PKG_STUB_OBJECTS $j" done AC_SUBST(PKG_STUB_SOURCES) AC_SUBST(PKG_STUB_OBJECTS) ]) #------------------------------------------------------------------------ # TEA_ADD_TCL_SOURCES -- # # Specify one or more Tcl source files. These should be platform # independent runtime files. # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_TCL_SOURCES #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_TCL_SOURCES], [ vars="$@" for i in $vars; do # check for existence, be strict because it is installed if test ! -f "${srcdir}/$i" ; then AC_MSG_ERROR([could not find tcl source file '${srcdir}/$i']) fi PKG_TCL_SOURCES="$PKG_TCL_SOURCES $i" done AC_SUBST(PKG_TCL_SOURCES) ]) #------------------------------------------------------------------------ # TEA_ADD_HEADERS -- # # Specify one or more source headers. Users should check for # the right platform before adding to their list. # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_HEADERS #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_HEADERS], [ vars="$@" for i in $vars; do # check for existence, be strict because it is installed if test ! -f "${srcdir}/$i" ; then AC_MSG_ERROR([could not find header file '${srcdir}/$i']) fi PKG_HEADERS="$PKG_HEADERS $i" done AC_SUBST(PKG_HEADERS) ]) #------------------------------------------------------------------------ # TEA_ADD_INCLUDES -- # # Specify one or more include dirs. Users should check for # the right platform before adding to their list. # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_INCLUDES #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_INCLUDES], [ vars="$@" for i in $vars; do PKG_INCLUDES="$PKG_INCLUDES $i" done AC_SUBST(PKG_INCLUDES) ]) #------------------------------------------------------------------------ # TEA_ADD_LIBS -- # # Specify one or more libraries. Users should check for # the right platform before adding to their list. For Windows, # libraries provided in "foo.lib" format will be converted to # "-lfoo" when using GCC (mingw). # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_LIBS #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_LIBS], [ vars="$@" for i in $vars; do if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then # Convert foo.lib to -lfoo for GCC. No-op if not *.lib i=`echo "$i" | sed -e 's/^\([[^-]].*\)\.[[lL]][[iI]][[bB]][$]/-l\1/'` fi PKG_LIBS="$PKG_LIBS $i" done AC_SUBST(PKG_LIBS) ]) #------------------------------------------------------------------------ # TEA_ADD_CFLAGS -- # # Specify one or more CFLAGS. Users should check for # the right platform before adding to their list. # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_CFLAGS #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_CFLAGS], [ PKG_CFLAGS="$PKG_CFLAGS $@" AC_SUBST(PKG_CFLAGS) ]) #------------------------------------------------------------------------ # TEA_ADD_CLEANFILES -- # # Specify one or more CLEANFILES. # # Arguments: # one or more file names to clean target # # Results: # # Appends to CLEANFILES, already defined for subst in LOAD_TCLCONFIG #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_CLEANFILES], [ CLEANFILES="$CLEANFILES $@" ]) #------------------------------------------------------------------------ # TEA_PREFIX -- # # Handle the --prefix=... option by defaulting to what Tcl gave # # Arguments: # none # # Results: # # If --prefix or --exec-prefix was not specified, $prefix and # $exec_prefix will be set to the values given to Tcl when it was # configured. #------------------------------------------------------------------------ AC_DEFUN([TEA_PREFIX], [ if test "${prefix}" = "NONE"; then prefix_default=yes if test x"${TCL_PREFIX}" != x; then AC_MSG_NOTICE([--prefix defaulting to TCL_PREFIX ${TCL_PREFIX}]) prefix=${TCL_PREFIX} else AC_MSG_NOTICE([--prefix defaulting to /usr/local]) prefix=/usr/local fi fi if test "${exec_prefix}" = "NONE" -a x"${prefix_default}" = x"yes" \ -o x"${exec_prefix_default}" = x"yes" ; then if test x"${TCL_EXEC_PREFIX}" != x; then AC_MSG_NOTICE([--exec-prefix defaulting to TCL_EXEC_PREFIX ${TCL_EXEC_PREFIX}]) exec_prefix=${TCL_EXEC_PREFIX} else AC_MSG_NOTICE([--exec-prefix defaulting to ${prefix}]) exec_prefix=$prefix fi fi ]) #------------------------------------------------------------------------ # TEA_SETUP_COMPILER_CC -- # # Do compiler checks the way we want. This is just a replacement # for AC_PROG_CC in TEA configure.ac files to make them cleaner. # # Arguments: # none # # Results: # # Sets up CC var and other standard bits we need to make executables. #------------------------------------------------------------------------ AC_DEFUN([TEA_SETUP_COMPILER_CC], [ # Don't put any macros that use the compiler (e.g. AC_TRY_COMPILE) # in this macro, they need to go into TEA_SETUP_COMPILER instead. AC_PROG_CC AC_PROG_CPP #-------------------------------------------------------------------- # Checks to see if the make program sets the $MAKE variable. #-------------------------------------------------------------------- AC_PROG_MAKE_SET #-------------------------------------------------------------------- # Find ranlib #-------------------------------------------------------------------- AC_CHECK_TOOL(RANLIB, ranlib) #-------------------------------------------------------------------- # Determines the correct binary file extension (.o, .obj, .exe etc.) #-------------------------------------------------------------------- AC_OBJEXT AC_EXEEXT ]) #------------------------------------------------------------------------ # TEA_SETUP_COMPILER -- # # Do compiler checks that use the compiler. This must go after # TEA_SETUP_COMPILER_CC, which does the actual compiler check. # # Arguments: # none # # Results: # # Sets up CC var and other standard bits we need to make executables. #------------------------------------------------------------------------ AC_DEFUN([TEA_SETUP_COMPILER], [ # Any macros that use the compiler (e.g. AC_TRY_COMPILE) have to go here. AC_REQUIRE([TEA_SETUP_COMPILER_CC]) #------------------------------------------------------------------------ # If we're using GCC, see if the compiler understands -pipe. If so, use it. # It makes compiling go faster. (This is only a performance feature.) #------------------------------------------------------------------------ if test -z "$no_pipe" -a -n "$GCC"; then AC_CACHE_CHECK([if the compiler understands -pipe], tcl_cv_cc_pipe, [ hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -pipe" AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])],[tcl_cv_cc_pipe=yes],[tcl_cv_cc_pipe=no]) CFLAGS=$hold_cflags]) if test $tcl_cv_cc_pipe = yes; then CFLAGS="$CFLAGS -pipe" fi fi if test "${TCL_MAJOR_VERSION}" -lt 9 -a "${TCL_MINOR_VERSION}" -lt 7; then AC_DEFINE(Tcl_Size, int, [Is 'Tcl_Size' in ?]) fi #-------------------------------------------------------------------- # Common compiler flag setup #-------------------------------------------------------------------- AC_C_BIGENDIAN(,,,[#]) ]) #------------------------------------------------------------------------ # TEA_MAKE_LIB -- # # Generate a line that can be used to build a shared/unshared library # in a platform independent manner. # # Arguments: # none # # Requires: # # Results: # # Defines the following vars: # CFLAGS - Done late here to note disturb other AC macros # MAKE_LIB - Command to execute to build the Tcl library; # differs depending on whether or not Tcl is being # compiled as a shared library. # MAKE_SHARED_LIB Makefile rule for building a shared library # MAKE_STATIC_LIB Makefile rule for building a static library # MAKE_STUB_LIB Makefile rule for building a stub library # VC_MANIFEST_EMBED_DLL Makefile rule for embedded VC manifest in DLL # VC_MANIFEST_EMBED_EXE Makefile rule for embedded VC manifest in EXE #------------------------------------------------------------------------ AC_DEFUN([TEA_MAKE_LIB], [ if test "${TEA_PLATFORM}" = "windows" -a "$GCC" != "yes"; then MAKE_STATIC_LIB="\${STLIB_LD} -out:\[$]@ \$(PKG_OBJECTS)" MAKE_SHARED_LIB="\${SHLIB_LD} \${LDFLAGS} \${LDFLAGS_DEFAULT} -out:\[$]@ \$(PKG_OBJECTS) \${SHLIB_LD_LIBS}" AC_EGREP_CPP([manifest needed], [ #if defined(_MSC_VER) && _MSC_VER >= 1400 print("manifest needed") #endif ], [ # Could do a CHECK_PROG for mt, but should always be with MSVC8+ VC_MANIFEST_EMBED_DLL="if test -f \[$]@.manifest ; then mt.exe -nologo -manifest \[$]@.manifest -outputresource:\[$]@\;2 ; fi" VC_MANIFEST_EMBED_EXE="if test -f \[$]@.manifest ; then mt.exe -nologo -manifest \[$]@.manifest -outputresource:\[$]@\;1 ; fi" MAKE_SHARED_LIB="${MAKE_SHARED_LIB} ; ${VC_MANIFEST_EMBED_DLL}" TEA_ADD_CLEANFILES([*.manifest]) ]) MAKE_STUB_LIB="\${STLIB_LD} -nodefaultlib -out:\[$]@ \$(PKG_STUB_OBJECTS)" else MAKE_STATIC_LIB="\${STLIB_LD} \[$]@ \$(PKG_OBJECTS)" MAKE_SHARED_LIB="\${SHLIB_LD} \${LDFLAGS} \${LDFLAGS_DEFAULT} -o \[$]@ \$(PKG_OBJECTS) \${SHLIB_LD_LIBS}" MAKE_STUB_LIB="\${STLIB_LD} \[$]@ \$(PKG_STUB_OBJECTS)" fi if test "${SHARED_BUILD}" = "1" ; then MAKE_LIB="${MAKE_SHARED_LIB} " else MAKE_LIB="${MAKE_STATIC_LIB} " fi #-------------------------------------------------------------------- # Shared libraries and static libraries have different names. # Use the double eval to make sure any variables in the suffix is # substituted. (@@@ Might not be necessary anymore) #-------------------------------------------------------------------- PACKAGE_LIB_PREFIX8="${PACKAGE_LIB_PREFIX}" PACKAGE_LIB_PREFIX9="${PACKAGE_LIB_PREFIX}tcl9" if test "${TCL_MAJOR_VERSION}" -gt 8 -a x"${with_tcl8}" = x; then PACKAGE_LIB_PREFIX="${PACKAGE_LIB_PREFIX9}" else PACKAGE_LIB_PREFIX="${PACKAGE_LIB_PREFIX8}" AC_DEFINE(TCL_MAJOR_VERSION, 8, [Compile for Tcl8?]) fi if test "${TEA_PLATFORM}" = "windows" ; then if test "${SHARED_BUILD}" = "1" ; then # We force the unresolved linking of symbols that are really in # the private libraries of Tcl and Tk. if test x"${TK_BIN_DIR}" != x ; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} \"`${CYGPATH} ${TK_BIN_DIR}/${TK_STUB_LIB_FILE}`\"" fi SHLIB_LD_LIBS="${SHLIB_LD_LIBS} \"`${CYGPATH} ${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}`\"" if test "$GCC" = "yes"; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} -static-libgcc" fi eval eval "PKG_LIB_FILE8=${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE9=${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE=${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" else if test "$GCC" = "yes"; then PACKAGE_LIB_PREFIX=lib${PACKAGE_LIB_PREFIX} fi eval eval "PKG_LIB_FILE8=${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE9=${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE=${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" fi # Some packages build their own stubs libraries if test "${TCL_MAJOR_VERSION}" -gt 8 -a x"${with_tcl8}" = x; then eval eval "PKG_STUB_LIB_FILE=${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}stub.a" else eval eval "PKG_STUB_LIB_FILE=${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}" fi if test "$GCC" = "yes"; then PKG_STUB_LIB_FILE=lib${PKG_STUB_LIB_FILE} fi # These aren't needed on Windows (either MSVC or gcc) RANLIB=: RANLIB_STUB=: else RANLIB_STUB="${RANLIB}" if test "${SHARED_BUILD}" = "1" ; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TCL_STUB_LIB_SPEC}" if test x"${TK_BIN_DIR}" != x ; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TK_STUB_LIB_SPEC}" fi eval eval "PKG_LIB_FILE8=lib${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE9=lib${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" RANLIB=: else eval eval "PKG_LIB_FILE8=lib${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE9=lib${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" fi # Some packages build their own stubs libraries if test "${TCL_MAJOR_VERSION}" -gt 8 -a x"${with_tcl8}" = x; then eval eval "PKG_STUB_LIB_FILE=lib${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}stub.a" else eval eval "PKG_STUB_LIB_FILE=lib${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}" fi fi # These are escaped so that only CFLAGS is picked up at configure time. # The other values will be substituted at make time. CFLAGS="${CFLAGS} \${CFLAGS_DEFAULT} \${CFLAGS_WARNING}" if test "${SHARED_BUILD}" = "1" ; then CFLAGS="${CFLAGS} \${SHLIB_CFLAGS}" fi AC_SUBST(MAKE_LIB) AC_SUBST(MAKE_SHARED_LIB) AC_SUBST(MAKE_STATIC_LIB) AC_SUBST(MAKE_STUB_LIB) # Substitute STUB_LIB_FILE in case package creates a stub library too. AC_SUBST(PKG_STUB_LIB_FILE) AC_SUBST(RANLIB_STUB) AC_SUBST(VC_MANIFEST_EMBED_DLL) AC_SUBST(VC_MANIFEST_EMBED_EXE) ]) #------------------------------------------------------------------------ # TEA_LIB_SPEC -- # # Compute the name of an existing object library located in libdir # from the given base name and produce the appropriate linker flags. # # Arguments: # basename The base name of the library without version # numbers, extensions, or "lib" prefixes. # extra_dir Extra directory in which to search for the # library. This location is used first, then # $prefix/$exec-prefix, then some defaults. # # Requires: # TEA_INIT and TEA_PREFIX must be called first. # # Results: # # Defines the following vars: # ${basename}_LIB_NAME The computed library name. # ${basename}_LIB_SPEC The computed linker flags. #------------------------------------------------------------------------ AC_DEFUN([TEA_LIB_SPEC], [ AC_MSG_CHECKING([for $1 library]) # Look in exec-prefix for the library (defined by TEA_PREFIX). tea_lib_name_dir="${exec_prefix}/lib" # Or in a user-specified location. if test x"$2" != x ; then tea_extra_lib_dir=$2 else tea_extra_lib_dir=NONE fi for i in \ `ls -dr ${tea_extra_lib_dir}/$1[[0-9]]*.lib 2>/dev/null ` \ `ls -dr ${tea_extra_lib_dir}/lib$1[[0-9]]* 2>/dev/null ` \ `ls -dr ${tea_lib_name_dir}/$1[[0-9]]*.lib 2>/dev/null ` \ `ls -dr ${tea_lib_name_dir}/lib$1[[0-9]]* 2>/dev/null ` \ `ls -dr /usr/lib/$1[[0-9]]*.lib 2>/dev/null ` \ `ls -dr /usr/lib/lib$1[[0-9]]* 2>/dev/null ` \ `ls -dr /usr/lib64/$1[[0-9]]*.lib 2>/dev/null ` \ `ls -dr /usr/lib64/lib$1[[0-9]]* 2>/dev/null ` \ `ls -dr /usr/local/lib/$1[[0-9]]*.lib 2>/dev/null ` \ `ls -dr /usr/local/lib/lib$1[[0-9]]* 2>/dev/null ` ; do if test -f "$i" ; then tea_lib_name_dir=`dirname $i` $1_LIB_NAME=`basename $i` $1_LIB_PATH_NAME=$i break fi done if test "${TEA_PLATFORM}" = "windows"; then $1_LIB_SPEC=\"`${CYGPATH} ${$1_LIB_PATH_NAME} 2>/dev/null`\" else # Strip off the leading "lib" and trailing ".a" or ".so" tea_lib_name_lib=`echo ${$1_LIB_NAME}|sed -e 's/^lib//' -e 's/\.[[^.]]*$//' -e 's/\.so.*//'` $1_LIB_SPEC="-L${tea_lib_name_dir} -l${tea_lib_name_lib}" fi if test "x${$1_LIB_NAME}" = x ; then AC_MSG_ERROR([not found]) else AC_MSG_RESULT([${$1_LIB_SPEC}]) fi ]) #------------------------------------------------------------------------ # TEA_PRIVATE_TCL_HEADERS -- # # Locate the private Tcl include files # # Arguments: # # Requires: # TCL_SRC_DIR Assumes that TEA_LOAD_TCLCONFIG has # already been called. # # Results: # # Substitutes the following vars: # TCL_TOP_DIR_NATIVE # TCL_INCLUDES #------------------------------------------------------------------------ AC_DEFUN([TEA_PRIVATE_TCL_HEADERS], [ # Allow for --with-tclinclude to take effect and define ${ac_cv_c_tclh} AC_REQUIRE([TEA_PUBLIC_TCL_HEADERS]) AC_MSG_CHECKING([for Tcl private include files]) TCL_SRC_DIR_NATIVE=`${CYGPATH} ${TCL_SRC_DIR}` TCL_TOP_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}\" # Check to see if tclPort.h isn't already with the public headers # Don't look for tclInt.h because that resides with tcl.h in the core # sources, but the Port headers are in a different directory if test "${TEA_PLATFORM}" = "windows" -a \ -f "${ac_cv_c_tclh}/tclWinPort.h"; then result="private headers found with public headers" elif test "${TEA_PLATFORM}" = "unix" -a \ -f "${ac_cv_c_tclh}/tclUnixPort.h"; then result="private headers found with public headers" else TCL_GENERIC_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/generic\" if test "${TEA_PLATFORM}" = "windows"; then TCL_PLATFORM_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/win\" else TCL_PLATFORM_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/unix\" fi # Overwrite the previous TCL_INCLUDES as this should capture both # public and private headers in the same set. # We want to ensure these are substituted so as not to require # any *_NATIVE vars be defined in the Makefile TCL_INCLUDES="-I${TCL_GENERIC_DIR_NATIVE} -I${TCL_PLATFORM_DIR_NATIVE}" if test "`uname -s`" = "Darwin"; then # If Tcl was built as a framework, attempt to use # the framework's Headers and PrivateHeaders directories case ${TCL_DEFS} in *TCL_FRAMEWORK*) if test -d "${TCL_BIN_DIR}/Headers" -a \ -d "${TCL_BIN_DIR}/PrivateHeaders"; then TCL_INCLUDES="-I\"${TCL_BIN_DIR}/Headers\" -I\"${TCL_BIN_DIR}/PrivateHeaders\" ${TCL_INCLUDES}" else TCL_INCLUDES="${TCL_INCLUDES} ${TCL_INCLUDE_SPEC} `echo "${TCL_INCLUDE_SPEC}" | sed -e 's/Headers/PrivateHeaders/'`" fi ;; esac result="Using ${TCL_INCLUDES}" else if test ! -f "${TCL_SRC_DIR}/generic/tclInt.h" ; then AC_MSG_ERROR([Cannot find private header tclInt.h in ${TCL_SRC_DIR}]) fi result="Using srcdir found in tclConfig.sh: ${TCL_SRC_DIR}" fi fi AC_SUBST(TCL_TOP_DIR_NATIVE) AC_SUBST(TCL_INCLUDES) AC_MSG_RESULT([${result}]) ]) #------------------------------------------------------------------------ # TEA_PUBLIC_TCL_HEADERS -- # # Locate the installed public Tcl header files # # Arguments: # None. # # Requires: # CYGPATH must be set # # Results: # # Adds a --with-tclinclude switch to configure. # Result is cached. # # Substitutes the following vars: # TCL_INCLUDES #------------------------------------------------------------------------ AC_DEFUN([TEA_PUBLIC_TCL_HEADERS], [ AC_MSG_CHECKING([for Tcl public headers]) AC_ARG_WITH(tclinclude, [ --with-tclinclude directory containing the public Tcl header files], with_tclinclude=${withval}) AC_CACHE_VAL(ac_cv_c_tclh, [ # Use the value from --with-tclinclude, if it was given if test x"${with_tclinclude}" != x ; then if test -f "${with_tclinclude}/tcl.h" ; then ac_cv_c_tclh=${with_tclinclude} else AC_MSG_ERROR([${with_tclinclude} directory does not contain tcl.h]) fi else list="" if test "`uname -s`" = "Darwin"; then # If Tcl was built as a framework, attempt to use # the framework's Headers directory case ${TCL_DEFS} in *TCL_FRAMEWORK*) list="`ls -d ${TCL_BIN_DIR}/Headers 2>/dev/null`" ;; esac fi # Look in the source dir only if Tcl is not installed, # and in that situation, look there before installed locations. if test -f "${TCL_BIN_DIR}/Makefile" ; then list="$list `ls -d ${TCL_SRC_DIR}/generic 2>/dev/null`" fi # Check order: pkg --prefix location, Tcl's --prefix location, # relative to directory of tclConfig.sh. eval "temp_includedir=${includedir}" list="$list \ `ls -d ${temp_includedir} 2>/dev/null` \ `ls -d ${TCL_PREFIX}/include 2>/dev/null` \ `ls -d ${TCL_BIN_DIR}/../include 2>/dev/null`" if test "${TEA_PLATFORM}" != "windows" -o "$GCC" = "yes"; then list="$list /usr/local/include /usr/include" if test x"${TCL_INCLUDE_SPEC}" != x ; then d=`echo "${TCL_INCLUDE_SPEC}" | sed -e 's/^-I//'` list="$list `ls -d ${d} 2>/dev/null`" fi fi for i in $list ; do if test -f "$i/tcl.h" ; then ac_cv_c_tclh=$i break fi done fi ]) # Print a message based on how we determined the include path if test x"${ac_cv_c_tclh}" = x ; then AC_MSG_ERROR([tcl.h not found. Please specify its location with --with-tclinclude]) else AC_MSG_RESULT([${ac_cv_c_tclh}]) fi # Convert to a native path and substitute into the output files. INCLUDE_DIR_NATIVE=`${CYGPATH} ${ac_cv_c_tclh}` TCL_INCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" AC_SUBST(TCL_INCLUDES) ]) #------------------------------------------------------------------------ # TEA_PRIVATE_TK_HEADERS -- # # Locate the private Tk include files # # Arguments: # # Requires: # TK_SRC_DIR Assumes that TEA_LOAD_TKCONFIG has # already been called. # # Results: # # Substitutes the following vars: # TK_INCLUDES #------------------------------------------------------------------------ AC_DEFUN([TEA_PRIVATE_TK_HEADERS], [ # Allow for --with-tkinclude to take effect and define ${ac_cv_c_tkh} AC_REQUIRE([TEA_PUBLIC_TK_HEADERS]) AC_MSG_CHECKING([for Tk private include files]) TK_SRC_DIR_NATIVE=`${CYGPATH} ${TK_SRC_DIR}` TK_TOP_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}\" # Check to see if tkPort.h isn't already with the public headers # Don't look for tkInt.h because that resides with tk.h in the core # sources, but the Port headers are in a different directory if test "${TEA_PLATFORM}" = "windows" -a \ -f "${ac_cv_c_tkh}/tkWinPort.h"; then result="private headers found with public headers" elif test "${TEA_PLATFORM}" = "unix" -a \ -f "${ac_cv_c_tkh}/tkUnixPort.h"; then result="private headers found with public headers" else TK_GENERIC_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/generic\" TK_XLIB_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/xlib\" if test "${TEA_PLATFORM}" = "windows"; then TK_PLATFORM_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/win\" else TK_PLATFORM_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/unix\" fi # Overwrite the previous TK_INCLUDES as this should capture both # public and private headers in the same set. # We want to ensure these are substituted so as not to require # any *_NATIVE vars be defined in the Makefile TK_INCLUDES="-I${TK_GENERIC_DIR_NATIVE} -I${TK_PLATFORM_DIR_NATIVE}" # Detect and add ttk subdir if test -d "${TK_SRC_DIR}/generic/ttk"; then TK_INCLUDES="${TK_INCLUDES} -I\"${TK_SRC_DIR_NATIVE}/generic/ttk\"" fi if test "${TEA_WINDOWINGSYSTEM}" != "x11"; then TK_INCLUDES="${TK_INCLUDES} -I\"${TK_XLIB_DIR_NATIVE}\"" fi if test "${TEA_WINDOWINGSYSTEM}" = "aqua"; then TK_INCLUDES="${TK_INCLUDES} -I\"${TK_SRC_DIR_NATIVE}/macosx\"" fi if test "`uname -s`" = "Darwin"; then # If Tk was built as a framework, attempt to use # the framework's Headers and PrivateHeaders directories case ${TK_DEFS} in *TK_FRAMEWORK*) if test -d "${TK_BIN_DIR}/Headers" -a \ -d "${TK_BIN_DIR}/PrivateHeaders"; then TK_INCLUDES="-I\"${TK_BIN_DIR}/Headers\" -I\"${TK_BIN_DIR}/PrivateHeaders\" ${TK_INCLUDES}" else TK_INCLUDES="${TK_INCLUDES} ${TK_INCLUDE_SPEC} `echo "${TK_INCLUDE_SPEC}" | sed -e 's/Headers/PrivateHeaders/'`" fi ;; esac result="Using ${TK_INCLUDES}" else if test ! -f "${TK_SRC_DIR}/generic/tkInt.h" ; then AC_MSG_ERROR([Cannot find private header tkInt.h in ${TK_SRC_DIR}]) fi result="Using srcdir found in tkConfig.sh: ${TK_SRC_DIR}" fi fi AC_SUBST(TK_TOP_DIR_NATIVE) AC_SUBST(TK_XLIB_DIR_NATIVE) AC_SUBST(TK_INCLUDES) AC_MSG_RESULT([${result}]) ]) #------------------------------------------------------------------------ # TEA_PUBLIC_TK_HEADERS -- # # Locate the installed public Tk header files # # Arguments: # None. # # Requires: # CYGPATH must be set # # Results: # # Adds a --with-tkinclude switch to configure. # Result is cached. # # Substitutes the following vars: # TK_INCLUDES #------------------------------------------------------------------------ AC_DEFUN([TEA_PUBLIC_TK_HEADERS], [ AC_MSG_CHECKING([for Tk public headers]) AC_ARG_WITH(tkinclude, [ --with-tkinclude directory containing the public Tk header files], with_tkinclude=${withval}) AC_CACHE_VAL(ac_cv_c_tkh, [ # Use the value from --with-tkinclude, if it was given if test x"${with_tkinclude}" != x ; then if test -f "${with_tkinclude}/tk.h" ; then ac_cv_c_tkh=${with_tkinclude} else AC_MSG_ERROR([${with_tkinclude} directory does not contain tk.h]) fi else list="" if test "`uname -s`" = "Darwin"; then # If Tk was built as a framework, attempt to use # the framework's Headers directory. case ${TK_DEFS} in *TK_FRAMEWORK*) list="`ls -d ${TK_BIN_DIR}/Headers 2>/dev/null`" ;; esac fi # Look in the source dir only if Tk is not installed, # and in that situation, look there before installed locations. if test -f "${TK_BIN_DIR}/Makefile" ; then list="$list `ls -d ${TK_SRC_DIR}/generic 2>/dev/null`" fi # Check order: pkg --prefix location, Tk's --prefix location, # relative to directory of tkConfig.sh, Tcl's --prefix location, # relative to directory of tclConfig.sh. eval "temp_includedir=${includedir}" list="$list \ `ls -d ${temp_includedir} 2>/dev/null` \ `ls -d ${TK_PREFIX}/include 2>/dev/null` \ `ls -d ${TK_BIN_DIR}/../include 2>/dev/null` \ `ls -d ${TCL_PREFIX}/include 2>/dev/null` \ `ls -d ${TCL_BIN_DIR}/../include 2>/dev/null`" if test "${TEA_PLATFORM}" != "windows" -o "$GCC" = "yes"; then list="$list /usr/local/include /usr/include" if test x"${TK_INCLUDE_SPEC}" != x ; then d=`echo "${TK_INCLUDE_SPEC}" | sed -e 's/^-I//'` list="$list `ls -d ${d} 2>/dev/null`" fi fi for i in $list ; do if test -f "$i/tk.h" ; then ac_cv_c_tkh=$i break fi done fi ]) # Print a message based on how we determined the include path if test x"${ac_cv_c_tkh}" = x ; then AC_MSG_ERROR([tk.h not found. Please specify its location with --with-tkinclude]) else AC_MSG_RESULT([${ac_cv_c_tkh}]) fi # Convert to a native path and substitute into the output files. INCLUDE_DIR_NATIVE=`${CYGPATH} ${ac_cv_c_tkh}` TK_INCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" AC_SUBST(TK_INCLUDES) if test "${TEA_WINDOWINGSYSTEM}" != "x11"; then # On Windows and Aqua, we need the X compat headers AC_MSG_CHECKING([for X11 header files]) if test ! -r "${INCLUDE_DIR_NATIVE}/X11/Xlib.h"; then INCLUDE_DIR_NATIVE="`${CYGPATH} ${TK_SRC_DIR}/xlib`" TK_XINCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" AC_SUBST(TK_XINCLUDES) fi AC_MSG_RESULT([${INCLUDE_DIR_NATIVE}]) fi ]) #------------------------------------------------------------------------ # TEA_PATH_CONFIG -- # # Locate the ${1}Config.sh file and perform a sanity check on # the ${1} compile flags. These are used by packages like # [incr Tk] that load *Config.sh files from more than Tcl and Tk. # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --with-$1=... # # Defines the following vars: # $1_BIN_DIR Full path to the directory containing # the $1Config.sh file #------------------------------------------------------------------------ AC_DEFUN([TEA_PATH_CONFIG], [ # # Ok, lets find the $1 configuration # First, look for one uninstalled. # the alternative search directory is invoked by --with-$1 # if test x"${no_$1}" = x ; then # we reset no_$1 in case something fails here no_$1=true AC_ARG_WITH($1, [ --with-$1 directory containing $1 configuration ($1Config.sh)], with_$1config=${withval}) AC_MSG_CHECKING([for $1 configuration]) AC_CACHE_VAL(ac_cv_c_$1config,[ # First check to see if --with-$1 was specified. if test x"${with_$1config}" != x ; then case ${with_$1config} in */$1Config.sh ) if test -f ${with_$1config}; then AC_MSG_WARN([--with-$1 argument should refer to directory containing $1Config.sh, not to $1Config.sh itself]) with_$1config=`echo ${with_$1config} | sed 's!/$1Config\.sh$!!'` fi;; esac if test -f "${with_$1config}/$1Config.sh" ; then ac_cv_c_$1config=`(cd ${with_$1config}; pwd)` else AC_MSG_ERROR([${with_$1config} directory doesn't contain $1Config.sh]) fi fi # then check for a private $1 installation if test x"${ac_cv_c_$1config}" = x ; then for i in \ ../$1 \ `ls -dr ../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ `ls -dr ../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ `ls -dr ../$1*[[0-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ ../../$1 \ `ls -dr ../../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ `ls -dr ../../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ `ls -dr ../../$1*[[0-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ ../../../$1 \ `ls -dr ../../../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ `ls -dr ../../../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ `ls -dr ../../../$1*[[0-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ ${srcdir}/../$1 \ `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]] 2>/dev/null` \ `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ ; do if test -f "$i/$1Config.sh" ; then ac_cv_c_$1config=`(cd $i; pwd)` break fi if test -f "$i/unix/$1Config.sh" ; then ac_cv_c_$1config=`(cd $i/unix; pwd)` break fi done fi # check in a few common install locations if test x"${ac_cv_c_$1config}" = x ; then for i in `ls -d ${libdir} 2>/dev/null` \ `ls -d ${exec_prefix}/lib 2>/dev/null` \ `ls -d ${prefix}/lib 2>/dev/null` \ `ls -d /usr/local/lib 2>/dev/null` \ `ls -d /usr/contrib/lib 2>/dev/null` \ `ls -d /usr/pkg/lib 2>/dev/null` \ `ls -d /usr/lib 2>/dev/null` \ `ls -d /usr/lib64 2>/dev/null` \ ; do if test -f "$i/$1Config.sh" ; then ac_cv_c_$1config=`(cd $i; pwd)` break fi done fi ]) if test x"${ac_cv_c_$1config}" = x ; then $1_BIN_DIR="# no $1 configs found" AC_MSG_WARN([Cannot find $1 configuration definitions]) exit 0 else no_$1= $1_BIN_DIR=${ac_cv_c_$1config} AC_MSG_RESULT([found $$1_BIN_DIR/$1Config.sh]) fi fi ]) #------------------------------------------------------------------------ # TEA_LOAD_CONFIG -- # # Load the $1Config.sh file # # Arguments: # # Requires the following vars to be set: # $1_BIN_DIR # # Results: # # Substitutes the following vars: # $1_SRC_DIR # $1_LIB_FILE # $1_LIB_SPEC #------------------------------------------------------------------------ AC_DEFUN([TEA_LOAD_CONFIG], [ AC_MSG_CHECKING([for existence of ${$1_BIN_DIR}/$1Config.sh]) if test -f "${$1_BIN_DIR}/$1Config.sh" ; then AC_MSG_RESULT([loading]) . "${$1_BIN_DIR}/$1Config.sh" else AC_MSG_RESULT([file not found]) fi # # If the $1_BIN_DIR is the build directory (not the install directory), # then set the common variable name to the value of the build variables. # For example, the variable $1_LIB_SPEC will be set to the value # of $1_BUILD_LIB_SPEC. An extension should make use of $1_LIB_SPEC # instead of $1_BUILD_LIB_SPEC since it will work with both an # installed and uninstalled version of Tcl. # if test -f "${$1_BIN_DIR}/Makefile" ; then AC_MSG_WARN([Found Makefile - using build library specs for $1]) $1_LIB_SPEC=${$1_BUILD_LIB_SPEC} $1_STUB_LIB_SPEC=${$1_BUILD_STUB_LIB_SPEC} $1_STUB_LIB_PATH=${$1_BUILD_STUB_LIB_PATH} $1_INCLUDE_SPEC=${$1_BUILD_INCLUDE_SPEC} $1_LIBRARY_PATH=${$1_LIBRARY_PATH} fi AC_SUBST($1_VERSION) AC_SUBST($1_BIN_DIR) AC_SUBST($1_SRC_DIR) AC_SUBST($1_LIB_FILE) AC_SUBST($1_LIB_SPEC) AC_SUBST($1_STUB_LIB_FILE) AC_SUBST($1_STUB_LIB_SPEC) AC_SUBST($1_STUB_LIB_PATH) # Allow the caller to prevent this auto-check by specifying any 2nd arg AS_IF([test "x$2" = x], [ # Check both upper and lower-case variants # If a dev wanted non-stubs libs, this function could take an option # to not use _STUB in the paths below AS_IF([test "x${$1_STUB_LIB_SPEC}" = x], [TEA_LOAD_CONFIG_LIB(translit($1,[a-z],[A-Z])_STUB)], [TEA_LOAD_CONFIG_LIB($1_STUB)]) ]) ]) #------------------------------------------------------------------------ # TEA_LOAD_CONFIG_LIB -- # # Helper function to load correct library from another extension's # ${PACKAGE}Config.sh. # # Results: # Adds to LIBS the appropriate extension library #------------------------------------------------------------------------ AC_DEFUN([TEA_LOAD_CONFIG_LIB], [ AC_MSG_CHECKING([For $1 library for LIBS]) # This simplifies the use of stub libraries by automatically adding # the stub lib to your path. Normally this would add to SHLIB_LD_LIBS, # but this is called before CONFIG_CFLAGS. More importantly, this adds # to PKG_LIBS, which becomes LIBS, and that is only used by SHLIB_LD. if test "x${$1_LIB_SPEC}" != "x" ; then if test "${TEA_PLATFORM}" = "windows" -a "$GCC" != "yes" ; then TEA_ADD_LIBS([\"`${CYGPATH} ${$1_LIB_PATH}`\"]) AC_MSG_RESULT([using $1_LIB_PATH ${$1_LIB_PATH}]) else TEA_ADD_LIBS([${$1_LIB_SPEC}]) AC_MSG_RESULT([using $1_LIB_SPEC ${$1_LIB_SPEC}]) fi else AC_MSG_RESULT([file not found]) fi ]) #------------------------------------------------------------------------ # TEA_EXPORT_CONFIG -- # # Define the data to insert into the ${PACKAGE}Config.sh file # # Arguments: # # Requires the following vars to be set: # $1 # # Results: # Substitutes the following vars: #------------------------------------------------------------------------ AC_DEFUN([TEA_EXPORT_CONFIG], [ #-------------------------------------------------------------------- # These are for $1Config.sh #-------------------------------------------------------------------- # pkglibdir must be a fully qualified path and (not ${exec_prefix}/lib) eval pkglibdir="[$]{libdir}/$1${PACKAGE_VERSION}" if test "${TCL_LIB_VERSIONS_OK}" = "ok"; then eval $1_LIB_FLAG="-l$1${PACKAGE_VERSION}" eval $1_STUB_LIB_FLAG="-l$1stub${PACKAGE_VERSION}" else eval $1_LIB_FLAG="-l$1`echo ${PACKAGE_VERSION} | tr -d .`" eval $1_STUB_LIB_FLAG="-l$1stub`echo ${PACKAGE_VERSION} | tr -d .`" fi if test "${TCL_MAJOR_VERSION}" -gt 8 -a x"${with_tcl8}" = x; then eval $1_STUB_LIB_FLAG="-l$1stub" fi $1_BUILD_LIB_SPEC="-L`$CYGPATH $(pwd)` ${$1_LIB_FLAG}" $1_LIB_SPEC="-L`$CYGPATH ${pkglibdir}` ${$1_LIB_FLAG}" $1_BUILD_STUB_LIB_SPEC="-L`$CYGPATH $(pwd)` [$]{$1_STUB_LIB_FLAG}" $1_STUB_LIB_SPEC="-L`$CYGPATH ${pkglibdir}` [$]{$1_STUB_LIB_FLAG}" $1_BUILD_STUB_LIB_PATH="`$CYGPATH $(pwd)`/[$]{PKG_STUB_LIB_FILE}" $1_STUB_LIB_PATH="`$CYGPATH ${pkglibdir}`/[$]{PKG_STUB_LIB_FILE}" AC_SUBST($1_BUILD_LIB_SPEC) AC_SUBST($1_LIB_SPEC) AC_SUBST($1_BUILD_STUB_LIB_SPEC) AC_SUBST($1_STUB_LIB_SPEC) AC_SUBST($1_BUILD_STUB_LIB_PATH) AC_SUBST($1_STUB_LIB_PATH) AC_SUBST(MAJOR_VERSION) AC_SUBST(MINOR_VERSION) AC_SUBST(PATCHLEVEL) ]) #------------------------------------------------------------------------ # TEA_INSTALLER -- # # Configure the installer. # # Arguments: # none # # Results: # Substitutes the following vars: # INSTALL # INSTALL_DATA_DIR # INSTALL_DATA # INSTALL_PROGRAM # INSTALL_SCRIPT # INSTALL_LIBRARY #------------------------------------------------------------------------ AC_DEFUN([TEA_INSTALLER], [ INSTALL='$(SHELL) $(srcdir)/tclconfig/install-sh -c' INSTALL_DATA_DIR='${INSTALL} -d -m 755' INSTALL_DATA='${INSTALL} -m 644' INSTALL_PROGRAM='${INSTALL} -m 755' INSTALL_SCRIPT='${INSTALL} -m 755' TEA_CONFIG_SYSTEM case $system in HP-UX-*) INSTALL_LIBRARY='${INSTALL} -m 755' ;; *) INSTALL_LIBRARY='${INSTALL} -m 644' ;; esac AC_SUBST(INSTALL) AC_SUBST(INSTALL_DATA_DIR) AC_SUBST(INSTALL_DATA) AC_SUBST(INSTALL_PROGRAM) AC_SUBST(INSTALL_SCRIPT) AC_SUBST(INSTALL_LIBRARY) ]) ### # Tip 430 - ZipFS Modifications ### #------------------------------------------------------------------------ # TEA_ZIPFS_SUPPORT # Locate a zip encoder installed on the system path, or none. # # Arguments: # none # # Results: # Substitutes the following vars: # MACHER_PROG # ZIP_PROG # ZIP_PROG_OPTIONS # ZIP_PROG_VFSSEARCH # ZIP_INSTALL_OBJS #------------------------------------------------------------------------ AC_DEFUN([TEA_ZIPFS_SUPPORT], [ MACHER_PROG="" ZIP_PROG="" ZIP_PROG_OPTIONS="" ZIP_PROG_VFSSEARCH="" ZIP_INSTALL_OBJS="" AC_MSG_CHECKING([for macher]) AC_CACHE_VAL(ac_cv_path_macher, [ search_path=`echo ${PATH} | sed -e 's/:/ /g'` for dir in $search_path ; do for j in `ls -r $dir/macher 2> /dev/null` \ `ls -r $dir/macher 2> /dev/null` ; do if test x"$ac_cv_path_macher" = x ; then if test -f "$j" ; then ac_cv_path_macher=$j break fi fi done done ]) if test -f "$ac_cv_path_macher" ; then MACHER_PROG="$ac_cv_path_macher" AC_MSG_RESULT([$MACHER_PROG]) AC_MSG_RESULT([Found macher in environment]) fi AC_MSG_CHECKING([for zip]) AC_CACHE_VAL(ac_cv_path_zip, [ search_path=`echo ${PATH} | sed -e 's/:/ /g'` for dir in $search_path ; do for j in `ls -r $dir/zip 2> /dev/null` \ `ls -r $dir/zip 2> /dev/null` ; do if test x"$ac_cv_path_zip" = x ; then if test -f "$j" ; then ac_cv_path_zip=$j break fi fi done done ]) if test -f "$ac_cv_path_zip" ; then ZIP_PROG="$ac_cv_path_zip" AC_MSG_RESULT([$ZIP_PROG]) ZIP_PROG_OPTIONS="-rq" ZIP_PROG_VFSSEARCH="*" AC_MSG_RESULT([Found INFO Zip in environment]) # Use standard arguments for zip else # It is not an error if an installed version of Zip can't be located. # We can use the locally distributed minizip instead ZIP_PROG="./minizip${EXEEXT_FOR_BUILD}" ZIP_PROG_OPTIONS="-o -r" ZIP_PROG_VFSSEARCH="*" ZIP_INSTALL_OBJS="minizip${EXEEXT_FOR_BUILD}" AC_MSG_RESULT([No zip found on PATH. Building minizip]) fi AC_SUBST(MACHER_PROG) AC_SUBST(ZIP_PROG) AC_SUBST(ZIP_PROG_OPTIONS) AC_SUBST(ZIP_PROG_VFSSEARCH) AC_SUBST(ZIP_INSTALL_OBJS) ]) # Local Variables: # mode: autoconf # End: tdom-0.9.6-src/tclconfig/install-sh0000755000175000017500000003577615025767703015756 0ustar rolfrolf#!/bin/sh # install - install a program, script, or datafile scriptversion=2020-11-14.01; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # 'make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. tab=' ' nl=' ' IFS=" $tab$nl" # Set DOITPROG to "echo" to test this script. doit=${DOITPROG-} doit_exec=${doit:-exec} # Put in absolute file names if you don't have them in your path; # or use environment vars. chgrpprog=${CHGRPPROG-chgrp} chmodprog=${CHMODPROG-chmod} chownprog=${CHOWNPROG-chown} cmpprog=${CMPPROG-cmp} cpprog=${CPPROG-cp} mkdirprog=${MKDIRPROG-mkdir} mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} posix_mkdir= # Desired mode of installed file. mode=0755 # Create dirs (including intermediate dirs) using mode 755. # This is like GNU 'install' as of coreutils 8.32 (2020). mkdir_umask=22 backupsuffix= chgrpcmd= chmodcmd=$chmodprog chowncmd= mvcmd=$mvprog rmcmd="$rmprog -f" stripcmd= src= dst= dir_arg= dst_arg= copy_on_change=false is_target_a_directory=possibly usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: --help display this help and exit. --version display version info and exit. -c (ignored) -C install only if different (preserve data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -p pass -p to $cpprog. -s $stripprog installed files. -S SUFFIX attempt to back up existing files, with suffix SUFFIX. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG By default, rm is invoked with -f; when overridden with RMPROG, it's up to you to specify -f if you want it. If -S is not specified, no backups are attempted. Email bug reports to bug-automake@gnu.org. Automake home page: https://www.gnu.org/software/automake/ " while test $# -ne 0; do case $1 in -c) ;; -C) copy_on_change=true;; -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 case $mode in *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -p) cpprog="$cpprog -p";; -s) stripcmd=$stripprog;; -S) backupsuffix="$2" shift;; -t) is_target_a_directory=always dst_arg=$2 # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac shift;; -T) is_target_a_directory=never;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done # We allow the use of options -d and -T together, by making -d # take the precedence; this is for compatibility with GNU install. if test -n "$dir_arg"; then if test -n "$dst_arg"; then echo "$0: target directory not allowed when installing a directory." >&2 exit 1 fi fi if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call 'install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then if test $# -gt 1 || test "$is_target_a_directory" = always; then if test ! -d "$dst_arg"; then echo "$0: $dst_arg: Is not a directory." >&2 exit 1 fi fi fi if test -z "$dir_arg"; then do_exit='(exit $ret); exit $ret' trap "ret=129; $do_exit" 1 trap "ret=130; $do_exit" 2 trap "ret=141; $do_exit" 13 trap "ret=143; $do_exit" 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names problematic for 'test' and other utilities. case $src in -* | [=\(\)!]) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? # Don't chown directories that already exist. if test $dstdir_status = 0; then chowncmd="" fi else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # If destination is a directory, append the input filename. if test -d "$dst"; then if test "$is_target_a_directory" = never; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dstbase=`basename "$src"` case $dst in */) dst=$dst$dstbase;; *) dst=$dst/$dstbase;; esac dstdir_status=0 else dstdir=`dirname "$dst"` test -d "$dstdir" dstdir_status=$? fi fi case $dstdir in */) dstdirslash=$dstdir;; *) dstdirslash=$dstdir/;; esac obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false # The $RANDOM variable is not portable (e.g., dash). Use it # here however when possible just to lower collision chance. tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap ' ret=$? rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null exit $ret ' 0 # Because "mkdir -p" follows existing symlinks and we likely work # directly in world-writeable /tmp, make sure that the '$tmpdir' # directory is successfully created first before we actually test # 'mkdir -p'. if (umask $mkdir_umask && $mkdirprog $mkdir_mode "$tmpdir" && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. test_tmpdir="$tmpdir/a" ls_ld_tmpdir=`ls -ld "$test_tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$test_tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null fi trap '' 0;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; [-=\(\)!]*) prefix='./';; *) prefix='';; esac oIFS=$IFS IFS=/ set -f set fnord $dstdir shift set +f IFS=$oIFS prefixes= for d do test X"$d" = X && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=${dstdirslash}_inst.$$_ rmtmp=${dstdirslash}_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && { test -z "$stripcmd" || { # Create $dsttmp read-write so that cp doesn't create it read-only, # which would cause strip to fail. if test -z "$doit"; then : >"$dsttmp" # No need to fork-exec 'touch'. else $doit touch "$dsttmp" fi } } && $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # If $backupsuffix is set, and the file being installed # already exists, attempt a backup. Don't worry if it fails, # e.g., if mv doesn't support -f. if test -n "$backupsuffix" && test -f "$dst"; then $doit $mvcmd -f "$dst" "$dst$backupsuffix" 2>/dev/null fi # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { test ! -f "$dst" || $doit $rmcmd "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: tdom-0.9.6-src/tclconfig/README.txt0000644000175000017500000000150415025767703015426 0ustar rolfrolfThese files comprise the basic building blocks for a Tcl Extension Architecture (TEA) extension. For more information on TEA see: http://www.tcl.tk/doc/tea/ This package is part of the Tcl project at SourceForge, but sources and bug/patch database are hosted on fossil here: https://core.tcl-lang.org/tclconfig This package is a freely available open source package. You can do virtually anything you like with it, such as modifying it, redistributing it, and selling it either in whole or in part. CONTENTS ======== The following is a short description of the files you will find in the sample extension. README.txt This file install-sh Program used for copying binaries and script files to their install locations. tcl.m4 Collection of Tcl autoconf macros. Included by a package's aclocal.m4 to define TEA_* macros. tdom-0.9.6-src/aclocal.m40000644000175000017500000000025415025767703013621 0ustar rolfrolf# # Include the TEA standard macro set # builtin(include,tclconfig/tcl.m4) # # Add here whatever m4 macros you want to define for your package # builtin(include,tdom.m4) tdom-0.9.6-src/generic/0000755000175000017500000000000015025767703013374 5ustar rolfrolftdom-0.9.6-src/generic/schema.h0000644000175000017500000002203615025767703015010 0ustar rolfrolf/*---------------------------------------------------------------------------- | Copyright (c) 2018-2022 Rolf Ade (rolf@pointsman.de) |----------------------------------------------------------------------------- | | | The contents of this file are subject to the Mozilla Public License | Version 2.0 (the "License"); you may not use this file except in | compliance with the License. You may obtain a copy of the License at | http://www.mozilla.org/MPL/ | | Software distributed under the License is distributed on an "AS IS" | basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the | License for the specific language governing rights and limitations | under the License. | | Contributor(s): | | | written by Rolf Ade | 2018-2022 | \---------------------------------------------------------------------------*/ #ifndef __SCHEMA_H__ #define __SCHEMA_H__ #include #include #define SPACE(c) IS_XML_WHITESPACE ((c)) #if !defined(checkNrArgs) #define checkNrArgs(l,h,err) if (objc < l || objc > h) { \ SetResult (err); \ return TCL_ERROR; \ } #endif typedef enum { SCHEMA_CTYPE_ANY, SCHEMA_CTYPE_NAME, SCHEMA_CTYPE_CHOICE, SCHEMA_CTYPE_INTERLEAVE, SCHEMA_CTYPE_PATTERN, SCHEMA_CTYPE_TEXT, SCHEMA_CTYPE_VIRTUAL, SCHEMA_CTYPE_KEYSPACE, SCHEMA_CTYPE_KEYSPACE_END, SCHEMA_CTYPE_JSON_STRUCT, } Schema_CP_Type; typedef enum { SCHEMA_CQUANT_ONE, SCHEMA_CQUANT_OPT, SCHEMA_CQUANT_REP, SCHEMA_CQUANT_PLUS, SCHEMA_CQUANT_NM, SCHEMA_CQUANT_ERROR, } SchemaQuant; typedef enum { MATCH_GLOBAL = 1, MATCH_ELEMENT_START, MATCH_ELEMENT_END, MATCH_TEXT, MATCH_ATTRIBUTE_TEXT, MATCH_DOM_KEYCONSTRAINT, MATCH_DOM_XPATH_BOOLEAN } ValidationAction; typedef int (*SchemaConstraintFunc) (Tcl_Interp *interp, void *constraintData, char *text); typedef void (*SchemaConstraintFreeFunc) (void *constraintData); typedef struct { void *constraintData; SchemaConstraintFunc constraint; SchemaConstraintFreeFunc freeData; } SchemaConstraint; typedef struct SchemaAttr { char *namespace; char *name; int required; struct SchemaAttr *next; struct SchemaCP *cp; } SchemaAttr; typedef unsigned int SchemaFlags; /* The SchemaFlags flags */ #define FORWARD_PATTERN_DEF 1 #define PLACEHOLDER_PATTERN_DEF 2 #define AMBIGUOUS_PATTERN 4 #define LOCAL_DEFINED_ELEMENT 8 #define CONSTRAINT_TEXT_CHILD 16 #define MIXED_CONTENT 32 #define ELEMENTTYPE_DEF 64 #define FORWARD_TYPE_DEF 128 #define TYPED_ELEMENT 256 #define HASH_ENTRY_DELETED 512 #define ANY_NOT 1024 typedef struct domKeyConstraint { char *name; ast selector; ast *fields; domLength nrFields; int flags; char *emptyFieldSetValue; size_t efsv_len; struct domKeyConstraint *next; } domKeyConstraint; typedef struct { char *name; int active; Tcl_HashTable ids; int unknownIDrefs; } SchemaKeySpace; typedef struct SchemaCP { Schema_CP_Type type; char *namespace; char *name; struct SchemaCP *typeptr; struct SchemaCP *next; SchemaFlags flags; struct SchemaCP **content; SchemaQuant *quants; unsigned int nc; void *typedata; SchemaAttr **attrs; unsigned int numAttr; unsigned int numReqAttr; domKeyConstraint *domKeys; SchemaKeySpace *keySpace; Tcl_Obj *defScript; Tcl_Obj *associated; } SchemaCP; typedef struct SchemaValidationStack { SchemaCP *pattern; struct SchemaValidationStack *next; struct SchemaValidationStack *down; int activeChild; int hasMatched; int *interleaveState; } SchemaValidationStack; typedef enum { VALIDATION_READY, VALIDATION_STARTED, VALIDATION_ERROR, VALIDATION_FINISHED } ValidationState; typedef struct { Tcl_HashTable ids; int unknownIDrefs; } SchemaDocKey; typedef struct SchemaData_ { Tcl_Obj *self; char *start; char *startNamespace; Tcl_HashTable element; Tcl_HashTable elementType; Tcl_HashTable elementTypeInstance; Tcl_HashTable namespace; char **prefixns; Tcl_HashTable prefix; Tcl_HashTable pattern; Tcl_HashTable attrNames; Tcl_HashTable textDef; SchemaCP **patternList; unsigned int numPatternList; unsigned int patternListSize; unsigned int forwardPatternDefs; SchemaQuant *quants; int inuse; int currentEvals; int cleanupAfterUse; int evalError; Tcl_Obj *reportCmd; SchemaValidationStack *lastMatchse; int recoverFlags; Tcl_Obj **evalStub; Tcl_Obj **textStub; char *currentNamespace; int defineToplevel; int isTextConstraint; int isAttributeConstraint; SchemaCP *cp; unsigned int contentSize; SchemaAttr **currentAttrs; unsigned int numAttr; unsigned int numReqAttr; unsigned int attrSize; SchemaValidationStack *stack; SchemaValidationStack *stackPool; ValidationState validationState; ValidationAction vaction; const char *vname; const char *vns; const char *vtext; unsigned int skipDeep; Tcl_DString *cdata; Tcl_HashTable ids; int unknownIDrefs; Tcl_HashTable idTables; Tcl_HashTable keySpaces; XML_Parser parser; domNode *node; domNode *insideNode; domTextNode *textNode; unsigned int choiceHashThreshold; unsigned int attributeHashThreshold; char *wsbuf; int wsbufLen; } SchemaData; #define GETASI (SchemaData*)Tcl_GetAssocData(interp, "tdom_schema", NULL); #define SETASI(v) Tcl_SetAssocData (interp, "tdom_schema", NULL, v) #define ADD_CONSTRAINT(sdata, sc) \ sc = TMALLOC (SchemaConstraint); \ memset (sc, 0, sizeof (SchemaConstraint)); \ if (sdata->cp->nc == sdata->contentSize) { \ sdata->cp->content = \ REALLOC (sdata->cp->content, \ 2 * sdata->contentSize \ * sizeof (SchemaCP*)); \ sdata->cp->quants = \ REALLOC (sdata->cp->quants, \ 2 * sdata->contentSize \ * sizeof (SchemaQuant)); \ sdata->contentSize *= 2; \ } \ sdata->cp->content[sdata->cp->nc] = (SchemaCP *) sc; \ sdata->cp->quants[sdata->cp->nc] = SCHEMA_CQUANT_ONE; \ sdata->cp->nc++; \ #define REMEMBER_PATTERN(pattern) \ if (sdata->numPatternList == sdata->patternListSize) { \ sdata->patternList = (SchemaCP **) REALLOC ( \ sdata->patternList, \ sizeof (SchemaCP*) * sdata->patternListSize * 2); \ sdata->patternListSize *= 2; \ } \ sdata->patternList[sdata->numPatternList] = pattern; \ sdata->numPatternList++; SchemaCP* tDOM_initSchemaCP ( Schema_CP_Type type, void *namespace, char *name ); #define initSchemaCP(type,namespace,name) \ tDOM_initSchemaCP(type,namespace,name) int tDOM_evalConstraints ( Tcl_Interp *interp, SchemaData *sdata, SchemaCP *cp, Tcl_Obj *script ); #define evalConstraints(interp,sdata,cp,script) \ tDOM_evalConstraints(interp,sdata,cp,script) int tDOM_checkText ( Tcl_Interp *interp, void *clientData, char *text ); #define checkText(interp,clientData,text) \ tDOM_checkText(interp,clientData,text) int tDOM_schemaInstanceCmd ( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] ); void tDOM_SchemaInit ( Tcl_Interp *interp ); int tDOM_probeElement ( Tcl_Interp *interp, SchemaData *sdata, const char *name, void *namespace ); int tDOM_probeAttributes ( Tcl_Interp *interp, SchemaData *sdata, const char **attr ); int tDOM_probeDomAttributes ( Tcl_Interp *interp, SchemaData *sdata, domAttrNode *attr ); int tDOM_probeElementEnd ( Tcl_Interp * interp, SchemaData *sdata ); int tDOM_probeText ( Tcl_Interp *interp, SchemaData *sdata, char *text, int *only_whites ); void tDOM_schemaReset ( SchemaData *sdata ); #endif tdom-0.9.6-src/generic/domalloc.h0000644000175000017500000000250415025767703015340 0ustar rolfrolf/*--------------------------------------------------------------------------- | Copyright (C) 1999-2000 Jochen C. Loewer (loewerj@hotmail.com) +---------------------------------------------------------------------------- | | A special memory allocator, which uses preallocated / bit masked | based administration of memory block with fixed sizes, like | DOM nodes. This will hopefully save some memory. | | | The contents of this file are subject to the Mozilla Public License | Version 2.0 (the "License"); you may not use this file except in | compliance with the License. You may obtain a copy of the License at | http://www.mozilla.org/MPL/ | | Software distributed under the License is distributed on an "AS IS" | basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the | License for the specific language governing rights and limitations | under the License. | | The Original Code is tDOM. | | The Initial Developer of the Original Code is Jochen Loewer | Portions created by Jochen Loewer are Copyright (C) 1998, 1999 | Jochen Loewer. All Rights Reserved. | | Contributor(s): | | | written by Jochen Loewer | October, 2000 | \--------------------------------------------------------------------------*/ void domAllocInit(void); void * domAlloc(int size); void domFree(void *mem); tdom-0.9.6-src/generic/tdomStubLib.c0000644000175000017500000000500415025767703015767 0ustar rolfrolf/*---------------------------------------------------------------------------- | Copyright (c) 2007 Rolf Ade (rolf@pointsman.de) +----------------------------------------------------------------------------- | | Implements entry point, which has to be called by C coded extensions | to tDOM. Following http://wiki.tcl.tk/3358. | | The contents of this file are subject to the Mozilla Public License | Version 2.0 (the "License"); you may not use this file except in | compliance with the License. You may obtain a copy of the License at | http://www.mozilla.org/MPL/ | | Software distributed under the License is distributed on an "AS IS" | basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the | License for the specific language governing rights and limitations | under the License. | | The Original Code is tDOM. | | The Initial Developer of the Original Code is Jochen Loewer | Portions created by Jochen Loewer are Copyright (C) 1998, 1999 | Jochen Loewer. All Rights Reserved. | | Contributor(s): | | | written by Rolf Ade | August, 2007 | \---------------------------------------------------------------------------*/ #ifndef USE_TCL_STUBS # define USE_TCL_STUBS #endif #undef USE_TCL_STUB_PROCS #include /* * Ensure that Tdom_InitStubs is built as an exported symbol. The other stub * functions should be built as non-exported symbols. */ #undef TCL_STORAGE_CLASS #define TCL_STORAGE_CLASS DLLEXPORT const TdomStubs *tdomStubsPtr; /*---------------------------------------------------------------------------- | Tdom_InitStubs | \---------------------------------------------------------------------------*/ const char * Tdom_InitStubs ( Tcl_Interp *interp, char *version, int exact ) { const char *actualVersion; ClientData clientData = NULL; #if (TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION == 0) Tcl_SetResult(interp, "Too old Tcl version. Binary extensions " "to tDOM are not possible, with a that outdated " "Tcl version.", TCL_STATIC); return NULL; #else actualVersion = Tcl_PkgRequireEx(interp, "tdom", version, exact, (ClientData*) &clientData); tdomStubsPtr = (TdomStubs*)clientData; if (!actualVersion) { return NULL; } if (!tdomStubsPtr) { Tcl_SetResult(interp, "This implementation of Tdom does not " "support stubs", TCL_STATIC); return NULL; } return actualVersion; #endif } tdom-0.9.6-src/generic/datatypes.c0000644000175000017500000017274315025767703015554 0ustar rolfrolf/*---------------------------------------------------------------------------- | Copyright (c) 2022 Rolf Ade (rolf@pointsman.de) |----------------------------------------------------------------------------- | | | The contents of this file are subject to the Mozilla Public License | Version 2.0 (the "License"); you may not use this file except in | compliance with the License. You may obtain a copy of the License at | http://www.mozilla.org/MPL/ | | Software distributed under the License is distributed on an "AS IS" | basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the | License for the specific language governing rights and limitations | under the License. | | Contributor(s): | | | written by Rolf Ade | 2022 | \---------------------------------------------------------------------------*/ #include #include #include #include #ifndef TDOM_NO_SCHEMA #define CHECK_TI \ if (!sdata) { \ SetResult ("Command called outside of schema context"); \ return TCL_ERROR; \ } \ if (!sdata->isTextConstraint) { \ SetResult ("Command called in invalid schema context"); \ return TCL_ERROR; \ } #if !defined(PTR2UINT) # if defined(HAVE_UINTPTR_T) || defined(uintptr_t) # define PTR2UINT(p) ((unsigned int)(uintptr_t)(p)) # else # define PTR2UINT(p) ((unsigned int)(p)) # endif #endif #if !defined(UINT2PTR) # if defined(HAVE_UINTPTR_T) || defined(uintptr_t) # define UINT2PTR(p) ((void *)(uintptr_t)(p)) # else # define UINT2PTR(p) ((void *)(p)) # endif #endif #ifndef WHITESPACETC_BUFFER_LEN_INIT # define WHITESPACETC_BUFFER_LEN_INIT 200 #endif #define SetResult(str) Tcl_ResetResult(interp); \ Tcl_SetStringObj(Tcl_GetObjResult(interp), (str), -1) static int integerImplXsd ( Tcl_Interp *UNUSED(interp), void *constraintData, char *text ) { char *c = text; if (*c == 0) return 0; switch ((intptr_t)constraintData) { case 0: /* integer */ if (*c == '-' || *c == '+') c++; break; case 1: /* negativeInteger */ if (*c != '-') return 0; c++; while (*c == '0') c++; break; case 2: /* nonNegativeInteger */ if (*c == '+') c++; else if (*c == '-') { c++; if (*c == '0') { c++; while (*c == '0') c++; if (*c == 0) return 1; } return 0; } break; case 3: /* nonPositiveInteger */ if (*c == '-') c++; else { if (*c == '+') c++; if (*c == 0) return 0; while (*c == '0') c++; if (*c == 0) return 1; return 0; } break; case 4: /* positiveInteger */ if (*c == '+') c++; while (*c == '0') c++; break; } if (*c == 0) return 0; while (isdigit(*c)) { c++; } if (*c != 0) return 0; return 1; } static int integerImplTcl ( Tcl_Interp *interp, void *constraintData, char *text ) { int n; if (Tcl_GetInt (interp, text, &n) != TCL_OK) { return 0; } switch ((intptr_t)constraintData) { case 0: /* integer */ break; case 1: /* negativeInteger */ if (n >= 0) return 0; break; case 2: /* nonNegativeInteger */ if (n < 0) return 0; break; case 3: /* nonPositiveInteger */ if (n > 0) return 0; break; case 4: /* positiveInteger */ if (n <= 0) return 0; break; } return 1; } static int integerTCObjCmd ( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] ) { SchemaData *sdata = GETASI; SchemaConstraint *sc; int type; static const char *types[] = { "xsd", "tcl", NULL }; enum typeSyms { t_xsd, t_tcl }; CHECK_TI checkNrArgs (1,2,"?xsd|tcl?"); if (objc == 1) { type = t_xsd; } else { if (Tcl_GetIndexFromObj (interp, objv[1], types, "type", 0, &type) != TCL_OK) { return TCL_ERROR; } } ADD_CONSTRAINT (sdata, sc) switch ((enum typeSyms) type) { case t_xsd: sc->constraint = integerImplXsd; break; case t_tcl: sc->constraint = integerImplTcl; break; } sc->constraintData = clientData; return TCL_OK; } typedef struct { int nrArg; Tcl_Obj **evalStub; SchemaData *sdata; } tclTCData; static void tclImplFree ( void *constraintData ) { tclTCData *tcdata = constraintData; int i; for (i = 0; i < tcdata->nrArg-1; i++) { Tcl_DecrRefCount (tcdata->evalStub[i]); } FREE (tcdata->evalStub); FREE (tcdata); } static int tclImpl ( Tcl_Interp *interp, void *constraintData, char *text ) { tclTCData *tcdata = constraintData; int result, boolVal; tcdata->evalStub[tcdata->nrArg-1] = Tcl_NewStringObj(text, -1); Tcl_IncrRefCount (tcdata->evalStub[tcdata->nrArg-1]); tcdata->sdata->currentEvals++; result = Tcl_EvalObjv (interp, tcdata->nrArg, tcdata->evalStub, TCL_EVAL_GLOBAL); tcdata->sdata->currentEvals--; Tcl_DecrRefCount (tcdata->evalStub[tcdata->nrArg-1]); if (result != TCL_OK) { tcdata->sdata->evalError = 1; return 0; } result = Tcl_GetBooleanFromObj (interp, Tcl_GetObjResult (interp), &boolVal); if (result != TCL_OK) { return 0; } if (boolVal) { return 1; } return 0; } static int tclTCObjCmd ( ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] ) { SchemaData *sdata = GETASI; SchemaConstraint *sc; tclTCData *tcdata; int i; CHECK_TI if (objc < 2) { SetResult ("Expected: tclcmd ?arg arg ...?"); return TCL_ERROR; } ADD_CONSTRAINT (sdata, sc) sc->constraint = tclImpl; sc->freeData = tclImplFree; tcdata = TMALLOC (tclTCData); tcdata->nrArg = objc; tcdata->evalStub = MALLOC (sizeof (Tcl_Obj*) * objc); for (i = 1; i < objc; i++) { tcdata->evalStub[i-1] = objv[i]; Tcl_IncrRefCount (tcdata->evalStub[i-1]); } tcdata->sdata = sdata; sc->constraintData = tcdata; return TCL_OK; } static void fixedImplFree ( void *constraintData ) { FREE (constraintData); } static int fixedImpl ( Tcl_Interp *UNUSED(interp), void *constraintData, char *text ) { if (strcmp (text, (char *) constraintData) == 0) { return 1; } return 0; } static int fixedTCObjCmd ( ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] ) { SchemaData *sdata = GETASI; SchemaConstraint *sc; CHECK_TI checkNrArgs (2,2,"Expected: "); ADD_CONSTRAINT (sdata, sc) sc->constraint = fixedImpl; sc->freeData = fixedImplFree; sc->constraintData = tdomstrdup (Tcl_GetString (objv[1])); return TCL_OK; } static void enumerationImplFree ( void *constraintData ) { Tcl_HashTable *values = (Tcl_HashTable *) constraintData; Tcl_DeleteHashTable (values); FREE (values); } static int enumerationImpl ( Tcl_Interp *UNUSED(interp), void *constraintData, char *text ) { Tcl_HashTable *values = (Tcl_HashTable *) constraintData; if (Tcl_FindHashEntry(values, text)) return 1; return 0; } static int enumerationTCObjCmd ( ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] ) { SchemaData *sdata = GETASI; SchemaConstraint *sc; Tcl_HashTable *values; domLength len, i; int hnew; Tcl_Obj *value; CHECK_TI checkNrArgs (2,2,"Expected: "); if (Tcl_ListObjLength (interp, objv[1], &len) != TCL_OK) { SetResult ("The argument must be a valid tcl list"); return TCL_ERROR; } ADD_CONSTRAINT (sdata, sc) sc->constraint = enumerationImpl; sc->freeData = enumerationImplFree; values = TMALLOC (Tcl_HashTable); Tcl_InitHashTable (values, TCL_STRING_KEYS); for (i = 0; i < len; i++) { Tcl_ListObjIndex (interp, objv[1], i, &value); Tcl_CreateHashEntry (values, Tcl_GetString (value), &hnew); } sc->constraintData = values; return TCL_OK; } static void matchImplFree ( void *constraintData ) { Tcl_DecrRefCount ((Tcl_Obj *) constraintData); } static int matchImpl ( Tcl_Interp *UNUSED(interp), void *constraintData, char *text ) { if (Tcl_StringCaseMatch (text, Tcl_GetString ((Tcl_Obj *) constraintData), 0)) return 1; return 0; } static int matchNocaseImpl ( Tcl_Interp *UNUSED(interp), void *constraintData, char *text ) { if (Tcl_StringCaseMatch (text, Tcl_GetString ((Tcl_Obj *) constraintData), TCL_MATCH_NOCASE)) return 1; return 0; } static int matchTCObjCmd ( ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] ) { SchemaData *sdata = GETASI; SchemaConstraint *sc; CHECK_TI checkNrArgs (2,3,"Expected: ?-nocase? "); if (objc == 3) { if (strcmp ("-nocase", Tcl_GetString (objv[1])) != 0) { SetResult ("Expected: ?-nocase? "); return TCL_ERROR; } objv++; } ADD_CONSTRAINT (sdata, sc) if (objc == 2) { sc->constraint = matchImpl; } else { sc->constraint = matchNocaseImpl; } sc->freeData = matchImplFree; Tcl_IncrRefCount (objv[1]); sc->constraintData = objv[1]; return TCL_OK; } static void regexpImplFree ( void *constraintData ) { Tcl_DecrRefCount ((Tcl_Obj *) constraintData); } static int regexpImpl ( Tcl_Interp *interp, void *constraintData, char *text ) { Tcl_Obj *textObj; int rc; textObj = Tcl_NewStringObj(text, -1); rc = Tcl_RegExpMatchObj (interp, textObj, (Tcl_Obj *) constraintData); Tcl_DecrRefCount (textObj); /* rc may be 1, 0, -1 */ if (rc == 1) { return 1; } return 0; } static int regexpTCObjCmd ( ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] ) { SchemaData *sdata = GETASI; SchemaConstraint *sc; CHECK_TI checkNrArgs (2,2,"Expected: "); /* Compile it as syntax test (plus caches the complied regexp in * the internal value) */ if (!Tcl_GetRegExpFromObj (interp, objv[1], TCL_REG_ADVANCED)) { return TCL_ERROR; } ADD_CONSTRAINT (sdata, sc) sc->constraint = regexpImpl; sc->freeData = regexpImplFree; Tcl_IncrRefCount (objv[1]); sc->constraintData = objv[1]; return TCL_OK; } static int nmtokenImpl ( Tcl_Interp *interp, void *UNUSED(constraintData), char *text ) { char *p; int clen, tokenSeen = 0; p = text; /* Skip leading space */ while (*p && *p == ' ') { p++; } while (*p && *p != ' ') { clen = UTF8_CHAR_LEN (*p); if (!clen) { SetResult ("Invalid UTF-8 character"); return 0; } if (!UTF8_GET_NAMING_NMTOKEN (p, clen)) { SetResult ("Attribute value isn't a NMTOKEN"); return 0; } tokenSeen = 1; p += clen; } /* Skip following space */ while (*p && *p == ' ') { p++; } if (*p) { SetResult ("Attribute value isn't a NMTOKEN"); return 0; } if (!*p && !tokenSeen) { SetResult ("Missing NMTOKEN value"); return 0; } return 1; } static int nmtokenTCObjCmd ( ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const UNUSED(objv[]) ) { SchemaData *sdata = GETASI; SchemaConstraint *sc; CHECK_TI checkNrArgs (1,1,"No arguments expected"); ADD_CONSTRAINT (sdata, sc) sc->constraint = nmtokenImpl; return TCL_OK; } static int nmtokensImpl ( Tcl_Interp *interp, void *UNUSED(constraintData), char *text ) { char *p; int clen, tokenSeen = 0; p = text; /* Skip leading space */ while (*p && *p == ' ') { p++; } while (*p) { if (*p == ' ') { p++; continue; } clen = UTF8_CHAR_LEN (*p); if (!clen) { SetResult ("Invalid UTF-8 character"); return 0; } if (!UTF8_GET_NAMING_NMTOKEN (p, clen)) { SetResult ("Invalid character: attribute value isn't a NMTOKENS"); return 0; } tokenSeen = 1; p += clen; } /* Any following space is already skipped above */ if (!tokenSeen) { SetResult ("Missing NMTOKENS value"); return 0; } return 1; } static int nmtokensTCObjCmd ( ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const UNUSED(objv[]) ) { SchemaData *sdata = GETASI; SchemaConstraint *sc; CHECK_TI checkNrArgs (1,1,"No arguments expected"); ADD_CONSTRAINT (sdata, sc) sc->constraint = nmtokensImpl; return TCL_OK; } static int numberImplXsd ( Tcl_Interp *UNUSED(interp), void *UNUSED(constraintData), char *text ) { char *c = text; if (!*c) return 0; if (*c == '-' || *c == '+') c++; while (isdigit(*c)) { c++; } if (*c == '.') c++; while (isdigit(*c)) { c++; } if (*c) return 0; return 1; } static int numberImplTcl ( Tcl_Interp *interp, void *UNUSED(constraintData), char *text ) { double d; if (Tcl_GetDouble (interp, text, &d) != TCL_OK) { return 0; } return 1; } static int numberTCObjCmd ( ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] ) { SchemaData *sdata = GETASI; SchemaConstraint *sc; int type; static const char *types[] = { "xsd", "tcl", NULL }; enum typeSyms { t_xsd, t_tcl }; CHECK_TI checkNrArgs (1,2,"?xsd|tcl?"); if (objc == 1) { type = t_xsd; } else { if (Tcl_GetIndexFromObj (interp, objv[1], types, "type", 0, &type) != TCL_OK) { return TCL_ERROR; } } ADD_CONSTRAINT (sdata, sc) switch ((enum typeSyms) type) { case t_xsd: sc->constraint = numberImplXsd; break; case t_tcl: sc->constraint = numberImplTcl; break; } return TCL_OK; } static int booleanImplXsd ( Tcl_Interp *UNUSED(interp), void *UNUSED(constraintData), char *text ) { char *c = text; switch (*c) { case '0': case '1': c++; if (*c == 0) return 1; break; case 't': if (strcmp (text, "true") == 0) return 1; break; case 'f': if (strcmp (text, "false") == 0) return 1; break; } return 0; } static int booleanImplTcl ( Tcl_Interp *interp, void *UNUSED(constraintData), char *text ) { int b; if (Tcl_GetBoolean (interp, text, &b) != TCL_OK) { return 0; } return 1; } static int booleanTCObjCmd ( ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] ) { SchemaData *sdata = GETASI; SchemaConstraint *sc; int type; static const char *types[] = { "xsd", "tcl", NULL }; enum typeSyms { t_xsd, t_tcl }; CHECK_TI checkNrArgs (1,2,"?xsd|tcl?"); if (objc == 1) { type = t_xsd; } else { if (Tcl_GetIndexFromObj (interp, objv[1], types, "type", 0, &type) != TCL_OK) { return TCL_ERROR; } } ADD_CONSTRAINT (sdata, sc) switch ((enum typeSyms) type) { case t_xsd: sc->constraint = booleanImplXsd; break; case t_tcl: sc->constraint = booleanImplTcl; break; } return TCL_OK; } static int isodateImpl ( Tcl_Interp *UNUSED(interp), void *constraintData, char *text ) { int i, y, m, d, h, min, s, zh, zm, seenNonzero = 0; if (constraintData < (void *)2) { if (*text == '-') { /* A bce date */ text++; } i = 1; /* Parse year */ while (*text >= '0' && *text <= '9') { if (*text > '0' && !seenNonzero) seenNonzero = i; text++; i++; } /* Premature end */ if (i < 5) return 0; if (i > 5) { /* The year has more than 4 digits. Only allowed if in fact * needed (no extra leading zeros). */ if (seenNonzero > 1) return 0; } if (*text != '-') return 0; /* We only need to know the modulo of the year for 4, 100 and 400, * for this the 4 last letters are enough */ y = atoi(text-4); /* There isn't a year 0. it's either 0001 or -0001 */ if (!seenNonzero) return 0; text++; /* Parse month */ for (i = 0; i < 2; i++) { if (*text < '0' || *text > '9') return 0; text++; } if (*text != '-') return 0; m = atoi(text-2); if (m < 1 || m > 12) return 0; text++; /* Parse day */ for (i = 0; i < 2; i++) { if (*text < '0' || *text > '9') return 0; text++; } d = atoi(text-2); if (d < 1) return 0; switch (m) { case 1: case 3: case 5: case 7: case 8: case 10: case 12: if (d > 31) return 0; break; case 4: case 6: case 9: case 11: if (d > 30) return 0; break; case 2: if (y % 4 == 0 && (y % 100 != 0 || y % 400 == 0)) { if (d > 29) return 0; } else { if (d > 28) return 0; } break; } } /* Date part end */ if (constraintData) { if (constraintData == (void *)1) { /* Time part starts */ if (*text != 'T') return 0; text++; } /* Parse hour part */ if (*text < '0' || *text > '9') return 0; h = (*text - 48) * 10; text++; if (*text < '0' || *text > '9') return 0; h += (*text - 48); if (h > 24) return 0; text++; if (*text != ':') return 0; text++; /* Parse minute part */ if (*text < '0' || *text > '9') return 0; min = (*text - 48) * 10; text++; if (*text < '0' || *text > '9') return 0; min += (*text - 48); if (min > 59) return 0; text++; if (*text != ':') return 0; text++; /* Parse seconds part */ if (*text < '0' || *text > '9') return 0; s = (*text - 48) * 10; text++; if (*text < '0' || *text > '9') return 0; s += (*text - 48); if (s > 59) return 0; text++; /* Check for optional fraction seconds part */ if (*text == '.') { if (h == 24) return 0; text++; /* Dangling decimal point is not allowed */ if (*text < '0' || *text > '9') return 0; text++; while (*text >= '0' && *text <= '9') text++; } if (h == 24 && (min > 0 || s > 0)) return 0; } if (*text == '\0') return 1; /* Parse optional timezone part */ switch (*text) { case 'Z': text++; if (*text != '\0') return 0; break; case '+': case '-': text++; for (i = 0; i < 2; i++) { if (*text < '0' || *text > '9') return 0; text++; } if (*text != ':') return 0; zh = atoi(text-2); if (zh > 14) return 0; text++; for (i = 0; i < 2; i++) { if (*text < '0' || *text > '9') return 0; text++; } if (*text != '\0') return 0; zm = atoi(text-2); if (zh < 14) { if (zm > 59) return 0; } else { if (zm != 0) return 0; } break; default: return 0; } return 1; } static int dateTCObjCmd ( ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const UNUSED(objv[]) ) { SchemaData *sdata = GETASI; SchemaConstraint *sc; CHECK_TI checkNrArgs (1,1,"No arguments expected"); ADD_CONSTRAINT (sdata, sc) sc->constraint = isodateImpl; sc->constraintData = (void *) 0; return TCL_OK; } static int dateTimeTCObjCmd ( ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const UNUSED(objv[]) ) { SchemaData *sdata = GETASI; SchemaConstraint *sc; CHECK_TI checkNrArgs (1,1,"No arguments expected"); ADD_CONSTRAINT (sdata, sc) sc->constraint = isodateImpl; sc->constraintData = (void *) 1; return TCL_OK; } static int timeTCObjCmd ( ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const UNUSED(objv[]) ) { SchemaData *sdata = GETASI; SchemaConstraint *sc; CHECK_TI checkNrArgs (1,1,"No arguments expected"); ADD_CONSTRAINT (sdata, sc) sc->constraint = isodateImpl; sc->constraintData = (void *) 2; return TCL_OK; } static int maxLengthImpl ( Tcl_Interp *interp, void *constraintData, char *text ) { unsigned int len = 0, maxlen = PTR2UINT(constraintData); int clen; while (*text != '\0') { clen = UTF8_CHAR_LEN (*text); if (!clen) { SetResult ("Invalid UTF-8 character"); return 0; } len++; if (len > maxlen) return 0; text += clen; } return 1; } static int maxLengthTCObjCmd ( ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] ) { SchemaData *sdata = GETASI; SchemaConstraint *sc; int len; CHECK_TI checkNrArgs (2,2,"Expected: "); if (Tcl_GetIntFromObj (interp, objv[1], &len) != TCL_OK) { SetResult ("Expected: "); return TCL_ERROR; } if (len < 1) { SetResult ("The maximum length must be at least 1"); } ADD_CONSTRAINT (sdata, sc) sc->constraint = maxLengthImpl; sc->constraintData = UINT2PTR(len); return TCL_OK; } static int minLengthImpl ( Tcl_Interp *interp, void *constraintData, char *text ) { unsigned int len = 0, minlen = PTR2UINT(constraintData); int clen; while (*text != '\0') { clen = UTF8_CHAR_LEN (*text); if (!clen) { SetResult ("Invalid UTF-8 character"); return 0; } len++; if (len >= minlen) return 1; text += clen; } return 0; } static int minLengthTCObjCmd ( ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] ) { SchemaData *sdata = GETASI; SchemaConstraint *sc; int len; CHECK_TI checkNrArgs (2,2,"Expected: "); if (Tcl_GetIntFromObj (interp, objv[1], &len) != TCL_OK) { SetResult ("Expected: "); return TCL_ERROR; } if (len < 1) { SetResult ("The minimum length must be at least 1"); } ADD_CONSTRAINT (sdata, sc) sc->constraint = minLengthImpl; sc->constraintData = UINT2PTR(len); return TCL_OK; } static int oneOfImpl ( Tcl_Interp *interp, void *constraintData, char *text ) { SchemaCP *cp = (SchemaCP *) constraintData; SchemaConstraint *sc; unsigned int i; /* Look also at checkText */ for (i = 0; i < cp->nc; i++) { sc = (SchemaConstraint *) cp->content[i]; if ((sc->constraint) (interp, sc->constraintData, text)) { return 1; } } return 0; } static int oneOfTCObjCmd ( ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] ) { SchemaData *sdata = GETASI; SchemaCP *cp; SchemaConstraint *sc; int rc; CHECK_TI checkNrArgs (2,2,"Expected: "); cp = initSchemaCP (SCHEMA_CTYPE_CHOICE, NULL, NULL); cp->type = SCHEMA_CTYPE_TEXT; REMEMBER_PATTERN (cp) rc = evalConstraints (interp, sdata, cp, objv[1]); if (rc == TCL_OK) { ADD_CONSTRAINT (sdata, sc) sc->constraint = oneOfImpl; sc->constraintData = (void *)cp; return TCL_OK; } return TCL_ERROR; } static int allOfTCObjCmd ( ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] ) { SchemaData *sdata = GETASI; SchemaCP *cp; SchemaConstraint *sc; int rc; CHECK_TI checkNrArgs (2,2,"Expected: "); cp = initSchemaCP (SCHEMA_CTYPE_CHOICE, NULL, NULL); cp->type = SCHEMA_CTYPE_TEXT; REMEMBER_PATTERN (cp) rc = evalConstraints (interp, sdata, cp, objv[1]); if (rc == TCL_OK) { ADD_CONSTRAINT (sdata, sc) sc->constraint = tDOM_checkText; sc->constraintData = (void *)cp; return TCL_OK; } return TCL_ERROR; } static int stripImpl ( Tcl_Interp *interp, void *constraintData, char *text ) { SchemaCP *cp = (SchemaCP *) constraintData; int rc, restore = 0; char *end, saved; while(SPACE((unsigned char)*text)) text++; if(*text != 0) { /* Not white space only */ /* Trim trailing space */ end = text + strlen(text) - 1; while(end > text && SPACE((unsigned char)*end)) end--; saved = end[1]; restore = 1; end[1] = '\0'; } rc = checkText (interp, cp, text); if (restore) end[1] = saved; return rc; } static int stripTCObjCmd ( ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] ) { SchemaData *sdata = GETASI; SchemaCP *cp; SchemaConstraint *sc; int rc; CHECK_TI checkNrArgs (2,2,"Expected: "); cp = initSchemaCP (SCHEMA_CTYPE_CHOICE, NULL, NULL); cp->type = SCHEMA_CTYPE_TEXT; REMEMBER_PATTERN (cp) rc = evalConstraints (interp, sdata, cp, objv[1]); if (rc == TCL_OK) { ADD_CONSTRAINT (sdata, sc) sc->constraint = stripImpl; sc->constraintData = (void *)cp; return TCL_OK; } return TCL_ERROR; } static int splitWhitespaceImpl ( Tcl_Interp *interp, void *constraintData, char *text ) { SchemaCP *cp = (SchemaCP *) constraintData; int rc = 0; char *p, *end, saved = 0; p = text; while (*p != 0) { while(SPACE (*p)) p++; if (*p == 0) break; end = p; end++; while (*end != 0 && !SPACE(*end)) end++; saved = *end; *end = 0; rc = checkText (interp, cp, p); *end = saved; p = end; if (!rc) break; } return rc; } typedef struct { int nrArg; Tcl_Obj **evalStub; SchemaData *sdata; SchemaCP *cp; } splitTclTCData; static int splitTclImpl ( Tcl_Interp *interp, void *constraintData, char *text ) { splitTclTCData *tcdata = (splitTclTCData *) constraintData; domLength listlen, i; int rc; Tcl_Obj *list, *listelm; tcdata->evalStub[tcdata->nrArg-1] = Tcl_NewStringObj(text, -1); Tcl_IncrRefCount (tcdata->evalStub[tcdata->nrArg-1]); tcdata->sdata->currentEvals++; rc = Tcl_EvalObjv (interp, tcdata->nrArg, tcdata->evalStub, TCL_EVAL_GLOBAL); tcdata->sdata->currentEvals--; Tcl_DecrRefCount (tcdata->evalStub[tcdata->nrArg-1]); if (rc != TCL_OK) { tcdata->sdata->evalError = 1; return 0; } list = Tcl_GetObjResult (interp); Tcl_IncrRefCount (list); Tcl_ResetResult (interp); if (Tcl_ListObjLength (interp, list, &listlen) != TCL_OK) { Tcl_DecrRefCount (list); tcdata->sdata->evalError = 1; return 0; } rc = 0; for (i = 0; i < listlen; i++) { Tcl_ListObjIndex (interp, list, i, &listelm); rc = checkText (interp, tcdata->cp, Tcl_GetString (listelm)); if (!rc) break; } Tcl_DecrRefCount (list); return rc; } static void splitTclImplFree ( void *constraintData ) { splitTclTCData *tcdata = constraintData; int i; for (i = 0; i < tcdata->nrArg-1; i++) { Tcl_DecrRefCount (tcdata->evalStub[i]); } FREE (tcdata->evalStub); FREE (tcdata); } static int splitTCObjCmd ( ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] ) { SchemaData *sdata = GETASI; SchemaCP *cp; SchemaConstraint *sc; int methodIndex, rc, i; splitTclTCData *tcdata; static const char *methods[] = { "whitespace", "tcl", NULL }; enum method { m_whitespace, m_tcl }; CHECK_TI if (objc < 2) { SetResult("Expected: ?type ?args?? "); return TCL_ERROR; } if (objc == 2) { methodIndex = m_whitespace; } else { if (Tcl_GetIndexFromObj (interp, objv[1], methods, "type", 0, &methodIndex) != TCL_OK) { return TCL_ERROR; } } switch ((enum method) methodIndex) { case m_whitespace: if (objc > 2) { SetResult ("Type whitespace expects no argument."); return TCL_ERROR; } break; case m_tcl: if (objc < 3) { SetResult ("Expected: tclcmd ?arg ...?."); return TCL_ERROR; } } cp = initSchemaCP (SCHEMA_CTYPE_CHOICE, NULL, NULL); cp->type = SCHEMA_CTYPE_TEXT; REMEMBER_PATTERN (cp) rc = evalConstraints (interp, sdata, cp, objv[objc-1]); if (rc != TCL_OK) { return TCL_ERROR; } ADD_CONSTRAINT (sdata, sc) switch ((enum method) methodIndex) { case m_whitespace: sc->constraint = splitWhitespaceImpl; sc->constraintData = cp; break; case m_tcl: sc->constraint = splitTclImpl; sc->freeData = splitTclImplFree; tcdata = TMALLOC (splitTclTCData); tcdata->nrArg = objc - 2; tcdata->evalStub = MALLOC (sizeof (Tcl_Obj*) * (objc-2)); for (i = 2; i < objc -1; i++) { tcdata->evalStub[i-2] = objv[i]; Tcl_IncrRefCount (tcdata->evalStub[i-2]); } tcdata->sdata = sdata; tcdata->cp = cp; sc->constraintData = tcdata; } return TCL_OK; } static int idImpl ( Tcl_Interp *UNUSED(interp), void *constraintData, char *text ) { SchemaData *sdata = (SchemaData *) constraintData; int hnew; Tcl_HashEntry *h; h = Tcl_CreateHashEntry (&sdata->ids, text, &hnew); if (hnew) { Tcl_SetHashValue (h, 1); return 1; } if (Tcl_GetHashValue (h) == 0) { Tcl_SetHashValue (h, 1); sdata->unknownIDrefs--; return 1; } else { /* Duplicate ID value */ return 0; } } static int docidImpl ( Tcl_Interp *UNUSED(interp), void *constraintData, char *text ) { SchemaDocKey *dk = (SchemaDocKey *) constraintData; int hnew; Tcl_HashEntry *h; h = Tcl_CreateHashEntry (&dk->ids, text, &hnew); if (hnew) { Tcl_SetHashValue (h, 1); return 1; } if (Tcl_GetHashValue (h) == 0) { Tcl_SetHashValue (h, 1); dk->unknownIDrefs--; return 1; } /* Duplicate ID value */ return 0; } static int idTCObjCmd ( ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] ) { SchemaData *sdata = GETASI; SchemaConstraint *sc; Tcl_HashEntry *h; int hnew; SchemaDocKey *dk; CHECK_TI checkNrArgs (1,2,"?key_space?"); ADD_CONSTRAINT (sdata, sc) if (objc == 1) { sc->constraint = idImpl; sc->constraintData = (void *)sdata; } else { h = Tcl_CreateHashEntry (&sdata->idTables, Tcl_GetString (objv[1]), &hnew); if (hnew) { dk = TMALLOC (SchemaDocKey); Tcl_InitHashTable (&dk->ids, TCL_STRING_KEYS); dk->unknownIDrefs = 0; Tcl_SetHashValue (h, dk); } else { dk = Tcl_GetHashValue (h); } sc->constraint = docidImpl; sc->constraintData = (void *)dk; } return TCL_OK; } static int idrefImpl ( Tcl_Interp *UNUSED(interp), void *constraintData, char *text ) { SchemaData *sdata = (SchemaData *) constraintData; int hnew; Tcl_HashEntry *h; h = Tcl_CreateHashEntry (&sdata->ids, text, &hnew); if (hnew) { Tcl_SetHashValue (h, 0); sdata->unknownIDrefs++; } return 1; } static int docidrefImpl ( Tcl_Interp *UNUSED(interp), void *constraintData, char *text ) { SchemaDocKey *dk = (SchemaDocKey *) constraintData; int hnew; Tcl_HashEntry *h; h = Tcl_CreateHashEntry (&dk->ids, text, &hnew); if (hnew) { Tcl_SetHashValue (h, 0); dk->unknownIDrefs++; } return 1; } static int idrefTCObjCmd ( ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] ) { SchemaData *sdata = GETASI; SchemaConstraint *sc; Tcl_HashEntry *h; int hnew; SchemaDocKey *dk; CHECK_TI checkNrArgs (1,2,"?key_space?"); ADD_CONSTRAINT (sdata, sc) if (objc == 1) { sc->constraint = idrefImpl; sc->constraintData = (void *)sdata; } else { h = Tcl_CreateHashEntry (&sdata->idTables, Tcl_GetString (objv[1]), &hnew); if (hnew) { dk = TMALLOC (SchemaDocKey); Tcl_InitHashTable (&dk->ids, TCL_STRING_KEYS); dk->unknownIDrefs = 0; Tcl_SetHashValue (h, dk); } else { dk = Tcl_GetHashValue (h); } sc->constraint = docidrefImpl; sc->constraintData = (void *)dk; } return TCL_OK; } static int keyImpl ( Tcl_Interp *UNUSED(interp), void *constraintData, char *text ) { SchemaKeySpace *ks = (SchemaKeySpace *) constraintData; int hnew; Tcl_HashEntry *h; if (!ks->active) return 1; h = Tcl_CreateHashEntry (&ks->ids, text, &hnew); if (hnew) { Tcl_SetHashValue (h, 1); return 1; } if (Tcl_GetHashValue (h) == 0) { Tcl_SetHashValue (h, 1); ks->unknownIDrefs--; return 1; } else { /* Duplicate ID value */ return 0; } } static int keyTCObjCmd ( ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] ) { SchemaData *sdata = GETASI; SchemaConstraint *sc; Tcl_HashEntry *h; int hnew; SchemaKeySpace *ks; CHECK_TI checkNrArgs (2,2,"key_space"); ADD_CONSTRAINT (sdata, sc) h = Tcl_CreateHashEntry (&sdata->keySpaces, Tcl_GetString (objv[1]), &hnew); if (hnew) { ks = TMALLOC (SchemaKeySpace); ks->active = 0; ks->unknownIDrefs = 0; Tcl_SetHashValue (h, ks); } else { ks = Tcl_GetHashValue (h); } sc->constraint = keyImpl; sc->constraintData = (void *) ks; return TCL_OK; } static int keyrefImpl ( Tcl_Interp *UNUSED(interp), void *constraintData, char *text ) { SchemaKeySpace *ks = (SchemaKeySpace *) constraintData; int hnew; Tcl_HashEntry *h; if (!ks->active) return 1; h = Tcl_CreateHashEntry (&ks->ids, text, &hnew); if (hnew) { Tcl_SetHashValue (h, 0); ks->unknownIDrefs++; } return 1; } static int keyrefTCObjCmd ( ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] ) { SchemaData *sdata = GETASI; SchemaConstraint *sc; Tcl_HashEntry *h; int hnew; SchemaKeySpace *ks; CHECK_TI checkNrArgs (2,2,"key_space"); ADD_CONSTRAINT (sdata, sc) h = Tcl_CreateHashEntry (&sdata->keySpaces, Tcl_GetString (objv[1]), &hnew); if (hnew) { ks = TMALLOC (SchemaKeySpace); Tcl_InitHashTable (&ks->ids, TCL_STRING_KEYS); ks->unknownIDrefs = 0; Tcl_SetHashValue (h, ks); } else { ks = Tcl_GetHashValue (h); } sc->constraint = keyrefImpl; sc->constraintData = (void *)ks; return TCL_OK; } static int base64Impl ( Tcl_Interp *UNUSED(interp), void *UNUSED(constraintData), char *text ) { int chars = 0, equals = 0; while (*text != '\0') { if (SPACE(*text)) { text++; continue; } if ( (*text >= 'A' && *text <= 'Z') || (*text >= 'a' && *text <= 'z') || (*text >= '0' && *text <= '9') || (*text = '+') || (*text = '/')) { chars++; text++; continue; } if (equals < 2 && *text == '=') { equals++; text++; continue; } break; } if (*text) { return 0; } if ((chars + equals) % 4 != 0) { return 0; } return 1; } static int base64TCObjCmd ( ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const UNUSED(objv[]) ) { SchemaData *sdata = GETASI; SchemaConstraint *sc; CHECK_TI checkNrArgs (1,1,"No arguments expected"); ADD_CONSTRAINT (sdata, sc) sc->constraint = base64Impl; return TCL_OK; } static int nameImpl ( Tcl_Interp *UNUSED(interp), void *UNUSED(constraintData), char *text ) { return domIsNAME (text); } static int nameTCObjCmd ( ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const UNUSED(objv[]) ) { SchemaData *sdata = GETASI; SchemaConstraint *sc; CHECK_TI checkNrArgs (1,1,"No arguments expected"); ADD_CONSTRAINT (sdata, sc) sc->constraint = nameImpl; return TCL_OK; } static int ncnameImpl ( Tcl_Interp *UNUSED(interp), void *UNUSED(constraintData), char *text ) { return domIsNCNAME (text); } static int ncnameTCObjCmd ( ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const UNUSED(objv[]) ) { SchemaData *sdata = GETASI; SchemaConstraint *sc; CHECK_TI checkNrArgs (1,1,"No arguments expected"); ADD_CONSTRAINT (sdata, sc) sc->constraint = ncnameImpl; return TCL_OK; } static int qnameImpl ( Tcl_Interp *UNUSED(interp), void *UNUSED(constraintData), char *text ) { return domIsQNAME (text); } static int qnameTCObjCmd ( ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const UNUSED(objv[]) ) { SchemaData *sdata = GETASI; SchemaConstraint *sc; CHECK_TI checkNrArgs (1,1,"No arguments expected"); ADD_CONSTRAINT (sdata, sc) sc->constraint = qnameImpl; return TCL_OK; } static int hexBinaryImpl ( Tcl_Interp *UNUSED(interp), void *UNUSED(constraintData), char *text ) { int count = 0; if (*text == 0) return 0; while (*text) { if ((*text >= '0' && *text <= '9') || (*text >= 'A' && *text <= 'F') || (*text >= 'a' && *text <= 'f')) { text++; count++; } else return 0; } if (count % 2 == 0) return 1; return 0; } static int hexBinaryTCObjCmd ( ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const UNUSED(objv[]) ) { SchemaData *sdata = GETASI; SchemaConstraint *sc; CHECK_TI checkNrArgs (1,1,"No arguments expected"); ADD_CONSTRAINT (sdata, sc) sc->constraint = hexBinaryImpl; return TCL_OK; } static int unsignedIntTypesImpl ( Tcl_Interp *UNUSED(interp), void *constraintData, char *text ) { char *c; int count = 0; int nrDigits[] = {3, 5, 10, 20}; const char *max[] = { "255", "65535", "4294967295", "18446744073709551615" }; if (*text == '+') text++; if (*text == 0) return 0; if (*text == '0') { text++; while (*text == '0') text++; if (*text == 0) return 1; } c = text; while (*text) { if (*text >= '0' && *text <= '9') { text++; count++; } else return 0; } if (count < nrDigits[(intptr_t) constraintData]) return 1; if (count == nrDigits[(intptr_t) constraintData]) { if (strcmp (max[(intptr_t) constraintData], c) >= 0) { return 1; } } return 0; } static int unsignedIntTypesTCObjCmd ( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const UNUSED(objv[]) ) { SchemaData *sdata = GETASI; SchemaConstraint *sc; CHECK_TI checkNrArgs (1,1,"No arguments expected"); ADD_CONSTRAINT (sdata, sc) sc->constraint = unsignedIntTypesImpl; sc->constraintData = clientData; return TCL_OK; } static int intTypesImpl ( Tcl_Interp *UNUSED(interp), void *constraintData, char *text ) { char *c; int count = 0; int nrDigits[] = {3, 5, 10, 20}; const char *compare; const char *max[] = { "127", "32767", "2147483647", "9223372036854775807" }; const char *min[] = { "128", "32768", "2147483648", "9223372036854775808" }; if (*text == '-') { compare = min[(intptr_t) constraintData]; } else { compare = max[(intptr_t) constraintData]; } if (*text == '+' || *text == '-') text++; if (*text == 0) return 0; if (*text == '0') { text++; while (*text == '0') text++; if (*text == 0) return 1; } c = text; while (*text) { if (*text >= '0' && *text <= '9') { text++; count++; } else return 0; } if (count < nrDigits[(intptr_t) constraintData]) return 1; if (count == nrDigits[(intptr_t) constraintData]) { if (strcmp (compare, c) >= 0) return 1; } return 0; } static int intTypesTCObjCmd ( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const UNUSED(objv[]) ) { SchemaData *sdata = GETASI; SchemaConstraint *sc; CHECK_TI checkNrArgs (1,1,"No arguments expected"); ADD_CONSTRAINT (sdata, sc) sc->constraint = intTypesImpl; sc->constraintData = clientData; return TCL_OK; } static void setvarImplFree ( void *constraintData ) { FREE (constraintData); } static int setvarImpl ( Tcl_Interp *interp, void *constraintData, char *text ) { char *varName = (char *)constraintData; if (!Tcl_SetVar (interp, varName, text, TCL_LEAVE_ERR_MSG)) { return 0; } return 1; } static int setvarTCObjCmd ( ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] ) { SchemaData *sdata = GETASI; SchemaConstraint *sc; CHECK_TI checkNrArgs (2,2,""); ADD_CONSTRAINT (sdata, sc) sc->constraint = setvarImpl; sc->freeData = setvarImplFree; sc->constraintData = tdomstrdup (Tcl_GetString (objv[1])); return TCL_OK; } typedef struct { SchemaCP *cp; SchemaData *sdata; } WhitespaceTCData; static void whitespaceImplFree ( void *constraintData ) { WhitespaceTCData *wsdata = (WhitespaceTCData *) constraintData; FREE (wsdata); } static int whitespaceImplReplace ( Tcl_Interp *interp, void *constraintData, char *text ) { WhitespaceTCData *wsdata = (WhitespaceTCData *) constraintData; char *p, *c, *alloced; SchemaData *sdata; sdata = wsdata->sdata; p = text; c = sdata->wsbuf; alloced = sdata->wsbuf + sdata->wsbufLen; while (*p) { if (*p == '\t' || *p == '\n' || *p == '\r') { *c = ' '; } else { *c = *p; } c++; if (c == alloced) { sdata->wsbuf = REALLOC (sdata->wsbuf, 2 * sdata->wsbufLen); c = sdata->wsbuf + sdata->wsbufLen; sdata->wsbufLen *= 2; alloced = sdata->wsbuf + sdata->wsbufLen; } p++; } *c = '\0'; return checkText (interp, wsdata->cp, sdata->wsbuf); } static int whitespaceImplCollapse ( Tcl_Interp *interp, void *constraintData, char *text ) { WhitespaceTCData *wsdata = (WhitespaceTCData *) constraintData; char *p, *c, *alloced; SchemaData *sdata; sdata = wsdata->sdata; p = text; c = sdata->wsbuf; alloced = sdata->wsbuf + sdata->wsbufLen; while (SPACE(*p)) p++; while (*p) { if (SPACE (*p)) { *c = ' '; c++; if (c == alloced) { sdata->wsbuf = REALLOC (sdata->wsbuf, 2 * sdata->wsbufLen); c = sdata->wsbuf + sdata->wsbufLen; sdata->wsbufLen *= 2; alloced = sdata->wsbuf + sdata->wsbufLen; } p++; while (SPACE (*p)) p++; if (!*p) c--; } else { *c = *p; c++; if (c == alloced) { sdata->wsbuf = REALLOC (sdata->wsbuf, 2 * sdata->wsbufLen); c = sdata->wsbuf + sdata->wsbufLen; sdata->wsbufLen *= 2; alloced = sdata->wsbuf + sdata->wsbufLen; } p++; } } *c = '\0'; return checkText (interp, wsdata->cp, wsdata->sdata->wsbuf); } static int whitespaceTCObjCmd ( ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] ) { SchemaData *sdata = GETASI; SchemaCP *cp; SchemaConstraint *sc; int type; WhitespaceTCData *wsdata; static const char *types[] = { "preserve", "replace", "collapse", NULL }; enum typeSyms { t_preserve, t_replace, t_collapse }; CHECK_TI checkNrArgs (3,3,"(\"preserve\"|\"replace\"|\"collapse\") " ""); if (Tcl_GetIndexFromObj (interp, objv[1], types, "type", 0, &type) != TCL_OK) { return TCL_ERROR; } cp = initSchemaCP (SCHEMA_CTYPE_CHOICE, NULL, NULL); cp->type = SCHEMA_CTYPE_TEXT; REMEMBER_PATTERN (cp) if (evalConstraints (interp, sdata, cp, objv[2]) != TCL_OK) { return TCL_ERROR; } if (type == t_preserve) { ADD_CONSTRAINT (sdata, sc) sc->constraint = tDOM_checkText; sc->constraintData = (void *)cp; return TCL_OK; } ADD_CONSTRAINT (sdata, sc) sc->freeData = whitespaceImplFree; if (sdata->wsbufLen == 0) { sdata->wsbuf = (char *) MALLOC (WHITESPACETC_BUFFER_LEN_INIT); sdata->wsbufLen = WHITESPACETC_BUFFER_LEN_INIT; } wsdata = TMALLOC (WhitespaceTCData); wsdata->sdata = sdata; wsdata->cp = cp; sc->constraintData = (void *)wsdata; if (type == t_replace) { sc->constraint = whitespaceImplReplace; } else { sc->constraint = whitespaceImplCollapse; } return TCL_OK; } static int notImpl ( Tcl_Interp *interp, void *constraintData, char *text ) { SchemaCP *cp = (SchemaCP *) constraintData; SchemaConstraint *sc; unsigned int i; /* Look also at checkText and oneOfImpl */ for (i = 0; i < cp->nc; i++) { sc = (SchemaConstraint *) cp->content[i]; if ((sc->constraint) (interp, sc->constraintData, text)) { return 0; } } return 1; } static int notTCObjCmd ( ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] ) { SchemaData *sdata = GETASI; SchemaCP *cp; SchemaConstraint *sc; int rc; CHECK_TI checkNrArgs (2,2,"Expected: "); cp = initSchemaCP (SCHEMA_CTYPE_CHOICE, NULL, NULL); cp->type = SCHEMA_CTYPE_TEXT; REMEMBER_PATTERN (cp) rc = evalConstraints (interp, sdata, cp, objv[1]); if (rc == TCL_OK) { ADD_CONSTRAINT (sdata, sc) sc->constraint = notImpl; sc->constraintData = (void *)cp; return TCL_OK; } return TCL_ERROR; } static int durationImpl ( Tcl_Interp *UNUSED(interp), void *UNUSED(constraintData), char *text ) { /* PnYnMnDTnHnMnS */ int p, n, seen = 0, seenT = 0; char des[9] = " YMDTHMS"; if (*text == '-') { /* Negative duration is allowed */ text++; } if (*text != 'P') return 0; text++; p = 0; while (*text) { n = 0; while (*text >= '0' && *text <= '9') { n++; text++; } if (!*text) return 0; if (*text == '.') { if (p < 4 || !n) return 0; text++; if (!*text) return 0; /* Ensure at least one digit after . */ if (*text < '0' || *text > '9') return 0; text++; while (*text >= '0' && *text <= '9') text++; if (*text != 'S') return 0; text++; if (*text) return 0; return 1; } for (; p < 8; p++) { if (*text == des[p]) break; } if (p == 4) { if (n) return 0; seenT = 1; text++; if (!*text) return 0; continue; } else { if (!n) return 0; seen = 1; } if (p > 4 && !seenT) return 0; if (p == 8 || !seen) return 0; text++; } if (!p) return 0; return 1; } static int durationTCObjCmd ( ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const UNUSED(objv[]) ) { SchemaData *sdata = GETASI; SchemaConstraint *sc; CHECK_TI checkNrArgs (1,1,"No arguments expected"); ADD_CONSTRAINT (sdata, sc) sc->constraint = durationImpl; return TCL_OK; } static int lengthImpl ( Tcl_Interp *interp, void *constraintData, char *text ) { unsigned int len = 0, length = PTR2UINT(constraintData); int clen; while (*text != '\0') { clen = UTF8_CHAR_LEN (*text); if (!clen) { SetResult ("Invalid UTF-8 character"); return 0; } len++; if (len > length) return 0; text += clen; } if (len == length) return 1; return 0; } static int lengthTCObjCmd ( ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] ) { SchemaData *sdata = GETASI; SchemaConstraint *sc; int len; CHECK_TI checkNrArgs (2,2,"Expected: "); if (Tcl_GetIntFromObj (interp, objv[1], &len) != TCL_OK) { SetResult ("Expected: "); return TCL_ERROR; } if (len < 0) { SetResult ("The length must be at least 0"); } ADD_CONSTRAINT (sdata, sc) sc->constraint = lengthImpl; sc->constraintData = UINT2PTR(len); return TCL_OK; } static int typeImpl ( Tcl_Interp *interp, void *constraintData, char *text ) { return checkText (interp, constraintData, text); } static int typeTCObjCmd ( ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] ) { SchemaData *sdata = GETASI; SchemaConstraint *sc; Tcl_HashEntry *h; int hnew; SchemaCP *pattern = NULL; CHECK_TI checkNrArgs (2,2,"Expected: "); h = Tcl_CreateHashEntry (&sdata->textDef, Tcl_GetString (objv[1]), &hnew); if (hnew) { pattern = initSchemaCP (SCHEMA_CTYPE_CHOICE, NULL, NULL); pattern->type = SCHEMA_CTYPE_TEXT; REMEMBER_PATTERN (pattern) pattern->flags |= FORWARD_PATTERN_DEF; sdata->forwardPatternDefs++; Tcl_SetHashValue (h, pattern); } ADD_CONSTRAINT (sdata, sc) sc->constraint = typeImpl; sc->constraintData = Tcl_GetHashValue (h); return TCL_OK; } static const char *jsonTextTypes[] = { "NULL", "TRUE", "FALSE", "STRING", "NUMBER", NULL }; enum jsonTextType { jt_null, jt_true, jt_false, jt_string, jt_number }; typedef struct { enum jsonTextType type; SchemaData *sdata; } jsontypeTCData; static void jsontypeImplFree ( void *constraintData ) { jsontypeTCData *cd = (jsontypeTCData *) constraintData; FREE (cd); } static int jsontypeImpl ( Tcl_Interp *UNUSED(interp), void *constraintData, char *UNUSED(text) ) { jsontypeTCData *cd = (jsontypeTCData *) constraintData; domTextNode *textNode = cd->sdata->textNode; if (!textNode) { return 1; } switch (cd->type) { case jt_null: return textNode->info == JSON_NULL ? 1 : 0; case jt_true: return textNode->info == JSON_TRUE ? 1 : 0; case jt_false: return textNode->info == JSON_FALSE ? 1 : 0; case jt_string: return textNode->info == JSON_STRING ? 1 : 0; case jt_number: return textNode->info == JSON_NUMBER ? 1 : 0; } return 0; } static int jsontypeTCObjCmd ( ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] ) { SchemaData *sdata = GETASI; SchemaConstraint *sc; int jsonType; jsontypeTCData *cd; CHECK_TI checkNrArgs (2,2,"Expected: "); if (Tcl_GetIndexFromObj (interp, objv[1], jsonTextTypes, "jsonType", 1, &jsonType) != TCL_OK) { return TCL_ERROR; } cd = TMALLOC (jsontypeTCData); cd->sdata = sdata; cd->type = jsonType; ADD_CONSTRAINT (sdata, sc) sc->constraint = jsontypeImpl; sc->constraintData = cd; sc->freeData = jsontypeImplFree; return TCL_OK; } static int dateObjCmd ( ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] ) { checkNrArgs (2,2,""); Tcl_SetObjResult (interp, Tcl_NewBooleanObj ( isodateImpl (interp, NULL, Tcl_GetString (objv[1])))); return TCL_OK; } static int dateTimeObjCmd ( ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] ) { checkNrArgs (2,2,""); Tcl_SetObjResult (interp, Tcl_NewBooleanObj ( isodateImpl (interp, (void *) 1, Tcl_GetString (objv[1])))); return TCL_OK; } static int timeObjCmd ( ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] ) { checkNrArgs (2,2,""); Tcl_SetObjResult (interp, Tcl_NewBooleanObj ( isodateImpl (interp, (void *) 2, Tcl_GetString (objv[1])))); return TCL_OK; } static int durationObjCmd ( ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] ) { checkNrArgs (2,2,""); Tcl_SetObjResult (interp, Tcl_NewBooleanObj ( durationImpl (interp, NULL, Tcl_GetString (objv[1])))); return TCL_OK; } void tDOM_DatatypesInit ( Tcl_Interp *interp ) { /* The text constraint commands */ Tcl_CreateObjCommand (interp,"tdom::schema::text::integer", integerTCObjCmd, (ClientData) 0, NULL); Tcl_CreateObjCommand (interp,"tdom::schema::text::negativeInteger", integerTCObjCmd, (ClientData) 1, NULL); Tcl_CreateObjCommand (interp,"tdom::schema::text::nonNegativeInteger", integerTCObjCmd, (ClientData) 2, NULL); Tcl_CreateObjCommand (interp,"tdom::schema::text::nonPositiveInteger", integerTCObjCmd, (ClientData) 3, NULL); Tcl_CreateObjCommand (interp,"tdom::schema::text::positiveInteger", integerTCObjCmd, (ClientData) 4, NULL); Tcl_CreateObjCommand (interp, "tdom::schema::text::tcl", tclTCObjCmd, NULL, NULL); Tcl_CreateObjCommand (interp, "tdom::schema::text::fixed", fixedTCObjCmd, NULL, NULL); Tcl_CreateObjCommand (interp, "tdom::schema::text::enumeration", enumerationTCObjCmd, NULL, NULL); Tcl_CreateObjCommand (interp, "tdom::schema::text::match", matchTCObjCmd, NULL, NULL); Tcl_CreateObjCommand (interp, "tdom::schema::text::regexp", regexpTCObjCmd, NULL, NULL); Tcl_CreateObjCommand (interp, "tdom::schema::text::nmtoken", nmtokenTCObjCmd, NULL, NULL); Tcl_CreateObjCommand (interp, "tdom::schema::text::nmtokens", nmtokensTCObjCmd, NULL, NULL); Tcl_CreateObjCommand (interp,"tdom::schema::text::number", numberTCObjCmd, NULL, NULL); Tcl_CreateObjCommand (interp,"tdom::schema::text::boolean", booleanTCObjCmd, NULL, NULL); Tcl_CreateObjCommand (interp,"tdom::schema::text::date", dateTCObjCmd, NULL, NULL); Tcl_CreateObjCommand (interp,"tdom::schema::text::dateTime", dateTimeTCObjCmd, NULL, NULL); Tcl_CreateObjCommand (interp,"tdom::schema::text::time", timeTCObjCmd, NULL, NULL); Tcl_CreateObjCommand (interp,"tdom::schema::text::duration", durationTCObjCmd, NULL, NULL); Tcl_CreateObjCommand (interp,"tdom::schema::text::maxLength", maxLengthTCObjCmd, NULL, NULL); Tcl_CreateObjCommand (interp,"tdom::schema::text::minLength", minLengthTCObjCmd, NULL, NULL); Tcl_CreateObjCommand (interp,"tdom::schema::text::oneOf", oneOfTCObjCmd, NULL, NULL); Tcl_CreateObjCommand (interp,"tdom::schema::text::allOf", allOfTCObjCmd, NULL, NULL); Tcl_CreateObjCommand (interp,"tdom::schema::text::strip", stripTCObjCmd, NULL, NULL); Tcl_CreateObjCommand (interp,"tdom::schema::text::split", splitTCObjCmd, NULL, NULL); Tcl_CreateObjCommand (interp,"tdom::schema::text::id", idTCObjCmd, NULL, NULL); Tcl_CreateObjCommand (interp,"tdom::schema::text::idref", idrefTCObjCmd, NULL, NULL); Tcl_CreateObjCommand (interp,"tdom::schema::text::base64", base64TCObjCmd, NULL, NULL); Tcl_CreateObjCommand (interp,"tdom::schema::text::key", keyTCObjCmd, NULL, NULL); Tcl_CreateObjCommand (interp,"tdom::schema::text::keyref", keyrefTCObjCmd, NULL, NULL); Tcl_CreateObjCommand (interp,"tdom::schema::text::name", nameTCObjCmd, NULL, NULL); Tcl_CreateObjCommand (interp,"tdom::schema::text::ncname", ncnameTCObjCmd, NULL, NULL); Tcl_CreateObjCommand (interp,"tdom::schema::text::qname", qnameTCObjCmd, NULL, NULL); Tcl_CreateObjCommand (interp,"tdom::schema::text::hexBinary", hexBinaryTCObjCmd, NULL, NULL); Tcl_CreateObjCommand (interp,"tdom::schema::text::unsignedByte", unsignedIntTypesTCObjCmd, (ClientData) 0, NULL); Tcl_CreateObjCommand (interp,"tdom::schema::text::unsignedShort", unsignedIntTypesTCObjCmd, (ClientData) 1, NULL); Tcl_CreateObjCommand (interp,"tdom::schema::text::unsignedInt", unsignedIntTypesTCObjCmd, (ClientData) 2, NULL); Tcl_CreateObjCommand (interp,"tdom::schema::text::unsignedLong", unsignedIntTypesTCObjCmd, (ClientData) 3, NULL); Tcl_CreateObjCommand (interp,"tdom::schema::text::byte", intTypesTCObjCmd, (ClientData) 0, NULL); Tcl_CreateObjCommand (interp,"tdom::schema::text::short", intTypesTCObjCmd, (ClientData) 1, NULL); Tcl_CreateObjCommand (interp,"tdom::schema::text::int", intTypesTCObjCmd, (ClientData) 2, NULL); Tcl_CreateObjCommand (interp,"tdom::schema::text::long", intTypesTCObjCmd, (ClientData) 3, NULL); Tcl_CreateObjCommand (interp,"tdom::schema::text::setvar", setvarTCObjCmd, (ClientData) 3, NULL); Tcl_CreateObjCommand (interp,"tdom::schema::text::whitespace", whitespaceTCObjCmd, (ClientData) 3, NULL); Tcl_CreateObjCommand (interp,"tdom::schema::text::not", notTCObjCmd, (ClientData) 3, NULL); Tcl_CreateObjCommand (interp,"tdom::schema::text::length", lengthTCObjCmd, (ClientData) 3, NULL); Tcl_CreateObjCommand (interp,"tdom::schema::text::type", typeTCObjCmd, NULL, NULL); Tcl_CreateObjCommand (interp,"tdom::schema::text::jsontype", jsontypeTCObjCmd, NULL, NULL); /* Exposed text type commands */ Tcl_CreateObjCommand (interp,"tdom::type::date", dateObjCmd, NULL, NULL); Tcl_CreateObjCommand (interp,"tdom::type::dateTime", dateTimeObjCmd, NULL, NULL); Tcl_CreateObjCommand (interp,"tdom::type::time", timeObjCmd, NULL, NULL); Tcl_CreateObjCommand (interp,"tdom::type::duration", durationObjCmd, NULL, NULL); } #endif tdom-0.9.6-src/generic/domhtml.h0000644000175000017500000000032115025767703015205 0ustar rolfrolf domDocument * HTML_SimpleParseDocument ( char *html, int ignoreWhiteSpaces, int forrest, domLength *pos, char **errStr ); tdom-0.9.6-src/generic/dom.h0000644000175000017500000010741715025767703014336 0ustar rolfrolf/*--------------------------------------------------------------------------- | Copyright (C) 1999 Jochen C. Loewer (loewerj@hotmail.com) +---------------------------------------------------------------------------- | | A DOM interface upon the expat XML parser for the C language | according to the W3C recommendation REC-DOM-Level-1-19981001 | | | The contents of this file are subject to the Mozilla Public License | Version 2.0 (the "License"); you may not use this file except in | compliance with the License. You may obtain a copy of the License at | http://www.mozilla.org/MPL/ | | Software distributed under the License is distributed on an "AS IS" | basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the | License for the specific language governing rights and limitations | under the License. | | The Original Code is tDOM. | | The Initial Developer of the Original Code is Jochen Loewer | Portions created by Jochen Loewer are Copyright (C) 1998, 1999 | Jochen Loewer. All Rights Reserved. | | Contributor(s): | | | written by Jochen Loewer | April 5, 1999 | \--------------------------------------------------------------------------*/ #ifndef __DOM_H__ #define __DOM_H__ #include #include #include #include #include #include #include #include /* * tDOM provides it's own memory allocator which is optimized for * low heap usage. It uses the native Tcl allocator underneath, * though, but it is not very MT-friendly. Therefore, you might * use the (normal) Tcl allocator with USE_NORMAL_ALLOCATOR * defined during compile time. Actually, the symbols name is * a misnomer. It should have benn called "USE_TCL_ALLOCATOR" * but I did not want to break any backward compatibility. */ #ifndef USE_NORMAL_ALLOCATOR # define MALLOC malloc # define FREE free # define REALLOC realloc # define tdomstrdup strdup #else # define domAllocInit() # define domAlloc MALLOC # define domFree FREE # if defined(TCL_MEM_DEBUG) || defined(NS_AOLSERVER) # define MALLOC Tcl_Alloc # define FREE(a) Tcl_Free((char*)(a)) # define REALLOC Tcl_Realloc # define tdomstrdup(s) (char*)strcpy(MALLOC(strlen((s))+1),(char*)s) # else # define MALLOC malloc # define FREE free # define REALLOC realloc # define tdomstrdup strdup # endif /* TCL_MEM_DEBUG */ #endif /* USE_NORMAL_ALLOCATOR */ #define TMALLOC(t) (t*)MALLOC(sizeof(t)) #if defined(TCL_MEM_DEBUG) || defined(NS_AOLSERVER) static void* my_malloc(size_t size){return Tcl_Alloc(size);} static void my_free(void *ptr){Tcl_Free((char*)ptr);} static void* my_realloc(void *ptr,size_t size){return Tcl_Realloc(ptr,size);} static XML_Memory_Handling_Suite memsuite = { my_malloc, my_realloc, my_free }; # define MEM_SUITE &memsuite #else # define MEM_SUITE NULL #endif /* * Beginning with 8.6, interp->errorLine isn't public visible anymore * (TIP 330) */ #if (TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION < 6) # define Tcl_GetErrorLine(interp) (interp)->errorLine #endif /* Beginning with Tcl 9.0 the string representation of a Tcl_Obj may * be bigger thant 2 GByte. Therefore some API functions differ. */ #if TCL_MAJOR_VERSION > 8 # ifdef _WIN32 # define TCL_THREADS 1 # endif # define domLength Tcl_Size # define Tcl_SetDomLengthObj Tcl_SetWideIntObj # define domLengthConversion "%" TCL_SIZE_MODIFIER "d" #else # define domLength int # define Tcl_SetDomLengthObj Tcl_SetIntObj # define domLengthConversion "%d" # define TCL_SIZE_MODIFIER "" # define Tcl_GetSizeIntFromObj Tcl_GetIntFromObj #endif #ifndef TDOM_LS_MODIFIER # ifdef XML_LARGE_SIZE # ifdef _WIN32 # define TDOM_LS_MODIFIER "I64" # else # define TDOM_LS_MODIFIER "ll" # endif # else # define TDOM_LS_MODIFIER "l" # endif #endif #ifndef TDOM_INLINE #ifdef _MSC_VER # define TDOM_INLINE __inline #else # define TDOM_INLINE inline #endif #endif /* Since the len argument of XML_Parse() is of type int, parsing of * strings has to be done in chunks anyway for Tcl 9 with its strings * potentially longer than 2 GByte. Because of internal changes in * exapt a chunk size of INT_MAX led to out of memory errors. * (TDOM_PCS = TDOM_PARSE_CHUNK_SIZE) */ #ifndef TDOM_PCS # define TDOM_PCS INT_MAX / 2 #endif /* The following is the machinery to have an UNUSED macro which * signals that a function parameter is known to be not used. This * works for some open source compiler. */ /* * Define __GNUC_PREREQ for determine available features of gcc and clang */ #undef __GNUC_PREREQ #if defined __GNUC__ && defined __GNUC_MINOR__ # define __GNUC_PREREQ(maj, min) \ ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) #else # define __GNUC_PREREQ(maj, min) (0) #endif /* * UNUSED uses the gcc __attribute__ unused and mangles the name, so the * attribute could not be used, if declared as unused. */ #ifdef UNUSED #elif __GNUC_PREREQ(2, 7) # define UNUSED(x) UNUSED_ ## x __attribute__((unused)) #elif defined(__LCLINT__) # define UNUSED(x) /*@unused@*/ (x) #else # define UNUSED(x) (x) #endif /* UNUSED stuff end */ #define domPanic(msg) Tcl_Panic((msg)); /* * If compiled against threaded Tcl core, we must take * some extra care about process-wide globals and the * way we name Tcl object accessor commands. */ #ifndef TCL_THREADS extern unsigned long domUniqueNodeNr; extern unsigned long domUniqueDocNr; extern Tcl_HashTable tdom_tagNames; extern Tcl_HashTable tdom_attrNames; # define TDomNotThreaded(x) x # define TDomThreaded(x) # define HASHTAB(doc,tab) tab # define NODE_NO(doc) ++domUniqueNodeNr # define DOC_NO(doc) ++domUniqueDocNr #else # define TDomNotThreaded(x) # define TDomThreaded(x) x # define HASHTAB(doc,tab) (doc)->tab # define NODE_NO(doc) ((doc)->nodeCounter)++ # define DOC_NO(doc) (uintptr_t)(doc) #endif /* TCL_THREADS */ #define DOC_CMD(s,doc) sprintf((s), "domDoc%p", (void *)(doc)) #define NODE_CMD(s,node) sprintf((s), "domNode%p", (void *)(node)) #define XSLT_CMD(s,doc) sprintf((s), "XSLTcmd%p", (void *)(doc)) #define XML_NAMESPACE "http://www.w3.org/XML/1998/namespace" #define XMLNS_NAMESPACE "http://www.w3.org/2000/xmlns" #define UTF8_1BYTE_CHAR(c) ( 0 == ((c) & 0x80)) #define UTF8_2BYTE_CHAR(c) ( 0xC0 == ((c) & 0xE0)) #define UTF8_3BYTE_CHAR(c) ( 0xE0 == ((c) & 0xF0)) #define UTF8_4BYTE_CHAR(c) ( 0xF0 == ((c) & 0xF8)) #define UTF8_CHAR_LEN(c) \ UTF8_1BYTE_CHAR((c)) ? 1 : \ (UTF8_2BYTE_CHAR((c)) ? 2 : \ (UTF8_3BYTE_CHAR((c)) ? 3 : \ (UTF8_4BYTE_CHAR((c)) ? 4 : 0))) /* The following 2 defines are out of the expat code */ /* A 2 byte UTF-8 representation splits the characters 11 bits between the bottom 5 and 6 bits of the bytes. We need 8 bits to index into pages, 3 bits to add to that index and 5 bits to generate the mask. */ #define UTF8_GET_NAMING2(pages, byte) \ (namingBitmap[((pages)[(((byte)[0]) >> 2) & 7] << 3) \ + ((((byte)[0]) & 3) << 1) \ + ((((byte)[1]) >> 5) & 1)] \ & (1u << (((byte)[1]) & 0x1F))) /* A 3 byte UTF-8 representation splits the characters 16 bits between the bottom 4, 6 and 6 bits of the bytes. We need 8 bits to index into pages, 3 bits to add to that index and 5 bits to generate the mask. */ #define UTF8_GET_NAMING3(pages, byte) \ (namingBitmap[((pages)[((((byte)[0]) & 0xF) << 4) \ + ((((byte)[1]) >> 2) & 0xF)] \ << 3) \ + ((((byte)[1]) & 3) << 1) \ + ((((byte)[2]) >> 5) & 1)] \ & (1u << (((byte)[2]) & 0x1F))) #define UTF8_GET_NAMING_NMTOKEN(p, n) \ ((n) == 1 \ ? nameChar7Bit[(int)(*(p))] \ : ((n) == 2 \ ? UTF8_GET_NAMING2(namePages, (const unsigned char *)(p)) \ : ((n) == 3 \ ? UTF8_GET_NAMING3(namePages, (const unsigned char *)(p)) \ : 0))) #define UTF8_GET_NAMING_NCNMTOKEN(p, n) \ ((n) == 1 \ ? NCnameChar7Bit[(int)(*(p))] \ : ((n) == 2 \ ? UTF8_GET_NAMING2(namePages, (const unsigned char *)(p)) \ : ((n) == 3 \ ? UTF8_GET_NAMING3(namePages, (const unsigned char *)(p)) \ : 0))) #define UTF8_GET_NAME_START(p, n) \ ((n) == 1 \ ? nameStart7Bit[(int)(*(p))] \ : ((n) == 2 \ ? UTF8_GET_NAMING2(nmstrtPages, (const unsigned char *)(p)) \ : ((n) == 3 \ ? UTF8_GET_NAMING3(nmstrtPages, (const unsigned char *)(p)) \ : 0))) #define UTF8_GET_NCNAME_START(p, n) \ ((n) == 1 \ ? NCnameStart7Bit[(int)(*(p))] \ : ((n) == 2 \ ? UTF8_GET_NAMING2(nmstrtPages, (const unsigned char *)(p)) \ : ((n) == 3 \ ? UTF8_GET_NAMING3(nmstrtPages, (const unsigned char *)(p)) \ : 0))) #define UTF8_XMLCHAR3(p) \ (*(p) == 0xED \ ? ((p)[1] < 0xA0 ? 1 : 0) \ : (*(p) == 0xEF \ ? ((p)[1] == 0xBF \ ? ((p)[2] == 0xBE || (p)[2] == 0xBF ? 0 : 1) \ : 1) \ : 1)) \ /* This definition is lax in the sense, that it accepts every 4 byte * utf-8 character beyond #xFFFF as valid, no matter, if Unicode has * (so far) defined a character for that encoding point. Additionally, * this define does not care about the discouraged characters beyond * #xFFFF (but after all, they are only discouraged, not * forbidden). */ #define UTF8_XMLCHAR(p, n) \ ((n) == 1 \ ? CharBit[(int)(*(p))] \ : ((n) == 2 \ ? 1 \ : ((n) == 3 \ ? (UTF8_XMLCHAR3(p)) \ : ((n) == 4 \ ? 1 : 0)))) #include "../expat/nametab.h" static const unsigned char nameChar7Bit[] = { /* 0x00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, /* 0x30 */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* 0x38 */ 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40 */ 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* 0x48 */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* 0x50 */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* 0x58 */ 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, /* 0x60 */ 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* 0x68 */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* 0x70 */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* 0x78 */ 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, }; static const unsigned char NCnameChar7Bit[] = { /* 0x00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, /* 0x30 */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* 0x38 */ 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40 */ 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* 0x48 */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* 0x50 */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* 0x58 */ 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, /* 0x60 */ 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* 0x68 */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* 0x70 */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* 0x78 */ 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, }; static const unsigned char nameStart7Bit[] = { /* 0x00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38 */ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40 */ 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* 0x48 */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* 0x50 */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* 0x58 */ 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, /* 0x60 */ 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* 0x68 */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* 0x70 */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* 0x78 */ 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, }; static const unsigned char NCnameStart7Bit[] = { /* 0x00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40 */ 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* 0x48 */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* 0x50 */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* 0x58 */ 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, /* 0x60 */ 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* 0x68 */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* 0x70 */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* 0x78 */ 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, }; static const unsigned char CharBit[] = { /* 0x00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08 */ 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, /* 0x10 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20 */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* 0x28 */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* 0x30 */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* 0x38 */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* 0x40 */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* 0x48 */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* 0x50 */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* 0x58 */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* 0x60 */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* 0x68 */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* 0x70 */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* 0x78 */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, }; #define isNameStart(x) UTF8_GET_NAME_START((x),UTF8_CHAR_LEN(*(x))) #define isNCNameStart(x) UTF8_GET_NCNAME_START((x),UTF8_CHAR_LEN(*(x))) #define isNameChar(x) UTF8_GET_NAMING_NMTOKEN((x),UTF8_CHAR_LEN(*(x))) #define isNCNameChar(x) UTF8_GET_NAMING_NCNMTOKEN((x),UTF8_CHAR_LEN(*(x))) #define IS_XML_WHITESPACE(c) ((c)==' ' || (c)=='\n' || (c)=='\r' || (c)=='\t') #define SPACE(c) IS_XML_WHITESPACE ((c)) /*-------------------------------------------------------------------------- | DOMString | \-------------------------------------------------------------------------*/ typedef char* domString; /*-------------------------------------------------------------------------- | domNodeType | \-------------------------------------------------------------------------*/ #if defined(_AIX) # define ELEMENT_NODE 1 # define ATTRIBUTE_NODE 2 # define TEXT_NODE 3 # define CDATA_SECTION_NODE 4 # define ENTITY_REFERENCE_NODE 5 # define ENTITY_NODE 6 # define PROCESSING_INSTRUCTION_NODE 7 # define COMMENT_NODE 8 # define DOCUMENT_NODE 9 # define DOCUMENT_TYPE_NODE 10 # define DOCUMENT_FRAGMENT_NODE 11 # define NOTATION_NODE 12 # define ALL_NODES 100 # define domNodeType int #else typedef enum { ELEMENT_NODE = 1, ATTRIBUTE_NODE = 2, TEXT_NODE = 3, CDATA_SECTION_NODE = 4, ENTITY_REFERENCE_NODE = 5, ENTITY_NODE = 6, PROCESSING_INSTRUCTION_NODE = 7, COMMENT_NODE = 8, DOCUMENT_NODE = 9, DOCUMENT_TYPE_NODE = 10, DOCUMENT_FRAGMENT_NODE = 11, NOTATION_NODE = 12, ALL_NODES = 100 } domNodeType; #endif /* The following defines used for NodeObjCmd */ #define PARSER_NODE 9999 /* Hack so that we can invoke XML parser */ /* More hacked domNodeTypes - used to signal, that we want to check name/data of the node to create. */ #define ELEMENT_NODE_ANAME_CHK 10000 #define ELEMENT_NODE_AVALUE_CHK 10001 #define ELEMENT_NODE_CHK 10002 #define TEXT_NODE_CHK 10003 #define COMMENT_NODE_CHK 10004 #define CDATA_SECTION_NODE_CHK 10005 #define PROCESSING_INSTRUCTION_NODE_NAME_CHK 10006 #define PROCESSING_INSTRUCTION_NODE_VALUE_CHK 10007 #define PROCESSING_INSTRUCTION_NODE_CHK 10008 /*-------------------------------------------------------------------------- | flags - indicating some internal features about nodes | \-------------------------------------------------------------------------*/ typedef unsigned int domNodeFlags; #define HAS_LINE_COLUMN 1 #define VISIBLE_IN_TCL 2 #define IS_DELETED 4 #define HAS_BASEURI 8 #define DISABLE_OUTPUT_ESCAPING 16 typedef unsigned int domAttrFlags; #define IS_ID_ATTRIBUTE 1 #define IS_NS_NODE 2 typedef unsigned int domDocFlags; #define OUTPUT_DEFAULT_INDENT 1 #define NEEDS_RENUMBERING 2 #define DONT_FREE 4 #define IGNORE_XMLNS 8 #define DOCUMENT_CMD 16 #define VAR_TRACE 32 #define INSIDE_FROM_SCRIPT 64 #define DELETE_AFTER_FROM_SCRIPT 128 /*-------------------------------------------------------------------------- | an index to the namespace records | \-------------------------------------------------------------------------*/ typedef unsigned int domNameSpaceIndex; /*-------------------------------------------------------------------------- | domException | \-------------------------------------------------------------------------*/ typedef enum { OK = 0, INDEX_SIZE_ERR = 1, DOMSTRING_SIZE_ERR = 2, HIERARCHY_REQUEST_ERR = 3, WRONG_DOCUMENT_ERR = 4, INVALID_CHARACTER_ERR = 5, NO_DATA_ALLOWED_ERR = 6, NO_MODIFICATION_ALLOWED_ERR = 7, NOT_FOUND_ERR = 8, NOT_SUPPORTED_ERR = 9, INUSE_ATTRIBUTE_ERR = 10 } domException; /*-------------------------------------------------------------------------- | domDocInfo | \-------------------------------------------------------------------------*/ typedef struct domDocInfo { /* 'name' is always the name of the documentElement, no struct element needed for this */ domString publicId; domString systemId; domString internalSubset; /* Currently missing, according to DOM 2: 'entities' and 'notations'. */ /* The following struct elements describes additional 'requested' facets of the document, following the xslt rec, section 16 */ float version; char *encoding; int omitXMLDeclaration; int standalone; Tcl_HashTable *cdataSectionElements; domString method; domString mediaType; } domDocInfo; /*-------------------------------------------------------------------------- | domDocument | \-------------------------------------------------------------------------*/ typedef struct domDocument { domNodeType nodeType : 8; domDocFlags nodeFlags : 8; domNameSpaceIndex dummy : 16; uintptr_t documentNumber; struct domNode *documentElement; struct domNode *fragments; #ifdef TCL_THREADS struct domNode *deletedNodes; #endif struct domNS **namespaces; int nsptr; int nslen; char **prefixNSMappings; /* Stores doc global prefix ns mappings for resolving of prefixes in seletNodes expr */ #ifdef TCL_THREADS unsigned int nodeCounter; #endif struct domNode *rootNode; Tcl_HashTable *ids; Tcl_HashTable *unparsedEntities; Tcl_HashTable *baseURIs; Tcl_HashTable *xpathCache; char *extResolver; domDocInfo *doctype; TDomThreaded ( Tcl_HashTable tdom_tagNames; /* Names of tags found in doc */ Tcl_HashTable tdom_attrNames; /* Names of tag attributes */ unsigned int refCount; /* # of object commands attached */ struct _domlock *lock; /* Lock for this document */ ) } domDocument; /*-------------------------------------------------------------------------- | domLock | \-------------------------------------------------------------------------*/ #ifdef TCL_THREADS typedef struct _domlock { domDocument* doc; /* The DOM document to be locked */ int numrd; /* # of readers waiting for lock */ int numwr; /* # of writers waiting for lock */ int lrcnt; /* Lock ref count, > 0: # of shared * readers, -1: exclusive writer */ Tcl_Mutex mutex; /* Mutex for serializing access */ Tcl_Condition rcond; /* Condition var for reader locks */ Tcl_Condition wcond; /* Condition var for writer locks */ struct _domlock *next; /* Next doc lock in global list */ } domlock; #define LOCK_READ 0 #define LOCK_WRITE 1 #endif /*-------------------------------------------------------------------------- | namespace | \-------------------------------------------------------------------------*/ typedef struct domNS { char *uri; char *prefix; int index; } domNS; #ifndef MAX_PREFIX_LEN # define MAX_PREFIX_LEN 80 #endif /*--------------------------------------------------------------------------- | type domActiveNS | \--------------------------------------------------------------------------*/ typedef struct _domActiveNS { int depth; domNS *namespace; } domActiveNS; /*-------------------------------------------------------------------------- | domLineColumn | \-------------------------------------------------------------------------*/ typedef struct domLineColumn { XML_Size line; XML_Size column; XML_Index byteIndex; } domLineColumn; typedef struct { int errorCode; XML_Size errorLine; XML_Size errorColumn; XML_Index byteIndex; } domParseForestErrorData; /*-------------------------------------------------------------------------- | domNode | \-------------------------------------------------------------------------*/ typedef struct domNode { domNodeType nodeType : 8; domNodeFlags nodeFlags : 8; #ifdef TDOM_LESS_NS domNameSpaceIndex namespace : 8; unsigned int info : 8; #else unsigned int dummy : 8; unsigned int info : 8; #endif unsigned int nodeNumber; domDocument *ownerDocument; struct domNode *parentNode; struct domNode *previousSibling; struct domNode *nextSibling; domString nodeName; /* now the element node specific fields */ #ifndef TDOM_LESS_NS domNameSpaceIndex namespace; #endif struct domNode *firstChild; struct domNode *lastChild; struct domAttrNode *firstAttr; } domNode; /*-------------------------------------------------------------------------- | domDeleteInfo | \-------------------------------------------------------------------------*/ typedef struct domDeleteInfo { domDocument * document; domNode * node; Tcl_Interp * interp; char * traceVarName; } domDeleteInfo; /*-------------------------------------------------------------------------- | domTextNode | \-------------------------------------------------------------------------*/ typedef struct domTextNode { domNodeType nodeType : 8; domNodeFlags nodeFlags : 8; #ifdef TDOM_LESS_NS domNameSpaceIndex namespace : 8; unsigned int info : 8; #else unsigned int dummy : 8; unsigned int info : 8; #endif unsigned int nodeNumber; domDocument *ownerDocument; struct domNode *parentNode; struct domNode *previousSibling; struct domNode *nextSibling; domString nodeValue; /* now the text node specific fields */ domLength valueLength; } domTextNode; /*-------------------------------------------------------------------------- | domProcessingInstructionNode | \-------------------------------------------------------------------------*/ typedef struct domProcessingInstructionNode { domNodeType nodeType : 8; domNodeFlags nodeFlags : 8; #ifdef TDOM_LESS_NS domNameSpaceIndex namespace : 8; unsigned int info : 8; #else unsigned int dummy : 8; unsigned int info : 8; #endif unsigned int nodeNumber; domDocument *ownerDocument; struct domNode *parentNode; struct domNode *previousSibling; struct domNode *nextSibling; domString targetValue; /* now the pi specific fields */ domLength targetLength; #ifndef TDOM_LESS_NS domNameSpaceIndex namespace; #endif domString dataValue; domLength dataLength; } domProcessingInstructionNode; /*-------------------------------------------------------------------------- | domAttrNode | \-------------------------------------------------------------------------*/ typedef struct domAttrNode { domNodeType nodeType : 8; domAttrFlags nodeFlags : 8; #ifdef TDOM_LESS_NS domNameSpaceIndex namespace : 8; unsigned int info : 8; #else unsigned int dummy : 8; unsigned int info : 8; domNameSpaceIndex namespace; #endif domString nodeName; domString nodeValue; domLength valueLength; struct domNode *parentNode; struct domAttrNode *nextSibling; } domAttrNode; /*-------------------------------------------------------------------------- | domAddCallback | \-------------------------------------------------------------------------*/ typedef int (*domAddCallback) (domNode * node, void * clientData); typedef void (*domFreeCallback) (domNode * node, void * clientData); #include /*-------------------------------------------------------------------------- | Function prototypes | \-------------------------------------------------------------------------*/ const char * domException2String (domException exception); void domModuleInitialize (void); domDocument * domCreateDoc (const char *baseURI, int storeLineColumn); domDocument * domCreateDocument (const char *uri, char *documentElementTagName); void domSetDocumentElement (domDocument *doc); domDocument * domReadDocument (XML_Parser parser, char *xml, domLength length, int ignoreWhiteSpaces, int keepCDATA, int storeLineColumn, int ignoreXMLNS, int feedbackAfter, Tcl_Obj *feedbackCmd, Tcl_Channel channel, const char *baseurl, Tcl_Obj *extResolver, int useForeignDTD, int forest, int paramEntityParsing, #ifndef TDOM_NO_SCHEMA SchemaData *sdata, #endif Tcl_Interp *interp, domParseForestErrorData *forestError, int *status); void domFreeDocument (domDocument *doc, domFreeCallback freeCB, void * clientData); void domFreeNode (domNode *node, domFreeCallback freeCB, void *clientData, int dontfree); domTextNode * domNewTextNode (domDocument *doc, const char *value, domLength length, domNodeType nodeType); domNode * domNewElementNode (domDocument *doc, const char *tagName); domNode * domNewElementNodeNS (domDocument *doc, const char *tagName, const char *uri); domProcessingInstructionNode * domNewProcessingInstructionNode ( domDocument *doc, const char *targetValue, domLength targetLength, const char *dataValue, domLength dataLength); domAttrNode * domSetAttribute (domNode *node, const char *attributeName, const char *attributeValue); domAttrNode * domSetAttributeNS (domNode *node, const char *attributeName, const char *attributeValue, const char *uri, int createNSIfNeeded); domAttrNode * domGetAttributeNodeNS (domNode *node, const char *uri, const char *localname); int domRemoveAttribute (domNode *node, const char *attributeName); int domRemoveAttributeNS (domNode *node, const char *uri, const char *localName); domNode * domPreviousSibling (domNode *attr); domException domDeleteNode (domNode *node, domFreeCallback freeCB, void *clientData); domException domRemoveChild (domNode *node, domNode *childToRemove); domException domAppendChild (domNode *node, domNode *childToAppend); domException domInsertBefore (domNode *node, domNode *childToInsert, domNode *refChild); domException domReplaceChild (domNode *node, domNode *newChild, domNode *oldChild); domException domSetNodeValue (domNode *node, const char *nodeValue, domLength valueLen); domNode * domCloneNode (domNode *node, int deep); domTextNode * domAppendNewTextNode (domNode *parent, char *value, domLength length, domNodeType nodeType, int disableOutputEscaping); domNode * domAppendNewElementNode (domNode *parent, const char *tagName, const char *uri); domNode * domAppendLiteralNode (domNode *parent, domNode *node); domNS * domAddNSToNode (domNode *node, domNS *nsToAdd); const char * domNamespacePrefix (domNode *node); const char * domNamespaceURI (domNode *node); const char * domGetLocalName (const char *nodeName); int domSplitQName (const char *name, char *prefix, const char **localName); domNS * domLookupNamespace (domDocument *doc, const char *prefix, const char *namespaceURI); domNS * domLookupPrefix (domNode *node, const char *prefix); int domIsNamespaceInScope (domActiveNS *NSstack, int NSstackPos, const char *prefix, const char *namespaceURI); const char * domLookupPrefixWithMappings (domNode *node, const char *prefix, char **prefixMappings); domNS * domLookupURI (domNode *node, char *uri); domNS * domGetNamespaceByIndex (domDocument *doc, unsigned int nsIndex); domNS * domNewNamespace (domDocument *doc, const char *prefix, const char *namespaceURI); int domGetLineColumn (domNode *node, XML_Size *line, XML_Size *column, XML_Index *byteIndex); int domXPointerChild (domNode * node, int all, int instance, domNodeType type, char *element, char *attrName, char *attrValue, domLength attrLen, domAddCallback addCallback, void * clientData); int domXPointerDescendant (domNode * node, int all, int instance, int * i, domNodeType type, char *element, char *attrName, char *attrValue, domLength attrLen, domAddCallback addCallback, void * clientData); int domXPointerAncestor (domNode * node, int all, int instance, int * i, domNodeType type, char *element, char *attrName, char *attrValue, domLength attrLen, domAddCallback addCallback, void * clientData); int domXPointerXSibling (domNode * node, int forward_mode, int all, int instance, domNodeType type, char *element, char *attrName, char *attrValue, domLength attrLen, domAddCallback addCallback, void * clientData); const char * findBaseURI (domNode *node); void tcldom_tolower (const char *str, char *str_out, int len); int domIsNAME (const char *name); int domIsPINAME (const char *name); int domIsQNAME (const char *name); int domIsNCNAME (const char *name); int domIsChar (const char *str); void domClearString (char *str, char *replacement, domLength repllen, Tcl_DString *clearedstr, int *changed); int domIsBMPChar (const char *str); int domIsComment (const char *str); int domIsCDATA (const char *str); int domIsPIValue (const char *str); int domIsHTML5CustomName (const char *str); void domCopyTo (domNode *node, domNode *parent, int copyNS); void domCopyNS (domNode *from, domNode *to); domAttrNode * domCreateXMLNamespaceNode (domNode *parent); void domRenumberTree (domNode *node); int domPrecedes (domNode *node, domNode *other); void domNormalize (domNode *node, int forXPath, domFreeCallback freeCB, void *clientData); domException domAppendData (domTextNode *node, char *value, domLength length, int disableOutputEscaping); #ifdef TCL_THREADS void domLocksLock(domlock *dl, int how); void domLocksUnlock(domlock *dl); void domLocksAttach(domDocument *doc); void domLocksDetach(domDocument *doc); void domLocksFinalize(ClientData dummy); #endif /*--------------------------------------------------------------------------- | coercion routines for calling from C++ | \--------------------------------------------------------------------------*/ domAttrNode * coerceToAttrNode( domNode *n ); domTextNode * coerceToTextNode( domNode *n ); domProcessingInstructionNode * coerceToProcessingInstructionNode( domNode *n ); #endif tdom-0.9.6-src/generic/nodecmd.c0000644000175000017500000007753315025767703015170 0ustar rolfrolf/*---------------------------------------------------------------------------- | Copyright (C) 1999 Jochen C. Loewer (loewerj@hotmail.com) +----------------------------------------------------------------------------- | | The contents of this file are subject to the Mozilla Public License | Version 2.0 (the "License"); you may not use this file except in | compliance with the License. You may obtain a copy of the License at | http://www.mozilla.org/MPL/ | | Software distributed under the License is distributed on an "AS IS" | basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the | License for the specific language governing rights and limitations | under the License. | | The Original Code is tDOM. | | The Initial Developer of the Original Code is Jochen Loewer. | | Portions created by Jochen Loewer are Copyright (C) 1998, 1999 | Jochen Loewer. All Rights Reserved. | | Portions created by Zoran Vasiljevic are Copyright (C) 2000-2002 | Zoran Vasiljevic. All Rights Reserved. | | Portions created by Rolf Ade are Copyright (C) 1999-2002 | Rolf Ade. All Rights Reserved. | | Written by Zoran Vasiljevic | July 12, 2000 | \---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------- | Includes | \---------------------------------------------------------------------------*/ #include #include #include #include #include /*---------------------------------------------------------------------------- | Types | | This structure represents one stack slot. The stack itself | is implemented as double-linked-list of following structures. | \---------------------------------------------------------------------------*/ typedef struct StackSlot { void *element; /* The stacked element */ struct StackSlot *nextPtr; /* Next link */ struct StackSlot *prevPtr; /* Previous link */ } StackSlot; /*---------------------------------------------------------------------------- | Beginning of the stack and current element pointer are local | to current thread and also local to this file. | For non-threaded environments, it's a regular static. | \---------------------------------------------------------------------------*/ typedef struct CurrentStack { StackSlot *elementStack; StackSlot *currentSlot; } CurrentStack; /*---------------------------------------------------------------------------- | Structure used as clientData of the created commands. | The structure stores, which type of node the command has | to create and, in case of elementNodes and if given, the | namespace of the node. \---------------------------------------------------------------------------*/ typedef struct NodeInfo { int type; char *namespace; int jsonType; char *tagName; int flags; } NodeInfo; /*---------------------------------------------------------------------------- | Forward declarations | \---------------------------------------------------------------------------*/ static void * StackPush (Tcl_Interp *, void *); static void * StackPop (Tcl_Interp *); static void * StackTop (Tcl_Interp *); static int NodeObjCmd (ClientData, Tcl_Interp *, int, Tcl_Obj *const o[]); static void StackFinalize (ClientData, Tcl_Interp *); extern int tcldom_appendXML (Tcl_Interp *, domNode *, Tcl_Obj *); /*---------------------------------------------------------------------------- | StackPush | \---------------------------------------------------------------------------*/ static void * StackPush ( Tcl_Interp *interp, void *element ) { StackSlot *newElement; CurrentStack *csPtr = (CurrentStack *) Tcl_GetAssocData(interp, "tdom_stk", NULL); /* nodecmd_init() initialize "tdom_stk", so csPtr never will be NULL. */ /*------------------------------------------------------------------- | Reuse already allocated stack slots, if any | \------------------------------------------------------------------*/ if (csPtr->currentSlot && csPtr->currentSlot->nextPtr) { csPtr->currentSlot = csPtr->currentSlot->nextPtr; csPtr->currentSlot->element = element; return element; } /*------------------------------------------------------------------- | Allocate new stack slot | \------------------------------------------------------------------*/ newElement = (StackSlot *) MALLOC(sizeof(StackSlot)); memset(newElement, 0, sizeof(StackSlot)); if (csPtr->elementStack == NULL) { csPtr->elementStack = newElement; } else { csPtr->currentSlot->nextPtr = newElement; newElement->prevPtr = csPtr->currentSlot; } csPtr->currentSlot = newElement; csPtr->currentSlot->element = element; return element; } /*---------------------------------------------------------------------------- | StackPop - pops the element from stack | \---------------------------------------------------------------------------*/ static void * StackPop (Tcl_Interp *interp) { void *element; CurrentStack *csPtr = (CurrentStack *) Tcl_GetAssocData(interp, "tdom_stk", NULL); element = csPtr->currentSlot->element; if (csPtr->currentSlot->prevPtr) { csPtr->currentSlot = csPtr->currentSlot->prevPtr; } else { csPtr->currentSlot->element = NULL; } return element; } /*---------------------------------------------------------------------------- | StackTop - returns top-level element from stack | \---------------------------------------------------------------------------*/ static void * StackTop (Tcl_Interp *interp) { CurrentStack *csPtr = (CurrentStack *) Tcl_GetAssocData(interp, "tdom_stk", NULL); if (csPtr->currentSlot == NULL) { return NULL; } return csPtr->currentSlot->element; } /*---------------------------------------------------------------------------- | StackFinalize - reclaims stack memory (slots only, not elements) | \---------------------------------------------------------------------------*/ static void StackFinalize ( ClientData clientData, Tcl_Interp *UNUSED(interp) ) { CurrentStack *csPtr = (CurrentStack *) clientData; StackSlot *tmp, *stack = csPtr->elementStack; while (stack) { tmp = stack->nextPtr; FREE((char *) stack); stack = tmp; } FREE((char *) csPtr); } /* *---------------------------------------------------------------------- * * namespaceTail -- * * Returns the trailing name at the end of a string with "::" * namespace qualifiers. These qualifiers are namespace names * separated by "::"s. For example, for "::foo::p" this function * returns a pointer to the "p" in that obj string rep, and for * "::" it returns a pointer to "". * * Results: * Returns a pointer to the start of the tail name. * * Side effects: * None. * *---------------------------------------------------------------------- */ static char* namespaceTail ( Tcl_Obj *nameObj ) { char *name,*p; domLength len; name = Tcl_GetStringFromObj(nameObj, &len); p = name + len; /* Isolate just the tail name, i.e. skip it's parent namespace */ while (--p > name) { if ((*p == ':') && (*(p-1) == ':')) { p++; /* just after the last "::" */ name = p; break; } } return name; } /*---------------------------------------------------------------------------- | NodeObjCmdDeleteProc | \---------------------------------------------------------------------------*/ static void NodeObjCmdDeleteProc ( ClientData clientData ) { NodeInfo *nodeInfo = (NodeInfo *) clientData; if (nodeInfo->namespace) { FREE (nodeInfo->namespace); } if (nodeInfo->tagName) { FREE (nodeInfo->tagName); } FREE (nodeInfo); } /*---------------------------------------------------------------------------- | nodecmd_processAttributes | \---------------------------------------------------------------------------*/ int nodecmd_processAttributes ( Tcl_Interp *interp, domNode *node, int type, int objc, Tcl_Obj *const objv[], Tcl_Obj **cmdObj, int flags ) { Tcl_Obj **opts; domLength i, len; char *tval, *aval, *p; const char *uri; char **mappings; int maybefq, fq; /* * Allow for following syntax: * cmd ?-option value ...? ?script? * cmd ?opton value ...? ?script? * cmd key_value_list script * where list contains "-key value ..." or "key value ..." */ if (flags & FS_ATT_NO_NAMESPACED) { maybefq = 0; } else { maybefq = 1; } mappings = node->ownerDocument->prefixNSMappings; if ((objc % 2) == 0) { *cmdObj = objv[objc-1]; len = objc - 2; /* skip both command and script */ opts = (Tcl_Obj**)objv + 1; } else if((objc == 3) && Tcl_ListObjGetElements(interp,objv[1],&len,&opts)==TCL_OK && (len == 0 || len > 1)) { if ((len % 2)) { Tcl_AppendResult(interp, "list must have " "an even number of elements", NULL); return TCL_ERROR; } *cmdObj = objv[2]; } else { cmdObj = NULL; len = objc - 1; /* skip command */ opts = (Tcl_Obj**)objv + 1; } for (i = 0; i < len; i += 2) { tval = Tcl_GetString(opts[i]); if (*tval == '-') { tval++; } uri = NULL; fq = 0; if (maybefq) { p = tval; while (*p) { if (*p == ':') { fq = 1; break; } p++; } } if (abs(type) == ELEMENT_NODE_ANAME_CHK || abs(type) == ELEMENT_NODE_CHK) { if (!tcldom_nameCheck (interp, tval, "attribute", fq)) { return TCL_ERROR; } } if (fq) { *p = '\0'; uri = domLookupPrefixWithMappings (node, tval, mappings); if (!uri) { Tcl_ResetResult (interp); Tcl_AppendResult (interp, "Attribute prefix '", tval, "' does not resolve", NULL); *p = ':'; return TCL_ERROR; } *p = ':'; } aval = Tcl_GetString(opts[i+1]); if (abs(type) == ELEMENT_NODE_AVALUE_CHK || abs(type) == ELEMENT_NODE_CHK) { if (!tcldom_textCheck (interp, aval, "attribute")) { return TCL_ERROR; } } if (uri) { domSetAttributeNS (node, tval, aval, uri, 1); } else { domSetAttribute(node, tval, aval); } } return TCL_OK; } /*---------------------------------------------------------------------------- | NodeObjCmd | \---------------------------------------------------------------------------*/ static int NodeObjCmd ( ClientData arg, /* Type of node to create. */ Tcl_Interp * interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *const objv[] /* Argument objects. */ ) { int type, createType, ret, disableOutputEscaping = 0, index = 1; domLength len, dlen; char *tag, *p, *tval, *aval; domNode *parent, *newNode = NULL; domTextNode *textNode = NULL; domDocument *doc; Tcl_Obj *cmdObj; NodeInfo *nodeInfo = (NodeInfo*) arg; /*------------------------------------------------------------------------ | Need parent node to get the owner document and to append new | child tag to it. The current parent node is stored on the stack. | \-----------------------------------------------------------------------*/ parent = (domNode *) StackTop(interp); if (parent == NULL) { Tcl_AppendResult(interp, "called outside domNode context", NULL); return TCL_ERROR; } doc = parent->ownerDocument; /*------------------------------------------------------------------------ | Create new node according to type. Special case is the ELEMENT_NODE | since here we may enter into recursion. The ELEMENT_NODE is the only | node type which may have script body as last argument. | \-----------------------------------------------------------------------*/ ret = TCL_OK; type = nodeInfo->type; switch (abs(type)) { case CDATA_SECTION_NODE: case CDATA_SECTION_NODE_CHK: case COMMENT_NODE: case COMMENT_NODE_CHK: case TEXT_NODE: case TEXT_NODE_CHK: tval = NULL; if (objc != 2) { if (abs(type) == TEXT_NODE || abs(type) == TEXT_NODE_CHK) { if (objc == 1 && (nodeInfo->jsonType == JSON_NULL || nodeInfo->jsonType == JSON_TRUE || nodeInfo->jsonType == JSON_FALSE)) { tval = ""; len = 0; } else if (objc != 3 || strcmp ("-disableOutputEscaping", Tcl_GetStringFromObj (objv[1], &len))!=0) { Tcl_WrongNumArgs(interp, 1, objv, "?-disableOutputEscaping? text"); return TCL_ERROR; } else { disableOutputEscaping = 1; index = 2; } } else { Tcl_WrongNumArgs(interp, 1, objv, "text"); return TCL_ERROR; } } if (!tval) { tval = Tcl_GetStringFromObj(objv[index], &len); } switch (abs(type)) { case TEXT_NODE_CHK: if (!tcldom_textCheck (interp, tval, "text")) return TCL_ERROR; createType = TEXT_NODE; break; case COMMENT_NODE_CHK: if (!tcldom_commentCheck (interp, tval)) return TCL_ERROR; createType = COMMENT_NODE; break; case CDATA_SECTION_NODE_CHK: if (!tcldom_CDATACheck (interp, tval)) return TCL_ERROR; createType = CDATA_SECTION_NODE; break; default: createType = nodeInfo->type; break; } textNode = domNewTextNode(doc, tval, len, createType); textNode->info = nodeInfo->jsonType; if (disableOutputEscaping) { textNode->nodeFlags |= DISABLE_OUTPUT_ESCAPING; } domAppendChild(parent, (domNode*) textNode); break; case PROCESSING_INSTRUCTION_NODE_NAME_CHK: case PROCESSING_INSTRUCTION_NODE_VALUE_CHK: case PROCESSING_INSTRUCTION_NODE_CHK: case PROCESSING_INSTRUCTION_NODE: if (objc != 3) { Tcl_WrongNumArgs(interp, 1, objv, "target data"); return TCL_ERROR; } tval = Tcl_GetStringFromObj(objv[1], &len); if (abs(type) == PROCESSING_INSTRUCTION_NODE_NAME_CHK || abs(type) == PROCESSING_INSTRUCTION_NODE_CHK) { if (!tcldom_PINameCheck (interp, tval)) return TCL_ERROR; } aval = Tcl_GetStringFromObj(objv[2], &dlen); if (abs(type) == PROCESSING_INSTRUCTION_NODE_VALUE_CHK || abs(type) == PROCESSING_INSTRUCTION_NODE_CHK) { if (!tcldom_PIValueCheck (interp, aval)) return TCL_ERROR; } newNode = (domNode *) domNewProcessingInstructionNode(doc, tval, len, aval, dlen); domAppendChild(parent, newNode); break; case PARSER_NODE: /* non-standard node-type : a hack! */ if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "markup"); return TCL_ERROR; } ret = tcldom_appendXML(interp, parent, objv[1]); break; case ELEMENT_NODE_ANAME_CHK: case ELEMENT_NODE_AVALUE_CHK: case ELEMENT_NODE_CHK: case ELEMENT_NODE: if (!nodeInfo->tagName) { tag = Tcl_GetStringFromObj(objv[0], &len); p = tag + len; /* Isolate just the tag name, i.e. skip it's parent namespace */ while (--p > tag) { if ((*p == ':') && (*(p-1) == ':')) { p++; /* just after the last "::" */ tag = p; break; } } } else { tag = nodeInfo->tagName; } newNode = domAppendNewElementNode (parent, tag, nodeInfo->namespace); newNode->info = nodeInfo->jsonType; cmdObj = NULL; if (nodecmd_processAttributes (interp, newNode, type, objc, objv, &cmdObj, nodeInfo->flags) != TCL_OK) { return TCL_ERROR; } if (cmdObj) { ret = nodecmd_appendFromScript(interp, newNode, cmdObj); } if (newNode->firstChild == NULL && nodeInfo->flags & FS_NOT_EMPTY) { domDeleteNode (newNode, NULL, NULL); } break; } if (type < 0 && newNode != NULL) { char buf[64]; tcldom_createNodeObj(interp, newNode, buf); Tcl_SetObjResult(interp, Tcl_NewStringObj(buf, (domLength)strlen(buf))); } if (ret == TCL_OK) doc->nodeFlags |= NEEDS_RENUMBERING; return ret; } /*---------------------------------------------------------------------------- | nodecmd_createNodeCmd - implements the "createNodeCmd" method of | "dom" Tcl command | | This command is used to generate other Tcl commands which in turn | generate tDOM nodes. These new commands can only be called within | the context of the domNode command, however. | | Syntax: dom createNodeCmd ?-returnNodeCmd? cmdName | | where can be one of: | elementNode, commentNode, textNode, cdataNode or piNode | | The optional "-returnNodeCmd" parameter, if given, instructs the | command to return the object-based node command of the newly generated | node. Without the parameter, the command returns current interp result. | | Example: | | % dom createNodeCmd elementNode html::body | % dom createNodeCmd -returnNodeCmd elementNode html::title | % dom createNodeCmd textNode html::t | | And usage: | | % set d [dom createDocument html] | % set n [$d documentElement] | % $n appendFromScript { | html::body { | set title [html::title {html::t "This is an example"}] | $title setAttribute dummy 1 | } | % puts [$n asHTML] | \---------------------------------------------------------------------------*/ int nodecmd_createNodeCmd ( Tcl_Interp * interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *const objv[], /* Argument objects. */ int checkName, /* Flag: Name checks? */ int checkCharData /* Flag: Data checks? */ ) { int index, ret, type, nodecmd = 0, jsonType = 0, haveJsonType = 0; int isElement = 0, flags = 0; char *nsName, buf[64]; Tcl_Obj *tagName = NULL, *namespace = NULL; Tcl_DString cmdName; NodeInfo *nodeInfo; /* * Syntax: * * dom createNodeCmd ?-returnNodeCmd? nodeType commandName */ enum subCmd { ELM_NODE, TXT_NODE, CDS_NODE, CMT_NODE, PIC_NODE, PRS_NODE }; static const char *subcmds[] = { "elementNode", "textNode", "cdataNode", "commentNode", "piNode", "parserNode", NULL }; static const char *options[] = { "-returnNodeCmd", "-jsonType", "-tagName", "-namespace", "-noNamespacedAttributes", "-notempty", NULL }; enum option { o_returnNodeCmd, o_jsonType, o_tagName, o_namespace, o_noNamespacedAttributes, o_notempty }; static const char *jsonTypes[] = { "NONE", "ARRAY", "OBJECT", "NULL", "TRUE", "FALSE", "STRING", "NUMBER", "BOOLEAN" }; if (objc < 3 ) { goto usage; } while (objc > 3) { if (Tcl_GetIndexFromObj (interp, objv[1], options, "option", 0, &index) != TCL_OK) { return TCL_ERROR; } switch ((enum option) index) { case o_returnNodeCmd: nodecmd = 1; objc--; objv++; break; case o_jsonType: if (Tcl_GetIndexFromObj (interp, objv[2], jsonTypes, "jsonType", 1, &jsonType) != TCL_OK) { return TCL_ERROR; } haveJsonType = 1; objc -= 2; objv += 2; break; case o_tagName: tagName = objv[2]; objc -= 2; objv += 2; break; case o_namespace: namespace = objv[2]; objc -= 2; objv += 2; break; case o_noNamespacedAttributes: flags |= FS_ATT_NO_NAMESPACED; objc--; objv++; break; case o_notempty: flags |= FS_NOT_EMPTY; objc--; objv++; break; } } if (objc != 3) { goto usage; } ret = Tcl_GetIndexFromObj(interp, objv[1], subcmds, "nodeType", 0, &index); if (ret != TCL_OK) { return ret; } /*-------------------------------------------------------------------- | Construct fully qualified command name using current namespace | \-------------------------------------------------------------------*/ Tcl_DStringInit(&cmdName); strcpy(buf, "namespace current"); ret = Tcl_Eval(interp, buf); if (ret != TCL_OK) { return ret; } nsName = (char *)Tcl_GetStringResult(interp); Tcl_DStringAppend(&cmdName, nsName, -1); if (strcmp(nsName, "::")) { Tcl_DStringAppend(&cmdName, "::", 2); } Tcl_DStringAppend(&cmdName, Tcl_GetString(objv[2]), -1); Tcl_ResetResult (interp); switch ((enum subCmd)index) { case ELM_NODE: isElement = 1; if (!haveJsonType) { if (!tcldom_nameCheck(interp, namespaceTail(objv[2]), "tag", 0)) { return TCL_ERROR; } if (checkName && checkCharData) { type = ELEMENT_NODE_CHK; } else if (checkName) { type = ELEMENT_NODE_ANAME_CHK; } else if (checkCharData) { type = ELEMENT_NODE_AVALUE_CHK; } else { type = ELEMENT_NODE; } } else { if (jsonType > 2) { Tcl_SetResult(interp, "For an element node the jsonType" " argument must be one out of this list: ARRAY" " OBJECT NONE.", NULL); return TCL_ERROR; } type = ELEMENT_NODE; } break; case PRS_NODE: type = PARSER_NODE; break; case TXT_NODE: if (!haveJsonType) { if (checkCharData) { type = TEXT_NODE_CHK; } else { type = TEXT_NODE; } } else { if (jsonType < 3 && jsonType > 0) { Tcl_SetResult(interp, "For a text node the jsonType " "argument must be one out of this list: " "TRUE FALSE NULL NUMBER STRING NONE or BOOLEAN", NULL); return TCL_ERROR; } type = TEXT_NODE; } break; case CDS_NODE: if (checkCharData) { type = CDATA_SECTION_NODE_CHK; } else { type = CDATA_SECTION_NODE; } break; case CMT_NODE: if (checkCharData) { type = COMMENT_NODE_CHK; } else { type = COMMENT_NODE; } break; case PIC_NODE: if (checkName && checkCharData) { type = PROCESSING_INSTRUCTION_NODE_CHK; } else if (checkName) { type = PROCESSING_INSTRUCTION_NODE_NAME_CHK; } else if (checkCharData) { type = PROCESSING_INSTRUCTION_NODE_VALUE_CHK; } else { type = PROCESSING_INSTRUCTION_NODE; } break; default: Tcl_SetResult (interp, "Invalid/unexpected node type", NULL); return TCL_ERROR; } if (tagName && !isElement) { Tcl_SetResult(interp, "The -tagName option is allowed only for " "element node commands.", NULL); return TCL_ERROR; } if (namespace && !isElement) { Tcl_SetResult(interp, "The -namespace option is allowed only for " "element node commands.", NULL); return TCL_ERROR; } if ((flags & ~FS_ATT_NO_NAMESPACED) && !isElement) { Tcl_SetResult(interp, "The -noNamespacedAttributes option is allowed " "only for element node commands.", NULL); return TCL_ERROR; } if (haveJsonType && type != ELEMENT_NODE && type != TEXT_NODE) { Tcl_SetResult(interp, "Only element and text nodes may have a " "JSON type.", NULL); return TCL_ERROR; } nodeInfo = (NodeInfo *) MALLOC (sizeof (NodeInfo)); nodeInfo->namespace = NULL; nodeInfo->flags = flags; nodeInfo->type = type; if (nodecmd) { nodeInfo->type *= -1; /* Signal this fact */ } nodeInfo->jsonType = jsonType; nodeInfo->tagName = NULL; if (namespace) { nodeInfo->namespace = tdomstrdup (Tcl_GetString(namespace)); } if (tagName) { nodeInfo->tagName = tdomstrdup (Tcl_GetString(tagName)); } Tcl_CreateObjCommand(interp, Tcl_DStringValue(&cmdName), NodeObjCmd, (ClientData)nodeInfo, NodeObjCmdDeleteProc); Tcl_DStringResult(interp, &cmdName); Tcl_DStringFree(&cmdName); return TCL_OK; usage: Tcl_AppendResult(interp, "dom createNodeCmd\n" "\t?-returnNodeCmd?\n" "\t?-jsonType ?\n" "\t?-tagName ?\n" " nodeType cmdName", NULL); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * nodecmd_appendFromScript -- * * This procedure implements the dom method appendFromScript. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * Appends new child nodes to node. * *---------------------------------------------------------------------- */ int nodecmd_appendFromScript ( Tcl_Interp *interp, /* Current interpreter. */ domNode *node, /* Parent dom node */ Tcl_Obj *cmdObj /* Argument objects. */ ) { int ret, insideEval; domNode *oldLastChild, *child, *nextChild; domDocument *doc; if (node->nodeType != ELEMENT_NODE) { Tcl_SetResult (interp, "NOT_AN_ELEMENT : can't append nodes", NULL); return TCL_ERROR; } doc = node->ownerDocument; oldLastChild = node->lastChild; StackPush(interp, (void *) node); insideEval = (doc->nodeFlags & INSIDE_FROM_SCRIPT); if (!insideEval) { doc->nodeFlags |= INSIDE_FROM_SCRIPT; } Tcl_AllowExceptions(interp); ret = Tcl_EvalObjEx(interp, cmdObj, 0); if (ret != TCL_ERROR) { Tcl_ResetResult(interp); } StackPop(interp); if (ret == TCL_ERROR) { if (oldLastChild) { child = oldLastChild->nextSibling; } else { child = node->firstChild; } while (child) { nextChild = child->nextSibling; domFreeNode (child, NULL, NULL, 0); child = nextChild; } if (oldLastChild) { oldLastChild->nextSibling = NULL; node->lastChild = oldLastChild; } else { node->firstChild = NULL; node->lastChild = NULL; } } if (!insideEval) { /* Top level reached */ node->ownerDocument->nodeFlags &= ~INSIDE_FROM_SCRIPT; if (doc->nodeFlags & DELETE_AFTER_FROM_SCRIPT) { tcldom_deleteDoc(interp, doc); return TCL_BREAK; } } return (ret == TCL_BREAK) ? TCL_OK : ret; } /* *---------------------------------------------------------------------- * * nodecmd_insertBeforeFromScript -- * * This procedure implements the dom method * insertBeforeFromScript. See the user documentation for details * on what it does. * * This procedure is actually mostly a wrapper around * nodecmd_appendFromScript. * * Results: * A standard Tcl result. * * Side effects: * Insert new child nodes before referenceChild to node. * *---------------------------------------------------------------------- */ int nodecmd_insertBeforeFromScript ( Tcl_Interp *interp, /* Current interpreter. */ domNode *node, /* Parent dom node */ Tcl_Obj *cmdObj, /* Argument objects. */ domNode *refChild /* Insert new children before this * node; may be NULL */ ) { int ret; domNode *storedLastChild, *n; if (!refChild) { return nodecmd_appendFromScript (interp, node, cmdObj); } if (node->nodeType != ELEMENT_NODE) { Tcl_SetResult (interp, "NOT_AN_ELEMENT : can't append nodes", NULL); return TCL_ERROR; } /* check, if node is in deed the parent of refChild */ if (refChild->parentNode != node) { /* If node is the root node of a document and refChild is in deed a child of this node, then refChild->parentNode will be NULL. In this case, we loop throu the children of node, to see, if the refChild is valid. */ Tcl_ResetResult (interp); if (node->ownerDocument->rootNode == node) { n = node->firstChild; while (n) { if (n == refChild) { /* refChild is in deed a child of node */ break; } n = n->nextSibling; } if (!n) { Tcl_SetStringObj(Tcl_GetObjResult(interp), "NOT_FOUND_ERR", -1); return TCL_ERROR; } } else { Tcl_SetStringObj(Tcl_GetObjResult(interp), "NOT_FOUND_ERR", -1); return TCL_ERROR; } } storedLastChild = node->lastChild; if (refChild->previousSibling) { refChild->previousSibling->nextSibling = NULL; node->lastChild = refChild->previousSibling; } else { node->firstChild = NULL; node->lastChild = NULL; } ret = nodecmd_appendFromScript (interp, node, cmdObj); if (node->lastChild) { node->lastChild->nextSibling = refChild; refChild->previousSibling = node->lastChild; } else { node->firstChild = refChild; } node->lastChild = storedLastChild; return ret; } /*---------------------------------------------------------------------------- | nodecmd_curentNode | \---------------------------------------------------------------------------*/ domNode * nodecmd_currentNode(Tcl_Interp *interp) { return StackTop(interp); } void nodecmd_init (Tcl_Interp *interp) { CurrentStack *csPtr = (CurrentStack *) MALLOC(sizeof(CurrentStack)); csPtr->elementStack = NULL; csPtr->currentSlot = NULL; Tcl_SetAssocData(interp, "tdom_stk", StackFinalize, (ClientData) csPtr); } /* EOF $RCSfile $ */ /* Emacs Setup Variables */ /* Local Variables: */ /* mode: C */ /* indent-tabs-mode: nil */ /* c-basic-offset: 4 */ /* End: */ tdom-0.9.6-src/generic/domjson.h0000644000175000017500000000174415025767703015224 0ustar rolfrolf #ifndef JSON_MAX_NESTING # define JSON_MAX_NESTING 2000 #endif #ifndef JSON_OBJECT_CONTAINER # define JSON_OBJECT_CONTAINER "objectcontainer" #endif #ifndef JSON_ARRAY_CONTAINER # define JSON_ARRAY_CONTAINER "arraycontainer" #endif typedef enum { JSON_START, JSON_WITHIN_ARRAY, JSON_WITHIN_OBJECT } JSONWithin; #define JSON_ARRAY 1 #define JSON_OBJECT 2 #define JSON_NULL 3 #define JSON_TRUE 4 #define JSON_FALSE 5 #define JSON_STRING 6 #define JSON_NUMBER 7 #define JSON_BOOLEAN 8 domDocument * JSON_Parse ( char *json, /* Complete text of the json string being parsed */ char *documentElement, /* name of the root element, may be NULL */ int maxnesting, char **errStr, domLength *byteIndex ); domDocument * TypedList2DOM ( Tcl_Interp *interp, Tcl_Obj *typedList ); int isJSONNumber ( char *num, domLength numlen ); int jsonEscape ( Tcl_Interp *interp, char *str, Tcl_DString *clearedstr, int *changed); tdom-0.9.6-src/generic/domlock.c0000644000175000017500000001107415025767703015173 0ustar rolfrolf/*---------------------------------------------------------------------------- | Copyright (C) 1999 Jochen C. Loewer (loewerj@hotmail.com) +----------------------------------------------------------------------------- | | The contents of this file are subject to the Mozilla Public License | Version 2.0 (the "License"); you may not use this file except in | compliance with the License. You may obtain a copy of the License at | http://www.mozilla.org/MPL/ | | Software distributed under the License is distributed on an "AS IS" | basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the | License for the specific language governing rights and limitations | under the License. | | The Original Code is tDOM. | | The Initial Developer of the Original Code is Jochen Loewer | Portions created by Jochen Loewer are Copyright (C) 1998, 1999 | Jochen Loewer. All Rights Reserved. | | This implements many-readers/single-writer locking of DOM documents. | | Contributor(s): | May02 Zoran Vasiljevic Added this file. | \---------------------------------------------------------------------------*/ #include #ifdef TCL_THREADS /*---------------------------------------------------------------------------- | Global list of document lock structures. These should be finalized | only on application exit. | \---------------------------------------------------------------------------*/ static Tcl_Mutex lockMutex = 0; static domlock *domLocks = NULL; /*---------------------------------------------------------------------------- | Lock the document according to passed flag | \---------------------------------------------------------------------------*/ void domLocksLock(domlock *dl, int how) { Tcl_MutexLock(&dl->mutex); switch (how) { case LOCK_READ: while (dl->lrcnt < 0 || dl->numwr > 0) { dl->numrd++; Tcl_ConditionWait(&dl->rcond, &dl->mutex, NULL); dl->numrd--; } dl->lrcnt++; break; case LOCK_WRITE: while (dl->lrcnt != 0) { dl->numwr++; Tcl_ConditionWait(&dl->wcond, &dl->mutex, NULL); dl->numwr--; } dl->lrcnt = -1; /* This designates the sole writer */ break; } Tcl_MutexUnlock(&dl->mutex); } /*---------------------------------------------------------------------------- | Unlock the previously locked document. | \---------------------------------------------------------------------------*/ void domLocksUnlock(domlock *dl) { Tcl_MutexLock(&dl->mutex); if (--dl->lrcnt < 0) { dl->lrcnt = 0; } if (dl->numwr) { Tcl_ConditionNotify(&dl->wcond); } else if (dl->numrd) { Tcl_ConditionNotify(&dl->rcond); } Tcl_MutexUnlock (&dl->mutex); } /*---------------------------------------------------------------------------- | Associate a lock with the document.. | \---------------------------------------------------------------------------*/ void domLocksAttach(domDocument *doc) { domlock *dl; Tcl_MutexLock(&lockMutex); dl = domLocks; if (dl == NULL) { dl = (domlock*)MALLOC(sizeof(domlock)); memset(dl, 0, sizeof(domlock)); } else { domLocks = dl->next; } dl->doc = doc; doc->lock = dl; Tcl_MutexUnlock(&lockMutex); } /*---------------------------------------------------------------------------- | Divorce DOM document from its lock. The lock structure is not | disposed and may be used for locking other documents. | \---------------------------------------------------------------------------*/ void domLocksDetach(domDocument *doc) { domlock *dl = doc->lock; Tcl_MutexLock(&lockMutex); if (dl->doc != doc) { domPanic("document lock mismatch"); } dl->next = domLocks; domLocks = dl; dl->doc = NULL; doc->lock = NULL; Tcl_MutexUnlock(&lockMutex); } /*---------------------------------------------------------------------------- | Reclaim storage used for lock structures. This should be done only | on application exit. | \---------------------------------------------------------------------------*/ void domLocksFinalize(ClientData UNUSED(dummy)) { domlock *tmp, *dl; Tcl_MutexLock(&lockMutex); dl = domLocks; while (dl != NULL) { Tcl_MutexFinalize(&dl->mutex); Tcl_ConditionFinalize(&dl->rcond); Tcl_ConditionFinalize(&dl->wcond); tmp = dl; dl = dl->next; FREE((char*)tmp); } domLocks = NULL; Tcl_MutexUnlock(&lockMutex); } #endif /* TCL_THREADS */ tdom-0.9.6-src/generic/domxslt.c0000644000175000017500000102733315025767703015243 0ustar rolfrolf/*---------------------------------------------------------------------------- | Copyright (c) 2000 Jochen Loewer (loewerj@hotmail.com) |----------------------------------------------------------------------------- | | A XSLT implementation for tDOM, according to the W3C | recommendation (16 Nov 1999). | See http://www.w3.org/TR/1999/REC-xslt-19991116 for details. | | | The contents of this file are subject to the Mozilla Public License | Version 2.0 (the "License"); you may not use this file except in | compliance with the License. You may obtain a copy of the License at | http://www.mozilla.org/MPL/ | | Software distributed under the License is distributed on an "AS IS" | basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the | License for the specific language governing rights and limitations | under the License. | | The Original Code is tDOM. | | The Initial Developer of the Original Code is Jochen Loewer | Portions created by Jochen Loewer are Copyright (C) 1999, 2000 | Jochen Loewer. All Rights Reserved. | | Contributor(s): | Aug01 Rolf Ade xsl:include, xsl:import, xsl:apply-imports, | document() plus several bug fixes | | Fall/Winter 01 Rolf Ade rewrite of xsl:number, xsl:key/key(), | handling of top-level var/parameter, | plenty of fixes and enhancements all | over the place. | | 2001-2007 Rolf Ade All changes and enhancements. | | written by Jochen Loewer | June, 2000 | \---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------- | Includes | \---------------------------------------------------------------------------*/ #include #include #include #include #include /* for hash tables */ #include #include #include /*---------------------------------------------------------------------------- | Defines | \---------------------------------------------------------------------------*/ #define XSLT_NAMESPACE "http://www.w3.org/1999/XSL/Transform" #define INITIAL_SIZE_FOR_KEYSETS 10 /* #define DEBUG */ /*---------------------------------------------------------------------------- | Debug Macros | \---------------------------------------------------------------------------*/ #ifdef DEBUG # define DBG(x) x #else # define DBG(x) #endif #define DBG(x) #define TRACE(x) DBG(fprintf(stderr,(x))) #define TRACE1(x,a) DBG(fprintf(stderr,(x),(a))) #define TRACE2(x,a,b) DBG(fprintf(stderr,(x),(a),(b))) #define TRACE3(x,a,b,c) DBG(fprintf(stderr,(x),(a),(b),(c))) #define TRACE4(x,a,b,c,d) DBG(fprintf(stderr,(x),(a),(b),(c),(d))) #define TRACE5(x,a,b,c,d,e) DBG(fprintf(stderr,(x),(a),(b),(c),(d),(e))) /*---------------------------------------------------------------------------- | Macros | \---------------------------------------------------------------------------*/ #define CHECK_RC if (rc < 0) return rc #define CHECK_RC1(x) if (rc < 0) {FREE((char*)(x)); return rc;} #define SET_TAG(t,n,s,v) if (strcmp(n,s)==0) { t->info = v; return v; } #define SETSCOPESTART xs->varFramesStack[xs->varFramesStackPtr].stop=1 #define SETPARAMDEF xs->varFramesStack[xs->varFramesStackPtr].stop=2 #if defined(_MSC_VER) # define STRCASECMP(a,b) stricmp (a,b) #else # define STRCASECMP(a,b) strcasecmp (a,b) #endif extern void printAst (int depth, ast t); /*-------------------------------------------------------------------------- | xsltTag | \-------------------------------------------------------------------------*/ typedef enum { unknown = 1, applyImports, applyTemplates, attribute, attributeSet, callTemplate, choose, comment, copy, copyOf, decimalFormat, element, fallback, forEach, xsltIf, import, include, key, message, namespaceAlias, number, output, otherwise, param, procinstr, preserveSpace, sort, stylesheet, stripSpace, text, template, transform, valueOf, variable, when, withParam } xsltTag; /*-------------------------------------------------------------------------- | xsltAttr | \-------------------------------------------------------------------------*/ typedef enum { a_caseorder = 1, a_count, a_dataType, a_disableOutputEscaping, a_doctypePublic, a_doctypeSystem, a_elements, a_encoding, a_format, a_from, a_href, a_lang, a_level, a_match, a_mediaType, a_method, a_mode, a_name, a_namespace, a_order, a_prio, a_select, a_space, a_terminate, a_test, a_use, a_useAttributeSets, a_value, a_groupingSeparator, a_groupingSize, a_decimalSeparator, a_infinity, a_minusSign, a_nan, a_percent, a_perMille, a_zeroDigit, a_digit, a_patternSeparator, a_version, a_excludeResultPrefixes, a_extensionElementPrefixes, a_stylesheetPrefix, a_resultPrefix, a_indent, a_omitXMLDeclaration, a_standalone, a_cdataSectionElements } xsltAttr; /*-------------------------------------------------------------------------- | xsltExclExtNS | \-------------------------------------------------------------------------*/ typedef struct xsltExclExtNS { char * uri; struct xsltExclExtNS * next; } xsltExclExtNS; /*-------------------------------------------------------------------------- | xsltSubDocs | \-------------------------------------------------------------------------*/ typedef struct xsltSubDoc { domDocument * doc; char * baseURI; Tcl_HashTable keyData; xsltExclExtNS * excludeNS; xsltExclExtNS * extensionNS; int fwCmpProcessing; int isStylesheet; int fixedXMLSource; int mustFree; struct xsltSubDoc * next; } xsltSubDoc; /*-------------------------------------------------------------------------- | xsltTemplate | \-------------------------------------------------------------------------*/ typedef struct xsltTemplate { char * match; const char * name; const char * nameURI; ast ast; const char * mode; const char * modeURI; double prio; domNode * content; double precedence; ast freeAst; xsltSubDoc * sDoc; struct xsltTemplate *next; } xsltTemplate; /*-------------------------------------------------------------------------- | xsltAttrSet | \-------------------------------------------------------------------------*/ typedef struct xsltAttrSet { const char * name; const char * uri; domNode * content; int inUse; struct xsltAttrSet *next; } xsltAttrSet; /*-------------------------------------------------------------------------- | xsltNodeSet | \-------------------------------------------------------------------------*/ typedef struct xsltNodeSet { domNode **nodes; domLength nr_nodes; domLength allocated; } xsltNodeSet; /*-------------------------------------------------------------------------- | xsltKeyInfo | \-------------------------------------------------------------------------*/ typedef struct xsltKeyInfo { domNode * node; char * match; ast matchAst; char * use; ast useAst; struct xsltKeyInfo * next; } xsltKeyInfo; /*-------------------------------------------------------------------------- | xsltVariable | \-------------------------------------------------------------------------*/ typedef struct xsltVariable { const char * name; const char * uri; domNode * node; xpathResultSet rs; int active; } xsltVariable; /*-------------------------------------------------------------------------- | xsltVarFrame | \-------------------------------------------------------------------------*/ typedef struct xsltVarFrame { xsltVariable * vars; int polluted; int nrOfVars; int varStartIndex; int stop; } xsltVarFrame; /*-------------------------------------------------------------------------- | xsltTopLevelVar | \-------------------------------------------------------------------------*/ typedef struct xsltTopLevelVar { domNode * node; char * name; int isParameter; double precedence; } xsltTopLevelVar; /*-------------------------------------------------------------------------- | xsltVarInProcess | \-------------------------------------------------------------------------*/ typedef struct xsltVarInProcess { char *name; struct xsltVarInProcess *next; } xsltVarInProcess; /*-------------------------------------------------------------------------- | xsltDecimalFormat | \-------------------------------------------------------------------------*/ typedef struct xsltDecimalFormat { char * name; char * uri; Tcl_UniChar decimalSeparator; Tcl_UniChar groupingSeparator; char * infinity; Tcl_UniChar minusSign; char * NaN; Tcl_UniChar percent; Tcl_UniChar perMille; Tcl_UniChar zeroDigit; Tcl_UniChar digit; Tcl_UniChar patternSeparator; struct xsltDecimalFormat * next; } xsltDecimalFormat; /*-------------------------------------------------------------------------- | xsltWSInfo | \-------------------------------------------------------------------------*/ typedef struct xsltWSInfo { int hasData; int stripAll; double wildcardPrec; Tcl_HashTable stripTokens; Tcl_HashTable preserveTokens; } xsltWSInfo; typedef struct xsltNSAlias { char *fromUri; char *toUri; double precedence; struct xsltNSAlias *next; } xsltNSAlias; /*-------------------------------------------------------------------------- | xsltState | \-------------------------------------------------------------------------*/ typedef struct { xsltTemplate * templates; int nestedApplyTemplates; int maxNestedApplyTemplates; Tcl_HashTable namedTemplates; Tcl_HashTable isElementTpls; xsltWSInfo wsInfo; domNode * xmlRootNode; domDocInfo doctype; int indentOutput; domDocument * resultDoc; domNode * lastNode; xsltVarFrame * varFramesStack; int varFramesStackPtr; int varFramesStackLen; xsltVariable * varStack; int varStackPtr; int varStackLen; xsltAttrSet * attrSets; Tcl_HashTable xpaths; Tcl_HashTable pattern; Tcl_HashTable formats; Tcl_HashTable topLevelVars; Tcl_HashTable keyInfos; xsltNSAlias * nsAliases; int nsUniqeNr; xsltVarInProcess * varsInProcess; xpathCBs cbs; xpathFuncCallback orig_funcCB; void * orig_funcClientData; xsltMsgCB xsltMsgCB; void * xsltMsgClientData; xsltDecimalFormat * decimalFormats; domNode * current; xsltSubDoc * subDocs; xsltSubDoc * currentSubDoc; xsltTemplate * currentTplRule; domNode * currentXSLTNode; domDocument * xsltDoc; } xsltState; typedef enum { latin_number, latin_upper, latin_lower, roman_upper, roman_lower } xsltNumberingType; /*-------------------------------------------------------------------------- | xsltNumberFormatToken | \-------------------------------------------------------------------------*/ typedef struct { xsltNumberingType type; int minlength; char *sepStart; int sepLen; } xsltNumberFormatToken; /*-------------------------------------------------------------------------- | xsltNumberFormat | \-------------------------------------------------------------------------*/ typedef struct { char *formatStr; int prologLen; xsltNumberFormatToken *tokens; int maxtokens; char *epilogStart; int epilogLen; } xsltNumberFormat; /*-------------------------------------------------------------------------- | Prototypes | \-------------------------------------------------------------------------*/ static int ApplyTemplates ( xsltState *xs, xpathResultSet *context, domNode *currentNode, domLength currentPos, domNode *actionNode, xpathResultSet *nodeList, const char *mode, const char *modeURI, char **errMsg); static int ApplyTemplate ( xsltState *xs, xpathResultSet *context, domNode *currentNode, domNode *exprContext, domLength currentPos, const char *mode, const char *modeURI, char **errMsg); static int ExecActions (xsltState *xs, xpathResultSet *context, domNode *currentNode, domLength currentPos, domNode *actionNode, char **errMsg); static domDocument * getExternalDocument (Tcl_Interp *interp, xsltState *xs, domDocument *xsltDoc, const char *baseURI, const char *href, int isStylesheet, int fixedXMLSource, char **errMsg); #ifdef DEBUG /*---------------------------------------------------------------------------- | printXML | \---------------------------------------------------------------------------*/ static void printXML (domNode *node, int level, int maxlevel) { domTextNode *tnode; domProcessingInstructionNode *pi; char tmp[80]; int i, l, n; n = 0; while (node) { for (i=0;inodeType == ELEMENT_NODE) { if (node->firstChild && node->firstChild->nodeType == TEXT_NODE) { tnode = (domTextNode*)node->firstChild; l = tnode->valueLength; if (l > 30) l = 30; memmove(tmp, tnode->nodeValue, l); tmp[l] = '\0'; fprintf(stderr, "<%s/domNode0x%p> '%s'\n", node->nodeName, node, tmp); } else { tmp[0] = '\0'; if ((level>=maxlevel) && (node->firstChild)) { strcpy( tmp, "..."); } fprintf(stderr, "<%s/domNode0x%p> %s\n", node->nodeName, node, tmp); } if (levelfirstChild) printXML(node->firstChild, level+1, maxlevel); } } if (node->nodeType == TEXT_NODE) { tnode = (domTextNode*)node; l = tnode->valueLength; if (l > 70) l = 70; memmove(tmp, tnode->nodeValue, l); tmp[l] = '\0'; fprintf(stderr, "'%s'\n", tmp); } if (node->nodeType == COMMENT_NODE) { tnode = (domTextNode*)node; l = tnode->valueLength; memmove (tmp, "", 3); tmp[7+l] = '\0'; fprintf(stderr, "'%s'\n", tmp); } if (node->nodeType == PROCESSING_INSTRUCTION_NODE) { pi = (domProcessingInstructionNode*)node; l = pi->targetLength; if (l > 70) l = 70; memmove(tmp, pi->targetValue, l); tmp[l] = '\0'; fprintf(stderr, "dataLength; if (l > 70) l = 70; memmove(tmp, pi->dataValue, l); tmp[l] = '\0'; fprintf(stderr, "%s?>\n", tmp); } node = node->nextSibling; n++; if (n>8) { fprintf(stderr, "...\n"); return; } } } #endif /* #ifdef DEBUG */ /*---------------------------------------------------------------------------- | reportError | \---------------------------------------------------------------------------*/ static void reportError ( domNode * node, char * str, char ** errMsg) { Tcl_DString dStr; char buffer[1024]; const char *baseURI; XML_Size line, column; XML_Index byteIndex; Tcl_DStringInit (&dStr); baseURI = findBaseURI (node); if (baseURI) { Tcl_DStringAppend (&dStr, "In entity ", 10); Tcl_DStringAppend (&dStr, baseURI, -1); } if (node->nodeFlags & HAS_LINE_COLUMN) { domGetLineColumn (node, &line, &column, &byteIndex); sprintf (buffer, " at line %" TDOM_LS_MODIFIER "d, column %" TDOM_LS_MODIFIER "d:\n", line, column); Tcl_DStringAppend (&dStr, buffer, -1); Tcl_DStringAppend (&dStr, str, -1); } else { if (baseURI) Tcl_DStringAppend (&dStr, ": ", 2); Tcl_DStringAppend (&dStr, str, -1); } if (*errMsg) FREE (*errMsg); *errMsg = tdomstrdup (Tcl_DStringValue (&dStr)); Tcl_DStringFree (&dStr); } /*---------------------------------------------------------------------------- | getAttr | \---------------------------------------------------------------------------*/ static char * getAttr ( domNode *node, char *name, xsltAttr attrTypeNo ) { domAttrNode *attr; attr = node->firstAttr; while (attr) { if (attr->info == (unsigned int)attrTypeNo) { return attr->nodeValue; } else if (attr->info == 0) { if (strcmp ((char*)attr->nodeName, name)==0) { attr->info = (unsigned int)attrTypeNo; return attr->nodeValue; } } attr = attr->nextSibling; } return NULL; } /*---------------------------------------------------------------------------- | getTag | \---------------------------------------------------------------------------*/ static xsltTag getTag ( domNode *node ) { const char *name; if (node->nodeType != ELEMENT_NODE) { node->info = (int)unknown; return unknown; } if (node->info != 0) { return (xsltTag)node->info; } name = domNamespaceURI(node); if ((name == NULL) || (strcmp(name, XSLT_NAMESPACE)!=0)) { node->info = (int)unknown; return unknown; } name = domGetLocalName(node->nodeName); switch (*name) { case 'a': SET_TAG(node,name,"apply-imports", applyImports); SET_TAG(node,name,"apply-templates",applyTemplates); SET_TAG(node,name,"attribute", attribute); SET_TAG(node,name,"attribute-set", attributeSet); break; case 'c': SET_TAG(node,name,"call-template", callTemplate); SET_TAG(node,name,"choose", choose); SET_TAG(node,name,"comment", comment); SET_TAG(node,name,"copy", copy); SET_TAG(node,name,"copy-of", copyOf); break; case 'd': SET_TAG(node,name,"decimal-format", decimalFormat); break; case 'e': SET_TAG(node,name,"element", element); break; case 'f': SET_TAG(node,name,"fallback", fallback); SET_TAG(node,name,"for-each", forEach); break; case 'i': SET_TAG(node,name,"if", xsltIf); SET_TAG(node,name,"import", import); SET_TAG(node,name,"include", include); break; case 'k': SET_TAG(node,name,"key", key); break; case 'm': SET_TAG(node,name,"message", message); break; case 'n': SET_TAG(node,name,"namespace-alias",namespaceAlias); SET_TAG(node,name,"number", number); break; case 'o': SET_TAG(node,name,"output", output); SET_TAG(node,name,"otherwise", otherwise); break; case 'p': SET_TAG(node,name,"param", param); SET_TAG(node,name,"preserve-space", preserveSpace); SET_TAG(node,name,"processing-instruction", procinstr); break; case 's': SET_TAG(node,name,"sort", sort); SET_TAG(node,name,"stylesheet", stylesheet); SET_TAG(node,name,"strip-space", stripSpace); break; case 't': SET_TAG(node,name,"template", template); SET_TAG(node,name,"text", text); SET_TAG(node,name,"transform", transform); break; case 'v': SET_TAG(node,name,"value-of", valueOf); SET_TAG(node,name,"variable", variable); break; case 'w': SET_TAG(node,name,"when", when); SET_TAG(node,name,"with-param", withParam); break; } node->info = (int)unknown; return unknown; } /*---------------------------------------------------------------------------- | xsltPopVarFrame | \---------------------------------------------------------------------------*/ static void xsltPopVarFrame ( xsltState * xs ) { int i; xsltVarFrame *frame; if (xs->varFramesStackPtr >= 0) { frame = &xs->varFramesStack[xs->varFramesStackPtr]; if (frame->nrOfVars) { for (i = frame->varStartIndex; i < frame->varStartIndex + frame->nrOfVars; i++) { xpathRSFree (&(&xs->varStack[i])->rs); } } xs->varStackPtr -= frame->nrOfVars; xs->varFramesStackPtr--; } } /*---------------------------------------------------------------------------- | xsltPushVarFrame | \---------------------------------------------------------------------------*/ static void xsltPushVarFrame ( xsltState * xs ) { xsltVarFrame * frame; xs->varFramesStackPtr++; if (xs->varFramesStackPtr >= xs->varFramesStackLen) { xs->varFramesStack = (xsltVarFrame *) REALLOC ((char*)xs->varFramesStack, sizeof (xsltVarFrame) * 2 * xs->varFramesStackLen); xs->varFramesStackLen *= 2; } frame = &(xs->varFramesStack[xs->varFramesStackPtr]); frame->polluted = 0; frame->nrOfVars = 0; frame->varStartIndex = -1; frame->stop = 0; } /*---------------------------------------------------------------------------- | xsltAddExternalDocument | \---------------------------------------------------------------------------*/ static int xsltAddExternalDocument ( xsltState * xs, const char * baseURI, const char * str, int fixedXMLSource, xpathResultSet * result, char ** errMsg ) { xsltSubDoc * sdoc; domDocument * extDocument; int found; DBG( fprintf (stderr, "xsltAddExternalDocument: baseURI '%s'\n", baseURI); fprintf (stderr, "xsltAddExternalDocument: systemID '%s'\n", str); ) found = 0; sdoc = xs->subDocs; if (str) { while (sdoc) { if (!sdoc->isStylesheet && sdoc->baseURI && strcmp (sdoc->baseURI, str)==0) { rsAddNode (result, sdoc->doc->rootNode); found = 1; break; } sdoc = sdoc->next; } } if (!found) { if (!xs->xsltDoc->extResolver) { *errMsg = tdomstrdup("Need resolver script for document() calls. " "(Use \"-externalentitycommand\")"); return -1; } extDocument = getExternalDocument ( (Tcl_Interp*)xs->orig_funcClientData, xs, xs->xsltDoc, baseURI, str, 0, fixedXMLSource, errMsg); if (extDocument) { rsAddNode (result, extDocument->rootNode); } else { return -1; } } return found; } /*---------------------------------------------------------------------------- | xsltNumberFormatTokenizer | \---------------------------------------------------------------------------*/ static xsltNumberFormat* xsltNumberFormatTokenizer ( xsltState *xs, char *formatStr, char **errMsg ) { char *p; int hnew, clen, nrOfTokens = 0; Tcl_HashEntry *h; xsltNumberFormat *format; /* TODO: make it l18n aware. */ h = Tcl_CreateHashEntry (&xs->formats, formatStr, &hnew); if (!hnew) { return (xsltNumberFormat *) Tcl_GetHashValue (h); } else { format = (xsltNumberFormat *)MALLOC(sizeof (xsltNumberFormat)); memset (format, 0 , sizeof (xsltNumberFormat)); format->tokens = (xsltNumberFormatToken *) MALLOC(sizeof (xsltNumberFormatToken) * 20); memset (format->tokens, 0, sizeof (xsltNumberFormatToken) * 20); format->maxtokens = 20; Tcl_SetHashValue (h, format); format->formatStr = p = Tcl_GetHashKey (&(xs->formats), h); } while (*p) { clen = UTF8_CHAR_LEN(*p); if (!clen) { reportError (xs->currentXSLTNode, "xsl:number: UTF-8 form of" " character longer than 4 Byte", errMsg); return NULL; } if (clen > 1) { /* hack: skip over multibyte chars - this may be wrong */ format->prologLen += clen; p += clen; continue; } if (isalnum((unsigned char)*p)) break; format->prologLen++; p++; } format->tokens[0].minlength = 1; if (!*p) { format->tokens[0].type = latin_number; return format; } #define addSeperator \ p++; \ if (*p) { \ format->tokens[nrOfTokens].sepStart = p; \ } \ while (*p) { \ clen = UTF8_CHAR_LEN(*p); \ if (!clen) { \ reportError (xs->currentXSLTNode, "xsl:number: UTF-8 form of character longer than 4 Byte", errMsg); \ return NULL; \ } \ if (clen > 1) { \ /* hack: skip over multibyte chars - this may be wrong */ \ format->tokens[nrOfTokens].sepLen += clen; \ p += clen; \ continue; \ } \ if (isalnum((unsigned char)*p)) break; \ format->tokens[nrOfTokens].sepLen++; \ p++; \ } \ if (*p) { \ if (format->tokens[nrOfTokens].sepLen == 0) goto wrongSyntax; \ } \ nrOfTokens++; \ if (nrOfTokens == format->maxtokens) { \ format->tokens = (xsltNumberFormatToken *) REALLOC ((char *)format->tokens, sizeof (xsltNumberFormatToken) * format->maxtokens * 2); \ format->maxtokens *= 2; \ } \ format->tokens[nrOfTokens].minlength = 1; \ continue; while (*p) { if (*p == '0') { format->tokens[nrOfTokens].minlength++; p++; continue; } if (*p == '1') { format->tokens[nrOfTokens].type = latin_number; addSeperator; } if (*p == 'A') { if (isalnum((unsigned char)*(p+1))) goto wrongSyntax; format->tokens[nrOfTokens].type = latin_upper; addSeperator; } if (*p == 'a') { if (isalnum((unsigned char)*(p+1))) goto wrongSyntax; format->tokens[nrOfTokens].type = latin_lower; addSeperator; } if (*p == 'I') { if (isalnum((unsigned char)*(p+1))) goto wrongSyntax; format->tokens[nrOfTokens].type = roman_upper; addSeperator; } if (*p == 'i') { if (isalnum((unsigned char)*(p+1))) goto wrongSyntax; format->tokens[nrOfTokens].type = roman_lower; addSeperator; } format->tokens[nrOfTokens].type = latin_number; while (isalnum((unsigned char)*(p+1))) { p++; } addSeperator; } format->epilogStart = format->tokens[nrOfTokens-1].sepStart; format->tokens[nrOfTokens-1].sepStart = NULL; format->epilogLen = format->tokens[nrOfTokens-1].sepLen; format->tokens[nrOfTokens-1].sepLen = 0; return format; wrongSyntax: reportError (xs->currentXSLTNode, "xsl:number: Wrong syntax in" " format attribute", errMsg); return NULL; } /*---------------------------------------------------------------------------- | formatValue | \---------------------------------------------------------------------------*/ static void formatValue ( xsltNumberFormat *f, int *useFormatToken, domLength value, Tcl_DString *str, char *groupingSeparator, long groupingSize, int addSeparater ) { domLength len, fulllen, gslen, m, i; int upper = 0, e, b, v, z; char tmp[80], *pt; Tcl_DString tmp1; static struct { const char *digit; const char *ldigit; int value; } RomanDigit[] = { { "M" , "m" , 1000, }, { "CM", "cm", 900, }, { "D" , "d" , 500, }, { "CD", "cd", 400, }, { "C" , "c" , 100, }, { "XC", "xc", 90, }, { "L" , "l" , 50, }, { "XL", "xl", 40, }, { "X" , "x" , 10, }, { "IX", "ix", 9, }, { "V" , "v" , 5, }, { "IV", "iv", 4, }, { "I" , "i" , 1 } }; switch (f->tokens[*useFormatToken].type) { case latin_number: sprintf (tmp, "%" TCL_SIZE_MODIFIER "d", value); fulllen = len = (domLength)strlen (tmp); if (f->tokens[*useFormatToken].minlength > fulllen) { fulllen = f->tokens[*useFormatToken].minlength; } if (groupingSeparator) { gslen = (domLength)strlen (groupingSeparator); Tcl_DStringInit (&tmp1); if (len < f->tokens[*useFormatToken].minlength) { for (i = 0; i < f->tokens[*useFormatToken].minlength - len; i++) { Tcl_DStringAppend (&tmp1, "0", 1); } } Tcl_DStringAppend (&tmp1, tmp, len); pt = Tcl_DStringValue (&tmp1); len = Tcl_DStringLength (&tmp1); m = len % groupingSize; if (m) { Tcl_DStringAppend (str, pt, m); pt += m; } i = len - m; while (i) { if (i != len) { Tcl_DStringAppend (str, groupingSeparator, gslen); } Tcl_DStringAppend (str, pt, groupingSize); pt += groupingSize; i -= groupingSize; } Tcl_DStringFree (&tmp1); } else { for (i = 0; i < fulllen - len; i++) { Tcl_DStringAppend (str, "0", 1); } Tcl_DStringAppend (str, tmp, len); } goto appendSeperator; break; case latin_upper: upper = 1; /* fall through */ case latin_lower: /* Home grown algorithm. (And I'm really not happy with it.) Please let rolf@pointsman.de know how to do this better / faster / more clever. */ if (value <= 0) { /* Hm, zero can't be expressed with letter sequences... What to do? One of the several cases, not mentioned by the spec. */ /* fall back to latin numbers */ sprintf (tmp, "%" TCL_SIZE_MODIFIER "d", value); break; } e = 1; m = b = 26; while (value > m) { b *= 26; m += b; e++; } m -= b; value -= m; for (i = 0; i < e; i++) { b /= 26; z = (int)(value / b); value = value - z*b; if (i < e -1) { if (value == 0) { value += b; } else { z++; } } if (upper) { tmp[i] = 64+z; } else { tmp[i] = 96+z; } } tmp[i] = '\0'; break; case roman_upper: upper = 1; /* fall through */ case roman_lower: /* Algorithm follows the idear of the converter at http://mini.net/cgi-bin/wikit/1749.html */ /* Side note: There exists a rarely used roman notation to express figures up to a few millions. Does somebody really need this? */ if (value > 3999 || value <= 0) { /* fall back to latin numbers */ sprintf (tmp, "%" TCL_SIZE_MODIFIER "d", value); break; } if (value == 0) { /* what to do with zero??? */ sprintf (tmp, "%d", 0); break; } v = 0; tmp[0] = '\0'; while (value > 0) { while (value >= RomanDigit[v].value) { if (upper) { strcat(tmp, RomanDigit[v].digit); } else { strcat(tmp, RomanDigit[v].ldigit); } value -= RomanDigit[v].value; } v++; } break; default: sprintf (tmp, "%" TCL_SIZE_MODIFIER "d", value); break; } len = (domLength)strlen (tmp); Tcl_DStringAppend (str, tmp, len); appendSeperator: if (addSeparater) { if (f->tokens[*useFormatToken].sepStart) { Tcl_DStringAppend (str, f->tokens[*useFormatToken].sepStart, f->tokens[*useFormatToken].sepLen); *useFormatToken += 1; } else { if (*useFormatToken > 0) { Tcl_DStringAppend (str, f->tokens[*useFormatToken-1].sepStart, f->tokens[*useFormatToken-1].sepLen); } else { /* insert default separator '.' */ Tcl_DStringAppend (str, ".", 1); } } } return; } /*---------------------------------------------------------------------------- | xsltFormatNumber | \---------------------------------------------------------------------------*/ static int addCurrencySymbol ( Tcl_UniChar *p, Tcl_UniChar *result, int *i ) { Tcl_DString dStr; Tcl_UniChar *p1, *currencySymbol; int move = 0; struct lconv *lc; setlocale (LC_MONETARY, ""); lc = localeconv(); Tcl_DStringInit (&dStr); if (*(p+1) == 0xa4) { if (lc->int_curr_symbol[0] == '\0') { currencySymbol = Tcl_UtfToUniCharDString ("$", -1, &dStr); } else { currencySymbol = Tcl_UtfToUniCharDString (lc->int_curr_symbol, -1, &dStr); } move = 1; } else { if (lc->currency_symbol[0] == '\0') { currencySymbol = Tcl_UtfToUniCharDString ("$", -1, &dStr); } else { currencySymbol = Tcl_UtfToUniCharDString (lc->currency_symbol, -1, &dStr); } } p1 = currencySymbol; while (*p1 && (*i < 79)) { result[(*i)++] = *p1; p1++; } Tcl_DStringFree (&dStr); return move; } static int xsltFormatNumber ( double number, char * formatStr, xsltDecimalFormat * df, char ** resultStr, domLength * resultLen, char ** errMsg ) { Tcl_UniChar prefix1[800], prefix2[800], suffix1[800], suffix2[800]; Tcl_UniChar save = '\0', save1, t, *prefix, *suffix, n[800], f[800]; Tcl_UniChar uniCharNull = '\0'; char stmp[240], ftmp[80], *tstr; char wrongFormat[] = "Unable to interpret format pattern."; domLength l, zl, gLen; int i, j, k, g, nZero, fHash, fZero, isNeg; int prefixMinux, percentMul = 0, perMilleMul = 0; Tcl_DString dStr, s; Tcl_UniChar *format, *negformat = NULL, *p, *p1; DBG(Tcl_DString bStr;) DBG(fprintf(stderr, "number: '%f'\nformatStr='%s' \n", number, formatStr);) prefix1[0] = '\0'; prefix2[0] = '\0'; suffix1[0] = '\0'; suffix2[0] = '\0'; n[0] = '\0'; f[0] = '\n'; prefix = NULL; suffix = NULL; Tcl_DStringInit (&s); Tcl_DStringInit (&dStr); if (number < 0.0) { isNeg = 1; number *= -1.0; } else if (number == 0.0) { sprintf (stmp, "%f", number); if (stmp[0] == '-') isNeg = 1; else isNeg = 0; } else { isNeg = 0; } format = Tcl_UtfToUniCharDString (formatStr, -1, &dStr); p = format; while (*p) { if (*p == df->patternSeparator) { save = *p; *p = '\0'; negformat = ++p; break; } p++; } /* Check for more than one patternSeparator in the formatStr */ while (*p) { if (*p == df->patternSeparator) { *errMsg = tdomstrdup("More than one patternSeparator in the pattern"); goto xsltFormatNumberError; } p++; } p = format; i = 0; while (*p && (*p!=df->zeroDigit) && (*p!=df->digit) && (*p!=df->groupingSeparator) && (*p!=df->decimalSeparator)) { if (*p == df->percent) (percentMul = 1); else if (*p == df->perMille) (perMilleMul = 1); if (i<79) { if (*p == 0xa4) { p += addCurrencySymbol (p, prefix1, &i); } else { prefix1[i++] = *p; } } p++; } prefix1[i] = '\0'; nZero = fHash = fZero = 0; gLen = -2222; while (*p) { if (*p==df->digit) { if (nZero) { *errMsg = tdomstrdup(wrongFormat); goto xsltFormatNumberError; } } else if (*p==df->zeroDigit) { nZero++; } else if (*p==df->groupingSeparator) { gLen=-1; } else break; p++; gLen++; } if (*p && (*p==df->decimalSeparator)) { p++; while (*p && (*p==df->zeroDigit)) { p++; fZero++; } while (*p && (*p==df->digit)) { p++; fHash++; } } i = 0; while (*p) { /* Check for more than one decimalSeparator */ if (*p == df->decimalSeparator) { *errMsg = tdomstrdup("More than one decimalSeparator in subpattern"); goto xsltFormatNumberError; } /* Check for groupingSeparator after decimalSeparator */ if (*p == df->groupingSeparator) { *errMsg = tdomstrdup("GroupingSeparator after decimalSeparator"); goto xsltFormatNumberError; } if (*p == df->percent) (percentMul = 1); else if (*p == df->perMille) (perMilleMul = 1); if (i<79) { if (*p == 0xa4) { p += addCurrencySymbol (p, suffix1, &i); } else { suffix1[i++] = *p; } } p++; } suffix1[i] = '\0'; if (save) *p = save; if (isNeg && negformat) { /* Only prefix and suffix are taken from the second format string */ percentMul = 0; perMilleMul = 0; p++; i = 0; while (*p && *p!=df->zeroDigit && *p!=df->digit && *p!=df->groupingSeparator && *p!=df->decimalSeparator) { if (*p == df->percent) (percentMul = 1); else if (*p == df->perMille) (perMilleMul = 1); if (i<79) { if (*p == 0xa4) { p += addCurrencySymbol (p, prefix2, &i); } else { prefix2[i++] = *p; } } p++; } prefix2[i] = '\0'; while (*p && ((*p==df->zeroDigit) || (*p==df->digit) || (*p==df->groupingSeparator) || (*p==df->decimalSeparator))) p++; i = 0; while (*p) { if (*p == df->percent) (percentMul = 1); else if (*p == df->perMille) (perMilleMul = 1); if (i<79) { if (*p == 0xa4) { p += addCurrencySymbol (p, suffix2, &i); } else { suffix2[i++] = *p; } } p++; } suffix2[i] = '\0'; } if (isNeg) { if (negformat) { prefixMinux = 1; p = prefix1; p1 = prefix2; while (prefixMinux) { if (*p != *p1) { prefixMinux = 0; break; } if (*p == 0) break; p++; p1++; } if (prefixMinux) { p = suffix1; p1 = suffix2; while (prefixMinux) { if (*p != *p1) { prefixMinux = 0; break; } if (*p == 0) break; p++; p1++; } } prefix = prefix2; suffix = suffix2; } else { prefixMinux = 1; prefix = prefix1; suffix = suffix1; } if (prefixMinux) { i = 0; save = prefix[0]; prefix[0] = df->minusSign; while (i < 79) { i++; save1 = prefix[i]; prefix[i] = save; if (save == 0) break; save = save1; } if (i == 79) prefix[79] = '\0'; } } else { prefix = prefix1; suffix = suffix1; } DBG( Tcl_DStringInit (&dbStr); fprintf (stderr, "prefix: '%s' ", Tcl_UniCharToUtfDString(prefix, Tcl_UniCharLen (prefix), &dbStr)); Tcl_DStringFree (&dbStr); Tcl_DStringInit (&dbStr); fprintf (stderr, "suffix: '%s'\n", Tcl_UniCharToUtfDString(suffix, Tcl_UniCharLen (suffix), &dbStr)); Tcl_DStringFree (&dbStr); ) if (percentMul) { number *= 100.0; } else if (perMilleMul) { number *= 1000.0; } if (fHash + fZero == 0) { i = (int) (number+0.5); } else { i = (int) number; /* format fraction part */ DBG(fprintf(stderr, "formatting fraction part: '%f', fZero+fHash: '%d'\n", number - i, fZero+fHash);) sprintf(ftmp,"%.*f", fZero+fHash, number -i); DBG(fprintf(stderr, "raw formatted fraction part: '%s'\n", ftmp);) if (ftmp[0] == '1') { i++; } } DBG(fprintf(stderr,"normal part nZero=%d i=%d glen=%d\n", nZero, i, gLen);) /* fill in grouping char */ if (gLen > 0) { sprintf(stmp,"%0*d", nZero, i); l = (domLength)strlen (stmp); for (j = 0; j < l; j++) { t = df->zeroDigit + stmp[j] - 48; Tcl_DStringAppend (&s, (char*)&t, sizeof (Tcl_UniChar)); } DBG( Tcl_DStringInit(&dbStr); fprintf (stderr, "'%s' ---> ..\n", stmp); fprintf(stderr,"s='%s' isNeg=%d'\n", Tcl_UniCharToUtfDString ( (Tcl_UniChar*)Tcl_DStringValue (&s), Tcl_UniCharLen((Tcl_UniChar*)Tcl_DStringValue(&s)), &dStr ), isNeg); Tcl_DStringFree (&dbStr); ) zl = l + ((l-1) / gLen); DBG(fprintf(stderr, "l=%d zl=%d \n", l, zl);) n[zl--] = '\0'; p = (Tcl_UniChar*)Tcl_DStringValue (&s) + l - 1; g = 0; while (zl>=0) { g++; n[zl--] = *p--; if ((g == gLen) && (zl>=1)) { n[zl--] = df->groupingSeparator; g = 0; } } Tcl_DStringSetLength (&s, 0); DBG( Tcl_DStringInit (&dbStr); fprintf(stderr,"s='%s' --> ", Tcl_UniCharToUtfDString ( (Tcl_UniChar*)Tcl_DStringValue (&s), Tcl_UniCharLen((Tcl_UniChar*)Tcl_DStringValue(&s)), &dStr)); Tcl_DStringFree (&dbStr); Tcl_DStringInit (&dbStr); fprintf(stderr,"n='%s'\n", Tcl_UniCharToUtfDString (n, Tcl_UniCharLen (n), &dbStr)); Tcl_DStringFree (&dbStr); ) } else { sprintf(stmp,"%0*d", nZero, i); l = (domLength)strlen (stmp); for (j = 0; j < l; j++) { n[j] = df->zeroDigit + (int) stmp[j] - 48; } n[l] = '\0'; DBG( Tcl_DStringInit (&dbStr); fprintf(stderr,"n='%s'\n", Tcl_UniCharToUtfDString(n, Tcl_UniCharLen (n), &dbStr)); Tcl_DStringFree (&dbStr); ) } DBG(fprintf(stderr, "number=%f fHash=%d fZero=%d \n", number, fHash, fZero);) if ((fHash+fZero) > 0) { l = (domLength)strlen(ftmp); while (l>0 && fHash>0) { /* strip not need 0's */ if (ftmp[l-1] == '0') { ftmp[l-1]='\0'; l--; fHash--; } else { break; } } k = 0; if ((number - i != 0.0) || (fZero > 0)) { while (ftmp[k] != '.') k++; k++; for (j = k ; j < l; j++) { f[j] = df->zeroDigit + (int) ftmp[j] - 48; } f[l] = '\0'; } DBG(fprintf(stderr, "f='%s'\n", f);) if (prefix) { Tcl_DStringAppend (&s, (char*) prefix, Tcl_UniCharLen (prefix) * sizeof(Tcl_UniChar)); } Tcl_DStringAppend (&s, (char*) n, Tcl_UniCharLen (n) * sizeof(Tcl_UniChar)); if (k) { Tcl_DStringAppend (&s, (char*)&df->decimalSeparator, sizeof (Tcl_UniChar)); Tcl_DStringAppend (&s, (char*)&(f[k]), Tcl_UniCharLen (&(f[k])) * sizeof(Tcl_UniChar)); } if (suffix) { Tcl_DStringAppend (&s, (char *) suffix, Tcl_UniCharLen (suffix) * sizeof(Tcl_UniChar)); } Tcl_DStringAppend (&s, (char *)&uniCharNull, sizeof (Tcl_UniChar)); } else { if (prefix) { Tcl_DStringAppend (&s, (char*) prefix, Tcl_UniCharLen (prefix) * sizeof(Tcl_UniChar)); } Tcl_DStringAppend (&s, (char*) n, Tcl_UniCharLen (n) * sizeof(Tcl_UniChar)); if (suffix) { Tcl_DStringAppend (&s, (char *) suffix, Tcl_UniCharLen (suffix) * sizeof(Tcl_UniChar)); } Tcl_DStringAppend (&s, (char *)&uniCharNull, sizeof (Tcl_UniChar)); } DBG( Tcl_DStringInit (&dbStr); fprintf(stderr, "returning s='%s' \n\n", Tcl_UniCharToUtfDString( (Tcl_UniChar*)Tcl_DStringValue (&s), Tcl_UniCharLen((Tcl_UniChar*)Tcl_DStringValue(&s)), &dStr )); Tcl_DStringFree (&dbStr); ) Tcl_DStringSetLength (&dStr, 0); tstr = Tcl_UniCharToUtfDString( (Tcl_UniChar*)Tcl_DStringValue (&s), Tcl_UniCharLen((Tcl_UniChar*)Tcl_DStringValue(&s)), &dStr ); *resultStr = tdomstrdup(tstr); Tcl_DStringFree (&dStr); Tcl_DStringFree (&s); *resultLen = (domLength)strlen(*resultStr); return 0; xsltFormatNumberError: Tcl_DStringFree (&dStr); Tcl_DStringFree (&s); return -1; } static xsltNodeSet * createXsltNodeSet (void) { xsltNodeSet * ns; ns = (xsltNodeSet *) MALLOC (sizeof(xsltNodeSet)); ns->nodes = (domNode**)MALLOC(INITIAL_SIZE_FOR_KEYSETS * sizeof(domNode*)); ns->allocated = INITIAL_SIZE_FOR_KEYSETS; ns->nr_nodes = 0; return ns; } /* Helper proc for buildKeyInfoForDoc. Adds node to the node set ns at the right position (in document order), if not already present. This is the same as the core of rsAddNode does. The used method to add may look a bit simpleminded, but experience shows, that in the vast majority of the cases node simply has to be appended to the array. */ static void nsAddNode ( xsltNodeSet *ns, domNode *node ) { domLength insertIndex, i; insertIndex = ns->nr_nodes; for (i = ns->nr_nodes - 1; i >= 0; i--) { if (node == ns->nodes[i]) return; if (!domPrecedes (node, ns->nodes[i])) { break; } insertIndex--; } if (ns->nr_nodes + 1 >= ns->allocated) { ns->nodes = (domNode**)REALLOC((void*)ns->nodes, 2 * ns->allocated * sizeof(domNode*)); ns->allocated *= 2; } if (insertIndex == ns->nr_nodes) { ns->nodes[ns->nr_nodes++] = node; } else { for (i = ns->nr_nodes - 1; i >= insertIndex; i--) { ns->nodes[i+1] = ns->nodes[i]; } ns->nodes[insertIndex] = node; ns->nr_nodes++; } } static int buildKeyInfoForDoc ( xsltSubDoc *sd, char *keyId, Tcl_HashTable *keyInfos, xsltState *xs, char **errMsg ) { int hnew, rc, docOrder, i; char *useValue; domNode *node, *savedCurrent; xpathResultSet rs, context; Tcl_HashTable *valueTable; Tcl_HashEntry *h; xsltKeyInfo *kinfo, *kinfoStart; xsltNodeSet *keyValues; h = Tcl_FindHashEntry (keyInfos, keyId); /* key must exist, this is already checked */ kinfoStart = (xsltKeyInfo *) Tcl_GetHashValue (h); /* this must be a new entry, no check for hnew==1 needed */ h = Tcl_CreateHashEntry (&(sd->keyData), keyId, &hnew); valueTable = (Tcl_HashTable *)MALLOC(sizeof (Tcl_HashTable)); Tcl_InitHashTable (valueTable, TCL_STRING_KEYS); Tcl_SetHashValue (h, valueTable); savedCurrent = xs->current; node = sd->doc->rootNode; while (node) { kinfo = kinfoStart; while (kinfo) { rc = xpathMatches (kinfo->matchAst, kinfo->node, node, &(xs->cbs), errMsg); if (rc < 0) { TRACE1("xpathMatches had errors '%s' \n", *errMsg); return rc; } if (rc > 0) { TRACE("found match for key !\n"); xpathRSInit (&rs); xpathRSInit (&context); rsAddNode (&context, node); DBG(printXML(node, 0, 2);) docOrder = 1; xs->current = node; rc = xpathEvalSteps (kinfo->useAst, &context, node, kinfo->node, 0, &docOrder, &(xs->cbs), &rs, errMsg); if (rc != XPATH_OK) { xpathRSFree (&rs); xpathRSFree (&context); return rc; } DBG(rsPrint(&rs)); if (rs.type == xNodeSetResult) { for (i = 0; i < rs.nr_nodes; i++) { useValue = xpathFuncStringForNode (rs.nodes[i]); TRACE1("use value = '%s'\n", useValue); h = Tcl_CreateHashEntry (valueTable, useValue, &hnew); if (hnew) { keyValues = createXsltNodeSet(); } else { keyValues = (xsltNodeSet *) Tcl_GetHashValue (h); } nsAddNode (keyValues, node); if (hnew) Tcl_SetHashValue (h, keyValues); FREE(useValue); } } else if (rs.type != EmptyResult) { useValue = xpathFuncString (&rs); TRACE1("use value = '%s'\n", useValue); h = Tcl_CreateHashEntry (valueTable, useValue, &hnew); if (hnew) { keyValues = createXsltNodeSet(); } else { keyValues = (xsltNodeSet *) Tcl_GetHashValue (h); } nsAddNode (keyValues, node); if (hnew) Tcl_SetHashValue (h, keyValues); FREE(useValue); } xpathRSFree( &context ); xpathRSFree( &rs ); } kinfo = kinfo->next; } if ((node->nodeType == ELEMENT_NODE) && (node->firstAttr)) { node = (domNode*) node->firstAttr; continue; } if (node->nodeType == ATTRIBUTE_NODE) { if (((domAttrNode*)node)->nextSibling) { node = (domNode*) ((domAttrNode*)node)->nextSibling; continue; } node = ((domAttrNode*)node)->parentNode; } if ((node->nodeType == ELEMENT_NODE) && (node->firstChild)) { node = node->firstChild; continue; } if (node->nextSibling) { node = node->nextSibling; continue; } while ( node->parentNode && (node->parentNode->nextSibling == NULL) ) { node = node->parentNode; } if (node->parentNode) { node = node->parentNode->nextSibling; } else { break; } } xs->current = savedCurrent; return 0; } /*---------------------------------------------------------------------------- | sortNodeSetByNodeNumber | \---------------------------------------------------------------------------*/ static void sortNodeSetByNodeNumber( domNode *nodes[], domLength n ) { domLength i, j, ln, rn; domNode *tmp; while (n > 1) { tmp = nodes[0]; nodes[0] = nodes[n/2]; nodes[n/2] = tmp; for (i = 0, j = n; ; ) { do { --j; } while (domPrecedes (nodes[0], nodes[j])); do { ++i; } while (i < j && domPrecedes (nodes[i], nodes[0])); if (i >= j) break; tmp = nodes[i]; nodes[i] = nodes[j]; nodes[j] = tmp; } tmp = nodes[j]; nodes[j] = nodes[0]; nodes[0] = tmp; ln = j; rn = n - ++j; if (ln < rn) { sortNodeSetByNodeNumber(nodes, ln); nodes += j; n = rn; } else { sortNodeSetByNodeNumber(&(nodes[j]), rn); n = ln; } } } /*---------------------------------------------------------------------------- | sortByDocOrder | \---------------------------------------------------------------------------*/ void sortByDocOrder ( xpathResultSet * rs ) { if (rs->type != xNodeSetResult) return; sortNodeSetByNodeNumber(rs->nodes, rs->nr_nodes); } /*---------------------------------------------------------------------------- | StripXMLSpace | \---------------------------------------------------------------------------*/ static void StripXMLSpace ( xsltState * xs, domNode * node ) { domNode *child, *newChild, *parent; size_t i, len; int onlySpace, found, strip; char *p, prefix[MAX_PREFIX_LEN]; const char *localName; double *f; domNS *ns; Tcl_HashEntry *h; Tcl_DString dStr; if (node->nodeType == TEXT_NODE) { p = ((domTextNode*)node)->nodeValue; len = ((domTextNode*)node)->valueLength; onlySpace = 1; for (i=0; iparentNode; while (parent) { p = getAttr(parent,"xml:space", a_space); if (p!=NULL) { if (strcmp(p,"preserve")==0) return; if (strcmp(p,"default")==0) break; } parent = parent->parentNode; } DBG(fprintf(stderr, "removing domNode0x%x(len %d) under '%s' \n", node, len, node->parentNode->nodeName);) domDeleteNode (node, NULL, NULL); } } else if (node->nodeType == ELEMENT_NODE) { if (node->firstChild == NULL) return; strip = xs->wsInfo.stripAll; found = 0; if (node->namespace) { domSplitQName (node->nodeName, prefix, &localName); } else { prefix[0] = '\0'; localName = node->nodeName; } ns = NULL; Tcl_DStringInit (&dStr); if (prefix[0] != '\0') { ns = domLookupPrefix (node, prefix); if (ns) { Tcl_DStringAppend (&dStr, ns->uri, -1); Tcl_DStringAppend (&dStr, ":*", 2); if (xs->wsInfo.stripAll) { h = Tcl_FindHashEntry (&xs->wsInfo.preserveTokens, Tcl_DStringValue (&dStr)); } else { h = Tcl_FindHashEntry (&xs->wsInfo.stripTokens, Tcl_DStringValue (&dStr)); } if (h) { f = Tcl_GetHashValue (h); if (*f >= xs->wsInfo.wildcardPrec) { strip = !xs->wsInfo.stripAll; found = 1; } } if (!found) { Tcl_DStringFree (&dStr); Tcl_DStringInit (&dStr); Tcl_DStringAppend (&dStr, ns->uri, -1); Tcl_DStringAppend (&dStr, ":", 1); } } } if (!found) { Tcl_DStringAppend (&dStr, localName, -1); if (xs->wsInfo.stripAll) { h = Tcl_FindHashEntry (&xs->wsInfo.preserveTokens, Tcl_DStringValue (&dStr)); } else { h = Tcl_FindHashEntry (&xs->wsInfo.stripTokens, Tcl_DStringValue (&dStr)); } if (h) { f = Tcl_GetHashValue (h); if (*f >= xs->wsInfo.wildcardPrec) { strip = !xs->wsInfo.stripAll; } } } Tcl_DStringFree (&dStr); if (strip) { child = node->firstChild; while (child) { newChild = child->nextSibling; StripXMLSpace (xs, child); child = newChild; } } else { child = node->firstChild; while (child) { if (child->nodeType == ELEMENT_NODE) { StripXMLSpace (xs, child); } child = child->nextSibling; } } } } /*---------------------------------------------------------------------------- | xsltXPathFuncs | \---------------------------------------------------------------------------*/ static int xsltXPathFuncs ( void * clientData, char * funcName, domNode * ctxNode, domLength ctxPos, xpathResultSet * ctx, domNode * exprContext, int argc, xpathResultSets * argv, xpathResultSet * result, char ** errMsg ) { xsltState * xs = clientData; char * keyId, *filterValue, *str = NULL; char prefix[MAX_PREFIX_LEN]; const char * localName, *baseURI, *nsStr; int rc, NaN, freeStr; domLength i, len, x; double n; xsltNodeSet * keyValues; Tcl_HashEntry * h; Tcl_HashTable * docKeyData; xsltSubDoc * sdoc; domDocument * ownerDoc; Tcl_DString dStr; domNS * ns; xsltDecimalFormat * df; DBG ( fprintf(stderr,"xsltXPathFuncs funcName='%s'\n",funcName); ) if (strcmp(funcName, "key")==0) { /*-------------------------------------------------------------------- | 'key' function \-------------------------------------------------------------------*/ DBG(fprintf(stderr,"xslt key function called!\n");) if (argc != 2) { reportError (exprContext, "key() needs two arguments!", errMsg); return -1; } /* check, if there is a key definition with the given name */ keyId = xpathFuncString(argv[0]); TRACE1("keyId='%s' \n", keyId); domSplitQName (keyId, prefix, &localName); Tcl_DStringInit (&dStr); if (prefix[0] != '\0') { ns = domLookupPrefix (exprContext, prefix); if (!ns) { reportError (exprContext, "There isn't a namespace bound to" " the prefix.", errMsg); FREE(keyId); return -1; } Tcl_DStringAppend (&dStr, ns->uri, -1); } Tcl_DStringAppend (&dStr, localName, -1); FREE(keyId); h = Tcl_FindHashEntry (&xs->keyInfos, Tcl_DStringValue (&dStr)); if (!h) { reportError (exprContext, "Unknown key in key() function call!", errMsg); Tcl_DStringFree (&dStr); return -1; } /* Short cut for empty result sets. */ if (argv[1]->type == EmptyResult) { Tcl_DStringFree (&dStr); return 0; } /* find the doc, the context node belongs to */ sdoc = xs->subDocs; if (ctxNode->nodeType == ATTRIBUTE_NODE) { ownerDoc = ((domAttrNode *)ctxNode)->parentNode->ownerDocument; } else { ownerDoc = ctxNode->ownerDocument; } while (sdoc) { if (sdoc->doc == ownerDoc) break; sdoc = sdoc->next; } DBG(if (!sdoc) fprintf (stderr, "key() function: ctxNode doesn't belong to a doc out of subDocs!!! This could not happen!. ERROR\n"); else (fprintf (stderr, "key() function: ctxNode belongs to doc %s\n", sdoc->baseURI));) h = Tcl_FindHashEntry (&(sdoc->keyData), Tcl_DStringValue (&dStr)); if (!h) { if (buildKeyInfoForDoc(sdoc, Tcl_DStringValue (&dStr), &(xs->keyInfos),xs,errMsg)<0) { Tcl_DStringFree (&dStr); return -1; } h = Tcl_FindHashEntry (&(sdoc->keyData), Tcl_DStringValue (&dStr)); } Tcl_DStringFree (&dStr); docKeyData = (Tcl_HashTable *) Tcl_GetHashValue (h); if (argv[1]->type == xNodeSetResult) { for (i = 0; i < argv[1]->nr_nodes; i++) { filterValue = xpathFuncStringForNode (argv[1]->nodes[i]); TRACE1("filterValue='%s' \n", filterValue); h = Tcl_FindHashEntry (docKeyData, filterValue); if (h) { keyValues = (xsltNodeSet *) Tcl_GetHashValue (h); if (result->type == EmptyResult) { result->type = xNodeSetResult; result->nodes = keyValues->nodes; result->intvalue = 1; result->nr_nodes = keyValues->nr_nodes; result->allocated = keyValues->allocated; } else { for (x = 0; x < keyValues->nr_nodes; x++) { rsAddNode(result, keyValues->nodes[x]); } } } FREE(filterValue); } } else { filterValue = xpathFuncString(argv[1]); TRACE1("filterValue='%s' \n", filterValue); h = Tcl_FindHashEntry (docKeyData, filterValue); if (h) { keyValues = (xsltNodeSet *) Tcl_GetHashValue (h); if (result->type == EmptyResult) { result->type = xNodeSetResult; result->nodes = keyValues->nodes; result->intvalue = 1; result->nr_nodes = keyValues->nr_nodes; result->allocated = keyValues->allocated; } else { for (x = 0; x < keyValues->nr_nodes; x++) { rsAddNode(result, keyValues->nodes[x]); } } } FREE(filterValue); } return 0; } else if (strcmp(funcName, "current")==0) { /*-------------------------------------------------------------------- | 'current' function \-------------------------------------------------------------------*/ DBG(fprintf(stderr, "xsltXPathFuncs 'current' = 'domNode0x%x' \n", xs->current);) if (argc != 0) { reportError (exprContext, "current() must not have any arguments", errMsg); return -1; } rsAddNode(result, xs->current); return 0; } else if (strcmp (funcName, "format-number")==0) { /*-------------------------------------------------------------------- | 'format-number' function \-------------------------------------------------------------------*/ DBG(fprintf(stderr, "before format-number argc=%d \n", argc);) if (argc == 3) { str = xpathFuncString (argv[2]); domSplitQName (str, prefix, &localName); ns = NULL; if (prefix[0] != '\0') { ns = domLookupPrefix (exprContext, prefix); if (!ns) { reportError (exprContext, "There isn't a namespace bound" " to the prefix.", errMsg); FREE(str); return -1; } } df = xs->decimalFormats->next; while (df) { if (strcmp(df->name, str)==0 && ((df->uri == NULL && ns == NULL) || (df->uri != NULL && ns != NULL && (strcmp (df->uri, ns->uri)==0)))) { break; } df = df->next; } FREE(str); if (df == NULL) { reportError (exprContext, "There isn't a decimal format with" " this name.", errMsg); return -1; } } else if (argc == 2) { df = xs->decimalFormats; } else { reportError (exprContext, "format-number: wrong # parameters:" " format-number(number, string, ?string?)!", errMsg); return -1; } NaN = 0; n = xpathFuncNumber (argv[0], &NaN); if (NaN) { if (NaN == 2) rsSetString (result, df->NaN); else if (NaN == 1) rsSetString (result, df->infinity); else { Tcl_DStringInit (&dStr); Tcl_DStringAppend (&dStr, "-", 1); Tcl_DStringAppend (&dStr, df->infinity, -1); rsSetString (result, Tcl_DStringValue (&dStr)); } return 0; } str = xpathFuncString (argv[1]); DBG(fprintf(stderr, "1 str='%s' \n", str);) result->type = StringResult; rc = xsltFormatNumber(n, str, df, &(result->string), &(result->string_len), errMsg); FREE(str); if (rc < 0) { result->type = EmptyResult; return rc; } DBG(fprintf(stderr, "after format-number \n");) return 0; } else if (strcmp (funcName, "document")==0) { /*-------------------------------------------------------------------- | 'document' function \-------------------------------------------------------------------*/ DBG(fprintf(stderr, "xsltXPathFuncs 'document' \n");) if (argc == 1) { if (argv[0]->type == xNodeSetResult) { for (i = 0; i < argv[0]->nr_nodes; i++) { freeStr = 0; if (argv[0]->nodes[i]->nodeType == ATTRIBUTE_NODE) { nsStr = ((domAttrNode*)argv[0]->nodes[i])->nodeValue; baseURI = findBaseURI (((domAttrNode*)argv[0]->nodes[i])->parentNode); } else { str = xpathGetStringValue (argv[0]->nodes[i], &len); nsStr = str; freeStr = 1; baseURI = findBaseURI (argv[0]->nodes[i]); } /* the case document('') */ if (*nsStr == '\0') { if (freeStr) { FREE(str); freeStr = 0; } nsStr = baseURI; } if (xsltAddExternalDocument(xs, baseURI, nsStr, 0, result, errMsg) < 0) { if (freeStr) FREE(str); return -1; } if (xs->wsInfo.hasData) { StripXMLSpace (xs, xs->subDocs->doc->documentElement); } if (freeStr) FREE(str); } } else { str = xpathFuncString (argv[0]); nsStr = str; if (xs->currentXSLTNode) { baseURI = findBaseURI (xs->currentXSLTNode); } else if (xs->currentTplRule) { baseURI = findBaseURI (xs->currentTplRule->content); } else { baseURI = findBaseURI (xs->xsltDoc->rootNode); } if (*nsStr == '\0') { nsStr = baseURI; } DBG (fprintf (stderr, "document() call, with 1 string arg = '%s'\n", str);) if (xsltAddExternalDocument(xs, baseURI, nsStr, 1, result, errMsg) < 0) { FREE(str); return -1; } if (xs->wsInfo.hasData) { StripXMLSpace (xs, xs->subDocs->doc->documentElement); } FREE(str); } } else if (argc == 2) { if (argv[1]->type != xNodeSetResult) { reportError (exprContext, "second arg of document() has to be" " a nodeset!", errMsg); return -1; } if (argv[1]->nodes[0]->nodeType == ATTRIBUTE_NODE) { baseURI = findBaseURI (((domAttrNode*)argv[1]->nodes[0])->parentNode); } else { baseURI = findBaseURI (argv[1]->nodes[0]); } if (argv[0]->type == xNodeSetResult) { for (i = 0; i < argv[0]->nr_nodes; i++) { freeStr = 0; if (argv[0]->nodes[i]->nodeType == ATTRIBUTE_NODE) { nsStr = ((domAttrNode*)argv[0]->nodes[i])->nodeValue; } else { str = xpathGetStringValue (argv[0]->nodes[i], &len); freeStr = 1; nsStr = str; } if (*nsStr == '\0') { if (freeStr) FREE(str); freeStr = 0; nsStr = baseURI; } if (xsltAddExternalDocument(xs, baseURI, nsStr, 0, result, errMsg) < 0) { if (freeStr) FREE(str); return -1; } if (xs->wsInfo.hasData) { StripXMLSpace (xs, xs->subDocs->doc->documentElement); } if (freeStr) FREE(str); } } else { str = xpathFuncString (argv[0]); nsStr = str; if (*str == '\0') { nsStr = baseURI; } if (xsltAddExternalDocument(xs, baseURI, nsStr, 0, result, errMsg) < 0) { FREE(str); return -1; } if (xs->wsInfo.hasData) { StripXMLSpace (xs, xs->subDocs->doc->documentElement); } FREE(str); } } else { reportError (exprContext, "wrong # of args in document() call!", errMsg); return -1; } return 0; } else { /* chain back to original callback */ if (xs->orig_funcCB) { return (xs->orig_funcCB)(xs->orig_funcClientData, funcName, ctxNode, ctxPos, ctx, exprContext, argc, argv, result, errMsg); } } return 0; } /*---------------------------------------------------------------------------- | evalXPath | \---------------------------------------------------------------------------*/ static int evalXPath ( xsltState * xs, xpathResultSet * context, domNode * currentNode, domLength currentPos, char * xpath, xpathResultSet * rs, char ** errMsg ) { int rc, hnew, docOrder = 1; ast t; domNode *savedCurrent; Tcl_HashEntry *h; h = Tcl_CreateHashEntry (&(xs->xpaths), xpath, &hnew); if (!hnew) { t = (ast)Tcl_GetHashValue(h); } else { rc = xpathParse (xpath, xs->currentXSLTNode, XPATH_EXPR, NULL, NULL, &t, errMsg); if (rc < 0) { reportError (xs->currentXSLTNode, *errMsg, errMsg); return rc; } Tcl_SetHashValue(h, t); } xpathRSInit( rs ); DBG(fprintf (stderr, "evalXPath evaluating xpath:\n");) DBG(printAst(3,t);) savedCurrent = xs->current; xs->current = currentNode; rc = xpathEvalSteps( t, context, currentNode, xs->currentXSLTNode, currentPos, &docOrder, &(xs->cbs), rs, errMsg); xs->current = savedCurrent; if (rc != XPATH_OK) { reportError (xs->currentXSLTNode, *errMsg, errMsg); xpathRSFree( rs ); } return rc; } /*---------------------------------------------------------------------------- | nodeGreater | \---------------------------------------------------------------------------*/ static int nodeGreater ( int typeText, int asc, int upperFirst, char * strA, char * strB, double realA, double realB, int * greater ) { int rc; char *strAptr, *strBptr; domLength lenA, lenB, len; Tcl_UniChar unicharA, unicharB; *greater = 0; if (typeText) { lenA = Tcl_NumUtfChars (strA, -1); lenB = Tcl_NumUtfChars (strB, -1); len = (lenA < lenB ? lenA : lenB); rc = Tcl_UtfNcasecmp (strA, strB, len); if (rc == 0) { if (lenA > lenB) { rc = 1; } else if (lenA < lenB) { rc = -1; } } if (rc == 0) { strAptr = strA; strBptr = strB; while (len-- > 0) { strAptr += Tcl_UtfToUniChar(strAptr, &unicharA); strBptr += Tcl_UtfToUniChar(strBptr, &unicharB); if (unicharA != unicharB) { rc = unicharA - unicharB; break; } } if (!upperFirst) { rc *= -1; } } if (asc) *greater = (rc > 0); else *greater = (rc < 0); } else { DBG( fprintf(stderr, "nodeGreater realA='%f' realB='%f'\n",realA, realB);) if (IS_NAN (realA) || IS_NAN (realB)) { if (asc) { if (IS_NAN (realA) && !IS_NAN (realB)) { *greater = 0; } else { if (IS_NAN (realB) && !IS_NAN (realA)) *greater = 1; } } else { if (IS_NAN (realA) && !IS_NAN(realB)) { *greater = 1; } else { if (IS_NAN (realB) && !IS_NAN(realA)) *greater = 0; } } } else { if (asc) *greater = (realA > realB); else *greater = (realA < realB); } } return 0; } static int fastMergeSort ( int txt, int asc, int upperFirst, domNode * a[], domLength * posa, domNode * b[], domLength * posb, char ** vs, double * vd, char ** vstmp, double * vdtmp, domLength size, char ** errMsg ) { domNode *tmp; domLength tmpPos, lptr, rptr, middle, i, j; int gt, rc; char *tmpVs; double tmpVd; if (size < 10) { /* use simple and fast insertion for small sizes ! */ for (i = 1; i < size; i++) { tmp = a [i]; tmpPos = posa [i]; tmpVs = vs [i]; tmpVd = vd [i]; j = i; if (j>0) { rc = nodeGreater(txt, asc, upperFirst, vs[j-1], tmpVs, vd[j-1], tmpVd, >); CHECK_RC; } while ( j > 0 && gt) { a [j] = a [j-1]; posa[j] = posa[j-1]; vs [j] = vs [j-1]; vd [j] = vd [j-1]; j--; if (j>0) { rc = nodeGreater(txt, asc, upperFirst, vs[j-1], tmpVs, vd[j-1], tmpVd, >); CHECK_RC; } } a [j] = tmp; posa[j] = tmpPos; vs [j] = tmpVs; vd [j] = tmpVd; } return 0; } middle = size/2; rc = fastMergeSort(txt, asc, upperFirst, a, posa, b, posb, vs, vd, vstmp, vdtmp, middle, errMsg); CHECK_RC; rc = fastMergeSort(txt, asc, upperFirst, a+middle, posa+middle, b+middle, posb+middle, vs+middle, vd+middle, vstmp+middle, vdtmp+middle, size-middle, errMsg); CHECK_RC; lptr = 0; rptr = middle; for (i = 0; i < size; i++) { if (lptr == middle) { b [i] = a [rptr ]; posb [i] = posa[rptr ]; vstmp[i] = vs [rptr ]; vdtmp[i] = vd [rptr++]; } else if (rptr < size) { rc = nodeGreater(txt, asc, upperFirst, vs[lptr], vs[rptr], vd[lptr], vd[rptr], >); if (gt) { b [i] = a [rptr ]; posb [i] = posa[rptr ]; vstmp[i] = vs [rptr ]; vdtmp[i] = vd [rptr++]; } else { b [i] = a [lptr ]; posb [i] = posa[lptr ]; vstmp[i] = vs [lptr ]; vdtmp[i] = vd [lptr++]; } } else { b [i] = a [lptr ]; posb [i] = posa[lptr ]; vstmp[i] = vs [lptr ]; vdtmp[i] = vd [lptr++]; } } memcpy(a, b, size*sizeof(domNode*)); memcpy(posa, posb, size*sizeof(domLength)); memcpy(vs, vstmp, size*sizeof(char*)); memcpy(vd, vdtmp, size*sizeof(double)); return 0; } static int sortNodeSetFastMerge( int txt, int asc, int upperFirst, domNode * nodes[], domLength n, char ** vs, double * vd, domLength * pos, char ** errMsg ) { domNode **b; domLength *posb; char **vstmp; double *vdtmp; int rc; b = (domNode **)MALLOC(n * sizeof(domNode *)); posb = (domLength *)MALLOC(n * sizeof(domLength)); vstmp = (char **)MALLOC(sizeof (char *) * n); vdtmp = (double *)MALLOC(sizeof (double) * n); rc = fastMergeSort(txt, asc, upperFirst, nodes, pos, b, posb, vs, vd, vstmp, vdtmp, n, errMsg); FREE((char*)posb); FREE((char*)b); FREE((char*)vstmp); FREE((char*)vdtmp); CHECK_RC; return 0; } /*---------------------------------------------------------------------------- | xsltSetVar | \---------------------------------------------------------------------------*/ static int xsltSetVar ( xsltState * xs, char * variableName, xpathResultSet * context, domNode * currentNode, domLength currentPos, char * select, domNode * actionNode, int active, char ** errMsg ) { xsltVariable * var; int rc; xpathResultSet rs; xsltVarFrame *tmpFrame = NULL; domNode *fragmentNode, *savedLastNode; char prefix[MAX_PREFIX_LEN]; const char *localName; domNS *ns; TRACE1("xsltSetVar variableName='%s' \n", variableName); if (select!=NULL) { TRACE2("xsltSetVar variableName='%s' select='%s'\n", variableName, select); rc = evalXPath (xs, context, currentNode, currentPos, select, &rs, errMsg); CHECK_RC; } else { if (!actionNode->firstChild) { xpathRSInit (&rs); rsSetString (&rs, ""); } else { fragmentNode = domNewElementNode(xs->resultDoc, ""); savedLastNode = xs->lastNode; xs->lastNode = fragmentNode; /* process the children as well */ xsltPushVarFrame (xs); rc = ExecActions(xs, context, currentNode, currentPos, actionNode->firstChild, errMsg); xsltPopVarFrame (xs); CHECK_RC; xpathRSInit(&rs); rsAddNodeFast(&rs, fragmentNode); xs->lastNode = savedLastNode; } } tmpFrame = &xs->varFramesStack[xs->varFramesStackPtr]; xs->varStackPtr++; if (xs->varStackPtr >= xs->varStackLen) { xs->varStack = (xsltVariable *) REALLOC ((char*)xs->varStack, sizeof (xsltVariable) * 2 * xs->varStackLen); xs->varStackLen *= 2; } var = &(xs->varStack[xs->varStackPtr]); if (tmpFrame->varStartIndex == -1) { tmpFrame->varStartIndex = xs->varStackPtr; } tmpFrame->nrOfVars++; domSplitQName (variableName, prefix, &localName); if (prefix[0] != '\0') { ns = domLookupPrefix (actionNode, prefix); if (!ns) { reportError (actionNode, "There isn't a namespace bound to" " the prefix.", errMsg); return -1; } var->uri = ns->uri; var->name = localName; } else { var->uri = NULL; var->name = variableName; } tmpFrame->polluted = 1; var->node = actionNode; var->rs = rs; var->active = active; DBG(rsPrint(&(var->rs))); return 0; } /*---------------------------------------------------------------------------- | xsltVarExists | \---------------------------------------------------------------------------*/ static int xsltVarExists ( xsltState * xs, char * variableName, domNode * exprContext ) { int i, frameIndex, found = 0; char prefix[MAX_PREFIX_LEN]; const char *localName, *uri, *varName; domNS *ns; xsltVarFrame *frame; TRACE1("xsltVarExists variableName='%s' \n", variableName); domSplitQName (variableName, prefix, &localName); if (prefix[0]) { ns = domLookupPrefix (exprContext, prefix); if (!ns) { /* TODO: this is an error, not only 'not found' */ return 0; } uri = ns->uri; varName = localName; } else { uri = NULL; varName = variableName; } frameIndex = xs->varFramesStackPtr; while (frameIndex >= 0) { frame = &xs->varFramesStack[frameIndex]; for (i = frame->varStartIndex; i < frame->varStartIndex + frame->nrOfVars; i++) { if ( (uri && !((&xs->varStack[i])->uri)) || (!uri && (&xs->varStack[i])->uri) || (uri && (&xs->varStack[i])->uri && (strcmp (uri, (&xs->varStack[i])->uri)!=0)) ) continue; if (strcmp((&xs->varStack[i])->name, varName)==0) { found = 1; (&xs->varStack[i])->active = 1; break; /* found the variable */ } } if (found) return 1; if (frame->stop) break; frameIndex--; } return 0; } /*---------------------------------------------------------------------------- | xsltGetVar | \---------------------------------------------------------------------------*/ static int xsltGetVar ( void * clientData, char * variableName, char * varURI, xpathResultSet * result, char **errMsg ) { xsltState *xs = clientData; xsltVarFrame *frame; xsltVariable *var; int rc, i, frameIndex, parFrameSkiped = 0; char *select; Tcl_HashEntry *h; xsltTopLevelVar *topLevelVar; xsltVarInProcess *varInProcess, thisVarInProcess; xpathResultSet nodeList; domNode *savedCurrentXSLTNode; Tcl_DString dErrMsg; TRACE1("xsltGetVar variableName='%s' \n", variableName); frameIndex = xs->varFramesStackPtr; while (frameIndex >= 0) { frame = &xs->varFramesStack[frameIndex]; if (frame->stop == 2 && !parFrameSkiped) { parFrameSkiped = 1; frameIndex--; continue; } for (i = frame->varStartIndex; i < frame->varStartIndex + frame->nrOfVars; i++) { var = &xs->varStack[i]; if (!var->active) continue; if ( (varURI && !var->uri) || (!varURI && var->uri) || (varURI && var->uri && (strcmp (varURI, var->uri)!=0)) ) continue; if (strcmp(var->name, variableName)==0) { TRACE1("xsltGetVar '%s':\n", variableName); DBG(rsPrint(&(var->rs))); rsCopy(result, &(var->rs) ); return XPATH_OK; } } if ((frame->stop == 1) && frameIndex > 1) frameIndex = 1; frameIndex--; } if (xs->varsInProcess) { h = Tcl_FindHashEntry (&xs->topLevelVars, variableName); if (h) { topLevelVar = (xsltTopLevelVar *) Tcl_GetHashValue (h); /* check for circular definitions */ varInProcess = xs->varsInProcess; while (varInProcess) { if (strcmp(varInProcess->name, variableName)==0) { reportError (topLevelVar->node, "circular top level" " variabale definition detected", errMsg); return XPATH_EVAL_ERR; } varInProcess = varInProcess->next; } thisVarInProcess.name = variableName; thisVarInProcess.next = xs->varsInProcess; xs->varsInProcess = &thisVarInProcess; xpathRSInit( &nodeList ); rsAddNodeFast( &nodeList, xs->xmlRootNode); savedCurrentXSLTNode = xs->currentXSLTNode; xs->currentXSLTNode = topLevelVar->node; select = getAttr (topLevelVar->node, "select", a_select); rc = xsltSetVar (xs, variableName, &nodeList, xs->xmlRootNode, 0, select, topLevelVar->node, 1, errMsg); xpathRSFree ( &nodeList ); CHECK_RC; rc = xsltGetVar (xs, variableName, varURI, result, errMsg); CHECK_RC; /* remove var out of the varsInProcess list. Should be first in the list, shouldn't it? */ varInProcess = xs->varsInProcess; if (varInProcess != &thisVarInProcess) { reportError (topLevelVar->node, "Error in top level" " vars processing.", errMsg); return XPATH_EVAL_ERR; } xs->varsInProcess = varInProcess->next; xs->currentXSLTNode = savedCurrentXSLTNode; return XPATH_OK; } } Tcl_DStringInit (&dErrMsg); Tcl_DStringAppend (&dErrMsg, "Variable \"", -1); Tcl_DStringAppend (&dErrMsg, variableName, -1); Tcl_DStringAppend (&dErrMsg, "\" has not been declared.", -1); reportError (xs->currentXSLTNode, Tcl_DStringValue (&dErrMsg), errMsg); Tcl_DStringFree (&dErrMsg); return XPATH_EVAL_ERR; } /*---------------------------------------------------------------------------- | addMatch | \---------------------------------------------------------------------------*/ static int addMatch ( xsltState *xs, domNode *node, xsltTemplate *tpl, char *prioStr, ast a, char **errMsg ) { xsltTemplate *t, *prevTpl; int rc, hnew; Tcl_DString dStr; Tcl_HashEntry *h; if (a->type == CombinePath) { t = (xsltTemplate *)MALLOC(sizeof(xsltTemplate)); t->freeAst = NULL; t->name = NULL; t->nameURI = NULL; t->mode = tpl->mode; t->modeURI = tpl->modeURI; t->content = tpl->content; t->precedence = tpl->precedence; t->sDoc = tpl->sDoc; t->next = NULL; if (prioStr) { t->prio = tpl->prio; } rc = addMatch (xs, node, t, prioStr, a->child->child, errMsg); CHECK_RC1(t); tpl->ast = a->child->next->child; } else { tpl->ast = a; } if (!prioStr) { tpl->prio = xpathGetPrio(tpl->ast); TRACE1("prio = %f for \n", tpl->prio); DBG(printAst( 0, tpl->ast);) TRACE("\n"); } if ((tpl->ast->type == IsElement && tpl->ast->strvalue[0] != '*') || tpl->ast->type == IsFQElement) { Tcl_DStringInit (&dStr); if (tpl->ast->type == IsFQElement) { Tcl_DStringAppend (&dStr, tpl->ast->strvalue, -1); Tcl_DStringAppend (&dStr, ":", 1); } if (tpl->mode) { if (tpl->modeURI) { Tcl_DStringAppend (&dStr, tpl->modeURI, -1); Tcl_DStringAppend (&dStr, ":", 1); } Tcl_DStringAppend (&dStr, tpl->mode, -1); Tcl_DStringAppend (&dStr, ":", 1); } if (tpl->ast->type == IsFQElement) { Tcl_DStringAppend (&dStr, tpl->ast->child->strvalue, -1); } else { Tcl_DStringAppend (&dStr, tpl->ast->strvalue, -1); } h = Tcl_CreateHashEntry (&(xs->isElementTpls), Tcl_DStringValue (&dStr), &hnew); Tcl_DStringFree (&dStr); if (hnew) { tpl->next = NULL; Tcl_SetHashValue (h, tpl); } else { t = (xsltTemplate *) Tcl_GetHashValue (h); prevTpl = NULL; while ( t && t->precedence >= tpl->precedence && t->prio > tpl->prio) { prevTpl = t; t = t->next; } if (prevTpl) { tpl->next = t; prevTpl->next = tpl; } else { tpl->next = Tcl_GetHashValue (h); Tcl_SetHashValue (h, tpl); } } } else { if (xs->templates == NULL) { xs->templates = tpl; } else { t = xs->templates; prevTpl = NULL; while ( t && t->precedence >= tpl->precedence && t->prio > tpl->prio) { prevTpl = t; t = t->next; } if (prevTpl) { tpl->next = t; prevTpl->next = tpl; } else { tpl->next = xs->templates; xs->templates = tpl; } } } TRACE5("AddTemplate '%s' '%s' '%s' '%s' '%2.2f' \n\n", tpl->match, tpl->name, tpl->mode, tpl->modeURI, tpl->prio); return 0; } /*---------------------------------------------------------------------------- | xsltAddTemplate | \---------------------------------------------------------------------------*/ static int xsltAddTemplate ( xsltState *xs, domNode *node, double precedence, char **errMsg ) { xsltTemplate *tpl, *t; char *prioStr, *str, prefix[MAX_PREFIX_LEN], *tailptr; const char *localName; int rc, hnew; domNS *ns; Tcl_HashEntry *h; Tcl_DString dStr; xsltSubDoc *sDoc; tpl = (xsltTemplate *)MALLOC(sizeof(xsltTemplate)); tpl->match = getAttr(node,"match", a_match); str = getAttr(node, "name", a_name); if (!tpl->match && !str) { reportError (node, " xsl:template must have a name or" " match attribute (or both)", errMsg); FREE ((char*)tpl); return -1; } tpl->name = NULL; tpl->nameURI = NULL; if (str) { if (!domIsQNAME (str)) { reportError (node, "The value of the \"name\" attribute must" " be a qname", errMsg); FREE ((char*)tpl); return -1; } domSplitQName (str, prefix, &localName); if (prefix[0] != '\0') { ns = domLookupPrefix (node, prefix); if (!ns) { reportError (node, "The prefix of the \"name\" attribute" " value isn't bound to a namespace.", errMsg); FREE ((char*)tpl); return -1; } tpl->nameURI = ns->uri; Tcl_DStringInit (&dStr); Tcl_DStringAppend (&dStr, ns->uri, -1); Tcl_DStringAppend (&dStr, ":", 1); Tcl_DStringAppend (&dStr, localName, -1); h = Tcl_CreateHashEntry (&(xs->namedTemplates), Tcl_DStringValue (&dStr), &hnew); Tcl_DStringFree (&dStr); } else { h = Tcl_CreateHashEntry (&(xs->namedTemplates), localName, &hnew); } tpl->name = localName; if (!hnew) { t = (xsltTemplate *) Tcl_GetHashValue (h); if (t->precedence == precedence) { reportError (node, "There is already a template with the" " same name and precedence.", errMsg); FREE ((char*)tpl); return -1; } if (!t->match) { FREE ((char*)t); } } Tcl_SetHashValue (h, tpl); TRACE3("Added named Template '%s' '%2.2f' '%2.2f' \n\n", tpl->name, tpl->precedence, tpl->prio); } tpl->ast = NULL; tpl->mode = NULL; tpl->modeURI = NULL; str = getAttr (node, "mode", a_mode); if (str) { rc = 0; if (!domIsQNAME (str)) { reportError (node, "The value of the \"mode\" attribute must" " be a qname.", errMsg); rc = -1; } if (!tpl->match) { reportError (node, "A template without a \"match\" attribute must" " not have a \"mode\" attribute.", errMsg); rc = -1; } domSplitQName (str, prefix, &localName); if (prefix[0] != '\0') { ns = domLookupPrefix (node, prefix); if (ns) { tpl->modeURI = ns->uri; } else { reportError (node, "The prefix of the \"mode\" attribute value" " isn't bound to a namespace.", errMsg); rc = -1; } } tpl->mode = localName; if (rc < 0) { /* If the template has a name attribute, it is already * stored in the namedTemplates hash table and will be * freed. */ if (!tpl->name) { FREE ((char*)tpl); } return -1; } } tpl->prio = 0.5; tpl->content = node; tpl->precedence = precedence; tpl->next = NULL; prioStr = getAttr(node,"priority", a_prio); if (prioStr) { tpl->prio = strtod (prioStr, &tailptr); if (tpl->prio == 0.0 && prioStr == tailptr) { /* If the template has a name attribute, it is already * stored in the namedTemplates hash table and will be * freed. */ if (!tpl->name) { FREE ((char*)tpl); } return -1; } } sDoc = xs->subDocs; while (sDoc) { if (sDoc->doc == node->ownerDocument) break; sDoc = sDoc->next; } tpl->sDoc = sDoc; TRACE1("compiling XPath '%s' ...\n", tpl->match); if (tpl->match) { rc = xpathParse(tpl->match, node, XPATH_TEMPMATCH_PATTERN, NULL, NULL, &(tpl->freeAst), errMsg); if (rc < 0) { reportError (node, *errMsg, errMsg); } else { rc = addMatch (xs, node, tpl, prioStr, tpl->freeAst, errMsg); } if (rc < 0) { if (tpl->name) { /* The template is already stored in the namedTemplates hash table. Therefore, we don't free tpl here, but set tpl->match to NULL, which ensures, that the tpl will be freed while the namedTemplates hash table is cleaned up. */ tpl->match = NULL; } else { FREE ((char*)tpl); } return rc; } } return 0; } /*---------------------------------------------------------------------------- | ExecUseAttributeSets | \---------------------------------------------------------------------------*/ static int ExecUseAttributeSets ( xsltState * xs, xpathResultSet * context, domNode * currentNode, domLength currentPos, domNode * actionNode, char * styles, char ** errMsg ) { xsltAttrSet *attrSet; char *pc, *aSet, save, *str, prefix[MAX_PREFIX_LEN]; const char *localName; int rc; domNS *ns; pc = styles; while (*pc) { while (*pc && IS_XML_WHITESPACE(*pc)) pc++; if (*pc == '\0') break; aSet = pc; while (*pc && !IS_XML_WHITESPACE(*pc)) pc++; save = *pc; *pc = '\0'; TRACE1("use-attribute-set '%s' \n", aSet); attrSet = xs->attrSets; while (attrSet) { TRACE2("use-Attr: '%s' == '%s' ? \n", attrSet->name, aSet); rc = 0; if (!attrSet->uri) { if (strcmp(attrSet->name, aSet)==0) rc = 1; } else { domSplitQName (aSet, prefix, &localName); if (prefix[0] != '\0') { ns = domLookupPrefix (actionNode, prefix); if (ns) { if (strcmp (ns->uri, attrSet->uri)==0) { if (strcmp (attrSet->name, localName)==0) rc = 1; } } } } if (rc) { if (attrSet->inUse) { attrSet->inUse = 0; *pc = save; reportError(actionNode, "Circular reference " "to attribute set", errMsg); return -1; } attrSet->inUse = 1; str = getAttr (attrSet->content, "use-attribute-sets", a_useAttributeSets); if (str) { rc = ExecUseAttributeSets (xs, context, currentNode, currentPos, attrSet->content, str, errMsg); if (rc < 0) { attrSet->inUse = 0; *pc = save; return rc; } } rc = ExecActions(xs, context, currentNode, currentPos, attrSet->content->firstChild, errMsg); attrSet->inUse = 0; if (rc < 0) { attrSet->inUse = 0; *pc = save; return rc; } } attrSet = attrSet->next; } *pc = save; } return 0; } /*---------------------------------------------------------------------------- | evalAttrTemplates | \---------------------------------------------------------------------------*/ static int evalAttrTemplates ( xsltState * xs, xpathResultSet * context, domNode * currentNode, domLength currentPos, char * str, char ** out, char ** errMsg ) { xpathResultSet rs; char *tplStart = NULL, *tplResult, *pc, literalChar; domLength aLen, p = 0; int rc, inTpl = 0, inLiteral = 0; aLen = 500; *out = MALLOC(aLen); while (*str) { if (inTpl) { if (!inLiteral) { if (*str == '\'') { inLiteral = 1; literalChar = '\''; } else if (*str == '"') { inLiteral = 1; literalChar = '"'; } } else { if (*str == literalChar) { inLiteral = 0; } } if (*str == '}' && !inLiteral) { *str = '\0'; TRACE1("attrTpl: '%s' \n", tplStart); rc = evalXPath (xs, context, currentNode, currentPos, tplStart, &rs, errMsg); *str = '}'; CHECK_RC1(*out); tplResult = xpathFuncString( &rs ); DBG(fprintf(stderr, "attrTpl tplResult='%s' \n", tplResult);) xpathRSFree( &rs ); pc = tplResult; while (*pc) { (*out)[p++] = *pc++; if (p>=aLen) { /* enlarge output buffer */ *out = REALLOC(*out, 2*aLen); aLen += aLen; } } inTpl = 0; FREE(tplResult); } } else { if (*str == '{') { if (*(str+1) == '{') { /*----------------------------------------------------- | read over escaped '{': | '{{text text}}' -> '{text text}' \----------------------------------------------------*/ str++; (*out)[p++] = *str++; if (p>=aLen) { /* enlarge output buffer */ *out = REALLOC(*out, 2*aLen); aLen += aLen; } while (*str && (*str != '}') && (*(str-1) != '}')) { (*out)[p++] = *str++; if (p>=aLen) { /* enlarge output buffer */ *out = REALLOC(*out, 2*aLen); aLen += aLen; } } if (!*str) break; } else { tplStart = str+1; inTpl = 1; inLiteral = 0; } } else { if (*str == '}' && *(str+1) == '}') { str++; } (*out)[p++] = *str; if (p>=aLen) { /* enlarge output buffer */ *out = REALLOC(*out, 2*aLen); aLen += aLen; } } } str++; } (*out)[p] = '\0'; DBG(fprintf(stderr, "evalAttrTemplates out='%s' \n", (*out) );) return 0; } /*---------------------------------------------------------------------------- | setParamVars | \---------------------------------------------------------------------------*/ static int setParamVars ( xsltState * xs, xpathResultSet * context, domNode * currentNode, domLength currentPos, domNode * actionNode, char ** errMsg ) { domNode *child; char *str, *select; int rc; child = actionNode->firstChild; while (child) { if (child->nodeType == ELEMENT_NODE) { TRACE1("setParamVars child '%s' \n", child->nodeName); if (child->info == withParam) { str = getAttr(child, "name", a_name); if (str) { TRACE1("setting with-param '%s' \n", str); xs->currentXSLTNode = child; select = getAttr(child, "select", a_select); if (select && child->firstChild) { reportError (child, "An xsl:parameter element with a" " select attribute must be empty", errMsg); return -1; } TRACE1("with-param select='%s'\n", select); rc = xsltSetVar(xs, str, context, currentNode, currentPos, select, child, 0, errMsg); CHECK_RC; } else { reportError (child, "xsl:with-param: missing mandatory" " attribute \"name\".", errMsg); return -1; } } } child = child->nextSibling; } return 0; } /*---------------------------------------------------------------------------- | doSortActions | \---------------------------------------------------------------------------*/ static int doSortActions ( xsltState * xs, xpathResultSet * nodelist, domNode * actionNode, xpathResultSet * context, domNode * currentNode, domLength currentPos, char ** errMsg ) { domNode *child; char *str, *evStr, *select; /* todo */ /* char *lang; */ char **vs = NULL; char prefix[MAX_PREFIX_LEN]; const char *localName; double *vd = NULL; int rc = 0, typeText, ascending, upperFirst, NaN; domLength i, *pos = NULL; xpathResultSet rs; child = actionNode->lastChild; /* do it backwards, so that multiple sort levels are correctly processed */ while (child) { if (child->nodeType == ELEMENT_NODE) { TRACE1("doSortActions child '%s' \n", child->nodeName); if (child->info == sort) { if (child->firstChild) { reportError (child, "xsl:sort has to be empty.", errMsg); rc = -1; break; } typeText = 1; ascending = 1; upperFirst = 1; select = getAttr(child, "select", a_select); if (!select) select = "."; xs->currentXSLTNode = child; str = getAttr(child, "data-type", a_dataType); if (str) { rc = evalAttrTemplates (xs, context, currentNode, currentPos, str, &evStr, errMsg); CHECK_RC; if (strcmp(evStr,"text")==0) typeText = 1; else if (strcmp(evStr,"number")==0) typeText = 0; else { domSplitQName (evStr, prefix, &localName); if (prefix[0] == '\0') { reportError (child, "data-type must be text, " "number or a prefixed name", errMsg); FREE(evStr); rc = -1; break; } /* OK, so it is a legal value. But we currently don't support non-standard data-types. We use the default, that is typeText = 1. */ } FREE(evStr); } str = getAttr(child, "order", a_order); if (str) { rc = evalAttrTemplates (xs, context, currentNode, currentPos, str, &evStr, errMsg); CHECK_RC; if (strcmp(evStr,"descending")==0) ascending = 0; else if (strcmp(evStr, "ascending")==0) ascending = 1; else { reportError (child, "order must be ascending or" " descending", errMsg); FREE(evStr); rc = -1; break; } FREE(evStr); } str = getAttr(child, "case-order", a_caseorder); if (str) { rc = evalAttrTemplates (xs, context, currentNode, currentPos, str, &evStr, errMsg); CHECK_RC; if (strcmp(evStr,"lower-first")==0) upperFirst = 0; else if (strcmp(evStr, "upper-first")==0) upperFirst = 1; else { reportError (child, "case-order must be lower-first" " or upper-first", errMsg); FREE(evStr); rc = -1; break; } FREE(evStr); } /* jcl: TODO */ /* lang = getAttr(child, "lang", a_lang); */ /* The getAttr call should be done, to set attr->info to the attribute type for faster checks in further runs */ getAttr(child, "lang", a_lang); TRACE4("sorting with '%s' typeText %d ascending %d nodeSetLen=%d\n", select, typeText, ascending, nodelist->nr_nodes); CHECK_RC; if (!pos) pos = (domLength*)MALLOC(sizeof(int) * nodelist->nr_nodes); for (i=0; inr_nodes;i++) pos[i] = i; xs->currentXSLTNode = child; if (!vs) { vs = (char **)MALLOC(sizeof (char *) * nodelist->nr_nodes); for (i=0; inr_nodes;i++) vs[i] = NULL; vd = (double *)MALLOC(sizeof (double) * nodelist->nr_nodes); for (i=0; inr_nodes;i++) vd[i] = 0.0; } for (i = 0; i < nodelist->nr_nodes; i++) { xpathRSInit (&rs); rc = evalXPath (xs, nodelist, nodelist->nodes[i], i, select, &rs, errMsg); if (rc < 0) goto doSortActionCleanUp; if (typeText) { vs[i] = xpathFuncString (&rs); } else { vd[i] = xpathFuncNumber (&rs, &NaN); } xpathRSFree (&rs); } rc = sortNodeSetFastMerge (typeText, ascending, upperFirst, nodelist->nodes, nodelist->nr_nodes, vs, vd, pos, errMsg); if (typeText) { for (i = 0; i < nodelist->nr_nodes; i++) { FREE(vs[i]); } } if (rc < 0) goto doSortActionCleanUp; } } child = child->previousSibling; } doSortActionCleanUp: if (pos) FREE((char*)pos); if (vs) FREE((char*)vs); if (vd) FREE((char*)vd); return rc; } /*---------------------------------------------------------------------------- | xsltNumber | \---------------------------------------------------------------------------*/ static int xsltNumber ( xsltState * xs, xpathResultSet * context, domNode * currentNode, domLength currentPos, domNode * actionNode, char ** errMsg ) { xpathResultSet rs; int rc, NaN, hnew, i, useFormatToken; domLength vs[20], *v, *vd = NULL, vVals = 0; long groupingSize = 0; char *value, *level, *count, *from, *str, *str1, *format; char *groupingSeparator = NULL, *groupingSizeStr = NULL; char *tail; ast t_count, t_from; domNode *node, *start; Tcl_HashEntry *h; xsltNumberFormat *f; Tcl_DString dStr; domProcessingInstructionNode *pi; v = vs; value = getAttr(actionNode, "value", a_value); str = getAttr(actionNode, "format", a_format); if (!str) str = "1"; xs->currentXSLTNode = actionNode; rc = evalAttrTemplates( xs, context, currentNode, currentPos, str, &format, errMsg); CHECK_RC; f = xsltNumberFormatTokenizer (xs, format, errMsg); if (!f) { FREE(format); return -1; } str = getAttr(actionNode, "grouping-separator", a_groupingSeparator); if (str) { str1 = getAttr (actionNode, "grouping-size", a_groupingSize); if (str1) { rc = evalAttrTemplates (xs, context, currentNode, currentPos, str, &groupingSeparator, errMsg); if (rc < 0) goto xsltNumberError; rc = evalAttrTemplates (xs, context, currentNode, currentPos, str1, &groupingSizeStr, errMsg); if (rc < 0) goto xsltNumberError; groupingSize = strtol (groupingSizeStr, &tail, 10); if (groupingSize <= 0) { /* This covers both cases: non integer value after evaluation and wrong (<= 0) integer value. */ reportError (actionNode, "The value of \"grouping-size\" must" " evaluate to a positive integer.", errMsg); goto xsltNumberError; } } } if (value) { TRACE2("xsltNumber value='%s' format='%s' \n", value, format); rc = evalXPath(xs, context, currentNode, currentPos, value, &rs, errMsg); if (rc < 0) goto xsltNumberError; vVals = 1; v[0] = xpathRound(xpathFuncNumber( &rs, &NaN )); /* MARK recoverable error */ /* This is one of the not so satisfying corners of the XSLT * rec. The rec doesn't say, what to do, if the value isn't a * (finit) number. E24 from the erratas doesn't makes things * much better - a little bit dubious wording and a not very * convincing decision. Well, at least saxon seems to follow * the words of E24. I'll postpone this topic. */ if (NaN) v[0] = 0; xpathRSFree( &rs ); } else { level = getAttr(actionNode, "level", a_level); if (!level) level = "single"; count = getAttr(actionNode, "count", a_count); from = getAttr(actionNode, "from", a_from); TRACE3("xsltNumber format='%s' count='%s' from='%s' \n", format, count, from); if (count) { h = Tcl_CreateHashEntry (&(xs->pattern), count, &hnew); if (!hnew) { t_count = (ast) Tcl_GetHashValue (h); } else { rc = xpathParse (count, actionNode, XPATH_FORMAT_PATTERN, NULL, NULL, &t_count, errMsg); if (rc < 0) goto xsltNumberError; Tcl_SetHashValue (h, t_count); } } else { Tcl_DStringInit (&dStr); if (currentNode->nodeType == ELEMENT_NODE) { if (!currentNode->parentNode && currentNode == currentNode->ownerDocument->rootNode) { Tcl_DStringAppend (&dStr, "/", 1); } else { /* TODO: This is wrong. Instead this should use the "expanded-name" of the current node. */ Tcl_DStringAppend (&dStr, currentNode->nodeName, -1); } } else if (currentNode->nodeType == ATTRIBUTE_NODE) { Tcl_DStringAppend (&dStr, "@", 1); Tcl_DStringAppend (&dStr, currentNode->nodeName, -1); } else if (currentNode->nodeType == COMMENT_NODE) { Tcl_DStringAppend (&dStr, "comment()", -1); } else if (currentNode->nodeType == TEXT_NODE) { Tcl_DStringAppend (&dStr, "text()", -1); } else if (currentNode->nodeType == PROCESSING_INSTRUCTION_NODE) { Tcl_DStringAppend (&dStr, "processing-instruction('", -1); pi = (domProcessingInstructionNode *)currentNode; Tcl_DStringAppend (&dStr, pi->targetValue, pi->targetLength); Tcl_DStringAppend (&dStr, "')", 2); } else { reportError (actionNode, "unknown node type!!!", errMsg); return -1; } h = Tcl_CreateHashEntry (&(xs->pattern), Tcl_DStringValue(&dStr), &hnew); if (!hnew) { t_count = (ast) Tcl_GetHashValue (h); } else { rc = xpathParse (Tcl_DStringValue (&dStr), actionNode, XPATH_FORMAT_PATTERN, NULL, NULL, &t_count, errMsg); if (rc < 0) { Tcl_DStringFree (&dStr); goto xsltNumberError; } Tcl_SetHashValue (h, t_count); } Tcl_DStringFree (&dStr); } if (from) { h = Tcl_CreateHashEntry (&(xs->pattern), from, &hnew); if (!hnew) { t_from = (ast) Tcl_GetHashValue (h); } else { rc = xpathParse (from, actionNode, XPATH_FORMAT_PATTERN, NULL, NULL, &t_from, errMsg); if (rc < 0) goto xsltNumberError; Tcl_SetHashValue (h, t_from); } } if (strcmp (level, "single")==0) { node = currentNode; start = NULL; if (from) { while (node) { rc = xpathMatches (t_from, actionNode, node, &(xs->cbs), errMsg); if (rc < 0) goto xsltNumberError; if (rc) break; if (node->nodeType == ATTRIBUTE_NODE) node = ((domAttrNode *)node)->parentNode; else node = node->parentNode; } } node = currentNode; while (node != start) { rc = xpathMatches (t_count, actionNode, node, &(xs->cbs), errMsg); if (rc < 0) goto xsltNumberError; if (rc) break; if (node->nodeType == ATTRIBUTE_NODE) node = ((domAttrNode *)node)->parentNode; else node = node->parentNode; } if (node == start) { domAppendNewTextNode (xs->lastNode, "", 0, TEXT_NODE, 0); FREE(format); return 0; } else { vVals = 1; v[0] = 1; node = domPreviousSibling (node); while (node) { rc = xpathMatches (t_count, actionNode, node, &(xs->cbs), errMsg); if (rc < 0) goto xsltNumberError; if (rc) v[0]++; node = domPreviousSibling (node); } } } else if (strcmp (level, "multiple")==0) { xpathRSInit (&rs); node = currentNode; while (node) { if (from) { rc = xpathMatches (t_from, actionNode, node, &(xs->cbs), errMsg); if (rc < 0) goto xsltNumberError; if (rc) break; } rc = xpathMatches (t_count, actionNode, node, &(xs->cbs), errMsg); if (rc < 0) goto xsltNumberError; if (rc) rsAddNode (&rs, node); if (node->nodeType == ATTRIBUTE_NODE) node = ((domAttrNode *)node)->parentNode; else node = node->parentNode; } if (rs.nr_nodes > 20) { vd = (domLength *)MALLOC(sizeof (domLength) * rs.nr_nodes); v = vd; } vVals = rs.nr_nodes; v[0] = 0; for (i = 0; i < rs.nr_nodes; i++) { node = domPreviousSibling (rs.nodes[i]); v[i] = 1; while (node) { rc = xpathMatches (t_count, actionNode, node, &(xs->cbs), errMsg); if (rc < 0) goto xsltNumberError; if (rc) v[i]++; node = domPreviousSibling (node); } } xpathRSFree (&rs); } else if (strcmp (level, "any")==0) { v[0] = 0; vVals = 1; node = currentNode; while (node) { if (from) { rc = xpathMatches (t_from, actionNode, node, &(xs->cbs), errMsg); if (rc < 0) goto xsltNumberError; if (rc) break; } rc = xpathMatches (t_count, actionNode, node, &(xs->cbs), errMsg); if (rc < 0) goto xsltNumberError; if (rc) v[0]++; if (domPreviousSibling (node)) { node = domPreviousSibling (node); while ((node->nodeType == ELEMENT_NODE) && node->lastChild) { node = node->lastChild; } continue; } if (node->nodeType == ATTRIBUTE_NODE) { node = ((domAttrNode *)node)->parentNode; } else { node = node->parentNode; } } } else { reportError (actionNode, "xsl:number: Wrong \"level\" attribute" " value!", errMsg); goto xsltNumberError; } } Tcl_DStringInit (&dStr); useFormatToken = 0; if (f->prologLen) { Tcl_DStringAppend (&dStr, f->formatStr, f->prologLen); } for (i = 0; i < vVals -1; i++) { formatValue (f, &useFormatToken, v[i], &dStr, groupingSeparator, groupingSize, 1); } if (vVals > 0) { formatValue (f, &useFormatToken, v[vVals-1], &dStr, groupingSeparator, groupingSize, 0); if (f->epilogLen) { Tcl_DStringAppend (&dStr, f->epilogStart, f->epilogLen); } domAppendNewTextNode(xs->lastNode, Tcl_DStringValue (&dStr), Tcl_DStringLength (&dStr), TEXT_NODE, 0); } FREE(format); if (groupingSeparator) FREE (groupingSeparator); if (groupingSizeStr) FREE (groupingSizeStr); if (vd) { FREE((char *)vd); } Tcl_DStringFree (&dStr); return 0; xsltNumberError: if (format) FREE (format); if (groupingSeparator) FREE (groupingSeparator); if (groupingSizeStr) FREE (groupingSizeStr); return -1; } /*---------------------------------------------------------------------------- | ExecAction | \---------------------------------------------------------------------------*/ static int ExecAction ( xsltState * xs, xpathResultSet * context, domNode * currentNode, domLength currentPos, domNode * actionNode, char ** errMsg ) { domNode *child, *n, *n1, *savedLastNode, *fragmentNode; xsltTemplate *tpl, *currentTplRule, *tplChoosen; domAttrNode *attr, *attr1; domTextNode *tnode; domNS *ns, *ns1; xsltSubDoc *sDoc, *currentSubDoc; xsltExclExtNS *eNS; xsltNSAlias *nsAlias; Tcl_DString dStr; domProcessingInstructionNode *pi; xpathResultSet rs, nodeList; char *str, *str2, *select, *pc, *nsAT, *out; const char *mode, *modeURI, *localName, *uri, *nsStr; char prefix[MAX_PREFIX_LEN], tmpErr[200]; int rc, b, i, terminate, chooseState, disableEsc = 0; domLength len; double currentPrio, currentPrec; Tcl_HashEntry *h; if (actionNode->nodeType == TEXT_NODE) { domAppendNewTextNode(xs->lastNode, ((domTextNode*)actionNode)->nodeValue, ((domTextNode*)actionNode)->valueLength, TEXT_NODE, 0); return 0; } if (actionNode->nodeType != ELEMENT_NODE) return 0; TRACE1("\nExecAction '%s' \n", actionNode->nodeName); DBG (printXML (currentNode, 3, 5);) xs->currentXSLTNode = actionNode; switch ( actionNode->info ) { case applyImports: if (actionNode->firstChild) { reportError(actionNode, "xsl:apply-imports has to be empty!", errMsg); return -1; } if (!xs->currentTplRule) { reportError(actionNode, "xsl:apply-imports not allowed here!", errMsg); return -1; } tplChoosen = NULL; currentPrio = -100000.0; currentPrec = 0.0; mode = xs->currentTplRule->mode; modeURI = xs->currentTplRule->modeURI; if (currentNode->nodeType == ELEMENT_NODE) { Tcl_DStringInit (&dStr); if (currentNode->namespace) { domSplitQName (currentNode->nodeName, prefix, &localName); Tcl_DStringAppend (&dStr, domNamespaceURI (currentNode), -1); Tcl_DStringAppend (&dStr, ":", 1); } if (mode) { if (modeURI) { Tcl_DStringAppend (&dStr, modeURI, -1); Tcl_DStringAppend (&dStr, ":", 1); } Tcl_DStringAppend (&dStr, mode, -1); Tcl_DStringAppend (&dStr, ":", 1); } if (currentNode->namespace) { Tcl_DStringAppend (&dStr, localName, -1); } else { Tcl_DStringAppend (&dStr, currentNode->nodeName, -1); } h = Tcl_FindHashEntry (&xs->isElementTpls, Tcl_DStringValue (&dStr)); Tcl_DStringFree (&dStr); if (h) { for (tpl = (xsltTemplate *) Tcl_GetHashValue (h); tpl != NULL; tpl = tpl->next) { if (tpl->precedence >= xs->currentTplRule->precedence || tpl == xs->currentTplRule) continue; TRACE3("testing element tpl match='%s' mode='%s' name='%s'\n", tpl->match, tpl->mode, tpl->name); TRACE4("tpl has prio='%f' precedence='%f'\n", tpl->prio, tpl->precedence, currentPrio, currentPrec); rc = xpathMatches ( tpl->ast, actionNode, currentNode, &(xs->cbs), errMsg); if (rc < 0) { TRACE1("xpathMatches had errors '%s' \n", *errMsg); return rc; } if (rc == 0) continue; TRACE3("matching '%s': %f > %f ? \n", tpl->match, tpl->prio , currentPrio); tplChoosen = tpl; currentPrio = tpl->prio; currentPrec = tpl->precedence; break; } } } TRACE2("apply-imports: current template precedence='%f' mode='%s'\n", xs->currentTplRule->precedence, xs->currentTplRule->mode); for (tpl = xs->templates; tpl != NULL; tpl = tpl->next) { TRACE4("testing tpl match='%s' mode='%s' modeURI='%s' name='%s'\n", tpl->match, tpl->mode, tpl->modeURI, tpl->name); /* exclude those, which don't match the current mode and the currentTplRule */ if ( ( mode && !tpl->mode) || (!mode && tpl->mode) || ( mode && tpl->mode && (strcmp(mode,tpl->mode)!=0)) || (!modeURI && tpl->modeURI) || ( modeURI && !tpl->modeURI) || ( modeURI && tpl->modeURI && (strcmp(modeURI, tpl->modeURI)!=0)) || (tpl == xs->currentTplRule) ) { TRACE("doesn't match mode\n"); continue; } TRACE4("tpl has prio='%f' precedence='%f', currentPrio='%f', currentPrec='%f'\n", tpl->prio, tpl->precedence, currentPrio, currentPrec); if (tpl->match && tpl->precedence < xs->currentTplRule->precedence && tpl->precedence >= currentPrec) { if (tpl->precedence > currentPrec || tpl->prio >= currentPrio) { rc = xpathMatches (tpl->ast, actionNode, currentNode, &(xs->cbs), errMsg); CHECK_RC; if (rc == 0) continue; TRACE3("matching '%s': %f > %f ? \n", tpl->match, tpl->prio , currentPrio); tplChoosen = tpl; currentPrec = tpl->precedence; currentPrio = tpl->prio; TRACE1("TAKING '%s' \n", tpl->match); } } } if (tplChoosen == NULL) { TRACE("nothing matches -> execute built-in template \n"); /*-------------------------------------------------------------------- | execute built-in template \-------------------------------------------------------------------*/ if (currentNode->nodeType == TEXT_NODE) { domAppendNewTextNode(xs->lastNode, ((domTextNode*)currentNode)->nodeValue, ((domTextNode*)currentNode)->valueLength, TEXT_NODE, 0); break; } else if (currentNode->nodeType == ELEMENT_NODE) { child = currentNode->firstChild; } else if (currentNode->nodeType == ATTRIBUTE_NODE) { domAppendNewTextNode (xs->lastNode, ((domAttrNode*)currentNode)->nodeValue, ((domAttrNode*)currentNode)->valueLength, TEXT_NODE, 0); break; } else { /* for all other node we don't have to recurse deeper */ break; } xpathRSInit( &rs ); while (child) { rsAddNodeFast ( &rs, child); child = child->nextSibling; } rc = ApplyTemplates (xs, context, currentNode, currentPos, actionNode, &rs, mode, modeURI, errMsg); xpathRSFree( &rs ); CHECK_RC; break; } xsltPushVarFrame (xs); SETSCOPESTART; currentTplRule = xs->currentTplRule; currentSubDoc = xs->currentSubDoc; xs->currentTplRule = tplChoosen; xs->currentSubDoc = tplChoosen->sDoc; rc = ExecActions(xs, context, currentNode, currentPos, tplChoosen->content->firstChild, errMsg); xsltPopVarFrame (xs); CHECK_RC; xs->currentTplRule = currentTplRule; xs->currentSubDoc = currentSubDoc; break; case applyTemplates: mode = NULL; modeURI = NULL; str = getAttr (actionNode, "mode", a_mode); if (str) { domSplitQName (str, prefix, &localName); if (prefix[0] != '\0') { ns = domLookupPrefix (actionNode, prefix); if (!ns) { reportError (actionNode, "The prefix of the \"name\"" " attribute value isn't bound to a" " namespace.", errMsg); return -1; } modeURI = ns->uri; } mode = localName; } select = getAttr(actionNode, "select", a_select); if (!select) { xpathRSInit (&rs); if (currentNode->nodeType == ELEMENT_NODE) { child = currentNode->firstChild; while (child) { rsAddNodeFast (&rs, child); child = child->nextSibling; } } } else { xpathRSInit( &nodeList ); rsAddNodeFast( &nodeList, currentNode ); DBG(rsPrint( &nodeList )); TRACE2("applyTemplates: select = '%s' mode='%s'\n", select, mode); rc = evalXPath(xs, &nodeList, currentNode, 1, select, &rs, errMsg); xpathRSFree( &nodeList ); CHECK_RC; TRACE1("applyTemplates: evalXPath for select = '%s' gave back:\n", select); DBG(rsPrint(&rs)); } if (rs.type == EmptyResult) break; else if (rs.type != xNodeSetResult) { reportError (actionNode, "The \"select\" expression of" " xsl:apply-templates elements must evaluate to" " a node set.", errMsg); xpathRSFree (&rs); return -1; } rc = doSortActions (xs, &rs, actionNode, context, currentNode, currentPos, errMsg); if (rc < 0) { xpathRSFree (&rs); return rc; } /* should not be necessary, because every node set is returned already in doc Order */ /* if (!sorted) sortByDocOrder(&rs); */ TRACE1(" evalXPath for select = '%s': (SORTED)\n", select); DBG(rsPrint(&rs)); rc = ApplyTemplates(xs, context, currentNode, currentPos, actionNode, &rs, mode, modeURI, errMsg); xpathRSFree( &rs ); CHECK_RC; break; case attribute: if (xs->lastNode->firstChild) { /* Adding an Attribute to an element after children have been added to it is an error. Ignore the attribute. */ break; } nsAT = getAttr(actionNode, "namespace", a_namespace); str = getAttr(actionNode, "name", a_name); if (!str) { reportError (actionNode, "xsl:attribute: missing mandatory" " attribute \"name\".", errMsg); return -1; } rc = evalAttrTemplates( xs, context, currentNode, currentPos, str, &str2, errMsg); CHECK_RC; domSplitQName (str2, prefix, &localName); if ((prefix[0] != '\0' && !domIsNCNAME (prefix)) || !domIsNCNAME (localName)) { reportError (actionNode, "xsl:attribute: Attribute name is not" " a valid QName.", errMsg); FREE(str2); return -1; } out = NULL; if (nsAT) { rc = evalAttrTemplates( xs, context, currentNode, currentPos, nsAT, &out, errMsg); CHECK_RC1(str2); } Tcl_DStringInit (&dStr); if (prefix[0] == '\0' && (strcmp(str2, "xmlns")==0)) { goto ignoreAttribute; } /* It isn't allowed to create namespace attributes with xsl:attribute, a "xmlns" prefix must be rewritten; see XSLT rec 7.1.3 */ if (prefix[0] && (strcmp(prefix, "xmlns")==0)) { sprintf (prefix, "ns%d", xs->nsUniqeNr++); Tcl_DStringAppend (&dStr, prefix, -1); Tcl_DStringAppend (&dStr, ":", 1); Tcl_DStringAppend (&dStr, localName, -1); } else { if (out) { if (out[0] == '\0') { if (prefix[0] != '\0') { Tcl_DStringAppend (&dStr, localName, -1); } else { Tcl_DStringAppend (&dStr, str2, -1); } FREE(out); out = NULL; } else { if (prefix[0] == '\0') { ns = domLookupURI (xs->lastNode, out); if (ns && (ns->prefix[0] != '\0')) { Tcl_DStringAppend (&dStr, ns->prefix, -1); Tcl_DStringAppend (&dStr, ":", 1); } else { sprintf (prefix, "ns%d", xs->nsUniqeNr++); Tcl_DStringAppend (&dStr, prefix, -1); Tcl_DStringAppend (&dStr, ":", 1); } } Tcl_DStringAppend (&dStr, str2, -1); } } else { if (prefix[0] != '\0') { ns = domLookupPrefix (actionNode, prefix); if (ns) out = tdomstrdup (ns->uri); else goto ignoreAttribute; } Tcl_DStringAppend (&dStr, str2, -1); } } savedLastNode = xs->lastNode; xs->lastNode = domNewElementNode (xs->resultDoc, "container"); xsltPushVarFrame (xs); rc = ExecActions(xs, context, currentNode, currentPos, actionNode->firstChild, errMsg); xsltPopVarFrame (xs); if (rc < 0) { if (out) FREE(out); FREE(str2); return rc; } pc = xpathGetStringValue (xs->lastNode, &len); DBG(fprintf (stderr, "xsl:attribute: create attribute \"%s\" with value \"%s\" in namespace \"%s\"\n", Tcl_DStringValue (&dStr), pc, out);) domSetAttributeNS (savedLastNode, Tcl_DStringValue (&dStr), pc, out, 1); FREE(pc); Tcl_DStringFree (&dStr); domDeleteNode (xs->lastNode, NULL, NULL); xs->lastNode = savedLastNode; ignoreAttribute: if (out) FREE(out); FREE(str2); break; case attributeSet: reportError (actionNode, "xsl:attribute-set is only allowed at" " top-level.", errMsg); return -1; case callTemplate: tplChoosen = NULL; str = getAttr(actionNode, "name", a_name); if (!str) { reportError (actionNode, "xsl:call-template must have a" " \"name\" attribute", errMsg); return -1; } domSplitQName (str, prefix, &localName); uri = NULL; if (prefix[0] != '\0') { ns = domLookupPrefix (actionNode, prefix); if (!ns) { reportError (actionNode, "The prefix of the \"name\"" " attribute value isn't bound to a" " namespace.", errMsg); return -1; } uri = ns->uri; } if (uri) { Tcl_DStringInit (&dStr); Tcl_DStringAppend (&dStr, uri, -1); Tcl_DStringAppend (&dStr, ":", 1); Tcl_DStringAppend (&dStr, localName, -1); h = Tcl_FindHashEntry (&(xs->namedTemplates), Tcl_DStringValue (&dStr)); Tcl_DStringFree (&dStr); } else { h = Tcl_FindHashEntry (&(xs->namedTemplates), localName); } if (!h) { reportError (actionNode, "xsl:call-template calls a non" " existing template!", errMsg); return -1; } tplChoosen = (xsltTemplate *) Tcl_GetHashValue (h); xsltPushVarFrame (xs); SETPARAMDEF; TRACE3("call template %s match='%s' name='%s' \n", localName, tplChoosen->match, tplChoosen->name); DBG(printXML(xs->lastNode, 0, 2);) rc = setParamVars (xs, context, currentNode, currentPos, actionNode, errMsg); if (rc < 0) { xsltPopVarFrame (xs); return rc; } currentSubDoc = xs->currentSubDoc; xs->currentSubDoc = tplChoosen->sDoc; SETSCOPESTART; rc = ExecActions(xs, context, currentNode, currentPos, tplChoosen->content->firstChild, errMsg); TRACE2("called template '%s': ApplyTemplate/ExecActions rc = %d \n", localName, rc); xsltPopVarFrame (xs); CHECK_RC; xs->currentSubDoc = currentSubDoc; DBG(printXML(xs->lastNode, 0, 2);) break; case choose: chooseState = 0; for( child = actionNode->firstChild; child != NULL; child = child->nextSibling) { if (child->nodeType != ELEMENT_NODE) continue; switch (child->info) { case when: if (chooseState > 1) { reportError (actionNode, "\"otherwise\" clause" " must be after all \"when\"" " clauses", errMsg); return -1; } else { chooseState = 1; } str = getAttr(child, "test", a_test); if (str) { TRACE1("checking when test '%s' \n", str); rc = evalXPath(xs, context, currentNode, currentPos, str, &rs, errMsg); CHECK_RC; b = xpathFuncBoolean( &rs ); xpathRSFree( &rs ); if (b) { TRACE("test is true!\n"); /* process the children as well */ xsltPushVarFrame (xs); rc = ExecActions(xs, context, currentNode, currentPos, child->firstChild, errMsg); xsltPopVarFrame (xs); CHECK_RC; return 0; } } else { reportError (child, "xsl:when: missing mandatory" " attribute \"test\".", errMsg); return -1; } break; case otherwise: if (chooseState != 1) { if (chooseState == 0) { reportError (actionNode, "\"choose\" must" " have at least one \"when\"" " clause", errMsg); } else { reportError (child, "only one \"otherwise\"" " clause allowed inside a" " \"choose\"", errMsg); } return -1; } else { chooseState = 2; } /* process the children as well */ xsltPushVarFrame (xs); rc = ExecActions(xs, context, currentNode, currentPos, child->firstChild, errMsg); xsltPopVarFrame (xs); CHECK_RC; break; default: reportError (actionNode, "only otherwise or when" " allowed in choose!", errMsg); return -1; } } if (chooseState == 0) { reportError (actionNode, "\"choose\" must have at least" " one \"when\" clause", errMsg); return -1; } break; case comment: fragmentNode = domNewElementNode(xs->resultDoc, ""); savedLastNode = xs->lastNode; xs->lastNode = fragmentNode; xsltPushVarFrame (xs); rc = ExecActions(xs, context, currentNode, currentPos, actionNode->firstChild, errMsg); xsltPopVarFrame (xs); CHECK_RC; child = fragmentNode->firstChild; while (child) { if (child->nodeType != TEXT_NODE) { domDeleteNode (fragmentNode, NULL, NULL); reportError (actionNode, "xsl:comment must not create" " nodes other than text nodes.", errMsg); return -1; } child = child->nextSibling; } str = xpathGetStringValue (fragmentNode, &len); if (!domIsComment (str)) { reportError (actionNode, "Invalid comment value", errMsg); domDeleteNode (fragmentNode, NULL, NULL); FREE(str); return -1; } xs->lastNode = savedLastNode; domAppendNewTextNode(xs->lastNode, str, len, COMMENT_NODE, 0); domDeleteNode (fragmentNode, NULL, NULL); FREE(str); break; case copy: DBG(if (currentNode->nodeType == ATTRIBUTE_NODE) { fprintf(stderr, "copy '%s' \n", ((domAttrNode*)currentNode)->nodeName); } else { fprintf(stderr, "copy '%s' \n", currentNode->nodeName); }) if (currentNode->nodeType == TEXT_NODE) { DBG(fprintf(stderr, "node is TEXT_NODE \n");) tnode = (domTextNode*)currentNode; domAppendNewTextNode(xs->lastNode, tnode->nodeValue, tnode->valueLength, TEXT_NODE, 0); } else if (currentNode->nodeType == ELEMENT_NODE) { DBG(fprintf(stderr, "node is ELEMENT_NODE \n");) savedLastNode = xs->lastNode; if (currentNode != currentNode->ownerDocument->rootNode) { n = domAppendNewElementNode(xs->lastNode, currentNode->nodeName, domNamespaceURI(currentNode) ); xs->lastNode = n; str = getAttr(actionNode, "use-attribute-sets", a_useAttributeSets); domCopyNS (currentNode, xs->lastNode); if (str) { rc = ExecUseAttributeSets (xs, context, currentNode, currentPos, actionNode, str, errMsg); CHECK_RC; } } /* process the children only for root and element nodes */ xsltPushVarFrame (xs); rc = ExecActions(xs, context, currentNode, currentPos, actionNode->firstChild, errMsg); xsltPopVarFrame (xs); CHECK_RC; xs->lastNode = savedLastNode; } else if (currentNode->nodeType == PROCESSING_INSTRUCTION_NODE) { pi = (domProcessingInstructionNode*)currentNode; n = (domNode*) domNewProcessingInstructionNode (xs->lastNode->ownerDocument, pi->targetValue, pi->targetLength, pi->dataValue, pi->dataLength); domAppendChild (xs->lastNode, n); } else if (currentNode->nodeType == COMMENT_NODE) { DBG(fprintf(stderr, "node is COMMENT_NODE \n");) tnode = (domTextNode *)currentNode; domAppendNewTextNode (xs->lastNode, tnode->nodeValue, tnode->valueLength, COMMENT_NODE, 0); } else if (currentNode->nodeType == ATTRIBUTE_NODE) { DBG(fprintf(stderr, "node is ATTRIBUTE_NODE \n");) if (xs->lastNode->firstChild) { /* Adding an Attribute to an element after children have been added to it is an error. Ignore the attribute. */ break; } if (xs->lastNode == xs->resultDoc->rootNode) { reportError (actionNode, "Cannot write an attribute" " when there is no open start tag", errMsg); return -1; } attr = (domAttrNode *)currentNode; domSetAttributeNS (xs->lastNode, attr->nodeName, attr->nodeValue, domNamespaceURI (currentNode), 1); } break; case copyOf: if (actionNode->firstChild) { reportError (actionNode, "xsl:copy-of has to be empty.", errMsg); return -1; } select = getAttr(actionNode, "select", a_select); if (!select) { reportError (actionNode, "xsl:copy-of: missing mandatory" " attribute \"select\".", errMsg); return -1; } rc = evalXPath(xs, context, currentNode, currentPos, select, &rs, errMsg); CHECK_RC; TRACE1(" copyOf select='%s':\n", select); DBG(rsPrint(&rs)); if (rs.type == xNodeSetResult) { for (i=0; inodeType == ATTRIBUTE_NODE) { if (xs->lastNode->firstChild) { /* Adding an Attribute to an element after children have been added to it is an error. Ignore the attribute. */ continue; } attr = (domAttrNode*)rs.nodes[i]; if (attr ->nodeFlags & IS_NS_NODE) { /* If someone selects explicitly namespace nodes to copy-of with e.g. namespace::* (remember: @* doesn't select namespace nodes), we must this handle separately.*/ /* The xmlns:xml namespace node will always be in scope, but never needed to be copied, because the result tree will also always already have it. To suppress, that the result tree gets glutted with xmlns:xml declarations (they would not harm, but ev. irritate some and are unnecessary, we check this here as a special case */ if (attr->namespace == 1) { continue; } ns = NULL; } else { ns = domGetNamespaceByIndex ( attr->parentNode->ownerDocument, attr->namespace ); } if (ns) uri = ns->uri; else uri = NULL; if (xs->lastNode == xs->resultDoc->rootNode) { reportError (actionNode, "Cannot write an" " attribute when there is no open" " start tag", errMsg); xpathRSFree (&rs); return -1; } domSetAttributeNS(xs->lastNode, attr->nodeName, attr->nodeValue, uri, 1); } else { if (*(rs.nodes[i]->nodeName) == '\0') { /* The rootNode of the Document or the rootNode of a result tree fragment */ child = rs.nodes[i]->firstChild; while (child) { domCopyTo(child, xs->lastNode, 1); child = child->nextSibling; } } else { domCopyTo (rs.nodes[i], xs->lastNode, 1); } } } } else { str = xpathFuncString( &rs ); TRACE1("copyOf: xpathString='%s' \n", str); domAppendNewTextNode(xs->lastNode, str, (domLength)strlen(str), TEXT_NODE, 0); FREE(str); } xpathRSFree( &rs ); break; case decimalFormat: reportError (actionNode, "xsl:decimal-format is only allowed" " at top-level.", errMsg); return -1; case element: nsAT = getAttr(actionNode, "namespace", a_namespace); str = getAttr(actionNode, "name", a_name); if (!str) { reportError (actionNode, "xsl:element: missing mandatory" " attribute \"name\".", errMsg); return -1; } rc = evalAttrTemplates( xs, context, currentNode, currentPos, str, &str2, errMsg); CHECK_RC; if (!domIsQNAME (str2)) { reportError (actionNode, "xsl:element: Element name is not a" " valid QName.", errMsg); FREE(str2); return -1; } out = NULL; nsStr = NULL; if (nsAT) { rc = evalAttrTemplates( xs, context, currentNode, currentPos, nsAT, &out, errMsg); CHECK_RC1(str2); nsStr = out; } else { domSplitQName (str2, prefix, &localName); if ((prefix[0] != '\0' && !domIsNCNAME (prefix)) || !domIsNCNAME (localName)) { reportError (actionNode, "xsl:element: Element name is" " not a valid QName.", errMsg); FREE(str2); return -1; } ns = domLookupPrefix (actionNode, prefix); if (ns) nsStr = ns->uri; else { if (prefix[0] != '\0') { reportError (actionNode, "xsl:element: there isn't" " a URI associated with the prefix of" " the element name.", errMsg); FREE(str2); return -1; } } } savedLastNode = xs->lastNode; xs->lastNode = domAppendNewElementNode (xs->lastNode, str2, nsStr); FREE(str2); if (nsAT) FREE(out); str = getAttr(actionNode, "use-attribute-sets", a_useAttributeSets); if (str) { TRACE1("use-attribute-sets = '%s' \n", str); rc = ExecUseAttributeSets (xs, context, currentNode, currentPos, actionNode, str, errMsg); CHECK_RC; } /* process the children as well */ if (actionNode->firstChild) { xsltPushVarFrame (xs); rc = ExecActions(xs, context, currentNode, currentPos, actionNode->firstChild, errMsg); xsltPopVarFrame (xs); } xs->lastNode = savedLastNode; CHECK_RC; break; case fallback: return 0; case forEach: select = getAttr(actionNode, "select", a_select); if (!select) { reportError (actionNode, "xsl:for-each: The select attribute" " is required.", errMsg); return -1; } DBG ( if (currentNode->nodeType == ELEMENT_NODE) { fprintf (stderr, "forEach select from Element Node '%s' domNode0x%x:\n", currentNode->nodeName, currentNode); if (currentNode->firstChild) { fprintf(stderr, "forEach select from child '%s' domNode0x%x:\n", currentNode->firstChild->nodeName, currentNode->firstChild); } } else if (currentNode->nodeType == ATTRIBUTE_NODE) { fprintf (stderr, "forEach select from Attribute Node '%s' Value '%s'\n", ((domAttrNode *)currentNode)->nodeName, ((domAttrNode *)currentNode)->nodeValue); } else { fprintf (stderr, "forEach select from nodetype %d\n", currentNode->nodeType); } ) xpathRSInit( &nodeList ); rsAddNodeFast( &nodeList, currentNode ); DBG(rsPrint( &nodeList )); rc = evalXPath(xs, &nodeList, currentNode, 1, select, &rs, errMsg); xpathRSFree (&nodeList); if (rc < 0) { return rc; } CHECK_RC; TRACE1("forEach: evalXPath for select = '%s' gave back:\n", select); DBG(rsPrint(&rs)); if (rs.type == xNodeSetResult) { rc = doSortActions (xs, &rs, actionNode, context, currentNode, currentPos, errMsg); if (rc < 0) { xpathRSFree (&rs); return rc; } /* should not be necessary, because every node set is returned already in doc Order */ /* if (!sorted) sortByDocOrder(&rs); */ TRACE1(" forEach for select = '%s': (SORTED)\n", select); DBG(rsPrint(&rs)); currentTplRule = xs->currentTplRule; xs->currentTplRule = NULL; xsltPushVarFrame (xs); for (i=0; ifirstChild, errMsg); if (rc < 0) { xsltPopVarFrame (xs); xpathRSFree( &rs ); return rc; } if ((&xs->varFramesStack[xs->varFramesStackPtr])->polluted) { xsltPopVarFrame (xs); xsltPushVarFrame (xs); } } xsltPopVarFrame (xs); xs->currentTplRule = currentTplRule; } else { if (rs.type != EmptyResult) { reportError (actionNode, "The \"select\" expression of" " xsl:for-each elements must evaluate to a" " node set.", errMsg); xpathRSFree (&rs); return -1; } } xpathRSFree( &rs ); break; case xsltIf: str = getAttr(actionNode, "test", a_test); if (str) { rc = evalXPath(xs, context, currentNode, currentPos, str, &rs, errMsg); CHECK_RC; b = xpathFuncBoolean( &rs ); xpathRSFree( &rs ); if (b) { /* process the children as well */ xsltPushVarFrame (xs); rc = ExecActions(xs, context, currentNode, currentPos, actionNode->firstChild, errMsg); xsltPopVarFrame (xs); CHECK_RC; } } else { reportError (actionNode, "xsl:if: missing mandatory attribute" " \"test\".", errMsg); return -1; } break; case import: reportError (actionNode, "xsl:import is only allowed at top-level.", errMsg); return -1; case include: reportError (actionNode, "xsl:include is only allowed at" " top-level.", errMsg); return -1; case key: reportError (actionNode, "xsl:key is only allowed at top-level.", errMsg); return -1; case message: str = getAttr(actionNode,"terminate", a_terminate); if (!str) terminate = 0; else if (strcmp (str, "yes") == 0) terminate = 1; else if (strcmp (str, "no") == 0) terminate = 0; else { reportError (actionNode, "Allowed values for the 'terminate'" "attribute: 'yes' or 'no'", errMsg); return -1; } fragmentNode = domNewElementNode(xs->resultDoc, ""); savedLastNode = xs->lastNode; xs->lastNode = fragmentNode; xsltPushVarFrame (xs); rc = ExecActions(xs, context, currentNode, currentPos, actionNode->firstChild, errMsg); xsltPopVarFrame (xs); CHECK_RC; str2 = xpathGetStringValue(fragmentNode, &len); rc = xs->xsltMsgCB (xs->xsltMsgClientData, str2, len, terminate); FREE(str2); xs->lastNode = savedLastNode; domDeleteNode (fragmentNode, NULL, NULL); if (terminate) { reportError (actionNode, "xsl:message with attribute" " \"terminate\"=\"yes\"", errMsg); return -1; } switch (rc) { case 0: return 0; case 3: reportError (actionNode, "", errMsg); return -1; default: sprintf (tmpErr, "Error while executing message callback." " Message callback result code: %d", rc); reportError (actionNode, tmpErr, errMsg); return -1; } case namespaceAlias: reportError (actionNode, "xsl:namespaceAlias is only allowed" " at top-level.", errMsg); return -1; case number: if (actionNode->firstChild) { reportError (actionNode, "xsl:number has to be empty.", errMsg); return -1; } rc = xsltNumber(xs, context, currentNode, currentPos, actionNode, errMsg); CHECK_RC; break; case output: return 0; case otherwise: reportError (actionNode, "xsl:otherwise must be immediately" " within xsl:choose", errMsg); return -1; case param: str = getAttr(actionNode, "name", a_name); if (str) { TRACE1("setting param '%s' ??\n", str); if (!xsltVarExists(xs, str, actionNode)) { TRACE1("setting param '%s': yes \n", str); select = getAttr(actionNode, "select", a_select); if (select && actionNode->firstChild) { reportError (actionNode, "An xsl:parameter element " " with a select attribute must be empty", errMsg); return -1; } TRACE1("param select='%s'\n", select); rc = xsltSetVar(xs, str, context, currentNode, currentPos, select, actionNode, 1, errMsg); CHECK_RC; } } else { reportError (actionNode, "xsl:param: missing mandatory " " attribute \"name\".", errMsg); return -1; } break; case preserveSpace: return 0; case procinstr: str = getAttr(actionNode, "name", a_name); if (str) { rc = evalAttrTemplates( xs, context, currentNode, currentPos, str, &str2, errMsg); CHECK_RC; if (!domIsPINAME (str2) || !domIsNCNAME(str2)) { reportError (actionNode, "xsl:processing-instruction: " "Processing instruction name is invalid.", errMsg); FREE(str2); return -1; } } else { reportError (actionNode, "xsl:processing-instruction:" " missing mandatory attribute \"name\".", errMsg); return -1; } fragmentNode = domNewElementNode(xs->resultDoc, ""); savedLastNode = xs->lastNode; xs->lastNode = fragmentNode; xsltPushVarFrame (xs); rc = ExecActions(xs, context, currentNode, currentPos, actionNode->firstChild, errMsg); xsltPopVarFrame (xs); if (rc < 0) { FREE (str2); return rc; } child = fragmentNode->firstChild; while (child) { if (child->nodeType != TEXT_NODE) { domDeleteNode (fragmentNode, NULL, NULL); reportError (actionNode, "xsl:processing-instruction must " "not create nodes other than text nodes.", errMsg); FREE(str2); return -1; } child = child->nextSibling; } str = xpathGetStringValue (fragmentNode, &len); if (!domIsPIValue (str)) { reportError (actionNode, "Invalid processing instruction " "value", errMsg); domDeleteNode (fragmentNode, NULL, NULL); FREE(str); FREE(str2); return -1; } xs->lastNode = savedLastNode; n = (domNode*)domNewProcessingInstructionNode( xs->resultDoc, str2, (domLength)strlen(str2), str, len); domAppendChild(xs->lastNode, n); domDeleteNode (fragmentNode, NULL, NULL); FREE(str2); FREE(str); break; case sort: case stylesheet: case stripSpace: case template: return 0; case text: str = getAttr(actionNode, "disable-output-escaping", a_disableOutputEscaping); if (str) { if (strcmp (str, "yes")==0) disableEsc = 1; } pc = xpathGetStringValue (actionNode, &len); DBG(fprintf(stderr, "text: pc='%s'%d \n", pc, len);) domAppendNewTextNode(xs->lastNode, pc, len, TEXT_NODE, disableEsc); FREE(pc); break; case transform: return 0; case valueOf: if (actionNode->firstChild) { reportError (actionNode, "xsl:value-of has to be empty.", errMsg); return -1; } str = getAttr(actionNode, "disable-output-escaping", a_disableOutputEscaping); if (str) { if (strcmp (str, "yes")==0) disableEsc = 1; } str = getAttr(actionNode, "select", a_select); if (str) { TRACE1("valueOf: str='%s' \n", str); rc = evalXPath(xs, context, currentNode, currentPos, str, &rs, errMsg); CHECK_RC; DBG(rsPrint(&rs)); str = xpathFuncString( &rs ); TRACE1("valueOf: xpathString='%s' \n", str); domAppendNewTextNode(xs->lastNode, str, (domLength)strlen(str), TEXT_NODE, disableEsc); xpathRSFree( &rs ); FREE(str); } else { reportError (actionNode, "xsl:value-of must have a" " \"select\" attribute!", errMsg); return -1; } break; case variable: str = getAttr(actionNode, "name", a_name); if (str) { if (xsltVarExists (xs, str, actionNode)) { Tcl_DStringInit (&dStr); Tcl_DStringAppend (&dStr, "Variable '", -1); Tcl_DStringAppend (&dStr, str, -1); Tcl_DStringAppend ( &dStr, "' is already declared in this template", -1); reportError (actionNode, Tcl_DStringValue (&dStr), errMsg); return -1; } select = getAttr(actionNode, "select", a_select); if (select && actionNode->firstChild) { reportError (actionNode, "An xsl:variable element with a" " select attribute must be empty", errMsg); return -1; } TRACE1("variable select='%s'\n", select); rc = xsltSetVar(xs, str, context, currentNode, currentPos, select, actionNode, 1, errMsg); CHECK_RC; } else { reportError (actionNode, "xsl:variable must have a \"name\"" " attribute!", errMsg); return -1; } break; case when: reportError (actionNode, "xsl:when must be immediately within" " xsl:choose", errMsg); return -1; case withParam: return 0; default: sDoc = xs->currentSubDoc; if (actionNode->namespace) { ns = actionNode->ownerDocument->namespaces[actionNode->namespace - 1]; eNS = sDoc->extensionNS; while (eNS) { if (eNS->uri) { if (strcmp (eNS->uri, ns->uri)==0) break; } else { if (ns->prefix[0] == '\0') break; } eNS = eNS->next; } if (eNS) { /* An extension element; process fallback */ child = actionNode->firstChild; while (child) { if (child->info == fallback) { xsltPushVarFrame (xs); rc = ExecActions (xs, context, currentNode, currentPos, child->firstChild, errMsg); xsltPopVarFrame (xs); CHECK_RC; } child = child->nextSibling; } return 0; } } savedLastNode = xs->lastNode; DBG(fprintf(stderr, "append new tag '%s' uri='%s' \n", actionNode->nodeName, domNamespaceURI(actionNode) );); xs->lastNode = domAppendLiteralNode (xs->lastNode, actionNode); n = actionNode; while (n) { attr = n->firstAttr; while (attr && (attr->nodeFlags & IS_NS_NODE)) { /* XSLT namespace isn't copied */ /* Well, XSLT implementers doesn't seem to agree at which point this rule out of the second paragraph of 7.1.1 must be applied: before or after applying the namespace aliases (or, in other words: is this rule (of not copying the XSLT namespace for lre) considered, at the time, the lre is found in the stylesheet or at the time, the lre is written to the result doc). In deed the rec doesn't clarify this explicitly. */ if (strcmp (attr->nodeValue, XSLT_NAMESPACE)==0){ attr = attr->nextSibling; continue; } ns = n->ownerDocument->namespaces[attr->namespace-1]; rc = 0; n1 = actionNode; while (n1 != n) { attr1 = n1->firstAttr; while (attr1 && (attr1->nodeFlags & IS_NS_NODE)) { ns1 = n1->ownerDocument->namespaces[attr1->namespace-1]; if (strcmp (ns1->prefix, ns->prefix)==0) { rc = 1; break; } attr1 = attr1->nextSibling; } if (rc) break; n1 = n1->parentNode; } if (rc) { attr = attr->nextSibling; continue; } str = ns->uri; nsAlias = xs->nsAliases; while (nsAlias) { if (strcmp (nsAlias->fromUri, ns->uri)==0) { ns->uri = nsAlias->toUri; break; } nsAlias = nsAlias->next; } eNS = sDoc->excludeNS; while (eNS) { if (eNS->uri) { if (strcmp (eNS->uri, ns->uri)==0) break; } else { if (ns->prefix[0] == '\0') break; } eNS = eNS->next; } if (!eNS) { eNS = sDoc->extensionNS; while (eNS) { if (eNS->uri) { if (strcmp (eNS->uri, ns->uri)==0) break; } else { if (ns->prefix[0] == '\0') break; } eNS = eNS->next; } if (!eNS) { domAddNSToNode (xs->lastNode, ns); } } ns->uri = str; attr = attr->nextSibling; } n = n->parentNode; } /* It's not clear, what to do, if the literal result element is in a namespace, that should be excluded. We follow saxon and xalan, which both add the namespace of the literal result element always to the result tree, to ensure that the result tree is conform to the XML namespace recommendation. */ if (actionNode->namespace) { ns = actionNode->ownerDocument->namespaces[actionNode->namespace-1]; str = ns->uri; nsAlias = xs->nsAliases; while (nsAlias) { if (strcmp (nsAlias->fromUri, ns->uri)==0) { ns->uri = nsAlias->toUri; break; } nsAlias = nsAlias->next; } ns1 = domAddNSToNode (xs->lastNode, ns); if (ns1) { xs->lastNode->namespace = ns1->index; } ns->uri = str; } else { ns = domLookupPrefix (xs->lastNode, ""); if (ns) { if (strcmp (ns->uri, "")!=0) { attr = domSetAttributeNS (xs->lastNode, "xmlns", "", NULL, 1); if (attr) { xs->lastNode->namespace = attr->namespace; } } else { xs->lastNode->namespace = ns->index; } } } n = xs->lastNode; /* process the attributes */ attr = actionNode->firstAttr; while (attr) { if (attr->nodeFlags & IS_NS_NODE) { attr = attr->nextSibling; continue; } /* TODO: xsl:exclude-result-prefixes attribute on literal elements on the ancestor-or-self axis */ uri = domNamespaceURI((domNode*)attr); if (uri && strcmp(uri, XSLT_NAMESPACE)==0) { domSplitQName((char*)attr->nodeName, prefix, &localName); if (strcmp(localName,"use-attribute-sets")==0) { str = attr->nodeValue; rc = ExecUseAttributeSets (xs, context, currentNode, currentPos, actionNode, str, errMsg); CHECK_RC; } } else { rc = evalAttrTemplates( xs, context, currentNode, currentPos, attr->nodeValue, &str, errMsg); CHECK_RC; if (uri) { nsAlias = xs->nsAliases; while (nsAlias) { if (strcmp (nsAlias->fromUri, uri)==0) { uri = nsAlias->toUri; break; } nsAlias = nsAlias->next; } } domSetAttributeNS (n, attr->nodeName, str, uri, 1); FREE(str); } attr = attr->nextSibling; } /* process the children as well */ xsltPushVarFrame (xs); rc = ExecActions(xs, context, currentNode, currentPos, actionNode->firstChild, errMsg); xsltPopVarFrame (xs); CHECK_RC; xs->lastNode = savedLastNode; return 0; } return 0; } /*---------------------------------------------------------------------------- | ExecActions | \---------------------------------------------------------------------------*/ static int ExecActions ( xsltState * xs, xpathResultSet * context, domNode * currentNode, domLength currentPos, domNode * actionNode, char ** errMsg ) { domNode *savedLastNode, *savedCurrentNode; int rc; savedLastNode = xs->lastNode; savedCurrentNode = xs->current; while (actionNode) { xs->current = currentNode; rc = ExecAction (xs, context, currentNode, currentPos, actionNode, errMsg); if (rc < 0) { xs->lastNode = savedLastNode; xs->current = savedCurrentNode; return rc; } actionNode = actionNode->nextSibling; } xs->lastNode = savedLastNode; xs->current = savedCurrentNode; return 0; } /*---------------------------------------------------------------------------- | ApplyTemplate | \---------------------------------------------------------------------------*/ static int ApplyTemplate ( xsltState * xs, xpathResultSet * context, domNode * currentNode, domNode * exprContext, domLength currentPos, const char * mode, const char * modeURI, char ** errMsg ) { xsltTemplate *tpl; xsltTemplate *tplChoosen, *currentTplRule; domNode *child; xpathResultSet rs; int rc; double currentPrio, currentPrec; char prefix[MAX_PREFIX_LEN]; const char *localName; Tcl_HashEntry *h; Tcl_DString dStr; xsltSubDoc *currentSubDoc; TRACE2("\n\nApplyTemplate mode='%s' currentPos=%d \n", mode, currentPos); DBG(printXML (currentNode, 0, 1);) /*-------------------------------------------------------------- | find template \-------------------------------------------------------------*/ tplChoosen = NULL; currentPrio = -100000.0; currentPrec = 0.0; if (currentNode->nodeType == ELEMENT_NODE) { Tcl_DStringInit (&dStr); if (currentNode->namespace) { domSplitQName (currentNode->nodeName, prefix, &localName); Tcl_DStringAppend (&dStr, domNamespaceURI (currentNode), -1); Tcl_DStringAppend (&dStr, ":", 1); } if (mode) { if (modeURI) { Tcl_DStringAppend (&dStr, modeURI, -1); Tcl_DStringAppend (&dStr, ":", 1); } Tcl_DStringAppend (&dStr, mode, -1); Tcl_DStringAppend (&dStr, ":", 1); } if (currentNode->namespace) { Tcl_DStringAppend (&dStr, localName, -1); } else { Tcl_DStringAppend (&dStr, currentNode->nodeName, -1); } h = Tcl_FindHashEntry (&xs->isElementTpls, Tcl_DStringValue (&dStr)); Tcl_DStringFree (&dStr); if (h) { for (tpl = (xsltTemplate *) Tcl_GetHashValue (h); tpl != NULL; tpl = tpl->next) { TRACE3("find element tpl match='%s' mode='%s' name='%s'\n", tpl->match, tpl->mode, tpl->name); TRACE4("tpl has prio='%f' precedence='%f'\n", tpl->prio, tpl->precedence, currentPrio, currentPrec); rc = xpathMatches ( tpl->ast, tpl->content, currentNode, &(xs->cbs), errMsg); if (rc < 0) { TRACE1("xpathMatches had errors '%s' \n", *errMsg); return rc; } if (rc == 0) continue; TRACE3("matching '%s': %f > %f ? \n", tpl->match, tpl->prio , currentPrio); tplChoosen = tpl; currentPrio = tpl->prio; currentPrec = tpl->precedence; break; } } } for( tpl = xs->templates; tpl != NULL; tpl = tpl->next) { TRACE3("find tpl match='%s' mode='%s' name='%s'\n", tpl->match, tpl->mode, tpl->name); /* exclude those, which don't match the current mode */ if ( ( mode && !tpl->mode) || (!mode && tpl->mode) || ( mode && tpl->mode && (strcmp(mode,tpl->mode)!=0)) || (!modeURI && tpl->modeURI) || ( modeURI && !tpl->modeURI) || ( modeURI && tpl->modeURI && (strcmp(modeURI, tpl->modeURI)!=0)) ) { TRACE("doesn't match mode\n"); continue; /* doesn't match mode */ } TRACE4("tpl has prio='%f' precedence='%f', currentPrio='%f', currentPrec='%f'\n", tpl->prio, tpl->precedence, currentPrio, currentPrec); /* According to XSLT rec 5.5: First test precedence */ if (tpl->precedence < currentPrec) break; if (tpl->precedence == currentPrec) { if (tpl->prio < currentPrio) break; if (tpl->prio == currentPrio && domPrecedes (tpl->content, tplChoosen->content)) break; } rc = xpathMatches ( tpl->ast, tpl->content, currentNode, &(xs->cbs), errMsg); TRACE1("xpathMatches = %d \n", rc); if (rc < 0) { TRACE1("xpathMatches had errors '%s' \n", *errMsg); return rc; } if (rc == 0) continue; TRACE3("matching '%s': %f > %f ? \n", tpl->match, tpl->prio , currentPrio); tplChoosen = tpl; TRACE1("TAKING '%s' \n", tpl->match); break; } if (tplChoosen == NULL) { TRACE("nothing matches -> execute built-in template \n"); /*-------------------------------------------------------------------- | execute built-in template \-------------------------------------------------------------------*/ if (currentNode->nodeType == TEXT_NODE) { domAppendNewTextNode(xs->lastNode, ((domTextNode*)currentNode)->nodeValue, ((domTextNode*)currentNode)->valueLength, TEXT_NODE, 0); return 0; } else if (currentNode->nodeType == DOCUMENT_NODE) { child = ((domDocument*)currentNode)->documentElement; } else if (currentNode->nodeType == ELEMENT_NODE) { child = currentNode->firstChild; } else if (currentNode->nodeType == ATTRIBUTE_NODE) { domAppendNewTextNode (xs->lastNode, ((domAttrNode*)currentNode)->nodeValue, ((domAttrNode*)currentNode)->valueLength, TEXT_NODE, 0); return 0; } else { return 0; /* for all other nodes we don't have to recurse deeper */ } xpathRSInit( &rs ); while (child) { rsAddNodeFast ( &rs, child); child = child->nextSibling; } rc = ApplyTemplates (xs, context, currentNode, currentPos, exprContext, &rs, mode, modeURI, errMsg); xpathRSFree( &rs ); CHECK_RC; } else { TRACE1("tplChoosen '%s' \n", tplChoosen->match); currentTplRule = xs->currentTplRule; currentSubDoc = xs->currentSubDoc; xs->currentTplRule = tplChoosen; xs->currentSubDoc = tplChoosen->sDoc; DBG(printXML (tplChoosen->content->firstChild, 0, 1);) rc = ExecActions(xs, context, currentNode, currentPos, tplChoosen->content->firstChild, errMsg); TRACE1("ApplyTemplate/ExecActions rc = %d \n", rc); xs->currentTplRule = currentTplRule; xs->currentSubDoc = currentSubDoc; CHECK_RC; } return 0; } /*---------------------------------------------------------------------------- | ApplyTemplates | \---------------------------------------------------------------------------*/ static int ApplyTemplates ( xsltState * xs, xpathResultSet * context, domNode * currentNode, domLength currentPos, domNode * actionNode, xpathResultSet * nodeList, const char * mode, const char * modeURI, char ** errMsg ) { domNode * savedLastNode; int rc, needNewVarFrame = 1; domLength i; if (nodeList->type == xNodeSetResult) { if (xs->nestedApplyTemplates > xs->maxNestedApplyTemplates) { *errMsg = tdomstrdup("Maximum nested apply templates reached " "(potential infinite template recursion?)."); return -1; } xs->nestedApplyTemplates++; savedLastNode = xs->lastNode; for (i=0; i < nodeList->nr_nodes; i++) { if (needNewVarFrame) { xsltPushVarFrame (xs); SETPARAMDEF; rc = setParamVars (xs, context, currentNode, currentPos, actionNode, errMsg); if (rc < 0) { xsltPopVarFrame (xs); xs->lastNode = savedLastNode; return rc; } SETSCOPESTART; (&xs->varFramesStack[xs->varFramesStackPtr])->polluted = 0; } rc = ApplyTemplate (xs, nodeList, nodeList->nodes[i], actionNode, i, mode, modeURI, errMsg); if (rc < 0) { xsltPopVarFrame (xs); xs->lastNode = savedLastNode; return rc; } if ((&xs->varFramesStack[xs->varFramesStackPtr])->polluted) { xsltPopVarFrame (xs); needNewVarFrame = 1; } else needNewVarFrame = 0; } if (!needNewVarFrame) { xsltPopVarFrame (xs); } xs->lastNode = savedLastNode; xs->nestedApplyTemplates--; } else { TRACE("ApplyTemplates: nodeList not a NodeSetResult !!!\n"); DBG(rsPrint(nodeList);) } return 0; } /*---------------------------------------------------------------------------- | fillElementList | \---------------------------------------------------------------------------*/ static int fillElementList ( xsltWSInfo * wsInfo, int strip, double precedence, domNode * node, char * str, char ** errMsg ) { char *pc, *start, save; char prefix[MAX_PREFIX_LEN]; const char *localName; double *f; int hnew; Tcl_HashEntry *h; Tcl_DString dStr; domNS *ns; pc = str; while (*pc) { while (*pc && IS_XML_WHITESPACE(*pc)) pc++; if (*pc == '\0') break; start = pc; while (*pc && !IS_XML_WHITESPACE(*pc)) pc++; save = *pc; *pc = '\0'; wsInfo->hasData = 1; if (strcmp (start, "*")==0) { if (strip) wsInfo->stripAll = 1; else wsInfo->stripAll = 0; wsInfo->wildcardPrec = precedence; } else { Tcl_DStringInit (&dStr); ns = NULL; domSplitQName (start, prefix, &localName); if (prefix[0] != '\0') { if (!domIsNCNAME (prefix)) { reportError (node, "Invalid token", errMsg); *pc = save; Tcl_DStringFree (&dStr); return -1; } ns = domLookupPrefix (node, prefix); if (!ns) { reportError (node, "prefix isn't bound to a namespace", errMsg); *pc = save; Tcl_DStringFree (&dStr); return -1; } Tcl_DStringAppend (&dStr, ns->uri, -1); Tcl_DStringAppend (&dStr, ":", 1); } if (strcmp ("*", localName) != 0) { if (!domIsNCNAME (localName)) { reportError (node, "Invalid token", errMsg); *pc = save; Tcl_DStringFree (&dStr); return -1; } } Tcl_DStringAppend (&dStr, localName, -1); if (strip) { h = Tcl_FindHashEntry (&wsInfo->preserveTokens, Tcl_DStringValue (&dStr)); } else { h = Tcl_FindHashEntry (&wsInfo->stripTokens, Tcl_DStringValue (&dStr)); } if (h) { FREE (Tcl_GetHashValue (h)); Tcl_DeleteHashEntry (h); } if (strip) { h = Tcl_CreateHashEntry (&wsInfo->stripTokens, Tcl_DStringValue (&dStr), &hnew); } else { h = Tcl_CreateHashEntry (&wsInfo->preserveTokens, Tcl_DStringValue (&dStr), &hnew); } if (hnew) { f = (double *)MALLOC(sizeof (double)); *f = precedence; Tcl_SetHashValue (h, f); } else { f = (double *)Tcl_GetHashValue (h); *f = precedence; } Tcl_DStringFree (&dStr); } *pc = save; } return 1; } /*---------------------------------------------------------------------------- | getCdataSectionElements | \---------------------------------------------------------------------------*/ static int getCdataSectionElements ( domNode * node, char * qnameList, Tcl_HashTable * HashTable, char ** errMsg ) { char *pc, *start, save, prefix[MAX_PREFIX_LEN]; const char *localName; int hnew; Tcl_DString dStr; domNS *ns; Tcl_DStringInit (&dStr); pc = qnameList; while (*pc) { while (*pc && IS_XML_WHITESPACE(*pc)) pc++; if (*pc == '\0') break; start = pc; while (*pc && !IS_XML_WHITESPACE(*pc)) pc++; save = *pc; *pc = '\0'; domSplitQName (start, prefix, &localName); if (prefix[0] != '\0') { if (!domIsNCNAME (prefix)) { Tcl_DStringSetLength (&dStr, 0); Tcl_DStringAppend (&dStr, "Invalid prefix '", -1); Tcl_DStringAppend (&dStr, prefix, -1); Tcl_DStringAppend (&dStr, "'.", 2); reportError (node, Tcl_DStringValue (&dStr), errMsg); Tcl_DStringFree (&dStr); return 0; } ns = domLookupPrefix (node, prefix); if (!ns) { Tcl_DStringSetLength (&dStr, 0); Tcl_DStringAppend (&dStr, "There isn't a namespace bound to" " the prefix '", -1); Tcl_DStringAppend (&dStr, prefix, -1); Tcl_DStringAppend (&dStr, "'.", 2); reportError (node, Tcl_DStringValue (&dStr), errMsg); Tcl_DStringFree (&dStr); return 0; } Tcl_DStringAppend (&dStr, ns->uri, -1); Tcl_DStringAppend (&dStr, ":", 1); } if (!domIsNCNAME (localName)) { Tcl_DStringSetLength (&dStr, 0); Tcl_DStringAppend (&dStr, "Invalid name '", -1); Tcl_DStringAppend (&dStr, prefix, -1); Tcl_DStringAppend (&dStr, "'.", 2); reportError (node, Tcl_DStringValue (&dStr), errMsg); Tcl_DStringFree (&dStr); return 0; } Tcl_DStringAppend (&dStr, localName, -1); Tcl_CreateHashEntry (HashTable, Tcl_DStringValue (&dStr), &hnew); Tcl_DStringSetLength (&dStr, 0); *pc = save; } return 1; } /*---------------------------------------------------------------------------- | StripXSLTSpace | \---------------------------------------------------------------------------*/ static void StripXSLTSpace ( domNode * node ) { domNode *child, *newChild, *parent; domLength i, len; int onlySpace; char *p; if (node->nodeType == TEXT_NODE) { node->info = (int)unknown; p = ((domTextNode*)node)->nodeValue; len = ((domTextNode*)node)->valueLength; onlySpace = 1; for (i=0; iparentNode && (node->parentNode->info == text)) { /* keep white texts below xsl:text elements */ return; } parent = node->parentNode; while (parent) { p = getAttr(parent,"xml:space", a_space); if (p!=NULL) { if (strcmp(p,"preserve")==0) return; if (strcmp(p,"default")==0) break; } parent = parent->parentNode; } DBG(fprintf(stderr, "removing domNode0x%x(len %d) under '%s' \n", node, len, node->parentNode->nodeName);) domDeleteNode (node, NULL, NULL); } } else if (node->nodeType == ELEMENT_NODE) { getTag(node); child = node->firstChild; while (child) { newChild = child->nextSibling; StripXSLTSpace (child); child = newChild; } } else { node->info = (int)unknown; } } /*---------------------------------------------------------------------------- | addExclExtNS | \---------------------------------------------------------------------------*/ static int parseList ( xsltSubDoc *docData, domNode *xsltRoot, char *str, int extensionNS, char **errMsg ) { xsltExclExtNS *eNS; char *pc, *start, save; domNS *ns; if (str) { pc = str; while (*pc) { while (*pc && IS_XML_WHITESPACE(*pc)) pc++; if (*pc == '\0') break; start = pc; while (*pc && !IS_XML_WHITESPACE(*pc)) pc++; save = *pc; *pc = '\0'; eNS = (xsltExclExtNS *)MALLOC(sizeof (xsltExclExtNS)); eNS->uri = NULL; if (extensionNS) { eNS->next = docData->extensionNS; docData->extensionNS = eNS; } else { eNS->next = docData->excludeNS; docData->excludeNS = eNS; } if (strcmp (start, "#default")==0) { ns = domLookupPrefix (xsltRoot, ""); if (!ns) { reportError (xsltRoot, "All prefixes listed in" " exclude-result-prefixes and" " extension-element-prefixes must be" " bound to a namespace.", errMsg); return -1; } } else { ns = domLookupPrefix (xsltRoot, start); if (!ns) { reportError (xsltRoot, "All prefixes listed in" " exclude-result-prefixes and" " extension-element-prefixes must be" " bound to a namespace.", errMsg); return -1; } eNS->uri = tdomstrdup (ns->uri); } *pc = save; } } return 1; } static int addExclExtNS ( xsltSubDoc *docData, domNode *xsltRoot, char **errMsg ) { char *str, *tailptr; int rc; double d; str = getAttr (xsltRoot, "version", a_version); if (!str) { reportError (xsltRoot, "missing mandatory attribute \"version\".", errMsg); return -1; } d = strtod (str, &tailptr); if (d == 0.0 && tailptr == str) { reportError (xsltRoot, "The value of the attribute \"version\" must" " be a number.", errMsg); return -1; } if (d > 1.0) { docData->fwCmpProcessing = 1; } else { if (d != 1.0) { reportError (xsltRoot, "Strange \"version\" value.", errMsg); return -1; } } str = getAttr (xsltRoot, "exclude-result-prefixes", a_excludeResultPrefixes); rc = parseList (docData, xsltRoot, str, 0, errMsg); CHECK_RC; str = getAttr (xsltRoot, "extension-element-prefixes", a_extensionElementPrefixes); rc = parseList (docData, xsltRoot, str, 1, errMsg); CHECK_RC; return 1; } /*---------------------------------------------------------------------------- | getExternalDocument | \---------------------------------------------------------------------------*/ static domDocument * getExternalDocument ( Tcl_Interp *interp, xsltState *xs, domDocument *xsltDoc, const char *baseURI, const char *href, int isStylesheet, int fixedXMLSource, char **errMsg ) { Tcl_Obj *cmdPtr, *resultObj, *extbaseObj, *xmlstringObj; Tcl_Obj *channelIdObj, *resultTypeObj; int mode, result, storeLineColumn; domLength len; int resultcode = 0; char *resultType, *extbase, *xmlstring, *channelId, s[20]; Tcl_Obj *extResolver = NULL; const char *str; domDocument *doc; xsltSubDoc *sdoc; XML_Parser parser; Tcl_Channel chan; Tcl_DString dStr; domParseForestErrorData forestError; if (isStylesheet && (href[0] == '\0')) { *errMsg = tdomstrdup("Recursive import/include: stylesheet tries " "to access itself."); return NULL; } DBG( fprintf (stderr, "getExternalDocument: baseURI '%s'\n", baseURI); fprintf (stderr, "getExternalDocument: systemID '%s'\n", href); ) cmdPtr = Tcl_NewStringObj (xsltDoc->extResolver, -1); Tcl_IncrRefCount (cmdPtr); if (baseURI) { Tcl_ListObjAppendElement(interp, cmdPtr, Tcl_NewStringObj (baseURI, (domLength)strlen(baseURI))); } else { Tcl_ListObjAppendElement(interp, cmdPtr, Tcl_NewStringObj ("", 0)); } Tcl_ListObjAppendElement (interp, cmdPtr, (href ? Tcl_NewStringObj (href, (domLength)strlen (href)) : Tcl_NewStringObj ("", 0))); Tcl_ListObjAppendElement (interp, cmdPtr, Tcl_NewStringObj ("", 0)); result = Tcl_EvalObjEx (interp, cmdPtr, TCL_EVAL_DIRECT | TCL_EVAL_GLOBAL); Tcl_DecrRefCount (cmdPtr); resultObj = Tcl_GetObjResult (interp); Tcl_IncrRefCount (resultObj); if (result != TCL_OK) { goto wrongScriptResult; } result = Tcl_ListObjLength (interp, resultObj, &len); if ((result != TCL_OK) || (len != 3)) { goto wrongScriptResult; } result = Tcl_ListObjIndex (interp, resultObj, 0, &resultTypeObj); if (result != TCL_OK) { goto wrongScriptResult; } resultType = Tcl_GetString(resultTypeObj); if (strcmp (resultType, "string") == 0) { Tcl_ListObjIndex (interp, resultObj, 2, &xmlstringObj); xmlstring = Tcl_GetStringFromObj (xmlstringObj, &len); chan = NULL; } else if (strcmp (resultType, "channel") == 0) { xmlstring = NULL; len = 0; Tcl_ListObjIndex (interp, resultObj, 2, &channelIdObj); channelId = Tcl_GetString(channelIdObj); chan = Tcl_GetChannel (interp, channelId, &mode); if (chan == (Tcl_Channel) NULL) { goto wrongScriptResult; } if ((mode & TCL_READABLE) == 0) { *errMsg = tdomstrdup("-externalentitycommand returned a channel that wasn't opened for reading"); return NULL; } } else if (strcmp (resultType, "filename") == 0) { *errMsg = tdomstrdup("-externalentitycommand result type \"filename\" not yet implemented"); return NULL; } else { goto wrongScriptResult; } Tcl_ListObjIndex (interp, resultObj, 1, &extbaseObj); extbase = Tcl_GetString(extbaseObj); /* Since stylesheets and source docouments have different white space stripping rules, an already parsed tree could only reused, if the 'usage type' of the already present tree is the same as for the currently requested document */ sdoc = xs->subDocs; while (sdoc) { if (isStylesheet == sdoc->isStylesheet && sdoc->baseURI && strcmp(sdoc->baseURI, extbase) == 0) { Tcl_DecrRefCount (resultObj); return sdoc->doc; } sdoc = sdoc->next; } if (xsltDoc->documentElement->nodeFlags & HAS_LINE_COLUMN) { storeLineColumn = 1; } else { storeLineColumn = 0; } parser = XML_ParserCreate_MM (NULL, MEM_SUITE, NULL); Tcl_ResetResult (interp); if (xsltDoc->extResolver) { extResolver = Tcl_NewStringObj(xsltDoc->extResolver, -1); Tcl_IncrRefCount (extResolver); } /* keep white space, no fiddling with the encoding (is this a good idea?) */ doc = domReadDocument (parser, xmlstring, len, 0, 0, storeLineColumn, 0, 0, NULL, chan, extbase, extResolver, 0, 0, (int) XML_PARAM_ENTITY_PARSING_ALWAYS, #ifndef TDOM_NO_SCHEMA NULL, #endif interp, &forestError, &resultcode); if (xsltDoc->extResolver) { Tcl_DecrRefCount (extResolver); } if (doc == NULL) { DBG(fprintf (stderr, "parse error, str len %d, xmlstring: -->%s<--\n", strlen (xmlstring), xmlstring);) Tcl_DStringInit (&dStr); Tcl_DStringAppend (&dStr, "Error while processing external entity \"", -1); Tcl_DStringAppend (&dStr, href, -1); Tcl_DStringAppend (&dStr, "\":\n", -1); str = Tcl_GetStringResult (interp); if (str[0] == '\0') { Tcl_DStringAppend (&dStr, "At line ", -1); sprintf (s, "%" TDOM_LS_MODIFIER "d", XML_GetCurrentLineNumber (parser)); Tcl_DStringAppend (&dStr, s, -1); Tcl_DStringAppend (&dStr, " character ", -1); sprintf (s, "%" TDOM_LS_MODIFIER "d", XML_GetCurrentColumnNumber (parser)); Tcl_DStringAppend (&dStr, s, -1); Tcl_DStringAppend (&dStr, ": ", 2); Tcl_DStringAppend (&dStr, XML_ErrorString (XML_GetErrorCode(parser)), -1); } else { Tcl_DStringAppend (&dStr, str, -1); } *errMsg = tdomstrdup (Tcl_DStringValue (&dStr)); Tcl_DStringFree (&dStr); XML_ParserFree (parser); Tcl_DecrRefCount (resultObj); return NULL; } XML_ParserFree (parser); /* TODO: If the stylesheet use the literal-result-element-as-stylesheet form, rewrite it to a "ordinary" stylesheet with root element xsl:stylesheet, with one template child with match pattern "/". */ sdoc = (xsltSubDoc*)MALLOC(sizeof (xsltSubDoc)); sdoc->doc = doc; sdoc->baseURI = tdomstrdup (extbase); Tcl_InitHashTable (&(sdoc->keyData), TCL_STRING_KEYS); sdoc->excludeNS = NULL; sdoc->extensionNS = NULL; sdoc->fwCmpProcessing = 0; sdoc->mustFree = 1; sdoc->isStylesheet = isStylesheet; sdoc->fixedXMLSource = fixedXMLSource; if (isStylesheet) { if (addExclExtNS (sdoc, doc->documentElement, errMsg) < 0) { Tcl_DeleteHashTable (&(sdoc->keyData)); domFreeDocument (sdoc->doc, NULL, NULL); FREE (sdoc->baseURI); FREE (sdoc); Tcl_DecrRefCount (resultObj); return NULL; } StripXSLTSpace (doc->rootNode); } sdoc->next = xs->subDocs; xs->subDocs = sdoc; Tcl_DecrRefCount (resultObj); return doc; wrongScriptResult: *errMsg = tdomstrdup(Tcl_GetStringResult(interp)); Tcl_DecrRefCount (resultObj); return NULL; } /*---------------------------------------------------------------------------- | processTopLevelVars | \---------------------------------------------------------------------------*/ static int processTopLevelVars ( domNode * xmlNode, xsltState * xs, char ** parameters, int ignoreUndeclaredParameters, char ** errMsg ) { int rc, i; char *select, prefix[MAX_PREFIX_LEN]; const char *localName; xpathResultSet nodeList, rs; Tcl_HashEntry *entryPtr; Tcl_HashSearch search; xsltTopLevelVar *topLevelVar; xsltVarInProcess varInProcess; xsltVariable *var; domNS *ns; Tcl_DString dStr; xpathRSInit (&nodeList); rsAddNodeFast (&nodeList, xmlNode); if (parameters) { i = 0; while (parameters[i]) { domSplitQName (parameters[i], prefix, &localName); ns = NULL; if (prefix[0] != '\0') { ns = domLookupPrefix (xs->xsltDoc->documentElement, prefix); if (!ns) { Tcl_DStringInit (&dStr); Tcl_DStringAppend (&dStr, "No namespace bound to prefix" " (passed parameter \"", -1); Tcl_DStringAppend (&dStr, parameters[i], -1); Tcl_DStringAppend (&dStr, "\")", -1); *errMsg = tdomstrdup (Tcl_DStringValue (&dStr)); Tcl_DStringFree (&dStr); xpathRSFree (&nodeList); return -1; } } Tcl_DStringInit (&dStr); if (ns) Tcl_DStringAppend (&dStr, ns->uri, -1); Tcl_DStringAppend (&dStr, localName, -1); entryPtr = Tcl_FindHashEntry (&xs->topLevelVars, Tcl_DStringValue (&dStr)); Tcl_DStringFree (&dStr); if (!entryPtr) { if (ignoreUndeclaredParameters) { i += 2; continue; } Tcl_DStringInit (&dStr); Tcl_DStringAppend (&dStr, "There isn't a parameter named \"", -1); Tcl_DStringAppend (&dStr, parameters[i], -1); Tcl_DStringAppend (&dStr, "\" defined at top level in the stylesheet.", -1); *errMsg = tdomstrdup (Tcl_DStringValue (&dStr)); Tcl_DStringFree (&dStr); xpathRSFree (&nodeList); return -1; } topLevelVar = (xsltTopLevelVar *) Tcl_GetHashValue (entryPtr); if (!topLevelVar->isParameter) { Tcl_DStringInit (&dStr); Tcl_DStringAppend (&dStr, "\"", 1); Tcl_DStringAppend (&dStr, parameters[i], -1); Tcl_DStringAppend (&dStr, "\" is defined as variable, not as parameter.", -1); *errMsg = tdomstrdup (Tcl_DStringValue (&dStr)); Tcl_DStringFree (&dStr); xpathRSFree (&nodeList); return -1; } if (xsltVarExists (xs, parameters[i], NULL)) { i += 2; continue; } xpathRSInit (&rs); rsSetString (&rs, parameters[i+1]); xs->varStackPtr++; if (xs->varStackPtr >= xs->varStackLen) { xs->varStack = (xsltVariable *) REALLOC ((char*)xs->varStack, sizeof (xsltVariable) * 2*xs->varStackLen); xs->varStackLen *= 2; } var = &(xs->varStack[xs->varStackPtr]); if (!xs->varFramesStack->nrOfVars) { xs->varFramesStack->varStartIndex = xs->varStackPtr; } xs->varFramesStack->nrOfVars++; var->name = localName; if (ns) var->uri = ns->uri; else var->uri = NULL; var->node = topLevelVar->node; var->rs = rs; var->active = 1; i += 2; } } for (entryPtr = Tcl_FirstHashEntry(&xs->topLevelVars, &search); entryPtr != (Tcl_HashEntry*) NULL; entryPtr = Tcl_NextHashEntry(&search)) { topLevelVar = (xsltTopLevelVar *)Tcl_GetHashValue (entryPtr); if (xsltVarExists (xs, topLevelVar->name, topLevelVar->node)) { continue; } varInProcess.name = topLevelVar->name; varInProcess.next = NULL; xs->varsInProcess = &varInProcess; xs->currentXSLTNode = topLevelVar->node; select = getAttr (topLevelVar->node, "select", a_select); if (select && topLevelVar->node->firstChild) { xpathRSFree (&nodeList); reportError (topLevelVar->node, "xsl:variable and xsl:param" " elements with a select attribute must be empty", errMsg); return -1; } rc = xsltSetVar(xs, topLevelVar->name, &nodeList, xmlNode, 0, select, topLevelVar->node, 1, errMsg); if (rc < 0) { xpathRSFree (&nodeList); return rc; } } xpathRSFree (&nodeList); xs->currentXSLTNode = NULL; xs->varsInProcess = NULL; return 0; } /*---------------------------------------------------------------------------- | processTopLevel | \---------------------------------------------------------------------------*/ static int processTopLevel ( Tcl_Interp * interp, domNode * xsltDocumentElement, xsltState * xs, double precedence, double * precedenceLowBound, char ** errMsg ) { domNode *node; domDocument *extStyleSheet; int rc, hnew, clen, newdf = 0, nonImportElemSeen = 0; int ignore; double childPrecedence, childLowBound; char *str, *name, *match, *use, *href; char prefix[MAX_PREFIX_LEN]; const char *localName, *baseURI; xsltTag tag; xsltAttrSet *attrSet; xsltKeyInfo *keyInfo; xsltDecimalFormat *df; xsltTopLevelVar *topLevelVar; xsltNSAlias *nsAlias; domNS *ns, *nsFrom, *nsTo; Tcl_HashEntry *h; Tcl_DString dStr; DBG(fprintf (stderr, "start processTopLevel. precedence: %f precedenceLowBound %f\n", precedence, *precedenceLowBound);); node = xsltDocumentElement->firstChild; while (node) { tag = getTag (node); if (!nonImportElemSeen && tag != unknown && tag != import) { nonImportElemSeen = 1; } switch ( tag ) { case attributeSet: str = getAttr(node, "name", a_name); if (str) { domSplitQName (str, prefix, &localName); ns = NULL; if (prefix[0] != '\0') { ns = domLookupPrefix (node, prefix); if (!ns) { reportError (node, "There isn't a namespace" " bound to the prefix.", errMsg); return -1; } } if (xs->attrSets) { attrSet = xs->attrSets; while (attrSet->next) attrSet = attrSet->next; attrSet->next = (xsltAttrSet*)MALLOC(sizeof(xsltAttrSet)); attrSet = attrSet->next; } else { attrSet = (xsltAttrSet*)MALLOC(sizeof(xsltAttrSet)); xs->attrSets = attrSet; } attrSet->next = NULL; attrSet->content = node; attrSet->name = localName; attrSet->inUse = 0; if (ns) { attrSet->uri = ns->uri; } else { attrSet->uri = NULL; } } else { reportError (node, "xsl:attribute-set: missing mandatory" " attribute \"name\".", errMsg); return -1; } break; case decimalFormat: if (node->firstChild) { reportError (node, "xsl:decimal-format has to be empty.", errMsg); return -1; } str = getAttr(node, "name", a_name); if (str) { domSplitQName (str, prefix, &localName); ns = NULL; if (prefix[0] != '\0') { ns = domLookupPrefix (node, prefix); if (!ns) { reportError (node, "There isn't a namespace bound" " to the prefix.", errMsg); return -1; } } /* a named decimal format */ df = xs->decimalFormats->next; while (df) { if (strcmp(df->name, str)==0 && ((df->uri == NULL && ns == NULL) || (df->uri != NULL && ns != NULL && (strcmp (df->uri, ns->uri)==0)))) { /* already existing, override it */ break; } df = df->next; } if (df == NULL) { df = (xsltDecimalFormat*)MALLOC(sizeof(xsltDecimalFormat)); memset (df, 0, sizeof (xsltDecimalFormat)); newdf = 1; /* initialize to defaults */ df->decimalSeparator = 46; df->groupingSeparator = 44; df->infinity = "Infinity"; df->minusSign = 45; df->NaN = "NaN"; df->percent = 37; df->perMille = 0x2030; df->zeroDigit = 48; df->digit = 35; df->patternSeparator = 59; df->name = tdomstrdup(str); if (ns) df->uri = tdomstrdup(ns->uri); else df->uri = NULL; /* prepend into list of decimal format after the default one */ df->next = xs->decimalFormats->next; xs->decimalFormats->next = df; } } else { /* definitions for default decimal format */ df = xs->decimalFormats; } str = getAttr(node, "decimal-separator", a_decimalSeparator); if (str) { clen = UTF8_CHAR_LEN (str[0]); if (!clen || str[clen] != '\0') { reportError (node, "decimal-separator has to be a" " single char", errMsg); if (newdf) FREE((char*)df); return -1; } Tcl_UtfToUniChar (str, &df->decimalSeparator); } str = getAttr(node, "grouping-separator", a_groupingSeparator); if (str) { clen = UTF8_CHAR_LEN (str[0]); if (!clen || str[clen] != '\0') { reportError (node, "groupingSeparator has to be a" " single char", errMsg); if (newdf) FREE((char*)df); return -1; } Tcl_UtfToUniChar (str, &df->groupingSeparator); } str = getAttr(node, "infinity", a_infinity); if (str) df->infinity = str; str = getAttr(node, "minus-sign", a_minusSign); if (str) { clen = UTF8_CHAR_LEN (str[0]); if (!clen || str[clen] != '\0') { reportError (node, "minus-sign has to be a single" " char", errMsg); if (newdf) FREE((char*)df); return -1; } Tcl_UtfToUniChar (str, &df->minusSign); } str = getAttr(node, "NaN", a_nan); if (str) df->NaN = str; str = getAttr(node, "percent", a_percent); if (str) { if (str[1] != '\0') { reportError (node, "percent has to be a single" " char", errMsg); return -1; } df->percent = str[0]; clen = UTF8_CHAR_LEN (str[0]); if (!clen || str[clen] != '\0') { reportError (node, "percent has to be a single" " char", errMsg); if (newdf) FREE((char*)df); return -1; } Tcl_UtfToUniChar (str, &df->percent); } str = getAttr(node, "per-mille", a_perMille); if (str) { clen = UTF8_CHAR_LEN (str[0]); if (!clen || str[clen] != '\0') { reportError (node, "per-mille has to be a single" " char", errMsg); if (newdf) FREE((char*)df); return -1; } Tcl_UtfToUniChar (str, &df->perMille); } str = getAttr(node, "zero-digit", a_zeroDigit); if (str) { clen = UTF8_CHAR_LEN (str[0]); if (!clen || str[clen] != '\0') { reportError (node, "zero-digit has to be a single" " char", errMsg); if (newdf) FREE((char*)df); return -1; } Tcl_UtfToUniChar (str, &df->zeroDigit); } str = getAttr(node, "digit", a_digit); if (str) { clen = UTF8_CHAR_LEN (str[0]); if (!clen || str[clen] != '\0') { reportError (node, "digit has to be a single char", errMsg); if (newdf) FREE((char*)df); return -1; } Tcl_UtfToUniChar (str, &df->digit); } str = getAttr(node, "pattern-separator", a_patternSeparator); if (str) { clen = UTF8_CHAR_LEN (str[0]); if (!clen || str[clen] != '\0') { reportError (node, "pattern-separator has to be a" " single char", errMsg); return -1; } Tcl_UtfToUniChar (str, &df->patternSeparator); } break; case import: if (nonImportElemSeen) { reportError (node, "xsl:import elements must come first", errMsg); return -1; } if (node->firstChild) { reportError (node, "xsl:import has to be empty!", errMsg); return -1; } if (!node->ownerDocument->extResolver) { reportError (node, "need resolver Script to include" " Stylesheet! (use" " \"-externalentitycommand\")", errMsg); return -1; } baseURI = findBaseURI (node); href = getAttr (node, "href", a_href); if (!href) { reportError (node, "xsl:import: missing mandatory" " attribute \"href\".", errMsg); return -1; } extStyleSheet = getExternalDocument (interp, xs, node->ownerDocument, baseURI, href, 1, 0, errMsg); if (!extStyleSheet) { return -1; } childPrecedence = (precedence + *precedenceLowBound) / 2; childLowBound = *precedenceLowBound; rc = processTopLevel (interp, extStyleSheet->documentElement, xs, childPrecedence, &childLowBound, errMsg); *precedenceLowBound = childPrecedence; if (rc != 0) { return rc; } break; case include: if (node->firstChild) { reportError (node, "xsl:include has to be empty.", errMsg); return -1; } if (!node->ownerDocument->extResolver) { reportError (node, "need resolver Script to include" "Stylesheet. (use" " \"-externalentitycommand\")", errMsg); return -1; } baseURI = findBaseURI (node); href = getAttr (node, "href", a_href); if (!href) { reportError (node, "xsl:include: missing mandatory" " attribute \"href\".", errMsg); return -1; } extStyleSheet = getExternalDocument (interp, xs, node->ownerDocument, baseURI, href, 1, 0, errMsg); if (!extStyleSheet) { return -1; } xs->currentXSLTNode = extStyleSheet->documentElement; rc = processTopLevel (interp, extStyleSheet->documentElement, xs, precedence, precedenceLowBound, errMsg); if (rc != 0) { return rc; } break; case key: if (node->firstChild) { reportError (node, "xsl:key has to be empty.", errMsg); return -1; } name = getAttr(node, "name", a_name); if (!name) { reportError (node, "xsl:key: missing mandatory" " attribute \"name\".", errMsg); return -1; } match = getAttr(node, "match", a_match); if (!match) { reportError (node, "xsl:key: missing mandatory" " attribute \"match\".", errMsg); return -1; } use = getAttr(node, "use", a_use); if (!use) { reportError (node, "xsl:key: missing mandatory" " attribute \"use\".", errMsg); return -1; } keyInfo = (xsltKeyInfo *)MALLOC(sizeof(xsltKeyInfo)); keyInfo->node = node; rc = xpathParse (match, node, XPATH_KEY_MATCH_PATTERN, NULL, NULL, &(keyInfo->matchAst), errMsg); if (rc < 0) { reportError (node, *errMsg, errMsg); FREE ((char*)keyInfo); return rc; } keyInfo->use = use; rc = xpathParse (use, node, XPATH_KEY_USE_EXPR, NULL, NULL, &(keyInfo->useAst), errMsg); if (rc < 0) { reportError (node, *errMsg, errMsg); xpathFreeAst (keyInfo->matchAst); FREE ((char*)keyInfo); return rc; } domSplitQName (name, prefix, &localName); Tcl_DStringInit (&dStr); if (prefix[0] != '\0') { ns = domLookupPrefix (node, prefix); if (!ns) { reportError (node, "There isn't a namespace bound" " to the prefix.", errMsg); xpathFreeAst (keyInfo->matchAst); xpathFreeAst (keyInfo->useAst); FREE((char*)keyInfo); return -1; } Tcl_DStringAppend (&dStr, ns->uri, -1); } Tcl_DStringAppend (&dStr, localName, -1); h = Tcl_CreateHashEntry (&(xs->keyInfos), Tcl_DStringValue (&dStr), &hnew); Tcl_DStringFree (&dStr); if (hnew) { keyInfo->next = NULL; } else { keyInfo->next = (xsltKeyInfo *)Tcl_GetHashValue (h); } Tcl_SetHashValue (h, keyInfo); break; case namespaceAlias: if (node->firstChild) { reportError (node, "xsl:namespace-alias has to be empty.", errMsg); return -1; } str = getAttr (node, "stylesheet-prefix", a_stylesheetPrefix); if (!str) { reportError (node, "xsl:namespace-alias: missing" " mandatory attribute" " \"stylesheet-prefix\".", errMsg); return -1 ; } if (strcmp (str, "#default")==0) { str = NULL; nsFrom = domLookupPrefix (node, ""); } else { nsFrom = domLookupPrefix (node, str); } if (!nsFrom) { reportError (node, "xsl:namespace-alias: no namespace" " bound to the \"stylesheet-prefix\".", errMsg); return -1; } str = getAttr (node, "result-prefix", a_resultPrefix); if (!str) { reportError (node, "xsl:namespace-alias: missing mandatory" " attribute \"result-prefix\".", errMsg); return -1; } if (strcmp (str, "#default")==0) { nsTo = domLookupPrefix (node, ""); } else { nsTo = domLookupPrefix (node, str); } if (!nsTo) { reportError (node, "xsl:namespace-alias: no namespace" " bound to the \"result-prefix\".", errMsg); return -1; } nsAlias = xs->nsAliases; ignore = 0; while (nsAlias) { if (strcmp (nsAlias->fromUri, nsFrom->uri)==0) { if (nsAlias->precedence > precedence) { ignore = 1; } break; } nsAlias = nsAlias->next; } if (ignore) break; if (nsAlias) { FREE(nsAlias->toUri); } else { nsAlias = (xsltNSAlias *)MALLOC(sizeof (xsltNSAlias)); nsAlias->fromUri = tdomstrdup (nsFrom->uri); nsAlias->next = xs->nsAliases; xs->nsAliases = nsAlias; } nsAlias->toUri = tdomstrdup (nsTo->uri); nsAlias->precedence = precedence; break; case output: if (node->firstChild) { reportError (node, "xsl:output has to be empty.", errMsg); return -1; } str = getAttr(node, "method", a_method); if (str) { if (xs->doctype.method) FREE(xs->doctype.method); xs->doctype.method = tdomstrdup(str); } str = getAttr(node, "encoding", a_encoding); if (str) { if (xs->doctype.encoding) FREE(xs->doctype.encoding); xs->doctype.encoding = tdomstrdup(str); } str = getAttr(node, "omit-xml-declaration", a_omitXMLDeclaration); if (str) { if (strcmp (str, "yes") == 0) { xs->doctype.omitXMLDeclaration = 1; } else if (strcmp (str, "no") == 0) { xs->doctype.omitXMLDeclaration = 0; } else { reportError (node, "Unexpected value for" " 'omit-xml-declaration' attribute", errMsg); return -1; } } str = getAttr(node, "standalone", a_standalone); if (str) { if (strcmp (str, "yes") == 0) { xs->doctype.standalone = 1; } else if (strcmp (str, "no") == 0) { xs->doctype.standalone = 0; } else { reportError (node, "Unexpected value for 'standalone'" " attribute", errMsg); return -1; } } str = getAttr(node, "doctype-public", a_doctypePublic); if (str) { if (xs->doctype.publicId) { FREE ((char*) xs->doctype.publicId); } xs->doctype.publicId = tdomstrdup(str); } str = getAttr(node, "doctype-system", a_doctypeSystem); if (str) { if (xs->doctype.systemId) { FREE ((char*) xs->doctype.systemId); } xs->doctype.systemId = tdomstrdup(str); } str = getAttr(node, "cdata-section-elements", a_cdataSectionElements); if (str) { if (!xs->doctype.cdataSectionElements) { xs->doctype.cdataSectionElements = (Tcl_HashTable *) MALLOC (sizeof (Tcl_HashTable)); Tcl_InitHashTable (xs->doctype.cdataSectionElements, TCL_STRING_KEYS); } if (!getCdataSectionElements (node, str, xs->doctype.cdataSectionElements, errMsg)) { return -1; } } str = getAttr(node, "indent", a_indent); if (str) { if (strcmp (str, "yes") == 0) { xs->indentOutput = 1; } else if (strcmp (str, "no") == 0) { xs->indentOutput = 0; } else { reportError (node, "Unexpected value for 'indent'" " attribute.", errMsg); return -1; } } str = getAttr(node, "media-type", a_mediaType); if (str) { if (xs->doctype.mediaType) FREE(xs->doctype.mediaType); xs->doctype.mediaType = tdomstrdup(str); } break; case preserveSpace: if (node->firstChild) { reportError (node, "xsl:preserve-space has to be empty.", errMsg); return -1; } str = getAttr(node, "elements", a_elements); if (str) { rc = fillElementList(&xs->wsInfo, 0, precedence, node, str, errMsg); CHECK_RC; } else { reportError (node, "xsl:preserve-space: missing required" " attribute \"elements\".", errMsg); return -1; } break; case stripSpace: if (node->firstChild) { reportError (node, "xsl:strip-space has to be empty.", errMsg); return -1; } str = getAttr(node, "elements", a_elements); if (str) { rc = fillElementList(&xs->wsInfo, 1, precedence, node, str, errMsg); CHECK_RC; } else { reportError (node, "xsl:strip-space: missing required" " attribute \"elements\".", errMsg); return -1; } break; case template: rc = xsltAddTemplate (xs, node, precedence, errMsg); CHECK_RC; break; case param: case variable: str = getAttr(node, "name", a_name); if (!str) { reportError (node, "xsl:variable and xsl:param elements" " must have a \"name\" attribute.", errMsg); return -1; } domSplitQName (str, prefix, &localName); ns = NULL; if (prefix[0] != '\0') { ns = domLookupPrefix (node, prefix); if (!ns) { reportError (node, "There isn't a namespace bound" " to the prefix.", errMsg); return -1; } } Tcl_DStringInit (&dStr); if (ns) { Tcl_DStringAppend (&dStr, ns->uri, -1); } Tcl_DStringAppend (&dStr, localName, -1); h = Tcl_CreateHashEntry (&(xs->topLevelVars), Tcl_DStringValue (&dStr), &hnew); Tcl_DStringFree (&dStr); if (!hnew) { topLevelVar = (xsltTopLevelVar *)Tcl_GetHashValue (h); /* Since imported stylesheets are processed at the point at which they encounters the definitions are already in increasing order of import precedence. Therefore, we have only to check, if there is a top level var or parm with the same precedence */ if (topLevelVar->precedence == precedence) { reportError (node, "There is already a variable" " or parameter with this name with the" " same import precedence.", errMsg); return -1; } } else { topLevelVar = (xsltTopLevelVar *) MALLOC (sizeof (xsltTopLevelVar)); Tcl_SetHashValue (h, topLevelVar); } topLevelVar->node = node; topLevelVar->name = str; if (tag == param) { topLevelVar->isParameter = 1; } else { topLevelVar->isParameter = 0; } topLevelVar->precedence = precedence; break; default: if (node->nodeType == ELEMENT_NODE) { if (!node->namespace) { reportError (node, "Top level elements must have a" " non-null namespace URI.", errMsg); return -1; } if (strcmp (XSLT_NAMESPACE, domNamespaceURI (node))==0) { if (!xs->currentSubDoc->fwCmpProcessing) { reportError (node, "XSLT element not allowed" " on top level or unknown XSLT" " element.", errMsg); return -1; } } } else if (node->nodeType == TEXT_NODE) { char *pc; int i, only_whites; only_whites = 1; for (i=0, pc = ((domTextNode*)node)->nodeValue; i < ((domTextNode*)node)->valueLength; i++, pc++) { if (!IS_XML_WHITESPACE(*pc)) { only_whites = 0; break; } } if (!only_whites) { reportError (node, "Non-whitespace text is not" " allowed between top level elements.", errMsg); return -1; } } break; } node = node->nextSibling; } return 0; } /*---------------------------------------------------------------------------- | xsltFreeState | \---------------------------------------------------------------------------*/ static void xsltFreeState ( xsltState * xs ) { xsltDecimalFormat *df, *dfsave; xsltKeyInfo *ki, *kisave; xsltNodeSet *kvalues; xsltSubDoc *sd, *sdsave; xsltAttrSet *as, *assave; xsltTemplate *tpl, *tplsave; xsltNumberFormat *nf; ast t; xsltTopLevelVar *tlv; xsltNSAlias *nsAlias, *nsAliasSave; xsltExclExtNS *eNS, *eNSsave; Tcl_HashEntry *entryPtr, *entryPtr1; Tcl_HashSearch search, search1; Tcl_HashTable *htable; double *f; if (xs->doctype.systemId) FREE(xs->doctype.systemId); if (xs->doctype.publicId) FREE(xs->doctype.publicId); if (xs->doctype.internalSubset) FREE(xs->doctype.internalSubset); if (xs->doctype.cdataSectionElements) { Tcl_DeleteHashTable (xs->doctype.cdataSectionElements); FREE (xs->doctype.cdataSectionElements); } for (entryPtr = Tcl_FirstHashEntry (&xs->namedTemplates, &search); entryPtr != (Tcl_HashEntry*) NULL; entryPtr = Tcl_NextHashEntry (&search)) { tpl = (xsltTemplate *) Tcl_GetHashValue (entryPtr); if (!tpl->match) { FREE(tpl); } } Tcl_DeleteHashTable (&xs->namedTemplates); for (entryPtr = Tcl_FirstHashEntry (&xs->isElementTpls, &search); entryPtr != (Tcl_HashEntry*) NULL; entryPtr = Tcl_NextHashEntry (&search)) { tpl = (xsltTemplate *) Tcl_GetHashValue (entryPtr); while (tpl) { if (tpl->freeAst) xpathFreeAst (tpl->freeAst); tplsave = tpl; tpl = tpl->next; FREE(tplsave); } } Tcl_DeleteHashTable (&xs->isElementTpls); for (entryPtr = Tcl_FirstHashEntry(&xs->xpaths, &search); entryPtr != (Tcl_HashEntry*) NULL; entryPtr = Tcl_NextHashEntry(&search)) { t = (ast) Tcl_GetHashValue (entryPtr); xpathFreeAst (t); } Tcl_DeleteHashTable(&xs->xpaths); for (entryPtr = Tcl_FirstHashEntry(&xs->pattern, &search); entryPtr != (Tcl_HashEntry*) NULL; entryPtr = Tcl_NextHashEntry(&search)) { t = (ast) Tcl_GetHashValue (entryPtr); xpathFreeAst (t); } Tcl_DeleteHashTable(&xs->pattern); for (entryPtr = Tcl_FirstHashEntry(&xs->formats, &search); entryPtr != (Tcl_HashEntry*) NULL; entryPtr = Tcl_NextHashEntry(&search)) { nf = (xsltNumberFormat *) Tcl_GetHashValue (entryPtr); FREE(nf->tokens); FREE(nf); } Tcl_DeleteHashTable(&xs->formats); for (entryPtr = Tcl_FirstHashEntry(&xs->topLevelVars, &search); entryPtr != (Tcl_HashEntry*) NULL; entryPtr = Tcl_NextHashEntry(&search)) { tlv = (xsltTopLevelVar *) Tcl_GetHashValue (entryPtr); FREE(tlv); } Tcl_DeleteHashTable (&xs->topLevelVars); /*--- free key definition information ---*/ for (entryPtr = Tcl_FirstHashEntry (&xs->keyInfos, &search); entryPtr != (Tcl_HashEntry*) NULL; entryPtr = Tcl_NextHashEntry (&search)) { ki = (xsltKeyInfo *) Tcl_GetHashValue (entryPtr); while (ki) { kisave = ki; ki = ki->next; xpathFreeAst (kisave->matchAst); xpathFreeAst (kisave->useAst); FREE(kisave); } } Tcl_DeleteHashTable (&xs->keyInfos); /*--- free sub documents ---*/ sd = xs->subDocs; while (sd) { sdsave = sd; sd = sd->next; for (entryPtr = Tcl_FirstHashEntry (&sdsave->keyData, &search); entryPtr != (Tcl_HashEntry*) NULL; entryPtr = Tcl_NextHashEntry (&search)) { htable = (Tcl_HashTable *) Tcl_GetHashValue (entryPtr); for (entryPtr1 = Tcl_FirstHashEntry (htable, &search1); entryPtr1 != (Tcl_HashEntry*) NULL; entryPtr1 = Tcl_NextHashEntry (&search1)) { kvalues = (xsltNodeSet *) Tcl_GetHashValue (entryPtr1); FREE(kvalues->nodes); FREE(kvalues); } Tcl_DeleteHashTable (htable); FREE(htable); } Tcl_DeleteHashTable (&sdsave->keyData); eNS = sdsave->excludeNS; while (eNS) { if (eNS->uri) FREE(eNS->uri); eNSsave = eNS; eNS = eNS->next; FREE(eNSsave); } eNS = sdsave->extensionNS; while (eNS) { if (eNS->uri) FREE(eNS->uri); eNSsave = eNS; eNS = eNS->next; FREE(eNSsave); } if (sdsave->baseURI) FREE(sdsave->baseURI); if (sdsave->mustFree) { domFreeDocument (sdsave->doc, NULL, NULL); } FREE(sdsave); } nsAlias = xs->nsAliases; while (nsAlias) { nsAliasSave = nsAlias; nsAlias = nsAlias->next; if (nsAliasSave->fromUri) FREE(nsAliasSave->fromUri); if (nsAliasSave->toUri) FREE(nsAliasSave->toUri); FREE(nsAliasSave); } /*--- free decimal formats ---*/ df = xs->decimalFormats; while (df) { dfsave = df; df = df->next; if (dfsave->name) FREE(dfsave->name); if (dfsave->uri) FREE(dfsave->uri); FREE(dfsave); } /*--- free attribute sets ---*/ as = xs->attrSets; while (as) { assave = as; as = as->next; FREE(assave); } /*--- free templates ---*/ tpl = xs->templates; while (tpl) { tplsave = tpl; if (tpl->freeAst) xpathFreeAst (tpl->freeAst); tpl = tpl->next; FREE(tplsave); } for (entryPtr = Tcl_FirstHashEntry (&(xs->wsInfo.stripTokens), &search); entryPtr != (Tcl_HashEntry*) NULL; entryPtr = Tcl_NextHashEntry (&search)) { f = (double *) Tcl_GetHashValue (entryPtr); FREE(f); } Tcl_DeleteHashTable (&(xs->wsInfo.stripTokens)); for (entryPtr = Tcl_FirstHashEntry (&(xs->wsInfo.preserveTokens), &search); entryPtr != (Tcl_HashEntry*) NULL; entryPtr = Tcl_NextHashEntry (&search)) { f = (double *) Tcl_GetHashValue (entryPtr); FREE(f); } Tcl_DeleteHashTable (&(xs->wsInfo.preserveTokens)); FREE(xs->varFramesStack); FREE(xs->varStack); if (xs->doctype.method) FREE(xs->doctype.method); if (xs->doctype.encoding) FREE(xs->doctype.encoding); if (xs->doctype.mediaType) FREE(xs->doctype.mediaType); FREE (xs); } void xsltFreeStateWrapper ( void *clientData ) { xsltFreeState ((xsltState *)clientData); } /*---------------------------------------------------------------------------- | xsltResetState | \---------------------------------------------------------------------------*/ static void xsltResetState ( xsltState * xs ) { xsltSubDoc *sd, *sdsave, *lastSubDoc = NULL; xsltNodeSet *kvalues; Tcl_HashEntry *entryPtr, *entryPtr1; Tcl_HashSearch search, search1; Tcl_HashTable *htable; /* Free the sub documents, which are resolved relative to nodes in * the xml source. */ /* XML documents don't have excludeNS and extensionNS information and the already parsed XSLT documents information is preserved, therefore, we don't touch excludeNS and extensionNS information */ /* This loop works only as coded, because, the first subdoc will * always be the primary XSLT doc, so xs->subDocs will not * change. Crusty stuff, this code. */ sd = xs->subDocs; while (sd) { sdsave = sd; sd = sd->next; if (sdsave->isStylesheet || sdsave->fixedXMLSource) { if (lastSubDoc) { lastSubDoc->next = sdsave; } else { xs->subDocs = sdsave; } lastSubDoc = sdsave; sdsave->next = NULL; } else { for (entryPtr = Tcl_FirstHashEntry (&sdsave->keyData, &search); entryPtr != (Tcl_HashEntry*) NULL; entryPtr = Tcl_NextHashEntry (&search)) { htable = (Tcl_HashTable *) Tcl_GetHashValue (entryPtr); for (entryPtr1 = Tcl_FirstHashEntry (htable, &search1); entryPtr1 != (Tcl_HashEntry*) NULL; entryPtr1 = Tcl_NextHashEntry (&search1)) { kvalues = (xsltNodeSet *) Tcl_GetHashValue (entryPtr1); FREE(kvalues->nodes); FREE(kvalues); } Tcl_DeleteHashTable (htable); FREE(htable); } Tcl_DeleteHashTable (&sdsave->keyData); if (sdsave->mustFree) { domFreeDocument (sdsave->doc, NULL, NULL); } if (sdsave->baseURI) FREE(sdsave->baseURI); FREE(sdsave); } } xs->nsUniqeNr = 0; /* In theory, the varFramesStack and varStack pointers should be always back to there initial state. But to be sure, we re-initialize, just in case of a bizarre error or something. */ xs->varFramesStackPtr = -1; xs->varStackPtr = -1; } /*---------------------------------------------------------------------------- | xsltCompileStylesheet | \---------------------------------------------------------------------------*/ void * xsltCompileStylesheet ( domDocument * xsltDoc, xpathFuncCallback funcCB, void * xpathFuncClientData, int guardXSLTTree, char ** errMsg ) { domNode *node; int rc; char *tailptr; const char *baseURI; double d, precedence, precedenceLowBound; xsltState *xs; xsltSubDoc *sdoc; domAttrNode *attr; xsltTemplate *tpl; if (!xsltDoc->documentElement) { *errMsg = tdomstrdup ("Document has no element node - can't be a valid " "XSLT 1.0 stylesheet."); return NULL; } *errMsg = NULL; xs = (xsltState *) MALLOC (sizeof (xsltState)); Tcl_InitHashTable ( &(xs->namedTemplates), TCL_STRING_KEYS); Tcl_InitHashTable ( &(xs->isElementTpls), TCL_STRING_KEYS); xs->cbs.varCB = xsltGetVar; xs->cbs.varClientData = (void*)xs; xs->cbs.funcCB = xsltXPathFuncs; xs->cbs.funcClientData = xs; xs->orig_funcCB = funcCB; xs->orig_funcClientData = xpathFuncClientData; xs->xsltMsgCB = NULL; xs->xsltMsgClientData = NULL; xs->varFramesStack = (xsltVarFrame *)MALLOC(sizeof (xsltVarFrame)*4); xs->varFramesStackPtr = -1; xs->varFramesStackLen = 4; xs->varStack = (xsltVariable *)MALLOC(sizeof (xsltVariable)*8); xs->varStackPtr = -1; xs->varStackLen = 8; xs->templates = NULL; xs->lastNode = NULL; xs->attrSets = NULL; xs->decimalFormats = (xsltDecimalFormat*)MALLOC(sizeof (xsltDecimalFormat)); xs->subDocs = NULL; xs->currentTplRule = NULL; xs->currentXSLTNode = NULL; xs->xsltDoc = xsltDoc; xs->varsInProcess = NULL; xs->nsAliases = NULL; xs->nsUniqeNr = 0; Tcl_InitHashTable ( &(xs->wsInfo.stripTokens), TCL_STRING_KEYS); Tcl_InitHashTable ( &(xs->wsInfo.preserveTokens), TCL_STRING_KEYS); xs->wsInfo.hasData = 0; xs->wsInfo.stripAll = 0; xs->wsInfo.wildcardPrec = 0.0; Tcl_InitHashTable ( &(xs->xpaths), TCL_STRING_KEYS); Tcl_InitHashTable ( &(xs->pattern), TCL_STRING_KEYS); Tcl_InitHashTable ( &(xs->formats), TCL_STRING_KEYS); Tcl_InitHashTable ( &(xs->topLevelVars), TCL_STRING_KEYS); Tcl_InitHashTable ( &(xs->keyInfos), TCL_STRING_KEYS); xs->decimalFormats->name = NULL; xs->decimalFormats->uri = NULL; xs->decimalFormats->decimalSeparator = 46; xs->decimalFormats->groupingSeparator = 44; xs->decimalFormats->minusSign = 45; xs->decimalFormats->percent = 37; xs->decimalFormats->perMille = 0x2030; xs->decimalFormats->zeroDigit = 48; xs->decimalFormats->digit = 35; xs->decimalFormats->patternSeparator = 59; xs->decimalFormats->infinity = "Infinity"; xs->decimalFormats->NaN = "NaN"; xs->decimalFormats->next = NULL; xs->indentOutput = 0; memset (&xs->doctype, 0, sizeof (domDocInfo)); node = xsltDoc->documentElement; /* add the XSLT doc to the doc list */ sdoc = (xsltSubDoc*)MALLOC(sizeof (xsltSubDoc)); sdoc->doc = xsltDoc; baseURI = findBaseURI (xsltDoc->documentElement); if (baseURI) { sdoc->baseURI = tdomstrdup (baseURI); } else { sdoc->baseURI = NULL; } Tcl_InitHashTable (&(sdoc->keyData), TCL_STRING_KEYS); sdoc->excludeNS = NULL; sdoc->extensionNS = NULL; sdoc->fwCmpProcessing = 0; sdoc->isStylesheet = 1; sdoc->next = xs->subDocs; sdoc->mustFree = !guardXSLTTree; sdoc->fixedXMLSource = 0; xs->subDocs = sdoc; xs->currentSubDoc = sdoc; if ((getTag(node) != stylesheet) && (getTag(node) != transform)) { /* Check for "Literal Result Element as Stylesheet" (XSLT rec 2.3) */ attr = domGetAttributeNodeNS (node, XSLT_NAMESPACE, "version"); if (!attr) { reportError (node, "The supplied DOM tree does not appear to be" " a stylesheet.", errMsg); goto error; } d = strtod (attr->nodeValue, &tailptr); if (d == 0.0 && tailptr == attr->nodeValue) { reportError (node, "The value of the attribute \"version\" must" " be a number.", errMsg); goto error; } if (d > 1.0) { sdoc->fwCmpProcessing = 1; } else if (d < 1.0) { reportError (node, "Strange \"xsl:version\" value, don't know," " how to handle.", errMsg); goto error; } StripXSLTSpace (xsltDoc->rootNode); /* According to XSLT rec 2.3 we add the literal result element as template, which matches "/" */ tpl = (xsltTemplate *) MALLOC (sizeof (xsltTemplate)); tpl->match = "/"; tpl->name = NULL; tpl->nameURI = NULL; tpl->mode = NULL; tpl->modeURI = NULL; tpl->prio = 0.5; tpl->content = node->ownerDocument->rootNode; tpl->precedence = 1.0; tpl->next = NULL; tpl->sDoc = sdoc; rc = xpathParse (tpl->match, node, XPATH_TEMPMATCH_PATTERN, NULL, NULL, &(tpl->freeAst), errMsg); tpl->ast = tpl->freeAst; xs->templates = tpl; if (rc < 0) goto error; } else { rc = addExclExtNS (sdoc, node, errMsg); if (rc < 0) goto error; StripXSLTSpace (xsltDoc->rootNode); precedence = 1.0; precedenceLowBound = 0.0; rc = processTopLevel (xpathFuncClientData, node, xs, precedence, &precedenceLowBound, errMsg); if (rc != 0) goto error; } return xs; error: xsltFreeState (xs); return NULL; } /*---------------------------------------------------------------------------- | xsltProcess | \---------------------------------------------------------------------------*/ int xsltProcess ( domDocument * xsltDoc, domNode * xmlNode, void * xsltCmdData, char ** parameters, int ignoreUndeclaredParameters, int maxApplyDepth, xpathFuncCallback funcCB, void * xpathFuncClientData, xsltMsgCB xsltMsgCB, void * xsltMsgClientData, char ** errMsg, domDocument ** resultDoc ) { xpathResultSet nodeList; domNode *node; int rc, hnew; const char *baseURI; xsltState *xs; xsltSubDoc *sdoc; Tcl_HashEntry *entryPtr; Tcl_HashSearch search; *errMsg = NULL; if (xsltCmdData) { xs = (xsltState *) xsltCmdData; } else { xs = (xsltState *) xsltCompileStylesheet (xsltDoc, funcCB, xpathFuncClientData, 1, errMsg); if (!xs) return -1; } xs->maxNestedApplyTemplates = maxApplyDepth; xs->nestedApplyTemplates = 0; if (xmlNode->nodeType == DOCUMENT_NODE) { xmlNode = ((domDocument *)xmlNode)->rootNode; } else { xmlNode = xmlNode->ownerDocument->rootNode; } DBG(printXML(xmlNode, 0, 1);) if (xmlNode->ownerDocument->nodeFlags & NEEDS_RENUMBERING) { domRenumberTree (xmlNode->ownerDocument->rootNode); xmlNode->ownerDocument->nodeFlags &= ~NEEDS_RENUMBERING; } xs->resultDoc = domCreateDoc(NULL, 0); if (xs->doctype.systemId) { xs->resultDoc->doctype = (domDocInfo *)MALLOC (sizeof (domDocInfo)); memset (xs->resultDoc->doctype, 0, (sizeof (domDocInfo))); xs->resultDoc->doctype->systemId = tdomstrdup (xs->doctype.systemId); } if (xs->doctype.publicId) { if (!xs->resultDoc->doctype) { xs->resultDoc->doctype = (domDocInfo*)MALLOC (sizeof (domDocInfo)); memset (xs->resultDoc->doctype, 0, (sizeof (domDocInfo))); } xs->resultDoc->doctype->publicId = tdomstrdup (xs->doctype.publicId); } if (xs->doctype.encoding) { if (!xs->resultDoc->doctype) { xs->resultDoc->doctype = (domDocInfo*)MALLOC (sizeof (domDocInfo)); memset (xs->resultDoc->doctype, 0, (sizeof (domDocInfo))); } xs->resultDoc->doctype->encoding = tdomstrdup (xs->doctype.encoding); } if (xs->doctype.mediaType) { if (!xs->resultDoc->doctype) { xs->resultDoc->doctype = (domDocInfo*)MALLOC (sizeof (domDocInfo)); memset (xs->resultDoc->doctype, 0, (sizeof (domDocInfo))); } xs->resultDoc->doctype->mediaType = tdomstrdup (xs->doctype.mediaType); } if (xs->doctype.standalone) { if (!xs->resultDoc->doctype) { xs->resultDoc->doctype = (domDocInfo*)MALLOC (sizeof (domDocInfo)); memset (xs->resultDoc->doctype, 0, (sizeof (domDocInfo))); } xs->resultDoc->doctype->standalone = 1; } if (xs->indentOutput) { xs->resultDoc->nodeFlags |= OUTPUT_DEFAULT_INDENT; } if (xs->doctype.cdataSectionElements) { if (!xs->resultDoc->doctype) { xs->resultDoc->doctype = (domDocInfo*)MALLOC (sizeof (domDocInfo)); memset (xs->resultDoc->doctype, 0, (sizeof (domDocInfo))); } xs->resultDoc->doctype->cdataSectionElements = (Tcl_HashTable *) MALLOC (sizeof (Tcl_HashTable)); Tcl_InitHashTable (xs->resultDoc->doctype->cdataSectionElements, TCL_STRING_KEYS); for (entryPtr = Tcl_FirstHashEntry (xs->doctype.cdataSectionElements, &search); entryPtr != (Tcl_HashEntry*) NULL; entryPtr = Tcl_NextHashEntry (&search)) { Tcl_CreateHashEntry (xs->resultDoc->doctype->cdataSectionElements, Tcl_GetHashKey ( xs->doctype.cdataSectionElements, entryPtr ), &hnew); } } xs->xmlRootNode = xmlNode; xs->lastNode = xs->resultDoc->rootNode; xs->xsltMsgCB = xsltMsgCB; xs->xsltMsgClientData = xsltMsgClientData; xsltPushVarFrame(xs); xpathRSInit( &nodeList ); rsAddNodeFast( &nodeList, xmlNode); /* strip space from the XML document, if necessary */ if (xs->wsInfo.hasData) { StripXMLSpace (xs, xmlNode); } /* add the XML doc to the doc list */ sdoc = (xsltSubDoc*)MALLOC(sizeof (xsltSubDoc)); sdoc->doc = xmlNode->ownerDocument; baseURI = findBaseURI (xmlNode); if (baseURI) { sdoc->baseURI = tdomstrdup (baseURI); } else { sdoc->baseURI = NULL; } Tcl_InitHashTable (&(sdoc->keyData), TCL_STRING_KEYS); sdoc->excludeNS = NULL; sdoc->extensionNS = NULL; sdoc->fwCmpProcessing = 0; sdoc->isStylesheet = 0; sdoc->mustFree = 0; sdoc->fixedXMLSource = 0; sdoc->next = xs->subDocs; xs->subDocs = sdoc; xs->currentSubDoc = sdoc; rc = processTopLevelVars (xmlNode, xs, parameters, ignoreUndeclaredParameters, errMsg); if (rc != 0) goto error; node = xs->xsltDoc->documentElement; rc = ApplyTemplates (xs, &nodeList, xmlNode, 0, node, &nodeList, NULL, NULL, errMsg); if (rc != 0) goto error; /* Rudimentary xsl:output support */ if (xs->doctype.method) { if (!xs->resultDoc->doctype) { xs->resultDoc->doctype = (domDocInfo*)MALLOC (sizeof (domDocInfo)); memset (xs->resultDoc->doctype, 0, (sizeof (domDocInfo))); } xs->resultDoc->doctype->method = tdomstrdup (xs->doctype.method); } else { /* default output method */ node = xs->resultDoc->rootNode->firstChild; while (node) { if (node->nodeType == TEXT_NODE) { char *pc; int i, only_whites; only_whites = 1; for (i=0, pc = ((domTextNode*)node)->nodeValue; i < ((domTextNode*)node)->valueLength; i++, pc++) { if (!IS_XML_WHITESPACE(*pc)) { only_whites = 0; break; } } if (!only_whites) break; } if (node->nodeType == ELEMENT_NODE) { if (STRCASECMP(node->nodeName, "html")==0) { if (!xs->resultDoc->doctype) { xs->resultDoc->doctype = (domDocInfo*)MALLOC (sizeof (domDocInfo)); memset (xs->resultDoc->doctype, 0, (sizeof (domDocInfo))); } xs->resultDoc->doctype->method = tdomstrdup ("html"); } break; } node = node->nextSibling; } } /* Make the first ELEMENT_NODE the documentElement. There could be text, comment or PI nodes before the first element node. If the root node doesn't have an element node under it's children, fall back to the firstChild as documentElement. */ domSetDocumentElement (xs->resultDoc); *resultDoc = xs->resultDoc; xsltPopVarFrame (xs); xpathRSFree( &nodeList ); if (xsltCmdData) { xsltResetState (xs); } else { xsltFreeState (xs); } return 0; error: xsltPopVarFrame (xs); xpathRSFree( &nodeList ); domFreeDocument (xs->resultDoc, NULL, NULL); xs->resultDoc = NULL; if (xsltCmdData) { xsltResetState (xs); } else { xsltFreeState (xs); } return -1; } /* xsltProcess */ tdom-0.9.6-src/generic/domhtml.c0000644000175000017500000063532515025767703015222 0ustar rolfrolf/*---------------------------------------------------------------------------- | Copyright (c) 2000 Jochen Loewer (loewerj@hotmail.com) |----------------------------------------------------------------------------- | | | !! EXPERIMENTAL / pre alpha !! | A simple (hopefully fast) HTML parser to build up a DOM structure | in memory. | Based on xmlsimple.c. | !! EXPERIMENTAL / pre alpha !! | | | The contents of this file are subject to the Mozilla Public License | Version 2.0 (the "License"); you may not use this file except in | compliance with the License. You may obtain a copy of the License at | http://www.mozilla.org/MPL/ | | Software distributed under the License is distributed on an "AS IS" | basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the | License for the specific language governing rights and limitations | under the License. | | The Original Code is tDOM. | | The Initial Developer of the Original Code is Jochen Loewer | Portions created by Jochen Loewer are Copyright (C) 1998, 1999 | Jochen Loewer. All Rights Reserved. | | Contributor(s): | | | written by Jochen Loewer | October 2000 | | ------------------------------------------------------------------------ | | Partly based on a parser for XML (for TMML by R.Hipp 1998). | This source code is released into the public domain by the author. | on 2002, December 17. | \---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------- | Includes | \---------------------------------------------------------------------------*/ #include #include #include #include /*---------------------------------------------------------------------------- | Defines | \---------------------------------------------------------------------------*/ #define DBG(x) #define RetError(m,p) *errStr = tdomstrdup(m); *pos = p; return TCL_ERROR; #define IsLetter(c) ( ((c)>='A' && (c)<='Z') || ((c)>='a' && (c)<='z') || ((c) >= '0' && (c) <= '9') ) #define TU(c) toupper((unsigned char)c) /*---------------------------------------------------------------------------- | Begin Character Entity Translator | | | The next section of code implements routines used to translate | character entity references into their corresponding strings. | | Examples: | | & "&" | < "<" | > ">" |   " " | \---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------- | Each entity reference is recorded as an instance of the following | structure \---------------------------------------------------------------------------*/ typedef struct Er Er; struct Er { const char *zName; /* The name of this entity reference. ex: "amp" */ const char *zValue; /* The value for this entity. ex: "&" */ Er *pNext; /* Next entity with the same hash on zName */ }; /*---------------------------------------------------------------------------- | The size of the hash table. For best results this should | be a prime number which is about the same size as the number of | character entity references known to the system. | \---------------------------------------------------------------------------*/ #define ER_HASH_SIZE 2129 /*---------------------------------------------------------------------------- | The following flag is TRUE if entity reference hash table needs | to be initialized. | \---------------------------------------------------------------------------*/ static int bErNeedsInit = 1; TDomThreaded(static Tcl_Mutex initMutex;) /*---------------------------------------------------------------------------- | The hash table | | If the name of an entity reference hashes to the value H, then | apErHash[H] will point to a linked list of Er structures, one of | which will be the Er structure for that entity reference | \---------------------------------------------------------------------------*/ static Er *apErHash[ER_HASH_SIZE]; /*---------------------------------------------------------------------------- | ErHash -- | | Hash an entity reference name. The value returned is an | integer between 0 and Er_HASH_SIZE-1, inclusive. | \---------------------------------------------------------------------------*/ static int ErHash( const char *zName ) { int h = 0; /* The hash value to be returned */ char c; /* The next character in the name being hashed */ while( (c=*zName)!=0 ){ h = h<<5 ^ h ^ c; zName++; } if( h<0 ) h = -h; return h % ER_HASH_SIZE; } /* ErHash */ /*---------------------------------------------------------------------------- | The following is a table of all entity references. To create | new character entities, add entries to this table. | | Note: For the decoder to work, the name of the entity reference | (including the leading & and closing ;) must not be shorter than | the value. | \---------------------------------------------------------------------------*/ /* This is a temporary hack to work around a bug of the gcc build chain * on RiscV. * see https://tdom.org/index.html/tktview?name=faa62e0934 */ #ifdef __riscv #pragma GCC push_options #pragma GCC optimize ("O0") #endif static Er er_sequences[] = { { "AElig", "\xC3\x86", 0 }, { "AMP", "\x26", 0 }, { "Aacute", "\xC3\x81", 0 }, { "Abreve", "\xC4\x82", 0 }, { "Acirc", "\xC3\x82", 0 }, { "Acy", "\xD0\x90", 0 }, { "Afr", "\xF0\x9D\x94\x84", 0 }, { "Agrave", "\xC3\x80", 0 }, { "Alpha", "\xCE\x91", 0 }, { "Amacr", "\xC4\x80", 0 }, { "And", "\xE2\xA9\x93", 0 }, { "Aogon", "\xC4\x84", 0 }, { "Aopf", "\xF0\x9D\x94\xB8", 0 }, { "ApplyFunction", "\xE2\x81\xA1", 0 }, { "Aring", "\xC3\x85", 0 }, { "Ascr", "\xF0\x9D\x92\x9C", 0 }, { "Assign", "\xE2\x89\x94", 0 }, { "Atilde", "\xC3\x83", 0 }, { "Auml", "\xC3\x84", 0 }, { "Backslash", "\xE2\x88\x96", 0 }, { "Barv", "\xE2\xAB\xA7", 0 }, { "Barwed", "\xE2\x8C\x86", 0 }, { "Bcy", "\xD0\x91", 0 }, { "Because", "\xE2\x88\xB5", 0 }, { "Bernoullis", "\xE2\x84\xAC", 0 }, { "Beta", "\xCE\x92", 0 }, { "Bfr", "\xF0\x9D\x94\x85", 0 }, { "Bopf", "\xF0\x9D\x94\xB9", 0 }, { "Breve", "\xCB\x98", 0 }, { "Bscr", "\xE2\x84\xAC", 0 }, { "Bumpeq", "\xE2\x89\x8E", 0 }, { "CHcy", "\xD0\xA7", 0 }, { "COPY", "\xC2\xA9", 0 }, { "Cacute", "\xC4\x86", 0 }, { "Cap", "\xE2\x8B\x92", 0 }, { "CapitalDifferentialD", "\xE2\x85\x85", 0 }, { "Cayleys", "\xE2\x84\xAD", 0 }, { "Ccaron", "\xC4\x8C", 0 }, { "Ccedil", "\xC3\x87", 0 }, { "Ccirc", "\xC4\x88", 0 }, { "Cconint", "\xE2\x88\xB0", 0 }, { "Cdot", "\xC4\x8A", 0 }, { "Cedilla", "\xC2\xB8", 0 }, { "CenterDot", "\xC2\xB7", 0 }, { "Cfr", "\xE2\x84\xAD", 0 }, { "Chi", "\xCE\xA7", 0 }, { "CircleDot", "\xE2\x8A\x99", 0 }, { "CircleMinus", "\xE2\x8A\x96", 0 }, { "CirclePlus", "\xE2\x8A\x95", 0 }, { "CircleTimes", "\xE2\x8A\x97", 0 }, { "ClockwiseContourIntegral", "\xE2\x88\xB2", 0 }, { "CloseCurlyDoubleQuote", "\xE2\x80\x9D", 0 }, { "CloseCurlyQuote", "\xE2\x80\x99", 0 }, { "Colon", "\xE2\x88\xB7", 0 }, { "Colone", "\xE2\xA9\xB4", 0 }, { "Congruent", "\xE2\x89\xA1", 0 }, { "Conint", "\xE2\x88\xAF", 0 }, { "ContourIntegral", "\xE2\x88\xAE", 0 }, { "Copf", "\xE2\x84\x82", 0 }, { "Coproduct", "\xE2\x88\x90", 0 }, { "CounterClockwiseContourIntegral", "\xE2\x88\xB3", 0 }, { "Cross", "\xE2\xA8\xAF", 0 }, { "Cscr", "\xF0\x9D\x92\x9E", 0 }, { "Cup", "\xE2\x8B\x93", 0 }, { "CupCap", "\xE2\x89\x8D", 0 }, { "DD", "\xE2\x85\x85", 0 }, { "DDotrahd", "\xE2\xA4\x91", 0 }, { "DJcy", "\xD0\x82", 0 }, { "DScy", "\xD0\x85", 0 }, { "DZcy", "\xD0\x8F", 0 }, { "Dagger", "\xE2\x80\xA1", 0 }, { "Darr", "\xE2\x86\xA1", 0 }, { "Dashv", "\xE2\xAB\xA4", 0 }, { "Dcaron", "\xC4\x8E", 0 }, { "Dcy", "\xD0\x94", 0 }, { "Del", "\xE2\x88\x87", 0 }, { "Delta", "\xCE\x94", 0 }, { "Dfr", "\xF0\x9D\x94\x87", 0 }, { "DiacriticalAcute", "\xC2\xB4", 0 }, { "DiacriticalDot", "\xCB\x99", 0 }, { "DiacriticalDoubleAcute", "\xCB\x9D", 0 }, { "DiacriticalGrave", "\x60", 0 }, { "DiacriticalTilde", "\xCB\x9C", 0 }, { "Diamond", "\xE2\x8B\x84", 0 }, { "DifferentialD", "\xE2\x85\x86", 0 }, { "Dopf", "\xF0\x9D\x94\xBB", 0 }, { "Dot", "\xC2\xA8", 0 }, { "DotDot", "\xE2\x83\x9C", 0 }, { "DotEqual", "\xE2\x89\x90", 0 }, { "DoubleContourIntegral", "\xE2\x88\xAF", 0 }, { "DoubleDot", "\xC2\xA8", 0 }, { "DoubleDownArrow", "\xE2\x87\x93", 0 }, { "DoubleLeftArrow", "\xE2\x87\x90", 0 }, { "DoubleLeftRightArrow", "\xE2\x87\x94", 0 }, { "DoubleLeftTee", "\xE2\xAB\xA4", 0 }, { "DoubleLongLeftArrow", "\xE2\x9F\xB8", 0 }, { "DoubleLongLeftRightArrow", "\xE2\x9F\xBA", 0 }, { "DoubleLongRightArrow", "\xE2\x9F\xB9", 0 }, { "DoubleRightArrow", "\xE2\x87\x92", 0 }, { "DoubleRightTee", "\xE2\x8A\xA8", 0 }, { "DoubleUpArrow", "\xE2\x87\x91", 0 }, { "DoubleUpDownArrow", "\xE2\x87\x95", 0 }, { "DoubleVerticalBar", "\xE2\x88\xA5", 0 }, { "DownArrow", "\xE2\x86\x93", 0 }, { "DownArrowBar", "\xE2\xA4\x93", 0 }, { "DownArrowUpArrow", "\xE2\x87\xB5", 0 }, { "DownBreve", "\xCC\x91", 0 }, { "DownLeftRightVector", "\xE2\xA5\x90", 0 }, { "DownLeftTeeVector", "\xE2\xA5\x9E", 0 }, { "DownLeftVector", "\xE2\x86\xBD", 0 }, { "DownLeftVectorBar", "\xE2\xA5\x96", 0 }, { "DownRightTeeVector", "\xE2\xA5\x9F", 0 }, { "DownRightVector", "\xE2\x87\x81", 0 }, { "DownRightVectorBar", "\xE2\xA5\x97", 0 }, { "DownTee", "\xE2\x8A\xA4", 0 }, { "DownTeeArrow", "\xE2\x86\xA7", 0 }, { "Downarrow", "\xE2\x87\x93", 0 }, { "Dscr", "\xF0\x9D\x92\x9F", 0 }, { "Dstrok", "\xC4\x90", 0 }, { "ENG", "\xC5\x8A", 0 }, { "ETH", "\xC3\x90", 0 }, { "Eacute", "\xC3\x89", 0 }, { "Ecaron", "\xC4\x9A", 0 }, { "Ecirc", "\xC3\x8A", 0 }, { "Ecy", "\xD0\xAD", 0 }, { "Edot", "\xC4\x96", 0 }, { "Efr", "\xF0\x9D\x94\x88", 0 }, { "Egrave", "\xC3\x88", 0 }, { "Element", "\xE2\x88\x88", 0 }, { "Emacr", "\xC4\x92", 0 }, { "EmptySmallSquare", "\xE2\x97\xBB", 0 }, { "EmptyVerySmallSquare", "\xE2\x96\xAB", 0 }, { "Eogon", "\xC4\x98", 0 }, { "Eopf", "\xF0\x9D\x94\xBC", 0 }, { "Epsilon", "\xCE\x95", 0 }, { "Equal", "\xE2\xA9\xB5", 0 }, { "EqualTilde", "\xE2\x89\x82", 0 }, { "Equilibrium", "\xE2\x87\x8C", 0 }, { "Escr", "\xE2\x84\xB0", 0 }, { "Esim", "\xE2\xA9\xB3", 0 }, { "Eta", "\xCE\x97", 0 }, { "Euml", "\xC3\x8B", 0 }, { "Exists", "\xE2\x88\x83", 0 }, { "ExponentialE", "\xE2\x85\x87", 0 }, { "Fcy", "\xD0\xA4", 0 }, { "Ffr", "\xF0\x9D\x94\x89", 0 }, { "FilledSmallSquare", "\xE2\x97\xBC", 0 }, { "FilledVerySmallSquare", "\xE2\x96\xAA", 0 }, { "Fopf", "\xF0\x9D\x94\xBD", 0 }, { "ForAll", "\xE2\x88\x80", 0 }, { "Fouriertrf", "\xE2\x84\xB1", 0 }, { "Fscr", "\xE2\x84\xB1", 0 }, { "GJcy", "\xD0\x83", 0 }, { "GT", "\x3E", 0 }, { "Gamma", "\xCE\x93", 0 }, { "Gammad", "\xCF\x9C", 0 }, { "Gbreve", "\xC4\x9E", 0 }, { "Gcedil", "\xC4\xA2", 0 }, { "Gcirc", "\xC4\x9C", 0 }, { "Gcy", "\xD0\x93", 0 }, { "Gdot", "\xC4\xA0", 0 }, { "Gfr", "\xF0\x9D\x94\x8A", 0 }, { "Gg", "\xE2\x8B\x99", 0 }, { "Gopf", "\xF0\x9D\x94\xBE", 0 }, { "GreaterEqual", "\xE2\x89\xA5", 0 }, { "GreaterEqualLess", "\xE2\x8B\x9B", 0 }, { "GreaterFullEqual", "\xE2\x89\xA7", 0 }, { "GreaterGreater", "\xE2\xAA\xA2", 0 }, { "GreaterLess", "\xE2\x89\xB7", 0 }, { "GreaterSlantEqual", "\xE2\xA9\xBE", 0 }, { "GreaterTilde", "\xE2\x89\xB3", 0 }, { "Gscr", "\xF0\x9D\x92\xA2", 0 }, { "Gt", "\xE2\x89\xAB", 0 }, { "HARDcy", "\xD0\xAA", 0 }, { "Hacek", "\xCB\x87", 0 }, { "Hat", "\x5E", 0 }, { "Hcirc", "\xC4\xA4", 0 }, { "Hfr", "\xE2\x84\x8C", 0 }, { "HilbertSpace", "\xE2\x84\x8B", 0 }, { "Hopf", "\xE2\x84\x8D", 0 }, { "HorizontalLine", "\xE2\x94\x80", 0 }, { "Hscr", "\xE2\x84\x8B", 0 }, { "Hstrok", "\xC4\xA6", 0 }, { "HumpDownHump", "\xE2\x89\x8E", 0 }, { "HumpEqual", "\xE2\x89\x8F", 0 }, { "IEcy", "\xD0\x95", 0 }, { "IJlig", "\xC4\xB2", 0 }, { "IOcy", "\xD0\x81", 0 }, { "Iacute", "\xC3\x8D", 0 }, { "Icirc", "\xC3\x8E", 0 }, { "Icy", "\xD0\x98", 0 }, { "Idot", "\xC4\xB0", 0 }, { "Ifr", "\xE2\x84\x91", 0 }, { "Igrave", "\xC3\x8C", 0 }, { "Im", "\xE2\x84\x91", 0 }, { "Imacr", "\xC4\xAA", 0 }, { "ImaginaryI", "\xE2\x85\x88", 0 }, { "Implies", "\xE2\x87\x92", 0 }, { "Int", "\xE2\x88\xAC", 0 }, { "Integral", "\xE2\x88\xAB", 0 }, { "Intersection", "\xE2\x8B\x82", 0 }, { "InvisibleComma", "\xE2\x81\xA3", 0 }, { "InvisibleTimes", "\xE2\x81\xA2", 0 }, { "Iogon", "\xC4\xAE", 0 }, { "Iopf", "\xF0\x9D\x95\x80", 0 }, { "Iota", "\xCE\x99", 0 }, { "Iscr", "\xE2\x84\x90", 0 }, { "Itilde", "\xC4\xA8", 0 }, { "Iukcy", "\xD0\x86", 0 }, { "Iuml", "\xC3\x8F", 0 }, { "Jcirc", "\xC4\xB4", 0 }, { "Jcy", "\xD0\x99", 0 }, { "Jfr", "\xF0\x9D\x94\x8D", 0 }, { "Jopf", "\xF0\x9D\x95\x81", 0 }, { "Jscr", "\xF0\x9D\x92\xA5", 0 }, { "Jsercy", "\xD0\x88", 0 }, { "Jukcy", "\xD0\x84", 0 }, { "KHcy", "\xD0\xA5", 0 }, { "KJcy", "\xD0\x8C", 0 }, { "Kappa", "\xCE\x9A", 0 }, { "Kcedil", "\xC4\xB6", 0 }, { "Kcy", "\xD0\x9A", 0 }, { "Kfr", "\xF0\x9D\x94\x8E", 0 }, { "Kopf", "\xF0\x9D\x95\x82", 0 }, { "Kscr", "\xF0\x9D\x92\xA6", 0 }, { "LJcy", "\xD0\x89", 0 }, { "LT", "\x3C", 0 }, { "Lacute", "\xC4\xB9", 0 }, { "Lambda", "\xCE\x9B", 0 }, { "Lang", "\xE2\x9F\xAA", 0 }, { "Laplacetrf", "\xE2\x84\x92", 0 }, { "Larr", "\xE2\x86\x9E", 0 }, { "Lcaron", "\xC4\xBD", 0 }, { "Lcedil", "\xC4\xBB", 0 }, { "Lcy", "\xD0\x9B", 0 }, { "LeftAngleBracket", "\xE2\x9F\xA8", 0 }, { "LeftArrow", "\xE2\x86\x90", 0 }, { "LeftArrowBar", "\xE2\x87\xA4", 0 }, { "LeftArrowRightArrow", "\xE2\x87\x86", 0 }, { "LeftCeiling", "\xE2\x8C\x88", 0 }, { "LeftDoubleBracket", "\xE2\x9F\xA6", 0 }, { "LeftDownTeeVector", "\xE2\xA5\xA1", 0 }, { "LeftDownVector", "\xE2\x87\x83", 0 }, { "LeftDownVectorBar", "\xE2\xA5\x99", 0 }, { "LeftFloor", "\xE2\x8C\x8A", 0 }, { "LeftRightArrow", "\xE2\x86\x94", 0 }, { "LeftRightVector", "\xE2\xA5\x8E", 0 }, { "LeftTee", "\xE2\x8A\xA3", 0 }, { "LeftTeeArrow", "\xE2\x86\xA4", 0 }, { "LeftTeeVector", "\xE2\xA5\x9A", 0 }, { "LeftTriangle", "\xE2\x8A\xB2", 0 }, { "LeftTriangleBar", "\xE2\xA7\x8F", 0 }, { "LeftTriangleEqual", "\xE2\x8A\xB4", 0 }, { "LeftUpDownVector", "\xE2\xA5\x91", 0 }, { "LeftUpTeeVector", "\xE2\xA5\xA0", 0 }, { "LeftUpVector", "\xE2\x86\xBF", 0 }, { "LeftUpVectorBar", "\xE2\xA5\x98", 0 }, { "LeftVector", "\xE2\x86\xBC", 0 }, { "LeftVectorBar", "\xE2\xA5\x92", 0 }, { "Leftarrow", "\xE2\x87\x90", 0 }, { "Leftrightarrow", "\xE2\x87\x94", 0 }, { "LessEqualGreater", "\xE2\x8B\x9A", 0 }, { "LessFullEqual", "\xE2\x89\xA6", 0 }, { "LessGreater", "\xE2\x89\xB6", 0 }, { "LessLess", "\xE2\xAA\xA1", 0 }, { "LessSlantEqual", "\xE2\xA9\xBD", 0 }, { "LessTilde", "\xE2\x89\xB2", 0 }, { "Lfr", "\xF0\x9D\x94\x8F", 0 }, { "Ll", "\xE2\x8B\x98", 0 }, { "Lleftarrow", "\xE2\x87\x9A", 0 }, { "Lmidot", "\xC4\xBF", 0 }, { "LongLeftArrow", "\xE2\x9F\xB5", 0 }, { "LongLeftRightArrow", "\xE2\x9F\xB7", 0 }, { "LongRightArrow", "\xE2\x9F\xB6", 0 }, { "Longleftarrow", "\xE2\x9F\xB8", 0 }, { "Longleftrightarrow", "\xE2\x9F\xBA", 0 }, { "Longrightarrow", "\xE2\x9F\xB9", 0 }, { "Lopf", "\xF0\x9D\x95\x83", 0 }, { "LowerLeftArrow", "\xE2\x86\x99", 0 }, { "LowerRightArrow", "\xE2\x86\x98", 0 }, { "Lscr", "\xE2\x84\x92", 0 }, { "Lsh", "\xE2\x86\xB0", 0 }, { "Lstrok", "\xC5\x81", 0 }, { "Lt", "\xE2\x89\xAA", 0 }, { "Map", "\xE2\xA4\x85", 0 }, { "Mcy", "\xD0\x9C", 0 }, { "MediumSpace", "\xE2\x81\x9F", 0 }, { "Mellintrf", "\xE2\x84\xB3", 0 }, { "Mfr", "\xF0\x9D\x94\x90", 0 }, { "MinusPlus", "\xE2\x88\x93", 0 }, { "Mopf", "\xF0\x9D\x95\x84", 0 }, { "Mscr", "\xE2\x84\xB3", 0 }, { "Mu", "\xCE\x9C", 0 }, { "NJcy", "\xD0\x8A", 0 }, { "Nacute", "\xC5\x83", 0 }, { "Ncaron", "\xC5\x87", 0 }, { "Ncedil", "\xC5\x85", 0 }, { "Ncy", "\xD0\x9D", 0 }, { "NegativeMediumSpace", "\xE2\x80\x8B", 0 }, { "NegativeThickSpace", "\xE2\x80\x8B", 0 }, { "NegativeThinSpace", "\xE2\x80\x8B", 0 }, { "NegativeVeryThinSpace", "\xE2\x80\x8B", 0 }, { "NestedGreaterGreater", "\xE2\x89\xAB", 0 }, { "NestedLessLess", "\xE2\x89\xAA", 0 }, { "NewLine", "\x0A", 0 }, { "Nfr", "\xF0\x9D\x94\x91", 0 }, { "NoBreak", "\xE2\x81\xA0", 0 }, { "NonBreakingSpace", "\xC2\xA0", 0 }, { "Nopf", "\xE2\x84\x95", 0 }, { "Not", "\xE2\xAB\xAC", 0 }, { "NotCongruent", "\xE2\x89\xA2", 0 }, { "NotCupCap", "\xE2\x89\xAD", 0 }, { "NotDoubleVerticalBar", "\xE2\x88\xA6", 0 }, { "NotElement", "\xE2\x88\x89", 0 }, { "NotEqual", "\xE2\x89\xA0", 0 }, { "NotEqualTilde", "\xE2\x89\x82\xCC\xB8", 0 }, { "NotExists", "\xE2\x88\x84", 0 }, { "NotGreater", "\xE2\x89\xAF", 0 }, { "NotGreaterEqual", "\xE2\x89\xB1", 0 }, { "NotGreaterFullEqual", "\xE2\x89\xA7\xCC\xB8", 0 }, { "NotGreaterGreater", "\xE2\x89\xAB\xCC\xB8", 0 }, { "NotGreaterLess", "\xE2\x89\xB9", 0 }, { "NotGreaterSlantEqual", "\xE2\xA9\xBE\xCC\xB8", 0 }, { "NotGreaterTilde", "\xE2\x89\xB5", 0 }, { "NotHumpDownHump", "\xE2\x89\x8E\xCC\xB8", 0 }, { "NotHumpEqual", "\xE2\x89\x8F\xCC\xB8", 0 }, { "NotLeftTriangle", "\xE2\x8B\xAA", 0 }, { "NotLeftTriangleBar", "\xE2\xA7\x8F\xCC\xB8", 0 }, { "NotLeftTriangleEqual", "\xE2\x8B\xAC", 0 }, { "NotLess", "\xE2\x89\xAE", 0 }, { "NotLessEqual", "\xE2\x89\xB0", 0 }, { "NotLessGreater", "\xE2\x89\xB8", 0 }, { "NotLessLess", "\xE2\x89\xAA\xCC\xB8", 0 }, { "NotLessSlantEqual", "\xE2\xA9\xBD\xCC\xB8", 0 }, { "NotLessTilde", "\xE2\x89\xB4", 0 }, { "NotNestedGreaterGreater", "\xE2\xAA\xA2\xCC\xB8", 0 }, { "NotNestedLessLess", "\xE2\xAA\xA1\xCC\xB8", 0 }, { "NotPrecedes", "\xE2\x8A\x80", 0 }, { "NotPrecedesEqual", "\xE2\xAA\xAF\xCC\xB8", 0 }, { "NotPrecedesSlantEqual", "\xE2\x8B\xA0", 0 }, { "NotReverseElement", "\xE2\x88\x8C", 0 }, { "NotRightTriangle", "\xE2\x8B\xAB", 0 }, { "NotRightTriangleBar", "\xE2\xA7\x90\xCC\xB8", 0 }, { "NotRightTriangleEqual", "\xE2\x8B\xAD", 0 }, { "NotSquareSubset", "\xE2\x8A\x8F\xCC\xB8", 0 }, { "NotSquareSubsetEqual", "\xE2\x8B\xA2", 0 }, { "NotSquareSuperset", "\xE2\x8A\x90\xCC\xB8", 0 }, { "NotSquareSupersetEqual", "\xE2\x8B\xA3", 0 }, { "NotSubset", "\xE2\x8A\x82\xE2\x83\x92", 0 }, { "NotSubsetEqual", "\xE2\x8A\x88", 0 }, { "NotSucceeds", "\xE2\x8A\x81", 0 }, { "NotSucceedsEqual", "\xE2\xAA\xB0\xCC\xB8", 0 }, { "NotSucceedsSlantEqual", "\xE2\x8B\xA1", 0 }, { "NotSucceedsTilde", "\xE2\x89\xBF\xCC\xB8", 0 }, { "NotSuperset", "\xE2\x8A\x83\xE2\x83\x92", 0 }, { "NotSupersetEqual", "\xE2\x8A\x89", 0 }, { "NotTilde", "\xE2\x89\x81", 0 }, { "NotTildeEqual", "\xE2\x89\x84", 0 }, { "NotTildeFullEqual", "\xE2\x89\x87", 0 }, { "NotTildeTilde", "\xE2\x89\x89", 0 }, { "NotVerticalBar", "\xE2\x88\xA4", 0 }, { "Nscr", "\xF0\x9D\x92\xA9", 0 }, { "Ntilde", "\xC3\x91", 0 }, { "Nu", "\xCE\x9D", 0 }, { "OElig", "\xC5\x92", 0 }, { "Oacute", "\xC3\x93", 0 }, { "Ocirc", "\xC3\x94", 0 }, { "Ocy", "\xD0\x9E", 0 }, { "Odblac", "\xC5\x90", 0 }, { "Ofr", "\xF0\x9D\x94\x92", 0 }, { "Ograve", "\xC3\x92", 0 }, { "Omacr", "\xC5\x8C", 0 }, { "Omega", "\xCE\xA9", 0 }, { "Omicron", "\xCE\x9F", 0 }, { "Oopf", "\xF0\x9D\x95\x86", 0 }, { "OpenCurlyDoubleQuote", "\xE2\x80\x9C", 0 }, { "OpenCurlyQuote", "\xE2\x80\x98", 0 }, { "Or", "\xE2\xA9\x94", 0 }, { "Oscr", "\xF0\x9D\x92\xAA", 0 }, { "Oslash", "\xC3\x98", 0 }, { "Otilde", "\xC3\x95", 0 }, { "Otimes", "\xE2\xA8\xB7", 0 }, { "Ouml", "\xC3\x96", 0 }, { "OverBar", "\xE2\x80\xBE", 0 }, { "OverBrace", "\xE2\x8F\x9E", 0 }, { "OverBracket", "\xE2\x8E\xB4", 0 }, { "OverParenthesis", "\xE2\x8F\x9C", 0 }, { "PartialD", "\xE2\x88\x82", 0 }, { "Pcy", "\xD0\x9F", 0 }, { "Pfr", "\xF0\x9D\x94\x93", 0 }, { "Phi", "\xCE\xA6", 0 }, { "Pi", "\xCE\xA0", 0 }, { "PlusMinus", "\xC2\xB1", 0 }, { "Poincareplane", "\xE2\x84\x8C", 0 }, { "Popf", "\xE2\x84\x99", 0 }, { "Pr", "\xE2\xAA\xBB", 0 }, { "Precedes", "\xE2\x89\xBA", 0 }, { "PrecedesEqual", "\xE2\xAA\xAF", 0 }, { "PrecedesSlantEqual", "\xE2\x89\xBC", 0 }, { "PrecedesTilde", "\xE2\x89\xBE", 0 }, { "Prime", "\xE2\x80\xB3", 0 }, { "Product", "\xE2\x88\x8F", 0 }, { "Proportion", "\xE2\x88\xB7", 0 }, { "Proportional", "\xE2\x88\x9D", 0 }, { "Pscr", "\xF0\x9D\x92\xAB", 0 }, { "Psi", "\xCE\xA8", 0 }, { "QUOT", "\x22", 0 }, { "Qfr", "\xF0\x9D\x94\x94", 0 }, { "Qopf", "\xE2\x84\x9A", 0 }, { "Qscr", "\xF0\x9D\x92\xAC", 0 }, { "RBarr", "\xE2\xA4\x90", 0 }, { "REG", "\xC2\xAE", 0 }, { "Racute", "\xC5\x94", 0 }, { "Rang", "\xE2\x9F\xAB", 0 }, { "Rarr", "\xE2\x86\xA0", 0 }, { "Rarrtl", "\xE2\xA4\x96", 0 }, { "Rcaron", "\xC5\x98", 0 }, { "Rcedil", "\xC5\x96", 0 }, { "Rcy", "\xD0\xA0", 0 }, { "Re", "\xE2\x84\x9C", 0 }, { "ReverseElement", "\xE2\x88\x8B", 0 }, { "ReverseEquilibrium", "\xE2\x87\x8B", 0 }, { "ReverseUpEquilibrium", "\xE2\xA5\xAF", 0 }, { "Rfr", "\xE2\x84\x9C", 0 }, { "Rho", "\xCE\xA1", 0 }, { "RightAngleBracket", "\xE2\x9F\xA9", 0 }, { "RightArrow", "\xE2\x86\x92", 0 }, { "RightArrowBar", "\xE2\x87\xA5", 0 }, { "RightArrowLeftArrow", "\xE2\x87\x84", 0 }, { "RightCeiling", "\xE2\x8C\x89", 0 }, { "RightDoubleBracket", "\xE2\x9F\xA7", 0 }, { "RightDownTeeVector", "\xE2\xA5\x9D", 0 }, { "RightDownVector", "\xE2\x87\x82", 0 }, { "RightDownVectorBar", "\xE2\xA5\x95", 0 }, { "RightFloor", "\xE2\x8C\x8B", 0 }, { "RightTee", "\xE2\x8A\xA2", 0 }, { "RightTeeArrow", "\xE2\x86\xA6", 0 }, { "RightTeeVector", "\xE2\xA5\x9B", 0 }, { "RightTriangle", "\xE2\x8A\xB3", 0 }, { "RightTriangleBar", "\xE2\xA7\x90", 0 }, { "RightTriangleEqual", "\xE2\x8A\xB5", 0 }, { "RightUpDownVector", "\xE2\xA5\x8F", 0 }, { "RightUpTeeVector", "\xE2\xA5\x9C", 0 }, { "RightUpVector", "\xE2\x86\xBE", 0 }, { "RightUpVectorBar", "\xE2\xA5\x94", 0 }, { "RightVector", "\xE2\x87\x80", 0 }, { "RightVectorBar", "\xE2\xA5\x93", 0 }, { "Rightarrow", "\xE2\x87\x92", 0 }, { "Ropf", "\xE2\x84\x9D", 0 }, { "RoundImplies", "\xE2\xA5\xB0", 0 }, { "Rrightarrow", "\xE2\x87\x9B", 0 }, { "Rscr", "\xE2\x84\x9B", 0 }, { "Rsh", "\xE2\x86\xB1", 0 }, { "RuleDelayed", "\xE2\xA7\xB4", 0 }, { "SHCHcy", "\xD0\xA9", 0 }, { "SHcy", "\xD0\xA8", 0 }, { "SOFTcy", "\xD0\xAC", 0 }, { "Sacute", "\xC5\x9A", 0 }, { "Sc", "\xE2\xAA\xBC", 0 }, { "Scaron", "\xC5\xA0", 0 }, { "Scedil", "\xC5\x9E", 0 }, { "Scirc", "\xC5\x9C", 0 }, { "Scy", "\xD0\xA1", 0 }, { "Sfr", "\xF0\x9D\x94\x96", 0 }, { "ShortDownArrow", "\xE2\x86\x93", 0 }, { "ShortLeftArrow", "\xE2\x86\x90", 0 }, { "ShortRightArrow", "\xE2\x86\x92", 0 }, { "ShortUpArrow", "\xE2\x86\x91", 0 }, { "Sigma", "\xCE\xA3", 0 }, { "SmallCircle", "\xE2\x88\x98", 0 }, { "Sopf", "\xF0\x9D\x95\x8A", 0 }, { "Sqrt", "\xE2\x88\x9A", 0 }, { "Square", "\xE2\x96\xA1", 0 }, { "SquareIntersection", "\xE2\x8A\x93", 0 }, { "SquareSubset", "\xE2\x8A\x8F", 0 }, { "SquareSubsetEqual", "\xE2\x8A\x91", 0 }, { "SquareSuperset", "\xE2\x8A\x90", 0 }, { "SquareSupersetEqual", "\xE2\x8A\x92", 0 }, { "SquareUnion", "\xE2\x8A\x94", 0 }, { "Sscr", "\xF0\x9D\x92\xAE", 0 }, { "Star", "\xE2\x8B\x86", 0 }, { "Sub", "\xE2\x8B\x90", 0 }, { "Subset", "\xE2\x8B\x90", 0 }, { "SubsetEqual", "\xE2\x8A\x86", 0 }, { "Succeeds", "\xE2\x89\xBB", 0 }, { "SucceedsEqual", "\xE2\xAA\xB0", 0 }, { "SucceedsSlantEqual", "\xE2\x89\xBD", 0 }, { "SucceedsTilde", "\xE2\x89\xBF", 0 }, { "SuchThat", "\xE2\x88\x8B", 0 }, { "Sum", "\xE2\x88\x91", 0 }, { "Sup", "\xE2\x8B\x91", 0 }, { "Superset", "\xE2\x8A\x83", 0 }, { "SupersetEqual", "\xE2\x8A\x87", 0 }, { "Supset", "\xE2\x8B\x91", 0 }, { "THORN", "\xC3\x9E", 0 }, { "TRADE", "\xE2\x84\xA2", 0 }, { "TSHcy", "\xD0\x8B", 0 }, { "TScy", "\xD0\xA6", 0 }, { "Tab", "\x09", 0 }, { "Tau", "\xCE\xA4", 0 }, { "Tcaron", "\xC5\xA4", 0 }, { "Tcedil", "\xC5\xA2", 0 }, { "Tcy", "\xD0\xA2", 0 }, { "Tfr", "\xF0\x9D\x94\x97", 0 }, { "Therefore", "\xE2\x88\xB4", 0 }, { "Theta", "\xCE\x98", 0 }, { "ThickSpace", "\xE2\x81\x9F\xE2\x80\x8A", 0 }, { "ThinSpace", "\xE2\x80\x89", 0 }, { "Tilde", "\xE2\x88\xBC", 0 }, { "TildeEqual", "\xE2\x89\x83", 0 }, { "TildeFullEqual", "\xE2\x89\x85", 0 }, { "TildeTilde", "\xE2\x89\x88", 0 }, { "Topf", "\xF0\x9D\x95\x8B", 0 }, { "TripleDot", "\xE2\x83\x9B", 0 }, { "Tscr", "\xF0\x9D\x92\xAF", 0 }, { "Tstrok", "\xC5\xA6", 0 }, { "Uacute", "\xC3\x9A", 0 }, { "Uarr", "\xE2\x86\x9F", 0 }, { "Uarrocir", "\xE2\xA5\x89", 0 }, { "Ubrcy", "\xD0\x8E", 0 }, { "Ubreve", "\xC5\xAC", 0 }, { "Ucirc", "\xC3\x9B", 0 }, { "Ucy", "\xD0\xA3", 0 }, { "Udblac", "\xC5\xB0", 0 }, { "Ufr", "\xF0\x9D\x94\x98", 0 }, { "Ugrave", "\xC3\x99", 0 }, { "Umacr", "\xC5\xAA", 0 }, { "UnderBar", "\x5F", 0 }, { "UnderBrace", "\xE2\x8F\x9F", 0 }, { "UnderBracket", "\xE2\x8E\xB5", 0 }, { "UnderParenthesis", "\xE2\x8F\x9D", 0 }, { "Union", "\xE2\x8B\x83", 0 }, { "UnionPlus", "\xE2\x8A\x8E", 0 }, { "Uogon", "\xC5\xB2", 0 }, { "Uopf", "\xF0\x9D\x95\x8C", 0 }, { "UpArrow", "\xE2\x86\x91", 0 }, { "UpArrowBar", "\xE2\xA4\x92", 0 }, { "UpArrowDownArrow", "\xE2\x87\x85", 0 }, { "UpDownArrow", "\xE2\x86\x95", 0 }, { "UpEquilibrium", "\xE2\xA5\xAE", 0 }, { "UpTee", "\xE2\x8A\xA5", 0 }, { "UpTeeArrow", "\xE2\x86\xA5", 0 }, { "Uparrow", "\xE2\x87\x91", 0 }, { "Updownarrow", "\xE2\x87\x95", 0 }, { "UpperLeftArrow", "\xE2\x86\x96", 0 }, { "UpperRightArrow", "\xE2\x86\x97", 0 }, { "Upsi", "\xCF\x92", 0 }, { "Upsilon", "\xCE\xA5", 0 }, { "Uring", "\xC5\xAE", 0 }, { "Uscr", "\xF0\x9D\x92\xB0", 0 }, { "Utilde", "\xC5\xA8", 0 }, { "Uuml", "\xC3\x9C", 0 }, { "VDash", "\xE2\x8A\xAB", 0 }, { "Vbar", "\xE2\xAB\xAB", 0 }, { "Vcy", "\xD0\x92", 0 }, { "Vdash", "\xE2\x8A\xA9", 0 }, { "Vdashl", "\xE2\xAB\xA6", 0 }, { "Vee", "\xE2\x8B\x81", 0 }, { "Verbar", "\xE2\x80\x96", 0 }, { "Vert", "\xE2\x80\x96", 0 }, { "VerticalBar", "\xE2\x88\xA3", 0 }, { "VerticalLine", "\x7C", 0 }, { "VerticalSeparator", "\xE2\x9D\x98", 0 }, { "VerticalTilde", "\xE2\x89\x80", 0 }, { "VeryThinSpace", "\xE2\x80\x8A", 0 }, { "Vfr", "\xF0\x9D\x94\x99", 0 }, { "Vopf", "\xF0\x9D\x95\x8D", 0 }, { "Vscr", "\xF0\x9D\x92\xB1", 0 }, { "Vvdash", "\xE2\x8A\xAA", 0 }, { "Wcirc", "\xC5\xB4", 0 }, { "Wedge", "\xE2\x8B\x80", 0 }, { "Wfr", "\xF0\x9D\x94\x9A", 0 }, { "Wopf", "\xF0\x9D\x95\x8E", 0 }, { "Wscr", "\xF0\x9D\x92\xB2", 0 }, { "Xfr", "\xF0\x9D\x94\x9B", 0 }, { "Xi", "\xCE\x9E", 0 }, { "Xopf", "\xF0\x9D\x95\x8F", 0 }, { "Xscr", "\xF0\x9D\x92\xB3", 0 }, { "YAcy", "\xD0\xAF", 0 }, { "YIcy", "\xD0\x87", 0 }, { "YUcy", "\xD0\xAE", 0 }, { "Yacute", "\xC3\x9D", 0 }, { "Ycirc", "\xC5\xB6", 0 }, { "Ycy", "\xD0\xAB", 0 }, { "Yfr", "\xF0\x9D\x94\x9C", 0 }, { "Yopf", "\xF0\x9D\x95\x90", 0 }, { "Yscr", "\xF0\x9D\x92\xB4", 0 }, { "Yuml", "\xC5\xB8", 0 }, { "ZHcy", "\xD0\x96", 0 }, { "Zacute", "\xC5\xB9", 0 }, { "Zcaron", "\xC5\xBD", 0 }, { "Zcy", "\xD0\x97", 0 }, { "Zdot", "\xC5\xBB", 0 }, { "ZeroWidthSpace", "\xE2\x80\x8B", 0 }, { "Zeta", "\xCE\x96", 0 }, { "Zfr", "\xE2\x84\xA8", 0 }, { "Zopf", "\xE2\x84\xA4", 0 }, { "Zscr", "\xF0\x9D\x92\xB5", 0 }, { "aacute", "\xC3\xA1", 0 }, { "abreve", "\xC4\x83", 0 }, { "ac", "\xE2\x88\xBE", 0 }, { "acE", "\xE2\x88\xBE\xCC\xB3", 0 }, { "acd", "\xE2\x88\xBF", 0 }, { "acirc", "\xC3\xA2", 0 }, { "acute", "\xC2\xB4", 0 }, { "acy", "\xD0\xB0", 0 }, { "aelig", "\xC3\xA6", 0 }, { "af", "\xE2\x81\xA1", 0 }, { "afr", "\xF0\x9D\x94\x9E", 0 }, { "agrave", "\xC3\xA0", 0 }, { "alefsym", "\xE2\x84\xB5", 0 }, { "aleph", "\xE2\x84\xB5", 0 }, { "alpha", "\xCE\xB1", 0 }, { "amacr", "\xC4\x81", 0 }, { "amalg", "\xE2\xA8\xBF", 0 }, { "amp", "\x26", 0 }, { "and", "\xE2\x88\xA7", 0 }, { "andand", "\xE2\xA9\x95", 0 }, { "andd", "\xE2\xA9\x9C", 0 }, { "andslope", "\xE2\xA9\x98", 0 }, { "andv", "\xE2\xA9\x9A", 0 }, { "ang", "\xE2\x88\xA0", 0 }, { "ange", "\xE2\xA6\xA4", 0 }, { "angle", "\xE2\x88\xA0", 0 }, { "angmsd", "\xE2\x88\xA1", 0 }, { "angmsdaa", "\xE2\xA6\xA8", 0 }, { "angmsdab", "\xE2\xA6\xA9", 0 }, { "angmsdac", "\xE2\xA6\xAA", 0 }, { "angmsdad", "\xE2\xA6\xAB", 0 }, { "angmsdae", "\xE2\xA6\xAC", 0 }, { "angmsdaf", "\xE2\xA6\xAD", 0 }, { "angmsdag", "\xE2\xA6\xAE", 0 }, { "angmsdah", "\xE2\xA6\xAF", 0 }, { "angrt", "\xE2\x88\x9F", 0 }, { "angrtvb", "\xE2\x8A\xBE", 0 }, { "angrtvbd", "\xE2\xA6\x9D", 0 }, { "angsph", "\xE2\x88\xA2", 0 }, { "angst", "\xC3\x85", 0 }, { "angzarr", "\xE2\x8D\xBC", 0 }, { "aogon", "\xC4\x85", 0 }, { "aopf", "\xF0\x9D\x95\x92", 0 }, { "ap", "\xE2\x89\x88", 0 }, { "apE", "\xE2\xA9\xB0", 0 }, { "apacir", "\xE2\xA9\xAF", 0 }, { "ape", "\xE2\x89\x8A", 0 }, { "apid", "\xE2\x89\x8B", 0 }, { "apos", "\x27", 0 }, { "approx", "\xE2\x89\x88", 0 }, { "approxeq", "\xE2\x89\x8A", 0 }, { "aring", "\xC3\xA5", 0 }, { "ascr", "\xF0\x9D\x92\xB6", 0 }, { "ast", "\x2A", 0 }, { "asymp", "\xE2\x89\x88", 0 }, { "asympeq", "\xE2\x89\x8D", 0 }, { "atilde", "\xC3\xA3", 0 }, { "auml", "\xC3\xA4", 0 }, { "awconint", "\xE2\x88\xB3", 0 }, { "awint", "\xE2\xA8\x91", 0 }, { "bNot", "\xE2\xAB\xAD", 0 }, { "backcong", "\xE2\x89\x8C", 0 }, { "backepsilon", "\xCF\xB6", 0 }, { "backprime", "\xE2\x80\xB5", 0 }, { "backsim", "\xE2\x88\xBD", 0 }, { "backsimeq", "\xE2\x8B\x8D", 0 }, { "barvee", "\xE2\x8A\xBD", 0 }, { "barwed", "\xE2\x8C\x85", 0 }, { "barwedge", "\xE2\x8C\x85", 0 }, { "bbrk", "\xE2\x8E\xB5", 0 }, { "bbrktbrk", "\xE2\x8E\xB6", 0 }, { "bcong", "\xE2\x89\x8C", 0 }, { "bcy", "\xD0\xB1", 0 }, { "bdquo", "\xE2\x80\x9E", 0 }, { "becaus", "\xE2\x88\xB5", 0 }, { "because", "\xE2\x88\xB5", 0 }, { "bemptyv", "\xE2\xA6\xB0", 0 }, { "bepsi", "\xCF\xB6", 0 }, { "bernou", "\xE2\x84\xAC", 0 }, { "beta", "\xCE\xB2", 0 }, { "beth", "\xE2\x84\xB6", 0 }, { "between", "\xE2\x89\xAC", 0 }, { "bfr", "\xF0\x9D\x94\x9F", 0 }, { "bigcap", "\xE2\x8B\x82", 0 }, { "bigcirc", "\xE2\x97\xAF", 0 }, { "bigcup", "\xE2\x8B\x83", 0 }, { "bigodot", "\xE2\xA8\x80", 0 }, { "bigoplus", "\xE2\xA8\x81", 0 }, { "bigotimes", "\xE2\xA8\x82", 0 }, { "bigsqcup", "\xE2\xA8\x86", 0 }, { "bigstar", "\xE2\x98\x85", 0 }, { "bigtriangledown", "\xE2\x96\xBD", 0 }, { "bigtriangleup", "\xE2\x96\xB3", 0 }, { "biguplus", "\xE2\xA8\x84", 0 }, { "bigvee", "\xE2\x8B\x81", 0 }, { "bigwedge", "\xE2\x8B\x80", 0 }, { "bkarow", "\xE2\xA4\x8D", 0 }, { "blacklozenge", "\xE2\xA7\xAB", 0 }, { "blacksquare", "\xE2\x96\xAA", 0 }, { "blacktriangle", "\xE2\x96\xB4", 0 }, { "blacktriangledown", "\xE2\x96\xBE", 0 }, { "blacktriangleleft", "\xE2\x97\x82", 0 }, { "blacktriangleright", "\xE2\x96\xB8", 0 }, { "blank", "\xE2\x90\xA3", 0 }, { "blk12", "\xE2\x96\x92", 0 }, { "blk14", "\xE2\x96\x91", 0 }, { "blk34", "\xE2\x96\x93", 0 }, { "block", "\xE2\x96\x88", 0 }, { "bne", "\x3D\xE2\x83\xA5", 0 }, { "bnequiv", "\xE2\x89\xA1\xE2\x83\xA5", 0 }, { "bnot", "\xE2\x8C\x90", 0 }, { "bopf", "\xF0\x9D\x95\x93", 0 }, { "bot", "\xE2\x8A\xA5", 0 }, { "bottom", "\xE2\x8A\xA5", 0 }, { "bowtie", "\xE2\x8B\x88", 0 }, { "boxDL", "\xE2\x95\x97", 0 }, { "boxDR", "\xE2\x95\x94", 0 }, { "boxDl", "\xE2\x95\x96", 0 }, { "boxDr", "\xE2\x95\x93", 0 }, { "boxH", "\xE2\x95\x90", 0 }, { "boxHD", "\xE2\x95\xA6", 0 }, { "boxHU", "\xE2\x95\xA9", 0 }, { "boxHd", "\xE2\x95\xA4", 0 }, { "boxHu", "\xE2\x95\xA7", 0 }, { "boxUL", "\xE2\x95\x9D", 0 }, { "boxUR", "\xE2\x95\x9A", 0 }, { "boxUl", "\xE2\x95\x9C", 0 }, { "boxUr", "\xE2\x95\x99", 0 }, { "boxV", "\xE2\x95\x91", 0 }, { "boxVH", "\xE2\x95\xAC", 0 }, { "boxVL", "\xE2\x95\xA3", 0 }, { "boxVR", "\xE2\x95\xA0", 0 }, { "boxVh", "\xE2\x95\xAB", 0 }, { "boxVl", "\xE2\x95\xA2", 0 }, { "boxVr", "\xE2\x95\x9F", 0 }, { "boxbox", "\xE2\xA7\x89", 0 }, { "boxdL", "\xE2\x95\x95", 0 }, { "boxdR", "\xE2\x95\x92", 0 }, { "boxdl", "\xE2\x94\x90", 0 }, { "boxdr", "\xE2\x94\x8C", 0 }, { "boxh", "\xE2\x94\x80", 0 }, { "boxhD", "\xE2\x95\xA5", 0 }, { "boxhU", "\xE2\x95\xA8", 0 }, { "boxhd", "\xE2\x94\xAC", 0 }, { "boxhu", "\xE2\x94\xB4", 0 }, { "boxminus", "\xE2\x8A\x9F", 0 }, { "boxplus", "\xE2\x8A\x9E", 0 }, { "boxtimes", "\xE2\x8A\xA0", 0 }, { "boxuL", "\xE2\x95\x9B", 0 }, { "boxuR", "\xE2\x95\x98", 0 }, { "boxul", "\xE2\x94\x98", 0 }, { "boxur", "\xE2\x94\x94", 0 }, { "boxv", "\xE2\x94\x82", 0 }, { "boxvH", "\xE2\x95\xAA", 0 }, { "boxvL", "\xE2\x95\xA1", 0 }, { "boxvR", "\xE2\x95\x9E", 0 }, { "boxvh", "\xE2\x94\xBC", 0 }, { "boxvl", "\xE2\x94\xA4", 0 }, { "boxvr", "\xE2\x94\x9C", 0 }, { "bprime", "\xE2\x80\xB5", 0 }, { "breve", "\xCB\x98", 0 }, { "brvbar", "\xC2\xA6", 0 }, { "bscr", "\xF0\x9D\x92\xB7", 0 }, { "bsemi", "\xE2\x81\x8F", 0 }, { "bsim", "\xE2\x88\xBD", 0 }, { "bsime", "\xE2\x8B\x8D", 0 }, { "bsol", "\x5C", 0 }, { "bsolb", "\xE2\xA7\x85", 0 }, { "bsolhsub", "\xE2\x9F\x88", 0 }, { "bull", "\xE2\x80\xA2", 0 }, { "bullet", "\xE2\x80\xA2", 0 }, { "bump", "\xE2\x89\x8E", 0 }, { "bumpE", "\xE2\xAA\xAE", 0 }, { "bumpe", "\xE2\x89\x8F", 0 }, { "bumpeq", "\xE2\x89\x8F", 0 }, { "cacute", "\xC4\x87", 0 }, { "cap", "\xE2\x88\xA9", 0 }, { "capand", "\xE2\xA9\x84", 0 }, { "capbrcup", "\xE2\xA9\x89", 0 }, { "capcap", "\xE2\xA9\x8B", 0 }, { "capcup", "\xE2\xA9\x87", 0 }, { "capdot", "\xE2\xA9\x80", 0 }, { "caps", "\xE2\x88\xA9\xEF\xB8\x80", 0 }, { "caret", "\xE2\x81\x81", 0 }, { "caron", "\xCB\x87", 0 }, { "ccaps", "\xE2\xA9\x8D", 0 }, { "ccaron", "\xC4\x8D", 0 }, { "ccedil", "\xC3\xA7", 0 }, { "ccirc", "\xC4\x89", 0 }, { "ccups", "\xE2\xA9\x8C", 0 }, { "ccupssm", "\xE2\xA9\x90", 0 }, { "cdot", "\xC4\x8B", 0 }, { "cedil", "\xC2\xB8", 0 }, { "cemptyv", "\xE2\xA6\xB2", 0 }, { "cent", "\xC2\xA2", 0 }, { "centerdot", "\xC2\xB7", 0 }, { "cfr", "\xF0\x9D\x94\xA0", 0 }, { "chcy", "\xD1\x87", 0 }, { "check", "\xE2\x9C\x93", 0 }, { "checkmark", "\xE2\x9C\x93", 0 }, { "chi", "\xCF\x87", 0 }, { "cir", "\xE2\x97\x8B", 0 }, { "cirE", "\xE2\xA7\x83", 0 }, { "circ", "\xCB\x86", 0 }, { "circeq", "\xE2\x89\x97", 0 }, { "circlearrowleft", "\xE2\x86\xBA", 0 }, { "circlearrowright", "\xE2\x86\xBB", 0 }, { "circledR", "\xC2\xAE", 0 }, { "circledS", "\xE2\x93\x88", 0 }, { "circledast", "\xE2\x8A\x9B", 0 }, { "circledcirc", "\xE2\x8A\x9A", 0 }, { "circleddash", "\xE2\x8A\x9D", 0 }, { "cire", "\xE2\x89\x97", 0 }, { "cirfnint", "\xE2\xA8\x90", 0 }, { "cirmid", "\xE2\xAB\xAF", 0 }, { "cirscir", "\xE2\xA7\x82", 0 }, { "clubs", "\xE2\x99\xA3", 0 }, { "clubsuit", "\xE2\x99\xA3", 0 }, { "colon", "\x3A", 0 }, { "colone", "\xE2\x89\x94", 0 }, { "coloneq", "\xE2\x89\x94", 0 }, { "comma", "\x2C", 0 }, { "commat", "\x40", 0 }, { "comp", "\xE2\x88\x81", 0 }, { "compfn", "\xE2\x88\x98", 0 }, { "complement", "\xE2\x88\x81", 0 }, { "complexes", "\xE2\x84\x82", 0 }, { "cong", "\xE2\x89\x85", 0 }, { "congdot", "\xE2\xA9\xAD", 0 }, { "conint", "\xE2\x88\xAE", 0 }, { "copf", "\xF0\x9D\x95\x94", 0 }, { "coprod", "\xE2\x88\x90", 0 }, { "copy", "\xC2\xA9", 0 }, { "copysr", "\xE2\x84\x97", 0 }, { "crarr", "\xE2\x86\xB5", 0 }, { "cross", "\xE2\x9C\x97", 0 }, { "cscr", "\xF0\x9D\x92\xB8", 0 }, { "csub", "\xE2\xAB\x8F", 0 }, { "csube", "\xE2\xAB\x91", 0 }, { "csup", "\xE2\xAB\x90", 0 }, { "csupe", "\xE2\xAB\x92", 0 }, { "ctdot", "\xE2\x8B\xAF", 0 }, { "cudarrl", "\xE2\xA4\xB8", 0 }, { "cudarrr", "\xE2\xA4\xB5", 0 }, { "cuepr", "\xE2\x8B\x9E", 0 }, { "cuesc", "\xE2\x8B\x9F", 0 }, { "cularr", "\xE2\x86\xB6", 0 }, { "cularrp", "\xE2\xA4\xBD", 0 }, { "cup", "\xE2\x88\xAA", 0 }, { "cupbrcap", "\xE2\xA9\x88", 0 }, { "cupcap", "\xE2\xA9\x86", 0 }, { "cupcup", "\xE2\xA9\x8A", 0 }, { "cupdot", "\xE2\x8A\x8D", 0 }, { "cupor", "\xE2\xA9\x85", 0 }, { "cups", "\xE2\x88\xAA\xEF\xB8\x80", 0 }, { "curarr", "\xE2\x86\xB7", 0 }, { "curarrm", "\xE2\xA4\xBC", 0 }, { "curlyeqprec", "\xE2\x8B\x9E", 0 }, { "curlyeqsucc", "\xE2\x8B\x9F", 0 }, { "curlyvee", "\xE2\x8B\x8E", 0 }, { "curlywedge", "\xE2\x8B\x8F", 0 }, { "curren", "\xC2\xA4", 0 }, { "curvearrowleft", "\xE2\x86\xB6", 0 }, { "curvearrowright", "\xE2\x86\xB7", 0 }, { "cuvee", "\xE2\x8B\x8E", 0 }, { "cuwed", "\xE2\x8B\x8F", 0 }, { "cwconint", "\xE2\x88\xB2", 0 }, { "cwint", "\xE2\x88\xB1", 0 }, { "cylcty", "\xE2\x8C\xAD", 0 }, { "dArr", "\xE2\x87\x93", 0 }, { "dHar", "\xE2\xA5\xA5", 0 }, { "dagger", "\xE2\x80\xA0", 0 }, { "daleth", "\xE2\x84\xB8", 0 }, { "darr", "\xE2\x86\x93", 0 }, { "dash", "\xE2\x80\x90", 0 }, { "dashv", "\xE2\x8A\xA3", 0 }, { "dbkarow", "\xE2\xA4\x8F", 0 }, { "dblac", "\xCB\x9D", 0 }, { "dcaron", "\xC4\x8F", 0 }, { "dcy", "\xD0\xB4", 0 }, { "dd", "\xE2\x85\x86", 0 }, { "ddagger", "\xE2\x80\xA1", 0 }, { "ddarr", "\xE2\x87\x8A", 0 }, { "ddotseq", "\xE2\xA9\xB7", 0 }, { "deg", "\xC2\xB0", 0 }, { "delta", "\xCE\xB4", 0 }, { "demptyv", "\xE2\xA6\xB1", 0 }, { "dfisht", "\xE2\xA5\xBF", 0 }, { "dfr", "\xF0\x9D\x94\xA1", 0 }, { "dharl", "\xE2\x87\x83", 0 }, { "dharr", "\xE2\x87\x82", 0 }, { "diam", "\xE2\x8B\x84", 0 }, { "diamond", "\xE2\x8B\x84", 0 }, { "diamondsuit", "\xE2\x99\xA6", 0 }, { "diams", "\xE2\x99\xA6", 0 }, { "die", "\xC2\xA8", 0 }, { "digamma", "\xCF\x9D", 0 }, { "disin", "\xE2\x8B\xB2", 0 }, { "div", "\xC3\xB7", 0 }, { "divide", "\xC3\xB7", 0 }, { "divideontimes", "\xE2\x8B\x87", 0 }, { "divonx", "\xE2\x8B\x87", 0 }, { "djcy", "\xD1\x92", 0 }, { "dlcorn", "\xE2\x8C\x9E", 0 }, { "dlcrop", "\xE2\x8C\x8D", 0 }, { "dollar", "\x24", 0 }, { "dopf", "\xF0\x9D\x95\x95", 0 }, { "dot", "\xCB\x99", 0 }, { "doteq", "\xE2\x89\x90", 0 }, { "doteqdot", "\xE2\x89\x91", 0 }, { "dotminus", "\xE2\x88\xB8", 0 }, { "dotplus", "\xE2\x88\x94", 0 }, { "dotsquare", "\xE2\x8A\xA1", 0 }, { "doublebarwedge", "\xE2\x8C\x86", 0 }, { "downarrow", "\xE2\x86\x93", 0 }, { "downdownarrows", "\xE2\x87\x8A", 0 }, { "downharpoonleft", "\xE2\x87\x83", 0 }, { "downharpoonright", "\xE2\x87\x82", 0 }, { "drbkarow", "\xE2\xA4\x90", 0 }, { "drcorn", "\xE2\x8C\x9F", 0 }, { "drcrop", "\xE2\x8C\x8C", 0 }, { "dscr", "\xF0\x9D\x92\xB9", 0 }, { "dscy", "\xD1\x95", 0 }, { "dsol", "\xE2\xA7\xB6", 0 }, { "dstrok", "\xC4\x91", 0 }, { "dtdot", "\xE2\x8B\xB1", 0 }, { "dtri", "\xE2\x96\xBF", 0 }, { "dtrif", "\xE2\x96\xBE", 0 }, { "duarr", "\xE2\x87\xB5", 0 }, { "duhar", "\xE2\xA5\xAF", 0 }, { "dwangle", "\xE2\xA6\xA6", 0 }, { "dzcy", "\xD1\x9F", 0 }, { "dzigrarr", "\xE2\x9F\xBF", 0 }, { "eDDot", "\xE2\xA9\xB7", 0 }, { "eDot", "\xE2\x89\x91", 0 }, { "eacute", "\xC3\xA9", 0 }, { "easter", "\xE2\xA9\xAE", 0 }, { "ecaron", "\xC4\x9B", 0 }, { "ecir", "\xE2\x89\x96", 0 }, { "ecirc", "\xC3\xAA", 0 }, { "ecolon", "\xE2\x89\x95", 0 }, { "ecy", "\xD1\x8D", 0 }, { "edot", "\xC4\x97", 0 }, { "ee", "\xE2\x85\x87", 0 }, { "efDot", "\xE2\x89\x92", 0 }, { "efr", "\xF0\x9D\x94\xA2", 0 }, { "eg", "\xE2\xAA\x9A", 0 }, { "egrave", "\xC3\xA8", 0 }, { "egs", "\xE2\xAA\x96", 0 }, { "egsdot", "\xE2\xAA\x98", 0 }, { "el", "\xE2\xAA\x99", 0 }, { "elinters", "\xE2\x8F\xA7", 0 }, { "ell", "\xE2\x84\x93", 0 }, { "els", "\xE2\xAA\x95", 0 }, { "elsdot", "\xE2\xAA\x97", 0 }, { "emacr", "\xC4\x93", 0 }, { "empty", "\xE2\x88\x85", 0 }, { "emptyset", "\xE2\x88\x85", 0 }, { "emptyv", "\xE2\x88\x85", 0 }, { "emsp", "\xE2\x80\x83", 0 }, { "emsp13", "\xE2\x80\x84", 0 }, { "emsp14", "\xE2\x80\x85", 0 }, { "eng", "\xC5\x8B", 0 }, { "ensp", "\xE2\x80\x82", 0 }, { "eogon", "\xC4\x99", 0 }, { "eopf", "\xF0\x9D\x95\x96", 0 }, { "epar", "\xE2\x8B\x95", 0 }, { "eparsl", "\xE2\xA7\xA3", 0 }, { "eplus", "\xE2\xA9\xB1", 0 }, { "epsi", "\xCE\xB5", 0 }, { "epsilon", "\xCE\xB5", 0 }, { "epsiv", "\xCF\xB5", 0 }, { "eqcirc", "\xE2\x89\x96", 0 }, { "eqcolon", "\xE2\x89\x95", 0 }, { "eqsim", "\xE2\x89\x82", 0 }, { "eqslantgtr", "\xE2\xAA\x96", 0 }, { "eqslantless", "\xE2\xAA\x95", 0 }, { "equals", "\x3D", 0 }, { "equest", "\xE2\x89\x9F", 0 }, { "equiv", "\xE2\x89\xA1", 0 }, { "equivDD", "\xE2\xA9\xB8", 0 }, { "eqvparsl", "\xE2\xA7\xA5", 0 }, { "erDot", "\xE2\x89\x93", 0 }, { "erarr", "\xE2\xA5\xB1", 0 }, { "escr", "\xE2\x84\xAF", 0 }, { "esdot", "\xE2\x89\x90", 0 }, { "esim", "\xE2\x89\x82", 0 }, { "eta", "\xCE\xB7", 0 }, { "eth", "\xC3\xB0", 0 }, { "euml", "\xC3\xAB", 0 }, { "euro", "\xE2\x82\xAC", 0 }, { "excl", "\x21", 0 }, { "exist", "\xE2\x88\x83", 0 }, { "expectation", "\xE2\x84\xB0", 0 }, { "exponentiale", "\xE2\x85\x87", 0 }, { "fallingdotseq", "\xE2\x89\x92", 0 }, { "fcy", "\xD1\x84", 0 }, { "female", "\xE2\x99\x80", 0 }, { "ffilig", "\xEF\xAC\x83", 0 }, { "fflig", "\xEF\xAC\x80", 0 }, { "ffllig", "\xEF\xAC\x84", 0 }, { "ffr", "\xF0\x9D\x94\xA3", 0 }, { "filig", "\xEF\xAC\x81", 0 }, { "fjlig", "\x66\x6A", 0 }, { "flat", "\xE2\x99\xAD", 0 }, { "fllig", "\xEF\xAC\x82", 0 }, { "fltns", "\xE2\x96\xB1", 0 }, { "fnof", "\xC6\x92", 0 }, { "fopf", "\xF0\x9D\x95\x97", 0 }, { "forall", "\xE2\x88\x80", 0 }, { "fork", "\xE2\x8B\x94", 0 }, { "forkv", "\xE2\xAB\x99", 0 }, { "fpartint", "\xE2\xA8\x8D", 0 }, { "frac12", "\xC2\xBD", 0 }, { "frac13", "\xE2\x85\x93", 0 }, { "frac14", "\xC2\xBC", 0 }, { "frac15", "\xE2\x85\x95", 0 }, { "frac16", "\xE2\x85\x99", 0 }, { "frac18", "\xE2\x85\x9B", 0 }, { "frac23", "\xE2\x85\x94", 0 }, { "frac25", "\xE2\x85\x96", 0 }, { "frac34", "\xC2\xBE", 0 }, { "frac35", "\xE2\x85\x97", 0 }, { "frac38", "\xE2\x85\x9C", 0 }, { "frac45", "\xE2\x85\x98", 0 }, { "frac56", "\xE2\x85\x9A", 0 }, { "frac58", "\xE2\x85\x9D", 0 }, { "frac78", "\xE2\x85\x9E", 0 }, { "frasl", "\xE2\x81\x84", 0 }, { "frown", "\xE2\x8C\xA2", 0 }, { "fscr", "\xF0\x9D\x92\xBB", 0 }, { "gE", "\xE2\x89\xA7", 0 }, { "gEl", "\xE2\xAA\x8C", 0 }, { "gacute", "\xC7\xB5", 0 }, { "gamma", "\xCE\xB3", 0 }, { "gammad", "\xCF\x9D", 0 }, { "gap", "\xE2\xAA\x86", 0 }, { "gbreve", "\xC4\x9F", 0 }, { "gcirc", "\xC4\x9D", 0 }, { "gcy", "\xD0\xB3", 0 }, { "gdot", "\xC4\xA1", 0 }, { "ge", "\xE2\x89\xA5", 0 }, { "gel", "\xE2\x8B\x9B", 0 }, { "geq", "\xE2\x89\xA5", 0 }, { "geqq", "\xE2\x89\xA7", 0 }, { "geqslant", "\xE2\xA9\xBE", 0 }, { "ges", "\xE2\xA9\xBE", 0 }, { "gescc", "\xE2\xAA\xA9", 0 }, { "gesdot", "\xE2\xAA\x80", 0 }, { "gesdoto", "\xE2\xAA\x82", 0 }, { "gesdotol", "\xE2\xAA\x84", 0 }, { "gesl", "\xE2\x8B\x9B\xEF\xB8\x80", 0 }, { "gesles", "\xE2\xAA\x94", 0 }, { "gfr", "\xF0\x9D\x94\xA4", 0 }, { "gg", "\xE2\x89\xAB", 0 }, { "ggg", "\xE2\x8B\x99", 0 }, { "gimel", "\xE2\x84\xB7", 0 }, { "gjcy", "\xD1\x93", 0 }, { "gl", "\xE2\x89\xB7", 0 }, { "glE", "\xE2\xAA\x92", 0 }, { "gla", "\xE2\xAA\xA5", 0 }, { "glj", "\xE2\xAA\xA4", 0 }, { "gnE", "\xE2\x89\xA9", 0 }, { "gnap", "\xE2\xAA\x8A", 0 }, { "gnapprox", "\xE2\xAA\x8A", 0 }, { "gne", "\xE2\xAA\x88", 0 }, { "gneq", "\xE2\xAA\x88", 0 }, { "gneqq", "\xE2\x89\xA9", 0 }, { "gnsim", "\xE2\x8B\xA7", 0 }, { "gopf", "\xF0\x9D\x95\x98", 0 }, { "grave", "\x60", 0 }, { "gscr", "\xE2\x84\x8A", 0 }, { "gsim", "\xE2\x89\xB3", 0 }, { "gsime", "\xE2\xAA\x8E", 0 }, { "gsiml", "\xE2\xAA\x90", 0 }, { "gt", "\x3E", 0 }, { "gtcc", "\xE2\xAA\xA7", 0 }, { "gtcir", "\xE2\xA9\xBA", 0 }, { "gtdot", "\xE2\x8B\x97", 0 }, { "gtlPar", "\xE2\xA6\x95", 0 }, { "gtquest", "\xE2\xA9\xBC", 0 }, { "gtrapprox", "\xE2\xAA\x86", 0 }, { "gtrarr", "\xE2\xA5\xB8", 0 }, { "gtrdot", "\xE2\x8B\x97", 0 }, { "gtreqless", "\xE2\x8B\x9B", 0 }, { "gtreqqless", "\xE2\xAA\x8C", 0 }, { "gtrless", "\xE2\x89\xB7", 0 }, { "gtrsim", "\xE2\x89\xB3", 0 }, { "gvertneqq", "\xE2\x89\xA9\xEF\xB8\x80", 0 }, { "gvnE", "\xE2\x89\xA9\xEF\xB8\x80", 0 }, { "hArr", "\xE2\x87\x94", 0 }, { "hairsp", "\xE2\x80\x8A", 0 }, { "half", "\xC2\xBD", 0 }, { "hamilt", "\xE2\x84\x8B", 0 }, { "hardcy", "\xD1\x8A", 0 }, { "harr", "\xE2\x86\x94", 0 }, { "harrcir", "\xE2\xA5\x88", 0 }, { "harrw", "\xE2\x86\xAD", 0 }, { "hbar", "\xE2\x84\x8F", 0 }, { "hcirc", "\xC4\xA5", 0 }, { "hearts", "\xE2\x99\xA5", 0 }, { "heartsuit", "\xE2\x99\xA5", 0 }, { "hellip", "\xE2\x80\xA6", 0 }, { "hercon", "\xE2\x8A\xB9", 0 }, { "hfr", "\xF0\x9D\x94\xA5", 0 }, { "hksearow", "\xE2\xA4\xA5", 0 }, { "hkswarow", "\xE2\xA4\xA6", 0 }, { "hoarr", "\xE2\x87\xBF", 0 }, { "homtht", "\xE2\x88\xBB", 0 }, { "hookleftarrow", "\xE2\x86\xA9", 0 }, { "hookrightarrow", "\xE2\x86\xAA", 0 }, { "hopf", "\xF0\x9D\x95\x99", 0 }, { "horbar", "\xE2\x80\x95", 0 }, { "hscr", "\xF0\x9D\x92\xBD", 0 }, { "hslash", "\xE2\x84\x8F", 0 }, { "hstrok", "\xC4\xA7", 0 }, { "hybull", "\xE2\x81\x83", 0 }, { "hyphen", "\xE2\x80\x90", 0 }, { "iacute", "\xC3\xAD", 0 }, { "ic", "\xE2\x81\xA3", 0 }, { "icirc", "\xC3\xAE", 0 }, { "icy", "\xD0\xB8", 0 }, { "iecy", "\xD0\xB5", 0 }, { "iexcl", "\xC2\xA1", 0 }, { "iff", "\xE2\x87\x94", 0 }, { "ifr", "\xF0\x9D\x94\xA6", 0 }, { "igrave", "\xC3\xAC", 0 }, { "ii", "\xE2\x85\x88", 0 }, { "iiiint", "\xE2\xA8\x8C", 0 }, { "iiint", "\xE2\x88\xAD", 0 }, { "iinfin", "\xE2\xA7\x9C", 0 }, { "iiota", "\xE2\x84\xA9", 0 }, { "ijlig", "\xC4\xB3", 0 }, { "imacr", "\xC4\xAB", 0 }, { "image", "\xE2\x84\x91", 0 }, { "imagline", "\xE2\x84\x90", 0 }, { "imagpart", "\xE2\x84\x91", 0 }, { "imath", "\xC4\xB1", 0 }, { "imof", "\xE2\x8A\xB7", 0 }, { "imped", "\xC6\xB5", 0 }, { "in", "\xE2\x88\x88", 0 }, { "incare", "\xE2\x84\x85", 0 }, { "infin", "\xE2\x88\x9E", 0 }, { "infintie", "\xE2\xA7\x9D", 0 }, { "inodot", "\xC4\xB1", 0 }, { "int", "\xE2\x88\xAB", 0 }, { "intcal", "\xE2\x8A\xBA", 0 }, { "integers", "\xE2\x84\xA4", 0 }, { "intercal", "\xE2\x8A\xBA", 0 }, { "intlarhk", "\xE2\xA8\x97", 0 }, { "intprod", "\xE2\xA8\xBC", 0 }, { "iocy", "\xD1\x91", 0 }, { "iogon", "\xC4\xAF", 0 }, { "iopf", "\xF0\x9D\x95\x9A", 0 }, { "iota", "\xCE\xB9", 0 }, { "iprod", "\xE2\xA8\xBC", 0 }, { "iquest", "\xC2\xBF", 0 }, { "iscr", "\xF0\x9D\x92\xBE", 0 }, { "isin", "\xE2\x88\x88", 0 }, { "isinE", "\xE2\x8B\xB9", 0 }, { "isindot", "\xE2\x8B\xB5", 0 }, { "isins", "\xE2\x8B\xB4", 0 }, { "isinsv", "\xE2\x8B\xB3", 0 }, { "isinv", "\xE2\x88\x88", 0 }, { "it", "\xE2\x81\xA2", 0 }, { "itilde", "\xC4\xA9", 0 }, { "iukcy", "\xD1\x96", 0 }, { "iuml", "\xC3\xAF", 0 }, { "jcirc", "\xC4\xB5", 0 }, { "jcy", "\xD0\xB9", 0 }, { "jfr", "\xF0\x9D\x94\xA7", 0 }, { "jmath", "\xC8\xB7", 0 }, { "jopf", "\xF0\x9D\x95\x9B", 0 }, { "jscr", "\xF0\x9D\x92\xBF", 0 }, { "jsercy", "\xD1\x98", 0 }, { "jukcy", "\xD1\x94", 0 }, { "kappa", "\xCE\xBA", 0 }, { "kappav", "\xCF\xB0", 0 }, { "kcedil", "\xC4\xB7", 0 }, { "kcy", "\xD0\xBA", 0 }, { "kfr", "\xF0\x9D\x94\xA8", 0 }, { "kgreen", "\xC4\xB8", 0 }, { "khcy", "\xD1\x85", 0 }, { "kjcy", "\xD1\x9C", 0 }, { "kopf", "\xF0\x9D\x95\x9C", 0 }, { "kscr", "\xF0\x9D\x93\x80", 0 }, { "lAarr", "\xE2\x87\x9A", 0 }, { "lArr", "\xE2\x87\x90", 0 }, { "lAtail", "\xE2\xA4\x9B", 0 }, { "lBarr", "\xE2\xA4\x8E", 0 }, { "lE", "\xE2\x89\xA6", 0 }, { "lEg", "\xE2\xAA\x8B", 0 }, { "lHar", "\xE2\xA5\xA2", 0 }, { "lacute", "\xC4\xBA", 0 }, { "laemptyv", "\xE2\xA6\xB4", 0 }, { "lagran", "\xE2\x84\x92", 0 }, { "lambda", "\xCE\xBB", 0 }, { "lang", "\xE2\x9F\xA8", 0 }, { "langd", "\xE2\xA6\x91", 0 }, { "langle", "\xE2\x9F\xA8", 0 }, { "lap", "\xE2\xAA\x85", 0 }, { "laquo", "\xC2\xAB", 0 }, { "larr", "\xE2\x86\x90", 0 }, { "larrb", "\xE2\x87\xA4", 0 }, { "larrbfs", "\xE2\xA4\x9F", 0 }, { "larrfs", "\xE2\xA4\x9D", 0 }, { "larrhk", "\xE2\x86\xA9", 0 }, { "larrlp", "\xE2\x86\xAB", 0 }, { "larrpl", "\xE2\xA4\xB9", 0 }, { "larrsim", "\xE2\xA5\xB3", 0 }, { "larrtl", "\xE2\x86\xA2", 0 }, { "lat", "\xE2\xAA\xAB", 0 }, { "latail", "\xE2\xA4\x99", 0 }, { "late", "\xE2\xAA\xAD", 0 }, { "lates", "\xE2\xAA\xAD\xEF\xB8\x80", 0 }, { "lbarr", "\xE2\xA4\x8C", 0 }, { "lbbrk", "\xE2\x9D\xB2", 0 }, { "lbrace", "\x7B", 0 }, { "lbrack", "\x5B", 0 }, { "lbrke", "\xE2\xA6\x8B", 0 }, { "lbrksld", "\xE2\xA6\x8F", 0 }, { "lbrkslu", "\xE2\xA6\x8D", 0 }, { "lcaron", "\xC4\xBE", 0 }, { "lcedil", "\xC4\xBC", 0 }, { "lceil", "\xE2\x8C\x88", 0 }, { "lcub", "\x7B", 0 }, { "lcy", "\xD0\xBB", 0 }, { "ldca", "\xE2\xA4\xB6", 0 }, { "ldquo", "\xE2\x80\x9C", 0 }, { "ldquor", "\xE2\x80\x9E", 0 }, { "ldrdhar", "\xE2\xA5\xA7", 0 }, { "ldrushar", "\xE2\xA5\x8B", 0 }, { "ldsh", "\xE2\x86\xB2", 0 }, { "le", "\xE2\x89\xA4", 0 }, { "leftarrow", "\xE2\x86\x90", 0 }, { "leftarrowtail", "\xE2\x86\xA2", 0 }, { "leftharpoondown", "\xE2\x86\xBD", 0 }, { "leftharpoonup", "\xE2\x86\xBC", 0 }, { "leftleftarrows", "\xE2\x87\x87", 0 }, { "leftrightarrow", "\xE2\x86\x94", 0 }, { "leftrightarrows", "\xE2\x87\x86", 0 }, { "leftrightharpoons", "\xE2\x87\x8B", 0 }, { "leftrightsquigarrow", "\xE2\x86\xAD", 0 }, { "leftthreetimes", "\xE2\x8B\x8B", 0 }, { "leg", "\xE2\x8B\x9A", 0 }, { "leq", "\xE2\x89\xA4", 0 }, { "leqq", "\xE2\x89\xA6", 0 }, { "leqslant", "\xE2\xA9\xBD", 0 }, { "les", "\xE2\xA9\xBD", 0 }, { "lescc", "\xE2\xAA\xA8", 0 }, { "lesdot", "\xE2\xA9\xBF", 0 }, { "lesdoto", "\xE2\xAA\x81", 0 }, { "lesdotor", "\xE2\xAA\x83", 0 }, { "lesg", "\xE2\x8B\x9A\xEF\xB8\x80", 0 }, { "lesges", "\xE2\xAA\x93", 0 }, { "lessapprox", "\xE2\xAA\x85", 0 }, { "lessdot", "\xE2\x8B\x96", 0 }, { "lesseqgtr", "\xE2\x8B\x9A", 0 }, { "lesseqqgtr", "\xE2\xAA\x8B", 0 }, { "lessgtr", "\xE2\x89\xB6", 0 }, { "lesssim", "\xE2\x89\xB2", 0 }, { "lfisht", "\xE2\xA5\xBC", 0 }, { "lfloor", "\xE2\x8C\x8A", 0 }, { "lfr", "\xF0\x9D\x94\xA9", 0 }, { "lg", "\xE2\x89\xB6", 0 }, { "lgE", "\xE2\xAA\x91", 0 }, { "lhard", "\xE2\x86\xBD", 0 }, { "lharu", "\xE2\x86\xBC", 0 }, { "lharul", "\xE2\xA5\xAA", 0 }, { "lhblk", "\xE2\x96\x84", 0 }, { "ljcy", "\xD1\x99", 0 }, { "ll", "\xE2\x89\xAA", 0 }, { "llarr", "\xE2\x87\x87", 0 }, { "llcorner", "\xE2\x8C\x9E", 0 }, { "llhard", "\xE2\xA5\xAB", 0 }, { "lltri", "\xE2\x97\xBA", 0 }, { "lmidot", "\xC5\x80", 0 }, { "lmoust", "\xE2\x8E\xB0", 0 }, { "lmoustache", "\xE2\x8E\xB0", 0 }, { "lnE", "\xE2\x89\xA8", 0 }, { "lnap", "\xE2\xAA\x89", 0 }, { "lnapprox", "\xE2\xAA\x89", 0 }, { "lne", "\xE2\xAA\x87", 0 }, { "lneq", "\xE2\xAA\x87", 0 }, { "lneqq", "\xE2\x89\xA8", 0 }, { "lnsim", "\xE2\x8B\xA6", 0 }, { "loang", "\xE2\x9F\xAC", 0 }, { "loarr", "\xE2\x87\xBD", 0 }, { "lobrk", "\xE2\x9F\xA6", 0 }, { "longleftarrow", "\xE2\x9F\xB5", 0 }, { "longleftrightarrow", "\xE2\x9F\xB7", 0 }, { "longmapsto", "\xE2\x9F\xBC", 0 }, { "longrightarrow", "\xE2\x9F\xB6", 0 }, { "looparrowleft", "\xE2\x86\xAB", 0 }, { "looparrowright", "\xE2\x86\xAC", 0 }, { "lopar", "\xE2\xA6\x85", 0 }, { "lopf", "\xF0\x9D\x95\x9D", 0 }, { "loplus", "\xE2\xA8\xAD", 0 }, { "lotimes", "\xE2\xA8\xB4", 0 }, { "lowast", "\xE2\x88\x97", 0 }, { "lowbar", "\x5F", 0 }, { "loz", "\xE2\x97\x8A", 0 }, { "lozenge", "\xE2\x97\x8A", 0 }, { "lozf", "\xE2\xA7\xAB", 0 }, { "lpar", "\x28", 0 }, { "lparlt", "\xE2\xA6\x93", 0 }, { "lrarr", "\xE2\x87\x86", 0 }, { "lrcorner", "\xE2\x8C\x9F", 0 }, { "lrhar", "\xE2\x87\x8B", 0 }, { "lrhard", "\xE2\xA5\xAD", 0 }, { "lrm", "\xE2\x80\x8E", 0 }, { "lrtri", "\xE2\x8A\xBF", 0 }, { "lsaquo", "\xE2\x80\xB9", 0 }, { "lscr", "\xF0\x9D\x93\x81", 0 }, { "lsh", "\xE2\x86\xB0", 0 }, { "lsim", "\xE2\x89\xB2", 0 }, { "lsime", "\xE2\xAA\x8D", 0 }, { "lsimg", "\xE2\xAA\x8F", 0 }, { "lsqb", "\x5B", 0 }, { "lsquo", "\xE2\x80\x98", 0 }, { "lsquor", "\xE2\x80\x9A", 0 }, { "lstrok", "\xC5\x82", 0 }, { "lt", "\x3C", 0 }, { "ltcc", "\xE2\xAA\xA6", 0 }, { "ltcir", "\xE2\xA9\xB9", 0 }, { "ltdot", "\xE2\x8B\x96", 0 }, { "lthree", "\xE2\x8B\x8B", 0 }, { "ltimes", "\xE2\x8B\x89", 0 }, { "ltlarr", "\xE2\xA5\xB6", 0 }, { "ltquest", "\xE2\xA9\xBB", 0 }, { "ltrPar", "\xE2\xA6\x96", 0 }, { "ltri", "\xE2\x97\x83", 0 }, { "ltrie", "\xE2\x8A\xB4", 0 }, { "ltrif", "\xE2\x97\x82", 0 }, { "lurdshar", "\xE2\xA5\x8A", 0 }, { "luruhar", "\xE2\xA5\xA6", 0 }, { "lvertneqq", "\xE2\x89\xA8\xEF\xB8\x80", 0 }, { "lvnE", "\xE2\x89\xA8\xEF\xB8\x80", 0 }, { "mDDot", "\xE2\x88\xBA", 0 }, { "macr", "\xC2\xAF", 0 }, { "male", "\xE2\x99\x82", 0 }, { "malt", "\xE2\x9C\xA0", 0 }, { "maltese", "\xE2\x9C\xA0", 0 }, { "map", "\xE2\x86\xA6", 0 }, { "mapsto", "\xE2\x86\xA6", 0 }, { "mapstodown", "\xE2\x86\xA7", 0 }, { "mapstoleft", "\xE2\x86\xA4", 0 }, { "mapstoup", "\xE2\x86\xA5", 0 }, { "marker", "\xE2\x96\xAE", 0 }, { "mcomma", "\xE2\xA8\xA9", 0 }, { "mcy", "\xD0\xBC", 0 }, { "mdash", "\xE2\x80\x94", 0 }, { "measuredangle", "\xE2\x88\xA1", 0 }, { "mfr", "\xF0\x9D\x94\xAA", 0 }, { "mho", "\xE2\x84\xA7", 0 }, { "micro", "\xC2\xB5", 0 }, { "mid", "\xE2\x88\xA3", 0 }, { "midast", "\x2A", 0 }, { "midcir", "\xE2\xAB\xB0", 0 }, { "middot", "\xC2\xB7", 0 }, { "minus", "\xE2\x88\x92", 0 }, { "minusb", "\xE2\x8A\x9F", 0 }, { "minusd", "\xE2\x88\xB8", 0 }, { "minusdu", "\xE2\xA8\xAA", 0 }, { "mlcp", "\xE2\xAB\x9B", 0 }, { "mldr", "\xE2\x80\xA6", 0 }, { "mnplus", "\xE2\x88\x93", 0 }, { "models", "\xE2\x8A\xA7", 0 }, { "mopf", "\xF0\x9D\x95\x9E", 0 }, { "mp", "\xE2\x88\x93", 0 }, { "mscr", "\xF0\x9D\x93\x82", 0 }, { "mstpos", "\xE2\x88\xBE", 0 }, { "mu", "\xCE\xBC", 0 }, { "multimap", "\xE2\x8A\xB8", 0 }, { "mumap", "\xE2\x8A\xB8", 0 }, { "nGg", "\xE2\x8B\x99\xCC\xB8", 0 }, { "nGtv", "\xE2\x89\xAB\xCC\xB8", 0 }, { "nLeftarrow", "\xE2\x87\x8D", 0 }, { "nLeftrightarrow", "\xE2\x87\x8E", 0 }, { "nLl", "\xE2\x8B\x98\xCC\xB8", 0 }, { "nLtv", "\xE2\x89\xAA\xCC\xB8", 0 }, { "nRightarrow", "\xE2\x87\x8F", 0 }, { "nVDash", "\xE2\x8A\xAF", 0 }, { "nVdash", "\xE2\x8A\xAE", 0 }, { "nabla", "\xE2\x88\x87", 0 }, { "nacute", "\xC5\x84", 0 }, { "nang", "\xE2\x88\xA0\xE2\x83\x92", 0 }, { "nap", "\xE2\x89\x89", 0 }, { "napE", "\xE2\xA9\xB0\xCC\xB8", 0 }, { "napid", "\xE2\x89\x8B\xCC\xB8", 0 }, { "napos", "\xC5\x89", 0 }, { "napprox", "\xE2\x89\x89", 0 }, { "natur", "\xE2\x99\xAE", 0 }, { "natural", "\xE2\x99\xAE", 0 }, { "naturals", "\xE2\x84\x95", 0 }, { "nbsp", "\xC2\xA0", 0 }, { "nbump", "\xE2\x89\x8E\xCC\xB8", 0 }, { "nbumpe", "\xE2\x89\x8F\xCC\xB8", 0 }, { "ncap", "\xE2\xA9\x83", 0 }, { "ncaron", "\xC5\x88", 0 }, { "ncedil", "\xC5\x86", 0 }, { "ncong", "\xE2\x89\x87", 0 }, { "ncongdot", "\xE2\xA9\xAD\xCC\xB8", 0 }, { "ncup", "\xE2\xA9\x82", 0 }, { "ncy", "\xD0\xBD", 0 }, { "ndash", "\xE2\x80\x93", 0 }, { "ne", "\xE2\x89\xA0", 0 }, { "neArr", "\xE2\x87\x97", 0 }, { "nearhk", "\xE2\xA4\xA4", 0 }, { "nearr", "\xE2\x86\x97", 0 }, { "nearrow", "\xE2\x86\x97", 0 }, { "nedot", "\xE2\x89\x90\xCC\xB8", 0 }, { "nequiv", "\xE2\x89\xA2", 0 }, { "nesear", "\xE2\xA4\xA8", 0 }, { "nesim", "\xE2\x89\x82\xCC\xB8", 0 }, { "nexist", "\xE2\x88\x84", 0 }, { "nexists", "\xE2\x88\x84", 0 }, { "nfr", "\xF0\x9D\x94\xAB", 0 }, { "ngE", "\xE2\x89\xA7\xCC\xB8", 0 }, { "nge", "\xE2\x89\xB1", 0 }, { "ngeq", "\xE2\x89\xB1", 0 }, { "ngeqq", "\xE2\x89\xA7\xCC\xB8", 0 }, { "ngeqslant", "\xE2\xA9\xBE\xCC\xB8", 0 }, { "nges", "\xE2\xA9\xBE\xCC\xB8", 0 }, { "ngsim", "\xE2\x89\xB5", 0 }, { "ngt", "\xE2\x89\xAF", 0 }, { "ngtr", "\xE2\x89\xAF", 0 }, { "nhArr", "\xE2\x87\x8E", 0 }, { "nharr", "\xE2\x86\xAE", 0 }, { "nhpar", "\xE2\xAB\xB2", 0 }, { "ni", "\xE2\x88\x8B", 0 }, { "nis", "\xE2\x8B\xBC", 0 }, { "nisd", "\xE2\x8B\xBA", 0 }, { "niv", "\xE2\x88\x8B", 0 }, { "njcy", "\xD1\x9A", 0 }, { "nlArr", "\xE2\x87\x8D", 0 }, { "nlE", "\xE2\x89\xA6\xCC\xB8", 0 }, { "nlarr", "\xE2\x86\x9A", 0 }, { "nldr", "\xE2\x80\xA5", 0 }, { "nle", "\xE2\x89\xB0", 0 }, { "nleftarrow", "\xE2\x86\x9A", 0 }, { "nleftrightarrow", "\xE2\x86\xAE", 0 }, { "nleq", "\xE2\x89\xB0", 0 }, { "nleqq", "\xE2\x89\xA6\xCC\xB8", 0 }, { "nleqslant", "\xE2\xA9\xBD\xCC\xB8", 0 }, { "nles", "\xE2\xA9\xBD\xCC\xB8", 0 }, { "nless", "\xE2\x89\xAE", 0 }, { "nlsim", "\xE2\x89\xB4", 0 }, { "nlt", "\xE2\x89\xAE", 0 }, { "nltri", "\xE2\x8B\xAA", 0 }, { "nltrie", "\xE2\x8B\xAC", 0 }, { "nmid", "\xE2\x88\xA4", 0 }, { "nopf", "\xF0\x9D\x95\x9F", 0 }, { "not", "\xC2\xAC", 0 }, { "notin", "\xE2\x88\x89", 0 }, { "notinE", "\xE2\x8B\xB9\xCC\xB8", 0 }, { "notindot", "\xE2\x8B\xB5\xCC\xB8", 0 }, { "notinva", "\xE2\x88\x89", 0 }, { "notinvb", "\xE2\x8B\xB7", 0 }, { "notinvc", "\xE2\x8B\xB6", 0 }, { "notni", "\xE2\x88\x8C", 0 }, { "notniva", "\xE2\x88\x8C", 0 }, { "notnivb", "\xE2\x8B\xBE", 0 }, { "notnivc", "\xE2\x8B\xBD", 0 }, { "npar", "\xE2\x88\xA6", 0 }, { "nparallel", "\xE2\x88\xA6", 0 }, { "nparsl", "\xE2\xAB\xBD\xE2\x83\xA5", 0 }, { "npart", "\xE2\x88\x82\xCC\xB8", 0 }, { "npolint", "\xE2\xA8\x94", 0 }, { "npr", "\xE2\x8A\x80", 0 }, { "nprcue", "\xE2\x8B\xA0", 0 }, { "npre", "\xE2\xAA\xAF\xCC\xB8", 0 }, { "nprec", "\xE2\x8A\x80", 0 }, { "npreceq", "\xE2\xAA\xAF\xCC\xB8", 0 }, { "nrArr", "\xE2\x87\x8F", 0 }, { "nrarr", "\xE2\x86\x9B", 0 }, { "nrarrc", "\xE2\xA4\xB3\xCC\xB8", 0 }, { "nrarrw", "\xE2\x86\x9D\xCC\xB8", 0 }, { "nrightarrow", "\xE2\x86\x9B", 0 }, { "nrtri", "\xE2\x8B\xAB", 0 }, { "nrtrie", "\xE2\x8B\xAD", 0 }, { "nsc", "\xE2\x8A\x81", 0 }, { "nsccue", "\xE2\x8B\xA1", 0 }, { "nsce", "\xE2\xAA\xB0\xCC\xB8", 0 }, { "nscr", "\xF0\x9D\x93\x83", 0 }, { "nshortmid", "\xE2\x88\xA4", 0 }, { "nshortparallel", "\xE2\x88\xA6", 0 }, { "nsim", "\xE2\x89\x81", 0 }, { "nsime", "\xE2\x89\x84", 0 }, { "nsimeq", "\xE2\x89\x84", 0 }, { "nsmid", "\xE2\x88\xA4", 0 }, { "nspar", "\xE2\x88\xA6", 0 }, { "nsqsube", "\xE2\x8B\xA2", 0 }, { "nsqsupe", "\xE2\x8B\xA3", 0 }, { "nsub", "\xE2\x8A\x84", 0 }, { "nsubE", "\xE2\xAB\x85\xCC\xB8", 0 }, { "nsube", "\xE2\x8A\x88", 0 }, { "nsubset", "\xE2\x8A\x82\xE2\x83\x92", 0 }, { "nsubseteq", "\xE2\x8A\x88", 0 }, { "nsubseteqq", "\xE2\xAB\x85\xCC\xB8", 0 }, { "nsucc", "\xE2\x8A\x81", 0 }, { "nsucceq", "\xE2\xAA\xB0\xCC\xB8", 0 }, { "nsup", "\xE2\x8A\x85", 0 }, { "nsupE", "\xE2\xAB\x86\xCC\xB8", 0 }, { "nsupe", "\xE2\x8A\x89", 0 }, { "nsupset", "\xE2\x8A\x83\xE2\x83\x92", 0 }, { "nsupseteq", "\xE2\x8A\x89", 0 }, { "nsupseteqq", "\xE2\xAB\x86\xCC\xB8", 0 }, { "ntgl", "\xE2\x89\xB9", 0 }, { "ntilde", "\xC3\xB1", 0 }, { "ntlg", "\xE2\x89\xB8", 0 }, { "ntriangleleft", "\xE2\x8B\xAA", 0 }, { "ntrianglelefteq", "\xE2\x8B\xAC", 0 }, { "ntriangleright", "\xE2\x8B\xAB", 0 }, { "ntrianglerighteq", "\xE2\x8B\xAD", 0 }, { "nu", "\xCE\xBD", 0 }, { "num", "\x23", 0 }, { "numero", "\xE2\x84\x96", 0 }, { "numsp", "\xE2\x80\x87", 0 }, { "nvDash", "\xE2\x8A\xAD", 0 }, { "nvHarr", "\xE2\xA4\x84", 0 }, { "nvap", "\xE2\x89\x8D\xE2\x83\x92", 0 }, { "nvdash", "\xE2\x8A\xAC", 0 }, { "nvge", "\xE2\x89\xA5\xE2\x83\x92", 0 }, { "nvgt", "\x3E\xE2\x83\x92", 0 }, { "nvinfin", "\xE2\xA7\x9E", 0 }, { "nvlArr", "\xE2\xA4\x82", 0 }, { "nvle", "\xE2\x89\xA4\xE2\x83\x92", 0 }, { "nvlt", "\x3C\xE2\x83\x92", 0 }, { "nvltrie", "\xE2\x8A\xB4\xE2\x83\x92", 0 }, { "nvrArr", "\xE2\xA4\x83", 0 }, { "nvrtrie", "\xE2\x8A\xB5\xE2\x83\x92", 0 }, { "nvsim", "\xE2\x88\xBC\xE2\x83\x92", 0 }, { "nwArr", "\xE2\x87\x96", 0 }, { "nwarhk", "\xE2\xA4\xA3", 0 }, { "nwarr", "\xE2\x86\x96", 0 }, { "nwarrow", "\xE2\x86\x96", 0 }, { "nwnear", "\xE2\xA4\xA7", 0 }, { "oS", "\xE2\x93\x88", 0 }, { "oacute", "\xC3\xB3", 0 }, { "oast", "\xE2\x8A\x9B", 0 }, { "ocir", "\xE2\x8A\x9A", 0 }, { "ocirc", "\xC3\xB4", 0 }, { "ocy", "\xD0\xBE", 0 }, { "odash", "\xE2\x8A\x9D", 0 }, { "odblac", "\xC5\x91", 0 }, { "odiv", "\xE2\xA8\xB8", 0 }, { "odot", "\xE2\x8A\x99", 0 }, { "odsold", "\xE2\xA6\xBC", 0 }, { "oelig", "\xC5\x93", 0 }, { "ofcir", "\xE2\xA6\xBF", 0 }, { "ofr", "\xF0\x9D\x94\xAC", 0 }, { "ogon", "\xCB\x9B", 0 }, { "ograve", "\xC3\xB2", 0 }, { "ogt", "\xE2\xA7\x81", 0 }, { "ohbar", "\xE2\xA6\xB5", 0 }, { "ohm", "\xCE\xA9", 0 }, { "oint", "\xE2\x88\xAE", 0 }, { "olarr", "\xE2\x86\xBA", 0 }, { "olcir", "\xE2\xA6\xBE", 0 }, { "olcross", "\xE2\xA6\xBB", 0 }, { "oline", "\xE2\x80\xBE", 0 }, { "olt", "\xE2\xA7\x80", 0 }, { "omacr", "\xC5\x8D", 0 }, { "omega", "\xCF\x89", 0 }, { "omicron", "\xCE\xBF", 0 }, { "omid", "\xE2\xA6\xB6", 0 }, { "ominus", "\xE2\x8A\x96", 0 }, { "oopf", "\xF0\x9D\x95\xA0", 0 }, { "opar", "\xE2\xA6\xB7", 0 }, { "operp", "\xE2\xA6\xB9", 0 }, { "oplus", "\xE2\x8A\x95", 0 }, { "or", "\xE2\x88\xA8", 0 }, { "orarr", "\xE2\x86\xBB", 0 }, { "ord", "\xE2\xA9\x9D", 0 }, { "order", "\xE2\x84\xB4", 0 }, { "orderof", "\xE2\x84\xB4", 0 }, { "ordf", "\xC2\xAA", 0 }, { "ordm", "\xC2\xBA", 0 }, { "origof", "\xE2\x8A\xB6", 0 }, { "oror", "\xE2\xA9\x96", 0 }, { "orslope", "\xE2\xA9\x97", 0 }, { "orv", "\xE2\xA9\x9B", 0 }, { "oscr", "\xE2\x84\xB4", 0 }, { "oslash", "\xC3\xB8", 0 }, { "osol", "\xE2\x8A\x98", 0 }, { "otilde", "\xC3\xB5", 0 }, { "otimes", "\xE2\x8A\x97", 0 }, { "otimesas", "\xE2\xA8\xB6", 0 }, { "ouml", "\xC3\xB6", 0 }, { "ovbar", "\xE2\x8C\xBD", 0 }, { "par", "\xE2\x88\xA5", 0 }, { "para", "\xC2\xB6", 0 }, { "parallel", "\xE2\x88\xA5", 0 }, { "parsim", "\xE2\xAB\xB3", 0 }, { "parsl", "\xE2\xAB\xBD", 0 }, { "part", "\xE2\x88\x82", 0 }, { "pcy", "\xD0\xBF", 0 }, { "percnt", "\x25", 0 }, { "period", "\x2E", 0 }, { "permil", "\xE2\x80\xB0", 0 }, { "perp", "\xE2\x8A\xA5", 0 }, { "pertenk", "\xE2\x80\xB1", 0 }, { "pfr", "\xF0\x9D\x94\xAD", 0 }, { "phi", "\xCF\x86", 0 }, { "phiv", "\xCF\x95", 0 }, { "phmmat", "\xE2\x84\xB3", 0 }, { "phone", "\xE2\x98\x8E", 0 }, { "pi", "\xCF\x80", 0 }, { "pitchfork", "\xE2\x8B\x94", 0 }, { "piv", "\xCF\x96", 0 }, { "planck", "\xE2\x84\x8F", 0 }, { "planckh", "\xE2\x84\x8E", 0 }, { "plankv", "\xE2\x84\x8F", 0 }, { "plus", "\x2B", 0 }, { "plusacir", "\xE2\xA8\xA3", 0 }, { "plusb", "\xE2\x8A\x9E", 0 }, { "pluscir", "\xE2\xA8\xA2", 0 }, { "plusdo", "\xE2\x88\x94", 0 }, { "plusdu", "\xE2\xA8\xA5", 0 }, { "pluse", "\xE2\xA9\xB2", 0 }, { "plusmn", "\xC2\xB1", 0 }, { "plussim", "\xE2\xA8\xA6", 0 }, { "plustwo", "\xE2\xA8\xA7", 0 }, { "pm", "\xC2\xB1", 0 }, { "pointint", "\xE2\xA8\x95", 0 }, { "popf", "\xF0\x9D\x95\xA1", 0 }, { "pound", "\xC2\xA3", 0 }, { "pr", "\xE2\x89\xBA", 0 }, { "prE", "\xE2\xAA\xB3", 0 }, { "prap", "\xE2\xAA\xB7", 0 }, { "prcue", "\xE2\x89\xBC", 0 }, { "pre", "\xE2\xAA\xAF", 0 }, { "prec", "\xE2\x89\xBA", 0 }, { "precapprox", "\xE2\xAA\xB7", 0 }, { "preccurlyeq", "\xE2\x89\xBC", 0 }, { "preceq", "\xE2\xAA\xAF", 0 }, { "precnapprox", "\xE2\xAA\xB9", 0 }, { "precneqq", "\xE2\xAA\xB5", 0 }, { "precnsim", "\xE2\x8B\xA8", 0 }, { "precsim", "\xE2\x89\xBE", 0 }, { "prime", "\xE2\x80\xB2", 0 }, { "primes", "\xE2\x84\x99", 0 }, { "prnE", "\xE2\xAA\xB5", 0 }, { "prnap", "\xE2\xAA\xB9", 0 }, { "prnsim", "\xE2\x8B\xA8", 0 }, { "prod", "\xE2\x88\x8F", 0 }, { "profalar", "\xE2\x8C\xAE", 0 }, { "profline", "\xE2\x8C\x92", 0 }, { "profsurf", "\xE2\x8C\x93", 0 }, { "prop", "\xE2\x88\x9D", 0 }, { "propto", "\xE2\x88\x9D", 0 }, { "prsim", "\xE2\x89\xBE", 0 }, { "prurel", "\xE2\x8A\xB0", 0 }, { "pscr", "\xF0\x9D\x93\x85", 0 }, { "psi", "\xCF\x88", 0 }, { "puncsp", "\xE2\x80\x88", 0 }, { "qfr", "\xF0\x9D\x94\xAE", 0 }, { "qint", "\xE2\xA8\x8C", 0 }, { "qopf", "\xF0\x9D\x95\xA2", 0 }, { "qprime", "\xE2\x81\x97", 0 }, { "qscr", "\xF0\x9D\x93\x86", 0 }, { "quaternions", "\xE2\x84\x8D", 0 }, { "quatint", "\xE2\xA8\x96", 0 }, { "quest", "\x3F", 0 }, { "questeq", "\xE2\x89\x9F", 0 }, { "quot", "\x22", 0 }, { "rAarr", "\xE2\x87\x9B", 0 }, { "rArr", "\xE2\x87\x92", 0 }, { "rAtail", "\xE2\xA4\x9C", 0 }, { "rBarr", "\xE2\xA4\x8F", 0 }, { "rHar", "\xE2\xA5\xA4", 0 }, { "race", "\xE2\x88\xBD\xCC\xB1", 0 }, { "racute", "\xC5\x95", 0 }, { "radic", "\xE2\x88\x9A", 0 }, { "raemptyv", "\xE2\xA6\xB3", 0 }, { "rang", "\xE2\x9F\xA9", 0 }, { "rangd", "\xE2\xA6\x92", 0 }, { "range", "\xE2\xA6\xA5", 0 }, { "rangle", "\xE2\x9F\xA9", 0 }, { "raquo", "\xC2\xBB", 0 }, { "rarr", "\xE2\x86\x92", 0 }, { "rarrap", "\xE2\xA5\xB5", 0 }, { "rarrb", "\xE2\x87\xA5", 0 }, { "rarrbfs", "\xE2\xA4\xA0", 0 }, { "rarrc", "\xE2\xA4\xB3", 0 }, { "rarrfs", "\xE2\xA4\x9E", 0 }, { "rarrhk", "\xE2\x86\xAA", 0 }, { "rarrlp", "\xE2\x86\xAC", 0 }, { "rarrpl", "\xE2\xA5\x85", 0 }, { "rarrsim", "\xE2\xA5\xB4", 0 }, { "rarrtl", "\xE2\x86\xA3", 0 }, { "rarrw", "\xE2\x86\x9D", 0 }, { "ratail", "\xE2\xA4\x9A", 0 }, { "ratio", "\xE2\x88\xB6", 0 }, { "rationals", "\xE2\x84\x9A", 0 }, { "rbarr", "\xE2\xA4\x8D", 0 }, { "rbbrk", "\xE2\x9D\xB3", 0 }, { "rbrace", "\x7D", 0 }, { "rbrack", "\x5D", 0 }, { "rbrke", "\xE2\xA6\x8C", 0 }, { "rbrksld", "\xE2\xA6\x8E", 0 }, { "rbrkslu", "\xE2\xA6\x90", 0 }, { "rcaron", "\xC5\x99", 0 }, { "rcedil", "\xC5\x97", 0 }, { "rceil", "\xE2\x8C\x89", 0 }, { "rcub", "\x7D", 0 }, { "rcy", "\xD1\x80", 0 }, { "rdca", "\xE2\xA4\xB7", 0 }, { "rdldhar", "\xE2\xA5\xA9", 0 }, { "rdquo", "\xE2\x80\x9D", 0 }, { "rdquor", "\xE2\x80\x9D", 0 }, { "rdsh", "\xE2\x86\xB3", 0 }, { "real", "\xE2\x84\x9C", 0 }, { "realine", "\xE2\x84\x9B", 0 }, { "realpart", "\xE2\x84\x9C", 0 }, { "reals", "\xE2\x84\x9D", 0 }, { "rect", "\xE2\x96\xAD", 0 }, { "reg", "\xC2\xAE", 0 }, { "rfisht", "\xE2\xA5\xBD", 0 }, { "rfloor", "\xE2\x8C\x8B", 0 }, { "rfr", "\xF0\x9D\x94\xAF", 0 }, { "rhard", "\xE2\x87\x81", 0 }, { "rharu", "\xE2\x87\x80", 0 }, { "rharul", "\xE2\xA5\xAC", 0 }, { "rho", "\xCF\x81", 0 }, { "rhov", "\xCF\xB1", 0 }, { "rightarrow", "\xE2\x86\x92", 0 }, { "rightarrowtail", "\xE2\x86\xA3", 0 }, { "rightharpoondown", "\xE2\x87\x81", 0 }, { "rightharpoonup", "\xE2\x87\x80", 0 }, { "rightleftarrows", "\xE2\x87\x84", 0 }, { "rightleftharpoons", "\xE2\x87\x8C", 0 }, { "rightrightarrows", "\xE2\x87\x89", 0 }, { "rightsquigarrow", "\xE2\x86\x9D", 0 }, { "rightthreetimes", "\xE2\x8B\x8C", 0 }, { "ring", "\xCB\x9A", 0 }, { "risingdotseq", "\xE2\x89\x93", 0 }, { "rlarr", "\xE2\x87\x84", 0 }, { "rlhar", "\xE2\x87\x8C", 0 }, { "rlm", "\xE2\x80\x8F", 0 }, { "rmoust", "\xE2\x8E\xB1", 0 }, { "rmoustache", "\xE2\x8E\xB1", 0 }, { "rnmid", "\xE2\xAB\xAE", 0 }, { "roang", "\xE2\x9F\xAD", 0 }, { "roarr", "\xE2\x87\xBE", 0 }, { "robrk", "\xE2\x9F\xA7", 0 }, { "ropar", "\xE2\xA6\x86", 0 }, { "ropf", "\xF0\x9D\x95\xA3", 0 }, { "roplus", "\xE2\xA8\xAE", 0 }, { "rotimes", "\xE2\xA8\xB5", 0 }, { "rpar", "\x29", 0 }, { "rpargt", "\xE2\xA6\x94", 0 }, { "rppolint", "\xE2\xA8\x92", 0 }, { "rrarr", "\xE2\x87\x89", 0 }, { "rsaquo", "\xE2\x80\xBA", 0 }, { "rscr", "\xF0\x9D\x93\x87", 0 }, { "rsh", "\xE2\x86\xB1", 0 }, { "rsqb", "\x5D", 0 }, { "rsquo", "\xE2\x80\x99", 0 }, { "rsquor", "\xE2\x80\x99", 0 }, { "rthree", "\xE2\x8B\x8C", 0 }, { "rtimes", "\xE2\x8B\x8A", 0 }, { "rtri", "\xE2\x96\xB9", 0 }, { "rtrie", "\xE2\x8A\xB5", 0 }, { "rtrif", "\xE2\x96\xB8", 0 }, { "rtriltri", "\xE2\xA7\x8E", 0 }, { "ruluhar", "\xE2\xA5\xA8", 0 }, { "rx", "\xE2\x84\x9E", 0 }, { "sacute", "\xC5\x9B", 0 }, { "sbquo", "\xE2\x80\x9A", 0 }, { "sc", "\xE2\x89\xBB", 0 }, { "scE", "\xE2\xAA\xB4", 0 }, { "scap", "\xE2\xAA\xB8", 0 }, { "scaron", "\xC5\xA1", 0 }, { "sccue", "\xE2\x89\xBD", 0 }, { "sce", "\xE2\xAA\xB0", 0 }, { "scedil", "\xC5\x9F", 0 }, { "scirc", "\xC5\x9D", 0 }, { "scnE", "\xE2\xAA\xB6", 0 }, { "scnap", "\xE2\xAA\xBA", 0 }, { "scnsim", "\xE2\x8B\xA9", 0 }, { "scpolint", "\xE2\xA8\x93", 0 }, { "scsim", "\xE2\x89\xBF", 0 }, { "scy", "\xD1\x81", 0 }, { "sdot", "\xE2\x8B\x85", 0 }, { "sdotb", "\xE2\x8A\xA1", 0 }, { "sdote", "\xE2\xA9\xA6", 0 }, { "seArr", "\xE2\x87\x98", 0 }, { "searhk", "\xE2\xA4\xA5", 0 }, { "searr", "\xE2\x86\x98", 0 }, { "searrow", "\xE2\x86\x98", 0 }, { "sect", "\xC2\xA7", 0 }, { "semi", "\x3B", 0 }, { "seswar", "\xE2\xA4\xA9", 0 }, { "setminus", "\xE2\x88\x96", 0 }, { "setmn", "\xE2\x88\x96", 0 }, { "sext", "\xE2\x9C\xB6", 0 }, { "sfr", "\xF0\x9D\x94\xB0", 0 }, { "sfrown", "\xE2\x8C\xA2", 0 }, { "sharp", "\xE2\x99\xAF", 0 }, { "shchcy", "\xD1\x89", 0 }, { "shcy", "\xD1\x88", 0 }, { "shortmid", "\xE2\x88\xA3", 0 }, { "shortparallel", "\xE2\x88\xA5", 0 }, { "shy", "\xC2\xAD", 0 }, { "sigma", "\xCF\x83", 0 }, { "sigmaf", "\xCF\x82", 0 }, { "sigmav", "\xCF\x82", 0 }, { "sim", "\xE2\x88\xBC", 0 }, { "simdot", "\xE2\xA9\xAA", 0 }, { "sime", "\xE2\x89\x83", 0 }, { "simeq", "\xE2\x89\x83", 0 }, { "simg", "\xE2\xAA\x9E", 0 }, { "simgE", "\xE2\xAA\xA0", 0 }, { "siml", "\xE2\xAA\x9D", 0 }, { "simlE", "\xE2\xAA\x9F", 0 }, { "simne", "\xE2\x89\x86", 0 }, { "simplus", "\xE2\xA8\xA4", 0 }, { "simrarr", "\xE2\xA5\xB2", 0 }, { "slarr", "\xE2\x86\x90", 0 }, { "smallsetminus", "\xE2\x88\x96", 0 }, { "smashp", "\xE2\xA8\xB3", 0 }, { "smeparsl", "\xE2\xA7\xA4", 0 }, { "smid", "\xE2\x88\xA3", 0 }, { "smile", "\xE2\x8C\xA3", 0 }, { "smt", "\xE2\xAA\xAA", 0 }, { "smte", "\xE2\xAA\xAC", 0 }, { "smtes", "\xE2\xAA\xAC\xEF\xB8\x80", 0 }, { "softcy", "\xD1\x8C", 0 }, { "sol", "\x2F", 0 }, { "solb", "\xE2\xA7\x84", 0 }, { "solbar", "\xE2\x8C\xBF", 0 }, { "sopf", "\xF0\x9D\x95\xA4", 0 }, { "spades", "\xE2\x99\xA0", 0 }, { "spadesuit", "\xE2\x99\xA0", 0 }, { "spar", "\xE2\x88\xA5", 0 }, { "sqcap", "\xE2\x8A\x93", 0 }, { "sqcaps", "\xE2\x8A\x93\xEF\xB8\x80", 0 }, { "sqcup", "\xE2\x8A\x94", 0 }, { "sqcups", "\xE2\x8A\x94\xEF\xB8\x80", 0 }, { "sqsub", "\xE2\x8A\x8F", 0 }, { "sqsube", "\xE2\x8A\x91", 0 }, { "sqsubset", "\xE2\x8A\x8F", 0 }, { "sqsubseteq", "\xE2\x8A\x91", 0 }, { "sqsup", "\xE2\x8A\x90", 0 }, { "sqsupe", "\xE2\x8A\x92", 0 }, { "sqsupset", "\xE2\x8A\x90", 0 }, { "sqsupseteq", "\xE2\x8A\x92", 0 }, { "squ", "\xE2\x96\xA1", 0 }, { "square", "\xE2\x96\xA1", 0 }, { "squarf", "\xE2\x96\xAA", 0 }, { "squf", "\xE2\x96\xAA", 0 }, { "srarr", "\xE2\x86\x92", 0 }, { "sscr", "\xF0\x9D\x93\x88", 0 }, { "ssetmn", "\xE2\x88\x96", 0 }, { "ssmile", "\xE2\x8C\xA3", 0 }, { "sstarf", "\xE2\x8B\x86", 0 }, { "star", "\xE2\x98\x86", 0 }, { "starf", "\xE2\x98\x85", 0 }, { "straightepsilon", "\xCF\xB5", 0 }, { "straightphi", "\xCF\x95", 0 }, { "strns", "\xC2\xAF", 0 }, { "sub", "\xE2\x8A\x82", 0 }, { "subE", "\xE2\xAB\x85", 0 }, { "subdot", "\xE2\xAA\xBD", 0 }, { "sube", "\xE2\x8A\x86", 0 }, { "subedot", "\xE2\xAB\x83", 0 }, { "submult", "\xE2\xAB\x81", 0 }, { "subnE", "\xE2\xAB\x8B", 0 }, { "subne", "\xE2\x8A\x8A", 0 }, { "subplus", "\xE2\xAA\xBF", 0 }, { "subrarr", "\xE2\xA5\xB9", 0 }, { "subset", "\xE2\x8A\x82", 0 }, { "subseteq", "\xE2\x8A\x86", 0 }, { "subseteqq", "\xE2\xAB\x85", 0 }, { "subsetneq", "\xE2\x8A\x8A", 0 }, { "subsetneqq", "\xE2\xAB\x8B", 0 }, { "subsim", "\xE2\xAB\x87", 0 }, { "subsub", "\xE2\xAB\x95", 0 }, { "subsup", "\xE2\xAB\x93", 0 }, { "succ", "\xE2\x89\xBB", 0 }, { "succapprox", "\xE2\xAA\xB8", 0 }, { "succcurlyeq", "\xE2\x89\xBD", 0 }, { "succeq", "\xE2\xAA\xB0", 0 }, { "succnapprox", "\xE2\xAA\xBA", 0 }, { "succneqq", "\xE2\xAA\xB6", 0 }, { "succnsim", "\xE2\x8B\xA9", 0 }, { "succsim", "\xE2\x89\xBF", 0 }, { "sum", "\xE2\x88\x91", 0 }, { "sung", "\xE2\x99\xAA", 0 }, { "sup", "\xE2\x8A\x83", 0 }, { "sup1", "\xC2\xB9", 0 }, { "sup2", "\xC2\xB2", 0 }, { "sup3", "\xC2\xB3", 0 }, { "supE", "\xE2\xAB\x86", 0 }, { "supdot", "\xE2\xAA\xBE", 0 }, { "supdsub", "\xE2\xAB\x98", 0 }, { "supe", "\xE2\x8A\x87", 0 }, { "supedot", "\xE2\xAB\x84", 0 }, { "suphsol", "\xE2\x9F\x89", 0 }, { "suphsub", "\xE2\xAB\x97", 0 }, { "suplarr", "\xE2\xA5\xBB", 0 }, { "supmult", "\xE2\xAB\x82", 0 }, { "supnE", "\xE2\xAB\x8C", 0 }, { "supne", "\xE2\x8A\x8B", 0 }, { "supplus", "\xE2\xAB\x80", 0 }, { "supset", "\xE2\x8A\x83", 0 }, { "supseteq", "\xE2\x8A\x87", 0 }, { "supseteqq", "\xE2\xAB\x86", 0 }, { "supsetneq", "\xE2\x8A\x8B", 0 }, { "supsetneqq", "\xE2\xAB\x8C", 0 }, { "supsim", "\xE2\xAB\x88", 0 }, { "supsub", "\xE2\xAB\x94", 0 }, { "supsup", "\xE2\xAB\x96", 0 }, { "swArr", "\xE2\x87\x99", 0 }, { "swarhk", "\xE2\xA4\xA6", 0 }, { "swarr", "\xE2\x86\x99", 0 }, { "swarrow", "\xE2\x86\x99", 0 }, { "swnwar", "\xE2\xA4\xAA", 0 }, { "szlig", "\xC3\x9F", 0 }, { "target", "\xE2\x8C\x96", 0 }, { "tau", "\xCF\x84", 0 }, { "tbrk", "\xE2\x8E\xB4", 0 }, { "tcaron", "\xC5\xA5", 0 }, { "tcedil", "\xC5\xA3", 0 }, { "tcy", "\xD1\x82", 0 }, { "tdot", "\xE2\x83\x9B", 0 }, { "telrec", "\xE2\x8C\x95", 0 }, { "tfr", "\xF0\x9D\x94\xB1", 0 }, { "there4", "\xE2\x88\xB4", 0 }, { "therefore", "\xE2\x88\xB4", 0 }, { "theta", "\xCE\xB8", 0 }, { "thetasym", "\xCF\x91", 0 }, { "thetav", "\xCF\x91", 0 }, { "thickapprox", "\xE2\x89\x88", 0 }, { "thicksim", "\xE2\x88\xBC", 0 }, { "thinsp", "\xE2\x80\x89", 0 }, { "thkap", "\xE2\x89\x88", 0 }, { "thksim", "\xE2\x88\xBC", 0 }, { "thorn", "\xC3\xBE", 0 }, { "tilde", "\xCB\x9C", 0 }, { "times", "\xC3\x97", 0 }, { "timesb", "\xE2\x8A\xA0", 0 }, { "timesbar", "\xE2\xA8\xB1", 0 }, { "timesd", "\xE2\xA8\xB0", 0 }, { "tint", "\xE2\x88\xAD", 0 }, { "toea", "\xE2\xA4\xA8", 0 }, { "top", "\xE2\x8A\xA4", 0 }, { "topbot", "\xE2\x8C\xB6", 0 }, { "topcir", "\xE2\xAB\xB1", 0 }, { "topf", "\xF0\x9D\x95\xA5", 0 }, { "topfork", "\xE2\xAB\x9A", 0 }, { "tosa", "\xE2\xA4\xA9", 0 }, { "tprime", "\xE2\x80\xB4", 0 }, { "trade", "\xE2\x84\xA2", 0 }, { "triangle", "\xE2\x96\xB5", 0 }, { "triangledown", "\xE2\x96\xBF", 0 }, { "triangleleft", "\xE2\x97\x83", 0 }, { "trianglelefteq", "\xE2\x8A\xB4", 0 }, { "triangleq", "\xE2\x89\x9C", 0 }, { "triangleright", "\xE2\x96\xB9", 0 }, { "trianglerighteq", "\xE2\x8A\xB5", 0 }, { "tridot", "\xE2\x97\xAC", 0 }, { "trie", "\xE2\x89\x9C", 0 }, { "triminus", "\xE2\xA8\xBA", 0 }, { "triplus", "\xE2\xA8\xB9", 0 }, { "trisb", "\xE2\xA7\x8D", 0 }, { "tritime", "\xE2\xA8\xBB", 0 }, { "trpezium", "\xE2\x8F\xA2", 0 }, { "tscr", "\xF0\x9D\x93\x89", 0 }, { "tscy", "\xD1\x86", 0 }, { "tshcy", "\xD1\x9B", 0 }, { "tstrok", "\xC5\xA7", 0 }, { "twixt", "\xE2\x89\xAC", 0 }, { "twoheadleftarrow", "\xE2\x86\x9E", 0 }, { "twoheadrightarrow", "\xE2\x86\xA0", 0 }, { "uArr", "\xE2\x87\x91", 0 }, { "uHar", "\xE2\xA5\xA3", 0 }, { "uacute", "\xC3\xBA", 0 }, { "uarr", "\xE2\x86\x91", 0 }, { "ubrcy", "\xD1\x9E", 0 }, { "ubreve", "\xC5\xAD", 0 }, { "ucirc", "\xC3\xBB", 0 }, { "ucy", "\xD1\x83", 0 }, { "udarr", "\xE2\x87\x85", 0 }, { "udblac", "\xC5\xB1", 0 }, { "udhar", "\xE2\xA5\xAE", 0 }, { "ufisht", "\xE2\xA5\xBE", 0 }, { "ufr", "\xF0\x9D\x94\xB2", 0 }, { "ugrave", "\xC3\xB9", 0 }, { "uharl", "\xE2\x86\xBF", 0 }, { "uharr", "\xE2\x86\xBE", 0 }, { "uhblk", "\xE2\x96\x80", 0 }, { "ulcorn", "\xE2\x8C\x9C", 0 }, { "ulcorner", "\xE2\x8C\x9C", 0 }, { "ulcrop", "\xE2\x8C\x8F", 0 }, { "ultri", "\xE2\x97\xB8", 0 }, { "umacr", "\xC5\xAB", 0 }, { "uml", "\xC2\xA8", 0 }, { "uogon", "\xC5\xB3", 0 }, { "uopf", "\xF0\x9D\x95\xA6", 0 }, { "uparrow", "\xE2\x86\x91", 0 }, { "updownarrow", "\xE2\x86\x95", 0 }, { "upharpoonleft", "\xE2\x86\xBF", 0 }, { "upharpoonright", "\xE2\x86\xBE", 0 }, { "uplus", "\xE2\x8A\x8E", 0 }, { "upsi", "\xCF\x85", 0 }, { "upsih", "\xCF\x92", 0 }, { "upsilon", "\xCF\x85", 0 }, { "upuparrows", "\xE2\x87\x88", 0 }, { "urcorn", "\xE2\x8C\x9D", 0 }, { "urcorner", "\xE2\x8C\x9D", 0 }, { "urcrop", "\xE2\x8C\x8E", 0 }, { "uring", "\xC5\xAF", 0 }, { "urtri", "\xE2\x97\xB9", 0 }, { "uscr", "\xF0\x9D\x93\x8A", 0 }, { "utdot", "\xE2\x8B\xB0", 0 }, { "utilde", "\xC5\xA9", 0 }, { "utri", "\xE2\x96\xB5", 0 }, { "utrif", "\xE2\x96\xB4", 0 }, { "uuarr", "\xE2\x87\x88", 0 }, { "uuml", "\xC3\xBC", 0 }, { "uwangle", "\xE2\xA6\xA7", 0 }, { "vArr", "\xE2\x87\x95", 0 }, { "vBar", "\xE2\xAB\xA8", 0 }, { "vBarv", "\xE2\xAB\xA9", 0 }, { "vDash", "\xE2\x8A\xA8", 0 }, { "vangrt", "\xE2\xA6\x9C", 0 }, { "varepsilon", "\xCF\xB5", 0 }, { "varkappa", "\xCF\xB0", 0 }, { "varnothing", "\xE2\x88\x85", 0 }, { "varphi", "\xCF\x95", 0 }, { "varpi", "\xCF\x96", 0 }, { "varpropto", "\xE2\x88\x9D", 0 }, { "varr", "\xE2\x86\x95", 0 }, { "varrho", "\xCF\xB1", 0 }, { "varsigma", "\xCF\x82", 0 }, { "varsubsetneq", "\xE2\x8A\x8A\xEF\xB8\x80", 0 }, { "varsubsetneqq", "\xE2\xAB\x8B\xEF\xB8\x80", 0 }, { "varsupsetneq", "\xE2\x8A\x8B\xEF\xB8\x80", 0 }, { "varsupsetneqq", "\xE2\xAB\x8C\xEF\xB8\x80", 0 }, { "vartheta", "\xCF\x91", 0 }, { "vartriangleleft", "\xE2\x8A\xB2", 0 }, { "vartriangleright", "\xE2\x8A\xB3", 0 }, { "vcy", "\xD0\xB2", 0 }, { "vdash", "\xE2\x8A\xA2", 0 }, { "vee", "\xE2\x88\xA8", 0 }, { "veebar", "\xE2\x8A\xBB", 0 }, { "veeeq", "\xE2\x89\x9A", 0 }, { "vellip", "\xE2\x8B\xAE", 0 }, { "verbar", "\x7C", 0 }, { "vert", "\x7C", 0 }, { "vfr", "\xF0\x9D\x94\xB3", 0 }, { "vltri", "\xE2\x8A\xB2", 0 }, { "vnsub", "\xE2\x8A\x82\xE2\x83\x92", 0 }, { "vnsup", "\xE2\x8A\x83\xE2\x83\x92", 0 }, { "vopf", "\xF0\x9D\x95\xA7", 0 }, { "vprop", "\xE2\x88\x9D", 0 }, { "vrtri", "\xE2\x8A\xB3", 0 }, { "vscr", "\xF0\x9D\x93\x8B", 0 }, { "vsubnE", "\xE2\xAB\x8B\xEF\xB8\x80", 0 }, { "vsubne", "\xE2\x8A\x8A\xEF\xB8\x80", 0 }, { "vsupnE", "\xE2\xAB\x8C\xEF\xB8\x80", 0 }, { "vsupne", "\xE2\x8A\x8B\xEF\xB8\x80", 0 }, { "vzigzag", "\xE2\xA6\x9A", 0 }, { "wcirc", "\xC5\xB5", 0 }, { "wedbar", "\xE2\xA9\x9F", 0 }, { "wedge", "\xE2\x88\xA7", 0 }, { "wedgeq", "\xE2\x89\x99", 0 }, { "weierp", "\xE2\x84\x98", 0 }, { "wfr", "\xF0\x9D\x94\xB4", 0 }, { "wopf", "\xF0\x9D\x95\xA8", 0 }, { "wp", "\xE2\x84\x98", 0 }, { "wr", "\xE2\x89\x80", 0 }, { "wreath", "\xE2\x89\x80", 0 }, { "wscr", "\xF0\x9D\x93\x8C", 0 }, { "xcap", "\xE2\x8B\x82", 0 }, { "xcirc", "\xE2\x97\xAF", 0 }, { "xcup", "\xE2\x8B\x83", 0 }, { "xdtri", "\xE2\x96\xBD", 0 }, { "xfr", "\xF0\x9D\x94\xB5", 0 }, { "xhArr", "\xE2\x9F\xBA", 0 }, { "xharr", "\xE2\x9F\xB7", 0 }, { "xi", "\xCE\xBE", 0 }, { "xlArr", "\xE2\x9F\xB8", 0 }, { "xlarr", "\xE2\x9F\xB5", 0 }, { "xmap", "\xE2\x9F\xBC", 0 }, { "xnis", "\xE2\x8B\xBB", 0 }, { "xodot", "\xE2\xA8\x80", 0 }, { "xopf", "\xF0\x9D\x95\xA9", 0 }, { "xoplus", "\xE2\xA8\x81", 0 }, { "xotime", "\xE2\xA8\x82", 0 }, { "xrArr", "\xE2\x9F\xB9", 0 }, { "xrarr", "\xE2\x9F\xB6", 0 }, { "xscr", "\xF0\x9D\x93\x8D", 0 }, { "xsqcup", "\xE2\xA8\x86", 0 }, { "xuplus", "\xE2\xA8\x84", 0 }, { "xutri", "\xE2\x96\xB3", 0 }, { "xvee", "\xE2\x8B\x81", 0 }, { "xwedge", "\xE2\x8B\x80", 0 }, { "yacute", "\xC3\xBD", 0 }, { "yacy", "\xD1\x8F", 0 }, { "ycirc", "\xC5\xB7", 0 }, { "ycy", "\xD1\x8B", 0 }, { "yen", "\xC2\xA5", 0 }, { "yfr", "\xF0\x9D\x94\xB6", 0 }, { "yicy", "\xD1\x97", 0 }, { "yopf", "\xF0\x9D\x95\xAA", 0 }, { "yscr", "\xF0\x9D\x93\x8E", 0 }, { "yucy", "\xD1\x8E", 0 }, { "yuml", "\xC3\xBF", 0 }, { "zacute", "\xC5\xBA", 0 }, { "zcaron", "\xC5\xBE", 0 }, { "zcy", "\xD0\xB7", 0 }, { "zdot", "\xC5\xBC", 0 }, { "zeetrf", "\xE2\x84\xA8", 0 }, { "zeta", "\xCE\xB6", 0 }, { "zfr", "\xF0\x9D\x94\xB7", 0 }, { "zhcy", "\xD0\xB6", 0 }, { "zigrarr", "\xE2\x87\x9D", 0 }, { "zopf", "\xF0\x9D\x95\xAB", 0 }, { "zscr", "\xF0\x9D\x93\x8F", 0 }, { "zwj", "\xE2\x80\x8D", 0 }, { "zwnj", "\xE2\x80\x8C", 0 }, }; /* End of temporary hack for RiskV */ #ifdef __riscv #pragma GCC pop_options #endif /*---------------------------------------------------------------------------- | ErInit -- | | Initialize the entity reference hash table | \---------------------------------------------------------------------------*/ static void ErInit (void) { size_t i; /* For looping through the list of entity references */ int h; /* The hash on a entity */ for(i=0; inodeType == ATTRIBUTE_NODE) { z = ((domAttrNode*)textOrAtt)->nodeValue; zlen = ((domAttrNode*)textOrAtt)->valueLength; } else { z = textOrAtt->nodeValue; zlen = textOrAtt->valueLength; } from = to = 0; if (bErNeedsInit) { TDomThreaded(Tcl_MutexLock(&initMutex);) if (bErNeedsInit) { ErInit(); bErNeedsInit = 0; } TDomThreaded(Tcl_MutexUnlock(&initMutex);) } while (z[from]) { if (z[from]=='&') { int isInvalid = 0; int i = from+1; int c; if (z[i] == '#') { /*--------------------------------------------- | convert character reference \--------------------------------------------*/ value = 0; if (z[++i] == 'x') { i++; while ((c=z[i]) && (c!=';')) { value = value * 16; if ((c>='0') && (c<='9')) { value += c-'0'; } else if ((c>='A') && (c<='F')) { value += c-'A' + 10; } else if ((c>='a') && (c<='f')) { value += c-'a' + 10; } else { /* error */ isInvalid = 1; break; } if (value > 2097152) { /* error */ isInvalid = 1; break; } i++; } } else { while ((c=z[i]) && (c!=';')) { value = value * 10; if ((c>='0') && (c<='9')) { value += c-'0'; } else { /* error */ isInvalid = 1; break; } if (value > 2097152) { /* error */ isInvalid = 1; break; } i++; } } if (z[i]!=';') { /* error */ isInvalid = 1; } if (isInvalid) { /* * In case the character reference was invalid * it was a false alaram, no valid character * reference, just copy the source chars; */ int j; for (j = from; j < i; j++) { z[to++] = z[j]; } from = i; } else { if (value < 0x80) { z[to++] = value; } else if (value <= 0x7FF) { z[to++] = (char) ((value >> 6) | 0xC0); z[to++] = (char) ((value | 0x80) & 0xBF); } else if (value <= 0xFFFF) { z[to++] = (char) ((value >> 12) | 0xE0); z[to++] = (char) (((value >> 6) | 0x80) & 0xBF); z[to++] = (char) ((value | 0x80) & 0xBF); } else { z[to++] = (char) ((value >> 18) | 0xf0); z[to++] = (char) (((value >> 12) & 0x3f) | 0x80); z[to++] = (char) (((value >> 6) & 0x3f) | 0x80); z[to++] = (char) ((value & 0x3f) | 0x80); } from = i+1; } } else { while (z[i] && isalnum((unsigned char)z[i])) { i++; } c = z[i]; z[i] = 0; h = ErHash(&z[from+1]); p = apErHash[h]; while (p && strcmp(p->zName,&z[from+1])!=0 ) { p = p->pNext; } ole = NULL; if (!p && c == ';') { /* Entity name not found. It may be one of the few * entities with a referenced UTF-8 byte sequence * which is longer than the reference. */ if (strcmp("nGt",&z[from+1]) == 0) { ole = "\xE2\x89\xAB\xE2\x83\x92\x00"; overlen = 1; } else if (strcmp("nLt",&z[from+1]) == 0) { ole = "\xE2\x89\xAA\xE2\x83\x92\x00"; overlen = 1; } } z[i] = c; if (p) { zVal = p->zValue; while (*zVal) { z[to++] = *(zVal++); } from = i; if (c==';') from++; } else { if (ole) { /* Over-long entity reference */ from = i; newNodeValue = MALLOC(zlen + 1 + overlen); memmove(newNodeValue,z,to); while (*ole) { newNodeValue[to++] = *(ole++); } memmove(newNodeValue + to, z + from + 1 , zlen - from); z = newNodeValue; zlen = zlen + overlen; if (textOrAtt->nodeType == ATTRIBUTE_NODE) { FREE (((domAttrNode*)textOrAtt)->nodeValue); ((domAttrNode*)textOrAtt)->nodeValue = z; ((domAttrNode*)textOrAtt)->valueLength = zlen; } else { FREE (textOrAtt->nodeValue); textOrAtt->nodeValue = z; textOrAtt->valueLength = zlen; } from = to; } else { z[to++] = z[from++]; } } } } else { z[to++] = z[from++]; } } z[to] = 0; if (textOrAtt->nodeType == ATTRIBUTE_NODE) { ((domAttrNode*)textOrAtt)->valueLength = to; } else { textOrAtt->valueLength = to; } } /*---------------------------------------------------------------------------- | End Of Character Entity Translator \---------------------------------------------------------------------------*/ DBG( /*---------------------------------------------------------------------------- | getDeep | \---------------------------------------------------------------------------*/ static int getDeep (domNode *n) { int d; d = 0; while (n->parentNode != NULL) { d++; n = n->parentNode; } return d; } ) /*---------------------------------------------------------------------------- | HTML_SimpleParse (non recursive) | | Parses the HTML string starting at 'pos' and continuing to the | first encountered error. | \---------------------------------------------------------------------------*/ static int HTML_SimpleParse ( char *html, /* HTML string */ domLength *pos, /* Index of next unparsed character in xml */ domDocument *doc, domNode *parent, int ignoreWhiteSpaces, int forest, char **errStr ) { register int c; /* Next character of the input file */ register char *pn, *e; register char *x, *start, *piSep; char savedChar; int hasContent; domNode *pnode; domNode *node = NULL, *parent_node = parent; domTextNode *tnode; domAttrNode *attrnode, *lastAttr; int ampersandSeen = 0; int only_whites = 0; int hnew, autoclose, ignore, maybeCustomName, rc; char tmp[250], *y = NULL; Tcl_HashEntry *h; domProcessingInstructionNode *pinode; x = &(html[*pos]); while ( (c=*x)!=0 ) { start = x; if ((c!='<') || ((c=='<') && (x[1]!='!') && (x[2]!='-') && (x[3]!='-') && (x[1]!='/') && !IsLetter(x[1])) ) { /*---------------------------------------------------------------- | read text between tags | \---------------------------------------------------------------*/ readText: ampersandSeen = 0; only_whites = 1; if (c=='<') x++; while ( (c=*x)!=0 && c!='<' ) { if (c=='&') ampersandSeen = 1; if ( !SPACE(c) ) only_whites = 0; x++; } if (!(only_whites && ignoreWhiteSpaces) && parent_node) { /*-------------------------------------------------------- | allocate new TEXT node \-------------------------------------------------------*/ tnode = (domTextNode*) domAlloc(sizeof(domTextNode)); memset(tnode, 0, sizeof(domTextNode)); tnode->nodeType = TEXT_NODE; tnode->ownerDocument = doc; tnode->nodeNumber = NODE_NO(doc); tnode->valueLength = (domLength)(x - start); tnode->nodeValue = (char*)MALLOC((x - start)+1); memmove(tnode->nodeValue, start, (x - start)); *(tnode->nodeValue + (x - start)) = 0; DBG(fprintf(stderr, "New text node: '%s'\n", tnode->nodeValue);) if (ampersandSeen) { TranslateEntityRefs (tnode); } tnode->parentNode = parent_node; if (parent_node->firstChild) { parent_node->lastChild->nextSibling = (domNode*)tnode; tnode->previousSibling = parent_node->lastChild; parent_node->lastChild = (domNode*)tnode; } else { parent_node->firstChild = parent_node->lastChild = (domNode*)tnode; } node = (domNode*)tnode; } } else if (x[1]=='/') { /*------------------------------------------------------------ | read and check closing tag \-----------------------------------------------------------*/ x += 2; while ((c=*x)!=0 && c!='>' && c!='<' && !SPACE(c) ) { *x = tolower(c); x++; } if (c==0) { RetError("Missing \">\"",(domLength)(start-html) ); } if ( (x-start)==2) { RetError("Null markup name",(domLength)(start-html) ); } *x = '\0'; /* temporarily terminate the string */ /*---------------------------------------------------------------------- | check for tags which could optional be close | like \---------------------------------------------------------------------*/ ignore = 0; pnode = NULL; if (parent_node) { if (parent_node->lastChild && (parent_node->lastChild->nodeType == ELEMENT_NODE)) { pnode = parent_node->lastChild; } else if (parent_node->lastChild && parent_node->lastChild->previousSibling && (parent_node->lastChild->previousSibling->nodeType == ELEMENT_NODE)) { pnode = parent_node->lastChild->previousSibling; } } if (pnode) { DBG(fprintf(stderr, "'%s' closing with last empty tag '%s' ?\n", start+2, pnode->nodeName);) if (strcmp(start+2,pnode->nodeName)==0) { switch (*(start+2)) { case 'o': if (!strcmp(start+2,"option")) ignore = 1; break; } } } if (!ignore) { /*---------------------------------------------------------------------- | look for a corresponding opening tag the way up the tag hierarchy \---------------------------------------------------------------------*/ pnode = parent_node; while (pnode != NULL) { DBG(fprintf(stderr, "checking '%s' to top hierarchy: '%s' \n", start+2,pnode->nodeName);) if (!strcmp(start+2,pnode->nodeName)) break; pnode = pnode->parentNode; } if (pnode == NULL) { /* beginning tag was not found the way up the tag hierarchy -> ignore the tag */ DBG(fprintf(stderr,"ignoring closing '%s' \n", start+2);) ignore = 1; } } if (!ignore) { pn = (char*)parent_node->nodeName; while (1) { DBG(fprintf(stderr, "comparing '%s' with pn='%s' \n", start+2, pn);) if (strcmp(start+2,pn)!=0) { /*---------------------------------------------------------- | check for parent tags which allow closing of sub tags | which belong to the parent tag \---------------------------------------------------------*/ ignore = 0; if (!strcmp(pn,"table") && (!strcmp(start+2,"tr") || !strcmp(start+2,"td")) ) { ignore = 1; } if (ignore) { parent_node = node->parentNode; break; } /*--------------------------------------------------------------- | check for tags for which end tag can be omitted \--------------------------------------------------------------*/ autoclose = 0; switch (pn[0]) { case 'a': if (!strcmp(pn,"a")) {autoclose = 1;} break; case 'b': if (!strcmp(pn,"b")) {autoclose = 1;} break; case 'c': if (!strcmp(pn,"colgroup")) {autoclose = 1;} break; case 'd': if (!strcmp(pn,"dd") || !strcmp(pn,"dt") || (!strcmp(start+2,"form") && !strcmp(pn,"div")) ) {autoclose = 1;} break; case 'h': if (!strcmp(pn,"head") || !strcmp(pn,"html")) {autoclose = 1;} break; case 'f': if (!strcmp(pn,"font")|| !strcmp(pn,"form")) {autoclose = 1;} break; case 'i': if (!strcmp(pn,"i")) {autoclose = 1;} break; case 'l': if (!strcmp(pn,"li")) {autoclose = 1;} break; case 'n': if (!strcmp(pn,"noscript")) {autoclose = 1;} break; case 'o': if (!strcmp(pn,"option")) {autoclose = 1;} break; case 'p': if (!strcmp(pn,"p")) {autoclose = 1;} break; case 's': if (!strcmp(pn,"span")) {autoclose = 1;} break; case 't': if (!strcmp(pn,"tbody") || !strcmp(pn,"td") || !strcmp(pn,"tfoot") || !strcmp(pn,"thead") || !strcmp(pn,"th") || !strcmp(pn,"tr") || !strcmp(pn,"tt")) {autoclose = 1;} break; case 'u': if (!strcmp(pn,"ul")) {autoclose = 1;} break; /* ext */ } /*--------------------------------------------------------------- | check for tags for close inner tags \--------------------------------------------------------------*/ switch (start[2]) { case 'b': if (!strcmp(start+2,"body")) autoclose = 1; break; } if (autoclose) { DBG(fprintf(stderr, "autoclose '%s' with '%s' \n", pn, start+2);) if (parent_node != NULL) { node = parent_node; parent_node = node->parentNode; break; } } sprintf(tmp, "Unterminated element '%s' (within '%s')", start+2, pn); *x = c; /* remove temporarily termination */ RetError(tmp,(domLength)(x - html)); } break; } /* move up */ node = parent_node; parent_node = NULL; if (node) parent_node = node->parentNode; } *x = c; /* remove temporarily termination */ while (SPACE(*x)) { x++; } if (*x=='>') { x++; } else { if (*x == '<') { /* start of new tag, ends closing tag */ } else { RetError("Missing \">\"",(domLength)(x - html)-1); } } if (parent_node == NULL) { /* we return to main node and so finished parsing */ return TCL_OK; } continue; } else { x++; if (*x=='!') { if (x[1]=='-' && x[2]=='-') { /*-------------------------------------------------------- | read over a comment \-------------------------------------------------------*/ x += 3; while ( (c=*x)!=0 && (c!='-' || x[1]!='-' || x[2]!='>')) { x++; } if (*x) { /*---------------------------------------------------- | allocate new COMMENT node for comments \---------------------------------------------------*/ tnode = (domTextNode*) domAlloc(sizeof(domTextNode)); memset(tnode, 0, sizeof(domTextNode)); tnode->nodeType = COMMENT_NODE; tnode->ownerDocument = doc; tnode->nodeNumber = NODE_NO(doc); tnode->parentNode = parent_node; tnode->valueLength = (domLength)(x - start - 4); tnode->nodeValue = (char*)MALLOC(tnode->valueLength+1); memmove(tnode->nodeValue, start+4, tnode->valueLength); *(tnode->nodeValue + tnode->valueLength) = 0; if (parent_node == NULL) { if (doc->rootNode->lastChild) { tnode->previousSibling = doc->rootNode->lastChild; doc->rootNode->lastChild->nextSibling = (domNode *) tnode; } else { doc->rootNode->firstChild = (domNode*) tnode; } doc->rootNode->lastChild = (domNode*) tnode; } else { if (parent_node->firstChild) { parent_node->lastChild->nextSibling = (domNode*)tnode; tnode->previousSibling = parent_node->lastChild; parent_node->lastChild = (domNode*)tnode; } else { parent_node->firstChild = parent_node->lastChild = (domNode*)tnode; } } x += 3; } else { RetError("Unterminated comment",(domLength)(start-html)); } continue; } else if (TU(x[1])=='D' && TU(x[2])=='O' && TU(x[3])=='C' && TU(x[4])=='T' && TU(x[5])=='Y' && TU(x[6])=='P' && TU(x[7])=='E' ) { /*-------------------------------------------------------- | read over a DOCTYPE definition \-------------------------------------------------------*/ x += 8; start = x; while (*x!=0) { if (*x=='[') { x++; while ((*x!=0) && (*x!=']')) x++; } else if (*x=='>') { break; } else { x++; } } if (*x) { x++; } else { RetError("Unterminated DOCTYPE definition",(domLength)(start-html)); } continue; } else if (x[1]=='[' && x[2]=='C' && x[3]=='D' && x[4]=='A' && x[5]=='T' && x[6]=='A' && x[7]=='[' ) { /*-------------------------------------------------------- | read over a '))) { x++; } if (*x) { if (parent_node) { /*---------------------------------------------------- | allocate new TEXT node for CDATA section data \---------------------------------------------------*/ tnode = (domTextNode*) domAlloc(sizeof(domTextNode)); memset(tnode, 0, sizeof(domTextNode)); tnode->nodeType = TEXT_NODE; tnode->ownerDocument = doc; tnode->nodeNumber = NODE_NO(doc); tnode->parentNode = parent_node; tnode->valueLength = (domLength)(x - start); tnode->nodeValue = (char*)MALLOC((x - start)+1); memmove(tnode->nodeValue, start, (x - start)); *(tnode->nodeValue + (x - start)) = 0; if (parent_node->firstChild) { parent_node->lastChild->nextSibling = (domNode*)tnode; tnode->previousSibling = parent_node->lastChild; parent_node->lastChild = (domNode*)tnode; } else { parent_node->firstChild = parent_node->lastChild = (domNode*)tnode; } } x += 3; } else { RetError("Unterminated CDATA definition",(domLength)(start-html) ); } continue; } else { RetError("Incorrect ')) { x++; } if (*x) { /*------------------------------------------------------------ | allocate new PI node for processing instruction section \-----------------------------------------------------------*/ pinode = (domProcessingInstructionNode*) MALLOC(sizeof(domProcessingInstructionNode)); memset(pinode, 0, sizeof(domProcessingInstructionNode)); pinode->nodeType = PROCESSING_INSTRUCTION_NODE; pinode->ownerDocument = doc; pinode->nodeNumber = NODE_NO(doc); pinode->parentNode = parent_node; /*------------------------------------------------- | extract PI target \------------------------------------------------*/ piSep = start; while ( (c=*piSep)!=0 && !SPACE(c) && (c!='?' || piSep[1]!='>')) { piSep++; } *piSep = '\0'; /* temporarily terminate the string */ pinode->targetLength = (domLength)strlen(start); pinode->targetValue = (char*)MALLOC(pinode->targetLength); memmove(pinode->targetValue, start, pinode->targetLength); *piSep = c; /* remove temporarily termination */ /*------------------------------------------------- | extract PI data \------------------------------------------------*/ while (SPACE(*piSep)) { piSep++; } pinode->dataLength = (domLength)(x - piSep); pinode->dataValue = (char*)MALLOC(pinode->dataLength); memmove(pinode->dataValue, piSep, pinode->dataLength); if (parent_node == NULL) { if (doc->rootNode->lastChild) { pinode->previousSibling = doc->rootNode->lastChild; doc->rootNode->lastChild->nextSibling = (domNode*) pinode; } else { doc->rootNode->firstChild = (domNode*) pinode; } doc->rootNode->lastChild = (domNode*) pinode; } else { if (parent_node->firstChild) { parent_node->lastChild->nextSibling = (domNode*)pinode; pinode->previousSibling = parent_node->lastChild; parent_node->lastChild = (domNode*)pinode; } else { parent_node->firstChild = parent_node->lastChild = (domNode*)pinode; } } x += 2; } else { RetError("Unterminated processing instruction(PI)",(domLength)(start-html)); } continue; } /*---------------------------------------------------------------- | new tag/element | \---------------------------------------------------------------*/ maybeCustomName = 0; while ((c=*x)!=0 && c!='/' && c!='>' && c!='<' && !SPACE(c) ) { if (!maybeCustomName && !isalnum(c)) maybeCustomName = 1; x++; } if (!maybeCustomName) { c = *x; *x = '\0'; /* temporarily terminate the string */ x = start + 1; while (*x) { *x = tolower(*x); x++; } *x = c; } else { c = *x; *x = '\0'; /* temporarily terminate the string */ rc = domIsHTML5CustomName (start+1); *x = c; if (!rc) { goto readText; } } hasContent = 1; if (c==0) { RetError("Missing \">\"",(domLength)(start-html)); } if ( (x-start)==1) { RetError("Null markup name",(domLength)(start-html)); } DBG(fprintf(stderr, "\nnew tag '%70.70s...' \n", start);) *x = '\0'; /* temporarily terminate the string */ /*----------------------------------------------------------- | check, whether new starting element close another | currently open one \----------------------------------------------------------*/ e = start+1; pn = ""; if (parent_node) { pn = (char*)parent_node->nodeName; } autoclose = 0; switch (*e) { case 'a': if(!strcmp(e,"a")&&!strcmp(pn,"a")) autoclose=1; break; case 'b': if(!strcmp(e,"b")&&!strcmp(pn,"b")) autoclose=1; break; case 'o': if (!strcmp(e,"option")&&!strcmp(pn,"option")) autoclose = 1; break; case 'p': if((!strcmp(e,"pre")&&!strcmp(pn,"pre")) ||(!strcmp(e,"p")&&!strcmp(pn,"p"))) autoclose=1; break; } if (autoclose) { DBG(fprintf(stderr, "autoclose '%s' because of new '%s' \n", pn, e);) node = parent_node; parent_node = node->parentNode; } /*----------------------------------------------------------- | create new DOM element node \----------------------------------------------------------*/ if (!parent_node && (strcmp(e,"html")!=0)) { // Insert missing html tag h = Tcl_CreateHashEntry(&HASHTAB(doc,tdom_tagNames), "html", &hnew); node = (domNode*) domAlloc(sizeof(domNode)); memset(node, 0, sizeof(domNode)); node->nodeType = ELEMENT_NODE; node->nodeName = (char *)&(h->key); node->ownerDocument = doc; node->nodeNumber = NODE_NO(doc); if (doc->rootNode->lastChild) { node->previousSibling = doc->rootNode->lastChild; doc->rootNode->lastChild->nextSibling = node; } else { doc->rootNode->firstChild = node; } doc->rootNode->lastChild = node; parent_node = node; DBG(fprintf(stderr, "%d: Inserted missing tag '%s' hasContent=%d nodeNumber=%d\n", getDeep(node), node->nodeName, hasContent, node->nodeNumber);) } h = Tcl_CreateHashEntry(&HASHTAB(doc,tdom_tagNames), e, &hnew); node = (domNode*) domAlloc(sizeof(domNode)); memset(node, 0, sizeof(domNode)); node->nodeType = ELEMENT_NODE; node->nodeName = (char *)&(h->key); node->ownerDocument = doc; node->nodeNumber = NODE_NO(doc); if (parent_node == NULL) { if (doc->rootNode->lastChild) { node->previousSibling = doc->rootNode->lastChild; doc->rootNode->lastChild->nextSibling = node; } else { doc->rootNode->firstChild = node; } doc->rootNode->lastChild = node; } else { node->parentNode = parent_node; if (parent_node->firstChild) { parent_node->lastChild->nextSibling = node; node->previousSibling = parent_node->lastChild; parent_node->lastChild = node; } else { parent_node->firstChild = parent_node->lastChild = node; } } *x = c; /* remove temporarily termination */ while (SPACE(*x) ) { x++; } /*----------------------------------------------------------- | read attribute name-value pairs \----------------------------------------------------------*/ lastAttr = NULL; while ( (c=*x) && (c!='/') && (c!='>') && (c!='<') ) { char *ArgName = x; domLength nArgName; char *ArgVal = NULL; domLength nArgVal = 0; while ((c=*x)!=0 && c!='=' && c!='>' && !SPACE(c) ) { *x = tolower(c); x++; } nArgName = (domLength)(x - ArgName); while (SPACE(*x)) { x++; } if (*x == '=') { /* attribute with value, like width="1234" */ x++; while (SPACE(*x)) { x++; } savedChar = *(ArgName + nArgName); *(ArgName + nArgName) = '\0'; /* terminate arg name */ if (*x=='>' || *x==0) { ArgVal = ArgName; nArgVal = nArgName; } else if ((c=*x)=='\"' || c=='\'') { register int cDelim = c; x++; ArgVal = x; ampersandSeen = 0; while ((c=*x)!=0 && c!=cDelim) { if (c=='&') ampersandSeen = 1; x++; } nArgVal = (domLength)(x - ArgVal); if (c==0) { RetError("Unterminated string",(domLength)(ArgVal - html - 1)); } else { x++; } } else if (c!=0 && c!='>') { ArgVal = x; while ((c=*x)!=0 && c!='>' && !SPACE(c)) { if (c=='&') ampersandSeen = 1; x++; } if (c==0) { RetError("Missing \">\"",(domLength)(start-html)); } nArgVal = (domLength)(x - ArgVal); } } else { /* attribute without value, like 'nowrap' */ savedChar = *(ArgName + nArgName); *(ArgName + nArgName) = '\0'; /* terminate arg name */ ArgVal = ArgName; nArgVal = nArgName; } /*-------------------------------------------------- | allocate new attribute node \--------------------------------------------------*/ h = Tcl_CreateHashEntry(&HASHTAB(doc,tdom_attrNames), ArgName, &hnew); attrnode = (domAttrNode*) domAlloc(sizeof(domAttrNode)); memset(attrnode, 0, sizeof(domAttrNode)); attrnode->parentNode = node; attrnode->nodeName = (char *)&(h->key); attrnode->nodeType = ATTRIBUTE_NODE; attrnode->nodeValue = (char*)MALLOC(nArgVal+1); attrnode->valueLength = nArgVal; memmove(attrnode->nodeValue, ArgVal, nArgVal); *(attrnode->nodeValue + nArgVal) = 0; if (ampersandSeen) { TranslateEntityRefs ((domTextNode*)attrnode); } if (!strcmp(ArgName, "id")) { if (!doc->ids) { doc->ids = (Tcl_HashTable *) MALLOC (sizeof (Tcl_HashTable)); Tcl_InitHashTable (doc->ids, TCL_STRING_KEYS); } h = Tcl_CreateHashEntry (doc->ids, attrnode->nodeValue, &hnew); /* How to resolve in case of duplicates? We follow, what the core dom building code does: the first value in document order wins. */ if (hnew) { Tcl_SetHashValue (h, node); attrnode->nodeFlags |= IS_ID_ATTRIBUTE; } } if (node->firstAttr) { lastAttr->nextSibling = attrnode; } else { node->firstAttr = attrnode; } lastAttr = attrnode; *(ArgName + nArgName) = savedChar; while (SPACE(*x)) { x++; } } /*----------------------------------------------------------- | check for empty HTML tags \----------------------------------------------------------*/ switch (node->nodeName[0]) { case 'a': if (!strcmp(node->nodeName,"area")) {hasContent = 0;} break; case 'b': if (!strcmp(node->nodeName,"br") || !strcmp(node->nodeName,"base") || !strcmp(node->nodeName,"basefont")) {hasContent = 0;} break; case 'c': if (!strcmp(node->nodeName,"col")) {hasContent = 0;} break; case 'e': if (!strcmp(node->nodeName,"embed")) {hasContent = 0;} break; case 'f': if (!strcmp(node->nodeName,"frame")) {hasContent = 0;} break; case 'h': if (!strcmp(node->nodeName,"hr")) {hasContent = 0;} break; case 'i': if (!strcmp(node->nodeName,"img") || !strcmp(node->nodeName,"input") || !strcmp(node->nodeName,"isindex")) {hasContent = 0;} break; case 'l': if (!strcmp(node->nodeName,"link")) {hasContent = 0;} break; case 'm': if (!strcmp(node->nodeName,"meta")) {hasContent = 0;} break; case 'p': if (!strcmp(node->nodeName,"param")) {hasContent = 0;} break; case 's': if (!strcmp(node->nodeName,"spacer") || !strcmp(node->nodeName,"source")) {hasContent = 0;} break; /*html5*/ } if (*x=='/') { hasContent = 0; x++; if (*x!='>') { RetError("Syntax Error",(domLength)(x - html - 1)); } } if (*x=='>') { x++; } DBG(fprintf(stderr, "%d: new node '%s' hasContent=%d \n", getDeep(node), node->nodeName, hasContent);) if ((strcmp(node->nodeName,"style" )==0) || (strcmp(node->nodeName,"script")==0) ) { /*----------------------------------------------------------- | read over any data within a 'style' or 'script' tag \----------------------------------------------------------*/ hasContent = 1; start = x; while (1) { while ( (*x!=0) && ((*x!='<') || (x[1]!='/'))) { x++; } if (!*x) break; y = x + 2; while (*y!=0 && SPACE(*y)) y++; if (TU(y[0]) == 'S' && TU(y[1]) == 'C' && TU(y[2]) == 'R' && TU(y[3]) == 'I' && TU(y[4]) == 'P' && TU(y[5]) == 'T' ) break; if (TU(y[0]) == 'S' && TU(y[1]) == 'T' && TU(y[2]) == 'Y' && TU(y[3]) == 'L' && TU(y[4]) == 'E' ) break; x++; } if (*x) { /*---------------------------------------------------- | allocate new TEXT node for style/script data \---------------------------------------------------*/ tnode = (domTextNode*) domAlloc(sizeof(domTextNode)); memset(tnode, 0, sizeof(domTextNode)); tnode->nodeType = TEXT_NODE; tnode->ownerDocument = doc; tnode->nodeNumber = NODE_NO(doc); tnode->parentNode = node; tnode->valueLength = (domLength)(x - start); tnode->nodeValue = (char*)MALLOC((x - start)+1); memmove(tnode->nodeValue, start, (x - start)); *(tnode->nodeValue + (x - start)) = 0; if (node->firstChild) { node->lastChild->nextSibling = (domNode*)tnode; tnode->previousSibling = node->lastChild; node->lastChild = (domNode*)tnode; } else { node->firstChild = node->lastChild = (domNode*)tnode; } } } if (hasContent) { /*------------------------------------------------------------ | recurs to read child tags/texts \-----------------------------------------------------------*/ parent_node = node; } DBG(fprintf(stderr, "%d: after node '%s' \n", getDeep(node), node->nodeName);) } } while (parent_node != NULL && node->parentNode) { pn = (char*)node->parentNode->nodeName; DBG(fprintf(stderr, "final autoclose '%s'? \n", pn);) /*--------------------------------------------------------------- | check for tags for which end tag can be omitted \--------------------------------------------------------------*/ autoclose = 0; switch (pn[0]) { case 'b': if (!strcmp(pn,"body")) {autoclose = 1;} break; case 'c': if (!strcmp(pn,"colgroup")) {autoclose = 1;} break; case 'd': if (!strcmp(pn,"dd") || !strcmp(pn,"dt")) {autoclose = 1;} break; case 'h': if (!strcmp(pn,"head") || !strcmp(pn,"html")) {autoclose = 1;} break; case 'l': if (!strcmp(pn,"li")) {autoclose = 1;} break; case 'o': if (!strcmp(pn,"option")) {autoclose = 1;} break; case 'p': if (!strcmp(pn,"p")) {autoclose = 1;} break; case 't': if (!strcmp(pn,"tbody") || !strcmp(pn,"td") || !strcmp(pn,"tfoot") || !strcmp(pn,"thead") || !strcmp(pn,"th") || !strcmp(pn,"tr")) {autoclose = 1;} break; case 'u': if (!strcmp(pn,"ul")) {autoclose = 1;} break; /* ext */ } if (!autoclose) break; DBG(fprintf(stderr, "final autoclosed '%s'! \n", pn);) node = node->parentNode; parent_node = node->parentNode; } if (parent_node == NULL) { /* we return to main node and so finished parsing */ return TCL_OK; } if (forest && parent_node == parent) { return TCL_OK; } RetError("Unexpected end",(domLength)(x - html)); } /* HTML_SimpleParse */ /*---------------------------------------------------------------------------- | HTML_SimpleParseDocument | | Create a document, parses the HTML string starting at 'pos' and | continuing to the first encountered error. | \---------------------------------------------------------------------------*/ domDocument * HTML_SimpleParseDocument ( char *html, /* Complete text of the file being parsed */ int ignoreWhiteSpaces, int forest, domLength *pos, char **errStr ) { domDocument *doc = domCreateDoc(NULL, 0); domNode *save, *node = NULL; Tcl_HashEntry *h; int hnew; if (forest) { // Create umbrella tag h = Tcl_CreateHashEntry(&HASHTAB(doc,tdom_tagNames), "forestroot", &hnew); node = (domNode*) domAlloc(sizeof(domNode)); memset(node, 0, sizeof(domNode)); node->nodeType = ELEMENT_NODE; node->nodeName = (char *)&(h->key); node->ownerDocument = doc; doc->rootNode->firstChild = node; doc->rootNode->lastChild = node; } *pos = 0; HTML_SimpleParse (html, pos, doc, node, ignoreWhiteSpaces, forest, errStr); if (forest) { doc->rootNode->firstChild = node->firstChild; doc->rootNode->lastChild = node->lastChild; save = node; for (node = doc->rootNode->firstChild; node != NULL; node = node->nextSibling) { node->parentNode = NULL; } domFree ((void*)save); } domSetDocumentElement (doc); return doc; } /* HTML_SimpleParseDocument */ tdom-0.9.6-src/generic/tclexpat.h0000644000175000017500000002054615025767703015400 0ustar rolfrolf #ifndef __TCL_EXPAT_H__ #define __TCL_EXPAT_H__ #include #include #include "dom.h" #include "schema.h" struct TclGenExpatInfo; typedef void (*CHandlerSet_userDataReset)(Tcl_Interp *interp, void *userData); typedef void (*CHandlerSet_userDataFree)(Tcl_Interp *interp, void *userData); typedef void (*CHandlerSet_parserReset)(XML_Parser parser, void *userData); typedef void (*CHandlerSet_initParse)(Tcl_Interp *interp, void *userData); typedef void(XMLCALL *tdom_CharacterDataHandler)(void *userData, const XML_Char *s, domLength len); typedef struct CHandlerSet { struct CHandlerSet *nextHandlerSet; char *name; /* refname of the handler set */ int ignoreWhiteCDATAs; /* ignore 'white' CDATA sections */ void *userData; /* Handler set specific Data Structure; the C handler set extension has to malloc the needed structure in his init func and has to provide a cleanup func (to free it). */ CHandlerSet_userDataReset resetProc; CHandlerSet_userDataFree freeProc; CHandlerSet_parserReset parserResetProc; CHandlerSet_initParse initParseProc; /* C func for element start */ XML_StartElementHandler elementstartcommand; /* C func for element end */ XML_EndElementHandler elementendcommand; /* C func for character data */ tdom_CharacterDataHandler datacommand; /* C func for namespace decl start */ XML_StartNamespaceDeclHandler startnsdeclcommand; /* C func for namespace decl end */ XML_EndNamespaceDeclHandler endnsdeclcommand; /* C func for processing instruction */ XML_ProcessingInstructionHandler picommand; /* C func for default data */ XML_DefaultHandler defaultcommand; /* C func for unparsed entity declaration */ XML_NotationDeclHandler notationcommand; /* C func for external entity */ XML_ExternalEntityRefHandler externalentitycommand; /* C func for unknown encoding */ XML_UnknownEncodingHandler unknownencodingcommand; /* C func for comments */ XML_CommentHandler commentCommand; /* C func for "not standalone" docs */ XML_NotStandaloneHandler notStandaloneCommand; /* C func for CDATA section start */ XML_StartCdataSectionHandler startCdataSectionCommand; /* C func for CDATA section end */ XML_EndCdataSectionHandler endCdataSectionCommand; /* C func for #include #include #include #include /* #define DEBUG */ /*---------------------------------------------------------------------------- | Debug Macros | \---------------------------------------------------------------------------*/ #ifdef DEBUG # define DBG(x) x #else # define DBG(x) #endif #define MutationEvent() #define MutationEvent2(type,node) #define MutationEvent3(type,node,relatioNode) #define MCHK(a) if ((a)==NULL) { \ fprintf(stderr, \ "Memory alloc error line: %d",__LINE__); \ exit(1); \ } #define INITIAL_BASEURISTACK_SIZE 4; /*--------------------------------------------------------------------------- | Globals | In threading environment, some are located in domDocument structure | and some are handled differently (domUniqueNodeNr, domUniqueDocNr) | \--------------------------------------------------------------------------*/ #ifndef TCL_THREADS unsigned long domUniqueNodeNr = 0; unsigned long domUniqueDocNr = 0; Tcl_HashTable tdom_tagNames; Tcl_HashTable tdom_attrNames; #endif static int domModuleIsInitialized = 0; TDomThreaded(static Tcl_Mutex initMutex;) static const char *domException2StringTable [] = { "OK - no exception", "INDEX_SIZE_ERR", "DOMSTRING_SIZE_ERR", "HIERARCHY_REQUEST_ERR", "WRONG_DOCUMENT_ERR", "INVALID_CHARACTER_ERR", "NO_DATA_ALLOWED_ERR", "NO_MODIFICATION_ALLOWED_ERR", "NOT_FOUND_ERR", "NOT_SUPPORTED_ERR", "INUSE_ATTRIBUTE_ERR" }; static char tdom_usage[] = "Usage tdom , where subCommand can be:\n" " enable \n" " getdoc \n" " setStoreLineColumn \n" ; /*--------------------------------------------------------------------------- | type domBaseURIstackElem | \--------------------------------------------------------------------------*/ typedef struct _domActiveBaseURI { int depth; const char *baseURI; } domActiveBaseURI; /*--------------------------------------------------------------------------- | type domReadInfo | \--------------------------------------------------------------------------*/ /* Keep in sync with tdomCmdReadInfo below */ typedef struct _domReadInfo { XML_Parser parser; domDocument *document; domNode *currentNode; int depth; int ignoreWhiteSpaces; int cdataSection; Tcl_DString *cdata; int storeLineColumn; domLength textStartLine; domLength textStartColumn; domLength textStartByteIndex; int ignorexmlns; int feedbackAfter; Tcl_Obj *feedbackCmd; XML_Index nextFeedbackPosition; Tcl_Interp *interp; int activeNSsize; int activeNSpos; domActiveNS *activeNS; int baseURIstackSize; int baseURIstackPos; domActiveBaseURI *baseURIstack; int insideDTD; #ifndef TDOM_NO_SCHEMA SchemaData *sdata; #endif int status; } domReadInfo; /*---------------------------------------------------------------------------- | Prototypes | \---------------------------------------------------------------------------*/ static void DispatchPCDATA (domReadInfo *info); #ifndef TCL_THREADS /*--------------------------------------------------------------------------- | domModuleFinalize | \--------------------------------------------------------------------------*/ static void domModuleFinalize(ClientData unused) { Tcl_HashEntry *entryPtr; Tcl_HashSearch search; entryPtr = Tcl_FirstHashEntry(&tdom_tagNames, &search); while (entryPtr) { Tcl_DeleteHashEntry(entryPtr); entryPtr = Tcl_NextHashEntry(&search); } Tcl_DeleteHashTable(&tdom_tagNames); entryPtr = Tcl_FirstHashEntry(&tdom_attrNames, &search); while (entryPtr) { Tcl_DeleteHashEntry(entryPtr); entryPtr = Tcl_NextHashEntry(&search); } Tcl_DeleteHashTable(&tdom_attrNames); return; } #endif /* TCL_THREADS */ /*--------------------------------------------------------------------------- | domModuleInitialize | \--------------------------------------------------------------------------*/ void domModuleInitialize ( ) { if (domModuleIsInitialized == 0) { TDomThreaded(Tcl_MutexLock(&initMutex);) if (domModuleIsInitialized == 0) { domAllocInit(); TDomNotThreaded ( Tcl_InitHashTable(&tdom_tagNames, TCL_STRING_KEYS); Tcl_InitHashTable(&tdom_attrNames, TCL_STRING_KEYS); Tcl_CreateExitHandler(domModuleFinalize, NULL); ) TDomThreaded( Tcl_CreateExitHandler(domLocksFinalize, NULL); ) domModuleIsInitialized = 1; } TDomThreaded(Tcl_MutexUnlock(&initMutex);) } } /*--------------------------------------------------------------------------- | coercion routines for calling from C++ | \--------------------------------------------------------------------------*/ domAttrNode * coerceToAttrNode( domNode *n ) { return (domAttrNode *)n; } domTextNode * coerceToTextNode( domNode *n ) { return (domTextNode *)n; } domProcessingInstructionNode * coerceToProcessingInstructionNode( domNode *n ) { return (domProcessingInstructionNode *)n; } /*--------------------------------------------------------------------------- | domIsNAME | \--------------------------------------------------------------------------*/ int domIsNAME ( const char *name ) { const char *p; p = name; if (!isNameStart(p)) return 0; p += UTF8_CHAR_LEN(*p); while (*p) { if (isNameChar(p)) p += UTF8_CHAR_LEN(*p); else return 0; } return 1; } /*--------------------------------------------------------------------------- | domIsPINAME | \--------------------------------------------------------------------------*/ int domIsPINAME ( const char *name ) { if (strlen (name) == 3 && ((name[0] == 'x') || (name[0] == 'X')) && ((name[1] == 'm') || (name[1] == 'M')) && ((name[2] == 'l') || (name[2] == 'L')) ) { return 0; } return domIsNAME (name); } /*--------------------------------------------------------------------------- | domIsQNAME | \--------------------------------------------------------------------------*/ int domIsQNAME ( const char *name ) { const char *p; p = name; if (!isNCNameStart(p)) return 0; p += UTF8_CHAR_LEN(*p); while (*p) { if (isNCNameChar(p)) p += UTF8_CHAR_LEN(*p); else { if (*p == ':') { p += 1; if (!isNCNameStart(p)) return 0; p += UTF8_CHAR_LEN(*p); break; } else return 0; } } while (*p) { if (isNCNameChar(p)) p += UTF8_CHAR_LEN(*p); else return 0; } return 1; } /*--------------------------------------------------------------------------- | domIsNCNAME | \--------------------------------------------------------------------------*/ int domIsNCNAME ( const char *name ) { const char *p; p = name; if (!isNCNameStart(p)) return 0; p += UTF8_CHAR_LEN(*p); while (*p) { if (isNCNameChar(p)) p += UTF8_CHAR_LEN(*p); else return 0; } return 1; } /*--------------------------------------------------------------------------- | domIsChar | \--------------------------------------------------------------------------*/ int domIsChar ( const char *str ) { const char *p; int clen; p = str; while (*p) { clen = UTF8_CHAR_LEN(*p); if (!clen) return 0; if (UTF8_XMLCHAR((unsigned const char *)p,clen)) p += clen; else return 0; } return 1; } /*--------------------------------------------------------------------------- | domIsHTML5CustomName | \--------------------------------------------------------------------------*/ int domIsHTML5CustomName ( const char *str ) { const char *p; domLength clen; int dashseen = 0; Tcl_UniChar uniChar; p = str; if (*p < 'a' || *p > 'z') { return 0; } p++; while (*p) { clen = UTF8_CHAR_LEN(*p); if (clen == 0) return 0; if (clen == 1) { if (*p == '-') { dashseen = 1; p++; } else { if (*p == '.' || (*p >= '0' && *p <= '9') || *p == '_' || (*p >= 'a' && *p <= 'z')) { p++; } else { return 0; } } continue; } if (clen == 4) { p += clen; continue; } clen = Tcl_UtfToUniChar (p, &uniChar); if (uniChar == 0xB7 || (uniChar >= 0xC0 && uniChar <= 0xD6) || (uniChar >= 0xD8 && uniChar <= 0xF6) || (uniChar >= 0xF8 && uniChar <= 0x37D) || (uniChar >= 0x37F && uniChar <= 0x1FFF) || (uniChar >= 0x200C && uniChar <= 0x200D) || (uniChar >= 0x203F && uniChar <= 0x2040) || (uniChar >= 0x2070 && uniChar <= 0x218F) || (uniChar >= 0x2C00 && uniChar <= 0x2FEF) || (uniChar >= 0x3001 && uniChar <= 0xD7FF) || (uniChar >= 0xF900 && uniChar <= 0xFDCF) || (uniChar >= 0xFDF0 && uniChar <= 0xFFFD)) { p += clen; } else { return 0; } } if (!dashseen) return 0; switch (str[0]) { case 'a': if (!strcmp(str,"annotation-xml")) {return 0;} break; case 'c': if (!strcmp(str,"color-profile")) {return 0;} break; case 'f': if (!strcmp(str,"font-face") || !strcmp(str,"font-face-src") || !strcmp(str,"font-face-uri") || !strcmp(str,"font-face-format") || !strcmp(str,"font-face-name")) {return 0;} break; case 'm': if (!strcmp(str,"missing-glyph")) {return 0;} break; } return 1; } /*--------------------------------------------------------------------------- | domClearString | \--------------------------------------------------------------------------*/ void domClearString ( char *str, char *replacement, domLength repllen, Tcl_DString *clearedstr, int *changed ) { char *p, *s; int clen; *changed = 0; p = str; while (*p) { clen = UTF8_CHAR_LEN(*p); if (!clen || !UTF8_XMLCHAR((unsigned const char*)p,clen)) { *changed = 1; Tcl_DStringInit (clearedstr); break; } p += clen; } if (!*changed) { return; } Tcl_DStringAppend (clearedstr, str, (domLength)(p-str)); if (repllen) { Tcl_DStringAppend (clearedstr, replacement, repllen); } if (clen) { p += clen; } else { /* If it isn't a UTF-8 encoded character what is it? And how * many of whatever it is? */ p++; } s = p; while (*p) { clen = UTF8_CHAR_LEN(*p); if (!clen || !UTF8_XMLCHAR((unsigned const char*)p,clen)) { Tcl_DStringAppend (clearedstr, s, (domLength)(p-s)); if (repllen) { Tcl_DStringAppend (clearedstr, replacement, repllen); } if (clen) { p += clen; } else { p++; } s = p; } else { p += clen; } } Tcl_DStringAppend (clearedstr, s, (domLength)(p-s)); } /*--------------------------------------------------------------------------- | domIsBMPChar | \--------------------------------------------------------------------------*/ int domIsBMPChar ( const char *str ) { const char *p; int clen; p = str; while (*p) { clen = UTF8_CHAR_LEN(*p); if (clen > 3 || clen == 0) return 0; p += clen; } return 1; } /*--------------------------------------------------------------------------- | domIsComment | \--------------------------------------------------------------------------*/ int domIsComment ( const char *str ) { const char *p; domLength len, i = 0; p = str; len = (domLength)strlen (str); while (i < len) { if (*p == '-') { if (i == len - 1) return 0; p++; i++; if (*p == '-') return 0; } p++; i++; } return domIsChar (str); } /*--------------------------------------------------------------------------- | domIsCDATA | \--------------------------------------------------------------------------*/ int domIsCDATA ( const char *str ) { const char *p; domLength len, i = 0; p = str; len = (domLength)strlen (str); while (i < len - 2) { if ( *p == ']' && p[1] == ']' && p[2] == '>') return 0; p++; i++; } return domIsChar (str); } /*--------------------------------------------------------------------------- | domIsPIValue | \--------------------------------------------------------------------------*/ int domIsPIValue ( const char *str ) { const char *p; domLength len, i = 0; p = str; len = (domLength)strlen (str); while (i < len - 1) { if (*p == '?' && p[1] == '>') return 0; p++; i++; } return domIsChar (str); } /*--------------------------------------------------------------------------- | domLookupNamespace | \--------------------------------------------------------------------------*/ domNS * domLookupNamespace ( domDocument *doc, const char *prefix, const char *namespaceURI ) { domNS *ns; int i; if (prefix==NULL) return NULL; for (i = 0; i <= doc->nsptr; i++) { ns = doc->namespaces[i]; if ( (ns->prefix != NULL) && (strcmp(prefix,ns->prefix)==0) && (strcmp(namespaceURI, ns->uri)==0) ) { return ns; } } return NULL; } /* *---------------------------------------------------------------------- * * domPrecedes -- * * This helper procedure returns if node precedes other with regard * to their position in the document and according to the document * order. The two nodes could be out of the two documents. Both * nodes must not be out of the fragments list. * * Results: * 1 if node precedes other in document order, 0 otherwise. * * Side effects: * None. * *---------------------------------------------------------------------- */ int domPrecedes ( domNode *node, domNode *other ) { domNode *nodeAncestor, *otherAncestor; domAttrNode *attrN, *attrO; if (node == other) { return 0; } if (node->nodeType == ATTRIBUTE_NODE) { attrN = (domAttrNode*)node; if (other->nodeType == ATTRIBUTE_NODE) { attrO = (domAttrNode*)other; if (attrN->parentNode == attrO->parentNode) { attrN = attrN->nextSibling; while (attrN) { if (attrN == attrO) { return 1; } attrN = attrN->nextSibling; } return 0; } else { node = attrN->parentNode; other = attrO->parentNode; } } else { if (attrN->parentNode == other) { return 0; } else { node = attrN->parentNode; } } } if (other->nodeType == ATTRIBUTE_NODE) { attrO = (domAttrNode*)other; if (node == attrO->parentNode) { return 1; } else { other = attrO->parentNode; } } if (node->ownerDocument != other->ownerDocument) { /* For mt tdom, this does not, what it should: whatever relative order two nodes out of different documents ever have (that is not determined by the rec) it must return always the same order (that is required by the rec). */ return (node->ownerDocument->documentNumber < other->ownerDocument->documentNumber); } #ifndef TCL_THREADS if (node->ownerDocument->nodeFlags & NEEDS_RENUMBERING) { domRenumberTree (node->ownerDocument->rootNode); node->ownerDocument->nodeFlags &= ~NEEDS_RENUMBERING; } return (node->nodeNumber < other->nodeNumber); # else if (node->ownerDocument->nodeFlags & NEEDS_RENUMBERING && node->ownerDocument->refCount <= 1) { domRenumberTree (node->ownerDocument->rootNode); node->ownerDocument->nodeFlags &= ~NEEDS_RENUMBERING; } if (!(node->ownerDocument->nodeFlags & NEEDS_RENUMBERING)) { return (node->nodeNumber < other->nodeNumber); } #endif otherAncestor = other; while (otherAncestor->parentNode) { otherAncestor = otherAncestor->parentNode; if (otherAncestor == node) { return 1; } } nodeAncestor = node; while (nodeAncestor->parentNode) { otherAncestor = other; while (otherAncestor->parentNode) { if (nodeAncestor->parentNode == otherAncestor->parentNode) { nodeAncestor = nodeAncestor->nextSibling; while (nodeAncestor) { if (nodeAncestor == otherAncestor) { return 1; } nodeAncestor = nodeAncestor->nextSibling; } return 0; } otherAncestor = otherAncestor->parentNode; } nodeAncestor = nodeAncestor->parentNode; if (nodeAncestor == other) { return 0; } } nodeAncestor = nodeAncestor->nextSibling; while (nodeAncestor) { if (nodeAncestor == otherAncestor) { return 1; } nodeAncestor = nodeAncestor->nextSibling; } if (node == node->ownerDocument->rootNode) { return 1; } return 0; } /*--------------------------------------------------------------------------- | domRenumberTree | \--------------------------------------------------------------------------*/ void domRenumberTree ( domNode *node ) { while (node) { node->nodeNumber = NODE_NO(node->ownerDocument); if (node->nodeType == ELEMENT_NODE) { domRenumberTree (node->firstChild); } node = node->nextSibling; } } /*--------------------------------------------------------------------------- | domLookupPrefixWithMappings | \--------------------------------------------------------------------------*/ const char * domLookupPrefixWithMappings ( domNode *node, const char *prefix, char **prefixMappings ) { int i; domNS *ns; if (prefixMappings) { i = 0; while (prefixMappings[i]) { if (strcmp (prefix, prefixMappings[i]) == 0) { return prefixMappings[i+1]; } i += 2; } } ns = domLookupPrefix (node, prefix); if (ns) return ns->uri; else return NULL; } /*--------------------------------------------------------------------------- | domLookupPrefix | \--------------------------------------------------------------------------*/ domNS * domLookupPrefix ( domNode *node, const char *prefix ) { domAttrNode *NSattr; domNode *orgNode = node; int found; found = 0; while (node) { if (node->firstAttr && !(node->firstAttr->nodeFlags & IS_NS_NODE)) { node = node->parentNode; continue; } NSattr = node->firstAttr; while (NSattr && (NSattr->nodeFlags & IS_NS_NODE)) { if (prefix[0] == '\0') { if (NSattr->nodeName[5] == '\0') { found = 1; break; } } else { if (NSattr->nodeName[5] != '\0' && strcmp (&NSattr->nodeName[6], prefix)==0) { found = 1; break; } } NSattr = NSattr->nextSibling; } if (found) { return domGetNamespaceByIndex (node->ownerDocument, NSattr->namespace); } node = node->parentNode; } if (prefix && (strcmp (prefix, "xml")==0)) { NSattr = orgNode->ownerDocument->rootNode->firstAttr; return domGetNamespaceByIndex (orgNode->ownerDocument, NSattr->namespace); } return NULL; } /*--------------------------------------------------------------------------- | domIsNamespaceInScope | \--------------------------------------------------------------------------*/ int domIsNamespaceInScope ( domActiveNS *NSstack, int NSstackPos, const char *prefix, const char *namespaceURI ) { int i; for (i = NSstackPos; i >= 0; i--) { if (NSstack[i].namespace->prefix[0] && (strcmp(NSstack[i].namespace->prefix, prefix)==0)) { if (strcmp(NSstack[i].namespace->uri, namespaceURI)==0) { /* OK, exactly the same namespace declaration is in scope */ return 1; } else { /* This prefix is currently assigned to another uri, we need a new NS declaration, to override this one */ return 0; } } } return 0; } /*--------------------------------------------------------------------------- | domLookupURI | \--------------------------------------------------------------------------*/ domNS * domLookupURI ( domNode *node, char *uri ) { domAttrNode *NSattr; int found, alreadyHaveDefault; found = 0; alreadyHaveDefault = 0; while (node) { if (node->firstAttr && !(node->firstAttr->nodeFlags & IS_NS_NODE)) { node = node->parentNode; continue; } NSattr = node->firstAttr; while (NSattr && (NSattr->nodeFlags & IS_NS_NODE)) { if (NSattr->nodeName[5] == '\0') { if (!alreadyHaveDefault) { if (strcmp (NSattr->nodeValue, uri)==0) { found = 1; break; } else { alreadyHaveDefault = 1; } } } else { if (strcmp (NSattr->nodeValue, uri)==0) { found = 1; break; } } NSattr = NSattr->nextSibling; } if (found) { return domGetNamespaceByIndex (node->ownerDocument, NSattr->namespace); } node = node->parentNode; } return NULL; } /*--------------------------------------------------------------------------- | domGetNamespaceByIndex | \--------------------------------------------------------------------------*/ domNS * domGetNamespaceByIndex ( domDocument *doc, unsigned int nsIndex ) { if (!nsIndex) return NULL; return doc->namespaces[nsIndex-1]; } /*--------------------------------------------------------------------------- | domNewNamespace | \--------------------------------------------------------------------------*/ domNS* domNewNamespace ( domDocument *doc, const char *prefix, const char *namespaceURI ) { domNS *ns = NULL; DBG(fprintf(stderr, "domNewNamespace '%s' --> '%s' \n", prefix, namespaceURI);) ns = domLookupNamespace (doc, prefix, namespaceURI); if (ns != NULL) return ns; doc->nsptr++; #ifdef TDOM_LESS_NS if (doc->nsptr > 254) { DBG(fprintf (stderr, "maximum number of namespaces exceeded!!!\n");) domPanic("domNewNamespace: maximum number of namespaces exceeded!"); } #endif if (doc->nsptr >= doc->nslen) { doc->namespaces = (domNS**) REALLOC ((char*) doc->namespaces, sizeof (domNS*) * 2 * doc->nslen); doc->nslen *= 2; } doc->namespaces[doc->nsptr] = (domNS*)MALLOC (sizeof (domNS)); ns = doc->namespaces[doc->nsptr]; if (prefix == NULL) { ns->prefix = tdomstrdup(""); } else { ns->prefix = tdomstrdup(prefix); } if (namespaceURI == NULL) { ns->uri = tdomstrdup(""); } else { ns->uri = tdomstrdup(namespaceURI); } ns->index = doc->nsptr + 1; return ns; } /*--------------------------------------------------------------------------- | domSplitQName - extract namespace prefix (if any) | \--------------------------------------------------------------------------*/ int domSplitQName ( const char *name, char *prefix, const char **localName ) { const char *s; char *p, *prefixEnd; s = name; p = prefix; prefixEnd = &prefix[MAX_PREFIX_LEN-1]; while (*s && (*s != ':')) { if (p < prefixEnd) *p++ = *s; s++; } if (*s != ':') { *prefix = '\0'; *localName = name; return 0; } *p++ = '\0'; *localName = ++s; DBG(fprintf(stderr, "domSplitName %s -> '%s' '%s'\n", name, prefix, *localName); ) return 1; } /*--------------------------------------------------------------------------- | domNamespaceURI | \--------------------------------------------------------------------------*/ const char * domNamespaceURI ( domNode *node ) { domAttrNode *attr; domNS *ns; if (node->nodeType == ATTRIBUTE_NODE) { attr = (domAttrNode*)node; if (!attr->namespace) return NULL; if (attr->nodeFlags & IS_NS_NODE) return NULL; ns = attr->parentNode->ownerDocument->namespaces[attr->namespace-1]; } else if (node->nodeType == ELEMENT_NODE) { if (!node->namespace) return NULL; ns = node->ownerDocument->namespaces[node->namespace-1]; } else { return NULL; } return ns->uri; } /*--------------------------------------------------------------------------- | domNamespacePrefix | \--------------------------------------------------------------------------*/ const char * domNamespacePrefix ( domNode *node ) { domAttrNode *attr; domNS *ns; if (node->nodeType == ATTRIBUTE_NODE) { attr = (domAttrNode*)node; if (!attr->namespace) return NULL; ns = attr->parentNode->ownerDocument->namespaces[attr->namespace-1]; } else if (node->nodeType == ELEMENT_NODE) { if (!node->namespace) return NULL; ns = node->ownerDocument->namespaces[node->namespace-1]; } else { return NULL; } if (ns) return ns->prefix; return NULL; } /*--------------------------------------------------------------------------- | domGetLocalName | \--------------------------------------------------------------------------*/ const char * domGetLocalName ( const char *nodeName ) { char prefix[MAX_PREFIX_LEN]; const char *localName; domSplitQName (nodeName, prefix, &localName); return localName; } /* *---------------------------------------------------------------------- * * domGetAttributeNodeNS -- * * Search a given node for an attribute with namespace "uri" and * localname "localname". * * Results: * Returns a pointer to the attribute, if there is one with the * given namespace and localname. Otherwise returns NULL. * * Side effects: * None. * *---------------------------------------------------------------------- */ domAttrNode * domGetAttributeNodeNS ( domNode *node, /* The attributes of this node are searched for a matching attribute; the node must exist */ const char *uri, /* The namespace of the demanded attribute */ const char *localname /* The localname of the demanded attribute */ ) { domAttrNode *attr; domNS *ns; int noNS; char prefix[MAX_PREFIX_LEN]; const char *attrLocalName; if (uri[0] == '\0') noNS = 1; else noNS = 0; attr = node->firstAttr; while (attr) { if (noNS) { if (!attr->namespace && strcmp (attr->nodeName, localname) == 0) { return attr; } } else { if (attr->namespace) { domSplitQName (attr->nodeName, prefix, &attrLocalName); if (strcmp (localname, attrLocalName) == 0) { ns = domGetNamespaceByIndex (node->ownerDocument, attr->namespace); if (strcmp (ns->uri, uri) == 0) { return attr; } } } } attr = attr->nextSibling; } return NULL; } /* *---------------------------------------------------------------------- * * domPreviousSibling -- * * Returns the previous node to the given node or NULL, if there * is no previous node. This function is needed in situations, * where the given node may also be an domAttrNode. Namespace * declaring attributes are treated as any other * attributes. Since the domAttrNode struct doesn't has an * element for the previous attribute, we need a function for the * relatively rare cases, the 'previous attribute' is * needed. Remember, that the XML rec say, that there is no * specific order of the attributes of a node. * * Results: * A pointer to the previous node of the given one * or NULL, if there isn't a previous node. * * Side effects: * None. * *---------------------------------------------------------------------- */ domNode * domPreviousSibling ( domNode *node /* The reference attribute */ ) { domAttrNode *attr, *attr1; if (node->nodeType != ATTRIBUTE_NODE) { return node->previousSibling; } attr = (domAttrNode*) node; if (attr->parentNode->firstAttr == attr) { return NULL; } attr1 = attr->parentNode->firstAttr; while (attr1) { if (attr1->nextSibling == attr) { return (domNode*)attr1; } attr1 = attr1->nextSibling; } /* Not reached */ return NULL; } #ifndef TDOM_NO_EXPAT /*--------------------------------------------------------------------------- | startElement | \--------------------------------------------------------------------------*/ static void startElement( void *userData, const char *name, const char **atts ) { domReadInfo *info = userData; domNode *node, *parentNode; domLineColumn *lc; domAttrNode *attrnode, *lastAttr; const char **atPtr, **idAttPtr; Tcl_HashEntry *h; size_t len; int hnew, pos, idatt, newNS, result; const char *xmlns, *localname; char tagPrefix[MAX_PREFIX_LEN]; char prefix[MAX_PREFIX_LEN]; domNS *ns; char feedbackCmd[24]; if (info->feedbackAfter) { if (info->nextFeedbackPosition <= XML_GetCurrentByteIndex (info->parser) ) { if (info->feedbackCmd) { result = Tcl_GlobalEvalObj(info->interp, info->feedbackCmd); } else { sprintf(feedbackCmd, "%s", "::dom::domParseFeedback"); result = Tcl_Eval(info->interp, feedbackCmd); } if (result != TCL_OK) { DBG(fprintf(stderr, "%s\n", Tcl_GetStringResult (info->interp));); info->status = result; XML_StopParser(info->parser, 1); return; } info->nextFeedbackPosition = XML_GetCurrentByteIndex (info->parser) + info->feedbackAfter; Tcl_ResetResult (info->interp); } } DispatchPCDATA (info); h = Tcl_CreateHashEntry(&HASHTAB(info->document,tdom_tagNames), name, &hnew); if (info->storeLineColumn) { node = (domNode*) domAlloc(sizeof(domNode) + sizeof(domLineColumn)); } else { node = (domNode*) domAlloc(sizeof(domNode)); } memset(node, 0, sizeof(domNode)); node->nodeType = ELEMENT_NODE; node->nodeName = (char *)&(h->key); node->nodeNumber = NODE_NO(info->document); node->ownerDocument = info->document; if (info->baseURIstack[info->baseURIstackPos].baseURI != XML_GetBase (info->parser)) { h = Tcl_CreateHashEntry (info->document->baseURIs, (char*) node, &hnew); Tcl_SetHashValue (h, tdomstrdup (XML_GetBase (info->parser))); node->nodeFlags |= HAS_BASEURI; info->baseURIstackPos++; if (info->baseURIstackPos >= info->baseURIstackSize) { info->baseURIstack = (domActiveBaseURI*) REALLOC( (char*)info->baseURIstack, sizeof(domActiveBaseURI) * 2 * info->baseURIstackSize); info->baseURIstackSize = 2 * info->baseURIstackSize; } info->baseURIstack[info->baseURIstackPos].baseURI = XML_GetBase (info->parser); info->baseURIstack[info->baseURIstackPos].depth = info->depth; } if (info->depth == 0) { if (info->document->rootNode->lastChild) { info->document->rootNode->lastChild->nextSibling = node; node->previousSibling = info->document->rootNode->lastChild; } else { info->document->rootNode->firstChild = node; } info->document->rootNode->lastChild = node; } else { parentNode = info->currentNode; node->parentNode = parentNode; if (parentNode->firstChild) { parentNode->lastChild->nextSibling = node; node->previousSibling = parentNode->lastChild; parentNode->lastChild = node; } else { parentNode->firstChild = parentNode->lastChild = node; } } info->currentNode = node; if (info->storeLineColumn) { lc = (domLineColumn*) ( ((char*)node) + sizeof(domNode)); node->nodeFlags |= HAS_LINE_COLUMN; lc->line = XML_GetCurrentLineNumber (info->parser); lc->column = XML_GetCurrentColumnNumber (info->parser); lc->byteIndex = XML_GetCurrentByteIndex (info->parser); } lastAttr = NULL; /*-------------------------------------------------------------- | process namespace declarations | \-------------------------------------------------------------*/ if (!info->ignorexmlns) { for (atPtr = atts; atPtr[0] && atPtr[1]; atPtr += 2) { if (strncmp(atPtr[0], "xmlns", 5) == 0) { xmlns = atPtr[0]; newNS = 1; if (xmlns[5] == ':') { if (atPtr[1][0] == '\0') { Tcl_SetResult (info->interp, "Missing URI in Namespace " "declaration", NULL); XML_StopParser(info->parser, 0); return; } if (domIsNamespaceInScope (info->activeNS, info->activeNSpos, &(xmlns[6]), atPtr[1])) { ns = domLookupPrefix (info->currentNode, &(xmlns[6])); newNS = 0; } else { ns = domNewNamespace(info->document, &xmlns[6], atPtr[1]); } } else { ns = domNewNamespace(info->document, "", atPtr[1]); } if (newNS) { /* push active namespace */ info->activeNSpos++; if (info->activeNSpos >= info->activeNSsize) { info->activeNS = (domActiveNS*) REALLOC( (char*)info->activeNS, sizeof(domActiveNS) * 2 * info->activeNSsize); info->activeNSsize = 2 * info->activeNSsize; } info->activeNS[info->activeNSpos].depth = info->depth; info->activeNS[info->activeNSpos].namespace = ns; } h = Tcl_CreateHashEntry(&HASHTAB(info->document, tdom_attrNames), atPtr[0], &hnew); attrnode = (domAttrNode*) domAlloc(sizeof(domAttrNode)); memset(attrnode, 0, sizeof(domAttrNode)); attrnode->nodeType = ATTRIBUTE_NODE; attrnode->nodeFlags = IS_NS_NODE; attrnode->namespace = ns->index; attrnode->nodeName = (char *)&(h->key); attrnode->parentNode = node; len = strlen(atPtr[1]); attrnode->valueLength = (domLength)len; attrnode->nodeValue = (char*)MALLOC(len+1); strcpy(attrnode->nodeValue, atPtr[1]); if (node->firstAttr) { lastAttr->nextSibling = attrnode; } else { node->firstAttr = attrnode; } lastAttr = attrnode; } } /*---------------------------------------------------------- | look for namespace of element \---------------------------------------------------------*/ domSplitQName (name, tagPrefix, &localname); for (pos = info->activeNSpos; pos >= 0; pos--) { if ( ((tagPrefix[0] == '\0') && (info->activeNS[pos].namespace->prefix[0] == '\0')) || ((tagPrefix[0] != '\0') && (info->activeNS[pos].namespace->prefix[0] != '\0') && (strcmp(tagPrefix, info->activeNS[pos].namespace->prefix) == 0)) ) { if (info->activeNS[pos].namespace->prefix[0] == '\0' && info->activeNS[pos].namespace->uri[0] == '\0' && tagPrefix[0] == '\0') { /* xml-names rec. 5.2: "The default namespace can be set to the empty string. This has the same effect, within the scope of the declaration, of there being no default namespace." */ goto elemNSfound; } node->namespace = info->activeNS[pos].namespace->index; DBG(fprintf(stderr, "tag='%s' uri='%s' \n", node->nodeName, info->activeNS[pos].namespace->uri); ) goto elemNSfound; } } if (tagPrefix[0] != '\0') { if (strcmp (tagPrefix, "xml")==0) { node->namespace = info->document->rootNode->firstAttr->namespace; } else { /* Since where here, this means, the element has a up to now not declared namespace prefix. */ Tcl_SetResult (info->interp, "Namespace prefix is not " "defined", NULL); XML_StopParser(info->parser, 0); return; } } } elemNSfound: /*-------------------------------------------------------------- | add the attribute nodes | \-------------------------------------------------------------*/ if ((idatt = XML_GetIdAttributeIndex (info->parser)) != -1) { if (!info->document->ids) { info->document->ids = TMALLOC (Tcl_HashTable); Tcl_InitHashTable (info->document->ids, TCL_STRING_KEYS); } h = Tcl_CreateHashEntry (info->document->ids, atts[idatt+1], &hnew); /* if hnew isn't 1 this is a validation error. Hm, no clear way to report this. And more, XSLT and XPath can process not valid XML, the spec mentioned this even within the context of id(). If some elements share the same ID, the first in document order should be used. Doing it this way, this is guaranteed for unchanged DOM trees. There are problems, if the DOM tree is changed, before using id() */ if (hnew) { Tcl_SetHashValue (h, node); } idAttPtr = atts + idatt; } else { idAttPtr = NULL; } /* lastAttr already set right, either to NULL above, or to the last NS attribute */ for (atPtr = atts; atPtr[0] && atPtr[1]; atPtr += 2) { if (!info->ignorexmlns) { if (strncmp(atPtr[0], "xmlns", 5) == 0) { continue; } } h = Tcl_CreateHashEntry(&HASHTAB(info->document, tdom_attrNames), atPtr[0], &hnew); attrnode = (domAttrNode*) domAlloc(sizeof(domAttrNode)); memset(attrnode, 0, sizeof(domAttrNode)); attrnode->nodeType = ATTRIBUTE_NODE; if (atPtr == idAttPtr) { attrnode->nodeFlags |= IS_ID_ATTRIBUTE; } attrnode->nodeName = (char *)&(h->key); attrnode->parentNode = node; len = strlen(atPtr[1]); attrnode->valueLength = (domLength)len; attrnode->nodeValue = (char*)MALLOC(len+1); strcpy(attrnode->nodeValue, (char *)atPtr[1]); if (node->firstAttr) { lastAttr->nextSibling = attrnode; } else { node->firstAttr = attrnode; } lastAttr = attrnode; if (!info->ignorexmlns) { /*---------------------------------------------------------- | look for attribute namespace \---------------------------------------------------------*/ domSplitQName (attrnode->nodeName, prefix, &localname); if (prefix[0] != '\0') { for (pos = info->activeNSpos; pos >= 0; pos--) { if ( ((prefix[0] == '\0') && (info->activeNS[pos].namespace->prefix[0] == '\0')) || ((prefix[0] != '\0') && (info->activeNS[pos].namespace->prefix[0] != '\0') && (strcmp(prefix, info->activeNS[pos].namespace->prefix) == 0)) ) { attrnode->namespace = info->activeNS[pos].namespace->index; DBG(fprintf(stderr, "attr='%s' uri='%s' \n", attrnode->nodeName, info->activeNS[pos].namespace->uri); ) goto attrNSfound; } } if (strcmp (prefix, "xml")==0) { attrnode->namespace = info->document->rootNode->firstAttr->namespace; } else { /* Since where here, this means, the attribute has a up to now not declared namespace prefix. We probably should return this as an error, shouldn't we?*/ } attrNSfound: ; } } } #ifndef TDOM_NO_SCHEMA if (info->sdata) { if (tDOM_probeElement (info->interp, info->sdata, node->nodeName, node->namespace ? info->document->namespaces[node->namespace-1]->uri : NULL) != TCL_OK) { XML_StopParser(info->parser, 0); } else { if (tDOM_probeDomAttributes (info->interp, info->sdata, node->firstAttr) != TCL_OK) { XML_StopParser(info->parser, 0); } } } #endif info->depth++; } /*--------------------------------------------------------------------------- | endElement | \--------------------------------------------------------------------------*/ static void endElement ( void *userData, const char *UNUSED(name) ) { domReadInfo *info = userData; DispatchPCDATA (info); info->depth--; if (!info->ignorexmlns) { /* pop active namespaces */ while ( (info->activeNSpos >= 0) && (info->activeNS[info->activeNSpos].depth == info->depth) ) { info->activeNSpos--; } } if (info->depth != -1) { info->currentNode = info->currentNode->parentNode; } else { info->currentNode = NULL; } if (info->depth) { if (info->baseURIstack[info->baseURIstackPos].depth == info->depth) { info->baseURIstackPos--; } } #ifndef TDOM_NO_SCHEMA if (info->sdata) { if (tDOM_probeElementEnd (info->interp, info->sdata) != TCL_OK) { XML_StopParser(info->parser, 0); } } #endif } /*--------------------------------------------------------------------------- | characterDataHandler | \--------------------------------------------------------------------------*/ static void characterDataHandler ( void *userData, const char *s, int len ) { domReadInfo *info = userData; Tcl_DStringAppend (info->cdata, s, len); if (info->storeLineColumn) { /* This works because the result of XML_GetCurrentLineNumber() * is always at least 1 */ if (!info->textStartLine) { info->textStartLine = (domLength)XML_GetCurrentLineNumber (info->parser); info->textStartColumn = (domLength)XML_GetCurrentColumnNumber (info->parser); info->textStartByteIndex = (domLength)XML_GetCurrentByteIndex (info->parser); } } return; } /*--------------------------------------------------------------------------- | startCDATA | \--------------------------------------------------------------------------*/ static void startCDATA ( void *userData ) { domReadInfo *info = userData; DispatchPCDATA (info); info->cdataSection = 1; if (info->storeLineColumn) { if (!info->textStartLine) { info->textStartLine = (domLength)XML_GetCurrentLineNumber (info->parser); info->textStartColumn = (domLength)XML_GetCurrentColumnNumber (info->parser); info->textStartByteIndex = (domLength)XML_GetCurrentByteIndex (info->parser); } } } /*--------------------------------------------------------------------------- | endCDATA | \--------------------------------------------------------------------------*/ static void endCDATA ( void *userData ) { domReadInfo *info = userData; DispatchPCDATA (info); info->cdataSection = 0; } /*--------------------------------------------------------------------------- | DispatchPCDATA | \--------------------------------------------------------------------------*/ static void DispatchPCDATA ( domReadInfo *info ) { domTextNode *node; domNode *parentNode; domLineColumn *lc; Tcl_HashEntry *h; char *s; int hnew, only_whites; domLength len; len = Tcl_DStringLength (info->cdata); #ifndef TDOM_NO_SCHEMA if (!len && !info->cdataSection && !(info->sdata && info->sdata->stack && info->sdata->stack->pattern->flags & CONSTRAINT_TEXT_CHILD)) { info->textStartLine = 0; return; } #else if (!len && !info->cdataSection) { info->textStartLine = 0; return; } #endif s = Tcl_DStringValue (info->cdata); parentNode = info->currentNode; if (!parentNode) { return; } if ( parentNode->lastChild && parentNode->lastChild->nodeType == TEXT_NODE && !info->cdataSection) { /* normalize text node, i.e. there are no adjacent text nodes */ node = (domTextNode*)parentNode->lastChild; node->nodeValue = REALLOC(node->nodeValue, node->valueLength + len); memmove(node->nodeValue + node->valueLength, s, len); node->valueLength += len; only_whites = 0; } else { if (info->ignoreWhiteSpaces) { char *pc; int i; only_whites = 1; for (i=0, pc = s; i < len; i++, pc++) { if ( (*pc != ' ') && (*pc != '\t') && (*pc != '\n') && (*pc != '\r') ) { only_whites = 0; break; } } if (only_whites) { goto checkTextConstraints; } } if (info->storeLineColumn) { node = (domTextNode*) domAlloc(sizeof(domTextNode) + sizeof(domLineColumn)); } else { node = (domTextNode*) domAlloc(sizeof(domTextNode)); } memset(node, 0, sizeof(domTextNode)); if (info->cdataSection) node->nodeType = CDATA_SECTION_NODE; else node->nodeType = TEXT_NODE; node->nodeNumber = NODE_NO(info->document); node->valueLength = len; node->nodeValue = (char*)MALLOC(len); memmove(node->nodeValue, s, len); node->ownerDocument = info->document; if (info->currentNode) { node->parentNode = parentNode; } if (parentNode->nodeType == ELEMENT_NODE) { if (parentNode->lastChild) { parentNode->lastChild->nextSibling = (domNode*)node; node->previousSibling = parentNode->lastChild; } else { parentNode->firstChild = (domNode*)node; } parentNode->lastChild = (domNode*)node; } if (info->baseURIstack[info->baseURIstackPos].baseURI != XML_GetBase (info->parser)) { h = Tcl_CreateHashEntry (info->document->baseURIs, (char*) node, &hnew); Tcl_SetHashValue (h, tdomstrdup (XML_GetBase (info->parser))); node->nodeFlags |= HAS_BASEURI; } if (info->storeLineColumn) { lc = (domLineColumn*) ( ((char*)node) + sizeof(domTextNode) ); node->nodeFlags |= HAS_LINE_COLUMN; lc->line = info->textStartLine; lc->column = info->textStartColumn; lc->byteIndex = info->textStartByteIndex; } } checkTextConstraints: #ifndef TDOM_NO_SCHEMA if (info->sdata) { if (tDOM_probeText (info->interp, info->sdata, s, &only_whites) != TCL_OK) { XML_StopParser(info->parser, 0); } } #endif info->textStartLine = 0; Tcl_DStringSetLength (info->cdata, 0); } /*--------------------------------------------------------------------------- | commentHandler | \--------------------------------------------------------------------------*/ static void commentHandler ( void *userData, const char *s ) { domReadInfo *info = userData; domTextNode *node; domNode *parentNode; domLineColumn *lc; size_t len; int hnew; Tcl_HashEntry *h; if (info->insideDTD) { DBG(fprintf (stderr, "commentHandler: insideDTD, skipping\n");) return; } DispatchPCDATA (info); len = strlen(s); parentNode = info->currentNode; if (info->storeLineColumn) { node = (domTextNode*) domAlloc(sizeof(domTextNode) + sizeof(domLineColumn)); } else { node = (domTextNode*) domAlloc(sizeof(domTextNode)); } memset(node, 0, sizeof(domTextNode)); node->nodeType = COMMENT_NODE; node->nodeNumber = NODE_NO(info->document); node->valueLength = (domLength)len; node->nodeValue = (char*)MALLOC(len); memmove(node->nodeValue, s, len); node->ownerDocument = info->document; node->parentNode = parentNode; if (parentNode == NULL) { if (info->document->rootNode->lastChild) { info->document->rootNode->lastChild->nextSibling = (domNode*)node; node->previousSibling = info->document->rootNode->lastChild; } else { info->document->rootNode->firstChild = (domNode*)node; } info->document->rootNode->lastChild = (domNode*)node; } else if(parentNode->nodeType == ELEMENT_NODE) { if (parentNode->firstChild) { parentNode->lastChild->nextSibling = (domNode*)node; node->previousSibling = parentNode->lastChild; parentNode->lastChild = (domNode*)node; } else { parentNode->firstChild = parentNode->lastChild = (domNode*)node; } } if (info->baseURIstack[info->baseURIstackPos].baseURI != XML_GetBase (info->parser)) { h = Tcl_CreateHashEntry (info->document->baseURIs, (char*) node, &hnew); Tcl_SetHashValue (h, tdomstrdup (XML_GetBase (info->parser))); node->nodeFlags |= HAS_BASEURI; } if (info->storeLineColumn) { lc = (domLineColumn*) ( ((char*)node) + sizeof(domTextNode) ); node->nodeFlags |= HAS_LINE_COLUMN; lc->line = XML_GetCurrentLineNumber (info->parser); lc->column = XML_GetCurrentColumnNumber(info->parser); lc->byteIndex = XML_GetCurrentByteIndex (info->parser); } } /*--------------------------------------------------------------------------- | processingInstructionHandler | \--------------------------------------------------------------------------*/ static void processingInstructionHandler( void *userData, const char *target, const char *data ) { domProcessingInstructionNode *node; domReadInfo *info = userData; domNode *parentNode; domLineColumn *lc; size_t len; int hnew; Tcl_HashEntry *h; if (info->insideDTD) { DBG(fprintf (stderr, "processingInstructionHandler: insideDTD, skipping\n");) return; } DispatchPCDATA (info); parentNode = info->currentNode; if (info->storeLineColumn) { node = (domProcessingInstructionNode*) domAlloc(sizeof(domProcessingInstructionNode) + sizeof(domLineColumn)); } else { node = (domProcessingInstructionNode*) domAlloc(sizeof(domProcessingInstructionNode)); } memset(node, 0, sizeof(domProcessingInstructionNode)); node->nodeType = PROCESSING_INSTRUCTION_NODE; node->nodeNumber = NODE_NO(info->document); if (info->baseURIstack[info->baseURIstackPos].baseURI != XML_GetBase (info->parser)) { h = Tcl_CreateHashEntry (info->document->baseURIs, (char*) node, &hnew); Tcl_SetHashValue (h, tdomstrdup (XML_GetBase (info->parser))); node->nodeFlags |= HAS_BASEURI; } len = strlen(target); node->targetLength = (domLength)len; node->targetValue = (char*)MALLOC(len); memmove(node->targetValue, target, len); len = strlen(data); node->dataLength = (domLength)len; node->dataValue = (char*)MALLOC(len); memmove(node->dataValue, data, len); node->ownerDocument = info->document; node->parentNode = parentNode; if (parentNode == NULL) { if (info->document->rootNode->lastChild) { info->document->rootNode->lastChild->nextSibling = (domNode*)node; node->previousSibling = info->document->rootNode->lastChild; } else { info->document->rootNode->firstChild = (domNode*)node; } info->document->rootNode->lastChild = (domNode*)node; } else if(parentNode->nodeType == ELEMENT_NODE) { if (parentNode->firstChild) { parentNode->lastChild->nextSibling = (domNode*)node; node->previousSibling = parentNode->lastChild; parentNode->lastChild = (domNode*)node; } else { parentNode->firstChild = parentNode->lastChild = (domNode*)node; } } if (info->storeLineColumn) { lc = (domLineColumn*)(((char*)node)+sizeof(domProcessingInstructionNode)); node->nodeFlags |= HAS_LINE_COLUMN; lc->line = XML_GetCurrentLineNumber (info->parser); lc->column = XML_GetCurrentColumnNumber(info->parser); lc->byteIndex = XML_GetCurrentByteIndex (info->parser); } } /*--------------------------------------------------------------------------- | entityDeclHandler | \--------------------------------------------------------------------------*/ static void entityDeclHandler ( void *userData, const char *entityName, int UNUSED(is_parameter_entity), const char *UNUSED(value), int UNUSED(value_length), const char *UNUSED(base), const char *systemId, const char *UNUSED(publicId), const char *notationName ) { domReadInfo *info = (domReadInfo *) userData; Tcl_HashEntry *entryPtr; int hnew; if (notationName) { if (!info->document->unparsedEntities) { info->document->unparsedEntities = TMALLOC (Tcl_HashTable); Tcl_InitHashTable (info->document->unparsedEntities, TCL_STRING_KEYS); } entryPtr = Tcl_CreateHashEntry (info->document->unparsedEntities, entityName, &hnew); if (hnew) { Tcl_SetHashValue (entryPtr, tdomstrdup (systemId)); } } } /*--------------------------------------------------------------------------- | externalEntityRefHandler | \--------------------------------------------------------------------------*/ static int externalEntityRefHandler ( XML_Parser parser, const char *openEntityNames, const char *base, const char *systemId, const char *publicId ) { domReadInfo *info = (domReadInfo *) XML_GetUserData (parser); Tcl_Obj *cmdPtr, *resultObj, *resultTypeObj, *extbaseObj, *xmlstringObj; Tcl_Obj *channelIdObj; int result, mode, done, keepresult = 0; domLength len, tclLen; XML_Parser extparser, oldparser = NULL; char buf[4096], *resultType, *extbase, *xmlstring, *xmlstringstart, *channelId, s[50]; Tcl_Channel chan = (Tcl_Channel) NULL; enum XML_Status status; XML_Index storedNextFeedbackPosition; const char *interpResult; if (info->document->extResolver == NULL) { Tcl_AppendResult (info->interp, "Can't read external entity \"", systemId, "\": No -externalentitycommand given", NULL); return 0; } DispatchPCDATA (info); /* * Take a copy of the callback script so that arguments may be appended. */ cmdPtr = Tcl_NewStringObj(info->document->extResolver, -1); Tcl_IncrRefCount(cmdPtr); if (base) { Tcl_ListObjAppendElement(info->interp, cmdPtr, Tcl_NewStringObj(base, (domLength)strlen(base))); } else { Tcl_ListObjAppendElement(info->interp, cmdPtr, Tcl_NewObj()); } /* For a document with doctype declaration, the systemId is always != NULL. But if the document doesn't have a doctype declaration and the user uses -useForeignDTD 1, the externalEntityRefHandler will be called with a systemId (and publicId and openEntityNames) == NULL. */ if (systemId) { Tcl_ListObjAppendElement(info->interp, cmdPtr, Tcl_NewStringObj(systemId, (domLength)strlen(systemId))); } else { Tcl_ListObjAppendElement(info->interp, cmdPtr, Tcl_NewObj()); } if (publicId) { Tcl_ListObjAppendElement(info->interp, cmdPtr, Tcl_NewStringObj(publicId, (domLength)strlen(publicId))); } else { Tcl_ListObjAppendElement(info->interp, cmdPtr, Tcl_NewObj()); } result = Tcl_EvalObjEx (info->interp, cmdPtr, TCL_EVAL_DIRECT | TCL_EVAL_GLOBAL); Tcl_DecrRefCount(cmdPtr); if (result != TCL_OK) { info->status = result; return 0; } extparser = XML_ExternalEntityParserCreate (parser, openEntityNames, 0); resultObj = Tcl_GetObjResult (info->interp); Tcl_IncrRefCount (resultObj); result = Tcl_ListObjLength (info->interp, resultObj, &tclLen); if ((result != TCL_OK) || (tclLen != 3)) { goto wrongScriptResult; } result = Tcl_ListObjIndex (info->interp, resultObj, 0, &resultTypeObj); if (result != TCL_OK) { goto wrongScriptResult; } resultType = Tcl_GetString(resultTypeObj); if (strcmp (resultType, "string") == 0) { Tcl_ListObjIndex (info->interp, resultObj, 2, &xmlstringObj); xmlstring = Tcl_GetStringFromObj (xmlstringObj, &len); chan = NULL; } else if (strcmp (resultType, "channel") == 0) { xmlstring = NULL; len = 0; Tcl_ListObjIndex (info->interp, resultObj, 2, &channelIdObj); channelId = Tcl_GetString(channelIdObj); chan = Tcl_GetChannel (info->interp, channelId, &mode); if (chan == (Tcl_Channel) NULL) { goto wrongScriptResult; } if ((mode & TCL_READABLE) == 0) { return 0; } } else if (strcmp (resultType, "filename") == 0) { /* result type "filename" not yet implemented */ return 0; } else { goto wrongScriptResult; } result = Tcl_ListObjIndex (info->interp, resultObj, 1, &extbaseObj); if (result != TCL_OK) { goto wrongScriptResult; } extbase = Tcl_GetString(extbaseObj); /* TODO: what to do, if this document was already parsed before ? */ if (!extparser) { Tcl_DecrRefCount (resultObj); Tcl_SetResult (info->interp, "unable to create expat external entity parser", NULL); return 0; } oldparser = info->parser; info->parser = extparser; XML_SetBase (extparser, extbase); storedNextFeedbackPosition = info->nextFeedbackPosition; info->nextFeedbackPosition = info->feedbackAfter; Tcl_ResetResult (info->interp); result = 1; xmlstringstart = xmlstring; if (chan == NULL) { do { done = (len < TDOM_PCS); status = XML_Parse (extparser, xmlstring, (int)(done ? len : TDOM_PCS), done); if (!done) { xmlstring += TDOM_PCS; len -= TDOM_PCS; } } while (!done && status == XML_STATUS_OK); switch (status) { case XML_STATUS_ERROR: interpResult = Tcl_GetStringResult(info->interp); if (interpResult[0] == '\0') { tcldom_reportErrorLocation ( info->interp, 20, 40, XML_GetCurrentLineNumber(extparser), XML_GetCurrentColumnNumber(extparser), xmlstringstart, systemId, XML_GetCurrentByteIndex(extparser), XML_ErrorString(XML_GetErrorCode(extparser)) ); } else { sprintf(s, "%" TDOM_LS_MODIFIER "d", XML_GetCurrentLineNumber(extparser)); Tcl_AppendResult(info->interp, ", referenced in entity \"", systemId, "\" at line ", s, " character ", NULL); sprintf(s, "%" TDOM_LS_MODIFIER "d", XML_GetCurrentColumnNumber(extparser)); Tcl_AppendResult(info->interp, s, NULL); } keepresult = 1; result = 0; break; case XML_STATUS_SUSPENDED: XML_StopParser (oldparser, 1); keepresult = 1; break; default: break; } } else { do { len = Tcl_Read (chan, buf, sizeof(buf)); done = len < sizeof(buf); status = XML_Parse (extparser, buf, (int)len, done); switch (status) { case XML_STATUS_ERROR: interpResult = Tcl_GetStringResult(info->interp); sprintf(s, "%" TDOM_LS_MODIFIER "d", XML_GetCurrentLineNumber(extparser)); if (interpResult[0] == '\0') { Tcl_ResetResult (info->interp); Tcl_AppendResult(info->interp, "error \"", XML_ErrorString(XML_GetErrorCode(extparser)), "\" in entity \"", systemId, "\" at line ", s, " character ", NULL); sprintf(s, "%" TDOM_LS_MODIFIER "d", XML_GetCurrentColumnNumber(extparser)); Tcl_AppendResult(info->interp, s, NULL); } else { Tcl_AppendResult(info->interp, ", referenced in entity \"", systemId, "\" at line ", s, " character ", NULL); sprintf(s, "%" TDOM_LS_MODIFIER "d", XML_GetCurrentColumnNumber(extparser)); Tcl_AppendResult(info->interp, s, NULL); } result = 0; keepresult = 1; done = 1; break; case XML_STATUS_SUSPENDED: XML_StopParser (oldparser, 1); keepresult = 1; done = 1; break; default: break; } } while (!done); } if (result) { DispatchPCDATA (info); } if (!keepresult) { Tcl_ResetResult (info->interp); } XML_ParserFree (extparser); info->parser = oldparser; info->nextFeedbackPosition = storedNextFeedbackPosition; Tcl_DecrRefCount (resultObj); return result; wrongScriptResult: Tcl_DecrRefCount (resultObj); Tcl_ResetResult (info->interp); XML_ParserFree (extparser); if (oldparser) { info->parser = oldparser; } info->status = TCL_ERROR; Tcl_AppendResult (info->interp, "The -externalentitycommand script " "has to return a Tcl list with 3 elements.\n" "Syntax: {string|channel|filename }\n", NULL); return 0; } /*--------------------------------------------------------------------------- | startDoctypeDeclHandler | \--------------------------------------------------------------------------*/ static void startDoctypeDeclHandler ( void *userData, const char *UNUSED(doctypeName), const char *sysid, const char *pubid, int UNUSED(has_internal_subset) ) { domReadInfo *info = (domReadInfo *) userData; if (pubid) { info->document->doctype = (domDocInfo*)MALLOC (sizeof (domDocInfo)); memset (info->document->doctype, 0, sizeof (domDocInfo)); info->document->doctype->systemId = tdomstrdup (sysid); info->document->doctype->publicId = tdomstrdup (pubid); } else if (sysid) { info->document->doctype = (domDocInfo*)MALLOC (sizeof (domDocInfo)); memset (info->document->doctype, 0, sizeof (domDocInfo)); info->document->doctype->systemId = tdomstrdup (sysid); } info->insideDTD = 1; } /*--------------------------------------------------------------------------- | endDoctypeDeclHandler | \--------------------------------------------------------------------------*/ static void endDoctypeDeclHandler ( void *userData ) { domReadInfo *info = (domReadInfo *) userData; info->insideDTD = 0; } /*--------------------------------------------------------------------------- | domReadDocument | \--------------------------------------------------------------------------*/ domDocument * domReadDocument ( XML_Parser parser, char *xml, domLength length, int ignoreWhiteSpaces, int keepCDATA, int storeLineColumn, int ignorexmlns, int feedbackAfter, Tcl_Obj *feedbackCmd, Tcl_Channel channel, const char *baseurl, Tcl_Obj *extResolver, int useForeignDTD, int forest, int paramEntityParsing, #ifndef TDOM_NO_SCHEMA SchemaData *sdata, #endif Tcl_Interp *interp, domParseForestErrorData *forestError, int *resultcode ) { int done; domLength tclLen, len; enum XML_Status status; domReadInfo info; char buf[8192]; Tcl_Obj *bufObj = NULL; Tcl_DString dStr; int useBinary = 0; char *str; domDocument *doc = domCreateDoc(baseurl, storeLineColumn); domNode *thisNode; if (extResolver) { doc->extResolver = tdomstrdup (Tcl_GetString (extResolver)); } if (ignorexmlns) { doc->nodeFlags |= IGNORE_XMLNS; } info.parser = parser; info.document = doc; info.currentNode = NULL; info.depth = 0; info.ignoreWhiteSpaces = ignoreWhiteSpaces; info.cdata = (Tcl_DString*) MALLOC (sizeof (Tcl_DString)); Tcl_DStringInit (info.cdata); info.cdataSection = 0; info.storeLineColumn = storeLineColumn; info.textStartLine = 0; info.ignorexmlns = ignorexmlns; info.feedbackAfter = feedbackAfter; info.feedbackCmd = feedbackCmd; info.nextFeedbackPosition = feedbackAfter; info.interp = interp; info.activeNSpos = -1; info.activeNSsize = 8; info.activeNS = (domActiveNS*) MALLOC (sizeof(domActiveNS) * info.activeNSsize); info.baseURIstackPos = 0; info.baseURIstackSize = INITIAL_BASEURISTACK_SIZE; info.baseURIstack = (domActiveBaseURI*) MALLOC (sizeof(domActiveBaseURI) * info.baseURIstackSize); info.insideDTD = 0; info.status = 0; #ifndef TDOM_NO_SCHEMA info.sdata = sdata; #endif XML_SetUserData(parser, &info); XML_SetBase (parser, baseurl); /* We must use XML_GetBase(), because XML_SetBase copies the baseURI, and we want to compare the pointers */ info.baseURIstack[0].baseURI = XML_GetBase (parser); info.baseURIstack[0].depth = 0; XML_UseForeignDTD (parser, (unsigned char) useForeignDTD); XML_SetElementHandler(parser, startElement, endElement); XML_SetCharacterDataHandler(parser, characterDataHandler); XML_SetCommentHandler(parser, commentHandler); XML_SetProcessingInstructionHandler(parser, processingInstructionHandler); XML_SetEntityDeclHandler (parser, entityDeclHandler); if (extResolver) { XML_SetExternalEntityRefHandler (parser, externalEntityRefHandler); } XML_SetParamEntityParsing (parser, (enum XML_ParamEntityParsing) paramEntityParsing); XML_SetDoctypeDeclHandler (parser, startDoctypeDeclHandler, endDoctypeDeclHandler); if (keepCDATA) { XML_SetCdataSectionHandler(parser, startCDATA, endCDATA); } if (forest) { /* The created external entity parser inherits all the * configuration and will happily parse a forest. */ parser = XML_ExternalEntityParserCreate (parser, "forest", 0); info.parser = parser; info.currentNode = doc->rootNode; } if (channel == NULL) { do { done = (length < TDOM_PCS); status = XML_Parse (parser, xml, (int)(done ? length : TDOM_PCS), done); if (!done) { xml += TDOM_PCS; length -= TDOM_PCS; } } while (!done && status == XML_STATUS_OK); } else { Tcl_DStringInit (&dStr); if (Tcl_GetChannelOption (interp, channel, "-encoding", &dStr) != TCL_OK) { domFreeDocument (doc, NULL, NULL); *resultcode = TCL_ERROR; doc = NULL; goto cleanup; } if (strcmp (Tcl_DStringValue (&dStr), "utf-8")==0 ) { useBinary = 1; } else { bufObj = Tcl_NewObj(); Tcl_SetObjLength (bufObj, 6144); } Tcl_DStringFree (&dStr); do { if (useBinary) { len = Tcl_Read (channel, buf, sizeof(buf)); done = len < sizeof(buf); } else { len = Tcl_ReadChars (channel, bufObj, 1024, 0); done = (len < 1024); str = Tcl_GetStringFromObj (bufObj, &tclLen); } if (useBinary) { status = XML_Parse (parser, buf, (int)len, done); } else { status = XML_Parse (parser, str, (int)tclLen, done); } } while (!done && status == XML_STATUS_OK); } switch (status) { case XML_STATUS_SUSPENDED: DBG(fprintf(stderr, "XML_STATUS_SUSPENDED\n");) if (info.status == TCL_BREAK) { Tcl_ResetResult(interp); } /* fall through */ case XML_STATUS_ERROR: DBG(fprintf(stderr, "XML_STATUS_ERROR\n");) domFreeDocument (doc, NULL, NULL); *resultcode = info.status; doc = NULL; if (forest) { forestError->errorLine = XML_GetCurrentLineNumber(parser); forestError->errorColumn = XML_GetCurrentColumnNumber(parser); forestError->byteIndex = XML_GetCurrentByteIndex(parser); forestError->errorCode = XML_GetErrorCode(parser); } break; case XML_STATUS_OK: if (forest) { info.currentNode = doc->rootNode; DispatchPCDATA (&info); thisNode = doc->rootNode->firstChild; while (thisNode) { thisNode->parentNode = NULL; thisNode = thisNode->nextSibling; } } break; } if (bufObj) { Tcl_DecrRefCount (bufObj); } cleanup: FREE ( info.activeNS ); FREE ( info.baseURIstack ); Tcl_DStringFree (info.cdata); FREE ( info.cdata); if (forest) { /* This is the external entity parser, the main parser will be * freed in caller context. */ XML_ParserFree (parser); } if (doc) domSetDocumentElement (doc); return doc; } #endif /* ifndef TDOM_NO_EXPAT */ /*--------------------------------------------------------------------------- | domException2String | \--------------------------------------------------------------------------*/ const char * domException2String ( domException exception ) { return domException2StringTable[exception]; } /*--------------------------------------------------------------------------- | domGetLineColumn | \--------------------------------------------------------------------------*/ int domGetLineColumn ( domNode *node, XML_Size *line, XML_Size *column, XML_Index *byteIndex ) { char *v; domLineColumn *lc; *line = -1; *column = -1; if (node->nodeFlags & HAS_LINE_COLUMN) { v = (char*)node; switch (node->nodeType) { case ELEMENT_NODE: v = v + sizeof(domNode); break; case TEXT_NODE: case CDATA_SECTION_NODE: case COMMENT_NODE: v = v + sizeof(domTextNode); break; case PROCESSING_INSTRUCTION_NODE: v = v + sizeof(domProcessingInstructionNode); break; default: return -1; } lc = (domLineColumn *)v; *line = lc->line; *column = lc->column; *byteIndex = lc->byteIndex; return 0; } else { return -1; } } domAttrNode * domCreateXMLNamespaceNode ( domNode *parent ) { Tcl_HashEntry *h; int hnew; domAttrNode *attr; domNS *ns; attr = (domAttrNode *) domAlloc (sizeof (domAttrNode)); memset (attr, 0, sizeof (domAttrNode)); h = Tcl_CreateHashEntry(&HASHTAB(parent->ownerDocument,tdom_attrNames), "xmlns:xml", &hnew); ns = domNewNamespace (parent->ownerDocument, "xml", XML_NAMESPACE); attr->nodeType = ATTRIBUTE_NODE; attr->nodeFlags = IS_NS_NODE; attr->namespace = ns->index; attr->nodeName = (char *)&(h->key); attr->parentNode = parent; attr->valueLength = (domLength)strlen (XML_NAMESPACE); attr->nodeValue = tdomstrdup (XML_NAMESPACE); return attr; } /* *---------------------------------------------------------------------- * * domCreateDoc -- * * This procedure allocates a new domDocument, initialize it and * creates its rootNode (with initialization). * * Results: * The domDocument node: * * Side effects: * Allocates memory for the returned domDocument and its * rootNode. * *---------------------------------------------------------------------- */ domDocument * domCreateDoc ( const char * baseURI, int storeLineColumn ) { Tcl_HashEntry *h; int hnew; domNode *rootNode; domDocument *doc; domLineColumn *lc; doc = (domDocument *) MALLOC (sizeof (domDocument)); memset(doc, 0, sizeof(domDocument)); doc->nodeType = DOCUMENT_NODE; doc->documentNumber = DOC_NO(doc); doc->nsptr = -1; doc->nslen = 4; doc->namespaces = (domNS**) MALLOC (sizeof (domNS*) * doc->nslen); /* We malloc and initialize the baseURIs hash table here to avoid cluttering of the code all over the place with checks. */ doc->baseURIs = TMALLOC (Tcl_HashTable); Tcl_InitHashTable (doc->baseURIs, TCL_ONE_WORD_KEYS); TDomThreaded( domLocksAttach(doc); Tcl_InitHashTable(&doc->tdom_tagNames, TCL_STRING_KEYS); Tcl_InitHashTable(&doc->tdom_attrNames, TCL_STRING_KEYS); ) if (storeLineColumn) { rootNode = (domNode*) domAlloc(sizeof(domNode)+sizeof(domLineColumn)); } else { rootNode = (domNode*) domAlloc(sizeof(domNode)); } memset(rootNode, 0, sizeof(domNode)); rootNode->nodeType = ELEMENT_NODE; if (baseURI) { h = Tcl_CreateHashEntry (doc->baseURIs, (char*)rootNode, &hnew); Tcl_SetHashValue (h, tdomstrdup (baseURI)); rootNode->nodeFlags |= HAS_BASEURI; } rootNode->namespace = 0; h = Tcl_CreateHashEntry(&HASHTAB(doc,tdom_tagNames), "", &hnew); rootNode->nodeName = (char *)&(h->key); rootNode->nodeNumber = NODE_NO(doc); rootNode->ownerDocument = doc; rootNode->parentNode = NULL; rootNode->firstChild = rootNode->lastChild = NULL; rootNode->firstAttr = domCreateXMLNamespaceNode (rootNode); if (storeLineColumn) { lc = (domLineColumn*) ( ((char*)rootNode) + sizeof(domNode)); rootNode->nodeFlags |= HAS_LINE_COLUMN; lc->line = 0; lc->column = 0; lc->byteIndex = 0; } doc->rootNode = rootNode; return doc; } /*--------------------------------------------------------------------------- | domCreateDocument | \--------------------------------------------------------------------------*/ domDocument * domCreateDocument ( const char *uri, char *documentElementTagName ) { Tcl_HashEntry *h; int hnew; domNode *node; domDocument *doc; char prefix[MAX_PREFIX_LEN]; const char *localName; domNS *ns = NULL; if (uri) { domSplitQName (documentElementTagName, prefix, &localName); DBG(fprintf(stderr, "rootName: -->%s<--, prefix: -->%s<--, localName: -->%s<--\n", documentElementTagName, prefix, localName);); } doc = domCreateDoc (NULL, 0); h = Tcl_CreateHashEntry(&HASHTAB(doc, tdom_tagNames), documentElementTagName, &hnew); node = (domNode*) domAlloc(sizeof(domNode)); memset(node, 0, sizeof(domNode)); node->nodeType = ELEMENT_NODE; node->nodeNumber = NODE_NO(doc); node->ownerDocument = doc; node->nodeName = (char *)&(h->key); doc->documentElement = node; if (uri) { ns = domNewNamespace (doc, prefix, uri); node->namespace = ns->index; domAddNSToNode (node, ns); } doc->rootNode->firstChild = doc->rootNode->lastChild = doc->documentElement; return doc; } /*--------------------------------------------------------------------------- | domSetDocumentElement | \--------------------------------------------------------------------------*/ void domSetDocumentElement ( domDocument *doc ) { domNode *node; doc->documentElement = NULL; node = doc->rootNode->firstChild; while (node) { if (node->nodeType == ELEMENT_NODE) { doc->documentElement = node; break; } node = node->nextSibling; } if (!doc->documentElement) { doc->documentElement = doc->rootNode->firstChild; } } /*--------------------------------------------------------------------------- | domFreeNode | \--------------------------------------------------------------------------*/ void domFreeNode ( domNode * node, domFreeCallback freeCB, void * clientData, int dontfree ) { int shared = 0; domNode *child, *ctemp; domAttrNode *atemp, *attr, *aprev; Tcl_HashEntry *entryPtr; if (node == NULL) { DBG(fprintf (stderr, "null ptr in domFreeNode (dom.c) !\n");) return; } TDomThreaded ( shared = node->ownerDocument && node->ownerDocument->refCount > 1; ) /*---------------------------------------------------------------- | dontfree instruct us to walk the node tree and apply the | user-supplied callback, *w/o* actually deleting nodes. | This is normally done when a thread detaches from the | shared DOM tree and wants to garbage-collect all nodecmds | in it's interpreter which attached to the tree nodes. \---------------------------------------------------------------*/ if (dontfree) { shared = 1; } else { node->nodeFlags |= IS_DELETED; } if (node->nodeType == ATTRIBUTE_NODE && !shared) { attr = ((domAttrNode*)node)->parentNode->firstAttr; aprev = NULL; while (attr && (attr != (domAttrNode*)node)) { aprev = attr; attr = attr->nextSibling; } if (attr) { if (aprev) { aprev->nextSibling = attr->nextSibling; } else { ((domAttrNode*)node)->parentNode->firstAttr = attr->nextSibling; } FREE (attr->nodeValue); domFree ((void*)attr); } } else if (node->nodeType == ELEMENT_NODE) { child = node->lastChild; while (child) { ctemp = child->previousSibling; if (freeCB) { freeCB(child, clientData); } domFreeNode (child, freeCB, clientData, dontfree); child = ctemp; } if (shared) { return; } attr = node->firstAttr; while (attr) { atemp = attr; attr = attr->nextSibling; FREE (atemp->nodeValue); domFree ((void*)atemp); } if (node->nodeFlags & HAS_BASEURI) { entryPtr = Tcl_FindHashEntry (node->ownerDocument->baseURIs, (char*)node); if (entryPtr) { FREE ((char *) Tcl_GetHashValue (entryPtr)); Tcl_DeleteHashEntry (entryPtr); } } domFree ((void*)node); } else if (node->nodeType == PROCESSING_INSTRUCTION_NODE && !shared) { FREE (((domProcessingInstructionNode*)node)->dataValue); FREE (((domProcessingInstructionNode*)node)->targetValue); domFree ((void*)node); } else if (!shared) { FREE (((domTextNode*)node)->nodeValue); domFree ((void*)node); } } /*--------------------------------------------------------------------------- | domDeleteNode - unlinks node from tree and free all child nodes | and itself | \--------------------------------------------------------------------------*/ domException domDeleteNode ( domNode * node, domFreeCallback freeCB, void * clientData ) { TDomThreaded(int shared = 0;) domDocument *doc; if (node->nodeType == ATTRIBUTE_NODE) { domPanic("domDeleteNode on ATTRIBUTE_NODE not supported!"); } TDomThreaded ( shared = node->ownerDocument->refCount > 1; ) doc = node->ownerDocument; /*---------------------------------------------------------------- | unlink node from child or fragment list \---------------------------------------------------------------*/ if (node->previousSibling) { node->previousSibling->nextSibling = node->nextSibling; } else { if (node->parentNode) { node->parentNode->firstChild = node->nextSibling; } else { /* Node may be a top level node */ if (doc->rootNode->firstChild == node) { doc->rootNode->firstChild = node->nextSibling; } } } if (node->nextSibling) { node->nextSibling->previousSibling = node->previousSibling; } else { if (node->parentNode) { node->parentNode->lastChild = node->previousSibling; } else { /* Node may be a top level node */ if (doc->rootNode->lastChild == node) { doc->rootNode->lastChild = node->previousSibling; } } } if (doc->fragments == node) { doc->fragments = node->nextSibling; } if (!node->parentNode) { domSetDocumentElement (doc); } /*---------------------------------------------------------------- | for shared docs, append node to the delete nodes list | otherwise delete the node physically \---------------------------------------------------------------*/ if (freeCB) { freeCB(node, clientData); } TDomThreaded ( if (shared) { if (doc->deletedNodes) { node->nextSibling = doc->deletedNodes; } else { node->nextSibling = NULL; } doc->deletedNodes = node; node->nodeFlags |= IS_DELETED; } ) MutationEvent3(DOMNodeRemoved, childToRemove, node); MutationEvent2(DOMSubtreeModified, node); domFreeNode(node, freeCB, clientData, 0); return OK; } /*--------------------------------------------------------------------------- | domFreeDocument | \--------------------------------------------------------------------------*/ void domFreeDocument ( domDocument * doc, domFreeCallback freeCB, void * clientData ) { domNode *node, *next; domNS *ns; int i, dontfree = 0; Tcl_HashEntry *entryPtr; Tcl_HashSearch search; if (doc->nodeFlags & DONT_FREE) { doc->nodeFlags &= ~DONT_FREE; dontfree = 1; } /*----------------------------------------------------------- | delete main trees, including top level PIs, etc. \-----------------------------------------------------------*/ node = doc->rootNode; if (node) { if (freeCB) { freeCB(node, clientData); } domFreeNode (node, freeCB, clientData, dontfree); } /*----------------------------------------------------------- | delete fragment trees \-----------------------------------------------------------*/ node = doc->fragments; while (node) { next = node->nextSibling; if (freeCB) { freeCB(node, clientData); } domFreeNode (node, freeCB, clientData, dontfree); node = next; } if (dontfree) return; /*----------------------------------------------------------- | delete namespaces \-----------------------------------------------------------*/ for (i = 0; i <= doc->nsptr; i++) { ns = doc->namespaces[i]; FREE(ns->uri); FREE(ns->prefix); FREE ((char*) ns); } FREE ((char *)doc->namespaces); /*----------------------------------------------------------- | delete global selectNodes prefix namespace mappings \-----------------------------------------------------------*/ if (doc->prefixNSMappings) { i = 0; while (doc->prefixNSMappings[i]) { FREE (doc->prefixNSMappings[i]); i++; } FREE (doc->prefixNSMappings); } /*----------------------------------------------------------- | delete doctype info \-----------------------------------------------------------*/ if (doc->doctype) { #define DOCINFO_FREE(item) if (doc->doctype->item) FREE(doc->doctype->item) DOCINFO_FREE(systemId); DOCINFO_FREE(publicId); DOCINFO_FREE(internalSubset); DOCINFO_FREE(encoding); DOCINFO_FREE(mediaType); DOCINFO_FREE(method); if (doc->doctype->cdataSectionElements) { Tcl_DeleteHashTable (doc->doctype->cdataSectionElements); FREE (doc->doctype->cdataSectionElements); } FREE((char*) doc->doctype); } /*----------------------------------------------------------- | delete ID hash table \-----------------------------------------------------------*/ if (doc->ids) { Tcl_DeleteHashTable (doc->ids); FREE (doc->ids); } /*----------------------------------------------------------- | delete unparsed entities hash table \-----------------------------------------------------------*/ if (doc->unparsedEntities) { entryPtr = Tcl_FirstHashEntry (doc->unparsedEntities, &search); while (entryPtr) { FREE (Tcl_GetHashValue (entryPtr)); entryPtr = Tcl_NextHashEntry (&search); } Tcl_DeleteHashTable (doc->unparsedEntities); FREE (doc->unparsedEntities); } /*----------------------------------------------------------- | delete base URIs hash table \-----------------------------------------------------------*/ entryPtr = Tcl_FirstHashEntry (doc->baseURIs, &search); while (entryPtr) { FREE (Tcl_GetHashValue (entryPtr)); entryPtr = Tcl_NextHashEntry (&search); } Tcl_DeleteHashTable (doc->baseURIs); FREE (doc->baseURIs); /*----------------------------------------------------------- | delete XPath cache hash table \-----------------------------------------------------------*/ if (doc->xpathCache) { entryPtr = Tcl_FirstHashEntry (doc->xpathCache, &search); while (entryPtr) { xpathFreeAst((ast)Tcl_GetHashValue (entryPtr)); entryPtr = Tcl_NextHashEntry (&search); } Tcl_DeleteHashTable (doc->xpathCache); FREE (doc->xpathCache); } if (doc->extResolver) { FREE (doc->extResolver); } /*----------------------------------------------------------- | delete tag/attribute hash tables (for threaded builds only) \-----------------------------------------------------------*/ TDomThreaded ( { Tcl_HashEntry *entryPtr; Tcl_HashSearch search; entryPtr = Tcl_FirstHashEntry(&doc->tdom_tagNames, &search); while (entryPtr) { Tcl_DeleteHashEntry(entryPtr); entryPtr = Tcl_NextHashEntry(&search); } Tcl_DeleteHashTable(&doc->tdom_tagNames); entryPtr = Tcl_FirstHashEntry(&doc->tdom_attrNames, &search); while (entryPtr) { Tcl_DeleteHashEntry(entryPtr); entryPtr = Tcl_NextHashEntry(&search); } Tcl_DeleteHashTable(&doc->tdom_attrNames); domLocksDetach(doc); node = doc->deletedNodes; while (node) { next = node->nextSibling; domFreeNode (node, freeCB, clientData, 0); node = next; } } ) FREE ((char*)doc); } /*--------------------------------------------------------------------------- | domSetAttribute | \--------------------------------------------------------------------------*/ domAttrNode * domSetAttribute ( domNode *node, const char *attributeName, const char *attributeValue ) { domAttrNode *attr, *lastAttr; Tcl_HashEntry *h; int hnew; if (!node || node->nodeType != ELEMENT_NODE) { return NULL; } /*---------------------------------------------------- | try to find an existing attribute \---------------------------------------------------*/ attr = node->firstAttr; while (attr && strcmp(attr->nodeName, attributeName)) { attr = attr->nextSibling; } if (attr) { if (attr->nodeFlags & IS_ID_ATTRIBUTE) { h = Tcl_FindHashEntry (node->ownerDocument->ids, attr->nodeValue); if (h) { Tcl_DeleteHashEntry (h); h = Tcl_CreateHashEntry (node->ownerDocument->ids, attributeValue, &hnew); /* XXX what to do, if hnew = 0 ??? */ Tcl_SetHashValue (h, node); } } FREE (attr->nodeValue); attr->valueLength = (domLength)strlen(attributeValue); attr->nodeValue = (char*)MALLOC(attr->valueLength+1); strcpy(attr->nodeValue, attributeValue); } else { /*----------------------------------------------- | add a complete new attribute node \----------------------------------------------*/ attr = (domAttrNode*) domAlloc(sizeof(domAttrNode)); memset(attr, 0, sizeof(domAttrNode)); h = Tcl_CreateHashEntry(&HASHTAB(node->ownerDocument,tdom_attrNames), attributeName, &hnew); attr->nodeType = ATTRIBUTE_NODE; attr->nodeFlags = 0; attr->namespace = 0; attr->nodeName = (char *)&(h->key); attr->parentNode = node; attr->valueLength = (domLength)strlen(attributeValue); attr->nodeValue = (char*)MALLOC(attr->valueLength+1); strcpy(attr->nodeValue, attributeValue); if (node->firstAttr) { lastAttr = node->firstAttr; /* move to the end of the attribute list */ while (lastAttr->nextSibling) lastAttr = lastAttr->nextSibling; lastAttr->nextSibling = attr; } else { node->firstAttr = attr; } } MutationEvent(); return attr; } /*--------------------------------------------------------------------------- | domSetAttributeNS | \--------------------------------------------------------------------------*/ domAttrNode * domSetAttributeNS ( domNode *node, const char *attributeName, const char *attributeValue, const char *uri, int createNSIfNeeded ) { domAttrNode *attr, *lastAttr; Tcl_HashEntry *h; int hnew, hasUri = 1, isNSAttr = 0, isDftNS = 0; domNS *ns; char prefix[MAX_PREFIX_LEN]; const char *localName, *newLocalName; Tcl_DString dStr; DBG(fprintf (stderr, "domSetAttributeNS: attributeName %s, attributeValue %s, uri %s\n", attributeName, attributeValue, uri);) if (!node || node->nodeType != ELEMENT_NODE) { return NULL; } domSplitQName (attributeName, prefix, &localName); if (!uri || uri[0]=='\0') hasUri = 0; if (hasUri && (prefix[0] == '\0')) return NULL; if ((prefix[0] == '\0' && strcmp (localName, "xmlns")==0) || (strcmp (prefix, "xmlns")==0)) { isNSAttr = 1; createNSIfNeeded = 0; if (prefix[0] == '\0') { isDftNS = 1; ns = domLookupPrefix (node, ""); } else { ns = domLookupPrefix (node, prefix); } if (ns && (strcmp (ns->uri, attributeValue)==0)) return NULL; if (!hasUri) { uri = attributeValue; isNSAttr = 1; hasUri = 1; if (strcmp (localName, "xmlns")==0) isDftNS = 1; } else { return NULL; } } if (!hasUri) { if (prefix[0] != '\0' && strcmp (prefix, "xml")==0) { uri = "http://www.w3.org/XML/1998/namespace"; hasUri = 1; } } if (!hasUri && prefix[0] != '\0') return NULL; /*---------------------------------------------------- | try to find an existing attribute \---------------------------------------------------*/ attr = node->firstAttr; while (attr) { if (hasUri) { if (attr->nodeFlags & IS_NS_NODE) { if (isNSAttr) { if (strcmp (attributeName, attr->nodeName)==0) { break; } } } else { if (attr->namespace && !isNSAttr) { ns = domGetNamespaceByIndex (node->ownerDocument, attr->namespace); if (strcmp (uri, ns->uri)==0) { newLocalName = localName; domSplitQName (attr->nodeName, prefix, &localName); if (strcmp (newLocalName, localName)==0) break; } } } } else { if (!attr->namespace) { if (strcmp (attr->nodeName, localName)==0) break; } } attr = attr->nextSibling; } if (attr) { DBG(fprintf (stderr, "domSetAttributeNS: resetting existing attribute %s ; old value: %s\n", attr->nodeName, attr->nodeValue);) if (attr->nodeFlags & IS_ID_ATTRIBUTE) { h = Tcl_FindHashEntry (node->ownerDocument->ids, attr->nodeValue); if (h) { Tcl_DeleteHashEntry (h); h = Tcl_CreateHashEntry (node->ownerDocument->ids, attributeValue, &hnew); Tcl_SetHashValue (h, node); } } FREE (attr->nodeValue); attr->valueLength = (domLength)strlen(attributeValue); attr->nodeValue = (char*)MALLOC(attr->valueLength+1); strcpy(attr->nodeValue, attributeValue); } else { /*-------------------------------------------------------- | add a complete new attribute node \-------------------------------------------------------*/ attr = (domAttrNode*) domAlloc(sizeof(domAttrNode)); memset(attr, 0, sizeof(domAttrNode)); h = Tcl_CreateHashEntry(&HASHTAB(node->ownerDocument,tdom_attrNames), attributeName, &hnew); attr->nodeType = ATTRIBUTE_NODE; if (hasUri) { if (isNSAttr) { if (isDftNS) { ns = domLookupNamespace (node->ownerDocument, "", uri); } else { ns = domLookupNamespace (node->ownerDocument, localName, uri); } } else { ns = domLookupPrefix (node, prefix); if (ns && (strcmp (ns->uri, uri)!=0)) ns = NULL; } if (!ns) { if (isNSAttr) { if (isDftNS) { ns = domNewNamespace (node->ownerDocument, "", uri); } else { ns = domNewNamespace (node->ownerDocument, localName, uri); } } else { ns = domNewNamespace (node->ownerDocument, prefix, uri); if (createNSIfNeeded) { if (prefix[0] == '\0') { domSetAttributeNS (node, "xmlns", uri, NULL, 0); } else { Tcl_DStringInit (&dStr); Tcl_DStringAppend (&dStr, "xmlns:", 6); Tcl_DStringAppend (&dStr, prefix, -1); domSetAttributeNS (node, Tcl_DStringValue (&dStr), uri, NULL, 0); } } } } attr->namespace = ns->index; if (isNSAttr) { attr->nodeFlags = IS_NS_NODE; } } attr->nodeName = (char *)&(h->key); attr->parentNode = node; attr->valueLength = (domLength)strlen(attributeValue); attr->nodeValue = (char*)MALLOC(attr->valueLength+1); strcpy(attr->nodeValue, attributeValue); if (isNSAttr) { if (node->firstAttr && (node->firstAttr->nodeFlags & IS_NS_NODE)) { lastAttr = node->firstAttr; while (lastAttr->nextSibling && (lastAttr->nextSibling->nodeFlags & IS_NS_NODE)) { lastAttr = lastAttr->nextSibling; } attr->nextSibling = lastAttr->nextSibling; lastAttr->nextSibling = attr; } else { attr->nextSibling = node->firstAttr; node->firstAttr = attr; } } else { if (node->firstAttr) { lastAttr = node->firstAttr; /* move to the end of the attribute list */ while (lastAttr->nextSibling) lastAttr = lastAttr->nextSibling; lastAttr->nextSibling = attr; } else { node->firstAttr = attr; } } } MutationEvent(); return attr; } /*--------------------------------------------------------------------------- | domRemoveAttribute | \--------------------------------------------------------------------------*/ int domRemoveAttribute ( domNode *node, const char *attributeName ) { domAttrNode *attr, *previous = NULL; Tcl_HashEntry *h; if (!node || node->nodeType != ELEMENT_NODE) { return -1; } /*---------------------------------------------------- | try to find the attribute \---------------------------------------------------*/ attr = node->firstAttr; while (attr && strcmp(attr->nodeName, attributeName)) { previous = attr; attr = attr->nextSibling; } if (attr) { if (previous) { previous->nextSibling = attr->nextSibling; } else { attr->parentNode->firstAttr = attr->nextSibling; } if (attr->nodeFlags & IS_ID_ATTRIBUTE) { h = Tcl_FindHashEntry (node->ownerDocument->ids, attr->nodeValue); if (h) Tcl_DeleteHashEntry (h); } FREE (attr->nodeValue); MutationEvent(); domFree ((void*)attr); return 0; } return -1; } /*--------------------------------------------------------------------------- | domRemoveAttributeNS | \--------------------------------------------------------------------------*/ int domRemoveAttributeNS ( domNode *node, const char *uri, const char *localName ) { domAttrNode *attr, *previous = NULL; domNS *ns = NULL; char prefix[MAX_PREFIX_LEN]; const char *str; Tcl_HashEntry *h; if (!node || node->nodeType != ELEMENT_NODE) { return -1; } attr = node->firstAttr; while (attr) { domSplitQName (attr->nodeName, prefix, &str); if (strcmp(localName,str)==0) { ns = domGetNamespaceByIndex(node->ownerDocument, attr->namespace); if (ns && strcmp(ns->uri, uri)==0) { if (previous) { previous->nextSibling = attr->nextSibling; } else { attr->parentNode->firstAttr = attr->nextSibling; } if (attr->nodeFlags & IS_ID_ATTRIBUTE) { h = Tcl_FindHashEntry (node->ownerDocument->ids, attr->nodeValue); if (h) Tcl_DeleteHashEntry (h); } FREE (attr->nodeValue); MutationEvent(); domFree ((void*)attr); return 0; } } previous = attr; attr = attr->nextSibling; } return -1; } /*--------------------------------------------------------------------------- | __dbgAttr | \--------------------------------------------------------------------------*/ DBG( static void __dbgAttr (domAttrNode *node) { DBG(fprintf(stderr, " %s=%s", node->nodeName, node->nodeValue);) if (node->nextSibling) __dbgAttr(node->nextSibling); } ) /*--------------------------------------------------------------------------- | domSetDocument | \--------------------------------------------------------------------------*/ void domSetDocument ( domNode *node, domDocument *doc ) { domNode *child; domNS *ns, *origNS; domDocument *origDoc; domAttrNode *attr; Tcl_HashEntry *h; TDomThreaded ( int hnew; ) if (node->nodeFlags & HAS_BASEURI) { h = Tcl_FindHashEntry (node->ownerDocument->baseURIs, (char*)node); if (h) { FREE ((char *) Tcl_GetHashValue (h)); Tcl_DeleteHashEntry (h); } node->nodeFlags &= ~HAS_BASEURI; } if (node->nodeType == ELEMENT_NODE) { origDoc = node->ownerDocument; node->ownerDocument = doc; for (attr = node->firstAttr; attr != NULL; attr = attr->nextSibling) { if (attr->nodeFlags & IS_NS_NODE) { origNS = origDoc->namespaces[attr->namespace-1]; ns = domNewNamespace (doc, origNS->prefix, origNS->uri); attr->namespace = ns->index; } else if (attr->namespace) { ns = domAddNSToNode (node, origDoc->namespaces[attr->namespace-1]); if (ns) attr->namespace = ns->index; } } if (node->namespace) { ns = domAddNSToNode (node, origDoc->namespaces[node->namespace-1]); if (ns) node->namespace = ns->index; } else { ns = domAddNSToNode (node, NULL); if (ns) { node->namespace = ns->index; } } DBG(fprintf(stderr, "domSetDocument node%s ", node->nodeName); __dbgAttr(node->firstAttr); fprintf(stderr, "\n"); ) TDomThreaded ( if (origDoc != doc) { /* Make hash table entries as necessary for * tdom_tagNames and tdom_attrNames. */ h = Tcl_CreateHashEntry(&doc->tdom_tagNames, node->nodeName, &hnew); node->nodeName = (domString) &(h->key); for (attr = node->firstAttr; attr != NULL; attr = attr->nextSibling) { h = Tcl_CreateHashEntry(&doc->tdom_attrNames, attr->nodeName, &hnew); attr->nodeName = (domString) &(h->key); } } ) child = node->firstChild; while (child != NULL) { domSetDocument (child, doc); child = child->nextSibling; } } else { node->ownerDocument = doc; } DBG(fprintf(stderr, "end domSetDocument node %s\n", node->nodeName);) } /*--------------------------------------------------------------------------- | domSetNodeValue | \--------------------------------------------------------------------------*/ domException domSetNodeValue ( domNode *node, const char *nodeValue, domLength valueLen ) { domTextNode *textnode; if ((node->nodeType != TEXT_NODE) && (node->nodeType != CDATA_SECTION_NODE) && (node->nodeType != COMMENT_NODE) ) { return NO_MODIFICATION_ALLOWED_ERR; } textnode = (domTextNode*) node; FREE(textnode->nodeValue); textnode->nodeValue = MALLOC (valueLen); textnode->valueLength = valueLen; memmove(textnode->nodeValue, nodeValue, valueLen); MutationEvent(); return OK; } /* *---------------------------------------------------------------------- * * domRemoveChild -- * * This procedure implements the dom method removeChild. Removes * child from the list of children of node. * * Results: * Returns a domException: * * NOT_FOUND_ERR: Raised if the node child is not a child of node. * * OK: otherwise * * Side effects: * Alters the involved document. * *---------------------------------------------------------------------- */ domException domRemoveChild ( domNode *node, domNode *child ) { domNode *n; /* check, if node is in deed the parent of child */ if (child->parentNode != node) { /* If node is the root node of a document and child is in deed a child of this node, then child->parentNode will be NULL. In this case, we loop throu the children of node, to see, if the child is valid. */ if (node->ownerDocument->rootNode == node) { n = node->firstChild; while (n) { if (n == child) { /* child is in deed a child of node */ break; } n = n->nextSibling; } if (!n) { return NOT_FOUND_ERR; } } else { return NOT_FOUND_ERR; } } if (child->previousSibling) { child->previousSibling->nextSibling = child->nextSibling; } else { node->firstChild = child->nextSibling; } if (child->nextSibling) { child->nextSibling->previousSibling = child->previousSibling; } else { node->lastChild = child->previousSibling; } /* link child into the fragments list */ if (child->ownerDocument->fragments) { child->nextSibling = child->ownerDocument->fragments; child->ownerDocument->fragments->previousSibling = child; child->ownerDocument->fragments = child; } else { child->ownerDocument->fragments = child; child->nextSibling = NULL; } child->parentNode = NULL; child->previousSibling = NULL; MutationEvent3(DOMNodeRemoved, child, node); MutationEvent2(DOMSubtreeModified, node); return OK; } /* *---------------------------------------------------------------------- * * domAppendChild -- * * This procedure implements the dom method appendChild. Adds the * node newChild to the end of the list of children of this * node. If the newChild is already in the tree, it is first * removed. * * Results: * Returns a domException: * * HIERARCHY_REQUEST_ERR: Raised if node is of a type that does * not allow children of the type of the childToAppend node, or * if the node to append is one of node's ancestors or the * rootNode of node's document. * * NOT_SUPPORTED_ERR: Raised if the childToInsert is the rootNode * of another document or if node is a rootNode. * * OK: otherwise * * Side effects: * Alters the involved document(s). * *---------------------------------------------------------------------- */ domException domAppendChild ( domNode *node, domNode *childToAppend ) { domNode *n; if (node->nodeType != ELEMENT_NODE) { return HIERARCHY_REQUEST_ERR; } /* check, whether childToAppend is node or one of node's ancestors */ n = node; while (n) { if (n == childToAppend) { return HIERARCHY_REQUEST_ERR; } n = n->parentNode; } if (childToAppend == childToAppend->ownerDocument->rootNode) { if (childToAppend == node->ownerDocument->rootNode) { return HIERARCHY_REQUEST_ERR; } else { return NOT_SUPPORTED_ERR; } } /* unlink childToAppend */ if (childToAppend->previousSibling) { childToAppend->previousSibling->nextSibling = childToAppend->nextSibling; } else { if (childToAppend->parentNode) { childToAppend->parentNode->firstChild = childToAppend->nextSibling; } else { /* childToAppend is either out of the fragment list or a child of the rootNode of its document */ if (childToAppend->ownerDocument->fragments == childToAppend) { childToAppend->ownerDocument->fragments = childToAppend->nextSibling; } else { childToAppend->ownerDocument->rootNode->firstChild = childToAppend->nextSibling; } } } if (childToAppend->nextSibling) { childToAppend->nextSibling->previousSibling = childToAppend->previousSibling; } else { if (childToAppend->parentNode) { childToAppend->parentNode->lastChild = childToAppend->previousSibling; } else { if (childToAppend->ownerDocument->rootNode->lastChild == childToAppend) { childToAppend->ownerDocument->rootNode->lastChild = childToAppend->previousSibling; } } } if (node->lastChild) { node->lastChild->nextSibling = childToAppend; childToAppend->previousSibling = node->lastChild; } else { node->firstChild = childToAppend; childToAppend->previousSibling = NULL; } node->lastChild = childToAppend; childToAppend->nextSibling = NULL; if (!childToAppend->parentNode && (childToAppend->ownerDocument->documentElement == childToAppend)) { childToAppend->ownerDocument->documentElement = childToAppend->ownerDocument->rootNode->firstChild; } if (node == node->ownerDocument->rootNode) { childToAppend->parentNode = NULL; } else { childToAppend->parentNode = node; } if ((node->ownerDocument != childToAppend->ownerDocument) || node->ownerDocument->nsptr || childToAppend->ownerDocument->baseURIs->numEntries) { domSetDocument (childToAppend, node->ownerDocument); } node->ownerDocument->nodeFlags |= NEEDS_RENUMBERING; MutationEvent(); return OK; } /* *---------------------------------------------------------------------- * * domInsertBefore -- * * This procedure implements the dom method insertBefore. * It inserts the node childToInsert before the existing child * node referenceChild. If referenceChild is null, insert * childToInsert at the end of the list of children of node. The * arguments node and childToInsert must be non NULL. The * childToInsert is unlinked from its previous place (fragment * list or tree). * * Results: * Returns a domException: * * HIERARCHY_REQUEST_ERR: Raised if node is of a type that does * not allow children of the type of the childToInsert node, or * if the node to insert is node or one of node's ancestors or the * rootNode of node's document. * * NOT_FOUND_ERR: Raised if refChild is not a child of this node. * * NOT_SUPPORTED_ERR: Raised if the childToInsert is the rootNode * of another document or if node is a rootNode. * * OK: otherwise * * Side effects: * Alters the involved document(s). * *---------------------------------------------------------------------- */ domException domInsertBefore ( domNode *node, domNode *childToInsert, domNode *referenceChild ) { domNode *n; if (node->nodeType != ELEMENT_NODE) { return HIERARCHY_REQUEST_ERR; } /* check, if node is in deed the parent of referenceChild */ if (referenceChild) { if (referenceChild->parentNode != node) { /* If node is the root node of a document and referenceChild is in deed a child of this node, then referenceChild->parentNode will be NULL. In this case, we loop throu the children of node, to see, if the referenceChild is valid. */ if (node->ownerDocument->rootNode == node) { n = node->firstChild; while (n) { if (n == referenceChild) { /* referenceChild is in deed a child of node */ break; } n = n->nextSibling; } if (!n) { return NOT_FOUND_ERR; } } else { return NOT_FOUND_ERR; } } } if (childToInsert == referenceChild) { return OK; } /* check, whether childToInsert is one of node's ancestors */ n = node; while (n) { if (n == childToInsert) { return HIERARCHY_REQUEST_ERR; } n = n->parentNode; } if (childToInsert == childToInsert->ownerDocument->rootNode) { if (childToInsert == node->ownerDocument->rootNode) { return HIERARCHY_REQUEST_ERR; } else { /* For now, we simply don't allow the rootNode of another element as childToInsert. The way to go may be simply to treat the rootNode as DocumentFragment and to insert all children of that rootNode before the referenceChild. This would result in a document without documentElement, which then should be handled right by other methods. This is planned, but not carefully considered, yet. */ return NOT_SUPPORTED_ERR; } } /* unlink childToInsert */ if (childToInsert->previousSibling) { childToInsert->previousSibling->nextSibling = childToInsert->nextSibling; } else { if (childToInsert->parentNode) { childToInsert->parentNode->firstChild = childToInsert->nextSibling; } else { /* childToInsert is either out of the fragment list or a child of the rootNode of its document */ if (childToInsert->ownerDocument->fragments == childToInsert) { childToInsert->ownerDocument->fragments = childToInsert->nextSibling; } else { childToInsert->ownerDocument->rootNode->firstChild = childToInsert->nextSibling; } } } if (childToInsert->nextSibling) { childToInsert->nextSibling->previousSibling = childToInsert->previousSibling; } else { if (childToInsert->parentNode) { childToInsert->parentNode->lastChild = childToInsert->previousSibling; } else { if (childToInsert->ownerDocument->rootNode->lastChild == childToInsert) { childToInsert->ownerDocument->rootNode->lastChild = childToInsert->previousSibling; } } } childToInsert->nextSibling = referenceChild; if (referenceChild) { if (referenceChild->previousSibling) { childToInsert->previousSibling = referenceChild->previousSibling; referenceChild->previousSibling->nextSibling = childToInsert; } else { node->firstChild = childToInsert; childToInsert->previousSibling = NULL; } referenceChild->previousSibling = childToInsert; } else { if (node->lastChild) { node->lastChild->nextSibling = childToInsert; childToInsert->previousSibling = node->lastChild; } else { node->firstChild = childToInsert; childToInsert->previousSibling = NULL; } node->lastChild = childToInsert; } if (!childToInsert->parentNode && (childToInsert->ownerDocument->documentElement == childToInsert)) { childToInsert->ownerDocument->documentElement = childToInsert->ownerDocument->rootNode->firstChild; } if (node == node->ownerDocument->rootNode) { childToInsert->parentNode = NULL; } else { childToInsert->parentNode = node; } if (node->ownerDocument != childToInsert->ownerDocument || node->ownerDocument->nsptr || childToInsert->ownerDocument->baseURIs->numEntries) { domSetDocument (childToInsert, node->ownerDocument); } node->ownerDocument->nodeFlags |= NEEDS_RENUMBERING; MutationEvent3(DOMNodeInsert, childToInsert, node); MutationEvent2(DOMSubtreeModified, node); return OK; } /* *---------------------------------------------------------------------- * * domReplaceChild -- * * This procedure implements the dom method replaceChild. * Replaces the child node oldChild with newChild in the list of * children of node 'node'. * * Results: * Returns a domException: * * HIERARCHY_REQUEST_ERR: Raised if node is of a type that does * not allow children of the type of the newChild node, or * if newChild is node or one of node's ancestors or the * rootNode of node's document. * * NOT_FOUND_ERR: Raised if oldChild is not a child of node. * * NOT_SUPPORTED_ERR: Raised if the newChild is the rootNode * of another document. * * OK: otherwise * * Side effects: * Alters the involved document(s). * *---------------------------------------------------------------------- */ domException domReplaceChild ( domNode *node, domNode *newChild, domNode *oldChild ) { domNode *n; if (node->nodeType != ELEMENT_NODE) { return HIERARCHY_REQUEST_ERR; } /* check, if node is in deed the parent of oldChild */ if (oldChild->parentNode != node) { /* If node is the root node of a document and oldChild is in deed a child of this node, then oldChild->parentNode will be NULL. In this case, we loop throu the children of node, to see, if the oldChild is valid. */ if (node->ownerDocument->rootNode == node) { n = node->firstChild; while (n) { if (n == oldChild) { /* oldChild is in deed a child of node */ break; } n = n->nextSibling; } if (!n) { return NOT_FOUND_ERR; } } else { return NOT_FOUND_ERR; } } if (oldChild == newChild) { return OK; } /* check, whether newChild is node or one of node's ancestors */ n = node; while (n) { if (n == newChild) { return HIERARCHY_REQUEST_ERR; } n = n->parentNode; } if (newChild == newChild->ownerDocument->rootNode) { if (newChild == node->ownerDocument->rootNode) { return HIERARCHY_REQUEST_ERR; } else { return NOT_SUPPORTED_ERR; } } /* unlink newChild */ if (newChild->previousSibling) { newChild->previousSibling->nextSibling = newChild->nextSibling; } else { if (newChild->parentNode) { newChild->parentNode->firstChild = newChild->nextSibling; } else { /* newChild is either out of the fragment list or a child of the rootNode of its document */ if (newChild->ownerDocument->fragments == newChild) { newChild->ownerDocument->fragments = newChild->nextSibling; } else { newChild->ownerDocument->rootNode->firstChild = newChild->nextSibling; } } } if (newChild->nextSibling) { newChild->nextSibling->previousSibling = newChild->previousSibling; } else { if (newChild->parentNode) { newChild->parentNode->lastChild = newChild->previousSibling; } else { if (newChild->ownerDocument->rootNode->lastChild == newChild) { newChild->ownerDocument->rootNode->lastChild = newChild->previousSibling; } } } newChild->nextSibling = oldChild->nextSibling; newChild->previousSibling = oldChild->previousSibling; if (!newChild->parentNode && (newChild->ownerDocument->documentElement == newChild)) { newChild->ownerDocument->documentElement = newChild->ownerDocument->rootNode->firstChild; } if (node == node->ownerDocument->rootNode) { newChild->parentNode = NULL; } else { newChild->parentNode = node; } if (oldChild->previousSibling) { oldChild->previousSibling->nextSibling = newChild; } else { node->firstChild = newChild; } if (oldChild->nextSibling) { oldChild->nextSibling->previousSibling = newChild; } else { node->lastChild = newChild; } if (node->ownerDocument != newChild->ownerDocument || node->ownerDocument->nsptr || newChild->ownerDocument->baseURIs->numEntries) { domSetDocument (newChild, node->ownerDocument); } /* add old child into his fragment list */ if (oldChild->ownerDocument->fragments) { oldChild->nextSibling = oldChild->ownerDocument->fragments; oldChild->ownerDocument->fragments->previousSibling = oldChild; oldChild->ownerDocument->fragments = oldChild; } else { oldChild->ownerDocument->fragments = oldChild; oldChild->nextSibling = oldChild->previousSibling = NULL; } oldChild->parentNode = NULL; node->ownerDocument->nodeFlags |= NEEDS_RENUMBERING; MutationEvent(); return OK; } /*--------------------------------------------------------------------------- | domNewTextNode | \--------------------------------------------------------------------------*/ domTextNode * domNewTextNode( domDocument *doc, const char *value, domLength length, domNodeType nodeType ) { domTextNode *node; node = (domTextNode*) domAlloc(sizeof(domTextNode)); memset(node, 0, sizeof(domTextNode)); node->nodeType = nodeType; node->nodeNumber = NODE_NO(doc); node->ownerDocument = doc; node->valueLength = length; node->nodeValue = (char*)MALLOC(length); memmove(node->nodeValue, value, length); if (doc->fragments) { node->nextSibling = doc->fragments; doc->fragments->previousSibling = (domNode*)node; doc->fragments = (domNode*)node; } else { doc->fragments = (domNode*)node; } return node; } void domEscapeCData ( char *value, domLength length, Tcl_DString *escapedData ) { domLength i, start = 0; char *pc; Tcl_DStringInit (escapedData); pc = value; for (i = 0; i < length; i++) { if (*pc == '&') { Tcl_DStringAppend (escapedData, &value[start], i - start); Tcl_DStringAppend (escapedData, "&", 5); start = i+1; } else if (*pc == '<') { Tcl_DStringAppend (escapedData, &value[start], i - start); Tcl_DStringAppend (escapedData, "<", 4); start = i+1; } else if (*pc == '>') { Tcl_DStringAppend (escapedData, &value[start], i - start); Tcl_DStringAppend (escapedData, ">", 4); start = i+1; } pc++; } if (start) { Tcl_DStringAppend (escapedData, &value[start], length - start); } } /*--------------------------------------------------------------------------- | domAppendNewTextNode | \--------------------------------------------------------------------------*/ domTextNode * domAppendNewTextNode( domNode *parent, char *value, domLength length, domNodeType nodeType, int disableOutputEscaping ) { domTextNode *node; if (!length && (nodeType == TEXT_NODE)) { return NULL; } if (parent->lastChild && parent->lastChild->nodeType == TEXT_NODE && nodeType == TEXT_NODE ) { /*------------------------------------------------------------------ | append to already existing text node \-----------------------------------------------------------------*/ domAppendData ((domTextNode *) (parent->lastChild), value, length, disableOutputEscaping); MutationEvent(); return (domTextNode*)parent->lastChild; } node = (domTextNode*) domAlloc(sizeof(domTextNode)); memset(node, 0, sizeof(domTextNode)); node->nodeType = nodeType; if (disableOutputEscaping) { node->nodeFlags |= DISABLE_OUTPUT_ESCAPING; } node->nodeNumber = NODE_NO(parent->ownerDocument); node->ownerDocument = parent->ownerDocument; node->valueLength = length; node->nodeValue = (char*)MALLOC(length); memmove(node->nodeValue, value, length); if (parent->lastChild) { parent->lastChild->nextSibling = (domNode*)node; node->previousSibling = parent->lastChild; } else { parent->firstChild = (domNode*)node; node->previousSibling = NULL; } parent->lastChild = (domNode*)node; node->nextSibling = NULL; if (parent != parent->ownerDocument->rootNode) { node->parentNode = parent; } MutationEvent(); return node; } /*--------------------------------------------------------------------------- | domAppendNewElementNode | \--------------------------------------------------------------------------*/ domNode * domAppendNewElementNode( domNode *parent, const char *tagName, const char *uri ) { Tcl_HashEntry *h; domNode *node; domNS *ns; domAttrNode *NSattr; int hnew; char prefix[MAX_PREFIX_LEN]; const char *localname; Tcl_DString dStr; if (parent == NULL) { DBG(fprintf(stderr, "dom.c: Error parent == NULL!\n");) return NULL; } h = Tcl_CreateHashEntry(&HASHTAB(parent->ownerDocument,tdom_tagNames), tagName, &hnew); node = (domNode*) domAlloc(sizeof(domNode)); memset(node, 0, sizeof(domNode)); node->nodeType = ELEMENT_NODE; node->nodeNumber = NODE_NO(parent->ownerDocument); node->ownerDocument = parent->ownerDocument; node->nodeName = (char *)&(h->key); if (parent->lastChild) { parent->lastChild->nextSibling = node; node->previousSibling = parent->lastChild; } else { parent->firstChild = node; node->previousSibling = NULL; } parent->lastChild = node; node->nextSibling = NULL; if (parent != parent->ownerDocument->rootNode) { node->parentNode = parent; } /*-------------------------------------------------------- | reuse existing namespace or create a new one \-------------------------------------------------------*/ if (uri) { domSplitQName (tagName, prefix, &localname); DBG(fprintf(stderr, "tag '%s' has prefix='%s' \n", tagName, prefix);) ns = domLookupPrefix (node, prefix); if (!ns || (strcmp (uri, ns->uri)!=0)) { ns = domNewNamespace(node->ownerDocument, prefix, uri); if (prefix[0] == '\0') { domSetAttributeNS (node, "xmlns", uri, NULL, 1); } else { Tcl_DStringInit (&dStr); Tcl_DStringAppend (&dStr, "xmlns:", 6); Tcl_DStringAppend (&dStr, prefix, -1); domSetAttributeNS (node, Tcl_DStringValue (&dStr), uri, NULL, 1); } } node->namespace = ns->index; } else { ns = domLookupPrefix (node, ""); if (ns) { if (strcmp (ns->uri, "")!=0) { NSattr = domSetAttributeNS (node, "xmlns", "", NULL, 1); if (NSattr) { node->namespace = NSattr->namespace; } } else { node->namespace = ns->index; } } } MutationEvent(); return node; } /* *---------------------------------------------------------------------- * * domAppendData -- * * This procedure implements the dom method appendData. It is * also used by domNormalize and domAppendNewTextNode. * * Results: * A domException; currently always OK. * * Side effects: * Appends the data to node. * *---------------------------------------------------------------------- */ domException domAppendData ( domTextNode *node, /* The node, to append value to. Must be a TEXT_NODE, COMMENT_NODE or CDATA_SECTION_NODE*/ char *value, /* The data to append */ domLength length, /* The length of value in byte */ int disableOutputEscaping /* If true, disable output escaping on the node */ ) { Tcl_DString escData; if (node->nodeFlags & DISABLE_OUTPUT_ESCAPING) { if (disableOutputEscaping) { node->nodeValue = REALLOC (node->nodeValue, node->valueLength + length); memmove (node->nodeValue + node->valueLength, value, length); node->valueLength += length; } else { domEscapeCData (value, length, &escData); if (Tcl_DStringLength (&escData)) { node->nodeValue = REALLOC (node->nodeValue, node->valueLength + Tcl_DStringLength (&escData)); memmove (node->nodeValue + node->valueLength, Tcl_DStringValue (&escData), Tcl_DStringLength (&escData)); node->valueLength += Tcl_DStringLength (&escData); } else { node->nodeValue = REALLOC (node->nodeValue, node->valueLength+length); memmove (node->nodeValue + node->valueLength, value, length); node->valueLength += length; } Tcl_DStringFree (&escData); } } else { if (disableOutputEscaping) { node->nodeFlags |= DISABLE_OUTPUT_ESCAPING; domEscapeCData (node->nodeValue, node->valueLength, &escData); if (Tcl_DStringLength (&escData)) { FREE (node->nodeValue); node->nodeValue = MALLOC (Tcl_DStringLength (&escData) + length); memmove (node->nodeValue, Tcl_DStringValue (&escData), Tcl_DStringLength (&escData)); node->valueLength = Tcl_DStringLength (&escData); } else { node->nodeValue = REALLOC (node->nodeValue, node->valueLength+length); } Tcl_DStringFree (&escData); } else { node->nodeValue = REALLOC (node->nodeValue, node->valueLength + length); } memmove (node->nodeValue + node->valueLength, value, length); node->valueLength += length; } return OK; } /* *---------------------------------------------------------------------- * * domNormalize -- * * This procedure implements the dom method normalize. Puts all * Text nodes in the full depth of the sub-tree underneath node, * including attribute nodes, into a "normal" form where only * structure (e.g., elements, comments, processing instructions, * CDATA sections, and entity references) separates Text nodes, * i.e., there are neither adjacent Text nodes nor empty Text * nodes. If the flag forXPath is true, then CDATASection nodes * are treated as if they are text nodes (and merged with * circumjacent text nodes). Node must be an ELEMENT_NODE. * * Results: * None. * * Side effects: * May alter the tree. * *---------------------------------------------------------------------- */ void domNormalize ( domNode *node, /* root of the sub-tree to normalize */ int forXPath, /* if true, treat CDATA_SECTION_NODEs as if they where TEXT_NODEs */ domFreeCallback freeCB, /* Function to call, if a node must be freed */ void *clientData /* ClientData, to provide to the freeCB */ ) { domNode *child, *nextChild; int merge = 0; if (node->nodeType != ELEMENT_NODE) return; child = node->firstChild; while (child) { merge = 0; switch (child->nodeType) { case ELEMENT_NODE: domNormalize (child, forXPath, freeCB, clientData); break; case TEXT_NODE: if (child->previousSibling && child->previousSibling->nodeType == TEXT_NODE) { merge = 1; } else { if (((domTextNode *)child)->valueLength == 0) { nextChild = child->nextSibling; domDeleteNode (child, freeCB, clientData); child = nextChild; continue; } } break; case CDATA_SECTION_NODE: if (forXPath) { if (child->previousSibling && child->previousSibling->nodeType == TEXT_NODE) { merge = 1; } else { if (((domTextNode *)child)->valueLength == 0) { nextChild = child->nextSibling; domDeleteNode (child, freeCB, clientData); child = nextChild; continue; } child->nodeType = TEXT_NODE; } } break; default: break; } if (merge) { domAppendData ( (domTextNode *)(child->previousSibling), ((domTextNode *)child)->nodeValue, ((domTextNode *)child)->valueLength, (child->nodeFlags & DISABLE_OUTPUT_ESCAPING) ); nextChild = child->nextSibling; domDeleteNode (child, freeCB, clientData); child = nextChild; } else { child = child->nextSibling; } } } /*--------------------------------------------------------------------------- | domAddNSToNode | \--------------------------------------------------------------------------*/ domNS * domAddNSToNode ( domNode *node, domNS *nsToAdd ) { domAttrNode *attr, *lastNSAttr; domNS *ns, noNS; Tcl_HashEntry *h; int hnew; Tcl_DString dStr; if (!nsToAdd) { noNS.uri = ""; noNS.prefix = ""; noNS.index = 0; nsToAdd = &noNS; } DBG(fprintf (stderr, "domAddNSToNode to node '%s': prefix: %s, uri: %s\n", node->nodeName, nsToAdd->prefix, nsToAdd->uri);) ns = domLookupPrefix (node, nsToAdd->prefix); if (ns) { if (strcmp (ns->uri, nsToAdd->uri)==0) { /* namespace already in scope, we're done. */ return ns; } } else { /* If the NS to set was no NS and there isn't a default NS we're done */ if (nsToAdd->prefix[0] == '\0' && nsToAdd->uri[0] == '\0') return NULL; } ns = domNewNamespace (node->ownerDocument, nsToAdd->prefix, nsToAdd->uri); Tcl_DStringInit (&dStr); if (nsToAdd->prefix[0] == '\0') { Tcl_DStringAppend (&dStr, "xmlns", 5); } else { Tcl_DStringAppend (&dStr, "xmlns:", 6); Tcl_DStringAppend (&dStr, nsToAdd->prefix, -1); } /* Add new namespace attribute */ attr = (domAttrNode*) domAlloc(sizeof(domAttrNode)); memset(attr, 0, sizeof(domAttrNode)); h = Tcl_CreateHashEntry(&HASHTAB(node->ownerDocument,tdom_attrNames), Tcl_DStringValue(&dStr), &hnew); attr->nodeType = ATTRIBUTE_NODE; attr->nodeFlags = IS_NS_NODE; attr->namespace = ns->index; attr->nodeName = (char *)&(h->key); attr->parentNode = node; attr->valueLength = (domLength)strlen(nsToAdd->uri); attr->nodeValue = (char*)MALLOC(attr->valueLength+1); strcpy(attr->nodeValue, nsToAdd->uri); lastNSAttr = NULL; if (node->firstAttr && (node->firstAttr->nodeFlags & IS_NS_NODE)) { lastNSAttr = node->firstAttr; while (lastNSAttr->nextSibling && (lastNSAttr->nextSibling->nodeFlags & IS_NS_NODE)) { lastNSAttr = lastNSAttr->nextSibling; } } if (lastNSAttr) { attr->nextSibling = lastNSAttr->nextSibling; lastNSAttr->nextSibling = attr; } else { attr->nextSibling = node->firstAttr; node->firstAttr = attr; } Tcl_DStringFree (&dStr); return ns; } /*--------------------------------------------------------------------------- | domAppendLiteralNode | \--------------------------------------------------------------------------*/ domNode * domAppendLiteralNode( domNode *parent, domNode *literalNode ) { Tcl_HashEntry *h; domNode *node; int hnew; if (parent == NULL) { DBG(fprintf(stderr, "dom.c: Error parent == NULL!\n");) return NULL; } h = Tcl_CreateHashEntry(&HASHTAB(parent->ownerDocument, tdom_tagNames), literalNode->nodeName, &hnew); node = (domNode*) domAlloc(sizeof(domNode)); memset(node, 0, sizeof(domNode)); node->nodeType = ELEMENT_NODE; node->nodeNumber = NODE_NO(parent->ownerDocument); node->ownerDocument = parent->ownerDocument; node->nodeName = (char *)&(h->key); if (parent->lastChild) { parent->lastChild->nextSibling = node; node->previousSibling = parent->lastChild; } else { parent->firstChild = node; node->previousSibling = NULL; } parent->lastChild = node; node->nextSibling = NULL; if (parent != parent->ownerDocument->rootNode) { node->parentNode = parent; } MutationEvent(); return node; } /*--------------------------------------------------------------------------- | domNewProcessingInstructionNode | \--------------------------------------------------------------------------*/ domProcessingInstructionNode * domNewProcessingInstructionNode( domDocument *doc, const char *targetValue, domLength targetLength, const char *dataValue, domLength dataLength ) { domProcessingInstructionNode *node; node = (domProcessingInstructionNode*) domAlloc(sizeof(domProcessingInstructionNode)); memset(node, 0, sizeof(domProcessingInstructionNode)); node->nodeType = PROCESSING_INSTRUCTION_NODE; node->nodeNumber = NODE_NO(doc); node->ownerDocument = doc; node->targetLength = targetLength; node->targetValue = (char*)MALLOC(targetLength); memmove(node->targetValue, targetValue, targetLength); node->dataLength = dataLength; node->dataValue = (char*)MALLOC(dataLength); memmove(node->dataValue, dataValue, dataLength); if (doc->fragments) { node->nextSibling = doc->fragments; doc->fragments->previousSibling = (domNode*)node; doc->fragments = (domNode*)node; } else { doc->fragments = (domNode*)node; } MutationEvent(); return node; } /*--------------------------------------------------------------------------- | domNewElementNode | \--------------------------------------------------------------------------*/ domNode * domNewElementNode( domDocument *doc, const char *tagName ) { domNode *node; Tcl_HashEntry *h; int hnew; h = Tcl_CreateHashEntry(&HASHTAB(doc, tdom_tagNames), tagName, &hnew); node = (domNode*) domAlloc(sizeof(domNode)); memset(node, 0, sizeof(domNode)); node->nodeType = ELEMENT_NODE; node->nodeNumber = NODE_NO(doc); node->ownerDocument = doc; node->nodeName = (char *)&(h->key); if (doc->fragments) { node->nextSibling = doc->fragments; doc->fragments->previousSibling = node; doc->fragments = node; } else { doc->fragments = node; } return node; } /*--------------------------------------------------------------------------- | domNewElementNodeNS | \--------------------------------------------------------------------------*/ domNode * domNewElementNodeNS ( domDocument *doc, const char *tagName, const char *uri ) { domNode *node; Tcl_HashEntry *h; int hnew; char prefix[MAX_PREFIX_LEN]; const char *localname; domNS *ns; domSplitQName (tagName, prefix, &localname); if (prefix[0] == '\0' && uri[0] == '\0') { return NULL; } h = Tcl_CreateHashEntry(&HASHTAB(doc, tdom_tagNames), tagName, &hnew); node = (domNode*) domAlloc(sizeof(domNode)); memset(node, 0, sizeof(domNode)); node->nodeType = ELEMENT_NODE; node->nodeNumber = NODE_NO(doc); node->ownerDocument = doc; node->nodeName = (char *)&(h->key); ns = domNewNamespace(doc, prefix, uri); node->namespace = ns->index; if (doc->fragments) { node->nextSibling = doc->fragments; doc->fragments->previousSibling = node; doc->fragments = node; } else { doc->fragments = node; } return node; } /*--------------------------------------------------------------------------- | domCloneNode | \--------------------------------------------------------------------------*/ domNode * domCloneNode ( domNode *node, int deep ) { domAttrNode *attr, *nattr; domNode *n, *child, *newChild; /*------------------------------------------------------------------ | create new node \-----------------------------------------------------------------*/ if (node->nodeType == PROCESSING_INSTRUCTION_NODE) { domProcessingInstructionNode *pinode = (domProcessingInstructionNode*)node; return (domNode*) domNewProcessingInstructionNode( pinode->ownerDocument, pinode->targetValue, pinode->targetLength, pinode->dataValue, pinode->dataLength); } if (node->nodeType != ELEMENT_NODE) { domTextNode *t1node, *tnode = (domTextNode*)node; t1node = domNewTextNode(tnode->ownerDocument, tnode->nodeValue, tnode->valueLength, tnode->nodeType); t1node->info = tnode->info; t1node->nodeFlags = tnode->nodeFlags; return (domNode*) t1node; } n = domNewElementNode(node->ownerDocument, node->nodeName); n->namespace = node->namespace; n->info = node->info; /*------------------------------------------------------------------ | copy attributes (if any) \-----------------------------------------------------------------*/ attr = node->firstAttr; while (attr != NULL) { nattr = domSetAttribute (n, attr->nodeName, attr->nodeValue ); nattr->namespace = attr->namespace; nattr->nodeFlags = attr->nodeFlags; attr = attr->nextSibling; } if (deep) { child = node->firstChild; while (child) { newChild = domCloneNode(child, deep); /* append new (cloned)child to cloned node, its new parent. Don't use domAppendChild for this, because that would mess around with the namespaces */ if (n->ownerDocument->fragments->nextSibling) { n->ownerDocument->fragments = n->ownerDocument->fragments->nextSibling; n->ownerDocument->fragments->previousSibling = NULL; newChild->nextSibling = NULL; } else { n->ownerDocument->fragments = NULL; } if (n->firstChild) { newChild->previousSibling = n->lastChild; n->lastChild->nextSibling = newChild; } else { n->firstChild = newChild; } n->lastChild = newChild; newChild->parentNode = n; /* clone next child */ child = child->nextSibling; } } return n; } /*---------------------------------------------------------------------------- | domCopyNS | \---------------------------------------------------------------------------*/ void domCopyNS ( domNode *from, domNode *to ) { domNode *n, *n1; domNS *ns, *ns1; domAttrNode *attr, *attr1; int skip; n = from; while (n) { attr = n->firstAttr; while (attr && (attr->nodeFlags & IS_NS_NODE)) { ns = n->ownerDocument->namespaces[attr->namespace-1]; skip = 0; n1 = from; while (n1 != n) { attr1 = n1->firstAttr; while (attr1 && (attr1->nodeFlags & IS_NS_NODE)) { ns1 = n1->ownerDocument->namespaces[attr1->namespace-1]; if ((ns1->prefix == NULL && ns->prefix == NULL) || (strcmp (ns1->prefix, ns->prefix)==0)) { skip = 1; break; } attr1 = attr1->nextSibling; } if (skip) break; n1 = n1->parentNode; } if (!skip) { /* Add this prefix/uri combination only to the destination, if it isn't already in scope */ ns1 = domLookupPrefix (to, ns->prefix); if (!ns1 || (strcmp (ns->uri, ns1->uri)!=0)) { domAddNSToNode (to, ns); } } attr = attr->nextSibling; } n = n->parentNode; } } /*--------------------------------------------------------------------------- | domCopyTo | \--------------------------------------------------------------------------*/ void domCopyTo ( domNode *node, domNode *parent, int copyNS ) { domAttrNode *attr, *nattr; domNode *n, *child; domNS *ns, *ns1; /*------------------------------------------------------------------ | create new node \-----------------------------------------------------------------*/ if (node->nodeType == PROCESSING_INSTRUCTION_NODE) { domProcessingInstructionNode *pinode = (domProcessingInstructionNode*)node; n = (domNode*) domNewProcessingInstructionNode( parent->ownerDocument, pinode->targetValue, pinode->targetLength, pinode->dataValue, pinode->dataLength); domAppendChild (parent, n); return; } if (node->nodeType != ELEMENT_NODE) { domTextNode *tnode = (domTextNode*)node; n = (domNode*) domNewTextNode(parent->ownerDocument, tnode->nodeValue, tnode->valueLength, tnode->nodeType); domAppendChild (parent, n); return; } n = domAppendLiteralNode (parent, node); if (copyNS) { domCopyNS (node, n); } /*------------------------------------------------------------------ | copy attributes (if any) \-----------------------------------------------------------------*/ attr = node->firstAttr; while (attr != NULL) { if (attr->nodeFlags & IS_NS_NODE) { if (copyNS) { /* If copyNS is true, then all namespaces in scope * (including the one declared with the node to copy) * are already copied over. */ attr = attr->nextSibling; continue; } ns = node->ownerDocument->namespaces[attr->namespace-1]; ns1 = domLookupPrefix (n, ns->prefix); if (ns1 && strcmp (ns->uri, ns1->uri)==0) { /* This namespace is already in scope, so we don't copy the namespace attribute over */ attr = attr->nextSibling; continue; } nattr = domSetAttribute (n, attr->nodeName, attr->nodeValue ); nattr->nodeFlags = attr->nodeFlags; ns1 = domNewNamespace (n->ownerDocument, ns->prefix, ns->uri); nattr->namespace = ns1->index; } else { nattr = domSetAttribute (n, attr->nodeName, attr->nodeValue ); nattr->nodeFlags = attr->nodeFlags; if (attr->namespace) { ns = node->ownerDocument->namespaces[attr->namespace-1]; ns1 = domLookupPrefix (n, ns->prefix); if (ns1) { nattr->namespace = ns1->index; } } } attr = attr->nextSibling; } /* We have to set the node namespace index after copying the attribute nodes over, because the node may be in a namespace, which is declared just at the node. */ if (node->namespace) { ns = node->ownerDocument->namespaces[node->namespace-1]; ns1 = domLookupPrefix (n, ns->prefix); n->namespace = ns1->index; } child = node->firstChild; while (child) { domCopyTo(child, n, 0); child = child->nextSibling; } } /*--------------------------------------------------------------------------- | domXPointerChild | \--------------------------------------------------------------------------*/ int domXPointerChild ( domNode * node, int all, int instance, domNodeType type, char * element, char * attrName, char * attrValue, domLength attrLen, domAddCallback addCallback, void * clientData ) { domNode *child; domAttrNode *attr; int i=0, result; if (node->nodeType != ELEMENT_NODE) { return 0; } if (instance<0) { child = node->lastChild; } else { child = node->firstChild; } while (child) { if ((type == ALL_NODES) || (child->nodeType == type)) { if ((element == NULL) || ((child->nodeType == ELEMENT_NODE) && (strcmp(child->nodeName,element)==0)) ) { if (attrName == NULL) { i = (instance<0) ? i-1 : i+1; if (all || (i == instance)) { result = addCallback (child, clientData); if (result) { return result; } } } else { attr = child->firstAttr; while (attr) { if ((strcmp(attr->nodeName,attrName)==0) && ( (strcmp(attrValue,"*")==0) || ( (attr->valueLength == attrLen) && (strcmp(attr->nodeValue,attrValue)==0) ) ) ) { i = (instance<0) ? i-1 : i+1; if (all || (i == instance)) { result = addCallback (child, clientData); if (result) { return result; } } } attr = attr->nextSibling; } } } } if (instance<0) { child = child->previousSibling; } else { child = child->nextSibling; } } return 0; } /*--------------------------------------------------------------------------- | domXPointerXSibling | \--------------------------------------------------------------------------*/ int domXPointerXSibling ( domNode * node, int forward_mode, int all, int instance, domNodeType type, char * element, char * attrName, char * attrValue, domLength attrLen, domAddCallback addCallback, void * clientData ) { domNode *sibling, *endSibling; domAttrNode *attr; int i=0, result; if (forward_mode) { if (instance<0) { endSibling = node; sibling = node; if (node->parentNode) { sibling = node->parentNode->lastChild; } } else { sibling = node->nextSibling; endSibling = NULL; } } else { if (instance<0) { endSibling = node; sibling = node; if (node->parentNode) { sibling = node->parentNode->firstChild; } } else { sibling = node->previousSibling; endSibling = NULL; } instance = -1 * instance; } while (sibling != endSibling) { if ((type == ALL_NODES) || (sibling->nodeType == type)) { if ((element == NULL) || ((sibling->nodeType == ELEMENT_NODE) && (strcmp(sibling->nodeName,element)==0)) ) { if (attrName == NULL) { i = (instance<0) ? i-1 : i+1; if (all || (i == instance)) { result = addCallback (sibling, clientData); if (result) { return result; } } } else { attr = sibling->firstAttr; while (attr) { if ((strcmp(attr->nodeName,attrName)==0) && ( (strcmp(attrValue,"*")==0) || ( (attr->valueLength == attrLen) && (strcmp(attr->nodeValue,attrValue)==0) ) ) ) { i = (instance<0) ? i-1 : i+1; if (all || (i == instance)) { result = addCallback (sibling, clientData); if (result) { return result; } } } attr = attr->nextSibling; } } } } if (instance<0) { sibling = sibling->previousSibling; } else { sibling = sibling->nextSibling; } } return 0; } /*--------------------------------------------------------------------------- | domXPointerDescendant | \--------------------------------------------------------------------------*/ int domXPointerDescendant ( domNode * node, int all, int instance, int * i, domNodeType type, char * element, char * attrName, char * attrValue, domLength attrLen, domAddCallback addCallback, void * clientData ) { domNode *child; domAttrNode *attr; int found=0, result; if (node->nodeType != ELEMENT_NODE) { return 0; } if (instance<0) { child = node->lastChild; } else { child = node->firstChild; } while (child) { found = 0; if ((type == ALL_NODES) || (child->nodeType == type)) { if ((element == NULL) || ((child->nodeType == ELEMENT_NODE) && (strcmp(child->nodeName,element)==0)) ) { if (attrName == NULL) { *i = (instance<0) ? (*i)-1 : (*i)+1; if (all || (*i == instance)) { result = addCallback (child, clientData); if (result) { return result; } found = 1; } } else { attr = child->firstAttr; while (attr) { if ((strcmp(attr->nodeName,attrName)==0) && ( (strcmp(attrValue,"*")==0) || ( (attr->valueLength == attrLen) && (strcmp(attr->nodeValue,attrValue)==0) ) ) ) { *i = (instance<0) ? (*i)-1 : (*i)+1; if (all || (*i == instance)) { result = addCallback (child, clientData); if (result) { return result; } found = 1; } } attr = attr->nextSibling; } } } } if (!found) { /* recurs into children */ result = domXPointerDescendant (child, all, instance, i, type, element, attrName, attrValue, attrLen, addCallback, clientData); if (result) { return result; } } if (instance<0) { child = child->previousSibling; } else { child = child->nextSibling; } } return 0; } /*--------------------------------------------------------------------------- | domXPointerAncestor | \--------------------------------------------------------------------------*/ int domXPointerAncestor ( domNode * node, int all, int instance, int * i, domNodeType type, char * element, char * attrName, char * attrValue, domLength attrLen, domAddCallback addCallback, void * clientData ) { domNode *ancestor; domAttrNode *attr; int result; ancestor = node->parentNode; if (ancestor) { if ((type == ALL_NODES) || (ancestor->nodeType == type)) { if ((element == NULL) || ((ancestor->nodeType == ELEMENT_NODE) && (strcmp(ancestor->nodeName,element)==0)) ) { if (attrName == NULL) { *i = (instance<0) ? (*i)-1 : (*i)+1; if (all || (*i == instance)) { result = addCallback (ancestor, clientData); if (result) { return result; } } } else { attr = ancestor->firstAttr; while (attr) { if ((strcmp(attr->nodeName,attrName)==0) && ( (strcmp(attrValue,"*")==0) || ( (attr->valueLength == attrLen) && (strcmp(attr->nodeValue,attrValue)==0) ) ) ) { *i = (instance<0) ? (*i)-1 : (*i)+1; if (all || (*i == instance)) { result = addCallback (ancestor, clientData); if (result) { return result; } } } attr = attr->nextSibling; } } } } /* go up */ result = domXPointerAncestor (ancestor, all, instance, i, type, element, attrName, attrValue, attrLen, addCallback, clientData); if (result) { return result; } } return 0; } /*--------------------------------------------------------------------------- | type tdomCmdReadInfo | \--------------------------------------------------------------------------*/ /* The struct members until the tdom cmd specific elements must be the * same as for domReadInfo. */ typedef struct _tdomCmdReadInfo { XML_Parser parser; domDocument *document; domNode *currentNode; int depth; int ignoreWhiteSpaces; int cdataSection; Tcl_DString *cdata; int storeLineColumn; domLength textStartLine; domLength textStartColumn; domLength textStartByteIndex; int ignorexmlns; int feedbackAfter; Tcl_Obj *feedbackCmd; XML_Index nextFeedbackPosition; Tcl_Interp *interp; int activeNSsize; int activeNSpos; domActiveNS *activeNS; int baseURIstackSize; int baseURIstackPos; domActiveBaseURI *baseURIstack; int insideDTD; #ifndef TDOM_NO_SCHEMA SchemaData *sdata; #endif int status; /* Now the tdom cmd specific elements */ int tdomStatus; Tcl_Obj *extResolver; TclGenExpatInfo *expatinfo; /* Use read-only ! */ } tdomCmdReadInfo; int tcldom_returnDocumentObj (Tcl_Interp *interp, domDocument *document, Tcl_Obj *var_name, int trace, int forOwnerDocument); void tdom_freeProc ( Tcl_Interp *UNUSED(interp), void *userData ) { tdomCmdReadInfo *info = (tdomCmdReadInfo *) userData; if (info->document) { domFreeDocument (info->document, NULL, NULL); } if (info->activeNS) { FREE (info->activeNS); } if (info->baseURIstack) { FREE (info->baseURIstack); } Tcl_DStringFree (info->cdata); FREE (info->cdata); if (info->extResolver) { Tcl_DecrRefCount (info->extResolver); } FREE (info); } void tdom_parserResetProc ( XML_Parser parser, void *userData ) { tdomCmdReadInfo *info = (tdomCmdReadInfo *) userData; info->parser = parser; } void tdom_resetProc ( Tcl_Interp *interp, void *userData ) { tdomCmdReadInfo *info = (tdomCmdReadInfo *) userData; if (!info->tdomStatus) return; if (info->document) { domFreeDocument (info->document, NULL, NULL); } info->document = NULL; info->currentNode = NULL; info->depth = 0; info->feedbackAfter = 0; info->ignorexmlns = 0; Tcl_DStringSetLength (info->cdata, 0); info->textStartLine = 0; info->nextFeedbackPosition = info->feedbackAfter; info->interp = interp; info->activeNSpos = -1; info->insideDTD = 0; info->baseURIstackPos = 0; info->tdomStatus = 0; } void tdom_initParseProc ( Tcl_Interp *UNUSED(interp), void *userData ) { tdomCmdReadInfo *info = (tdomCmdReadInfo *) userData; info->document = domCreateDoc(XML_GetBase (info->parser), info->storeLineColumn); if (info->extResolver) { info->document->extResolver = tdomstrdup (Tcl_GetString (info->extResolver)); } info->baseURIstack[0].baseURI = XML_GetBase (info->parser); info->baseURIstack[0].depth = 0; info->tdomStatus = 2; info->status = 0; info->expatinfo->cdataStartLine = 0; } static void tdom_charDataHandler ( void *userData, const char *s, domLength len ) { tdomCmdReadInfo *info = (tdomCmdReadInfo *) userData; Tcl_DStringAppend (info->cdata, s, len); if (info->storeLineColumn) { if (!info->textStartLine) { info->textStartLine = info->expatinfo->cdataStartLine; info->textStartColumn = info->expatinfo->cdataStartColumn; info->textStartByteIndex = info->expatinfo->cdataStartByteIndex; } } DispatchPCDATA ((domReadInfo*) info); return; } static void tdom_startCDATA ( void *userData ) { tdomCmdReadInfo *info = (tdomCmdReadInfo *) userData; DispatchPCDATA ((domReadInfo*) info); info->cdataSection = 1; if (info->storeLineColumn) { info->textStartLine = (domLength)XML_GetCurrentLineNumber (info->parser); info->textStartColumn = (domLength)XML_GetCurrentColumnNumber (info->parser); info->textStartByteIndex = (domLength)XML_GetCurrentByteIndex (info->parser); } } int TclTdomObjCmd ( ClientData UNUSED(dummy), Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] ) { CHandlerSet *handlerSet; int methodIndex, result, boolVal; tdomCmdReadInfo *info; TclGenExpatInfo *expat; Tcl_Obj *newObjName = NULL; static const char *tdomMethods[] = { "enable", "getdoc", "setStoreLineColumn", "setExternalEntityResolver", "keepEmpties", "remove", "ignorexmlns", "keepCDATA", "keepTextStart", NULL }; enum tdomMethod { m_enable, m_getdoc, m_setStoreLineColumn, m_setExternalEntityResolver, m_keepEmpties, m_remove, m_ignorexmlns, m_keepCDATA, m_keepTextStart }; if (objc < 3 || objc > 4) { Tcl_WrongNumArgs (interp, 1, objv, tdom_usage); return TCL_ERROR; } if (!CheckExpatParserObj (interp, objv[1])) { Tcl_SetResult (interp, "First argument has to be a expat parser object", NULL); return TCL_ERROR; } if (Tcl_GetIndexFromObj (interp, objv[2], tdomMethods, "method", 0, &methodIndex) != TCL_OK) { Tcl_SetResult (interp, tdom_usage, NULL); return TCL_ERROR; } switch ((enum tdomMethod) methodIndex) { default: Tcl_SetResult (interp, "unknown method", NULL); return TCL_ERROR; case m_enable: expat = GetExpatInfo (interp, objv[1]); if (expat->parsingState != 0) { Tcl_SetResult (interp, "Parser is not in init or reset state.", NULL); return TCL_ERROR; } handlerSet = CHandlerSetCreate ("tdom"); handlerSet->ignoreWhiteCDATAs = 1; handlerSet->resetProc = tdom_resetProc; handlerSet->freeProc = tdom_freeProc; handlerSet->parserResetProc = tdom_parserResetProc; handlerSet->initParseProc = tdom_initParseProc; handlerSet->elementstartcommand = startElement; handlerSet->elementendcommand = endElement; handlerSet->datacommand = tdom_charDataHandler; handlerSet->commentCommand = commentHandler; handlerSet->picommand = processingInstructionHandler; handlerSet->entityDeclCommand = entityDeclHandler; handlerSet->startDoctypeDeclCommand = startDoctypeDeclHandler; handlerSet->endDoctypeDeclCommand = endDoctypeDeclHandler; info = (tdomCmdReadInfo *) MALLOC (sizeof (tdomCmdReadInfo)); memset(info, 0, sizeof(tdomCmdReadInfo)); info->parser = expat->parser; info->ignoreWhiteSpaces = 1; info->cdata = (Tcl_DString*) MALLOC (sizeof (Tcl_DString)); Tcl_DStringInit (info->cdata); info->interp = interp; info->activeNSpos = -1; info->activeNSsize = 8; info->activeNS = (domActiveNS*) MALLOC(sizeof(domActiveNS) * info->activeNSsize); info->baseURIstackSize = INITIAL_BASEURISTACK_SIZE; info->baseURIstack = (domActiveBaseURI*) MALLOC (sizeof(domActiveBaseURI) * info->baseURIstackSize); info->expatinfo = expat; handlerSet->userData = info; CHandlerSetInstall (interp, objv[1], handlerSet); break; case m_getdoc: info = CHandlerSetGetUserData (interp, objv[1], "tdom"); if (!info) { Tcl_SetResult (interp, "parser object isn't tdom enabled.", NULL); return TCL_ERROR; } expat = GetExpatInfo (interp, objv[1]); if (info->tdomStatus != 2 || !expat->finished) { Tcl_SetResult (interp, "No DOM tree available.", NULL); return TCL_ERROR; } domSetDocumentElement (info->document); result = tcldom_returnDocumentObj (interp, info->document, newObjName, 0, 0); info->document = NULL; return result; case m_setStoreLineColumn: info = CHandlerSetGetUserData (interp, objv[1], "tdom"); if (!info) { Tcl_SetResult (interp, "parser object isn't tdom enabled.", NULL); return TCL_ERROR; } Tcl_SetIntObj (Tcl_GetObjResult (interp), info->storeLineColumn); if (objc == 4) { if (Tcl_GetBooleanFromObj (interp, objv[3], &boolVal) != TCL_OK) { return TCL_ERROR; } info->storeLineColumn = boolVal; } info->tdomStatus = 1; break; case m_remove: result = CHandlerSetRemove (interp, objv[1], "tdom"); if (result == 2) { Tcl_SetResult (interp, "expat parser obj hasn't a C handler set named \"tdom\"", NULL); return TCL_ERROR; } break; case m_setExternalEntityResolver: if (objc != 4) { Tcl_SetResult (interp, "You must name a Tcl command as external entity resolver for setExternalEntityResolver.", NULL); return TCL_ERROR; } info = CHandlerSetGetUserData (interp, objv[1], "tdom"); if (!info) { Tcl_SetResult (interp, "parser object isn't tdom enabled.", NULL); return TCL_ERROR; } if (info->extResolver) { Tcl_DecrRefCount (info->extResolver); } if (strcmp (Tcl_GetString (objv[3]), "") == 0) { info->extResolver = NULL; } else { info->extResolver = objv[3]; Tcl_IncrRefCount (info->extResolver); } info->tdomStatus = 1; break; case m_keepEmpties: if (objc != 4) { Tcl_SetResult (interp, "wrong # of args for method keepEmpties.", NULL); return TCL_ERROR; } handlerSet = CHandlerSetGet (interp, objv[1], "tdom"); if (!handlerSet) { Tcl_SetResult (interp, "parser object isn't tdom enabled.", NULL); return TCL_ERROR; } info = handlerSet->userData; if (!info) { Tcl_SetResult (interp, "parser object isn't tdom enabled.", NULL); return TCL_ERROR; } Tcl_SetIntObj (Tcl_GetObjResult (interp), info->ignoreWhiteSpaces); if (Tcl_GetBooleanFromObj (interp, objv[3], &boolVal) != TCL_OK) { return TCL_ERROR; } info->ignoreWhiteSpaces = !boolVal; handlerSet->ignoreWhiteCDATAs = !boolVal; info->tdomStatus = 1; break; case m_keepCDATA: if (objc != 4) { Tcl_SetResult (interp, "wrong # of args for method keepCDATA.", NULL); return TCL_ERROR; } handlerSet = CHandlerSetGet (interp, objv[1], "tdom"); if (!handlerSet) { Tcl_SetResult (interp, "parser object isn't tdom enabled.", NULL); return TCL_ERROR; } info = handlerSet->userData; if (!info) { Tcl_SetResult (interp, "parser object isn't tdom enabled.", NULL); return TCL_ERROR; } if (Tcl_GetBooleanFromObj (interp, objv[3], &boolVal) != TCL_OK) { return TCL_ERROR; } if (boolVal) { handlerSet->startCdataSectionCommand = tdom_startCDATA; handlerSet->endCdataSectionCommand = endCDATA; } else { handlerSet->startCdataSectionCommand = NULL; handlerSet->endCdataSectionCommand = NULL; } info->tdomStatus = 1; break; case m_keepTextStart: if (objc != 4) { Tcl_SetResult (interp, "wrong # of args for method keepCDATA.", NULL); return TCL_ERROR; } handlerSet = CHandlerSetGet (interp, objv[1], "tdom"); if (!handlerSet) { Tcl_SetResult (interp, "parser object isn't tdom enabled.", NULL); return TCL_ERROR; } info = handlerSet->userData; if (!info) { Tcl_SetResult (interp, "parser object isn't tdom enabled.", NULL); return TCL_ERROR; } if (Tcl_GetBooleanFromObj (interp, objv[3], &boolVal) != TCL_OK) { return TCL_ERROR; } expat = GetExpatInfo (interp, objv[1]); expat->keepTextStart = boolVal; expat->cdataStartLine = 0; break; case m_ignorexmlns: info = CHandlerSetGetUserData (interp, objv[1], "tdom"); if (!info) { Tcl_SetResult (interp, "parser object isn't tdom enabled.", NULL); return TCL_ERROR; } Tcl_SetIntObj (Tcl_GetObjResult (interp), info->ignorexmlns); if (objc == 4) { if (Tcl_GetBooleanFromObj (interp, objv[3], &boolVal) != TCL_OK) { return TCL_ERROR; } info->ignorexmlns = boolVal; } info->tdomStatus = 1; break; } return TCL_OK; } tdom-0.9.6-src/generic/schema.c0000644000175000017500000071671315025767703015017 0ustar rolfrolf/*---------------------------------------------------------------------------- | Copyright (c) 2018 - 2022 Rolf Ade (rolf@pointsman.de) |----------------------------------------------------------------------------- | | | The contents of this file are subject to the Mozilla Public License | Version 2.0 (the "License"); you may not use this file except in | compliance with the License. You may obtain a copy of the License at | http://www.mozilla.org/MPL/ | | Software distributed under the License is distributed on an "AS IS" | basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the | License for the specific language governing rights and limitations | under the License. | | Contributor(s): | | | written by Rolf Ade | 2018-2022 | \---------------------------------------------------------------------------*/ #include #include #include #include #include #include #ifndef TDOM_NO_SCHEMA #include #include #ifdef _MSC_VER #include #else #include #endif #define SetResult(str) Tcl_ResetResult(interp); \ Tcl_SetStringObj(Tcl_GetObjResult(interp), (str), -1) /* #define DEBUG */ /* #define DDEBUG */ /*---------------------------------------------------------------------------- | Debug Macros | \---------------------------------------------------------------------------*/ #ifdef DEBUG # define DBG(x) x #else # define DBG(x) #endif #if defined(DEBUG) || defined(DDEBUG) # define DDBG(x) x #else # define DDBG(x) #endif /*---------------------------------------------------------------------------- | Choice/attribute handling method threshold | \---------------------------------------------------------------------------*/ #ifndef TDOM_CHOICE_HASH_THRESHOLD # define TDOM_CHOICE_HASH_THRESHOLD 5 #endif #ifndef TDOM_ATTRIBUTE_HASH_THRESHOLD # define TDOM_ATTRIBUTE_HASH_THRESHOLD 5 #endif #ifndef TDOM_EXPAT_READ_SIZE # define TDOM_EXPAT_READ_SIZE (1024*8) #endif /*---------------------------------------------------------------------------- | Initial buffer sizes | \---------------------------------------------------------------------------*/ #ifndef CONTENT_ARRAY_SIZE_INIT # define CONTENT_ARRAY_SIZE_INIT 20 #endif #ifndef ANON_PATTERN_ARRAY_SIZE_INIT # define ANON_PATTERN_ARRAY_SIZE_INIT 256 #endif #ifndef URI_BUFFER_LEN_INIT # define URI_BUFFER_LEN_INIT 128 #endif #ifndef ATTR_ARRAY_INIT # define ATTR_ARRAY_INIT 4 #endif /*---------------------------------------------------------------------------- | Local defines | \---------------------------------------------------------------------------*/ #ifndef O_BINARY # ifdef _O_BINARY # define O_BINARY _O_BINARY # else # define O_BINARY 0 # endif #endif #ifndef TCL_MATCH_NOCASE # define TCL_MATCH_NOCASE 1 #endif /*---------------------------------------------------------------------------- | Local typedefs | \---------------------------------------------------------------------------*/ typedef struct { SchemaData *sdata; Tcl_Interp *interp; XML_Parser parser; Tcl_DString *cdata; int onlyWhiteSpace; char *uri; int maxUriLen; Tcl_Obj *externalentitycommandObj; } ValidateMethodData; static const char *ValidationAction2str[] = { "NOT_USED", "MATCH_GLOBAL", "MATCH_ELEMENT_START", "MATCH_ELEMENT_END", "MATCH_TEXT", "MATCH_ATTRIBUTE_TEXT", "MATCH_DOM_KEYCONSTRAINT", "MATCH_DOM_XPATH_BOOLEAN" }; typedef enum { DOM_KEYCONSTRAINT, DOM_XPATH_BOOLEAN, MISSING_ATTRIBUTE, MISSING_ELEMENT, UNEXPECTED_TEXT, MISSING_TEXT, UNEXPECTED_ROOT_ELEMENT, UNEXPECTED_ELEMENT, UNKNOWN_ATTRIBUTE, INVALID_KEYREF, UNKNOWN_ROOT_ELEMENT, UNKNOWN_GLOBAL_ID, UNKNOWN_ID, INVALID_ATTRIBUTE_VALUE, INVALID_VALUE, INVALID_JSON_TYPE, } ValidationErrorType; static const char *ValidationErrorType2str[] = { "DOM_KEYCONSTRAINT", "DOM_XPATH_BOOLEAN", "MISSING_ATTRIBUTE", "MISSING_ELEMENT", "UNEXPECTED_TEXT", "MISSING_TEXT", "UNEXPECTED_ROOT_ELEMENT", "UNEXPECTED_ELEMENT", "UNKNOWN_ATTRIBUTE", "INVALID_KEYREF", "UNKNOWN_ROOT_ELEMENT", "UNKNOWN_GLOBAL_ID", "UNKNOWN_ID", "INVALID_ATTRIBUTE_VALUE", "INVALID_VALUE", "INVALID_JSON_TYPE" }; typedef enum { VALIDATE_STRING, VALIDATE_FILENAME, VALIDATE_CHANNEL } ValidationInput; static const char *jsonStructTypes[] = { "NONE", "OBJECT", "ARRAY", NULL }; typedef enum { jt_none, jt_object, jt_array } jsonStructType; /*---------------------------------------------------------------------------- | Recovering related flags | \---------------------------------------------------------------------------*/ #define RECOVER_FLAG_REWIND 1 #define RECOVER_FLAG_DONT_REPORT 2 #define RECOVER_FLAG_IGNORE 4 #define RECOVER_FLAG_MATCH_END_CONTINUE 8 /*---------------------------------------------------------------------------- | [schemacmd info expected] related flags | \---------------------------------------------------------------------------*/ #define EXPECTED_IGNORE_MATCHED 1 #define EXPECTED_ONLY_MANDATORY 2 #define EXPECTED_PROBE_MAYSKIP 4 /*---------------------------------------------------------------------------- | domKeyConstraint related flags | \---------------------------------------------------------------------------*/ #define DKC_FLAG_IGNORE_EMPTY_FIELD_SET 1 #define DKC_FLAG_BOOLEAN 2 /*---------------------------------------------------------------------------- | Macros | \---------------------------------------------------------------------------*/ #define SetResultV(str) if (!sdata->evalError) { \ Tcl_ResetResult(interp); \ Tcl_SetStringObj(Tcl_GetObjResult(interp), (str), -1); \ } #define SetResult3(str1,str2,str3) Tcl_ResetResult(interp); \ Tcl_AppendResult(interp, (str1), (str2), (str3), NULL) #define SetResult3V(str1,str2,str3) if (!sdata->evalError) { \ Tcl_ResetResult(interp); \ Tcl_AppendResult(interp, (str1), (str2), (str3), NULL); \ } #define SetIntResult(i) Tcl_ResetResult(interp); \ Tcl_SetDomLengthObj(Tcl_GetObjResult(interp), (i)) #define SetLongResult(i) Tcl_ResetResult(interp); \ Tcl_SetLongObj(Tcl_GetObjResult(interp), (i)) #define SetBooleanResult(i) Tcl_ResetResult(interp); \ Tcl_SetBooleanObj(Tcl_GetObjResult(interp), (i)) #define checkNrArgs(l,h,err) if (objc < l || objc > h) { \ SetResult (err); \ return TCL_ERROR; \ } #if defined(DEBUG) || defined(DDEBUG) static const char *Schema_CP_Type2str[] = { "ANY", "NAME", "CHOICE", "INTERLEAVE", "PATTERN", "TEXT", "VIRTUAL", "KEYSPACE_START", "KEYSPACE_END", "JSON_STRUCT_TYPE" }; static const char *Schema_Quant_Type2str[] = { "ONE", "OPT", "REP", "PLUS", "NM", "ERROR" }; #endif #define CHECK_SI \ if (!sdata) { \ SetResult ("Command called outside of schema context"); \ return TCL_ERROR; \ } \ if (sdata->isTextConstraint) { \ SetResult ("Command called in invalid schema context"); \ return TCL_ERROR; \ } #define CHECK_TOPLEVEL \ if (sdata->defineToplevel) { \ SetResult("Command not allowed at top level " \ "in schema define evaluation"); \ return TCL_ERROR; \ } #define CHECK_RECURSIVE_CALL \ if (clientData != NULL) { \ savedsdata = GETASI; \ if (savedsdata == sdata) { \ SetResult ("This recursive call is not allowed"); \ return TCL_ERROR; \ } \ } else if (!sdata->defineToplevel) { \ SetResult ("Command only allowed at lop level"); \ return TCL_ERROR; \ } #define CHECK_EVAL \ if (sdata->currentEvals) { \ SetResult ("This method is not allowed in nested evaluation"); \ return TCL_ERROR; \ } #define CHECK_REWIND \ if (sdata->recoverFlags & RECOVER_FLAG_REWIND) { \ rewindStack (sdata); \ sdata->recoverFlags &= ~RECOVER_FLAG_REWIND; \ } \ #define maxOne(quant) \ ((quant) == SCHEMA_CQUANT_ONE || (quant) == SCHEMA_CQUANT_OPT) ? 1 : 0 #define minOne(quant) \ ((quant) == SCHEMA_CQUANT_ONE || (quant) == SCHEMA_CQUANT_PLUS) ? 1 : 0 #define mayRepeat(quant) \ ((quant) == SCHEMA_CQUANT_REP || (quant) == SCHEMA_CQUANT_PLUS) ? 1 : 0 #define mayMiss(quant) \ ((quant) == SCHEMA_CQUANT_REP || (quant) == SCHEMA_CQUANT_OPT) ? 1 : 0 #define hasMatched(quant,hm) \ (hm) == 0 ? mayMiss(quant) : 1 #define mustMatch(quant,hm) \ (hm) == 0 ? minOne(quant) : 0 #define getContext(cp, ac, hm) \ cp = se->pattern; \ ac = se->activeChild; \ hm = se->hasMatched; \ if (hm && maxOne (cp->quants[ac])) { \ ac += + 1; \ hm = 0; \ } \ #define updateStack(sdata,se,ac) \ if (!(sdata->recoverFlags & RECOVER_FLAG_REWIND)) { \ se->activeChild = ac; \ se->hasMatched = 1; \ } \ static const char *unknownNS = "type = type; switch (type) { case SCHEMA_CTYPE_NAME: pattern->flags |= CONSTRAINT_TEXT_CHILD; /* Fall through. */ case SCHEMA_CTYPE_PATTERN: pattern->namespace = (char *)namespace; pattern->name = name; /* Fall through. */ case SCHEMA_CTYPE_CHOICE: case SCHEMA_CTYPE_INTERLEAVE: pattern->content = (SchemaCP**) MALLOC ( sizeof(SchemaCP*) * CONTENT_ARRAY_SIZE_INIT ); pattern->quants = (SchemaQuant*) MALLOC ( sizeof (SchemaQuant) * CONTENT_ARRAY_SIZE_INIT ); break; case SCHEMA_CTYPE_TEXT: /* content/quant will be allocated, if the cp in fact has * constraints */ break; case SCHEMA_CTYPE_KEYSPACE_END: case SCHEMA_CTYPE_KEYSPACE: pattern->name = name; break; case SCHEMA_CTYPE_ANY: pattern->namespace = namespace; break; case SCHEMA_CTYPE_VIRTUAL: case SCHEMA_CTYPE_JSON_STRUCT: /* Do nothing */ break; } return pattern; } DDBG( static void serializeCP ( SchemaCP *pattern ) { fprintf (stderr, "CP %p type: %s\n", pattern, Schema_CP_Type2str[pattern->type]); switch (pattern->type) { case SCHEMA_CTYPE_KEYSPACE_END: case SCHEMA_CTYPE_KEYSPACE: fprintf (stderr, "\tName: '%s'\n", pattern->name); break; case SCHEMA_CTYPE_NAME: case SCHEMA_CTYPE_PATTERN: fprintf (stderr, "\tName: '%s' Namespace: '%s'\n", pattern->name, pattern->namespace); if (pattern->flags & FORWARD_PATTERN_DEF) { fprintf (stderr, "\tAnonymously defined NAME\n"); } if (pattern->flags & PLACEHOLDER_PATTERN_DEF) { fprintf (stderr, "\tAs placeholder defined NAME\n"); } if (pattern->flags & LOCAL_DEFINED_ELEMENT) { fprintf (stderr, "\tLocal defined NAME\n"); } if (pattern->flags & ELEMENTTYPE_DEF) { fprintf (stderr, "\tElementtype '%s'\n", pattern->name); } if (pattern->flags & TYPED_ELEMENT) { fprintf (stderr, "\tTyped element - type '%s'\n", pattern->typeptr->name); } /* Fall through. */ case SCHEMA_CTYPE_CHOICE: case SCHEMA_CTYPE_INTERLEAVE: fprintf (stderr, "\t%d children\n", pattern->nc); break; case SCHEMA_CTYPE_ANY: if (pattern->namespace) { fprintf (stderr, "\tNamespace: '%s'\n", pattern->namespace); } if (pattern->typedata) { fprintf (stderr, "\t%d namespaces\n", ((Tcl_HashTable*)pattern->typedata)->numEntries); } break; case SCHEMA_CTYPE_TEXT: case SCHEMA_CTYPE_VIRTUAL: case SCHEMA_CTYPE_JSON_STRUCT: /* Do nothing */ break; } } static void serializeQuant ( SchemaQuant quant ) { fprintf (stderr, "Quant type: %s\n", Schema_Quant_Type2str[quant]); } static int getDeep ( SchemaValidationStack *se ) { int i = 0; while (se) { if (se->pattern->type == SCHEMA_CTYPE_NAME) i++; se = se->down; } return i; } static void serializeStack ( SchemaData *sdata ) { SchemaValidationStack *se; fprintf (stderr, "++++ Current validation stack:\n"); se = sdata->stack; while (se) { serializeCP (se->pattern); fprintf (stderr, "\tdeep: %d ac: %d hm: %d\n", getDeep (se), se->activeChild, se->hasMatched); se = se->down; } fprintf (stderr, "++++ Stack bottom\n"); } ) /* DBG end */ static void freedomKeyConstraints ( domKeyConstraint *kc ) { domKeyConstraint *knext; int i; while (kc) { knext = kc->next; if (kc->name) FREE (kc->name); if (kc->emptyFieldSetValue) FREE (kc->emptyFieldSetValue); xpathFreeAst (kc->selector); for (i = 0; i < kc->nrFields; i++) { xpathFreeAst (kc->fields[i]); } FREE (kc->fields); FREE (kc); kc = knext; } } static void freeSchemaCP ( SchemaCP *pattern ) { unsigned int i; SchemaConstraint *sc; switch (pattern->type) { case SCHEMA_CTYPE_ANY: if (pattern->typedata) { Tcl_DeleteHashTable ((Tcl_HashTable *) pattern->typedata); FREE (pattern->typedata); } break; case SCHEMA_CTYPE_VIRTUAL: for (i = 0; i < pattern->nc; i++) { Tcl_DecrRefCount ((Tcl_Obj *)pattern->content[i]); } FREE (pattern->content); break; case SCHEMA_CTYPE_TEXT: for (i = 0; i < pattern->nc; i++) { sc = (SchemaConstraint *) pattern->content[i]; if (sc->freeData) { (sc->freeData) (sc->constraintData); } FREE (pattern->content[i]); } /* fall through */ default: if (pattern->flags & TYPED_ELEMENT) break; FREE (pattern->content); FREE (pattern->quants); if (pattern->attrs) { for (i = 0; i < pattern->numAttr; i++) { FREE (pattern->attrs[i]); } FREE (pattern->attrs); } freedomKeyConstraints (pattern->domKeys); if (pattern->type != SCHEMA_CTYPE_JSON_STRUCT && pattern->typedata) { Tcl_DeleteHashTable ((Tcl_HashTable *) pattern->typedata); FREE (pattern->typedata); } break; } if (pattern->defScript) { Tcl_DecrRefCount (pattern->defScript); } if (pattern->associated) { Tcl_DecrRefCount (pattern->associated); } FREE (pattern); } static SchemaData* initSchemaData ( Tcl_Obj *cmdNameObj) { SchemaData *sdata; domLength len; char *name; sdata = TMALLOC (SchemaData); memset (sdata, 0, sizeof(SchemaData)); name = Tcl_GetStringFromObj (cmdNameObj, &len); sdata->self = Tcl_NewStringObj (name, len); Tcl_IncrRefCount (sdata->self); Tcl_InitHashTable (&sdata->element, TCL_STRING_KEYS); Tcl_InitHashTable (&sdata->elementType, TCL_STRING_KEYS); Tcl_InitHashTable (&sdata->elementTypeInstance, TCL_ONE_WORD_KEYS); Tcl_InitHashTable (&sdata->prefix, TCL_STRING_KEYS); Tcl_InitHashTable (&sdata->pattern, TCL_STRING_KEYS); Tcl_InitHashTable (&sdata->attrNames, TCL_STRING_KEYS); Tcl_InitHashTable (&sdata->namespace, TCL_STRING_KEYS); Tcl_InitHashTable (&sdata->textDef, TCL_STRING_KEYS); sdata->patternList = (SchemaCP **) MALLOC ( sizeof (SchemaCP*) * ANON_PATTERN_ARRAY_SIZE_INIT); sdata->patternListSize = ANON_PATTERN_ARRAY_SIZE_INIT; /* evalStub initialization */ sdata->evalStub = (Tcl_Obj **) MALLOC (sizeof (Tcl_Obj*) * 4); sdata->evalStub[0] = Tcl_NewStringObj("::namespace", 11); Tcl_IncrRefCount (sdata->evalStub[0]); sdata->evalStub[1] = Tcl_NewStringObj("eval", 4); Tcl_IncrRefCount (sdata->evalStub[1]); sdata->evalStub[2] = Tcl_NewStringObj("::tdom::schema", 14); Tcl_IncrRefCount (sdata->evalStub[2]); /* textStub initialization */ sdata->textStub = (Tcl_Obj **) MALLOC (sizeof (Tcl_Obj*) * 4); sdata->textStub[0] = Tcl_NewStringObj("::namespace", 11); Tcl_IncrRefCount (sdata->textStub[0]); sdata->textStub[1] = Tcl_NewStringObj("eval", 4); Tcl_IncrRefCount (sdata->textStub[1]); sdata->textStub[2] = Tcl_NewStringObj("::tdom::schema::text", 20); Tcl_IncrRefCount (sdata->textStub[2]); sdata->cdata = TMALLOC (Tcl_DString); Tcl_DStringInit (sdata->cdata); Tcl_InitHashTable (&sdata->ids, TCL_STRING_KEYS); sdata->unknownIDrefs = 0; Tcl_InitHashTable (&sdata->idTables, TCL_STRING_KEYS); Tcl_InitHashTable (&sdata->keySpaces, TCL_STRING_KEYS); sdata->choiceHashThreshold = TDOM_CHOICE_HASH_THRESHOLD; sdata->attributeHashThreshold = TDOM_ATTRIBUTE_HASH_THRESHOLD; return sdata; } static void schemaInstanceDelete ( ClientData clientData ) { SchemaData *sdata = (SchemaData *) clientData; unsigned int i; SchemaValidationStack *down; Tcl_HashEntry *h; Tcl_HashSearch search; SchemaDocKey *dk; SchemaKeySpace *ks; /* Protect the clientData to be freed inside (even nested) * Tcl_Eval*() calls to avoid invalid mem access and postpone the * cleanup until the Tcl_Eval*() calls are finished (done in * tDOM_schemaInstanceCmd()). */ if (sdata->currentEvals || sdata->inuse > 0) { sdata->cleanupAfterUse = 1; return; } Tcl_DecrRefCount (sdata->self); if (sdata->start) FREE (sdata->start); if (sdata->prefixns) { i = 0; while (sdata->prefixns[i]) { FREE (sdata->prefixns[i]); i++; } FREE (sdata->prefixns); } Tcl_DeleteHashTable (&sdata->namespace); Tcl_DeleteHashTable (&sdata->element); Tcl_DeleteHashTable (&sdata->elementType); Tcl_DeleteHashTable (&sdata->elementTypeInstance); Tcl_DeleteHashTable (&sdata->prefix); Tcl_DeleteHashTable (&sdata->pattern); Tcl_DeleteHashTable (&sdata->attrNames); Tcl_DeleteHashTable (&sdata->textDef); for (i = 0; i < sdata->numPatternList; i++) { freeSchemaCP (sdata->patternList[i]); } FREE (sdata->patternList); FREE (sdata->quants); while (sdata->stack) { down = sdata->stack->down; if (sdata->stack->interleaveState) FREE (sdata->stack->interleaveState); FREE (sdata->stack); sdata->stack = down; } while (sdata->lastMatchse) { down = sdata->lastMatchse->down; if (sdata->lastMatchse->interleaveState) FREE (sdata->lastMatchse->interleaveState); FREE (sdata->lastMatchse); sdata->lastMatchse = down; } while (sdata->stackPool) { down = sdata->stackPool->down; /* interleaveState always got cleaned up at putting se back to * pool */ FREE (sdata->stackPool); sdata->stackPool = down; } Tcl_DecrRefCount (sdata->evalStub[0]); Tcl_DecrRefCount (sdata->evalStub[1]); Tcl_DecrRefCount (sdata->evalStub[2]); FREE (sdata->evalStub); Tcl_DecrRefCount (sdata->textStub[0]); Tcl_DecrRefCount (sdata->textStub[1]); Tcl_DecrRefCount (sdata->textStub[2]); FREE (sdata->textStub); Tcl_DStringFree (sdata->cdata); FREE (sdata->cdata); if (sdata->reportCmd) { Tcl_DecrRefCount (sdata->reportCmd); } Tcl_DeleteHashTable (&sdata->ids); for (h = Tcl_FirstHashEntry (&sdata->idTables, &search); h != NULL; h = Tcl_NextHashEntry (&search)) { dk = Tcl_GetHashValue (h); Tcl_DeleteHashTable (&dk->ids); FREE (dk); } Tcl_DeleteHashTable (&sdata->idTables); for (h = Tcl_FirstHashEntry (&sdata->keySpaces, &search); h != NULL; h = Tcl_NextHashEntry (&search)) { ks = Tcl_GetHashValue (h); if (ks->active) { Tcl_DeleteHashTable (&ks->ids); } FREE (ks); } Tcl_DeleteHashTable (&sdata->keySpaces); if (sdata->wsbufLen) { FREE (sdata->wsbuf); } FREE (sdata); } static void cleanupLastPattern ( SchemaData *sdata, unsigned int from ) { unsigned int i, j, k, freed, isElement; char *name; Tcl_HashTable *hashTable; Tcl_HashEntry *h, *h1; SchemaCP *this, *previous, *current, *typePattern, *this1; for (i = from; i < sdata->numPatternList; i++) { this = sdata->patternList[i]; hashTable = NULL; isElement = 0; name = this->name; if (this->type == SCHEMA_CTYPE_NAME) { /* Local defined elements aren't saved under their local * name bucket in the sdata->element hash table. */ if (this->flags & LOCAL_DEFINED_ELEMENT) { freeSchemaCP (sdata->patternList[i]); continue; } if (this->flags & ELEMENTTYPE_DEF) { hashTable = &sdata->elementType; } else if (this->flags & TYPED_ELEMENT) { hashTable = &sdata->elementTypeInstance; if (this->flags & HASH_ENTRY_DELETED) { freeSchemaCP (sdata->patternList[i]); continue; } } else { hashTable = &sdata->element; isElement = 1; } } else if (this->type == SCHEMA_CTYPE_PATTERN) { hashTable = &sdata->pattern; } if (name && hashTable) { if (this->flags & FORWARD_PATTERN_DEF) { sdata->forwardPatternDefs--; } h = Tcl_FindHashEntry (hashTable, name); if (h) { previous = NULL; current = Tcl_GetHashValue (h); while (current != NULL && current != this) { previous = current; current = current->next; } if (current) { if (previous) { if (current->next) { previous->next = current->next; } else { previous->next = NULL; } } else { if (current->next) { Tcl_SetHashValue (h, current->next); } else { if (isElement) { /* Typed elements with the same name * use the pointer to the key string * of the below deleted hash entry in * the name element of the pattern * structure. Additionally the pointer * to the key string is used as key in * the elementTypeInstance hash table. * We mark every element instance * pattern stored in * elementTypeInstance under this key * and delete the entry. */ h1 = Tcl_FindHashEntry ( &sdata->elementTypeInstance, name ); if (h1) { this1 = (SchemaCP *) Tcl_GetHashValue (h1); while (this1) { this1->flags |= HASH_ENTRY_DELETED; this1 = this1->next; } Tcl_DeleteHashEntry (h1); } } Tcl_DeleteHashEntry (h); } } } } if (this->flags & TYPED_ELEMENT) { /* If the type of the element is forward defined, then * the pointer to the below freed cp is noted in the * forward type definition. Clean that up. */ /* First step: Check, if the typePtr is still valid. */ freed = 0; for (j = from; j < i; j++) { if (this->typeptr == sdata->patternList[j]) { freed = 1; break; } } if (!freed) { typePattern = this->typeptr; if (typePattern->flags & FORWARD_PATTERN_DEF) { for (k = 0; k < typePattern->nc; k++) { if (this == typePattern->content[k]) { /* Later noted pattern are allocated * later than this and will be freed * later on in this cleanupLastPattern * call, so this is safe and * efficient. */ typePattern->nc = k; break; } } } } } } freeSchemaCP (sdata->patternList[i]); } sdata->numPatternList = from; } static void addToContent ( SchemaData *sdata, SchemaCP *pattern, SchemaQuant quant, int n, int m ) { SchemaCP *wrapperCP; SchemaCP *savedCP = NULL; unsigned int savedContenSize; if (sdata->cp->type == SCHEMA_CTYPE_NAME && sdata->cp->flags & CONSTRAINT_TEXT_CHILD && (pattern->type != SCHEMA_CTYPE_TEXT || pattern->nc == 0)) { sdata->cp->flags &= ~CONSTRAINT_TEXT_CHILD; } if (sdata->cp->type == SCHEMA_CTYPE_CHOICE || sdata->cp->type == SCHEMA_CTYPE_INTERLEAVE) { if (pattern->type == SCHEMA_CTYPE_CHOICE) { if (pattern->flags & MIXED_CONTENT) { sdata->cp->flags |= MIXED_CONTENT; } wrapperCP = initSchemaCP (SCHEMA_CTYPE_PATTERN, NULL, NULL); REMEMBER_PATTERN (wrapperCP); wrapperCP->content[0] = pattern; wrapperCP->quants[0] = SCHEMA_CQUANT_ONE; wrapperCP->nc = 1; pattern = wrapperCP; } if (sdata->cp->type == SCHEMA_CTYPE_CHOICE && quant != SCHEMA_CQUANT_ONE) { wrapperCP = initSchemaCP (SCHEMA_CTYPE_PATTERN, NULL, NULL); REMEMBER_PATTERN (wrapperCP); if (sdata->cp->nc == sdata->contentSize) { sdata->cp->content = REALLOC (sdata->cp->content, 2 * sdata->contentSize * sizeof (SchemaCP*)); sdata->cp->quants = REALLOC (sdata->cp->quants, 2 * sdata->contentSize * sizeof (SchemaQuant)); sdata->contentSize *= 2; } sdata->cp->content[sdata->cp->nc] = wrapperCP; sdata->cp->quants[sdata->cp->nc] = SCHEMA_CQUANT_ONE; sdata->cp->nc++; savedCP = sdata->cp; savedContenSize = sdata->contentSize; sdata->cp = wrapperCP; sdata->contentSize = CONTENT_ARRAY_SIZE_INIT; } } if (quant == SCHEMA_CQUANT_NM) { int i, newChilds, thisquant; if (m == -1) { m = n + 1; newChilds = m; thisquant = SCHEMA_CQUANT_REP; } else { newChilds = (n >= m) ? n : m; thisquant = SCHEMA_CQUANT_OPT; } while (sdata->cp->nc + newChilds >= sdata->contentSize) { sdata->cp->content = REALLOC (sdata->cp->content, 2 * sdata->contentSize * sizeof (SchemaCP*)); sdata->cp->quants = REALLOC (sdata->cp->quants, 2 * sdata->contentSize * sizeof (SchemaQuant)); sdata->contentSize *= 2; } for (i = 0; i < n; i++) { sdata->cp->content[sdata->cp->nc+i] = pattern; sdata->cp->quants[sdata->cp->nc+i] = SCHEMA_CQUANT_ONE; } for (i = n; i < m; i++) { sdata->cp->content[sdata->cp->nc+i] = pattern; sdata->cp->quants[sdata->cp->nc+i] = thisquant; } sdata->cp->nc = sdata->cp->nc + newChilds; } else { if (sdata->cp->nc == sdata->contentSize) { sdata->cp->content = REALLOC (sdata->cp->content, 2 * sdata->contentSize * sizeof (SchemaCP*)); sdata->cp->quants = REALLOC (sdata->cp->quants, 2 * sdata->contentSize * sizeof (SchemaQuant)); sdata->contentSize *= 2; } sdata->cp->content[sdata->cp->nc] = pattern; sdata->cp->quants[sdata->cp->nc] = quant; sdata->cp->nc++; } if (savedCP) { sdata->cp = savedCP; sdata->contentSize = savedContenSize; } } static SchemaValidationStack * getStackElement ( SchemaData *sdata, SchemaCP *pattern ) { SchemaValidationStack *stackElm; if (sdata->stackPool) { stackElm = sdata->stackPool; sdata->stackPool = stackElm->down; } else { stackElm = TMALLOC (SchemaValidationStack); } memset (stackElm, 0, sizeof (SchemaValidationStack)); stackElm->pattern = pattern; return stackElm; } static void repoolStackElement ( SchemaData *sdata, SchemaValidationStack *se ) { if (se->interleaveState) { FREE (se->interleaveState); se->interleaveState = NULL; } se->down = sdata->stackPool; sdata->stackPool = se; } static void pushToStack ( SchemaData *sdata, SchemaCP *pattern ) { SchemaValidationStack *se, *nextse; DBG(fprintf(stderr, "push to Stack:\n");serializeCP(pattern)); if (pattern->type == SCHEMA_CTYPE_NAME && sdata->lastMatchse) { se = sdata->lastMatchse; while (se) { nextse = se->down; repoolStackElement (sdata, se); se = nextse; } sdata->lastMatchse = NULL; } se = getStackElement (sdata, pattern); se->down = sdata->stack; if (pattern->type == SCHEMA_CTYPE_INTERLEAVE) { se->interleaveState = MALLOC (sizeof (int) * pattern->nc); memset (se->interleaveState, 0, sizeof (int) * pattern->nc); } sdata->stack = se; } static void popFromStack ( SchemaData *sdata, SchemaValidationStack **stack ) { SchemaValidationStack *se; DBG(fprintf(stderr, "popFromStack:\n"); serializeCP((*stack)->pattern)); se = (*stack)->down; repoolStackElement (sdata, *stack); *stack = se; } static void popStack ( SchemaData *sdata ) { SchemaValidationStack *se, *nextse; DBG(fprintf(stderr, "popStack:\n"); serializeCP(sdata->stack->pattern)); if (sdata->stack->pattern->type == SCHEMA_CTYPE_NAME) { se = sdata->lastMatchse; while (se) { nextse = se->down; repoolStackElement (sdata, se); se = nextse; } sdata->lastMatchse = NULL; se = sdata->stack->down; repoolStackElement (sdata, sdata->stack); sdata->stack = se; } else { if (sdata->stack->hasMatched) { se = sdata->stack->down; sdata->stack->down = sdata->lastMatchse; sdata->lastMatchse = sdata->stack; sdata->stack = se; } else { se = sdata->stack->down; repoolStackElement (sdata, sdata->stack); sdata->stack = se; } } } static void finalizeElement ( SchemaData *sdata, int ac ) { SchemaValidationStack *se; SchemaCP *cp, *cp1; unsigned int i; se = sdata->stack; cp = se->pattern; if (cp->type == SCHEMA_CTYPE_NAME || cp->type == SCHEMA_CTYPE_PATTERN) { for (i = ac; i < cp->nc; i++) { cp1 = cp->content[ac]; if (cp1->type == SCHEMA_CTYPE_KEYSPACE) { if (!cp1->keySpace->active) { Tcl_InitHashTable (&cp1->keySpace->ids, TCL_STRING_KEYS); cp1->keySpace->active = 1; cp1->keySpace->unknownIDrefs = 0; } else { cp1->keySpace->active++; } } else if (cp->content[ac]->type == SCHEMA_CTYPE_KEYSPACE_END) { cp1->keySpace->active--; if (!cp1->keySpace->active) { cp1->keySpace->unknownIDrefs = 0; Tcl_DeleteHashTable (&cp1->keySpace->ids); } } } } popStack (sdata); /* cp is still the pattern from stack top before the popStack */ if (cp->type != SCHEMA_CTYPE_NAME) { finalizeElement (sdata, sdata->stack->activeChild + 1); } } static void rewindStack ( SchemaData *sdata ) { SchemaValidationStack *se; while (sdata->lastMatchse) { se = sdata->lastMatchse; sdata->lastMatchse = se->down; se->down = sdata->stack; sdata->stack = se; } } static int recover ( Tcl_Interp *interp, SchemaData *sdata, ValidationErrorType errorType, ValidationAction action, const char *name, const char *ns, char *text, int ac ) { Tcl_Obj *cmdPtr; int rc; SchemaValidationStack *se; if (!sdata->reportCmd || sdata->evalError) return 0; if (sdata->recoverFlags & RECOVER_FLAG_DONT_REPORT) return 1; /* If non SCHEMA_CTYPE_NAME and the pattern hasn't already matched * that's a pattern pushed on stack to look for (probe) if it * matches (or allows empty match). Even if the pattern fail it * may be optional; recovering is done at the caller level in case * the pattern isn't optional. */ if (sdata->stack && sdata->stack->pattern->type != SCHEMA_CTYPE_NAME && sdata->stack->activeChild == 0 && sdata->stack->hasMatched == 0) return 0; cmdPtr = Tcl_DuplicateObj (sdata->reportCmd); Tcl_IncrRefCount(cmdPtr); Tcl_ListObjAppendElement (interp, cmdPtr, sdata->self); Tcl_ListObjAppendElement ( interp, cmdPtr, Tcl_NewStringObj (ValidationErrorType2str[errorType], -1) ); /* In case of unknown element the name/ns arguments of recover() * are NULL, but sdata->vname/sdata->vns are already * pre-filled. */ if (name) sdata->vname = name; if (ns) sdata->vns = ns; sdata->vtext = text; sdata->vaction = action; switch (errorType) { case INVALID_JSON_TYPE: case MISSING_TEXT: case INVALID_KEYREF: case INVALID_VALUE: if (sdata->stack) { se = sdata->stack; while (se->pattern->type != SCHEMA_CTYPE_NAME) { se = se->down; } sdata->vname = se->pattern->name; sdata->vns = se->pattern->namespace; } break; case MISSING_ELEMENT: if (action == MATCH_ELEMENT_END) { if (sdata->stack) { se = sdata->stack; while (se->pattern->type != SCHEMA_CTYPE_NAME) { se = se->down; } sdata->vname = se->pattern->name; sdata->vns = se->pattern->namespace; } } break; default: break; } sdata->currentEvals++; rc = Tcl_EvalObjEx (interp, cmdPtr, TCL_EVAL_GLOBAL | TCL_EVAL_DIRECT); sdata->currentEvals--; sdata->vaction = 0; if (name) sdata->vname = name; if (ns) sdata->vns = ns; sdata->vtext = NULL; Tcl_DecrRefCount (cmdPtr); if (rc != TCL_OK) { sdata->evalError = 1; return 0; } switch (errorType) { case MISSING_ELEMENT: if (action == MATCH_ELEMENT_START) { if (strcmp (Tcl_GetStringResult (interp), "ignore") == 0) { sdata->recoverFlags |= RECOVER_FLAG_IGNORE; return 1; } else if (strcmp (Tcl_GetStringResult (interp), "vanish") == 0) { sdata->recoverFlags |= RECOVER_FLAG_REWIND; sdata->skipDeep = 1; return 1; } else { /* Rewind stack to last match and ignore the just opened * Element. */ finalizeElement (sdata, ac+1); sdata->skipDeep = 2; } } else if (action == MATCH_ELEMENT_END) { if (strcmp (Tcl_GetStringResult (interp), "ignore") == 0) { sdata->recoverFlags |= RECOVER_FLAG_MATCH_END_CONTINUE; } else { sdata->recoverFlags |= RECOVER_FLAG_DONT_REPORT; } } break; case MISSING_TEXT: if (action == MATCH_ELEMENT_END) { if (strcmp (Tcl_GetStringResult (interp), "ignore") == 0) { sdata->recoverFlags |= RECOVER_FLAG_MATCH_END_CONTINUE; } else { sdata->recoverFlags |= RECOVER_FLAG_DONT_REPORT; } } break; case UNEXPECTED_ELEMENT: if (strcmp (Tcl_GetStringResult (interp), "vanish") == 0) { sdata->recoverFlags |= RECOVER_FLAG_REWIND; sdata->skipDeep = 1; return 1; } else { finalizeElement (sdata, ac+1); sdata->skipDeep = 2; } break; case UNEXPECTED_TEXT: sdata->recoverFlags |= RECOVER_FLAG_REWIND; break; default: break; } return 1; } /* The cp argument must be type SCHEMA_CTYPE_TEXT */ int tDOM_checkText ( Tcl_Interp *interp, void *clientData, char *text ) { unsigned int i; SchemaCP *cp = (SchemaCP *) clientData; SchemaConstraint *sc; /* Look also at oneOfImpl */ for (i = 0; i < cp->nc; i++) { sc = (SchemaConstraint *) cp->content[i]; if (!(sc->constraint) (interp, sc->constraintData, text)) { return 0; } } return 1; } /* The argument ac points to the child of the current top-most stack * element pattern which is to evaluate. */ static int evalVirtual ( Tcl_Interp *interp, SchemaData *sdata, int ac ) { int rc; SchemaCP *cp; cp = sdata->stack->pattern->content[ac]; sdata->currentEvals++; rc = Tcl_EvalObjv (interp, cp->nc, (Tcl_Obj **) cp->content, TCL_EVAL_GLOBAL); sdata->currentEvals--; if (rc != TCL_OK) { sdata->evalError = 1; return 0; } return 1; } /* Check, if the pattern to probe does not call itself (even * indirectly) without a match inbetween.*/ static TDOM_INLINE int recursivePattern ( SchemaValidationStack *se, SchemaCP *pattern ) { int rc = 0; while (se && se->pattern->type != SCHEMA_CTYPE_NAME) { if (!se->hasMatched && se->pattern == pattern) { rc = 1; break; } se = se->down; } return rc; } static int checkJsonStructType ( Tcl_Interp *interp, SchemaData *sdata, SchemaCP *cp, ValidationErrorType errorType, ValidationAction action, int ac ) { jsonStructType jsonType; char *str; Tcl_Obj *strObj; if (!sdata->insideNode) return 1; jsonType = (intptr_t) cp->typedata; switch (jsonType) { case jt_none: if (sdata->insideNode->info > 0 && sdata->insideNode->info < 8) goto error; break; case jt_object: if (sdata->insideNode->info != JSON_OBJECT) goto error; break; case jt_array: if (sdata->insideNode->info != JSON_ARRAY) goto error; break; default: SetResult ("Internal error: invalid JSON structure type!"); sdata->evalError = 1; return 0; } return 1; error: if (!recover (interp, sdata, errorType, action, sdata->insideNode->nodeName, domNamespaceURI(sdata->insideNode), NULL, ac)) { str = xpathNodeToXPath (sdata->insideNode, 0); strObj = Tcl_NewStringObj (str, -1); Tcl_AppendStringsToObj (strObj, ": Wrong JSON type", NULL); Tcl_SetObjResult (interp, strObj); FREE (str); sdata->evalError = 2; return 0; } return 1; } static int matchingAny ( char *namespace, SchemaCP *candidate ) { Tcl_HashEntry *h; if (candidate->flags & ANY_NOT) { if (candidate->namespace || candidate->typedata) { /* The any wildcard is limited to one or several * namespaces (the empty namespace may be one of * them). */ if (namespace) { if (candidate->typedata) { h = Tcl_FindHashEntry ( (Tcl_HashTable *)candidate->typedata, namespace); if (h) return 0; } else { if (candidate->namespace == namespace) { return 0; } } } else { if (candidate->namespace == emptyStr) { return 0; } } } return 1; } else { if (candidate->namespace || candidate->typedata) { /* The any wildcard is limited to one or several * namespaces (the empty namespace may be one of * them). */ if (namespace) { if (candidate->typedata) { h = Tcl_FindHashEntry ( (Tcl_HashTable *)candidate->typedata, namespace); if (!h) return 0; } else { if (candidate->namespace != namespace) { return 0; } } } else { if (candidate->namespace != emptyStr) { return 0; } } } return 1; } } static int matchElementStart ( Tcl_Interp *interp, SchemaData *sdata, char *name, char *namespace ) { SchemaCP *cp, *candidate, *icp; int hm, mayskip, thismayskip, rc, isName = 0; unsigned int ac, i; SchemaValidationStack *se; Tcl_HashEntry *h; if (!sdata->stack) return 0; se = sdata->stack; getContext (cp, ac, hm); switch (cp->type) { case SCHEMA_CTYPE_NAME: isName = 1; /* fall through */ case SCHEMA_CTYPE_PATTERN: while (ac < cp->nc) { candidate = cp->content[ac]; mayskip = 0; switch (candidate->type) { case SCHEMA_CTYPE_TEXT: if (candidate->nc) { if (!checkText (interp, candidate, "")) { if (recover (interp, sdata, MISSING_TEXT, MATCH_ELEMENT_START, name, namespace, NULL, ac)) { mayskip = 1; break; } return 0; } } break; case SCHEMA_CTYPE_ANY: if (!matchingAny (namespace, candidate)) break; updateStack (sdata, se, ac); sdata->skipDeep = 1; /* See comment in tDOM_probeElement: sdata->vname and * sdata->vns may be pre-filled. We reset it here.*/ sdata->vname = NULL; sdata->vns = NULL; return 1; case SCHEMA_CTYPE_NAME: DBG(fprintf (stderr, "name: %s ns: %s candidate name: %s " "candidate ns: %s\n", name, namespace, candidate->name, candidate->namespace)); if (candidate->name == name && candidate->namespace == namespace) { pushToStack (sdata, candidate); updateStack (sdata, se, ac); return 1; } break; case SCHEMA_CTYPE_CHOICE: if (candidate->typedata) { h = Tcl_FindHashEntry ((Tcl_HashTable *)candidate->typedata, name); if (h) { icp = Tcl_GetHashValue (h); if (icp->namespace == namespace) { pushToStack (sdata, icp); updateStack (sdata, se, ac); return 1; } } /* TODO: Short-cut in case of no match (looking * for empty match, recovering). For now fall * throu to simple, serial approach. */ } for (i = 0; i < candidate->nc; i++) { icp = candidate->content[i]; switch (icp->type) { case SCHEMA_CTYPE_TEXT: break; case SCHEMA_CTYPE_ANY: if (!matchingAny (namespace, icp)) break; updateStack (sdata, se, ac); sdata->skipDeep = 1; /* See comment in tDOM_probeElement: sdata->vname * and sdata->vns may be pre-filled. We reset it * here.*/ sdata->vname = NULL; sdata->vns = NULL; return 1; case SCHEMA_CTYPE_NAME: if (icp->name == name && icp->namespace == namespace) { pushToStack (sdata, icp); updateStack (sdata, se, ac); return 1; } break; case SCHEMA_CTYPE_CHOICE: SetResult ("MIXED or CHOICE child of MIXED or CHOICE"); sdata->evalError = 1; return 0; case SCHEMA_CTYPE_PATTERN: if (recursivePattern (se, icp)) { mayskip = 1; continue; } /* fall through */ case SCHEMA_CTYPE_INTERLEAVE: pushToStack (sdata, icp); rc = matchElementStart (interp, sdata, name, namespace); if (rc == 1) { updateStack (sdata, se, ac); return 1; } popStack (sdata); if (rc == -1) mayskip = 1; break; case SCHEMA_CTYPE_VIRTUAL: SetResult ("Virtual constrain in MIXED or CHOICE"); sdata->evalError = 1; return 0; case SCHEMA_CTYPE_KEYSPACE_END: case SCHEMA_CTYPE_KEYSPACE: SetResult ("Keyspace constrain in MIXED or CHOICE"); sdata->evalError = 1; return 0; case SCHEMA_CTYPE_JSON_STRUCT: SetResult ("JSON structure constrain in MIXED or CHOICE"); sdata->evalError = 2; return 0; } if (!mayskip && mayMiss (candidate->quants[i])) mayskip = 1; } break; case SCHEMA_CTYPE_VIRTUAL: if (evalVirtual (interp, sdata, ac)) { hm = 1; break; } else return 0; case SCHEMA_CTYPE_JSON_STRUCT: if (!checkJsonStructType ( interp, sdata, candidate, INVALID_JSON_TYPE, MATCH_ELEMENT_START, ac) ) { return 0; }; ac++; hm = 0; continue; case SCHEMA_CTYPE_PATTERN: if (recursivePattern (se, candidate)) { mayskip = 1; break; } /* fall through */ case SCHEMA_CTYPE_INTERLEAVE: pushToStack (sdata, candidate); rc = matchElementStart (interp, sdata, name, namespace); if (rc == 1) { updateStack (sdata, se, ac); return 1; } popStack (sdata); if (rc == -1) mayskip = 1; break; case SCHEMA_CTYPE_KEYSPACE_END: candidate->keySpace->active--; if (!candidate->keySpace->active) { if (candidate->keySpace->unknownIDrefs) { if (!recover (interp, sdata, INVALID_KEYREF, MATCH_ELEMENT_START, name, namespace, NULL, ac)) { SetResultV ("Invalid key ref."); sdata->evalError = 2; return 0; } candidate->keySpace->unknownIDrefs = 0; } Tcl_DeleteHashTable (&candidate->keySpace->ids); } ac++; hm = 0; continue; case SCHEMA_CTYPE_KEYSPACE: if (!candidate->keySpace->active) { Tcl_InitHashTable (&candidate->keySpace->ids, TCL_STRING_KEYS); candidate->keySpace->active = 1; candidate->keySpace->unknownIDrefs = 0; } else { candidate->keySpace->active++; } ac++; hm = 0; continue; } if (!mayskip && mustMatch (cp->quants[ac], hm)) { if (recover (interp, sdata, MISSING_ELEMENT, MATCH_ELEMENT_START, name, namespace, NULL, ac)) { if (sdata->recoverFlags & RECOVER_FLAG_IGNORE) { /* We pretend the ac content particle had * matched. */ updateStack (sdata, se, ac); } return 1; } return 0; } ac++; hm = 0; } if (isName) { if (recover (interp, sdata, UNEXPECTED_ELEMENT, MATCH_ELEMENT_START, name, namespace, NULL, 0)) { return 1; } return 0; } return -1; case SCHEMA_CTYPE_KEYSPACE: case SCHEMA_CTYPE_KEYSPACE_END: case SCHEMA_CTYPE_VIRTUAL: case SCHEMA_CTYPE_CHOICE: case SCHEMA_CTYPE_TEXT: case SCHEMA_CTYPE_ANY: case SCHEMA_CTYPE_JSON_STRUCT: /* Never pushed onto stack */ SetResult ("Invalid CTYPE onto the validation stack!"); sdata->evalError = 1; return 0; case SCHEMA_CTYPE_INTERLEAVE: mayskip = 1; for (i = 0; i < cp->nc; i++) { thismayskip = 0; if (se->interleaveState[i]) { if (maxOne (cp->quants[i])) continue; } icp = cp->content[i]; switch (icp->type) { case SCHEMA_CTYPE_TEXT: if (icp->nc) { if (checkText (interp, icp, "")) { thismayskip = 1; } } else { thismayskip = 1; } break; case SCHEMA_CTYPE_ANY: if (!matchingAny (namespace, icp)) break; sdata->skipDeep = 1; se->hasMatched = 1; se->interleaveState[i] = 1; /* See comment in tDOM_probeElement: sdata->vname and * sdata->vns may be pre-filled. We reset it here.*/ sdata->vname = NULL; sdata->vns = NULL; return 1; case SCHEMA_CTYPE_NAME: if (icp->name == name && icp->namespace == namespace) { pushToStack (sdata, icp); se->hasMatched = 1; se->interleaveState[i] = 1; return 1; } break; case SCHEMA_CTYPE_CHOICE: SetResult ("MIXED or CHOICE child of INTERLEAVE"); sdata->evalError = 1; return 0; case SCHEMA_CTYPE_PATTERN: if (recursivePattern (se, icp)) { thismayskip = 1; break; } /* fall through */ case SCHEMA_CTYPE_INTERLEAVE: pushToStack (sdata, icp); rc = matchElementStart (interp, sdata, name, namespace); if (rc == 1) { if (!(sdata->recoverFlags & RECOVER_FLAG_REWIND)) { se->hasMatched = 1; se->interleaveState[i] = 1; } return 1; } popStack (sdata); if (rc == -1) thismayskip = 1; break; case SCHEMA_CTYPE_VIRTUAL: SetResult ("Virtual constraint child of INTERLEAVE"); sdata->evalError = 1; return 0; case SCHEMA_CTYPE_KEYSPACE_END: case SCHEMA_CTYPE_KEYSPACE: SetResult ("Keyspace constraint child of INTERLEAVE"); sdata->evalError = 1; return 0; case SCHEMA_CTYPE_JSON_STRUCT: SetResult ("JSON structure constraint child of INTERLEAVE"); sdata->evalError = 1; return 0; } if (!thismayskip && minOne (cp->quants[i])) mayskip = 0; } if (mayskip) break; if (recover (interp, sdata, MISSING_ELEMENT, MATCH_ELEMENT_START, name, namespace, NULL, cp->nc)) { if (sdata->recoverFlags & RECOVER_FLAG_IGNORE) { /* We mark the first so far not matched mandatory * interleave child cp as matched */ for (i = 0; i < cp->nc; i++) { if (!se->interleaveState[i]) { if (minOne (cp->quants[i])) { se->interleaveState[i] = 1; break; } } } } return 1; } return 0; } return -1; } static void * getNamespacePtr ( SchemaData *sdata, char *ns ) { Tcl_HashEntry *h; int hnew; if (!ns) return NULL; if (ns[0] == '\0') return NULL; h = Tcl_FindHashEntry (&sdata->prefix, ns); if (h) { return Tcl_GetHashValue (h); } h = Tcl_CreateHashEntry (&sdata->namespace, ns, &hnew); return Tcl_GetHashKey (&sdata->namespace, h); } int tDOM_probeElement ( Tcl_Interp *interp, SchemaData *sdata, const char *name, void *namespace ) { Tcl_HashEntry *h; void *namespacePtr, *namePtr; SchemaCP *pattern; int rc = 1, reportError; if (sdata->skipDeep) { sdata->skipDeep++; return TCL_OK; } if (sdata->validationState == VALIDATION_FINISHED) { SetResult ("Validation finished."); return TCL_ERROR; } DBG( fprintf (stderr, "tDOM_probeElement: look if '%s' in ns '%s' match\n", name, (char *)namespace); ); if (namespace) { h = Tcl_FindHashEntry (&sdata->namespace, namespace); } else { h = NULL; } if (h) { namespacePtr = Tcl_GetHashKey (&sdata->namespace, h); } else { if (namespace) { /* This namespace isn't known at all by the schema; this * element may only match an any condition. If it does we * know only later. So we use namePtr and namespacePtr * both NULL that match nothing else in the schema and * will be able to look if there is such a possible any * match in the schema. */ rc = 0; /* If there isn't a matching any cp this is a validation * error. To have the node name/namespace information * available in case of recovering we prefill the sdata * struct here.*/ sdata->vname = name; sdata->vns = namespace; namespacePtr = (void *) unknownNS; } else { namespacePtr = NULL; } } if (!rc) { /* Already the provided namespace isn't known to the schema, * so the name in that namespace of course also. */ namePtr = NULL; } else { h = Tcl_FindHashEntry (&sdata->element, name); if (h) { namePtr = Tcl_GetHashKey (&sdata->element, h); } else { namePtr = NULL; /* Prefill in case of validation error. See above. */ sdata->vname = name; } } if (sdata->validationState == VALIDATION_READY) { /* The root of the tree to check. */ if (sdata->start) { if (strcmp (name, sdata->start) != 0) { if (recover (interp, sdata, UNEXPECTED_ROOT_ELEMENT, MATCH_ELEMENT_START, name, namespace, NULL, 0)) { sdata->validationState = VALIDATION_FINISHED; return TCL_OK; } SetResult ("Root element doesn't match"); return TCL_ERROR; } if (namespace) { if (!sdata->startNamespace|| strcmp (namespace, sdata->startNamespace) != 0) { if (recover (interp, sdata, UNEXPECTED_ROOT_ELEMENT, MATCH_ELEMENT_START, name, namespace, NULL, 0)) { sdata->validationState = VALIDATION_FINISHED; return TCL_OK; } SetResult ("Root element namespace doesn't match"); return TCL_ERROR; } } else { if (sdata->startNamespace) { if (recover (interp, sdata, UNEXPECTED_ROOT_ELEMENT, MATCH_ELEMENT_START, name, namespace, NULL, 0)) { sdata->validationState = VALIDATION_FINISHED; return TCL_OK; } SetResult ("Root element namespace doesn't match"); return TCL_ERROR; } } } reportError = 0; if (h) { pattern = (SchemaCP *) Tcl_GetHashValue (h); while (pattern) { if (pattern->namespace == namespacePtr) { if (pattern->flags & PLACEHOLDER_PATTERN_DEF || pattern->flags & FORWARD_PATTERN_DEF) { reportError = 1; } break; } pattern = pattern->next; } } else { pattern = NULL; } sdata->validationState = VALIDATION_STARTED; if (reportError || pattern == NULL) { if (recover (interp, sdata, UNKNOWN_ROOT_ELEMENT, MATCH_ELEMENT_START, name, namespace, NULL, 0)) { sdata->skipDeep = 1; return TCL_OK; } SetResult ("Unknown element"); return TCL_ERROR; } pushToStack (sdata, pattern); return TCL_OK; } /* The normal case: we're inside the tree */ /* In case of recovering and if the user wants a required cp to be * treated as matched (or in other words: that the validation * engine should ignore the mandatory state of the cp) we unwind * the call stack to have updated stack elements, to be able to * pretend, we have seen the mandatory cp. Now try to match the * open element from this stack state. */ while (1) { rc = matchElementStart (interp, sdata, (char *) namePtr, namespacePtr); while (rc == -1) { popStack (sdata); rc = matchElementStart (interp, sdata, (char *) namePtr, namespacePtr); }; if (rc) { DBG( fprintf (stderr, "tDOM_probeElement: element '%s' match\n", name); serializeStack (sdata); fprintf (stderr, "\n"); ); if (sdata->recoverFlags & RECOVER_FLAG_IGNORE) { sdata->recoverFlags &= ~RECOVER_FLAG_IGNORE; continue; } CHECK_REWIND; return TCL_OK; } break; } DBG( fprintf (stderr, "element '%s' DOESN'T match\n", name); serializeStack (sdata); fprintf (stderr, "\n"); ); if (!sdata->evalError) { SetResult ("Element \""); if (namespacePtr) { Tcl_AppendResult (interp, namespacePtr, ":", NULL); } Tcl_AppendResult (interp, name, "\" doesn't match", NULL); } return TCL_ERROR; } int probeAttribute ( Tcl_Interp *interp, SchemaData *sdata, const char *name, const char *ns, char *value, int *isrequired ) { unsigned int i; SchemaCP *cp; Tcl_HashTable *t; Tcl_HashEntry *h; SchemaAttr *attr; cp = sdata->stack->pattern; *isrequired = 0; if (cp->typedata) { t = (Tcl_HashTable *) cp->typedata; h = Tcl_FindHashEntry (t, name); if (!h) return 0; attr = (SchemaAttr *) Tcl_GetHashValue (h); while (attr && attr->namespace != ns) { attr = attr->next; } if (!attr) return 0; if (attr->cp) { if (!checkText (interp, attr->cp, value)) { if (!recover (interp, sdata, INVALID_ATTRIBUTE_VALUE, MATCH_ELEMENT_START, name, ns, value, 0)) { SetResult3V ("Attribute value doesn't match for " "attribute '", name , "'"); sdata->evalError = 2; return 0; } } } if (attr->required) *isrequired = 1; return 1; } for (i = 0; i < cp->numAttr; i++) { if (cp->attrs[i]->namespace == ns && cp->attrs[i]->name == name) { if (cp->attrs[i]->cp) { if (!checkText (interp, cp->attrs[i]->cp, value)) { if (!recover (interp, sdata, INVALID_ATTRIBUTE_VALUE, MATCH_ATTRIBUTE_TEXT, name, ns, value, i)) { SetResult3V ("Attribute value doesn't match for " "attribute '", name , "'"); sdata->evalError = 2; return 0; } } } if (cp->attrs[i]->required) *isrequired = 1; return 1; } } return 0; } int tDOM_probeAttributes ( Tcl_Interp *interp, SchemaData *sdata, const char **attr ) { char **atPtr, *ln, *namespace, *ns; int j, found, nsatt, req; unsigned int i, reqAttr = 0; SchemaCP *cp; Tcl_HashEntry *h; cp = sdata->stack->pattern; for (atPtr = (char **) attr; atPtr[0] && atPtr[1]; atPtr += 2) { found = 0; ln = atPtr[0]; j = 0; while (*ln && *ln != '\xFF') { j++, ln++; } if (*ln == '\xFF') { namespace = atPtr[0]; namespace[j] = '\0'; ln++; nsatt = 1; } else { namespace = NULL; ln = atPtr[0]; nsatt = 0; } h = Tcl_FindHashEntry (&sdata->attrNames, ln); if (!h) goto unknowncleanup; ln = Tcl_GetHashKey (&sdata->attrNames, h); ns = NULL; if (namespace) { h = Tcl_FindHashEntry (&sdata->namespace, namespace); if (!h) goto unknowncleanup; ns = Tcl_GetHashKey (&sdata->namespace, h); } found = probeAttribute (interp, sdata, ln, ns, atPtr[1], &req); if (sdata->evalError) { return TCL_ERROR; } reqAttr += req; unknowncleanup: if (!found) { if (!recover (interp, sdata, UNKNOWN_ATTRIBUTE, MATCH_ELEMENT_START, ln, namespace, NULL, 0)) { if (!sdata->evalError) { if (nsatt) { SetResult ("Unknown attribute \""); Tcl_AppendResult (interp, namespace, ":", ln, "\"", NULL); } else { SetResult3 ("Unknown attribute \"", ln, "\""); } } if (nsatt) namespace[j] = '\xFF'; return TCL_ERROR; } } if (nsatt) namespace[j] = '\xFF'; } if (reqAttr != cp->numReqAttr) { /* Lookup the missing attribute(s) */ if (!sdata->evalError) { SetResult ("Missing mandatory attribute(s):"); } for (i = 0; i < cp->numAttr; i++) { if (!cp->attrs[i]->required) continue; found = 0; for (atPtr = (char **) attr; atPtr[0] && atPtr[1]; atPtr += 2) { ln = atPtr[0]; if (cp->attrs[i]->namespace) { j = 0; while (*ln && *ln != '\xFF') { j++, ln++; } if (*ln == '\xFF') { namespace = atPtr[0]; namespace[j] = '\0'; ln++; nsatt = 1; } else { continue; } if (strcmp (cp->attrs[i]->namespace, namespace) != 0) { if (nsatt) namespace[j] = '\xFF'; continue; } if (nsatt) namespace[j] = '\xFF'; } if (strcmp (ln, cp->attrs[i]->name) == 0) { found = 1; break; } } if (!found) { if (!recover (interp, sdata, MISSING_ATTRIBUTE, MATCH_ELEMENT_START, cp->attrs[i]->name, cp->attrs[i]->namespace, NULL, i)) { if (cp->attrs[i]->namespace) { Tcl_AppendResult (interp, " ", cp->attrs[i]->namespace, ":", cp->attrs[i]->name, NULL); } else { Tcl_AppendResult (interp, " ", cp->attrs[i]->name, NULL); } } } } if (!sdata->reportCmd) { return TCL_ERROR; } } return TCL_OK; } int tDOM_probeDomAttributes ( Tcl_Interp *interp, SchemaData *sdata, domAttrNode *attr ) { domAttrNode *atPtr; int found, req; unsigned int i, reqAttr = 0; const char *ns, *ln; SchemaCP *cp; Tcl_HashEntry *h; cp = sdata->stack->pattern; atPtr = attr; while (atPtr) { if (atPtr->nodeFlags & IS_NS_NODE) goto nextAttr; found = 0; if (atPtr->namespace) { ns = domNamespaceURI ((domNode *)atPtr); /* A namespaced attribute must always have a prefix */ ln = atPtr->nodeName; while (*ln) { if (*ln == ':') { ln++; break; } ln++; } } else { ns = NULL; ln = atPtr->nodeName; } h = Tcl_FindHashEntry (&sdata->attrNames, ln); if (!h) goto unknown; ln = Tcl_GetHashKey (&sdata->attrNames, h); if (ns) { h = Tcl_FindHashEntry (&sdata->namespace, ns); if (!h) goto unknown; ns = Tcl_GetHashKey (&sdata->namespace, h); } else { ns = NULL; } found = probeAttribute (interp, sdata, ln, ns, atPtr->nodeValue, &req); reqAttr += req; unknown: if (!found) { if (!recover (interp, sdata, UNKNOWN_ATTRIBUTE, MATCH_ELEMENT_START, ln, ns, NULL, 0)) { if (!sdata->evalError) { if (ns) { SetResult ("Unknown attribute \""); Tcl_AppendResult (interp, ns, ":", atPtr->nodeName, "\"", NULL); } else { SetResult3 ("Unknown attribute \"", atPtr->nodeName, "\""); } sdata->validationState = VALIDATION_ERROR; } return TCL_ERROR; } } nextAttr: atPtr = atPtr->nextSibling; } if (reqAttr != cp->numReqAttr) { /* Lookup the missing attribute(s) */ if (!sdata->evalError) { SetResult ("Missing mandatory attribute(s):"); } for (i = 0; i < cp->numAttr; i++) { if (!cp->attrs[i]->required) continue; found = 0; atPtr = attr; while (atPtr) { if (cp->attrs[i]->namespace) { if (!atPtr->namespace) goto nextAttr2; ns = domNamespaceURI ((domNode *)atPtr); if (strcmp (ns, cp->attrs[i]->namespace) != 0) { goto nextAttr2; } ln = atPtr->nodeName; while (*ln) { if (*ln == ':') { ln++; break; } ln++; } } else { if (atPtr->namespace) goto nextAttr2; ln = atPtr->nodeName; } if (strcmp (ln, cp->attrs[i]->name) == 0) { found = 1; break; } nextAttr2: atPtr = atPtr->nextSibling; } if (!found) { if (!recover (interp, sdata, MISSING_ATTRIBUTE, MATCH_ELEMENT_START, cp->attrs[i]->name, cp->attrs[i]->namespace, NULL, i)) { if (!sdata->evalError) { if (cp->attrs[i]->namespace) { Tcl_AppendResult (interp, " ", cp->attrs[i]->namespace, ":", cp->attrs[i]->name, NULL); } else { Tcl_AppendResult (interp, " ", cp->attrs[i]->name, NULL); } } } } } if (!sdata->reportCmd) { sdata->validationState = VALIDATION_ERROR; return TCL_ERROR; } } return TCL_OK; } static int probeEventAttribute ( Tcl_Interp *interp, SchemaData *sdata, Tcl_Obj *attr, domLength len ) { int found, req; domLength i; unsigned int reqAttr = 0; char *name, *ns; SchemaCP *cp; Tcl_HashEntry *h; Tcl_Obj *attname, *attns, *attvalue; cp = sdata->stack->pattern; for (i = 0; i < len; i += 2) { found = 0; ns = NULL; name = NULL; attns = NULL; Tcl_ListObjIndex (interp, attr, i, &attname); Tcl_ListObjIndex (interp, attr, i+1, &attvalue); if (Tcl_ListObjLength (interp, attname, &len) == TCL_OK) { if (len == 2) { Tcl_ListObjIndex (interp, attname, 1, &attns); Tcl_ListObjIndex (interp, attname, 0, &attname); } } h = Tcl_FindHashEntry (&sdata->attrNames, Tcl_GetString (attname)); if (!h) goto unknown; name = Tcl_GetHashKey (&sdata->attrNames, h); if (attns) { h = Tcl_FindHashEntry (&sdata->namespace, Tcl_GetString (attns)); if (!h) goto unknown; ns = Tcl_GetHashKey (&sdata->namespace, h); } found = probeAttribute (interp, sdata, name, ns, Tcl_GetString (attvalue), &req); reqAttr += req; unknown: if (!found) { if (!recover (interp, sdata, UNKNOWN_ATTRIBUTE, MATCH_ELEMENT_START, Tcl_GetString (attname), Tcl_GetString (attns), NULL, 0)) { if (ns) { SetResult ("Unknown attribute \""); Tcl_AppendResult (interp, ns, ":", name, "\"", NULL); } else { SetResult3 ("Unknown attribute \"", name, "\""); } sdata->validationState = VALIDATION_ERROR; return TCL_ERROR; } } } if (reqAttr != cp->numReqAttr) { SetResult ("Missing mandatory attribute(s)"); return TCL_ERROR; } return TCL_OK; } /* Returns either -1, 0, 1, 2 -1 means a pattern or an interleave ended without error, look further at parents next sibling. 0 means rewind with validation error. 1 means element content may end here. 2 means recovering requested further error reporting about missing children in the current element. To be able to answer a [info expected] on the occasion of the next error, we update the stack in this case and let tDOM_probeElementEnd restart checkElementEnd again with this stack state. */ static int checkElementEnd ( Tcl_Interp *interp, SchemaData *sdata ) { SchemaValidationStack *se; SchemaCP *cp, *ic; int hm, thismayskip, mayskip = 0, rc; unsigned int ac, i; int isName = 0; DBG(fprintf (stderr, "checkElementEnd:\n"); serializeStack(sdata);); se = sdata->stack; getContext (cp, ac, hm); if (cp->type == SCHEMA_CTYPE_INTERLEAVE) { ac = 0; hm = 0; mayskip = 1; } switch (cp->type) { case SCHEMA_CTYPE_NAME: isName = 1; /* Fall through */ case SCHEMA_CTYPE_INTERLEAVE: case SCHEMA_CTYPE_PATTERN: if (ac < cp->nc && (hasMatched (cp->quants[ac], hm))) { DBG(fprintf (stderr, "ac %d has matched, skipping to next ac\n", ac)); ac++; hm = 0; } while (ac < cp->nc) { DBG(fprintf (stderr, "ac %d hm %d mayMiss: %d\n", ac, hm, mayMiss (cp->quants[ac]))); if (se->interleaveState && se->interleaveState[ac]) { ac++; continue; } if (mayMiss (cp->quants[ac])) { ac++; continue; } switch (cp->content[ac]->type) { case SCHEMA_CTYPE_KEYSPACE_END: /* Don't happen as INTERLEAVE child */ cp->content[ac]->keySpace->active--; if (!cp->content[ac]->keySpace->active) { if (cp->content[ac]->keySpace->unknownIDrefs) { if (!recover (interp, sdata, INVALID_KEYREF, MATCH_ELEMENT_END, NULL, NULL, cp->content[ac]->keySpace->name, 0)) { SetResultV ("Invalid key ref."); sdata->evalError = 2; return 0; } cp->content[ac]->keySpace->unknownIDrefs = 0; } Tcl_DeleteHashTable (&cp->content[ac]->keySpace->ids); } break; case SCHEMA_CTYPE_KEYSPACE: /* Don't happen as INTERLEAVE child */ if (!cp->content[ac]->keySpace->active) { Tcl_InitHashTable (&cp->content[ac]->keySpace->ids, TCL_STRING_KEYS); cp->content[ac]->keySpace->active = 1; cp->content[ac]->keySpace->unknownIDrefs = 0; } else { cp->content[ac]->keySpace->active++; } break; case SCHEMA_CTYPE_TEXT: if (cp->content[ac]->nc) { if (!checkText (interp, cp->content[ac], "")) { if (recover (interp, sdata, MISSING_TEXT, MATCH_ELEMENT_END, NULL, NULL, NULL, ac)) { break; } return 0; } } break; case SCHEMA_CTYPE_CHOICE: /* Don't happen as INTERLEAVE child */ thismayskip = 0; for (i = 0; i < cp->content[ac]->nc; i++) { if (mayMiss (cp->content[ac]->quants[i])) { thismayskip = 1; break; } ic = cp->content[ac]->content[i]; switch (ic->type) { case SCHEMA_CTYPE_TEXT: if (ic->nc) { if (!checkText (interp, ic, "")) { continue; } } thismayskip = 1; break; case SCHEMA_CTYPE_NAME: case SCHEMA_CTYPE_ANY: continue; case SCHEMA_CTYPE_PATTERN: if (recursivePattern (se, ic)) { thismayskip = 1; break; } /* fall through */ case SCHEMA_CTYPE_INTERLEAVE: pushToStack (sdata, ic); if (checkElementEnd (interp, sdata) == -1) { thismayskip = 1; } popStack (sdata); break; case SCHEMA_CTYPE_KEYSPACE_END: case SCHEMA_CTYPE_KEYSPACE: case SCHEMA_CTYPE_VIRTUAL: case SCHEMA_CTYPE_JSON_STRUCT: case SCHEMA_CTYPE_CHOICE: SetResult ("Invalid CTYPE in MIXED or CHOICE"); sdata->evalError = 1; return 0; } if (thismayskip) break; } if (thismayskip) break; if (!recover (interp, sdata, MISSING_ELEMENT, MATCH_ELEMENT_END, NULL, NULL, NULL, 0)) { return 0; } if (sdata->recoverFlags & RECOVER_FLAG_MATCH_END_CONTINUE) { updateStack (sdata, se, ac); return 2; } break; case SCHEMA_CTYPE_VIRTUAL: if (evalVirtual (interp, sdata, ac)) break; else return 0; case SCHEMA_CTYPE_JSON_STRUCT: if (!checkJsonStructType (interp, sdata, cp->content[ac], INVALID_JSON_TYPE, MATCH_ELEMENT_END, ac)) { return 0; } break; case SCHEMA_CTYPE_PATTERN: if (recursivePattern (se, cp->content[ac])) { break; } /* fall through */ case SCHEMA_CTYPE_INTERLEAVE: pushToStack (sdata, cp->content[ac]); rc = checkElementEnd (interp, sdata); if (rc == 0) { popStack (sdata); if (sdata->stack->pattern->type == SCHEMA_CTYPE_NAME || sdata->stack->activeChild || sdata->stack->hasMatched) { if (recover (interp, sdata, MISSING_ELEMENT, MATCH_ELEMENT_END, NULL, NULL, NULL, 0)) { if (sdata->recoverFlags & RECOVER_FLAG_MATCH_END_CONTINUE) { updateStack (sdata, se, ac); return 2; } break; } } return 0; } if (rc == 2) { updateStack (sdata, se, ac); return 2; } popStack (sdata); break; case SCHEMA_CTYPE_ANY: case SCHEMA_CTYPE_NAME: if (recover (interp, sdata, MISSING_ELEMENT, MATCH_ELEMENT_END, NULL, NULL, NULL, 0)) { if (sdata->recoverFlags & RECOVER_FLAG_MATCH_END_CONTINUE) { updateStack (sdata, se, ac); return 2; } break; } return 0; } ac++; } if (se->interleaveState) { if (!mayskip) return 0; } if (isName) return 1; return -1; case SCHEMA_CTYPE_KEYSPACE_END: case SCHEMA_CTYPE_KEYSPACE: case SCHEMA_CTYPE_VIRTUAL: case SCHEMA_CTYPE_CHOICE: case SCHEMA_CTYPE_TEXT: case SCHEMA_CTYPE_ANY: case SCHEMA_CTYPE_JSON_STRUCT: /* Never pushed onto stack */ SetResult ("Invalid CTYPE onto the validation stack!"); sdata->evalError = 1; return 0; } /* Not reached */ return 0; } static int checkDocKeys ( Tcl_Interp *interp, SchemaData *sdata ) { Tcl_HashEntry *h, *h1; Tcl_HashSearch search, search1; int haveErrMsg = 0; SchemaDocKey *dk; if (sdata->evalError) return 0; if (sdata->unknownIDrefs) { if (!recover (interp, sdata, UNKNOWN_ID, MATCH_GLOBAL, NULL, NULL, NULL, 0)) { haveErrMsg = 1; SetResult ("References to unknown IDs:"); for (h = Tcl_FirstHashEntry (&sdata->ids, &search); h != NULL; h = Tcl_NextHashEntry (&search)) { if (Tcl_GetHashValue (h) == 0) { Tcl_AppendResult (interp, " '", Tcl_GetHashKey (&sdata->ids, h), "'", NULL); } } } } if (sdata->idTables.numEntries) { for (h = Tcl_FirstHashEntry (&sdata->idTables, &search); h != NULL; h = Tcl_NextHashEntry (&search)) { dk = Tcl_GetHashValue (h); if (dk->unknownIDrefs) { if (!recover (interp, sdata, UNKNOWN_GLOBAL_ID, MATCH_GLOBAL, NULL, NULL, NULL, 0)) { if (haveErrMsg) { Tcl_AppendResult (interp, "\n", NULL); } else { haveErrMsg = 1; } Tcl_AppendResult (interp, "References to unknown IDs in ID space '", Tcl_GetHashKey (&sdata->idTables, h), "':", NULL); for (h1 = Tcl_FirstHashEntry (&dk->ids, &search1); h1 != NULL; h1 = Tcl_NextHashEntry (&search1)) { if (Tcl_GetHashValue (h1) == 0) { Tcl_AppendResult (interp, " '", Tcl_GetHashKey (&dk->ids, h1), "'", NULL); } } } } } } if (haveErrMsg) { sdata->validationState = VALIDATION_ERROR; return 0; } return 1; } int tDOM_probeElementEnd ( Tcl_Interp *interp, SchemaData *sdata ) { int rc; DBG(if (sdata->stack) { fprintf (stderr, "tDOM_probeElementEnd: look if current stack top can " " end name: '%s' deep: %d\n", sdata->stack->pattern->name, getDeep (sdata->stack)); } else {fprintf (stderr, "stack is NULL\n");} ); if (sdata->skipDeep) { sdata->skipDeep--; return TCL_OK; } if (sdata->validationState == VALIDATION_FINISHED) { SetResult ("Validation finished"); return TCL_ERROR; } if (sdata->validationState == VALIDATION_READY) { SetResult ("No validation started"); return TCL_ERROR; } if (sdata->validationState == VALIDATION_ERROR) { return TCL_ERROR; } while (1) { rc = checkElementEnd (interp, sdata); while (rc == -1) { popStack (sdata); rc = checkElementEnd (interp, sdata); } sdata->recoverFlags &= ~RECOVER_FLAG_DONT_REPORT; if (rc == 2) { sdata->recoverFlags &= ~RECOVER_FLAG_MATCH_END_CONTINUE; continue; } if (rc == 1) { popStack (sdata); if (sdata->stack == NULL) { /* End of the first pattern (the tree root) without error. */ /* Check for unknown ID references */ if (!checkDocKeys (interp, sdata)) { return TCL_ERROR; } /* We have successfully finished validation */ sdata->validationState = VALIDATION_FINISHED; } DBG( fprintf(stderr, "tDOM_probeElementEnd: _CAN_ end here.\n"); serializeStack (sdata); ); return TCL_OK; } break; } SetResultV ("Missing mandatory content"); sdata->validationState = VALIDATION_ERROR; DBG( fprintf(stderr, "tDOM_probeElementEnd: CAN'T end here.\n"); serializeStack (sdata); ); return TCL_ERROR; } static int matchText ( Tcl_Interp *interp, SchemaData *sdata, char *text ) { SchemaCP *cp, *candidate, *ic; SchemaValidationStack *se; int hm, isName = 0, mayskip; unsigned int ac, i; DBG(fprintf (stderr, "matchText called with text '%s'\n", text)); se = sdata->stack; getContext (cp, ac, hm); while (1) { switch (cp->type) { case SCHEMA_CTYPE_NAME: isName = 1; /* fall through */ case SCHEMA_CTYPE_PATTERN: while (ac < cp->nc) { candidate = cp->content[ac]; switch (candidate->type) { case SCHEMA_CTYPE_TEXT: if (checkText (interp, candidate, text)) { updateStack (sdata, se, ac); return 1; } if (sdata->evalError) return 0; if (recover (interp, sdata, INVALID_VALUE, MATCH_TEXT, NULL, NULL, text, ac)) { updateStack (sdata, se, ac); return 1; } SetResult ("Invalid text content"); return 0; case SCHEMA_CTYPE_CHOICE: if (candidate->flags & MIXED_CONTENT) { updateStack (sdata, se, ac); return 1; } for (i = 0; i < candidate->nc; i++) { ic = candidate->content[i]; switch (ic->type) { case SCHEMA_CTYPE_TEXT: if (checkText (interp, ic, text)) { updateStack (sdata, se, ac); return 1; } break; case SCHEMA_CTYPE_NAME: case SCHEMA_CTYPE_ANY: break; case SCHEMA_CTYPE_PATTERN: if (recursivePattern (se, ic)) { break; } /* fall through */ case SCHEMA_CTYPE_INTERLEAVE: pushToStack (sdata, ic); if (matchText (interp, sdata, text)) { updateStack (sdata, se, ac); return 1; } popStack (sdata); break; case SCHEMA_CTYPE_VIRTUAL: SetResult ("Virtual constrain in MIXED or" " CHOICE"); sdata->evalError = 1; return 0; case SCHEMA_CTYPE_CHOICE: SetResult ("MIXED or CHOICE child of MIXED or" " CHOICE"); sdata->evalError = 1; return 0; case SCHEMA_CTYPE_KEYSPACE_END: case SCHEMA_CTYPE_KEYSPACE: SetResult ("Keyspace constrain in MIXED or" " CHOICE"); sdata->evalError = 1; return 0; case SCHEMA_CTYPE_JSON_STRUCT: SetResult ("JSON structure constrain in MIXED or" " CHOICE"); sdata->evalError = 1; return 0; } } if (mustMatch (cp->quants[ac], hm)) { if (recover (interp, sdata, UNEXPECTED_TEXT, MATCH_TEXT, NULL, NULL, text, 0)) { return 1; } SetResultV ("Unexpected text content"); return 0; } break; case SCHEMA_CTYPE_PATTERN: if (recursivePattern (se, candidate)) { break; } /* fall through */ case SCHEMA_CTYPE_INTERLEAVE: pushToStack (sdata, candidate); if (matchText (interp, sdata, text)) { updateStack (sdata, se, ac); return 1; } popStack (sdata); if (mustMatch (cp->quants[ac], hm)) { if (recover (interp, sdata, UNEXPECTED_TEXT, MATCH_TEXT, NULL, NULL, text, 0)) { return 1; } SetResultV ("Unexpected text content"); return 0; } break; case SCHEMA_CTYPE_VIRTUAL: if (!evalVirtual (interp, sdata, ac)) return 0; break; case SCHEMA_CTYPE_JSON_STRUCT: if (checkJsonStructType (interp, sdata, candidate, INVALID_JSON_TYPE, MATCH_TEXT, ac)) { ac++; continue; } return 0; case SCHEMA_CTYPE_KEYSPACE: if (!cp->content[ac]->keySpace->active) { Tcl_InitHashTable (&cp->content[ac]->keySpace->ids, TCL_STRING_KEYS); cp->content[ac]->keySpace->active = 1; cp->content[ac]->keySpace->unknownIDrefs = 0; } else { cp->content[ac]->keySpace->active++; } break; case SCHEMA_CTYPE_KEYSPACE_END: cp->content[ac]->keySpace->active--; if (!cp->content[ac]->keySpace->active) { if (cp->content[ac]->keySpace->unknownIDrefs) { if (!recover (interp, sdata, INVALID_KEYREF, MATCH_TEXT, NULL, NULL, text, ac)) { return 0; SetResultV ("Invalid key ref."); sdata->evalError = 2; } cp->content[ac]->keySpace->unknownIDrefs = 0; } Tcl_DeleteHashTable (&cp->content[ac]->keySpace->ids); } break; case SCHEMA_CTYPE_NAME: case SCHEMA_CTYPE_ANY: if (mustMatch (cp->quants[ac], hm)) { if (recover (interp, sdata, UNEXPECTED_TEXT, MATCH_TEXT, NULL, NULL, text, ac)) { return 1; } SetResultV ("Unexpected text content"); return 0; } break; } ac++; } if (isName) { if (recover (interp, sdata, UNEXPECTED_TEXT, MATCH_TEXT, NULL, NULL, text, 0)) { return 1; } SetResultV ("Unexpected text content"); return 0; } popStack (sdata); se = sdata->stack; getContext (cp, ac, hm); ac++; continue; case SCHEMA_CTYPE_KEYSPACE: case SCHEMA_CTYPE_KEYSPACE_END: case SCHEMA_CTYPE_VIRTUAL: case SCHEMA_CTYPE_JSON_STRUCT: case SCHEMA_CTYPE_CHOICE: case SCHEMA_CTYPE_TEXT: case SCHEMA_CTYPE_ANY: /* Never pushed onto stack */ SetResult ("Invalid CTYPE onto the validation stack!"); sdata->evalError = 1; return 0; case SCHEMA_CTYPE_INTERLEAVE: mayskip = 1; for (i = 0; i < cp->nc; i++) { if (se->interleaveState[i]) { if (maxOne (cp->quants[i])) continue; } else { if (minOne (cp->quants[i])) mayskip = 0; } ic = cp->content[i]; switch (ic->type) { case SCHEMA_CTYPE_TEXT: if (checkText (interp, ic, text)) { if (!(sdata->recoverFlags & RECOVER_FLAG_REWIND)) { se->hasMatched = 1; se->interleaveState[i] = 1; } return 1; } break; case SCHEMA_CTYPE_NAME: case SCHEMA_CTYPE_ANY: break; case SCHEMA_CTYPE_PATTERN: if (recursivePattern (se, ic)) { break; } /* fall through */ case SCHEMA_CTYPE_INTERLEAVE: pushToStack (sdata, ic); if (matchText (interp, sdata, text)) { updateStack (sdata, se, ac); return 1; } popStack (sdata); break; case SCHEMA_CTYPE_CHOICE: SetResult ("MIXED or CHOICE child of INTERLEAVE"); sdata->evalError = 1; return 0; case SCHEMA_CTYPE_KEYSPACE_END: case SCHEMA_CTYPE_KEYSPACE: SetResult ("Keyspace child of INTERLEAVE"); sdata->evalError = 1; return 0; case SCHEMA_CTYPE_VIRTUAL: break; case SCHEMA_CTYPE_JSON_STRUCT: SetResult ("JSON structure constraint child of" "INTERLEAVE"); sdata->evalError = 1; return 0; } } if (!mayskip) { if (recover (interp, sdata, UNEXPECTED_TEXT, MATCH_TEXT, NULL, NULL, text, ac)) { return 1; } SetResultV ("Unexpected text content"); return 0; } popStack (sdata); se = sdata->stack; getContext (cp, ac, hm); ac++; continue; } /* Not reached, but this is inside a while (1) {} loop ...*/ break; } /* Not reached, but at least makes the compiler happy. */ return 0; } int tDOM_probeText ( Tcl_Interp *interp, SchemaData *sdata, char *text, int *only_whites ) { int myonly_whites; char *pc; DBG(fprintf (stderr, "tDOM_probeText started, text: '%s'\n", text);) if (sdata->skipDeep) { return TCL_OK; } if (sdata->validationState == VALIDATION_FINISHED) { SetResult ("Validation finished"); return TCL_ERROR; } if (sdata->validationState == VALIDATION_READY) { SetResult ("No validation started"); return TCL_ERROR; } if (sdata->stack->pattern->flags & CONSTRAINT_TEXT_CHILD) { if (!*text && sdata->stack->pattern->nc == 0) { return TCL_OK; } if (matchText (interp, sdata, text)) { CHECK_REWIND; return TCL_OK; } } else { if (only_whites) { myonly_whites = *only_whites; } else { myonly_whites = 1; pc = text; while (SPACE (*pc)) pc++; if (*pc) myonly_whites = 0; } if (myonly_whites) return TCL_OK; if (matchText (interp, sdata, text)) { CHECK_REWIND; return TCL_OK; } } if (!sdata->evalError) { SetResult ("Text content doesn't match"); } return TCL_ERROR; } static void startElement( void *userData, const char *name, const char **atts ) { ValidateMethodData *vdata = (ValidateMethodData *) userData; SchemaData *sdata; char *namespace; const char *s; int i = 0; DBG(fprintf (stderr, "startElement: '%s'\n", name);) sdata = vdata->sdata; if (!sdata->skipDeep && sdata->stack && Tcl_DStringLength (vdata->cdata)) { if (tDOM_probeText (vdata->interp, sdata, Tcl_DStringValue (vdata->cdata), NULL) != TCL_OK) { sdata->validationState = VALIDATION_ERROR; XML_StopParser (vdata->parser, 0); Tcl_DStringSetLength (vdata->cdata, 0); vdata->onlyWhiteSpace = 1; return; } Tcl_DStringSetLength (vdata->cdata, 0); vdata->onlyWhiteSpace = 1; } s = name; while (*s && *s != '\xFF') { i++; s++; } namespace = NULL; if (*s == '\xFF') { s++; if (i) { if (i >= vdata->maxUriLen - 1) { vdata->uri = (char *) REALLOC (vdata->uri, vdata->maxUriLen * 2); vdata->maxUriLen *= 2; } memcpy (vdata->uri, name, i); vdata->uri[i] = '\0'; namespace = vdata->uri; } } else { s = name; } if (tDOM_probeElement (vdata->interp, sdata, s, namespace) != TCL_OK) { sdata->validationState = VALIDATION_ERROR; XML_StopParser (vdata->parser, 0); return; } if (sdata->skipDeep == 0 && (atts[0] || (sdata->stack && sdata->stack->pattern->attrs))) { if (tDOM_probeAttributes (vdata->interp, sdata, atts) != TCL_OK) { sdata->validationState = VALIDATION_ERROR; XML_StopParser (vdata->parser, 0); } } } static void endElement ( void *userData, const char *UNUSED(name) ) { ValidateMethodData *vdata = (ValidateMethodData *) userData; SchemaData *sdata; DBG(fprintf (stderr, "endElement: '%s'\n", name);) sdata = vdata->sdata; if (sdata->validationState == VALIDATION_ERROR) { return; } if (!sdata->skipDeep && sdata->stack && Tcl_DStringLength (vdata->cdata)) { if (tDOM_probeText (vdata->interp, sdata, Tcl_DStringValue (vdata->cdata), NULL) != TCL_OK) { sdata->validationState = VALIDATION_ERROR; XML_StopParser (vdata->parser, 0); Tcl_DStringSetLength (vdata->cdata, 0); vdata->onlyWhiteSpace = 1; return; } } if (Tcl_DStringLength (vdata->cdata)) { Tcl_DStringSetLength (vdata->cdata, 0); vdata->onlyWhiteSpace = 1; } if (tDOM_probeElementEnd (vdata->interp, sdata) != TCL_OK) { sdata->validationState = VALIDATION_ERROR; XML_StopParser (vdata->parser, 0); } } static void characterDataHandler ( void *userData, const char *s, int len ) { ValidateMethodData *vdata = (ValidateMethodData *) userData; const char *pc; if (vdata->onlyWhiteSpace) { int i = 0; pc = s; while (i < len) { if ( (*pc == ' ') || (*pc == '\n') || (*pc == '\r') || (*pc == '\t') ) { pc++; i++; continue; } vdata->onlyWhiteSpace = 0; break; } } Tcl_DStringAppend (vdata->cdata, s, len); } static void schemaxpathRSFree ( xpathResultSet *rs ) { if (rs->type == StringResult) FREE (rs->string); FREE (rs->nodes); } static int checkdomKeyConstraints ( Tcl_Interp *interp, SchemaData *sdata, domNode *node ) { xpathResultSet nodeList, rs, frs; domKeyConstraint *kc; domNode *n; domAttrNode *attr; int rc, i, j, hnew, skip, first; domLength len; char *errMsg = NULL, *keystr, *efsv; Tcl_HashTable htable; Tcl_DString dStr; xpathCBs cbs; kc = sdata->stack->pattern->domKeys; memset (&nodeList, 0, sizeof (xpathResultSet)); nodeList.type = EmptyResult; memset (&rs, 0, sizeof (xpathResultSet)); rs.type = EmptyResult; memset (&frs, 0, sizeof (xpathResultSet)); frs.type = EmptyResult; Tcl_DStringInit (&dStr); xpathRSReset (&nodeList, node); cbs.funcCB = tcldom_xpathFuncCallBack; cbs.funcClientData = interp; cbs.varCB = NULL; cbs.varClientData = NULL; while (kc) { xpathRSReset (&rs, NULL); rc = xpathEvalAst (kc->selector, &nodeList, node, &cbs, &rs, &errMsg); if (rc) { SetResult (errMsg); goto booleanErrorCleanup; } if (kc->flags & DKC_FLAG_BOOLEAN) { i = xpathFuncBoolean (&rs); if (!i) { if (!recover (interp, sdata, DOM_XPATH_BOOLEAN, MATCH_DOM_KEYCONSTRAINT, kc->name, NULL, NULL, 0)) { SetResultV ("INVALID_DOM_XPATH_BOOLEAN"); goto booleanErrorCleanup; } } kc = kc->next; continue; } if (rs.type == EmptyResult) goto nextConstraint; if (rs.type != xNodeSetResult) { SetResult ("INVALID_DOM_KEYCONSTRAINT"); goto errorCleanup; } Tcl_InitHashTable (&htable, TCL_STRING_KEYS); for (i = 0; i < rs.nr_nodes; i++) { n = rs.nodes[i]; if (n->nodeType != ELEMENT_NODE) { SetResult ("INVALID_DOM_KEYCONSTRAINT"); goto errorCleanup; } xpathRSReset (&nodeList, n); if (kc->nrFields == 1) { xpathRSReset (&frs, NULL); rc = xpathEvalAst (kc->fields[0], &nodeList, n, &cbs, &frs, &errMsg); if (rc) { SetResult (errMsg); goto errorCleanup; } if (frs.type != xNodeSetResult && frs.type != EmptyResult) { SetResult ("INVALID_DOM_KEYCONSTRAINT"); goto errorCleanup; } if (frs.type == EmptyResult || frs.nr_nodes == 0) { if (kc->flags & DKC_FLAG_IGNORE_EMPTY_FIELD_SET) { continue; } efsv = ""; if (kc->emptyFieldSetValue) { efsv = kc->emptyFieldSetValue; } Tcl_CreateHashEntry (&htable, efsv, &hnew); if (!hnew) { if (recover (interp, sdata, DOM_KEYCONSTRAINT, MATCH_DOM_KEYCONSTRAINT, kc->name, NULL, efsv, 0)) { break; } SetResultV ("DOM_KEYCONSTRAINT"); goto errorCleanup; } continue; } if (frs.nr_nodes != 1) { if (recover (interp, sdata, DOM_KEYCONSTRAINT, MATCH_DOM_KEYCONSTRAINT, kc->name, NULL, NULL, 0)) { break; } SetResultV ("DOM_KEYCONSTRAINT"); goto errorCleanup; } if (frs.nodes[0]->nodeType != ELEMENT_NODE && frs.nodes[0]->nodeType != ATTRIBUTE_NODE) { SetResult ("INVALID_DOM_KEYCONSTRAINT"); goto errorCleanup; } if (frs.nodes[0]->nodeType == ATTRIBUTE_NODE) { attr = (domAttrNode *) frs.nodes[0]; Tcl_CreateHashEntry (&htable, attr->nodeValue, &hnew); if (!hnew) { if (recover (interp, sdata, DOM_KEYCONSTRAINT, MATCH_DOM_KEYCONSTRAINT, kc->name, NULL, attr->nodeValue, 0)) { break; } SetResultV ("DOM_KEYCONSTRAINT"); goto errorCleanup; } } else { keystr = xpathGetStringValue (frs.nodes[0], &len); Tcl_CreateHashEntry (&htable, keystr, &hnew); if (!hnew) { if (recover (interp, sdata, DOM_KEYCONSTRAINT, MATCH_DOM_KEYCONSTRAINT, kc->name, NULL, keystr, 0)) { FREE(keystr); break; } FREE(keystr); SetResultV ("DOM_KEYCONSTRAINT"); goto errorCleanup; } FREE(keystr); } } else { Tcl_DStringSetLength (&dStr, 0); skip = 0; first = 1; for (j = 0; j < kc->nrFields; j++) { xpathRSReset (&frs, NULL); rc = xpathEvalAst (kc->fields[j], &nodeList, n, &cbs, &frs, &errMsg); if (rc) { SetResult (errMsg); goto errorCleanup; } if (frs.type != xNodeSetResult && frs.type != EmptyResult) { SetResult ("INVALID_DOM_KEYCONSTRAINT"); goto errorCleanup; } if (frs.type == EmptyResult || frs.nr_nodes == 0) { if (kc->flags & DKC_FLAG_IGNORE_EMPTY_FIELD_SET) { continue; } if (kc->emptyFieldSetValue) { if (first) first = 0; else Tcl_DStringAppend (&dStr, ":", 1); Tcl_DStringAppend (&dStr, kc->emptyFieldSetValue, (domLength)kc->efsv_len); } else { if (first) first = 0; else Tcl_DStringAppend (&dStr, ":", 1); } continue; } if (frs.nr_nodes != 1) { if (recover (interp, sdata, DOM_KEYCONSTRAINT, MATCH_DOM_KEYCONSTRAINT, kc->name, NULL, NULL, 0)) { skip = 1; break; } SetResultV ("DOM_KEYCONSTRAINT"); goto errorCleanup; } if (frs.nodes[0]->nodeType != ELEMENT_NODE && frs.nodes[0]->nodeType != ATTRIBUTE_NODE) { SetResult ("INVALID_DOM_KEYCONSTRAINT"); goto errorCleanup; } if (first) first = 0; else Tcl_DStringAppend (&dStr, ":", 1); if (frs.nodes[0]->nodeType == ATTRIBUTE_NODE) { attr = (domAttrNode *) frs.nodes[0]; Tcl_DStringAppend (&dStr, attr->nodeValue, attr->valueLength); } else { keystr = xpathGetStringValue (frs.nodes[0], &len); Tcl_DStringAppend (&dStr, keystr, len); FREE (keystr); } } if (skip) break; Tcl_CreateHashEntry (&htable, Tcl_DStringValue (&dStr), &hnew); if (!hnew) { if (recover (interp, sdata, DOM_KEYCONSTRAINT, MATCH_DOM_KEYCONSTRAINT, kc->name, NULL, Tcl_DStringValue (&dStr),0)) { break; } SetResultV ("DOM_KEYCONSTRAINT"); goto errorCleanup; } } } Tcl_DeleteHashTable (&htable); nextConstraint: kc = kc->next; } schemaxpathRSFree (&frs); schemaxpathRSFree (&rs); schemaxpathRSFree (&nodeList); return TCL_OK; errorCleanup: Tcl_DeleteHashTable (&htable); booleanErrorCleanup: schemaxpathRSFree (&frs); schemaxpathRSFree (&rs); schemaxpathRSFree (&nodeList); return TCL_ERROR; } static void validateDOMerrorReport ( Tcl_Interp *interp, SchemaData *sdata, domNode *node ) { char *str; Tcl_Obj *strObj; if (node) { str = xpathNodeToXPath (node, 0); strObj = Tcl_NewStringObj (str, -1); Tcl_AppendStringsToObj (strObj, ": ", Tcl_GetStringResult (interp), NULL); Tcl_SetObjResult (interp, strObj); FREE (str); } sdata->evalError = 2; } static int validateDOM ( Tcl_Interp *interp, SchemaData *sdata, domNode *node ) { char *ln; domNode *savednode, *savedinsideNode; Tcl_Obj *str; int rc; if (node->namespace) { if (node->ownerDocument->namespaces[node->namespace-1]->prefix[0] == '\0') { ln = node->nodeName; } else { ln = node->nodeName; while (*ln && (*ln != ':')) { ln++; } if (*ln == ':') { ln++; } else { /* Ups? */ ln = node->nodeName; } } } else { ln = node->nodeName; } savednode = sdata->node; sdata->node = node; if (tDOM_probeElement (interp, sdata, ln, node->namespace ? node->ownerDocument->namespaces[node->namespace-1]->uri : NULL) != TCL_OK) { validateDOMerrorReport (interp, sdata, node); return TCL_ERROR; } /* In case of UNKNOWN_ROOT_ELEMENT and reportCmd is set * sdata->stack is NULL. */ if (!sdata->stack) return TCL_OK; if (sdata->skipDeep == 0) { if (node->firstAttr) { if (tDOM_probeDomAttributes (interp, sdata, node->firstAttr) != TCL_OK) { validateDOMerrorReport (interp, sdata, node); return TCL_ERROR; } } else { if (sdata->stack->pattern->numReqAttr) { /* tDOM_probeDomAttributes fills interp result with a * msg which required attributes are missing in case * of no reportCmd. In case of reportCmd * tDOM_probeDomAttributes() returns only error in the * case of error in called scripts. */ if (tDOM_probeDomAttributes (interp, sdata, NULL) != TCL_OK) { validateDOMerrorReport (interp, sdata, node); return TCL_ERROR; } } } } if (sdata->stack->pattern->domKeys) { if (checkdomKeyConstraints (interp, sdata, node) != TCL_OK) { validateDOMerrorReport (interp, sdata, node); return TCL_ERROR; } } savedinsideNode = sdata->insideNode; sdata->insideNode = node; node = node->firstChild; while (node) { switch (node->nodeType) { case ELEMENT_NODE: if (Tcl_DStringLength (sdata->cdata)) { if (tDOM_probeText (interp, sdata, Tcl_DStringValue (sdata->cdata), NULL) != TCL_OK) { validateDOMerrorReport (interp, sdata, node); return TCL_ERROR; } Tcl_DStringSetLength (sdata->cdata, 0); } if (validateDOM (interp, sdata, node) != TCL_OK) { return TCL_ERROR; } break; case TEXT_NODE: case CDATA_SECTION_NODE: str = Tcl_NewStringObj (((domTextNode *) node)->nodeValue, ((domTextNode *) node)->valueLength); sdata->textNode = (domTextNode *)node; rc = tDOM_probeText (interp, sdata, Tcl_GetString (str), NULL); Tcl_DecrRefCount (str); sdata->textNode = NULL; if (rc != TCL_OK) { validateDOMerrorReport (interp, sdata, node); return TCL_ERROR; } break; case COMMENT_NODE: case PROCESSING_INSTRUCTION_NODE: /* They are just ignored by validation. */ break; default: SetResult ("Unexpected node type in validateDOM!"); validateDOMerrorReport (interp, sdata, node); return TCL_ERROR; } node = node->nextSibling; } if (tDOM_probeElementEnd (interp, sdata) != TCL_OK) { validateDOMerrorReport (interp, sdata, node); return TCL_ERROR; } sdata->node = savednode; sdata->insideNode = savedinsideNode; return TCL_OK; } static void schemaReset ( SchemaData *sdata ) { Tcl_HashEntry *h; Tcl_HashSearch search; SchemaDocKey *dk; SchemaKeySpace *ks; while (sdata->stack) popStack (sdata); while (sdata->lastMatchse) popFromStack (sdata, &sdata->lastMatchse); sdata->recoverFlags = 0; sdata->validationState = VALIDATION_READY; sdata->skipDeep = 0; sdata->evalError = 0; sdata->vaction = 0; sdata->vname = NULL; sdata->vns = NULL; sdata->vtext = NULL; Tcl_DStringSetLength (sdata->cdata, 0); if (sdata->ids.numEntries) { Tcl_DeleteHashTable (&sdata->ids); Tcl_InitHashTable (&sdata->ids, TCL_STRING_KEYS); sdata->unknownIDrefs = 0; } if (sdata->idTables.numEntries) { for (h = Tcl_FirstHashEntry (&sdata->idTables, &search); h != NULL; h = Tcl_NextHashEntry (&search)) { dk = Tcl_GetHashValue (h); if ((&dk->ids)->numEntries) { Tcl_DeleteHashTable (&dk->ids); Tcl_InitHashTable (&dk->ids, TCL_STRING_KEYS); dk->unknownIDrefs = 0; } } } if (sdata->keySpaces.numEntries) { for (h = Tcl_FirstHashEntry (&sdata->keySpaces, &search); h != NULL; h = Tcl_NextHashEntry (&search)) { ks = Tcl_GetHashValue (h); if (ks->active && ks->ids.numEntries) { Tcl_DeleteHashTable (&ks->ids); Tcl_InitHashTable (&ks->ids, TCL_STRING_KEYS); } ks->unknownIDrefs = 0; ks->active = 0; } } sdata->parser = NULL; sdata->node = NULL; sdata->insideNode = NULL; sdata->textNode = NULL; } void tDOM_schemaReset ( SchemaData *sdata ) { if (sdata->cleanupAfterUse && sdata->inuse == 0 && sdata->currentEvals == 0) { schemaInstanceDelete (sdata); return; } schemaReset (sdata); } int tDOM_evalConstraints ( Tcl_Interp *interp, SchemaData *sdata, SchemaCP *cp, Tcl_Obj *script ) { int result, savedIsTextConstraint; SchemaCP *savedCP; unsigned int savedContenSize; /* Save some state of sdata .. */ savedCP = sdata->cp; savedContenSize = sdata->contentSize; savedIsTextConstraint = sdata->isTextConstraint; /* ... and prepare sdata for definition evaluation. */ sdata->cp = cp; sdata->contentSize = CONTENT_ARRAY_SIZE_INIT; sdata->isTextConstraint = 1; sdata->textStub[3] = script; sdata->currentEvals++; result = Tcl_EvalObjv (interp, 4, sdata->textStub, TCL_EVAL_GLOBAL); sdata->currentEvals--; /* ... and restore the previously saved sdata states */ sdata->isTextConstraint = savedIsTextConstraint; sdata->cp = savedCP; sdata->contentSize = savedContenSize; return result; } /* cp must be of type SCHEMA_CTYPE_NAME for useful results */ static Tcl_Obj* serializeElementName ( Tcl_Interp *interp, SchemaCP *cp ) { Tcl_Obj *rObj; rObj = Tcl_NewObj(); Tcl_ListObjAppendElement (interp, rObj, Tcl_NewStringObj (cp->name, -1)); if (cp->namespace) { Tcl_ListObjAppendElement (interp, rObj, Tcl_NewStringObj (cp->namespace, -1)); } return rObj; } static Tcl_Obj* serializeElementTypeName ( Tcl_Interp *interp, SchemaCP *cp ) { Tcl_Obj *rObj; rObj = Tcl_NewObj(); Tcl_ListObjAppendElement (interp, rObj, Tcl_NewStringObj (cp->name, -1)); if (cp->namespace) { Tcl_ListObjAppendElement (interp, rObj, Tcl_NewStringObj (cp->namespace, -1)); } return rObj; } /* cp must be of type SCHEMA_CTYPE_ANY for useful results */ static Tcl_Obj* serializeAnyCP ( Tcl_Interp *interp, SchemaCP *cp ) { Tcl_Obj *rObj, *nslistLObj; Tcl_HashTable *t; Tcl_HashEntry *h; Tcl_HashSearch search; rObj = Tcl_NewObj(); Tcl_ListObjAppendElement (interp, rObj, Tcl_NewStringObj ("", 5)); if (cp->namespace || cp->typedata) { nslistLObj = Tcl_NewObj(); if (cp->namespace) { Tcl_ListObjAppendElement (interp, nslistLObj, Tcl_NewStringObj (cp->namespace, -1)); } if (cp->typedata) { t = (Tcl_HashTable *)cp->typedata; for (h = Tcl_FirstHashEntry (t, &search); h != NULL; h = Tcl_NextHashEntry (&search)) { Tcl_ListObjAppendElement ( interp, nslistLObj, Tcl_NewStringObj (Tcl_GetHashKey (t, h), -1) ); } } Tcl_ListObjAppendElement (interp, rObj, nslistLObj); } else { Tcl_ListObjAppendElement (interp, rObj, Tcl_NewObj()); } return rObj; } /* The cp argument may be NULL. If it isn't NULL cp must be of type * SCHEMA_CTYPE_TEXT for useful results */ static Tcl_Obj* serializeTextCP ( Tcl_Interp *interp ) { Tcl_Obj *rObj; rObj = Tcl_NewObj(); Tcl_ListObjAppendElement (interp, rObj, Tcl_NewStringObj ("#text", 5)); Tcl_ListObjAppendElement (interp, rObj, Tcl_NewObj()); return rObj; } static Tcl_Obj* serializeElementEnd ( Tcl_Interp *interp ) { Tcl_Obj *rObj; rObj = Tcl_NewObj(); Tcl_ListObjAppendElement (interp, rObj, Tcl_NewStringObj ("", 12)); Tcl_ListObjAppendElement (interp, rObj, Tcl_NewObj()); return rObj; } static void definedElements ( Tcl_HashTable *htable, Tcl_Interp *interp ) { Tcl_Obj *rObj, *elmObj; Tcl_HashEntry *h; Tcl_HashSearch search; SchemaCP *cp; rObj = Tcl_GetObjResult (interp); for (h = Tcl_FirstHashEntry (htable, &search); h != NULL; h = Tcl_NextHashEntry (&search)) { cp = (SchemaCP *) Tcl_GetHashValue (h); while (cp) { if (cp->flags & FORWARD_PATTERN_DEF || cp->flags & PLACEHOLDER_PATTERN_DEF) { cp = cp->next; continue; } elmObj = serializeElementName (interp, cp); Tcl_ListObjAppendElement (interp, rObj, elmObj); cp = cp->next; } } } static void definedElementtypes ( SchemaData *sdata, Tcl_Interp *interp ) { Tcl_Obj *rObj, *elmObj; Tcl_HashEntry *h; Tcl_HashSearch search; SchemaCP *cp; rObj = Tcl_GetObjResult (interp); for (h = Tcl_FirstHashEntry (&sdata->elementType, &search); h != NULL; h = Tcl_NextHashEntry (&search)) { cp = (SchemaCP *) Tcl_GetHashValue (h); while (cp) { if (cp->flags & FORWARD_PATTERN_DEF || cp->flags & PLACEHOLDER_PATTERN_DEF) { cp = cp->next; continue; } if (cp->flags & FORWARD_PATTERN_DEF || cp->flags & PLACEHOLDER_PATTERN_DEF) continue; elmObj = serializeElementTypeName (interp, cp); Tcl_ListObjAppendElement (interp, rObj, elmObj); cp = cp->next; } } } static int getNextExpectedWorker ( SchemaData *sdata, SchemaValidationStack *se, Tcl_Interp *interp, Tcl_HashTable *seenCPs, Tcl_Obj *rObj, int expectedFlags ) { int hm, hnew, mustMatch, mayskip, rc = 1, probeMayskip = 0; unsigned int ac, i; SchemaCP *cp, *ic, *jc; SchemaValidationStack *se1; if (expectedFlags & EXPECTED_PROBE_MAYSKIP) { probeMayskip = 1; } getContext (cp, ac, hm); if ((expectedFlags & EXPECTED_IGNORE_MATCHED || expectedFlags & EXPECTED_ONLY_MANDATORY) && hm) { ac++; hm = 0; } else { if (hm && maxOne(cp->quants[ac])) { ac++; hm = 0; } } switch (cp->type) { case SCHEMA_CTYPE_INTERLEAVE: ac = 0; mustMatch = 0; /* fall through */ case SCHEMA_CTYPE_NAME: case SCHEMA_CTYPE_PATTERN: while (ac < cp->nc) { if (se->interleaveState && se->interleaveState[ac] && maxOne (cp->quants[ac])) { ac++; hm = 0; continue; } if (expectedFlags & EXPECTED_ONLY_MANDATORY && !(mustMatch (cp->quants[ac], hm))) { ac++; hm = 0; continue; } ic = cp->content[ac]; mayskip = 0; switch (ic->type) { case SCHEMA_CTYPE_NAME: if (probeMayskip) break; Tcl_ListObjAppendElement (interp, rObj, serializeElementName (interp, ic)); break; case SCHEMA_CTYPE_PATTERN: if (recursivePattern (se, ic)) { break; } /* fall through */ case SCHEMA_CTYPE_INTERLEAVE: if (expectedFlags & EXPECTED_ONLY_MANDATORY && !se->hasMatched) { expectedFlags |= EXPECTED_PROBE_MAYSKIP; se1 = getStackElement (sdata, ic); mayskip = getNextExpectedWorker (sdata, se1, interp, seenCPs, rObj, expectedFlags); repoolStackElement (sdata, se1); if (!probeMayskip) { expectedFlags &= ~EXPECTED_PROBE_MAYSKIP; } if (mayskip) break; } if (probeMayskip) break; Tcl_CreateHashEntry (seenCPs, (char *)ic, &hnew); if (hnew) { se1 = getStackElement (sdata, ic); mayskip = getNextExpectedWorker (sdata, se1, interp, seenCPs, rObj, expectedFlags); repoolStackElement (sdata, se1); } break; case SCHEMA_CTYPE_ANY: if (probeMayskip) break; if (!(expectedFlags & EXPECTED_ONLY_MANDATORY) || minOne (cp->quants[ac])) { Tcl_ListObjAppendElement (interp, rObj, serializeAnyCP (interp, ic)); } break; case SCHEMA_CTYPE_TEXT: if (ic->nc == 0 || checkText (interp, ic, "")) { mayskip = 1; } if (probeMayskip) break; if (!(expectedFlags & EXPECTED_ONLY_MANDATORY) || mayskip == 0) { Tcl_ListObjAppendElement (interp, rObj, serializeTextCP (interp)); } break; case SCHEMA_CTYPE_CHOICE: if (probeMayskip) { for (i = 0; i < ic->nc; i++) { if (mayMiss (ic->quants[i])) { mayskip = 1; break; } jc = ic->content[i]; switch (jc->type) { case SCHEMA_CTYPE_PATTERN: if (recursivePattern (se, ic)) { mayskip = 1; break; } /* fall through */ case SCHEMA_CTYPE_INTERLEAVE: se1 = getStackElement (sdata, ic); mayskip = getNextExpectedWorker ( sdata, se1, interp, seenCPs, rObj, expectedFlags ); repoolStackElement (sdata, se1); break; case SCHEMA_CTYPE_TEXT: if (ic->nc == 0 || checkText (interp, ic, "")) { mayskip = 1; } break; default: break; } if (mayskip) break; } break; } if (ic->flags & MIXED_CONTENT) { if (!(expectedFlags & EXPECTED_ONLY_MANDATORY)) { Tcl_ListObjAppendElement ( interp, rObj, serializeTextCP (interp)); } } for (i = 0; i < ic->nc; i++) { jc = ic->content[i]; switch (jc->type) { case SCHEMA_CTYPE_NAME: if (!(expectedFlags & EXPECTED_ONLY_MANDATORY) || minOne (cp->quants[i])) { Tcl_ListObjAppendElement ( interp, rObj, serializeElementName (interp, jc) ); } break; case SCHEMA_CTYPE_PATTERN: if (recursivePattern (se, jc)) { break; } /* fall through */ case SCHEMA_CTYPE_INTERLEAVE: Tcl_CreateHashEntry (seenCPs, (char *)jc, &hnew); if (hnew) { se1 = getStackElement (sdata, jc); mayskip = getNextExpectedWorker ( sdata, se1, interp, seenCPs, rObj, expectedFlags ); repoolStackElement (sdata, se1); } break; case SCHEMA_CTYPE_ANY: if (!(expectedFlags & EXPECTED_ONLY_MANDATORY) || minOne (cp->quants[i])) { Tcl_ListObjAppendElement ( interp, rObj, serializeAnyCP (interp, jc) ); } break; case SCHEMA_CTYPE_TEXT: if (!(expectedFlags & EXPECTED_ONLY_MANDATORY) || minOne (cp->quants[i])) { Tcl_ListObjAppendElement ( interp, rObj, serializeTextCP (interp) ); } break; case SCHEMA_CTYPE_CHOICE: SetResult ("MIXED or CHOICE child of MIXED or CHOICE"); sdata->evalError = 1; return 0; case SCHEMA_CTYPE_VIRTUAL: case SCHEMA_CTYPE_JSON_STRUCT: case SCHEMA_CTYPE_KEYSPACE: case SCHEMA_CTYPE_KEYSPACE_END: break; } } break; case SCHEMA_CTYPE_VIRTUAL: case SCHEMA_CTYPE_JSON_STRUCT: case SCHEMA_CTYPE_KEYSPACE: case SCHEMA_CTYPE_KEYSPACE_END: mayskip = 1; break; } if (cp->type == SCHEMA_CTYPE_INTERLEAVE) { if (!mustMatch && minOne(cp->quants[ac])) mustMatch = 1; } else { if (!mayskip && !hm && minOne (cp->quants[ac])) break; } ac++; hm = 0; } if (cp->type == SCHEMA_CTYPE_NAME) { if (ac == cp->nc) { /* The currently open element can end here, no * mandatory elements missing. * The element end is always mandatory.*/ Tcl_ListObjAppendElement ( interp, rObj, serializeElementEnd (interp) ); } rc = 0; } else if (cp->type == SCHEMA_CTYPE_INTERLEAVE) { if (mustMatch) rc = 0; } else { /* SCHEMA_CTYPE_PATTERN */ if (ac < cp->nc) rc = 0; } break; case SCHEMA_CTYPE_ANY: case SCHEMA_CTYPE_CHOICE: case SCHEMA_CTYPE_TEXT: case SCHEMA_CTYPE_VIRTUAL: case SCHEMA_CTYPE_JSON_STRUCT: case SCHEMA_CTYPE_KEYSPACE: case SCHEMA_CTYPE_KEYSPACE_END: SetResult ("Invalid CTYPE onto the validation stack!"); sdata->evalError = 1; return 0; } return rc; } static Tcl_Obj * unifyMatchList ( Tcl_Interp *interp, Tcl_HashTable *htable, Tcl_Obj *list ) { domLength len, i; int hnew; Tcl_HashEntry *h; Tcl_Obj *rObj, *thisObj; Tcl_HashSearch search; rObj = Tcl_NewObj(); Tcl_ListObjLength (interp, list, &len); if (len == 0) return rObj; if (len == 1) { Tcl_ListObjIndex (interp, list, 0, &thisObj); Tcl_ListObjAppendElement (interp, rObj, thisObj); return rObj; } Tcl_InitHashTable (htable, TCL_STRING_KEYS); for (i = 0; i < len; i++) { Tcl_ListObjIndex (interp, list, i, &thisObj); h = Tcl_CreateHashEntry (htable, Tcl_GetString (thisObj), &hnew); if (hnew) { Tcl_SetHashValue (h, thisObj); } } for (h = Tcl_FirstHashEntry (htable, &search); h != NULL; h = Tcl_NextHashEntry (&search)) { Tcl_ListObjAppendElement (interp, rObj, Tcl_GetHashValue (h)); } Tcl_DeleteHashTable (htable); return rObj; } static void getNextExpected ( SchemaData *sdata, Tcl_Interp *interp, int expectedFlags ) { int remainingLastMatch, count, rc; Tcl_Obj *rObj; Tcl_HashTable localHash; SchemaValidationStack *se; rObj = Tcl_NewObj(); Tcl_InitHashTable (&localHash, TCL_ONE_WORD_KEYS); remainingLastMatch = 0; if (sdata->lastMatchse) { se = sdata->lastMatchse; while (se->down) { remainingLastMatch++; se = se->down; } while (se && getNextExpectedWorker (sdata, se, interp, &localHash, rObj, expectedFlags)) { if (remainingLastMatch) { count = 1; se = sdata->lastMatchse; while (count < remainingLastMatch) { se = se->down; count++; } remainingLastMatch--; } else break; } } se = sdata->stack; while (se) { if (!se->hasMatched && se->pattern->type != SCHEMA_CTYPE_NAME) { se = se->down; continue; } rc = getNextExpectedWorker (sdata, se, interp, &localHash, rObj, expectedFlags); if (se->pattern->type == SCHEMA_CTYPE_NAME) break; se = se->down; if (!rc) break; } Tcl_DeleteHashTable (&localHash); Tcl_SetObjResult (interp, unifyMatchList (interp, &localHash, rObj)); Tcl_DecrRefCount (rObj); } static int schemaInstanceInfoCmd ( SchemaData *sdata, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] ) { int methodIndex, expectedFlags; XML_Size line, column; XML_Index byteIndex; Tcl_HashEntry *h; SchemaCP *cp; SchemaValidationStack *se; void *ns; Tcl_Obj *rObj; static const char *schemaInstanceInfoMethods[] = { "validationstate", "vstate", "definedElements", "stack", "toplevel", "expected", "definition", "validationaction", "vaction", "line", "column", "byteIndex", "domNode", "nrForwardDefinitions", "typedefinition", "definedElementtypes", "patterndefinition", "definedPatterns", NULL }; enum schemaInstanceInfoMethod { m_validationstate, m_vstate, m_definedElements, m_stack, m_toplevel, m_expected, m_definition, m_validationaction, m_vaction, m_line, m_column, m_byteIndex, m_domNode, m_nrForwardDefinitions, m_typedefinition, m_definedElementtypes, m_patterndefinition, m_definedPatterns }; static const char *schemaInstanceInfoStackMethods[] = { "top", "inside", "associated", NULL }; enum schemaInstanceInfoStackMethod { m_top, m_inside, m_associated }; static const char *schemaInstanceInfoVactionMethods[] = { "name", "namespace", "text", NULL }; enum schemaInstanceInfoVactionMethod { m_name, m_namespace, m_text }; static const char *schemaInstanceInfoExpectedOptions[] = { "-ignorematched", "-onlymandatory", NULL }; enum schemaInstanceInfoExpectedOption { o_ignorematched, o_onlymandatory }; if (objc < 2) { Tcl_WrongNumArgs (interp, 1, objv, "subcommand ?arguments?"); return TCL_ERROR; } if (Tcl_GetIndexFromObj (interp, objv[1], schemaInstanceInfoMethods, "method", 0, &methodIndex) != TCL_OK) { return TCL_ERROR; } Tcl_ResetResult (interp); switch ((enum schemaInstanceInfoMethod) methodIndex) { case m_validationstate: case m_vstate: switch (sdata->validationState) { case VALIDATION_READY: SetResult ("READY"); break; case VALIDATION_STARTED: SetResult ("VALIDATING"); break; case VALIDATION_FINISHED: SetResult ("FINISHED"); break; default: SetResult ("Internal error: Invalid validation state"); return TCL_ERROR; } break; case m_definedElements: if (objc != 2) { Tcl_WrongNumArgs (interp, 1, objv, "definedElements"); return TCL_ERROR; } definedElements (&sdata->element, interp); break; case m_definedPatterns: if (objc != 2) { Tcl_WrongNumArgs (interp, 1, objv, "definedPatterns"); return TCL_ERROR; } definedElements (&sdata->pattern, interp); break; case m_definedElementtypes: if (objc != 2) { Tcl_WrongNumArgs (interp, 1, objv, "definedElementtypes"); return TCL_ERROR; } definedElementtypes (sdata, interp); break; case m_stack: if (objc != 3) { Tcl_WrongNumArgs (interp, 2, objv, "top|inside"); return TCL_ERROR; } if (Tcl_GetIndexFromObj (interp, objv[2], schemaInstanceInfoStackMethods, "method", 0, &methodIndex) != TCL_OK) { return TCL_ERROR; } if (!sdata->stack) { return TCL_OK; } se = sdata->stack; switch ((enum schemaInstanceInfoStackMethod) methodIndex) { case m_inside: rObj = Tcl_NewObj(); while (se) { if (se->pattern->type == SCHEMA_CTYPE_NAME) { Tcl_ListObjAppendElement (interp, rObj, serializeElementName (interp, se->pattern)); } se = se->down; } Tcl_SetObjResult (interp, rObj); return TCL_OK; case m_top: while (se->pattern->type != SCHEMA_CTYPE_NAME) { se = se->down; } rObj = serializeElementName (interp, se->pattern); Tcl_SetObjResult (interp, rObj); return TCL_OK; case m_associated: if (!se->pattern->associated) { return TCL_OK; } Tcl_SetObjResult (interp, se->pattern->associated); return TCL_OK; } break; case m_toplevel: if (objc != 2) { Tcl_WrongNumArgs (interp, 2, objv, ""); return TCL_ERROR; } if (!sdata->currentEvals) { SetResult ("not called while schema evaluation"); return TCL_ERROR; } if (!sdata->defineToplevel && sdata->currentEvals > 1) { SetBooleanResult (0); } else { SetBooleanResult (1); } return TCL_OK; case m_expected: if (objc < 2 || objc > 4) { Tcl_WrongNumArgs (interp, 2, objv, "?-ignorematched? ?-onlymandatory?"); return TCL_ERROR; } if (sdata->validationState == VALIDATION_ERROR || sdata->validationState == VALIDATION_FINISHED) { return TCL_OK; } expectedFlags = 0; while (objc > 2) { if (Tcl_GetIndexFromObj (interp, objv[2], schemaInstanceInfoExpectedOptions, "option", 0, &methodIndex) != TCL_OK) { return TCL_ERROR; } switch ((enum schemaInstanceInfoExpectedOption) methodIndex) { case o_ignorematched: expectedFlags |= EXPECTED_IGNORE_MATCHED; break; case o_onlymandatory: expectedFlags |= EXPECTED_ONLY_MANDATORY; break; } objv++; objc--; } if (!sdata->stack) { if (sdata->start) { Tcl_AppendElement (interp, sdata->start); if (sdata->startNamespace) { Tcl_AppendElement (interp, sdata->startNamespace); } } else { definedElements (&sdata->element, interp); } } else { getNextExpected (sdata, interp, expectedFlags); } break; case m_definition: if (objc < 3 || objc > 4) { Tcl_WrongNumArgs (interp, 1, objv, "name ?namespace?"); return TCL_ERROR; } h = Tcl_FindHashEntry (&sdata->element, Tcl_GetString (objv[2])); if (!h) { SetResult ("Unknown element definition"); return TCL_ERROR; } cp = Tcl_GetHashValue (h); ns = NULL; if (objc == 4) { ns = getNamespacePtr (sdata, Tcl_GetString (objv[3])); } while (cp && cp->namespace != ns) { cp = cp->next; } if (!cp || cp->flags & LOCAL_DEFINED_ELEMENT || cp->flags & PLACEHOLDER_PATTERN_DEF) { SetResult ("Unknown element definition"); return TCL_ERROR; } Tcl_AppendElement (interp, "defelement"); Tcl_AppendElement (interp, cp->name); if (cp->namespace) { Tcl_AppendElement (interp, cp->namespace); } if (cp->defScript) { Tcl_AppendElement (interp, Tcl_GetString (cp->defScript)); } break; case m_patterndefinition: if (objc < 3 || objc > 4) { Tcl_WrongNumArgs (interp, 1, objv, "name ?namespace?"); return TCL_ERROR; } h = Tcl_FindHashEntry (&sdata->pattern, Tcl_GetString (objv[2])); if (!h) { SetResult ("Unknown pattern definition"); return TCL_ERROR; } cp = Tcl_GetHashValue (h); ns = NULL; if (objc == 4) { ns = getNamespacePtr (sdata, Tcl_GetString (objv[3])); } while (cp && cp->namespace != ns) { cp = cp->next; } if (!cp || cp->flags & PLACEHOLDER_PATTERN_DEF) { SetResult ("Unknown pattern definition"); return TCL_ERROR; } Tcl_AppendElement (interp, "defpattern"); Tcl_AppendElement (interp, cp->name); if (cp->namespace) { Tcl_AppendElement (interp, cp->namespace); } if (cp->defScript) { Tcl_AppendElement (interp, Tcl_GetString (cp->defScript)); } break; case m_typedefinition: if (objc < 3 || objc > 4) { Tcl_WrongNumArgs (interp, 2, objv, "name ?namespace?"); return TCL_ERROR; } h = Tcl_FindHashEntry (&sdata->elementType, Tcl_GetString (objv[2])); if (!h) { SetResult ("Unknown elementtype definition"); return TCL_ERROR; } cp = Tcl_GetHashValue (h); ns = NULL; if (objc == 4) { ns = getNamespacePtr (sdata, Tcl_GetString (objv[3])); } while (cp && cp->namespace != ns) { cp = cp->next; } if (!cp || cp->flags & PLACEHOLDER_PATTERN_DEF) { SetResult ("Unknown elementtype definition"); return TCL_ERROR; } Tcl_AppendElement (interp, "defelementtype"); Tcl_AppendElement (interp, cp->name); if (cp->namespace) { Tcl_AppendElement (interp, cp->namespace); } if (cp->defScript) { Tcl_AppendElement (interp, Tcl_GetString (cp->defScript)); } break; case m_vaction: case m_validationaction: if (sdata->validationState != VALIDATION_STARTED || sdata->currentEvals == 0) { SetResult ("NONE"); break; } if (objc == 2) { SetResult (ValidationAction2str[sdata->vaction]); break; } if (objc != 3) { Tcl_WrongNumArgs (interp, 2, objv, "?name|namespace|text?"); return TCL_ERROR; } if (Tcl_GetIndexFromObj (interp, objv[2], schemaInstanceInfoVactionMethods, "method", 0, &methodIndex) != TCL_OK) { return TCL_ERROR; } switch ((enum schemaInstanceInfoVactionMethod) methodIndex) { case m_name: SetResult (sdata->vname); break; case m_namespace: SetResult (sdata->vns); break; case m_text: SetResult (sdata->vtext); break; } break; case m_line: if (!sdata->parser && !sdata->node) break; if (sdata->parser) { SetLongResult ((domLength)XML_GetCurrentLineNumber (sdata->parser)); break; } if (domGetLineColumn(sdata->node, &line, &column, &byteIndex) < 0) break; SetLongResult ((domLength)line); break; case m_column: if (!sdata->parser && !sdata->node) break; if (sdata->parser) { SetLongResult ((domLength)XML_GetCurrentColumnNumber (sdata->parser)); break; } if (domGetLineColumn(sdata->node, &line, &column, &byteIndex) < 0) break; SetLongResult ((domLength)column); break; case m_byteIndex: if (!sdata->parser && !sdata->node) break; if (sdata->parser) { SetLongResult ((domLength)XML_GetCurrentByteIndex (sdata->parser)); break; } if (domGetLineColumn(sdata->node, &line, &column, &byteIndex) < 0) break; SetLongResult ((domLength)byteIndex); break; case m_domNode: if (!sdata->node) break; /* We distinguish between calls from reportCmd and others * (from scripts called with the tcl cmd). */ if (sdata->vaction) { /* This is the case: called from reportCmd. */ return tcldom_setInterpAndReturnVar (interp, sdata->node, NULL); } else { /* This is the case: called from a with tcl called script. */ return tcldom_setInterpAndReturnVar (interp, sdata->insideNode, NULL); } break; case m_nrForwardDefinitions: if (objc != 2) { Tcl_WrongNumArgs(interp, 2, objv, ""); return TCL_ERROR; } SetIntResult(sdata->forwardPatternDefs); break; } return TCL_OK; } static void attributeLookupPreparation ( SchemaData *sdata, SchemaCP *cp ) { Tcl_HashTable *t; unsigned int i; int hnew; Tcl_HashEntry *h; SchemaAttr *attr; if (cp->numAttr <= sdata->attributeHashThreshold) return; t = TMALLOC (Tcl_HashTable); Tcl_InitHashTable (t, TCL_STRING_KEYS); for (i = 0; i < cp->numAttr; i++) { h = Tcl_CreateHashEntry (t, cp->attrs[i]->name, &hnew); if (hnew) { Tcl_SetHashValue (h, cp->attrs[i]); } else { attr = (SchemaAttr *) Tcl_GetHashValue (h); cp->attrs[i]->next = attr->next; attr->next = cp->attrs[i]; } } cp->typedata = (void *)t; } static void validateReportError ( Tcl_Interp *interp, SchemaData *sdata, XML_Parser parser ) { Tcl_Obj *resultObj; char sl[50], sc[50]; resultObj = Tcl_NewObj (); sprintf(sl, "%" TDOM_LS_MODIFIER "d", XML_GetCurrentLineNumber(parser)); sprintf(sc, "%" TDOM_LS_MODIFIER "d", XML_GetCurrentColumnNumber(parser)); if (sdata->validationState == VALIDATION_ERROR) { Tcl_AppendStringsToObj (resultObj, "error \"", Tcl_GetStringResult (interp), "\" at line ", sl, " character ", sc, NULL); } else { Tcl_AppendStringsToObj (resultObj, "error \"", XML_ErrorString(XML_GetErrorCode(parser)), "\" at line ", sl, " character ", sc, NULL); } Tcl_SetObjResult (interp, resultObj); } static int externalEntityRefHandler ( XML_Parser parser, const char *openEntityNames, const char *base, const char *systemId, const char *publicId ) { ValidateMethodData *vdata; Tcl_Obj *cmdPtr, *resultObj, *resultTypeObj, *extbaseObj, *xmlstringObj; Tcl_Obj *channelIdObj; int result, mode, done, keepresult = 0; domLength len, tclLen; XML_Parser extparser, oldparser = NULL; char buf[4096], *resultType, *extbase, *xmlstring, *xmlstringstart, *channelId, s[50]; Tcl_Channel chan = (Tcl_Channel) NULL; enum XML_Status status; const char *interpResult; vdata = (ValidateMethodData *) XML_GetUserData (parser); if (vdata->externalentitycommandObj == NULL) { Tcl_AppendResult (vdata->interp, "Can't read external entity \"", systemId, "\": No -externalentitycommand given", NULL); return 0; } cmdPtr = Tcl_NewStringObj(Tcl_GetString(vdata->externalentitycommandObj), -1); Tcl_IncrRefCount(cmdPtr); if (base) { Tcl_ListObjAppendElement(vdata->interp, cmdPtr, Tcl_NewStringObj(base, (domLength)strlen(base))); } else { Tcl_ListObjAppendElement(vdata->interp, cmdPtr, Tcl_NewObj()); } /* For a document with doctype declaration, the systemId is always != NULL. But if the document doesn't have a doctype declaration and the user uses -useForeignDTD 1, the externalEntityRefHandler will be called with a systemId (and publicId and openEntityNames) == NULL. */ if (systemId) { Tcl_ListObjAppendElement(vdata->interp, cmdPtr, Tcl_NewStringObj(systemId, (domLength)strlen(systemId))); } else { Tcl_ListObjAppendElement(vdata->interp, cmdPtr, Tcl_NewObj()); } if (publicId) { Tcl_ListObjAppendElement(vdata->interp, cmdPtr, Tcl_NewStringObj(publicId, (domLength)strlen(publicId))); } else { Tcl_ListObjAppendElement(vdata->interp, cmdPtr, Tcl_NewObj()); } result = Tcl_EvalObjEx (vdata->interp, cmdPtr, TCL_EVAL_DIRECT | TCL_EVAL_GLOBAL); Tcl_DecrRefCount(cmdPtr); if (result != TCL_OK) { vdata->sdata->evalError = 1; return 0; } extparser = XML_ExternalEntityParserCreate (parser, openEntityNames, 0); resultObj = Tcl_GetObjResult (vdata->interp); Tcl_IncrRefCount (resultObj); result = Tcl_ListObjLength (vdata->interp, resultObj, &tclLen); if ((result != TCL_OK) || (tclLen != 3)) { goto wrongScriptResult; } result = Tcl_ListObjIndex (vdata->interp, resultObj, 0, &resultTypeObj); if (result != TCL_OK) { goto wrongScriptResult; } resultType = Tcl_GetString(resultTypeObj); if (strcmp (resultType, "string") == 0) { result = Tcl_ListObjIndex (vdata->interp, resultObj, 2, &xmlstringObj); xmlstring = Tcl_GetStringFromObj (xmlstringObj, &len); } else if (strcmp (resultType, "channel") == 0) { xmlstring = NULL; len = 0; result = Tcl_ListObjIndex (vdata->interp, resultObj, 2, &channelIdObj); channelId = Tcl_GetString(channelIdObj); chan = Tcl_GetChannel (vdata->interp, channelId, &mode); if (chan == (Tcl_Channel) NULL) { goto wrongScriptResult; } if ((mode & TCL_READABLE) == 0) { return 0; } } else if (strcmp (resultType, "filename") == 0) { /* result type "filename" not yet implemented */ return 0; } else { goto wrongScriptResult; } result = Tcl_ListObjIndex (vdata->interp, resultObj, 1, &extbaseObj); if (result != TCL_OK) { goto wrongScriptResult; } extbase = Tcl_GetString(extbaseObj); /* TODO: what to do, if this document was already parsed before ? */ if (!extparser) { Tcl_DecrRefCount (resultObj); Tcl_SetResult (vdata->interp, "unable to create expat external entity parser", NULL); return 0; } oldparser = vdata->parser; vdata->parser = extparser; XML_SetBase (extparser, extbase); Tcl_ResetResult (vdata->interp); result = 1; xmlstringstart = xmlstring; if (chan == NULL) { do { done = (len < TDOM_PCS); status = XML_Parse (extparser, xmlstring, (int)(done ? len : TDOM_PCS), done); if (!done) { xmlstring += TDOM_PCS; len -= TDOM_PCS; } } while (!done && status == XML_STATUS_OK); switch (status) { case XML_STATUS_ERROR: interpResult = Tcl_GetStringResult(vdata->interp); if (interpResult[0] == '\0') { tcldom_reportErrorLocation ( vdata->interp, 20, 40, XML_GetCurrentLineNumber(extparser), XML_GetCurrentColumnNumber(extparser), xmlstringstart, systemId, XML_GetCurrentByteIndex(extparser), XML_ErrorString(XML_GetErrorCode(extparser))); } else { sprintf(s, "%" TDOM_LS_MODIFIER "d", XML_GetCurrentLineNumber(extparser)); Tcl_AppendResult(vdata->interp, ", referenced in entity \"", systemId, "\" at line ", s, " character ", NULL); sprintf(s, "%" TDOM_LS_MODIFIER "d", XML_GetCurrentColumnNumber(extparser)); Tcl_AppendResult(vdata->interp, s, NULL); } keepresult = 1; result = 0; break; case XML_STATUS_SUSPENDED: XML_StopParser (oldparser, 1); keepresult = 1; break; default: break; } } else { do { len = Tcl_Read (chan, buf, sizeof(buf)); done = len < sizeof(buf); status = XML_Parse (extparser, buf, (int)len, done); switch (status) { case XML_STATUS_ERROR: interpResult = Tcl_GetStringResult(vdata->interp); sprintf(s, "%" TDOM_LS_MODIFIER "d", XML_GetCurrentLineNumber(extparser)); if (interpResult[0] == '\0') { Tcl_ResetResult (vdata->interp); Tcl_AppendResult( vdata->interp, "error \"", XML_ErrorString(XML_GetErrorCode(extparser)), "\" in entity \"", systemId, "\" at line ", s, " character ", NULL ); sprintf(s, "%" TDOM_LS_MODIFIER "d", XML_GetCurrentColumnNumber(extparser)); Tcl_AppendResult(vdata->interp, s, NULL); } else { Tcl_AppendResult( vdata->interp, ", referenced in entity \"", systemId, "\" at line ", s, " character ", NULL ); sprintf(s, "%" TDOM_LS_MODIFIER "d", XML_GetCurrentColumnNumber(extparser)); Tcl_AppendResult(vdata->interp, s, NULL); } result = 0; keepresult = 1; done = 1; break; case XML_STATUS_SUSPENDED: XML_StopParser (oldparser, 1); keepresult = 1; done = 1; break; default: break; } } while (!done); } if (!keepresult) { Tcl_ResetResult (vdata->interp); } XML_ParserFree (extparser); vdata->parser = oldparser; Tcl_DecrRefCount (resultObj); return result; wrongScriptResult: Tcl_DecrRefCount (resultObj); Tcl_ResetResult (vdata->interp); XML_ParserFree (extparser); if (oldparser) { vdata->parser = oldparser; } vdata->sdata->evalError = 1; Tcl_AppendResult (vdata->interp, "The -externalentitycommand script " "has to return a Tcl list with 3 elements.\n" "Syntax: {string|channel|filename }\n", NULL); return 0; } static int validateSource ( ValidationInput source, SchemaData *sdata, ValidateMethodData *vdata, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] ) { XML_Parser parser; char sep = '\xFF'; Tcl_DString cdata; Tcl_Obj *bufObj; char *xmlstr, *filename, *str, *baseurl = NULL; int result, fd, mode, done, rc, value, useForeignDTD = 0; domLength len, tclLen; int forest = 0; int paramEntityParsing = XML_PARAM_ENTITY_PARSING_ALWAYS; Tcl_DString translatedFilename; int optionIndex; Tcl_Channel channel; static const char *validateOptions[] = { "-baseurl", "-externalentitycommand", "-paramentityparsing", "-useForeignDTD", "-forest", NULL }; enum validateOption { o_baseurl, o_externalentitycommand, o_paramentityparsing, o_useForeignDTD, o_forest }; static const char *paramEntityParsingValues[] = { "always", "never", "notstandalone", (char *) NULL }; enum paramEntityParsingValue { EXPAT_PARAMENTITYPARSINGALWAYS, EXPAT_PARAMENTITYPARSINGNEVER, EXPAT_PARAMENTITYPARSINGNOTSTANDALONE }; if (objc < 3) { Tcl_WrongNumArgs (interp, 2, objv, "?-baseurl ? " "?-externalentitycommand ? " "?-paramentityparsing (always|never|standalone? " " ?resultVarName?"); return TCL_ERROR; } if (sdata->validationState != VALIDATION_READY) { SetResult ("The schema command is busy"); return TCL_ERROR; } objc -= 2; objv += 2; memset (vdata, 0, sizeof (ValidateMethodData)); vdata->externalentitycommandObj = Tcl_NewStringObj ("::tdom::extRefHandler", 21); Tcl_IncrRefCount (vdata->externalentitycommandObj); while (objc > 2) { if (Tcl_GetIndexFromObj (interp, objv[0], validateOptions, "option", 0, &optionIndex) != TCL_OK) { return TCL_ERROR; } switch ((enum validateOption) optionIndex) { case o_baseurl: baseurl = Tcl_GetString (objv[1]); break; case o_externalentitycommand: if (vdata->externalentitycommandObj) Tcl_DecrRefCount (vdata->externalentitycommandObj); Tcl_GetStringFromObj (objv[1], &len); if (len) { vdata->externalentitycommandObj = objv[1]; Tcl_IncrRefCount (objv[1]); } else { vdata->externalentitycommandObj = NULL; } break; case o_paramentityparsing: if (Tcl_GetIndexFromObj(interp, objv[1], paramEntityParsingValues, "value", 0, &value) != TCL_OK) { Tcl_DecrRefCount (vdata->externalentitycommandObj); return TCL_ERROR; } switch ((enum paramEntityParsingValue) value) { case EXPAT_PARAMENTITYPARSINGALWAYS: paramEntityParsing = XML_PARAM_ENTITY_PARSING_ALWAYS; break; case EXPAT_PARAMENTITYPARSINGNEVER: paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER; break; case EXPAT_PARAMENTITYPARSINGNOTSTANDALONE: paramEntityParsing = XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE; break; } break; case o_useForeignDTD: if (Tcl_GetBooleanFromObj(interp, objv[1], &useForeignDTD) != TCL_OK) { return TCL_ERROR; } break; case o_forest: if (Tcl_GetBooleanFromObj(interp, objv[1], &forest) != TCL_OK) { return TCL_ERROR; } break; } objc -= 2; objv += 2; } parser = XML_ParserCreate_MM (NULL, MEM_SUITE, &sep); vdata->interp = interp; vdata->sdata = sdata; vdata->parser = parser; sdata->parser = parser; Tcl_DStringInit (&cdata); vdata->cdata = &cdata; vdata->onlyWhiteSpace = 1; vdata->uri = (char *) MALLOC (URI_BUFFER_LEN_INIT); vdata->maxUriLen = URI_BUFFER_LEN_INIT; XML_SetUserData (parser, vdata); XML_SetBase (parser, baseurl); XML_SetElementHandler (parser, startElement, endElement); XML_SetCharacterDataHandler (parser, characterDataHandler); if (vdata->externalentitycommandObj) { XML_SetExternalEntityRefHandler (parser, externalEntityRefHandler); } XML_UseForeignDTD (parser, (unsigned char) useForeignDTD); XML_SetParamEntityParsing (parser, paramEntityParsing); switch (source) { case VALIDATE_STRING: xmlstr = Tcl_GetStringFromObj (objv[0], &len); result = TCL_OK; do { done = (len < TDOM_PCS); if (XML_Parse (parser, xmlstr, (int)(done ? len : TDOM_PCS), done) != XML_STATUS_OK || sdata->validationState == VALIDATION_ERROR) { validateReportError (interp, sdata, parser); result = TCL_ERROR; break; } if (!done) { xmlstr += TDOM_PCS; len -= TDOM_PCS; } } while (!done); break; case VALIDATE_FILENAME: filename = Tcl_TranslateFileName (interp, Tcl_GetString (objv[0]), &translatedFilename); if (filename == NULL) { result = TCL_ERROR; goto cleanup; } fd = open(filename, O_BINARY|O_RDONLY); if (fd < 0) { Tcl_ResetResult (interp); Tcl_AppendResult (interp, "error opening file \"", filename, "\"", (char *) NULL); result = TCL_ERROR; goto cleanup; } for (;;) { domLength nread; char *fbuf = XML_GetBuffer (parser, TDOM_EXPAT_READ_SIZE); if (!fbuf) { close (fd); Tcl_ResetResult (interp); Tcl_SetResult (interp, "Out of memory\n", NULL); result = TCL_ERROR; goto cleanup; } nread = read(fd, fbuf, TDOM_EXPAT_READ_SIZE); if (nread < 0) { close (fd); Tcl_ResetResult (interp); Tcl_AppendResult (interp, "error reading from file \"", filename, "\"", (char *) NULL); result = TCL_ERROR; goto cleanup; } result = XML_ParseBuffer (parser, (int)nread, nread == 0); if (result != XML_STATUS_OK || !nread || sdata->validationState == VALIDATION_ERROR) { close (fd); break; } } if (result != XML_STATUS_OK || sdata->validationState == VALIDATION_ERROR) { validateReportError (interp, sdata, parser); result = TCL_ERROR; } else { result = TCL_OK; } cleanup: Tcl_DStringFree (&translatedFilename); break; case VALIDATE_CHANNEL: channel = Tcl_GetChannel(interp, Tcl_GetString (objv[0]), &mode); if (channel == NULL) { SetResult ("The channel argument isn't a tcl channel"); result = TCL_ERROR; break; } bufObj = Tcl_NewObj(); Tcl_SetObjLength (bufObj, 6144); result = TCL_OK; do { len = Tcl_ReadChars (channel, bufObj, 1024, 0); done = (len < 1024); str = Tcl_GetStringFromObj(bufObj, &tclLen); rc = XML_Parse (parser, str, (int)tclLen, done); if (rc != XML_STATUS_OK || sdata->validationState == VALIDATION_ERROR) { validateReportError (interp, sdata, parser); result = TCL_ERROR; break; } } while (!done); Tcl_DecrRefCount (bufObj); break; } XML_ParserFree (parser); sdata->parser = NULL; FREE (vdata->uri); Tcl_DStringFree (&cdata); Tcl_DecrRefCount (vdata->externalentitycommandObj); /* sdata->evalError == 1 means Tcl evaluation error in called * script. sdata->evalError == 2 is used to signal "abort but * leave interp result alone, it is set". */ if (sdata->evalError == 1) { result = TCL_ERROR; } else { if (result == TCL_OK) { SetBooleanResult (1); } else { if (objc == 2) { Tcl_SetVar (interp, Tcl_GetString (objv[1]), Tcl_GetStringResult (interp), 0); } result = TCL_OK; SetBooleanResult (0); } } schemaReset (sdata); return result; } /* This implements the script interface to the created schema commands. Since validation may call out to Tcl scripts those scripts may delete the schema command (which just validates input by calling out to a Tcl script). This is handled by Tcl evaluation level counting and postponing the schema data deletion until back on top. After any code by this function that may have called out to a Tcl script it is important not to return locally but to signal the return value with the result variable and ensure to reach the code at the end of tDOM_schemaInstanceCmd. */ int tDOM_schemaInstanceCmd ( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] ) { int methodIndex, keywordIndex, hnew, patternIndex; int result = TCL_OK, forwardDef = 0, j, k = 0; int savedDefineToplevel, type, n; domLength len; unsigned int i, savedNumPatternList, nrTypeInstances, typeInstancesLen; SchemaData *savedsdata = NULL, *sdata = (SchemaData *) clientData; Tcl_HashTable *hashTable; Tcl_HashEntry *h, *h1; SchemaCP *pattern, *current = NULL; void *namespacePtr, *savedNamespacePtr; char *errMsg; domDocument *doc; domNode *node; Tcl_Obj *attData; SchemaCP **typeInstances; ValidateMethodData vdata; static const char *schemaInstanceMethods[] = { "defelement", "defpattern", "start", "event", "delete", "reset", "define", "validate", "domvalidate", "deftexttype", "info", "reportcmd", "prefixns", "validatefile", "validatechannel", "defelementtype", "set", NULL }; enum schemaInstanceMethod { m_defelement, m_defpattern, m_start, m_event, m_delete, m_reset, m_define, m_validate, m_domvalidate, m_deftexttype, m_info, m_reportcmd, m_prefixns, m_validatefile, m_validatechannel, m_defelementtype, m_set }; static const char *eventKeywords[] = { "start", "end", "text", NULL }; enum eventKeyword { k_elementstart, k_elementend, k_text }; static const char *setKeywords[] = { "choiceHashThreshold", "attributeHashThreshold", NULL }; enum setKeyword { s_choiceHashThreshold, s_attributeHashThreshold }; if (sdata == NULL) { /* Inline defined defelement, defelementtype, defpattern, * deftexttype, start or prefixns */ sdata = GETASI; CHECK_SI; if (!sdata->defineToplevel && sdata->currentEvals > 1) { SetResult ("Command not allowed in nested schema define script"); return TCL_ERROR; } k = 1; } if (objc + k < 2) { Tcl_WrongNumArgs (interp, 1, objv, "subcommand ?arguments?"); return TCL_ERROR; } if (Tcl_GetIndexFromObj (interp, objv[1-k], schemaInstanceMethods, "method", 0, &methodIndex) != TCL_OK) { return TCL_ERROR; } Tcl_ResetResult (interp); switch ((enum schemaInstanceMethod) methodIndex) { case m_defelement: case m_defpattern: CHECK_RECURSIVE_CALL if (objc != 4-k && objc != 5-k) { Tcl_WrongNumArgs (interp, 2-k, objv, "" " ?? pattern"); return TCL_ERROR; } if ((enum schemaInstanceMethod) methodIndex == m_defelement) { hashTable = &sdata->element; type = SCHEMA_CTYPE_NAME; } else { hashTable = &sdata->pattern; type = SCHEMA_CTYPE_PATTERN; } savedNumPatternList = sdata->numPatternList; namespacePtr = NULL; patternIndex = 3-k; if (objc == 5-k) { patternIndex = 4-k; namespacePtr = getNamespacePtr (sdata, Tcl_GetString (objv[3-k])); } h = Tcl_CreateHashEntry (hashTable, Tcl_GetString (objv[2-k]), &hnew); pattern = NULL; if (!hnew) { pattern = (SchemaCP *) Tcl_GetHashValue (h); while (pattern) { if (pattern->namespace == namespacePtr) { if (pattern->flags & FORWARD_PATTERN_DEF || pattern->flags & PLACEHOLDER_PATTERN_DEF) { forwardDef = 1; break; } if ((enum schemaInstanceMethod) methodIndex == m_defelement) { SetResult ("Element already defined " "in this namespace"); } else { SetResult ("Pattern already defined " "in this namespace"); } return TCL_ERROR; } pattern = pattern->next; } } if (pattern == NULL) { pattern = initSchemaCP (type, namespacePtr, Tcl_GetHashKey (hashTable, h)); if (!hnew) { current = (SchemaCP *) Tcl_GetHashValue (h); pattern->next = current; } REMEMBER_PATTERN (pattern); Tcl_SetHashValue (h, pattern); } SETASI(sdata); savedDefineToplevel = sdata->defineToplevel; savedNamespacePtr = sdata->currentNamespace; sdata->defineToplevel = 0; sdata->currentNamespace = namespacePtr; sdata->cp = pattern; sdata->numAttr = 0; sdata->numReqAttr = 0; sdata->currentAttrs = NULL; sdata->contentSize = CONTENT_ARRAY_SIZE_INIT; sdata->evalStub[3] = objv[patternIndex]; sdata->currentEvals++; result = Tcl_EvalObjv (interp, 4, sdata->evalStub, TCL_EVAL_GLOBAL); sdata->currentEvals--; sdata->currentNamespace = NULL; pattern->attrs = sdata->currentAttrs; pattern->numAttr = sdata->numAttr; pattern->numReqAttr = sdata->numReqAttr; if (result == TCL_OK) { if (pattern->numAttr) { attributeLookupPreparation (sdata, pattern); } if (forwardDef) { if (pattern->flags & FORWARD_PATTERN_DEF) { sdata->forwardPatternDefs--; pattern->flags &= ~FORWARD_PATTERN_DEF; } pattern->flags &= ~PLACEHOLDER_PATTERN_DEF; } pattern->defScript = objv[patternIndex]; Tcl_IncrRefCount (pattern->defScript); } else { if (forwardDef) { pattern->nc = 0; } cleanupLastPattern (sdata, savedNumPatternList); } sdata->defineToplevel = savedDefineToplevel; sdata->currentNamespace = savedNamespacePtr; if (!savedDefineToplevel) { SETASI(savedsdata); } break; case m_define: CHECK_EVAL if (objc != 3) { Tcl_WrongNumArgs (interp, 2, objv, ""); return TCL_ERROR; } if (clientData) { savedsdata = GETASI; if (savedsdata == sdata) { SetResult ("Recursive call of schema command is not allowed"); return TCL_ERROR; } } SETASI(sdata); savedNumPatternList = sdata->numPatternList; sdata->currentNamespace = 0; sdata->cp = NULL; sdata->contentSize = 0; sdata->defineToplevel = 1; sdata->evalStub[3] = objv[2]; sdata->currentEvals++; result = Tcl_EvalObjv (interp, 4, sdata->evalStub, TCL_EVAL_GLOBAL); sdata->currentEvals--; if (result != TCL_OK) { cleanupLastPattern (sdata, savedNumPatternList); } sdata->defineToplevel = 0; SETASI(savedsdata); break; case m_deftexttype: CHECK_RECURSIVE_CALL if (objc != 4-k) { Tcl_WrongNumArgs (interp, 2-k, objv, "" " "); return TCL_ERROR; } h = Tcl_CreateHashEntry (&sdata->textDef, Tcl_GetString (objv[2-k]), &hnew); if (!hnew) { pattern = Tcl_GetHashValue (h); if (pattern->flags & FORWARD_PATTERN_DEF) { forwardDef = 1; } else { SetResult ("There is already a text type definition with " "this name"); return TCL_ERROR; } } else { pattern = initSchemaCP (SCHEMA_CTYPE_CHOICE, NULL, NULL); pattern->type = SCHEMA_CTYPE_TEXT; REMEMBER_PATTERN (pattern); } SETASI(sdata); savedDefineToplevel = sdata->defineToplevel; result = evalConstraints (interp, sdata, pattern, objv[3-k]); sdata->defineToplevel = savedDefineToplevel; if (!savedDefineToplevel) { SETASI(savedsdata); } if (result == TCL_OK) { if (forwardDef) { pattern->flags &= ~FORWARD_PATTERN_DEF; sdata->forwardPatternDefs--; } else { Tcl_SetHashValue (h, pattern); } } else { if (!forwardDef) { Tcl_DeleteHashEntry (h); } } break; case m_start: CHECK_RECURSIVE_CALL if (objc < 3-k || objc > 4-k) { Tcl_WrongNumArgs (interp, 2-k, objv, "" " ??"); return TCL_ERROR; } if (sdata->start) { FREE (sdata->start); } if (objc == 3-k && strcmp (Tcl_GetString (objv[2-k]), "") == 0) { sdata->startNamespace = NULL; sdata->start = NULL; break; } sdata->start = tdomstrdup (Tcl_GetString (objv[2-k])); if (objc == 4-k) { sdata->startNamespace = getNamespacePtr (sdata, Tcl_GetString (objv[3-k])); } break; case m_event: CHECK_EVAL if (objc < 3) { Tcl_WrongNumArgs (interp, 2, objv, "" " ??"); return TCL_ERROR; } if (Tcl_GetIndexFromObj (interp, objv[2], eventKeywords, "keyword", 0, &keywordIndex) != TCL_OK) { return TCL_ERROR; } switch ((enum eventKeyword) keywordIndex) { case k_elementstart: if (objc < 4 || objc > 6) { Tcl_WrongNumArgs (interp, 3, objv, "" "?? ??"); return TCL_ERROR; } namespacePtr = NULL; len = 0; attData = NULL; if (objc == 6) { namespacePtr = getNamespacePtr (sdata, Tcl_GetString (objv[5])); } if (objc >= 5) { if (Tcl_ListObjLength (interp, objv[4], &len) != TCL_OK) { if (objc == 6) { SetResult ("Invalid attribute information"); return TCL_ERROR; } else { namespacePtr = getNamespacePtr (sdata, Tcl_GetString (objv[4])); len = 0; } } else { if (len == 1) { namespacePtr = getNamespacePtr (sdata, Tcl_GetString (objv[4])); len = 0; } else if (len % 2 != 0) { SetResult ("Invalid attribute information"); return TCL_ERROR; } else { attData = objv[4]; } } } result = tDOM_probeElement (interp, sdata, Tcl_GetString (objv[3]), namespacePtr); /* In case of UNKNOWN_ROOT_ELEMENT and reportCmd is set * sdata->stack is NULL. */ if (!sdata->stack) break; if (sdata->skipDeep == 0 && result == TCL_OK) { result = probeEventAttribute (interp, sdata, attData, len); } break; case k_elementend: if (objc != 3) { Tcl_WrongNumArgs (interp, 3, objv, "No arguments expected."); return TCL_ERROR; } result = tDOM_probeElementEnd (interp, sdata); break; case k_text: if (objc != 4) { Tcl_WrongNumArgs (interp, 3, objv, ""); return TCL_ERROR; } result = tDOM_probeText (interp, sdata, Tcl_GetString (objv[3]), NULL); break; } break; case m_delete: if (objc != 2) { Tcl_WrongNumArgs(interp, 2, objv, ""); return TCL_ERROR; } Tcl_DeleteCommand(interp, Tcl_GetString(objv[0])); /* We return immediately here to avoid clashes with postponed sdata cleanup at the end of the function. */ return TCL_OK; case m_reset: CHECK_EVAL schemaReset (sdata); break; case m_validate: result = validateSource (VALIDATE_STRING, sdata, &vdata, interp, objc, objv); break; case m_validatefile: result = validateSource (VALIDATE_FILENAME, sdata, &vdata, interp, objc, objv); break; case m_validatechannel: result = validateSource (VALIDATE_CHANNEL, sdata, &vdata, interp, objc, objv); break; case m_domvalidate: CHECK_EVAL if (objc < 3 || objc > 4) { Tcl_WrongNumArgs (interp, 2, objv, " ?resultVarName?"); return TCL_ERROR; } doc = tcldom_getDocumentFromName (interp, Tcl_GetString (objv[2]), &errMsg); if (doc) { node = doc->documentElement; } else { node = tcldom_getNodeFromObj (interp, objv[2]); if (!node) { SetResult ("The second argument must be either a " "document or a element node"); return TCL_ERROR; } } if (validateDOM (interp, sdata, node) == TCL_OK) { SetBooleanResult (1); if (objc == 4) { Tcl_SetVar (interp, Tcl_GetString (objv[3]), "", 0); } } else { if (objc == 4) { Tcl_SetVar (interp, Tcl_GetString (objv[3]), Tcl_GetStringResult (interp), 0); } SetBooleanResult (0); } schemaReset (sdata); break; case m_info: objv++; objc--; result = schemaInstanceInfoCmd (sdata, interp, objc, objv); break; case m_reportcmd: if (objc == 2) { if (sdata->reportCmd) { Tcl_SetObjResult (interp, sdata->reportCmd); } else { Tcl_SetObjResult (interp, Tcl_NewObj()); } break; } if (objc != 3) { Tcl_WrongNumArgs (interp, 2, objv, ""); return TCL_ERROR; } if (sdata->reportCmd) { Tcl_DecrRefCount (sdata->reportCmd); } if (strlen (Tcl_GetString (objv[2])) == 0) { sdata->reportCmd = NULL; } else { sdata->reportCmd = objv[2]; Tcl_IncrRefCount (sdata->reportCmd); } break; case m_prefixns: CHECK_RECURSIVE_CALL if (objc != 2-k && objc != 3-k) { Tcl_WrongNumArgs (interp, 2-k, objv, "?prefixUriList?"); return TCL_ERROR; } if (!k) {objc--; objv++;} result = tcldom_prefixNSlist (&sdata->prefixns, interp, objc, objv, "prefixns"); if (sdata->prefix.numEntries) { Tcl_DeleteHashTable (&sdata->prefix); Tcl_InitHashTable (&sdata->prefix, TCL_STRING_KEYS); } if (result == TCL_OK && sdata->prefixns) { j = 0; while (sdata->prefixns[j]) { h1 = Tcl_CreateHashEntry (&sdata->prefix, sdata->prefixns[j], &hnew); /* This means: First prefix mapping wins */ if (hnew) { h = Tcl_CreateHashEntry (&sdata->namespace, sdata->prefixns[j+1], &hnew); Tcl_SetHashValue (h1, Tcl_GetHashKey (&sdata->namespace, h)); } j += 2; } } break; case m_defelementtype: CHECK_RECURSIVE_CALL if (objc != 4-k && objc != 5-k) { Tcl_WrongNumArgs (interp, 2-k, objv, " " " ?? pattern"); return TCL_ERROR; } savedNumPatternList = sdata->numPatternList; namespacePtr = NULL; patternIndex = 3-k; if (objc == 5-k) { namespacePtr = getNamespacePtr (sdata, Tcl_GetString (objv[3-k])); patternIndex = 4-k; } h = Tcl_CreateHashEntry (&sdata->elementType , Tcl_GetString (objv[2-k]), &hnew); pattern = NULL; if (!hnew) { pattern = (SchemaCP *) Tcl_GetHashValue (h); while (pattern) { if (pattern->namespace == namespacePtr) { if (pattern->flags & FORWARD_PATTERN_DEF) { forwardDef = 1; break; } SetResult ("Element type already defined in this " "namespace"); return TCL_ERROR; } pattern = pattern->next; } } if (pattern == NULL) { pattern = initSchemaCP (SCHEMA_CTYPE_NAME, namespacePtr, Tcl_GetHashKey (&sdata->elementType, h)); pattern->flags |= ELEMENTTYPE_DEF; if (!hnew) { current = (SchemaCP *) Tcl_GetHashValue (h); pattern->next = current; } REMEMBER_PATTERN (pattern); Tcl_SetHashValue (h, pattern); } if (forwardDef) { /* The type was already forward defined. Save the with the forward defined pattern stored instance elements to be able to set the actual content of the instance pattern after the type content is eventually defined below. */ typeInstances = pattern->content; nrTypeInstances = pattern->nc; typeInstancesLen = pattern->numAttr; pattern->content = (SchemaCP**) MALLOC ( sizeof(SchemaCP*) * CONTENT_ARRAY_SIZE_INIT ); pattern->numAttr = 0; pattern->nc = 0; } SETASI(sdata); savedDefineToplevel = sdata->defineToplevel; savedNamespacePtr = sdata->currentNamespace; sdata->defineToplevel = 0; sdata->currentNamespace = namespacePtr; sdata->cp = pattern; sdata->numAttr = 0; sdata->numReqAttr = 0; sdata->currentAttrs = NULL; sdata->contentSize = CONTENT_ARRAY_SIZE_INIT; sdata->evalStub[3] = objv[patternIndex]; sdata->currentEvals++; result = Tcl_EvalObjv (interp, 4, sdata->evalStub, TCL_EVAL_GLOBAL); sdata->currentEvals--; sdata->currentNamespace = NULL; pattern->attrs = sdata->currentAttrs; pattern->numAttr = sdata->numAttr; pattern->numReqAttr = sdata->numReqAttr; if (result == TCL_OK) { if (pattern->numAttr) { attributeLookupPreparation (sdata, pattern); } if (forwardDef) { sdata->forwardPatternDefs--; pattern->flags &= ~FORWARD_PATTERN_DEF; for (i = 0; i < nrTypeInstances; i++) { typeInstances[i]->content = pattern->content; typeInstances[i]->quants = pattern->quants; typeInstances[i]->nc = pattern->nc; typeInstances[i]->typedata = pattern->typedata; typeInstances[i]->attrs = pattern->attrs; typeInstances[i]->numAttr = pattern->numAttr; typeInstances[i]->numReqAttr = pattern->numReqAttr; typeInstances[i]->domKeys = pattern->domKeys; typeInstances[i]->keySpace = pattern->keySpace; /* TODO: decide what to do with associated */ } FREE (typeInstances); } pattern->defScript = objv[patternIndex]; Tcl_IncrRefCount (pattern->defScript); } else { if (forwardDef) { FREE (pattern->content); pattern->content = typeInstances; pattern->nc = nrTypeInstances; pattern->numAttr = typeInstancesLen; } cleanupLastPattern (sdata, savedNumPatternList); } sdata->defineToplevel = savedDefineToplevel; sdata->currentNamespace = savedNamespacePtr; if (!savedDefineToplevel) { SETASI(savedsdata); } break; case m_set: if (objc < 3 || objc > 4) { Tcl_WrongNumArgs (interp, 2, objv, "setting ?value?"); return TCL_ERROR; } if (Tcl_GetIndexFromObj (interp, objv[2], setKeywords, "setting", 0, &keywordIndex) != TCL_OK) { return TCL_ERROR; } switch ((enum setKeyword) keywordIndex) { case s_choiceHashThreshold: if (objc == 4) { if (Tcl_GetIntFromObj (interp, objv[3], &n) != TCL_OK) { SetResult ("Invalid threshold value"); return TCL_ERROR; } if (n < 0) { SetResult ("Invalid threshold value"); return TCL_ERROR; } sdata->choiceHashThreshold = n; } SetIntResult (sdata->choiceHashThreshold); break; case s_attributeHashThreshold: if (objc == 4) { if (Tcl_GetIntFromObj (interp, objv[3], &n) != TCL_OK) { SetResult ("Invalid threshold value"); return TCL_ERROR; } if (n < 0) { SetResult ("Invalid threshold value"); return TCL_ERROR; } sdata->attributeHashThreshold = n; } SetIntResult (sdata->attributeHashThreshold); break; } break; default: Tcl_SetResult (interp, "unknown method", NULL); result = TCL_ERROR; break; } if (sdata->cleanupAfterUse && sdata->currentEvals == 0 && !(sdata->inuse > 0)) { schemaInstanceDelete (sdata); } return result; } /* *---------------------------------------------------------------------------- * * tDOM_SchemaObjCmd -- * * This procedure is invoked to process the "schema" command. * See the user documentation for what it does. * * Results: * A standard Tcl result. * * Side effects: * * *---------------------------------------------------------------------------- */ int tDOM_SchemaObjCmd ( ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] ) { int methodIndex, ind, result = TCL_OK; SchemaData *sdata; static const char *schemaMethods[] = { "create", NULL }; enum schemaMethod { m_create }; if (objc < 2 || objc > 3) { Tcl_WrongNumArgs (interp, 1, objv, "subcommand ?argument?"); return TCL_ERROR; } if (objc == 2) { methodIndex = m_create; ind = 1; } else { if (Tcl_GetIndexFromObj (interp, objv[1], schemaMethods, "method", 0, &methodIndex) != TCL_OK) { return TCL_ERROR; } ind = 2; } Tcl_ResetResult (interp); switch ((enum schemaMethod) methodIndex) { case m_create: sdata = initSchemaData (objv[ind]); Tcl_CreateObjCommand (interp, Tcl_GetString(objv[ind]), tDOM_schemaInstanceCmd, (ClientData) sdata, schemaInstanceDelete); Tcl_SetObjResult (interp, objv[ind]); break; default: Tcl_SetResult (interp, "unknown method", NULL); result = TCL_ERROR; break; } return result; } static SchemaQuant getQuant ( Tcl_Interp *interp, Tcl_Obj *quantObj, int *n, int *m ) { char *quantStr; domLength len; Tcl_Obj *thisObj; *n = 0; *m = 0; if (!quantObj) { return SCHEMA_CQUANT_ONE; } quantStr = Tcl_GetStringFromObj (quantObj, &len); if (len == 1) { switch (quantStr[0]) { case '!': return SCHEMA_CQUANT_ONE; case '*': return SCHEMA_CQUANT_REP; case '?': return SCHEMA_CQUANT_OPT; case '+': return SCHEMA_CQUANT_PLUS; } } if (Tcl_ListObjLength (interp, quantObj, &len) != TCL_OK) { SetResult ("Invalid quant specifier"); return SCHEMA_CQUANT_ERROR; } if (len != 1 && len != 2) { SetResult ("Invalid quant specifier"); return SCHEMA_CQUANT_ERROR; } if (len == 1) { if (Tcl_GetIntFromObj (interp, quantObj, n) != TCL_OK) { SetResult ("Invalid quant specifier"); return SCHEMA_CQUANT_ERROR; } if (*n < 1) { SetResult ("Invalid quant specifier"); return SCHEMA_CQUANT_ERROR; } if (*n == 1) { return SCHEMA_CQUANT_ONE; *n = 0; } return SCHEMA_CQUANT_NM; } /* The "list-ness" of the quantObj is already checked by the * Tcl_ListObjLength() call above, no need to check result. */ Tcl_ListObjIndex (interp, quantObj, 0, &thisObj); if (Tcl_GetIntFromObj (interp, thisObj, n) != TCL_OK) { SetResult ("Invalid quant specifier"); return SCHEMA_CQUANT_ERROR; } if (*n < 0) { SetResult ("Invalid quant specifier"); return SCHEMA_CQUANT_ERROR; } Tcl_ListObjIndex (interp, quantObj, 1, &thisObj); if (Tcl_GetIntFromObj (interp, thisObj, m) == TCL_OK) { if (*n > *m) { SetResult ("Invalid quant specifier"); return SCHEMA_CQUANT_ERROR; } if (*n == 0 && *m == 1) { return SCHEMA_CQUANT_OPT; } if (*n == 1 && *m == 1) { return SCHEMA_CQUANT_ONE; } return SCHEMA_CQUANT_NM; } else { quantStr = Tcl_GetStringFromObj (thisObj, &len); if (len == 1 && quantStr[0] == '*') { if (*n == 0) { return SCHEMA_CQUANT_REP; } *m = -1; return SCHEMA_CQUANT_NM; } else { SetResult ("Invalid quant specifier"); return SCHEMA_CQUANT_ERROR; } } } /* Implements the schema definition command "any" */ static int AnyPatternObjCmd ( ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] ) { SchemaData *sdata = GETASI; SchemaCP *pattern; SchemaQuant quant; char *ns = NULL, *ns1; int n, m, hnew, revert, optionIndex; domLength nrns, i; Tcl_Obj *nsObj; Tcl_HashTable *t = NULL; static const char *anyOptions[] = { "-not", "--", NULL }; enum anyOption { o_not, o_Last }; CHECK_SI CHECK_TOPLEVEL revert = 0; while (objc > 1) { if (Tcl_GetIndexFromObj(interp, objv[1], anyOptions, "option", 0, &optionIndex) != TCL_OK) { break; } switch ((enum anyOption) optionIndex) { case o_not: revert = 1; objv++; objc--; continue; case o_Last: objv++; objc--; break; } if ((enum anyOption) optionIndex == o_Last) break; } checkNrArgs (1,3,"(options? ?namespace list? ?quant?"); quant = SCHEMA_CQUANT_ONE; if (objc == 1) { n = 0; m = 0; goto createpattern; } else if (objc == 2) { quant = getQuant (interp, objv[1], &n, &m); if (quant != SCHEMA_CQUANT_ERROR) { goto createpattern; } quant = SCHEMA_CQUANT_ONE; } else { quant = getQuant (interp, objv[2], &n, &m); if (quant == SCHEMA_CQUANT_ERROR) { return TCL_ERROR; } } if (Tcl_ListObjLength (interp, objv[1], &nrns) != TCL_OK) { SetResult ("The argument must be a valid tcl list"); return TCL_ERROR; } if (nrns == 1) { Tcl_ListObjIndex (interp, objv[1], 0, &nsObj); ns1 = Tcl_GetString (nsObj); if (ns1[0] == '\0') { ns = emptyStr; } else { ns = getNamespacePtr (sdata, Tcl_GetString (nsObj)); } } else { t = TMALLOC (Tcl_HashTable); Tcl_InitHashTable (t, TCL_ONE_WORD_KEYS); for (i = 0; i < nrns; i++) { Tcl_ListObjIndex (interp, objv[1], i, &nsObj); ns1 = Tcl_GetString (nsObj); if (ns1[0] == '\0') { ns = emptyStr; } else { ns1 = getNamespacePtr (sdata, Tcl_GetString (nsObj)); Tcl_CreateHashEntry (t, ns1, &hnew); } } } createpattern: pattern = initSchemaCP (SCHEMA_CTYPE_ANY, ns, NULL); if (t) pattern->typedata = (void*)t; if (revert) pattern->flags |= ANY_NOT; REMEMBER_PATTERN (pattern) addToContent(sdata, pattern, quant, n, m); return TCL_OK; } static int evalDefinition ( Tcl_Interp *interp, SchemaData *sdata, Tcl_Obj *definition, SchemaCP *pattern, SchemaQuant quant, int n, int m ) { SchemaCP *savedCP; SchemaAttr **savedCurrentAttrs; unsigned int savedContenSize, i; unsigned int savedAttrSize, savedNumAttr, savedNumReqAttr; int result, onlyName, hnew; Tcl_HashEntry *h; Tcl_HashTable *t; /* Save some state of sdata .. */ savedCP = sdata->cp; savedContenSize = sdata->contentSize; savedNumAttr = sdata->numAttr; savedNumReqAttr = sdata->numReqAttr; savedAttrSize = sdata->attrSize; savedCurrentAttrs = sdata->currentAttrs; /* ... and prepare sdata for definition evaluation. */ sdata->cp = pattern; sdata->contentSize = CONTENT_ARRAY_SIZE_INIT; sdata->numAttr = 0; sdata->numReqAttr = 0; sdata->currentAttrs = NULL; sdata->attrSize = 0; sdata->currentEvals++; result = Tcl_EvalObjEx (interp, definition, TCL_EVAL_DIRECT); sdata->currentEvals--; pattern->attrs = sdata->currentAttrs; pattern->numAttr = sdata->numAttr; pattern->numReqAttr = sdata->numReqAttr; /* ... and restore the previously saved sdata states */ sdata->cp = savedCP; sdata->contentSize = savedContenSize; sdata->numAttr = savedNumAttr; sdata->numReqAttr = savedNumReqAttr; sdata->currentAttrs = savedCurrentAttrs; sdata->attrSize = savedAttrSize; if (result != TCL_OK) { freeSchemaCP (pattern); return result; } REMEMBER_PATTERN (pattern); if (pattern->numAttr) { attributeLookupPreparation (sdata, pattern); } if (pattern->type == SCHEMA_CTYPE_CHOICE) { onlyName = 1; for (i = 0; i < pattern->nc; i++) { if (pattern->content[i]->type != SCHEMA_CTYPE_NAME && pattern->content[i]->type != SCHEMA_CTYPE_TEXT) { onlyName = 0; break; } } if (onlyName && pattern->nc > sdata->choiceHashThreshold) { t = TMALLOC (Tcl_HashTable); Tcl_InitHashTable (t, TCL_ONE_WORD_KEYS); hnew = 1; for (i = 0; i < pattern->nc; i++) { if (pattern->content[i]->type != SCHEMA_CTYPE_NAME) { continue; } h = Tcl_CreateHashEntry (t, pattern->content[i]->name, &hnew); if (!hnew) { break; } Tcl_SetHashValue (h, pattern->content[i]); } if (hnew) { pattern->typedata = (void *)t; } else { /* No simple lookup possible because of more than one * element with the same local name belong to the * choices. Rewind. */ Tcl_DeleteHashTable (t); FREE (t); } } } addToContent (sdata, pattern, quant, n, m); return TCL_OK; } /* Implements the schema definition commands "element" */ static int ElementPatternObjCmd ( ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] ) { SchemaData *sdata = GETASI; Tcl_HashEntry *h; SchemaCP *pattern = NULL, *typePattern = NULL, *current; SchemaQuant quant; int hnew, n, m, typed = 0, ind = 3, localdef = 0; char *namePtr; CHECK_SI CHECK_TOPLEVEL checkNrArgs (2,5,"Expected: elementName ?quant? ?(pattern|\"type\" " "typename)?"); quant = getQuant (interp, objc == 2 ? NULL : objv[2], &n, &m); if (quant == SCHEMA_CQUANT_ERROR) { /* May be default quant with local definition or type. */ if (objc != 3 && objc != 4) { SetResult("Expected: elementName ?quant? ?(pattern|\"type\" " "typename)?"); return TCL_ERROR; } quant = SCHEMA_CQUANT_ONE; if (objc == 4) { /* Reference to type */ typed = 1; } else { ind = 2; localdef = 1; } } else { if (objc == 5) { typed = 1; ind = 4; } else if (objc == 4) { localdef = 1; } } if (typed) { if (strcmp (Tcl_GetString (objv[ind-1]), "type") != 0) { SetResult("Expected: elementName ?quant? ?(pattern|\"type\" " "typename)?"); return TCL_ERROR; } } h = Tcl_CreateHashEntry (&sdata->element, Tcl_GetString(objv[1]), &hnew); namePtr = Tcl_GetHashKey (&sdata->element, h); if (hnew) { pattern = initSchemaCP( SCHEMA_CTYPE_NAME, sdata->currentNamespace, namePtr); if (typed || localdef) { pattern->flags |= PLACEHOLDER_PATTERN_DEF; } else { pattern->flags |= FORWARD_PATTERN_DEF; sdata->forwardPatternDefs++; } Tcl_SetHashValue (h, pattern); REMEMBER_PATTERN (pattern); } if (typed) { pattern = NULL; h = Tcl_CreateHashEntry (&sdata->elementType, Tcl_GetString (objv[ind]), &hnew); if (!hnew) { typePattern = (SchemaCP *) Tcl_GetHashValue (h); while (typePattern) { if (typePattern->namespace == sdata->currentNamespace) { break; } typePattern = typePattern->next; } } if (!typePattern) { typePattern = initSchemaCP ( SCHEMA_CTYPE_NAME, sdata->currentNamespace, Tcl_GetHashKey (&sdata->elementType, h)); typePattern->flags |= (ELEMENTTYPE_DEF | FORWARD_PATTERN_DEF); sdata->forwardPatternDefs++; REMEMBER_PATTERN (typePattern); /* We (ab)use the numAttr for the allocated content length * for forward defined types, to be able to store the * instance pattern until the type pattern is eventually * defined. */ typePattern->numAttr = CONTENT_ARRAY_SIZE_INIT; if (!hnew) { current = (SchemaCP *) Tcl_GetHashValue (h); typePattern->next = current; } Tcl_SetHashValue (h, typePattern); } h = Tcl_CreateHashEntry (&sdata->elementTypeInstance, namePtr, &hnew); if (!hnew) { pattern = (SchemaCP *) Tcl_GetHashValue (h); while (pattern) { if (pattern->namespace == sdata->currentNamespace && pattern->typeptr == typePattern) { break; } pattern = pattern->next; } } if (!pattern) { pattern = TMALLOC (SchemaCP); memset (pattern, 0, sizeof(SchemaCP)); pattern->type = SCHEMA_CTYPE_NAME; pattern->namespace = sdata->currentNamespace; pattern->name = namePtr; pattern->flags |= TYPED_ELEMENT; REMEMBER_PATTERN (pattern); if (!hnew) { current = (SchemaCP *) Tcl_GetHashValue (h); pattern->next = current; } Tcl_SetHashValue (h, pattern); pattern->typeptr = typePattern; } if (typePattern->flags & FORWARD_PATTERN_DEF) { /* Remember the instance pattern with the type pattern * (a bit misusing struct members) to be able to set * the instance pattern to the actual content if the * type pattern is eventually defined. */ if (typePattern->nc == typePattern->numAttr) { typePattern->content = REALLOC (typePattern->content, 2 * typePattern->numAttr * sizeof (SchemaCP*)); typePattern->numAttr *= 2; } typePattern->content[typePattern->nc] = pattern; typePattern->nc++; } else { pattern->content = typePattern->content; pattern->quants = typePattern->quants; pattern->nc = typePattern->nc; pattern->typedata = typePattern->typedata; pattern->attrs = typePattern->attrs; pattern->numAttr = typePattern->numAttr; pattern->numReqAttr = typePattern->numReqAttr; pattern->domKeys = typePattern->domKeys; pattern->keySpace = typePattern->keySpace; /* TODO: decide what to do with associated */ } addToContent (sdata, pattern, quant, n, m); } else if (localdef) { pattern = initSchemaCP (SCHEMA_CTYPE_NAME, sdata->currentNamespace, namePtr); pattern->flags |= LOCAL_DEFINED_ELEMENT; return evalDefinition (interp, sdata, objv[ind], pattern, quant, n, m); } else { /* Reference to an element. */ if (!hnew) { pattern = (SchemaCP *) Tcl_GetHashValue (h); while (pattern) { if (pattern->namespace == sdata->currentNamespace) { break; } pattern = pattern->next; } if (!pattern) { pattern = initSchemaCP (SCHEMA_CTYPE_NAME, sdata->currentNamespace, namePtr); pattern->flags |= FORWARD_PATTERN_DEF; sdata->forwardPatternDefs++; if (!hnew) { current = (SchemaCP *) Tcl_GetHashValue (h); pattern->next = current; } REMEMBER_PATTERN (pattern); Tcl_SetHashValue (h, pattern); } } addToContent (sdata, pattern, quant, n, m); } return TCL_OK; } /* Implements the schema definition commands "ref" */ static int RefPatternObjCmd ( ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] ) { SchemaData *sdata = GETASI; Tcl_HashEntry *h; SchemaCP *pattern = NULL, *current; SchemaQuant quant; int hnew, n, m; CHECK_SI CHECK_TOPLEVEL checkNrArgs (2,3,"Expected: patternName ?quant?"); quant = getQuant (interp, objc == 2 ? NULL : objv[2], &n, &m); if (quant == SCHEMA_CQUANT_ERROR) { return TCL_ERROR; } h = Tcl_CreateHashEntry (&sdata->pattern, Tcl_GetString(objv[1]), &hnew); if (!hnew) { pattern = (SchemaCP *) Tcl_GetHashValue (h); while (pattern) { if (pattern->namespace == sdata->currentNamespace) { break; } pattern = pattern->next; } } if (!pattern) { pattern = initSchemaCP ( SCHEMA_CTYPE_PATTERN, sdata->currentNamespace, Tcl_GetHashKey (&sdata->pattern, h) ); pattern->flags |= FORWARD_PATTERN_DEF; sdata->forwardPatternDefs++; if (!hnew) { current = (SchemaCP *) Tcl_GetHashValue (h); pattern->next = current; } REMEMBER_PATTERN (pattern); Tcl_SetHashValue (h, pattern); } addToContent (sdata, pattern, quant, n, m); return TCL_OK; } /* Implements the schema definition commands "choice", "group", * "interleave" and "mixed" */ static int AnonPatternObjCmd ( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] ) { SchemaData *sdata = GETASI; Schema_CP_Type patternType; SchemaQuant quant; SchemaCP *pattern; int n, m; CHECK_SI CHECK_TOPLEVEL checkNrArgs (2,3,"Expected: ?quant? definition"); quant = getQuant (interp, objc == 2 ? NULL : objv[1], &n, &m); if (quant == SCHEMA_CQUANT_ERROR) { return TCL_ERROR; } if (clientData == 0) { patternType = SCHEMA_CTYPE_CHOICE; } else if (clientData == (ClientData) 1) { patternType = SCHEMA_CTYPE_CHOICE; /* Default quant for mixed is * */ if (objc == 2) { quant = SCHEMA_CQUANT_REP; } } else if (clientData == (ClientData) 2) { patternType = SCHEMA_CTYPE_INTERLEAVE; } else { patternType = SCHEMA_CTYPE_PATTERN; } pattern = initSchemaCP (patternType, NULL, NULL); if (clientData == (ClientData) 1) { pattern->flags |= MIXED_CONTENT; } return evalDefinition (interp, sdata, objc == 2 ? objv[1] : objv[2], pattern, quant, n, m); } static int maybeAddAttr ( Tcl_Interp *interp, SchemaData *sdata, Tcl_Obj *nameObj, Tcl_Obj *namespaceObj, Tcl_Obj *scriptObj, int required, SchemaCP *type ) { Tcl_HashEntry *h; int hnew, result = TCL_OK; unsigned int i; char *name, *namespace = NULL; SchemaAttr *attr; SchemaCP *cp; if (namespaceObj) { namespace = getNamespacePtr (sdata, Tcl_GetString (namespaceObj)); } h = Tcl_CreateHashEntry (&sdata->attrNames, Tcl_GetString (nameObj), &hnew); name = Tcl_GetHashKey (&sdata->attrNames, h); if (!hnew) { /* Check, if there is already an attribute with this name and namespace */ for (i = 0; i < sdata->numAttr; i++) { if (sdata->currentAttrs[i]->name == name && sdata->currentAttrs[i]->namespace == namespace) { /* Ignore the later attribute declaration */ return TCL_OK; } } } attr = TMALLOC (SchemaAttr); attr->namespace = namespace; attr->name = name; attr->next = NULL; attr->required = required; if (scriptObj) { cp = initSchemaCP (SCHEMA_CTYPE_CHOICE, NULL, NULL); cp->type = SCHEMA_CTYPE_TEXT; REMEMBER_PATTERN (cp) sdata->isAttributeConstraint = 1; result = evalConstraints (interp, sdata, cp, scriptObj); sdata->isAttributeConstraint = 0; attr->cp = cp; } else if (type) { attr->cp = type; } else { attr->cp = NULL; } if (!sdata->currentAttrs) { sdata->currentAttrs = MALLOC (sizeof(SchemaAttr*) * ATTR_ARRAY_INIT); sdata->attrSize = ATTR_ARRAY_INIT; } else if (sdata->numAttr == sdata->attrSize) { sdata->currentAttrs = REALLOC (sdata->currentAttrs, 2 * sdata->attrSize * sizeof (SchemaAttr)); sdata->attrSize *= 2; } sdata->currentAttrs[sdata->numAttr] = attr; sdata->numAttr++; if (required) { sdata->numReqAttr++; } return result; } static int AttributePatternObjCmd ( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] ) { SchemaData *sdata = GETASI; char *str; int required = 1; domLength len; Tcl_Obj *nsObj, *nameObj; Tcl_HashEntry *h; SchemaCP *type; CHECK_SI CHECK_TOPLEVEL if (sdata->cp->type != SCHEMA_CTYPE_NAME) { SetResult ("The commands attribute and nsattribute are only allowed " "toplevel in element definition scripts"); return TCL_ERROR; } if (clientData) { checkNrArgs (3,6,"Expected:" " name namespace" " | name namespace attquant" " | name namespace ?attquant? " " | name namespace ?attquant? \"type\" typename"); nsObj = objv[2]; } else { checkNrArgs (2,5,"Expected:" " name" " | name attquant" " | name ?attquant? " " | name ?attquant? \"type\" typename"); nsObj = NULL; } nameObj = objv[1]; if (clientData) { objv++; objc--; } if (objc == 2) { return maybeAddAttr (interp, sdata, nameObj, nsObj, NULL, 1, NULL); } str = Tcl_GetStringFromObj (objv[2], &len); if (len == 1) { if (str[0] == '?') { required = 0; } else if (str[0] != '!') { SetResult ("Invalid attribute quant"); return TCL_ERROR; } if (objc == 3) { return maybeAddAttr (interp, sdata, nameObj, nsObj, NULL, required, NULL); } objv++; objc--; str = Tcl_GetStringFromObj (objv[2], &len); } if (objc == 4) { if (len != 4 || strcmp("type", str) != 0) { if (clientData) { SetResult ("Expected:" " name namespace" " | name namespace attquant" " | name namespace ?attquant? " " | name namespace ?attquant? \"type\" typename"); } else { SetResult ("Expected:" " name" " | name attquant" " | name ?attquant? " " | name ?attquant? \"type\" typename"); } return TCL_ERROR; } h = Tcl_FindHashEntry (&sdata->textDef, Tcl_GetString (objv[3])); if (!h) { SetResult3 ("Unknown text type \"", Tcl_GetString (objv[3]), "\""); return TCL_ERROR; } type = (SchemaCP *) Tcl_GetHashValue (h); return maybeAddAttr (interp, sdata, nameObj, nsObj, NULL, required, type); } else { return maybeAddAttr (interp, sdata, nameObj, nsObj, objv[2], required, NULL); } } static int NamespacePatternObjCmd ( ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] ) { SchemaData *sdata = GETASI; char *currentNamespace; int result; CHECK_SI CHECK_TOPLEVEL checkNrArgs (3,3,"Expected: namespace pattern"); currentNamespace = sdata->currentNamespace; sdata->currentNamespace = getNamespacePtr (sdata, Tcl_GetString(objv[1])); sdata->currentEvals++; result = Tcl_EvalObjEx (interp, objv[2], TCL_EVAL_DIRECT); sdata->currentEvals--; sdata->currentNamespace = currentNamespace; return result; } static int TextPatternObjCmd ( ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] ) { SchemaData *sdata = GETASI; SchemaQuant quant = SCHEMA_CQUANT_OPT; SchemaCP *pattern; Tcl_HashEntry *h; int hnew, result = TCL_OK; CHECK_SI CHECK_TOPLEVEL checkNrArgs (1,3,"?? | type "); if (objc == 1) { pattern = initSchemaCP (SCHEMA_CTYPE_TEXT, NULL, NULL); } else if (objc == 2) { quant = SCHEMA_CQUANT_ONE; pattern = initSchemaCP (SCHEMA_CTYPE_CHOICE, NULL, NULL); pattern->type = SCHEMA_CTYPE_TEXT; } else { if (strcmp("type", Tcl_GetString (objv[1])) != 0) { SetResult ("Expected: ?? | type "); return TCL_ERROR; } h = Tcl_CreateHashEntry (&sdata->textDef, Tcl_GetString (objv[2]), &hnew); if (hnew) { pattern = initSchemaCP (SCHEMA_CTYPE_CHOICE, NULL, NULL); pattern->type = SCHEMA_CTYPE_TEXT; REMEMBER_PATTERN (pattern) pattern->flags |= FORWARD_PATTERN_DEF; sdata->forwardPatternDefs++; Tcl_SetHashValue (h, pattern); } quant = SCHEMA_CQUANT_ONE; pattern = (SchemaCP *) Tcl_GetHashValue (h); } if (objc == 2) { result = evalConstraints (interp, sdata, pattern, objv[1]); } if (result == TCL_OK) { if (objc < 3) { REMEMBER_PATTERN (pattern) } addToContent (sdata, pattern, quant, 0, 0); } else { freeSchemaCP (pattern); } return result; } static int VirtualPatternObjCmd ( ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] ) { SchemaData *sdata = GETASI; SchemaCP *pattern; int i; CHECK_SI CHECK_TOPLEVEL if (objc < 2) { SetResult ("Expected: ?arg? ?arg? ..."); return TCL_ERROR; } if (sdata->cp->type != SCHEMA_CTYPE_NAME && sdata->cp->type != SCHEMA_CTYPE_PATTERN) { SetResult ("The \"tcl\" schema definition command is only " "allowed in sequential context (defelement, " "element, group or defpattern)"); return TCL_ERROR; } pattern = initSchemaCP (SCHEMA_CTYPE_VIRTUAL, NULL, NULL); REMEMBER_PATTERN (pattern) pattern->content = MALLOC (sizeof (Tcl_Obj*) * (objc-1)); for (i = 0; i < objc-1; i++) { pattern->content[i] = (SchemaCP *) objv[i+1]; Tcl_IncrRefCount (objv[i+1]); } pattern->nc = objc-1; addToContent (sdata, pattern, SCHEMA_CQUANT_ONE, 0, 0); return TCL_OK; } static int SelfObjCmd ( ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const UNUSED(objv[]) ) { SchemaData *sdata = GETASI; CHECK_SI CHECK_TOPLEVEL if (objc != 1) { SetResult ("No argument expected"); return TCL_ERROR; } Tcl_SetObjResult (interp, Tcl_DuplicateObj (sdata->self)); return TCL_OK; } static int domuniquePatternObjCmd ( ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] ) { SchemaData *sdata = GETASI; ast t; char *errMsg = NULL; domKeyConstraint *kc, *kc1; domLength i, nrFields; int flags = 0; Tcl_Obj *elm; CHECK_SI CHECK_TOPLEVEL checkNrArgs (3, 6, "Expected: ?? ?\"IGNORE_EMPTY_FIELD_SET\"|(?\"EMPTY_FIELD_SET_VALUE\" cp->type != SCHEMA_CTYPE_NAME) { SetResult ("The domunique schema definition command is only " "allowed as direct child of an element."); } if (Tcl_ListObjLength (interp, objv[2], &nrFields) != TCL_OK) { SetResult ("The argument must be a valid tcl list"); return TCL_ERROR; } if (nrFields == 0) { SetResult ("Non empty fieldlist argument expected."); return TCL_ERROR; } if (objc == 5) { if (strcmp (Tcl_GetString (objv[4]), "IGNORE_EMPTY_FIELD_SET") != 0) { SetResult3 ("Unknown flag '", Tcl_GetString (objv[4]), "'"); return TCL_ERROR; } flags |= DKC_FLAG_IGNORE_EMPTY_FIELD_SET; } if (objc == 6) { if (strcmp (Tcl_GetString (objv[4]), "EMPTY_FIELD_SET_VALUE") != 0) { SetResult3 ("Unknown flag '", Tcl_GetString (objv[4]), "'"); return TCL_ERROR; } } if (xpathParse (Tcl_GetString (objv[1]), NULL, XPATH_EXPR, sdata->prefixns, NULL, &t, &errMsg) < 0) { SetResult3 ("Error in selector xpath: '", errMsg, ""); FREE (errMsg); return TCL_ERROR; } kc = TMALLOC (domKeyConstraint); memset (kc, 0, sizeof (domKeyConstraint)); kc->fields = MALLOC (sizeof (ast) * nrFields); memset (kc->fields, 0, sizeof (ast) * nrFields); kc->nrFields = nrFields; kc->selector = t; kc->flags = flags; for (i = 0; i < nrFields; i++) { Tcl_ListObjIndex (interp, objv[2], i, &elm); if (xpathParse (Tcl_GetString (elm), NULL, XPATH_EXPR, sdata->prefixns, NULL, &t, &errMsg) < 0) { SetResult3 ("Error in field xpath: '", errMsg, ""); FREE (errMsg); xpathFreeAst (t); freedomKeyConstraints (kc); return TCL_ERROR; } kc->fields[i] = t; } if (objc >= 4) { kc->name = tdomstrdup (Tcl_GetString (objv[3])); } if (objc == 6) { kc->emptyFieldSetValue = tdomstrdup (Tcl_GetString (objv[5])); kc->efsv_len = strlen (kc->emptyFieldSetValue); } /* Append to end so that the constraints are checked in * definition order */ if (sdata->cp->domKeys) { kc1 = sdata->cp->domKeys; while (1) { if (kc1->next) kc1 = kc1->next; else break; } kc1->next = kc; } else { sdata->cp->domKeys = kc; } return TCL_OK; } static int domxpathbooleanPatternObjCmd ( ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] ) { SchemaData *sdata = GETASI; ast t; char *errMsg = NULL; domKeyConstraint *kc, *kc1; CHECK_SI CHECK_TOPLEVEL checkNrArgs (2, 3, "Expected: ??"); if (sdata->cp->type != SCHEMA_CTYPE_NAME) { SetResult ("The domxpathboolean schema definition command is only " "allowed as direct child of an element."); } if (xpathParse (Tcl_GetString (objv[1]), NULL, XPATH_EXPR, sdata->prefixns, NULL, &t, &errMsg) < 0) { SetResult3 ("Error in selector xpath: '", errMsg, ""); FREE (errMsg); return TCL_ERROR; } kc = TMALLOC (domKeyConstraint); memset (kc, 0, sizeof (domKeyConstraint)); kc->selector = t; kc->flags |= DKC_FLAG_BOOLEAN; if (objc == 3) { kc->name = tdomstrdup (Tcl_GetString (objv[2])); } /* Append to end so that the constraints are checked in * definition order */ if (sdata->cp->domKeys) { kc1 = sdata->cp->domKeys; while (1) { if (kc1->next) kc1 = kc1->next; else break; } kc1->next = kc; } else { sdata->cp->domKeys = kc; } return TCL_OK; } static int jsontypePatternObjCmd ( ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] ) { SchemaData *sdata = GETASI; int jsonType; SchemaCP *pattern; CHECK_SI CHECK_TOPLEVEL if (sdata->cp->type != SCHEMA_CTYPE_NAME) { SetResult ("The command jsontype is only allowed toplevel in element " "definition scripts"); return TCL_ERROR; } checkNrArgs (2,2,"Expected: "); if (Tcl_GetIndexFromObj (interp, objv[1], jsonStructTypes, "jsonType", 1, &jsonType) != TCL_OK) { return TCL_ERROR; } pattern = initSchemaCP (SCHEMA_CTYPE_JSON_STRUCT, NULL, NULL); pattern->typedata = (void *) (intptr_t) jsonType; REMEMBER_PATTERN (pattern); addToContent (sdata, pattern, SCHEMA_CQUANT_ONE, 0, 0); return TCL_OK; } static int keyspacePatternObjCmd ( ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] ) { SchemaData *sdata = GETASI; SchemaCP *pattern; domLength nrKeyspaces, i; int hnew; Tcl_Obj *ksObj; SchemaKeySpace *ks; Tcl_HashEntry *h; CHECK_SI CHECK_TOPLEVEL checkNrArgs (3, 3, "Expected: pattern"); if (sdata->cp->type != SCHEMA_CTYPE_NAME && sdata->cp->type != SCHEMA_CTYPE_PATTERN) { SetResult ("The keyspace schema definition command is only " "allowed in sequential context (defelement, " "element or defpattern)"); return TCL_ERROR; } if (Tcl_ListObjLength (interp, objv[1], &nrKeyspaces) != TCL_OK) { SetResult ("The argument must be a valid tcl " "list"); return TCL_ERROR; } for (i = 0; i < nrKeyspaces; i++) { Tcl_ListObjIndex (interp, objv[1], i, &ksObj); h = Tcl_CreateHashEntry (&sdata->keySpaces, Tcl_GetString (ksObj), &hnew); if (hnew) { ks = TMALLOC (SchemaKeySpace); ks->name = Tcl_GetHashKey (&sdata->keySpaces, h); ks->active = 0; ks->unknownIDrefs = 0; Tcl_SetHashValue (h, ks); } else { ks = Tcl_GetHashValue (h); } pattern = initSchemaCP (SCHEMA_CTYPE_KEYSPACE, Tcl_GetString (ksObj), NULL); pattern->keySpace = ks; REMEMBER_PATTERN (pattern); addToContent (sdata, pattern, SCHEMA_CQUANT_ONE, 0, 0); } sdata->currentEvals++; if (Tcl_EvalObjEx (interp, objv[2], TCL_EVAL_DIRECT) != TCL_OK) { return TCL_ERROR; } sdata->currentEvals--; for (i = 0; i < nrKeyspaces; i++) { Tcl_ListObjIndex (interp, objv[1], i, &ksObj); h = Tcl_FindHashEntry (&sdata->keySpaces, Tcl_GetString(ksObj)); pattern = initSchemaCP (SCHEMA_CTYPE_KEYSPACE_END, Tcl_GetString (ksObj), NULL); REMEMBER_PATTERN (pattern); pattern->keySpace = Tcl_GetHashValue (h); addToContent (sdata, pattern, SCHEMA_CQUANT_ONE, 0, 0); } return TCL_OK; } static int associatePatternObjCmd ( ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] ) { SchemaData *sdata = GETASI; CHECK_SI CHECK_TOPLEVEL checkNrArgs (2, 2, "Expected: data"); switch (sdata->cp->type) { case SCHEMA_CTYPE_NAME: case SCHEMA_CTYPE_PATTERN: case SCHEMA_CTYPE_INTERLEAVE: break; default: SetResult ("The associate schema definition command is only " "allowed inside of global or local element, pattern or " "interleval context"); return TCL_ERROR; } if (sdata->cp->associated) { Tcl_DecrRefCount (sdata->cp->associated); } sdata->cp->associated = objv[1]; Tcl_IncrRefCount (sdata->cp->associated); return TCL_OK; } void tDOM_SchemaInit ( Tcl_Interp *interp ) { Tcl_CreateObjCommand (interp, "tdom::schema", tDOM_SchemaObjCmd, NULL, NULL); /* Inline definition commands. */ Tcl_CreateObjCommand (interp, "tdom::schema::defelement", tDOM_schemaInstanceCmd, NULL, NULL); Tcl_CreateObjCommand (interp, "tdom::schema::defelementtype", tDOM_schemaInstanceCmd, NULL, NULL); Tcl_CreateObjCommand (interp, "tdom::schema::defpattern", tDOM_schemaInstanceCmd, NULL, NULL); Tcl_CreateObjCommand (interp, "tdom::schema::deftexttype", tDOM_schemaInstanceCmd, NULL, NULL); Tcl_CreateObjCommand (interp, "tdom::schema::start", tDOM_schemaInstanceCmd, NULL, NULL); Tcl_CreateObjCommand (interp, "tdom::schema::prefixns", tDOM_schemaInstanceCmd, NULL, NULL); /* The "any" definition command. */ Tcl_CreateObjCommand (interp, "tdom::schema::any", AnyPatternObjCmd, NULL, NULL); /* The named pattern commands "element" and "ref". */ Tcl_CreateObjCommand (interp, "tdom::schema::element", ElementPatternObjCmd, NULL, NULL); Tcl_CreateObjCommand (interp, "tdom::schema::ref", RefPatternObjCmd, NULL, NULL); /* The anonymous pattern commands "choice", "mixed", "interleave" * and "group". */ Tcl_CreateObjCommand (interp, "tdom::schema::choice", AnonPatternObjCmd, (ClientData) 0, NULL); Tcl_CreateObjCommand (interp, "tdom::schema::mixed", AnonPatternObjCmd, (ClientData) 1, NULL); Tcl_CreateObjCommand (interp, "tdom::schema::interleave", AnonPatternObjCmd, (ClientData) 2, NULL); Tcl_CreateObjCommand (interp, "tdom::schema::group", AnonPatternObjCmd, (ClientData) 3, NULL); /* The "attribute", "nsattribute", "namespace" and "text" * definition commands. */ Tcl_CreateObjCommand (interp, "tdom::schema::attribute", AttributePatternObjCmd, NULL, NULL); Tcl_CreateObjCommand (interp, "tdom::schema::nsattribute", AttributePatternObjCmd, (ClientData) 1, NULL); Tcl_CreateObjCommand (interp, "tdom::schema::namespace", NamespacePatternObjCmd, NULL, NULL); Tcl_CreateObjCommand (interp, "tdom::schema::text", TextPatternObjCmd, NULL, NULL); /* The 'virtual' "tcl" and the "self" definition command */ Tcl_CreateObjCommand (interp, "tdom::schema::tcl", VirtualPatternObjCmd, NULL, NULL); Tcl_CreateObjCommand (interp, "tdom::schema::self", SelfObjCmd, NULL, NULL); /* XPath constraints for DOM validation */ Tcl_CreateObjCommand (interp,"tdom::schema::domunique", domuniquePatternObjCmd, NULL, NULL); Tcl_CreateObjCommand (interp,"tdom::schema::domxpathboolean", domxpathbooleanPatternObjCmd, NULL, NULL); /* JSON structure types for DOM validation */ Tcl_CreateObjCommand (interp,"tdom::schema::jsontype", jsontypePatternObjCmd, NULL, NULL); /* Local key constraints */ Tcl_CreateObjCommand (interp, "tdom::schema::keyspace", keyspacePatternObjCmd, NULL, NULL); /* The associate command */ Tcl_CreateObjCommand (interp,"tdom::schema::associate", associatePatternObjCmd, NULL, NULL); tDOM_DatatypesInit (interp); } #else /* #ifndef TDOM_NO_SCHEMA */ SchemaData * tdomGetSchemadata (Tcl_Interp *interp) { return 0; } #endif /* #ifndef TDOM_NO_SCHEMA */ tdom-0.9.6-src/generic/tclpull.h0000644000175000017500000000017115025767703015223 0ustar rolfrolf int tDOM_PullParserCmd (ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); tdom-0.9.6-src/generic/domxpath.c0000644000175000017500000063536615025767703015407 0ustar rolfrolf/*---------------------------------------------------------------------------- | Copyright (c) 1999-2001 Jochen Loewer (loewerj@hotmail.com) |----------------------------------------------------------------------------- | | A XPath implementation (lexer/parser/evaluator) for tDOM, | the DOM implementation for Tcl. | Based on November 16 1999 Recommendation of the W3C | (http://www.w3.org/TR/1999/REC-xslt-19991116) | | | The contents of this file are subject to the Mozilla Public License | Version 2.0 (the "License"); you may not use this file except in | compliance with the License. You may obtain a copy of the License at | http://www.mozilla.org/MPL/ | | Software distributed under the License is distributed on an "AS IS" | basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the | License for the specific language governing rights and limitations | under the License. | | The Original Code is tDOM. | | The Initial Developer of the Original Code is Jochen Loewer | Portions created by Jochen Loewer are Copyright (C) 1999 - 2001 | Jochen Loewer. All Rights Reserved. | | Portions created by Zoran Vasiljevic are Copyright (C) 2000-2002 | Zoran Vasiljevic. All Rights Reserved. | | Portions created by Rolf Ade are Copyright (C) 1999-2007 | Rolf Ade. All Rights Reserved. | | Contributor(s): | April00 Rolf Ade Add support for following/preceding/ | precedingSibling axis plus several | bug fixes | | Aug00 Rolf Ade Rewrite of comparisons plus several | bug fixes/reports | | Aug01 Rolf Ade id(), unparsed-entity(), lang(), fixes | | 2002 Rolf Ade Namespace aware nodetests and NS wildcard | expr, namespace aware variables, keys and | function, made lexer utf-8 aware, node sets | could now include nodes of different types, | better IEEE 754 rules support, code | restructured, several optimizations and bug | fixes. | | written by Jochen Loewer | July, 1999 | \---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------- | Includes | \---------------------------------------------------------------------------*/ #include #include #include #include #include #include #include #include #include #include #include /*---------------------------------------------------------------------------- | Macros | \---------------------------------------------------------------------------*/ #define JDBG(x) #define DBG(x) #define DDBG(x) #define TRACE(x) DDBG(fprintf(stderr,(x))) #define TRACE1(x,a) DDBG(fprintf(stderr,(x),(a))) #define TRACE2(x,a,b) DDBG(fprintf(stderr,(x),(a),(b))) #define TRACE3(x,a,b,c) DDBG(fprintf(stderr,(x),(a),(b),(c))) #define INITIAL_SIZE 100 #define ADD_TOKEN(t) if ((l+1)>=allocated) { \ tokens=(XPathTokens)REALLOC((char*)tokens, 2*allocated\ *sizeof(XPathToken)); \ allocated = allocated * 2; \ } \ tokens[l].token = (t); \ tokens[l++].pos = i; \ tokens[l].token = EOS; \ tokens[l].strvalue = NULL; \ tokens[l].intvalue = 0; \ tokens[l].realvalue = 0.0; #define DeclProduction(name) static ast name (int *l,XPathTokens tokens,char **errMsg) #define Production(name) static ast name (int *l,XPathTokens tokens,char **errMsg) \ { char *__func = #name; \ ast a = NULL; \ TRACE2("\nProduction "#name": start l=%d next:%s\n", \ *l,token2str[tokens[*l].token]); #define EndProduction TRACE3("EndProd %s: start l=%d next:%s\n", \ __func, *l,token2str[tokens[*l].token]); \ DDBG(printAst(0,a);) \ return a; \ } #define LA tokens[*l].token #define LA2 tokens[*l+1].token #define LA3 tokens[*l+2].token /* #define Recurse(p) rc=p(l,tokens,errMsg);if(rc==NULL)return rc;*/ #define Recurse(p) p(l,tokens,errMsg) #define Consume(tk) if (tokens[*l].token == tk) { \ TRACE2("Production %s: %s consumed\n", \ __func, token2str[tokens[*l].token]); \ (*l)++; \ } else { \ if (*errMsg==NULL) {ErrExpected(#tk);} \ else return a; \ } #define STRVAL tokens[(*l)-1].strvalue #define INTVAL tokens[(*l)-1].intvalue #define REALVAL tokens[(*l)-1].realvalue #define NEWCONS ((ast)MALLOC(sizeof(astElem))) #define IS_STR(c,s) (c==*(tokens[(*l)-1].strvalue))&&(strcmp(tokens[(*l)-1].strvalue,s)==0) #define IS_FUNC(c,s) ((*(step->strvalue)==(c)) && (strcmp((s),step->strvalue)==0)) #define ErrExpected(msg) *errMsg = (char*)MALLOC(255); \ **errMsg = '\0'; \ strcpy(*errMsg, __func); \ strcat(*errMsg, ": Expected " #msg); \ return a; #define CHECK_RC if (rc) return rc #define checkRsAddNode(rs,node) if (useFastAdd) rsAddNodeFast( rs,node); \ else rsAddNode (rs,node); /*---------------------------------------------------------------------------- | Types for Lexer | \---------------------------------------------------------------------------*/ typedef enum { LPAR, RPAR, LBRACKET, RBRACKET, DOT, DOTDOT, ATTRIBUTEPREFIX, ATTRIBUTE, COMMA, COLONCOLON, LITERAL, NSPREFIX, NSWC, INTNUMBER, REALNUMBER, SLASH, SLASHSLASH, PIPE, PLUS, MINUS, EQUAL, NOTEQ, LT, LTE, GT, GTE, AND, OR, MOD, DIV, MULTIPLY, FUNCTION, VARIABLE, FQVARIABLE, WCARDNAME, COMMENT, TEXT, PINSTR, NODE, AXISNAME, EOS } Token; static const char *token2str[] = { "LPAR", "RPAR", "LBRACKET", "RBRACKET", "DOT", "DOTDOT", "ATTRIBUTEPREFIX", "ATTRIBUTE", "COMMA", "COLONCOLON", "LITERAL", "NSPREFIX", "NSWC", "INTNUMBER", "REALNUMBER", "SLASH", "SLASHSLASH", "PIPE", "PLUS", "MINUS", "EQUAL", "NOTEQ", "LT", "LTE", "GT", "GTE", "AND", "OR", "MOD", "DIV", "MULTIPLY", "FUNCTION", "VARIABLE", "FQVARIABLE", "WCARDNAME", "COMMENT", "TEXT", "PI", "NODE", "AXISNAME", "EOS" }; typedef struct { Token token; char *strvalue; dom_minl intvalue; double realvalue; domLength pos; } XPathToken; typedef XPathToken *XPathTokens; /*---------------------------------------------------------------------------- | Types for abstract syntax trees | \---------------------------------------------------------------------------*/ static const char *astType2str[] = { "Int", "Real", "Mult", "Div", "Mod", "UnaryMinus", "IsNSElement", "IsNode", "IsComment", "IsText", "IsPI", "IsSpecificPI", "IsElement", "IsFQElement", "GetVar", "GetFQVar", "Literal", "ExecFunction", "Pred", "EvalSteps", "SelectRoot", "CombineSets", "Add", "Subtract", "Less", "LessOrEq", "Greater", "GreaterOrEq", "Equal", "NotEqual", "And", "Or", "IsNSAttr", "IsAttr", "AxisAncestor", "AxisAncestorOrSelf", "AxisAttribute", "AxisChild", "AxisDescendant", "AxisDescendantOrSelf", "AxisFollowing", "AxisFollowingSibling", "AxisNamespace", "AxisParent", "AxisPreceding", "AxisPrecedingSilbing", "AxisSelf", "GetContextNode", "GetParentNode", "AxisDescendantOrSelfLit", "AxisDescendantLit", "SlashSlash", "CombinePath", "IsRoot", "ToParent", "ToAncestors", "FillNodeList", "FillWithCurrentNode", "ExecIdKey" }; static const char *xpathResultTypes[] = { "unknown", "empty", "bool", "number", "number", "string", "xNodeSet", "number", "number", "number", "nodes", "attrnodes", "mixed", NULL }; /*---------------------------------------------------------------------------- | functionTag | \---------------------------------------------------------------------------*/ typedef enum { f_unknown = 1, f_boolean, f_ceiling, f_concat, f_contains, f_count, f_false, f_floor, f_generateId, f_id, f_lang, f_last, f_laststring, f_localName, f_name, f_namespaceUri, f_normalizeSpace, f_not, f_number, f_position, f_round, f_startsWith, f_string, f_stringLength, f_substring, f_substringAfter, f_substringBefore, f_sum, f_translate, f_true, f_unparsedEntityUri, f_fqfunction } functionTag; /*---------------------------------------------------------------------------- | Prototypes / Forwards | \---------------------------------------------------------------------------*/ DeclProduction(OrExpr); DeclProduction(Predicate); DeclProduction(RelativeLocationPath); DeclProduction(AbsoluteLocationPath); char *xpathFuncString (xpathResultSet *rs ); static int xpathEvalStep (ast step, domNode *ctxNode, domNode *exprContext, domLength position, xpathResultSet *nodeList, xpathCBs *cbs, xpathResultSet *result, int *docOrder, char **errMsg); static int xpathEvalPredicate (ast steps, domNode *exprContext, xpathResultSet *result, xpathResultSet *stepResult, xpathCBs *cbs, int *docOrder, char **errMsg); /*---------------------------------------------------------------------------- | xpathResultType2string | \---------------------------------------------------------------------------*/ const char * xpathResultType2string ( xpathResultType type ) { return xpathResultTypes[type]; } /*---------------------------------------------------------------------------- | XPath result set functions | \---------------------------------------------------------------------------*/ void xpathRSFree ( xpathResultSet *rs ) { if (rs->type == xNodeSetResult) { if (!rs->intvalue) { if (rs->nodes) FREE((char*)rs->nodes); } rs->nr_nodes = 0; } else if (rs->type == StringResult) { if (rs->string) FREE((char*)rs->string); } rs->type = EmptyResult; } void xpathRSReset ( xpathResultSet *rs, domNode *node ) { if (rs->type == StringResult) FREE(rs->string); if (node) { if (!rs->nodes) { rs->nodes = (domNode**)MALLOC( INITIAL_SIZE*sizeof(domNode*)); rs->allocated = INITIAL_SIZE; } rs->nodes[0] = node; rs->nr_nodes = 1; rs->type = xNodeSetResult; } else { rs->nr_nodes = 0; if (rs->nodes) rs->type = xNodeSetResult; else rs->type = EmptyResult; } } void rsPrint ( xpathResultSet *rs ) { domLength i = 0,l; char tmp[80]; switch (rs->type) { case EmptyResult: fprintf(stderr, "empty result \n"); break; case BoolResult: #if TCL_MAJOR_VERSION > 8 fprintf(stderr, "boolean result: %" TCL_SIZE_MODIFIER "d \n", #else fprintf(stderr, "boolean result: %ld \n", #endif rs->intvalue); break; case IntResult: #if TCL_MAJOR_VERSION > 8 fprintf(stderr, "boolean result: %" TCL_SIZE_MODIFIER "d \n", #else fprintf(stderr, "boolean result: %ld \n", #endif rs->intvalue); break; case RealResult: fprintf(stderr, "real result: %f \n", rs->realvalue); break; case StringResult: fprintf(stderr, "string result: -%80s-\n", rs->string); break; case xNodeSetResult: if (!i) fprintf(stderr,"nodeSet result (len " domLengthConversion "):\n", rs->nr_nodes); for (i=0; inr_nodes; i++) { if (rs->nodes[i]->nodeType == ELEMENT_NODE) { fprintf(stderr, "%2" TCL_SIZE_MODIFIER "i domNode%p %s ", i, (void *)rs->nodes[i], rs->nodes[i]->nodeName); if (rs->nodes[i]->firstChild && rs->nodes[i]->firstChild->nodeType == TEXT_NODE) { l = ((domTextNode*)rs->nodes[i]->firstChild)->valueLength; if (l > 25) l = 25; memcpy(tmp, ((domTextNode*)rs->nodes[i]->firstChild)->nodeValue, l); tmp[l] = '\0'; fprintf(stderr, "'%s'", tmp); } fprintf(stderr, "\n"); } else if (rs->nodes[i]->nodeType == TEXT_NODE) { l = ((domTextNode*)rs->nodes[i])->valueLength; if (l > 60) l = 60; memcpy(tmp, ((domTextNode*)rs->nodes[i])->nodeValue, l); tmp[l] = '\0'; fprintf(stderr, "%2" TCL_SIZE_MODIFIER "i domNode%p text:'%s' \n", i, (void *)rs->nodes[i], tmp); } else if (rs->nodes[i]->nodeType == COMMENT_NODE) { l = ((domTextNode*)rs->nodes[i])->valueLength; memcpy (tmp, "", 3); tmp[7+l] = '\0'; fprintf(stderr, "%2" TCL_SIZE_MODIFIER "i domNode%p text:'%s' \n", i, (void *)rs->nodes[i], tmp); } else if (rs->nodes[i]->nodeType == ATTRIBUTE_NODE) { fprintf(stderr, "%2" TCL_SIZE_MODIFIER "i Attr %s='%80s'\n", i, ((domAttrNode*)rs->nodes[i])->nodeName, ((domAttrNode*)rs->nodes[i])->nodeValue); } } break; case NaNResult: fprintf (stderr, "NaN result\n"); break; case InfResult: fprintf (stderr, "Inf result\n"); break; case NInfResult: fprintf (stderr, "-Inf result\n"); break; default: fprintf (stderr, "unknown result type: '%d'!!!\n", rs->type); break; } } void rsSetReal ( xpathResultSet *rs, double d) { rs->type = RealResult; rs->realvalue = d; } void rsSetReal2 ( xpathResultSet *rs, double d) { if (d <= (double)LONG_MIN || d >= (double)LONG_MAX || d != (long)d) { rs->type = RealResult; rs->realvalue = d; } else { rs->type = IntResult; rs->intvalue = (long)d; } } void rsSetNaN ( xpathResultSet *rs ) { rs->type = NaNResult; } void rsSetInf ( xpathResultSet *rs ) { rs->type = InfResult; } void rsSetNInf ( xpathResultSet *rs ) { rs->type = NInfResult; } void rsSetLong ( xpathResultSet *rs, dom_minl i) { rs->type = IntResult; rs->intvalue = i; } void rsSetBool ( xpathResultSet *rs, dom_minl i) { rs->type = BoolResult; rs->intvalue = (i ? 1 : 0); } void rsSetString ( xpathResultSet *rs, const char *s) { rs->type = StringResult; if (s) { rs->string = tdomstrdup(s); rs->string_len = (domLength)strlen(s); } else { rs->string = tdomstrdup(""); rs->string_len = 0; } rs->nr_nodes = 0; } void rsAddNode ( xpathResultSet *rs, domNode *node) { if ((rs->type != EmptyResult) && (rs->type != xNodeSetResult)) { domPanic("Can not add node to non NodeSetResult xpathResultSet!"); } if (rs->type == EmptyResult) { rs->type = xNodeSetResult; rs->nodes = (domNode**)MALLOC(INITIAL_SIZE * sizeof(domNode*)); rs->allocated = INITIAL_SIZE; rs->nr_nodes = 1; rs->nodes[0] = node; } else { domLength insertIndex, i; if (rs->intvalue) { /* we must do a copy-on-write */ domNode **nodes; nodes = (domNode**)MALLOC(rs->allocated * sizeof(domNode*)); memcpy (nodes, rs->nodes, sizeof(domNode*) * rs->nr_nodes); rs->nodes = nodes; rs->intvalue = 0; } insertIndex = rs->nr_nodes; for (i = rs->nr_nodes - 1; i >= 0; i--) { if (node == rs->nodes[i]) return; if (!domPrecedes (node, rs->nodes[i])) { break; } insertIndex--; } if ((rs->nr_nodes+1) >= rs->allocated) { rs->nodes = (domNode**)REALLOC((void*)rs->nodes, 2 * rs->allocated * sizeof(domNode*)); rs->allocated = rs->allocated * 2; } if (insertIndex == rs->nr_nodes) { rs->nodes[rs->nr_nodes++] = node; } else { for (i = rs->nr_nodes - 1; i >= insertIndex; i--) { rs->nodes[i+1] = rs->nodes[i]; } rs->nodes[insertIndex] = node; rs->nr_nodes++; } } } void rsAddNodeFast ( xpathResultSet *rs, domNode *node) { if ((rs->type != EmptyResult) && (rs->type != xNodeSetResult)) { domPanic("Can not add node to non NodeSetResult xpathResultSet!"); } if (rs->type == EmptyResult) { rs->type = xNodeSetResult; rs->nodes = (domNode**)MALLOC(INITIAL_SIZE * sizeof(domNode*)); rs->allocated = INITIAL_SIZE; rs->nr_nodes = 1; rs->nodes[0] = node; } else { if ((rs->nr_nodes+1) >= rs->allocated) { rs->nodes = (domNode**)REALLOC((void*)rs->nodes, 2 * rs->allocated * sizeof(domNode*)); rs->allocated = rs->allocated * 2; } rs->nodes[rs->nr_nodes++] = node; } } void rsCopy ( xpathResultSet *to, xpathResultSet *from ) { domLength i; to->type = from->type; to->intvalue = from->intvalue; if (from->type == RealResult) { to->realvalue = from->realvalue; } else if (from->type == StringResult) { to->string = tdomstrdup(from->string); to->string_len = from->string_len; } else if (from->type == xNodeSetResult) { to->nr_nodes = from->nr_nodes; to->nodes = (domNode**)MALLOC(from->nr_nodes * sizeof(domNode*)); for (i=0; inr_nodes; i++) to->nodes[i] = from->nodes[i]; to->intvalue = 0; } } /*---------------------------------------------------------------------------- | AST construct functions | \---------------------------------------------------------------------------*/ static ast New( astType type ) { ast t = NEWCONS; t->type = type; t->next = t->child = NULL; t->strvalue = NULL; t->intvalue = 0; t->realvalue = 0.0; return t; } static ast New1( astType type, ast a) { ast t = NEWCONS; t->type = type; t->next = NULL; t->child = a; t->strvalue = NULL; t->intvalue = 0; t->realvalue = 0.0; return t; } static ast New1WithEvalSteps( astType type, ast a) { ast t = NEWCONS; t->type = type; t->next = NULL; if (a && a->next) { t->child = New1(EvalSteps,a); } else { t->child = a; } t->strvalue = NULL; t->intvalue = 0; t->realvalue = 0.0; return t; } static ast New2( astType type, ast a, ast b ) { ast t = NEWCONS; t->type = type; t->next = NULL; t->strvalue = NULL; t->intvalue = 0; t->realvalue = 0.0; if (a && a->next) { t->child = New1(EvalSteps,a); } else { t->child = a; } if (b && b->next) { t->child->next = New1(EvalSteps, b); } else { t->child->next = b; } return t; } static ast NewInt( dom_minl i ) { ast t = NEWCONS; t->type = Int; t->strvalue = NULL; t->intvalue = i; t->realvalue = 0.0; t->next = t->child = NULL; return t; } static ast NewReal( double r ) { ast t = NEWCONS; t->type = Real; t->strvalue = NULL; t->intvalue = 0; t->realvalue = r; t->next = t->child = NULL; return t; } static ast NewStr( astType type, char *str ) { ast t = NEWCONS; t->type = type; t->strvalue = tdomstrdup(str); t->intvalue = 0; t->realvalue = 0.0; t->next = t->child = NULL; return t; } static ast Append( ast m, ast n ) { if (!n) return NULL; if (!m) return NULL; while (m->next != NULL) m = m->next; m->next = n; return m; } static ast AddChild( ast m, ast child ) { if (!child) return NULL; if (!m) return NULL; if (m->child == NULL) { m->child = child; } else { ast c = m->child; while (c->next != NULL) c = c->next; c->next = child; } return m; } static ast AddChildWithEvalSteps( ast m, ast child ) { if (!child) return NULL; if (!m) return NULL; if (child->next) { child = New1(EvalSteps, child); } if (m->child == NULL) { m->child = child; } else { ast c = m->child; while (c->next != NULL) c = c->next; c->next = child; } /*child->next = NULL;*/ return m; } static void freeAst (ast t) { ast tmp; while (t) { tmp = t->next; if (t->strvalue) FREE(t->strvalue); if (t->child) freeAst (t->child); FREE((char*)t); t = tmp; } } void printAst (int depth, ast t) { int i; while (t) { for (i=0; itype]); switch (t->type) { case Int : #if TCL_MAJOR_VERSION > 8 fprintf(stderr, "%" TCL_SIZE_MODIFIER "d", t->intvalue); break; #else fprintf(stderr, "%ld", t->intvalue); break; #endif case Real: fprintf(stderr, "%f", t->realvalue); break; case IsElement: case IsFQElement: case IsNSAttr: case IsAttr: case ExecFunction: case Literal: case GetFQVar: case GetVar: fprintf(stderr, "'%s'", t->strvalue); break; default: break; } fprintf(stderr, "\n"); if (t->child) printAst (depth+1, t->child); t = t->next; } } /*---------------------------------------------------------------------------- | xpathFreeAst | \---------------------------------------------------------------------------*/ void xpathFreeAst( ast t ) { freeAst(t); } /*---------------------------------------------------------------------------- | xpathLexer | \---------------------------------------------------------------------------*/ static XPathTokens xpathLexer ( char *xpath, domNode *exprContext, char **prefixMappings, int *useNamespaceAxis, xpathParseVarCB *varParseCB, char **errMsg ) { domLength l, allocated, i, k, start, offset; char delim, *ps, save, tmpErr[80], *tailptr; const char *uri; XPathTokens tokens; int token = EOS; tokens = (XPathTokens)MALLOC(INITIAL_SIZE * sizeof(XPathToken)); if (tokens == NULL) { *errMsg = tdomstrdup("Unable to alloc initial memory!"); return NULL; } allocated = INITIAL_SIZE; l = 0; tokens[l].token = EOS; tokens[l].strvalue = NULL; tokens[l].intvalue = 0; tokens[l].realvalue = 0.0; i = 0; while (xpath[i]) { switch (xpath[i]) { case ' ' : case '\n': case '\r': case '\t': i++; continue; case '(': token = LPAR; break; case ')': token = RPAR; break; case '[': token = LBRACKET; break; case ']': token = RBRACKET; break; case '@': i++; while (xpath[i] && IS_XML_WHITESPACE(xpath[i])) i++; if ( isNCNameStart (&xpath[i]) ) { ps = &(xpath[i]); i += UTF8_CHAR_LEN (xpath[i]); while (xpath[i] && isNCNameChar (&xpath[i])) i += UTF8_CHAR_LEN (xpath[i]); save = xpath[i]; xpath[i] = '\0'; if (save == ':' && xpath[i+1] != ':') { uri = domLookupPrefixWithMappings ( exprContext, ps, prefixMappings); if (!uri) { xpath[i] = save; *errMsg = tdomstrdup ("Prefix doesn't" " resolve"); return tokens; } tokens[l].strvalue = tdomstrdup (uri); xpath[i] = save; token = ATTRIBUTEPREFIX; ADD_TOKEN (token); if (xpath[i+1] == '*') { token = ATTRIBUTE; tokens[l].strvalue = tdomstrdup("*"); i++; } else { ps = &(xpath[++i]); if (!(isNCNameStart (&xpath[i]))) { *errMsg = tdomstrdup ("Illegal attribute" " name"); return tokens; } i += UTF8_CHAR_LEN (xpath[i]); while (xpath[i] && isNCNameChar (&xpath[i])) i += UTF8_CHAR_LEN (xpath[i]); save = xpath[i]; xpath[i] = '\0'; token = ATTRIBUTE; tokens[l].strvalue = tdomstrdup(ps); xpath[i--] = save; } } else { tokens[l].strvalue = tdomstrdup(ps); xpath[i] = save; token = ATTRIBUTE; i--; } } else if (xpath[i]=='*') { tokens[l].strvalue = tdomstrdup("*"); token = ATTRIBUTE; } else { *errMsg = tdomstrdup("Expected attribute name"); return tokens; }; break; case ',': token = COMMA; break; case ':': if (xpath[i+1] == ':') { token = COLONCOLON; i++; } else { *errMsg = tdomstrdup("Unexpected token ':'"); return tokens; }; break; case '"' : case '\'': delim = xpath[i]; start = ++i; while (xpath[i] && (xpath[i] != delim)) i++; if (!xpath[i]) { *errMsg = tdomstrdup("Undetermined string"); return tokens; } xpath[i] = '\0'; /* terminate string */ tokens[l].strvalue = tdomstrdup(&xpath[start]); token = LITERAL; xpath[i] = delim; break; case '/': if (xpath[i+1] == '/') { token = SLASHSLASH; i++; } else { token = SLASH; }; break; case '|': token = PIPE; break; case '+': token = PLUS; break; case '-': token = MINUS; break; case '=': token = EQUAL; break; case '!': if (xpath[i+1] == '=') { token = NOTEQ; i++; } else { *errMsg = tdomstrdup("Unexpected token '!'"); return tokens; }; break; case '<': if (xpath[i+1] == '=') { token = LTE; i++; } else { token = LT; };break; case '>': if (xpath[i+1] == '=') { token = GTE; i++; } else { token = GT; }; break; case '*': if ((l>0) && (tokens[l-1].token != COLONCOLON) && (tokens[l-1].token != LPAR) && (tokens[l-1].token != LBRACKET) && (tokens[l-1].token != COMMA) && (tokens[l-1].token != SLASH) && (tokens[l-1].token != SLASHSLASH) ) { token = MULTIPLY; } else { token = WCARDNAME; tokens[l].strvalue = tdomstrdup("*"); }; break; case '$': if (varParseCB) { ps = (varParseCB->parseVarCB) ( varParseCB->parseVarClientData, &xpath[i], &offset, errMsg ); if (ps) { token = LITERAL; tokens[l].strvalue = tdomstrdup (ps); i += offset - 1; } else { return tokens; } } else { i++; if ( isNCNameStart (&xpath[i])) { ps = &(xpath[i]); i += UTF8_CHAR_LEN (xpath[i]); while (xpath[i] && isNCNameChar(&xpath[i])) i += UTF8_CHAR_LEN(xpath[i]); if (xpath[i] == ':' && xpath[i+1] != ':') { token = FQVARIABLE; save = xpath[i]; xpath[i] = '\0'; uri = domLookupPrefixWithMappings ( exprContext, ps, prefixMappings); if (!uri) { xpath[i] = save; *errMsg = tdomstrdup ("Prefix doesn't" " resolve"); return tokens; } tokens[l].strvalue = tdomstrdup (uri); xpath[i] = save; ADD_TOKEN (token); ps = &(xpath[++i]); if (!isNCNameStart (&xpath[i])) { *errMsg = tdomstrdup ("Illegal variable" " name"); return tokens; } i += UTF8_CHAR_LEN (xpath[i]); while (xpath[i] && isNCNameChar (&xpath[i])) i += UTF8_CHAR_LEN (xpath[i]); } token = VARIABLE; save = xpath[i]; xpath[i] = '\0'; tokens[l].strvalue = tdomstrdup(ps); xpath[i--] = save; } else { *errMsg = tdomstrdup("Expected variable name"); return tokens; } } break; case '%': if (!varParseCB) { *errMsg = tdomstrdup ("Unexpected char '%'"); return tokens; } ps = (varParseCB->parseVarCB) ( varParseCB->parseVarClientData, &xpath[i], &offset, errMsg ); if (ps) { token = WCARDNAME; tokens[l].strvalue = tdomstrdup (ps); /* We kind of misuse the (in case of * WCARDNAME token otherwise not used) * intvalue to mark this WCARDNAME token * to be meant as literal - this is to * distinguish between '*' as wildcard and * as literal element name. */ tokens[l].intvalue = 1; i += offset - 1; } else { return tokens; } break; case '.': if (xpath[i+1] == '.') { token = DOTDOT; i++; break; } else if (!isdigit((unsigned char)xpath[i+1])) { token = DOT; break; } /* DOT followed by digit, i.e. a REAL. Handled by default. */ /* fall through */ default: if ( isNCNameStart (&xpath[i])) { ps = &(xpath[i]); i += UTF8_CHAR_LEN (xpath[i]); while (xpath[i] && isNCNameChar(&xpath[i])) { i += UTF8_CHAR_LEN(xpath[i]); } k = i; if (xpath[i] == ':') { if (xpath[i+1] == '*') { save = xpath[i]; xpath[i] = '\0'; /* terminate */ token = NSWC; uri = domLookupPrefixWithMappings ( exprContext, ps, prefixMappings); if (!uri) { xpath[i] = save; *errMsg = tdomstrdup ("Prefix doesn't" " resolve"); return tokens; } tokens[l].strvalue = tdomstrdup (uri); xpath[i] = save; i++; break; } if (xpath[i+1] != ':') { save = xpath[i]; xpath[i] = '\0'; /* terminate */ token = NSPREFIX; uri = domLookupPrefixWithMappings ( exprContext, ps, prefixMappings); if (!uri) { xpath[i] = save; *errMsg = tdomstrdup ("Prefix doesn't" " resolve"); return tokens; } tokens[l].strvalue = tdomstrdup (uri); xpath[i] = save; ADD_TOKEN (token); ps = &(xpath[++i]); if (!(isNCNameStart (&xpath[i]))) { *errMsg = tdomstrdup ("Illegal character in" " localname"); return tokens; } i += UTF8_CHAR_LEN (xpath[i]); while (xpath[i] && isNCNameChar (&xpath[i])) i += UTF8_CHAR_LEN (xpath[i]); k = i; } } /* read over white space */ while ((xpath[k] == ' ') || (xpath[k] == '\n') || (xpath[k] == '\r') || (xpath[k] == '\t') ) k++; if (l>0 && tokens[l-1].token == NSPREFIX) { if (xpath[k]!='(') token = WCARDNAME; else token = FUNCTION; save = xpath[i]; xpath[i] = '\0'; tokens[l].strvalue = tdomstrdup(ps); xpath[i--] = save; break; } if (xpath[k]=='(') { save = xpath[i]; xpath[i] = '\0'; /* terminate */ if (strcmp(ps,"text")==0) { token = TEXT; } else if (strcmp(ps,"node")==0) { token = NODE; } else if (strcmp(ps,"comment")==0) { token = COMMENT; } else if (strcmp(ps,"processing-instruction")==0) { token = PINSTR; } else { if ((save!='(') && (strcmp(ps,"and")==0)) token = AND; else if ((save!='(') && (strcmp(ps,"or")==0)) token = OR; else if ((save!='(') && (strcmp(ps,"mod")==0)) token = MOD; else if ((save!='(') && (strcmp(ps,"div")==0)) token = DIV; else { token = FUNCTION; tokens[l].strvalue = tdomstrdup(ps); } } xpath[i] = save; } else if ((xpath[k]==':') && (xpath[k+1]==':')) { token = AXISNAME; save = xpath[i]; xpath[i] = '\0'; /* terminate */ tokens[l].strvalue = tdomstrdup(ps); if (ps[0] == 'n'&& strcmp(ps, "namespace")==0) { *useNamespaceAxis = 1; } xpath[i] = save; } else { save = xpath[i]; xpath[i] = '\0'; if ((l>0) && (tokens[l-1].token != COLONCOLON) && (tokens[l-1].token != LPAR) && (tokens[l-1].token != LBRACKET) && (tokens[l-1].token != COMMA) && (tokens[l-1].token != SLASH) && (tokens[l-1].token != SLASHSLASH) && (tokens[l-1].token != PIPE) && (tokens[l-1].token != PLUS) && (tokens[l-1].token != MINUS) && (tokens[l-1].token != EQUAL) && (tokens[l-1].token != NOTEQ) && (tokens[l-1].token != LT) && (tokens[l-1].token != LTE) && (tokens[l-1].token != GT) && (tokens[l-1].token != GTE) && (tokens[l-1].token != AND) && (tokens[l-1].token != OR) && (tokens[l-1].token != MOD) && (tokens[l-1].token != DIV) && (tokens[l-1].token != MULTIPLY) ) { if (strcmp(ps,"and")==0) { token = AND; } else if (strcmp(ps,"or")==0) { token = OR; } else if (strcmp(ps,"mod")==0) { token = MOD; } else if (strcmp(ps,"div")==0) { token = DIV; } else { token = WCARDNAME; tokens[l].strvalue = tdomstrdup(ps); } } else { token = WCARDNAME; tokens[l].strvalue = tdomstrdup(ps); } xpath[i] = save; } i--; } else if (isdigit((unsigned char)xpath[i]) || (xpath[i] == '.')) { if (xpath[i] == '.') { token = REALNUMBER; } else { token = INTNUMBER; } ps = &(xpath[i++]); while (xpath[i] && isdigit((unsigned char)xpath[i])) i++; if (xpath[i]=='.') { if (token == REALNUMBER) { sprintf (tmpErr, "Unexpected character " "'%c' at position %" TCL_SIZE_MODIFIER "i", xpath[i], i); *errMsg = tdomstrdup (tmpErr); return tokens; } token = REALNUMBER; i++; while (xpath[i] && isdigit((unsigned char)xpath[i])) i++; } save = xpath[i]; xpath[i] = '\0'; if (token == INTNUMBER) { errno = 0; tokens[l].intvalue = strtol(ps, NULL, 10); if (errno == ERANGE && ( tokens[l].intvalue == LONG_MAX || tokens[l].intvalue == LONG_MIN)) { token = REALNUMBER; } } tokens[l].realvalue = strtod(ps, &tailptr); xpath[i--] = save; if (tokens[l].realvalue == 0.0 && tailptr == ps) { sprintf (tmpErr, "Number value too large " "at position %" TCL_SIZE_MODIFIER "i", i); *errMsg = tdomstrdup (tmpErr); return tokens; } } else { sprintf (tmpErr, "Unexpected character '%c' at " "position %" TCL_SIZE_MODIFIER "i", xpath[i], i); *errMsg = tdomstrdup (tmpErr); return tokens; } break; } /* switch */ ADD_TOKEN(token); i++; } ADD_TOKEN(EOS); return tokens; } /* xpathLexer */ /*----------------------------------------------------------------- | NodeTest production | \----------------------------------------------------------------*/ Production(NodeTest) if (LA==NODE) { Consume(NODE); Consume(LPAR); Consume(RPAR); a = New (IsNode); } else if (LA==TEXT) { Consume(TEXT); Consume(LPAR); Consume(RPAR); a = New (IsText); } else if (LA==COMMENT) { Consume(COMMENT); Consume(LPAR); Consume(RPAR); a = New (IsComment); } else if (LA==PINSTR) { Consume(PINSTR); Consume(LPAR); if (LA==LITERAL) { Consume(LITERAL); a = NewStr (IsSpecificPI, STRVAL); } else { a = New (IsPI); } Consume(RPAR); } else if (LA==MULTIPLY) { Consume(MULTIPLY); a = NewStr (IsElement, "*"); } else if (LA==NSPREFIX) { ast b; Consume (NSPREFIX); a = NewStr (IsFQElement, STRVAL); Consume (WCARDNAME); b = NewStr (IsElement, STRVAL); AddChild (a, b); } else if (LA==NSWC) { Consume (NSWC); a = NewStr (IsNSElement, STRVAL); } else { Consume(WCARDNAME); a = NewStr (IsElement, STRVAL); a->intvalue = INTVAL; } EndProduction /*----------------------------------------------------------------- | AbbreviatedBasis production | \----------------------------------------------------------------*/ Production(AbbreviatedBasis) if (LA==ATTRIBUTE) { Consume(ATTRIBUTE); a = New1( AxisAttribute, NewStr(IsAttr, STRVAL) ); } else if (LA==ATTRIBUTEPREFIX) { ast b, c; Consume(ATTRIBUTEPREFIX); a = New (AxisAttribute); b = NewStr (IsNSAttr, STRVAL); AddChild (a, b); Consume(ATTRIBUTE); c = NewStr (IsAttr, STRVAL); AddChild (b, c); } else { a = New1( AxisChild, Recurse(NodeTest)); } EndProduction /*----------------------------------------------------------------- | getFunctionTag | \----------------------------------------------------------------*/ static functionTag getFunctionTag (char *funcName) { switch (funcName[0]) { case 'b': if (strcmp (funcName, "boolean")==0) return f_boolean; break; case 'c': if (strcmp (funcName, "ceiling")==0) return f_ceiling; else if (strcmp (funcName, "concat")==0) return f_concat; else if (strcmp (funcName, "contains")==0) return f_contains; else if (strcmp (funcName, "count")==0) return f_count; break; case 'f': if (strcmp (funcName, "false")==0) return f_false; else if (strcmp (funcName, "floor")==0) return f_floor; break; case 'g': if (strcmp (funcName, "generate-id")==0) return f_generateId; break; case 'i': if (strcmp (funcName, "id")==0) return f_id; break; case 'l': if (strcmp (funcName, "lang")==0) return f_lang; else if (strcmp (funcName, "last")==0) return f_last; else if (strcmp (funcName, "laststring")==0) return f_laststring; else if (strcmp (funcName, "local-name")==0) return f_localName; break; case 'n': if (strcmp (funcName, "name")==0) return f_name; else if (strcmp (funcName, "namespace-uri")==0) return f_namespaceUri; else if (strcmp (funcName, "normalize-space")==0) return f_normalizeSpace; else if (strcmp (funcName, "not")==0) return f_not; else if (strcmp (funcName, "number")==0) return f_number; break; case 'p': if (strcmp (funcName, "position")==0) return f_position; break; case 'r': if (strcmp (funcName, "round")==0) return f_round; break; case 's': if (strcmp (funcName, "starts-with")==0) return f_startsWith; else if (strcmp (funcName, "string")==0) return f_string; else if (strcmp (funcName, "string-length")==0) return f_stringLength; else if (strcmp (funcName, "substring")==0) return f_substring; else if (strcmp (funcName, "substring-after")==0) return f_substringAfter; else if (strcmp (funcName, "substring-before")==0) return f_substringBefore; else if (strcmp (funcName, "sum")==0) return f_sum; break; case 't': if (strcmp (funcName, "translate")==0) return f_translate; else if (strcmp (funcName, "true")==0) return f_true; break; case 'u': if (strcmp (funcName, "unparsed-entity-uri")==0) return f_unparsedEntityUri; break; default: break; } return f_unknown; } /*----------------------------------------------------------------- | FilterExpr production | \----------------------------------------------------------------*/ Production(FilterExpr) if (LA==VARIABLE) { Consume(VARIABLE); a = NewStr( GetVar, STRVAL); } else if (LA==FQVARIABLE) { Consume(FQVARIABLE); a = NewStr( GetFQVar, STRVAL); Consume(VARIABLE); AddChild (a, NewStr( GetVar, STRVAL)); } else if (LA==LPAR) { Consume(LPAR); a = New1(EvalSteps, Recurse(OrExpr)); Consume(RPAR); } else if (LA==LITERAL) { Consume(LITERAL); a = NewStr( Literal, STRVAL); } else if (LA==INTNUMBER) { Consume(INTNUMBER); a = NewInt( INTVAL ); } else if (LA==REALNUMBER) { Consume(REALNUMBER); a = NewReal( REALVAL ); } else if (LA==FUNCTION || LA==NSPREFIX) { if (LA==FUNCTION) { Consume(FUNCTION); a = NewStr( ExecFunction, STRVAL); a->intvalue = getFunctionTag (STRVAL); } else { Consume(NSPREFIX); a = NewStr( ExecFunction, STRVAL); a->intvalue = f_fqfunction; Consume(FUNCTION); AddChild (a, NewStr( ExecFunction, STRVAL)); } Consume(LPAR); if (LA!=RPAR) { AddChildWithEvalSteps (a, Recurse(OrExpr)); while(LA==COMMA) { Consume(COMMA); AddChildWithEvalSteps (a, Recurse(OrExpr) ); } } Consume(RPAR); } else { ErrExpected("$var or (expr) or literal or number or func"); } while (LA==LBRACKET) { ast b; b = Recurse(Predicate); if (!b) return a; Append( a, New1WithEvalSteps( Pred, b)); } EndProduction /*----------------------------------------------------------------- | PathExpr production | \----------------------------------------------------------------*/ Production(PathExpr) if ( (LA==VARIABLE) ||(LA==FQVARIABLE) ||(LA==LPAR) ||(LA==LITERAL) ||(LA==INTNUMBER) ||(LA==REALNUMBER) ||(LA==FUNCTION) ||(LA==NSPREFIX && LA2==FUNCTION) ) { a = Recurse(FilterExpr); if (LA==SLASH) { Consume(SLASH); Append(a, Recurse(RelativeLocationPath)); } else if (LA==SLASHSLASH) { ast b; Consume(SLASHSLASH); b = Recurse(RelativeLocationPath); if (!b) return a; if (b->type == AxisChild) { b->type = AxisDescendant; } else { Append(a, New( AxisDescendantOrSelf ) ); } Append(a, b ); } } else { if ( (LA==SLASH) || (LA==SLASHSLASH)) { return Recurse(AbsoluteLocationPath); } else { return Recurse(RelativeLocationPath); } } EndProduction /*----------------------------------------------------------------- | UnionExpr production | \----------------------------------------------------------------*/ Production(UnionExpr) a = Recurse(PathExpr); while (LA==PIPE) { Consume(PIPE); a = New2( CombineSets, a, Recurse(PathExpr)); } EndProduction /*----------------------------------------------------------------- | UnaryExpr production | \----------------------------------------------------------------*/ Production(UnaryExpr) if (LA==MINUS) { Consume(MINUS); a = Recurse(UnionExpr); if (!a) { if (*errMsg == NULL) { ErrExpected("UnionExpr"); } return NULL; } if ((a->type == Int) && (a->next == NULL)) { a->intvalue = a->intvalue * -1; } else if ((a->type == Real) && (a->next == NULL)) { a->realvalue = a->realvalue * -1; } else { a = New1( UnaryMinus, a); } } else { a = Recurse(UnionExpr); } EndProduction /*----------------------------------------------------------------- | MultiplicativeExpr production | \----------------------------------------------------------------*/ Production(MultiplicativeExpr) a = Recurse(UnaryExpr); while ( (LA==MULTIPLY) ||(LA==DIV) ||(LA==MOD) ) { if (LA==MULTIPLY) { Consume(MULTIPLY); a = New2( Mult, a, Recurse(UnaryExpr)); } else if (LA==DIV) { Consume(DIV); a = New2( Div, a, Recurse(UnaryExpr)); } else { Consume(MOD); a = New2( Mod, a, Recurse(UnaryExpr)); } } EndProduction /*----------------------------------------------------------------- | AdditiveExpr production | \----------------------------------------------------------------*/ Production(AdditiveExpr) a = Recurse(MultiplicativeExpr); while ( (LA==PLUS) ||(LA==MINUS) ) { if (LA==PLUS) { Consume(PLUS); a = New2( Add, a, Recurse(MultiplicativeExpr)); } else { Consume(MINUS); a = New2( Subtract, a, Recurse(MultiplicativeExpr)); } } EndProduction /*----------------------------------------------------------------- | RelationalExpr production | \----------------------------------------------------------------*/ Production(RelationalExpr) a = Recurse(AdditiveExpr); while ( (LA==LT) ||(LA==LTE) ||(LA==GT) ||(LA==GTE) ) { if (LA==LT) { Consume(LT); a = New2( Less, a, Recurse(AdditiveExpr)); } else if (LA==LTE) { Consume(LTE); a = New2( LessOrEq, a, Recurse(AdditiveExpr)); } else if (LA==GT) { Consume(GT); a = New2( Greater, a, Recurse(AdditiveExpr)); } else { Consume(GTE); a = New2( GreaterOrEq, a, Recurse(AdditiveExpr)); } } EndProduction /*----------------------------------------------------------------- | EqualityExpr production | \----------------------------------------------------------------*/ Production(EqualityExpr) a = Recurse(RelationalExpr); while ( (LA==EQUAL) ||(LA==NOTEQ) ) { if (LA==EQUAL) { Consume(EQUAL); a = New2( Equal, a, Recurse(RelationalExpr)); } else { Consume(NOTEQ); a = New2( NotEqual, a, Recurse(RelationalExpr)); } } EndProduction /*----------------------------------------------------------------- | AndExpr production | \----------------------------------------------------------------*/ Production(AndExpr) a = Recurse(EqualityExpr); while (LA==AND) { Consume(AND); a = New2( And, a, Recurse(EqualityExpr)); } EndProduction /*----------------------------------------------------------------- | OrExpr production | \----------------------------------------------------------------*/ Production(OrExpr) a = Recurse(AndExpr); while (LA==OR) { Consume(OR); a = New2( Or, a, Recurse(AndExpr)); } EndProduction /*----------------------------------------------------------------- | Predicate production | \----------------------------------------------------------------*/ Production(Predicate) Consume(LBRACKET); a = Recurse(OrExpr); Consume(RBRACKET); EndProduction /*----------------------------------------------------------------- | Basis production | \----------------------------------------------------------------*/ Production(Basis) if (LA==AXISNAME) { astType t; Consume(AXISNAME); if (IS_STR('c',"child")) { t = AxisChild; } else if (IS_STR('d',"descendant")) { t = AxisDescendantLit; } else if (IS_STR('d',"descendant-or-self")) { t = AxisDescendantOrSelfLit; } else if (IS_STR('s',"self")) { t = AxisSelf; } else if (IS_STR('a',"attribute")) { t = AxisAttribute; } else if (IS_STR('a',"ancestor")) { t = AxisAncestor; } else if (IS_STR('a',"ancestor-or-self")) { t = AxisAncestorOrSelf; } else if (IS_STR('f',"following")) { t = AxisFollowing; } else if (IS_STR('f',"following-sibling")) { t = AxisFollowingSibling; } else if (IS_STR('n',"namespace")) { t = AxisNamespace; } else if (IS_STR('p',"parent")) { t = AxisParent; } else if (IS_STR('p',"preceding")) { t = AxisPreceding; } else if (IS_STR('p',"preceding-sibling")) { t = AxisPrecedingSibling; } else { ErrExpected("correct axis name"); } a = New( t ); Consume(COLONCOLON); AddChild( a, Recurse(NodeTest)); } else { a = Recurse(AbbreviatedBasis); } EndProduction /*----------------------------------------------------------------- | Step production | \----------------------------------------------------------------*/ static dom_minl IsStepPredOptimizable (ast a) { ast b; dom_minl left; /* Must be called with a != NULL */ DBG ( fprintf (stderr, "IsStepPredOptimizable:\n"); printAst (0,a); ) switch (a->type) { case Int: return a->intvalue; case Less: case LessOrEq: b = a->child; if (!b) return 0; if (b->type != ExecFunction || b->intvalue != f_position) return 0; b = b->next; if (!b) return 0; if (b->type != Int) return 0; if (a->type == Less) return b->intvalue; else return b->intvalue + 1; case Greater: case GreaterOrEq: b = a->child; if (!b) return 0; if (b->type != Int) return 0; left = b->intvalue; b = b->next; if (!b) return 0; if (b->type != ExecFunction || b->intvalue != f_position) return 0; if (a->type == Greater) return left; else return left + 1; case Equal: b = a->child; if (!b) return 0; if (b->type == Int && b->next && b->next->type == ExecFunction && b->next->intvalue == f_position) return b->intvalue; if (b->type == ExecFunction && b->intvalue == f_position && b->next && b->next->type == Int) return b->next->intvalue; return 0; default: return 0; } } Production(Step) if (LA==DOT) { Consume(DOT); a = New( GetContextNode ); /* a = New1( AxisSelf, New (IsNode)); */ } else if (LA==DOTDOT) { Consume(DOTDOT); a = New( GetParentNode ); /* a = New1( AxisParent, New (IsNode)); */ } else { ast b; int isFirst = 1; a = Recurse(Basis); if (LA==LBRACKET && !a) { if (*errMsg == NULL) { ErrExpected("Step"); } return NULL; } while (LA==LBRACKET) { b = Recurse (Predicate); if (!b) return a; if (isFirst) { a->intvalue = IsStepPredOptimizable (b); DBG (fprintf (stderr, "step type %s, intvalue: %d\n", astType2str[a->type], a->intvalue);) isFirst = 0; } Append( a, New1WithEvalSteps( Pred, b)); } } EndProduction /*----------------------------------------------------------------- | RelativeLocationPath production | \----------------------------------------------------------------*/ Production(RelativeLocationPath) a = Recurse(Step); if (!a) return NULL; while ((LA==SLASH) || (LA==SLASHSLASH)) { if (LA==SLASH) { Consume(SLASH); Append(a, Recurse(Step)); } else { ast b; Consume(SLASHSLASH); b = Recurse(Step); if (!b) return a; if (b->type == AxisChild) { b->type = AxisDescendant; } else { Append(a, New( AxisDescendantOrSelf ) ); } Append(a, b ); } } EndProduction /*----------------------------------------------------------------- | AbsoluteLocationPath production | \----------------------------------------------------------------*/ Production(AbsoluteLocationPath) if (LA==SLASH) { ast b; Consume(SLASH); a = New(SelectRoot); if ( (LA==AXISNAME) ||(LA==WCARDNAME) ||(LA==NSPREFIX) ||(LA==NSWC) ||(LA==NODE) ||(LA==TEXT) ||(LA==COMMENT) ||(LA==PINSTR) ||(LA==DOT) ||(LA==DOTDOT) ||(LA==ATTRIBUTE) ||(LA==ATTRIBUTEPREFIX) ) { b = Recurse(RelativeLocationPath); Append(a, b); } } else if (LA==SLASHSLASH) { ast b; Consume(SLASHSLASH); a = New(SelectRoot); b = Recurse(RelativeLocationPath); if (!b) { freeAst (a); return NULL; } if (b->type == AxisChild) { b->type = AxisDescendant; } else { Append(a, New( AxisDescendantOrSelf ) ); } Append(a, b ); } else { ErrExpected("/ or //"); } EndProduction /*----------------------------------------------------------------- | XSLT StepPattern production | \----------------------------------------------------------------*/ static int usesPositionInformation ( ast a) { while (a) { if (a->type == ExecFunction && (a->intvalue == f_position || a->intvalue == f_last || a->intvalue == f_laststring || a->intvalue == f_unknown)) { return 1; } if (a->child) { if (usesPositionInformation (a->child)) return 1; } a = a->next; } return 0; } /* Must be called with a != NULL */ static int checkStepPatternPredOptimizability ( ast a , dom_minl *max) { ast b; switch (a->type) { case Literal: case AxisAncestor: case AxisAncestorOrSelf: case AxisChild: case AxisAttribute: case AxisDescendant: case AxisDescendantLit: case AxisDescendantOrSelf: case AxisDescendantOrSelfLit: case AxisFollowing: case AxisFollowingSibling: case AxisNamespace: case AxisParent: case AxisPreceding: case AxisPrecedingSibling: case AxisSelf: case IsNode: case IsComment: case IsText: case IsPI: case IsSpecificPI: case IsElement: case GetContextNode: case GetParentNode: break; case And: case Or: if (usesPositionInformation(a->child)) return 0; return 1; case Less: case LessOrEq: b = a->child; if (b && b->type == ExecFunction && b->intvalue == f_position && b->next && b->next->type == Int) { if (a->type == Less) *max = b->next->intvalue; else *max = b->next->intvalue + 1; return 0; } if (usesPositionInformation(a->child)) return 0; return 1; case Greater: case GreaterOrEq: b = a->child; if (b && b->type == Int && b->next && b->next->type == ExecFunction && b->next->intvalue == f_position) { if (a->type == Greater) *max = b->intvalue; else *max = b->intvalue + 1; return 0; } if (usesPositionInformation(a->child)) return 0; return 1; case Equal: b = a->child; if (b && b->type == Int && b->next && b->next->type == ExecFunction && b->next->intvalue == f_position) { *max = b->intvalue; return 0; } if (b && b->type == ExecFunction && b->intvalue == f_position && b->next && b->next->type == Int) { *max = b->next->intvalue; return 0; } if (usesPositionInformation(a->child)) return 0; return 1; case NotEqual: if (usesPositionInformation(a->child)) return 0; return 1; case Int: *max = a->intvalue; return 0; case ExecFunction: return !usesPositionInformation(a); default: return 0; } return 1; } /* Must be called with a != NULL */ static long IsStepPatternPredOptimizable ( ast a, dom_minl *max ) { long f; *max = 0; f = checkStepPatternPredOptimizability(a, max); DBG( if (f) { fprintf(stderr, "\nStepPattern Pred is optimizable:\n"); } else { fprintf(stderr, "\nStepPattern Pred is not optimizable, max = %d:\n", *max); } printAst(0,a); ) return f; } /*----------------------------------------------------------------- | XSLT StepPattern production | \----------------------------------------------------------------*/ Production(StepPattern) if (LA==AXISNAME) { astType t; Consume(AXISNAME); if (IS_STR('c',"child")) { t = AxisChild; } else if (IS_STR('a',"attribute")) { t = AxisAttribute; } else { ErrExpected("correct axis name (child/attribute)"); } Consume(COLONCOLON); a = New1( t, Recurse(NodeTest)); } else if (LA==ATTRIBUTE) { Consume(ATTRIBUTE); a = New1( AxisAttribute, NewStr(IsAttr, STRVAL) ); } else if (LA==ATTRIBUTEPREFIX) { ast b, c; Consume(ATTRIBUTEPREFIX); a = New ( AxisAttribute); b = NewStr (IsNSAttr, STRVAL); AddChild (a, b); Consume(ATTRIBUTE); c = NewStr (IsAttr, STRVAL); AddChild (b, c); } else { a = Recurse(NodeTest); } if (!a) { if (*errMsg == NULL) { ErrExpected("StepPattern") }; return NULL; } { ast b = NULL, c = NULL, aCopy = NULL; int stepIsOptimizable = 1, isFirst = 1; dom_minl max, savedmax = 0; while (LA==LBRACKET) { b = Recurse (Predicate); if (!b) return a; if (stepIsOptimizable) { if (!IsStepPatternPredOptimizable(b, &max)) stepIsOptimizable = 0; } if (isFirst) { savedmax = max; c = New1WithEvalSteps( Pred, b); isFirst = 0; } else { Append (c, New1WithEvalSteps( Pred, b)); } } if (!isFirst) { if (stepIsOptimizable) { Append (a, New (FillWithCurrentNode)); } else { /* copy the step before the Predicate */ aCopy = NEWCONS; aCopy->type = a->type; aCopy->next = NULL; if (a->strvalue) aCopy->strvalue = tdomstrdup(a->strvalue); else aCopy->strvalue = NULL; aCopy->intvalue = a->intvalue; aCopy->realvalue = a->realvalue; aCopy->child = NULL; if (a->child) { ast aCopyChild = NEWCONS; aCopyChild->type = a->child->type; aCopyChild->next = NULL; aCopyChild->child = NULL; if (a->child->strvalue) { aCopyChild->strvalue = tdomstrdup(a->child->strvalue); } else { aCopyChild->strvalue = NULL; } aCopyChild->intvalue = a->child->intvalue; aCopyChild->realvalue = a->child->realvalue; aCopy->child = aCopyChild; } b = New1( FillNodeList, aCopy); b->intvalue = savedmax; Append( a, b); } Append (a, c); } } EndProduction /*----------------------------------------------------------------- | XSLT RelativePathPattern production | \----------------------------------------------------------------*/ Production(RelativePathPattern) a = Recurse(StepPattern); while ((LA==SLASH) || (LA==SLASHSLASH)) { ast b; if (LA==SLASH) { Consume(SLASH); b = Recurse(StepPattern); if (b) { Append(b, New(ToParent) ); Append(b, a); a = b; } } else { Consume(SLASHSLASH); b = Recurse(StepPattern); if (b) { Append(b, New(ToAncestors) ); Append(b, a); a = b; } } } EndProduction /*----------------------------------------------------------------- | XSLT IdKeyPattern production | \----------------------------------------------------------------*/ Production(IdKeyPattern) Consume(FUNCTION); if (strcmp(STRVAL, "id" )==0) { ast b; /* id */ a = NewStr( ExecIdKey, STRVAL); a->intvalue = f_id; Consume(LPAR); Consume(LITERAL); b = NewStr( Literal, STRVAL); AddChild (a, b); Consume(RPAR); } else { ast b; /* key */ a = NewStr( ExecIdKey, STRVAL); Consume(LPAR); Consume(LITERAL); b = NewStr( Literal, STRVAL); AddChild (a, b); Consume(COMMA); Consume(LITERAL); b = NewStr( Literal, STRVAL); AddChild (a, b); Consume(RPAR); } EndProduction /*----------------------------------------------------------------- | XSLT LocationPathPattern production | \----------------------------------------------------------------*/ Production(LocationPathPattern) if (LA==SLASH) { Consume(SLASH); if (LA==EOS || LA==PIPE) { a = New(IsRoot); } else { a = Recurse(RelativePathPattern); if (a) { Append( a, New(ToParent) ); Append( a, New(IsRoot) ); } } } else if ((LA==FUNCTION) && ( (strcmp(tokens[*l].strvalue, "id" )==0) ||(strcmp(tokens[*l].strvalue, "key")==0) ) ) { ast b; b = Recurse(IdKeyPattern); if (LA==SLASH) { Consume(SLASH); a = Recurse(RelativePathPattern); if (a) { Append( a, New(ToParent) ); } } else if (LA==SLASHSLASH) { Consume(SLASHSLASH); a = Recurse(RelativePathPattern); if (a) { Append( a, New(ToAncestors) ); } } if (!a) { a = b; } else { Append( a, b); } } else { if (LA==SLASHSLASH) { Consume(SLASHSLASH); a = Recurse(RelativePathPattern); if (a) { Append( a, New(ToAncestors) ); Append( a, New(IsRoot) ); } } else { a = Recurse(RelativePathPattern); } } EndProduction /*----------------------------------------------------------------- | XSLT Pattern production | \----------------------------------------------------------------*/ Production(Pattern) a = Recurse(LocationPathPattern); while (LA==PIPE) { Consume(PIPE); a = New2( CombinePath, New1(EvalSteps, a), New1(EvalSteps, Recurse(LocationPathPattern) ) ); } EndProduction /*---------------------------------------------------------------------------- | xpathFreeTokens | \---------------------------------------------------------------------------*/ static int xpathFreeTokens ( XPathTokens tokens ) { int i; for (i=0; tokens[i].token != EOS; i++) { if (tokens[i].strvalue) { FREE(tokens[i].strvalue); } } FREE((char*)tokens); return 0; } /*---------------------------------------------------------------------------- | xpathParsePostProcess | \---------------------------------------------------------------------------*/ static int xpathParsePostProcess ( ast t, xpathExprType type, domNode *exprContext, char **prefixMappings, char **errMsg ) { DBG( fprintf(stderr, "xpathParsePostProcess start:\n"); printAst (0, t); ) while (t) { DBG(printAst (4, t);) if (type != XPATH_EXPR) { if (type != XPATH_KEY_USE_EXPR) { /* 12.4: "It is an error to use the current function in a pattern." */ if (t->type == ExecFunction && t->intvalue == f_unknown && (strcmp (t->strvalue, "current")==0)) { *errMsg = tdomstrdup( "The 'current' function is not allowed in Pattern." ); return 0; } } if (type == XPATH_KEY_MATCH_PATTERN || type == XPATH_KEY_USE_EXPR) { /* 12.2: "It is an error for the value of either the use attribute or the match attribute to contain a VariableReference, or a call to the key function." */ if (t->type == ExecFunction && t->intvalue == f_unknown && (strcmp (t->strvalue, "key")==0)) { *errMsg = tdomstrdup("The 'key' function is not allowed " "in the use and match attribute " "pattern of xsl:key."); return 0; } if (t->type == GetVar || t->type == GetFQVar) { *errMsg = tdomstrdup("Variable references are not allowed " "in the use and match attribute of " "xsl:key."); return 0; } } if (type == XPATH_TEMPMATCH_PATTERN) { /* 5.3: "It is an error for the value of the match attribute to contain a VariableReference." */ if (t->type == GetVar || t->type == GetFQVar) { *errMsg = tdomstrdup("Variable references are not allowed " "in the match attribute of " "xsl:template." ); return 0; } } } if (t->child) { if (!xpathParsePostProcess (t->child, type, exprContext, prefixMappings, errMsg)) return 0; } t = t->next; } return 1; } /*---------------------------------------------------------------------------- | xpathParse | \---------------------------------------------------------------------------*/ int xpathParse ( char *xpath, domNode *exprContext, xpathExprType type, char **prefixMappings, xpathParseVarCB *varParseCB, ast *t, char **errMsg ) { XPathTokens tokens; int i, l; size_t len, newlen, slen; int useNamespaceAxis = 0; char tmp[200]; DDBG(fprintf(stderr, "\nLex output following tokens for '%s':\n", xpath);) *errMsg = NULL; tokens = xpathLexer(xpath, exprContext, prefixMappings, &useNamespaceAxis, varParseCB, errMsg); if (*errMsg != NULL) { if (tokens != NULL) xpathFreeTokens (tokens); return XPATH_LEX_ERR; } DDBG( for (i=0; tokens[i].token != EOS; i++) { fprintf(stderr, "%3d %-12s %5ld %8.3g %5ld %s\n", i, token2str[tokens[i].token-LPAR], tokens[i].intvalue, tokens[i].realvalue, tokens[i].pos, tokens[i].strvalue ); } ) l = 0; *t = NULL; if (type == XPATH_EXPR || type == XPATH_KEY_USE_EXPR) { *t = OrExpr (&l, tokens, errMsg); } else { *t = Pattern (&l, tokens, errMsg); } if ((*errMsg == NULL) && (tokens[l].token != EOS)) { *errMsg = tdomstrdup("Unexpected tokens (beyond end)!"); } if (*errMsg == NULL && ((type != XPATH_EXPR) || useNamespaceAxis)) { xpathParsePostProcess (*t, type, exprContext, prefixMappings, errMsg); } if (*errMsg) { len = strlen(*errMsg); newlen = strlen(xpath); *errMsg = (char*)REALLOC(*errMsg, len+newlen+10); memmove(*errMsg + len, " for '", 6); memmove(*errMsg + len+6, xpath, newlen); memmove(*errMsg + len+6+newlen, "' ", 3); for (i=0; tokens[i].token != EOS; i++) { #if TCL_MAJOR_VERSION > 8 sprintf(tmp, "%s\n%3s%3d %-12s %5" TCL_SIZE_MODIFIER "d %09.3g %5" TCL_SIZE_MODIFIER "d ", #else sprintf(tmp, "%s\n%3s%3d %-12s %5ld %09.3g %5d ", #endif (i==0) ? "\n\nParsed symbols:" : "", (i==l) ? "-->" : " ", i, token2str[tokens[i].token-LPAR], tokens[i].intvalue, tokens[i].realvalue, tokens[i].pos ); len = strlen(*errMsg); newlen = strlen(tmp); slen = 0; if (tokens[i].strvalue) { slen = strlen(tokens[i].strvalue); } *errMsg = (char*)REALLOC(*errMsg, len+newlen+slen+1); memmove(*errMsg + len, tmp, newlen); memmove(*errMsg + len + newlen, tokens[i].strvalue, slen); (*errMsg)[len + newlen + slen] = '\0'; } } DBG( if (type) { fprintf(stderr, "\nPattern AST for '%s': \n", xpath); printAst (0, *t); } else { fprintf(stderr, "AST (xpathParse):\n"); printAst (0, *t); } ) xpathFreeTokens (tokens); if (*errMsg!=NULL) { if (*t) freeAst (*t); return XPATH_SYNTAX_ERR; } return 0; } /* xpathParse */ /*---------------------------------------------------------------------------- | xpathNodeTest | \---------------------------------------------------------------------------*/ int xpathNodeTest ( domNode *node, ast step ) { const char *localName, *nodeUri; if (!(step->child)) return 1; if (step->child->type == IsElement) { if (node->nodeType == ELEMENT_NODE) { if ((step->child->strvalue[0] == '*') && (step->child->strvalue[1] == '\0') && (node->ownerDocument->rootNode != node) && (step->child->intvalue == 0)) return 1; if (node->namespace && (node->ownerDocument->namespaces[node->namespace-1]->prefix[0] != '\0' || node->ownerDocument->namespaces[node->namespace-1]->uri[0] != '\0') ) return 0; return (strcmp(node->nodeName, step->child->strvalue)==0); } return 0; } else if (step->child->type == IsAttr) { if (node->nodeType == ATTRIBUTE_NODE) { if (node->nodeFlags & IS_NS_NODE) return 0; if ( (step->child->strvalue[0] == '*') &&(step->child->strvalue[1] == '\0') ) { return 1; } return (strcmp( ((domAttrNode*)node)->nodeName, step->child->strvalue)==0); } return 0; } else if (step->child->type == IsFQElement) { if (node->nodeType != ELEMENT_NODE || node->namespace == 0) return 0; nodeUri = domNamespaceURI (node); if (!nodeUri) return 0; if (strcmp (step->child->strvalue, nodeUri) != 0) return 0; localName = domGetLocalName (node->nodeName); if (strcmp (step->child->child->strvalue, localName)==0) return 1; return 0; } else if (step->child->type == IsNSElement) { nodeUri = domNamespaceURI (node); if (!nodeUri) return 0; if (nodeUri && (strcmp (step->child->strvalue, nodeUri)==0)) return 1; return 0; } else if (step->child->type == IsNSAttr) { if (node->nodeType != ATTRIBUTE_NODE || node->nodeFlags & IS_NS_NODE) return 0; nodeUri = domNamespaceURI (node); if (!nodeUri) return 0; if (strcmp (step->child->strvalue, nodeUri) != 0) return 0; if (strcmp (step->child->child->strvalue, "*")==0) return 1; localName = domGetLocalName (((domAttrNode *) node)->nodeName); if (strcmp (step->child->child->strvalue, localName)==0) return 1; return 0; } else if (step->child->type == IsNode) { DBG(fprintf(stderr, "nodeTest: nodeType=%d \n", node->nodeType);) return 1; } else if (step->child->type == IsText) { DBG(fprintf(stderr, "nodeTest: nodeType=%d == %d?? \n", node->nodeType, TEXT_NODE);) return (node->nodeType == TEXT_NODE); } else if (step->child->type == IsPI) { return (node->nodeType == PROCESSING_INSTRUCTION_NODE); } else if (step->child->type == IsSpecificPI) { return (node->nodeType == PROCESSING_INSTRUCTION_NODE && strncmp (((domProcessingInstructionNode*)node)->targetValue, step->child->strvalue, ((domProcessingInstructionNode*)node)->targetLength) == 0); } else if (step->child->type == IsComment) { return (node->nodeType == COMMENT_NODE); } return 1; } /*---------------------------------------------------------------------------- | xpathFuncBoolean | \---------------------------------------------------------------------------*/ int xpathFuncBoolean ( xpathResultSet *rs ) { switch (rs->type) { case BoolResult: return ( rs->intvalue ? 1 : 0 ); case IntResult: return ( rs->intvalue ? 1 : 0 ); case RealResult: return ((rs->realvalue != 0.0 ) && !IS_NAN (rs->realvalue)); case StringResult: return ( rs->string_len > 0 ); case xNodeSetResult: return ( rs->nr_nodes > 0 ); case InfResult: case NInfResult: return 1; /* NaNResult and EmptyResult are 'false' */ default: return 0; } } static double xpathStringToNumber ( char *str, int *NaN ) { int dotseen = 0; double d; char *pc, *tailptr; /* Just to use strtod() isn't sufficient for a few reasons: - strtod() accepts a leading - or +, but XPath allows only a leading - - strtod() accepts the string representation of a hexadecimal number, but XPath does not - strtod() accepts an optional exponent but XPath does not - strtod() accepts leading whitespace including \f and \v, but XPath doesn't allow this characters. Since this two characters are not legal XML characters, they can not be part of a DOM tree and therefore there isn't a problem with XPath expressions on DOM trees or in XSLT. But on Tcl level it's possible, to feed that characters literal into the XPath engine. */ *NaN = 0; pc = str; while (*pc && IS_XML_WHITESPACE(*pc)) pc++; if (!*pc) goto returnNaN; if (*pc == '-') { pc++; if (!*pc) goto returnNaN; } else if (*pc == '.') { dotseen = 1; pc++; if (!*pc) goto returnNaN; } if (!isdigit((unsigned char)*pc)) goto returnNaN; while (*pc) { if (isdigit((unsigned char)*pc)) { pc++; continue; } if (*pc == '.' && !dotseen) { dotseen = 1; pc++; continue; } break; } while (*pc && IS_XML_WHITESPACE(*pc)) pc++; if (*pc) goto returnNaN; /* If we are here str is a number string, as XPath expects it. Now we just use strtod(), to get the number */ d = strtod (str, &tailptr); if (d == 0.0 && tailptr == str) goto returnNaN; else if (IS_NAN(d)) goto returnNaN; return d; returnNaN: *NaN = 2; return strtod ("nan", &tailptr); } /*---------------------------------------------------------------------------- | xpathFuncNumber | \---------------------------------------------------------------------------*/ double xpathFuncNumber ( xpathResultSet *rs, int *NaN ) { double d; char *pc, *tailptr; *NaN = 0; switch (rs->type) { case BoolResult: return (rs->intvalue? 1.0 : 0.0); case IntResult: return (double)rs->intvalue; case RealResult: if (IS_NAN(rs->realvalue)) *NaN = 2; else if (IS_INF(rs->realvalue)!=0) *NaN = IS_INF(rs->realvalue); return rs->realvalue; case NaNResult: *NaN = 2; return 0.0; case InfResult: *NaN = 1; #ifdef INFINITY return INFINITY; #else # ifdef DBL_MAX return DBL_MAX; # else /* well, what? */ return 0.0 # endif #endif case NInfResult: *NaN = -1; #ifdef INFINITY return -INFINITY; #else # ifdef DBL_MAX return -DBL_MAX; # else /* well, what? */ return 0.0 # endif #endif case StringResult: return xpathStringToNumber(rs->string, NaN); case xNodeSetResult: pc = xpathFuncString(rs); d = xpathStringToNumber(pc, NaN); FREE(pc); return d; default: DBG(fprintf(stderr, "funcNumber: default: 0.0\n");) d = strtod ("nan", &tailptr); *NaN = 2; return d; } } /*---------------------------------------------------------------------------- | xpathGetStringValue | \---------------------------------------------------------------------------*/ static char * xpathGetStringValueForElement ( domNode *node, domLength *len ) { char *pc, *t; domLength l; domNode *child; if (node->nodeType == ELEMENT_NODE) { DBG(fprintf(stderr,"GetTextValue: tag='%s' \n", node->nodeName);) pc = MALLOC(1); *pc = '\0'; *len = 0; child = node->firstChild; while (child) { t = xpathGetStringValueForElement(child, &l); pc = (char*)REALLOC(pc, 1 + *len + l); memmove(pc + *len, t, l ); *len += l; pc[*len] = '\0'; FREE((char*)t); child = child->nextSibling; } } else if (node->nodeType == TEXT_NODE) { *len = ((domTextNode*)node)->valueLength; pc = (char*)MALLOC(1+*len); memmove(pc, ((domTextNode*)node)->nodeValue, *len); pc[*len] = '\0'; DBG(fprintf(stderr,"GetTextValue: text='%s' \n", pc);) } else { pc = tdomstrdup (""); *len = 0; } return pc; } char * xpathGetStringValue ( domNode *node, domLength *len ) { char *pc, *t; domLength l; domNode *child; domAttrNode *attr; if (node->nodeType == ELEMENT_NODE) { DBG(fprintf(stderr,"GetTextValue: tag='%s' \n", node->nodeName);) pc = MALLOC(1); *pc = '\0'; *len = 0; child = node->firstChild; while (child) { t = xpathGetStringValueForElement(child, &l); pc = (char*)REALLOC(pc, 1 + *len + l); memmove(pc + *len, t, l ); *len += l; pc[*len] = '\0'; FREE((char*)t); child = child->nextSibling; } } else if ((node->nodeType == TEXT_NODE) || (node->nodeType == CDATA_SECTION_NODE) || (node->nodeType == COMMENT_NODE) ) { *len = ((domTextNode*)node)->valueLength; pc = (char*)MALLOC(1+*len); memmove(pc, ((domTextNode*)node)->nodeValue, *len); pc[*len] = '\0'; DBG(fprintf(stderr,"GetTextValue: text='%s' \n", pc);) } else if (node->nodeType == PROCESSING_INSTRUCTION_NODE) { *len = ((domProcessingInstructionNode*)node)->dataLength; pc = (char*)MALLOC(1+*len); memmove(pc, ((domProcessingInstructionNode*)node)->dataValue, *len); pc[*len] = '\0'; } else if (node->nodeType == ATTRIBUTE_NODE) { attr = (domAttrNode*)node; DBG(fprintf(stderr,"GetTextValue: attr='%s' \n", attr->nodeName);) pc = MALLOC(attr->valueLength +1); memmove(pc, attr->nodeValue, attr->valueLength); *(pc + attr->valueLength) = '\0'; *len = attr->valueLength; } else { pc = tdomstrdup (""); *len = 0; } return pc; } /*---------------------------------------------------------------------------- | xpathFuncString | \---------------------------------------------------------------------------*/ char * xpathFuncString ( xpathResultSet *rs ) { char tmp[80], *pc; domLength len; switch (rs->type) { case BoolResult: if (rs->intvalue) return (tdomstrdup("true")); else return (tdomstrdup("false")); case IntResult: #if TCL_MAJOR_VERSION > 8 sprintf(tmp, "%" TCL_SIZE_MODIFIER "d", rs->intvalue); #else sprintf(tmp, "%ld", rs->intvalue); #endif return (tdomstrdup(tmp)); case RealResult: if (IS_NAN (rs->realvalue)) return tdomstrdup ("NaN"); else if (IS_INF (rs->realvalue)) { if (IS_INF (rs->realvalue) == 1) return tdomstrdup ("Infinity"); else return tdomstrdup ("-Infinity"); } sprintf(tmp, "%g", rs->realvalue); /* strip trailing 0 and . */ len = (domLength)strlen(tmp); for (; (len > 0) && (tmp[len-1] == '0'); len--) tmp[len-1] = '\0'; if ((len > 0) && (tmp[len-1] == '.')) tmp[len-1] = '\0'; return (tdomstrdup(tmp)); case NaNResult: return tdomstrdup ("NaN"); case InfResult: return tdomstrdup ("Infinity"); case NInfResult: return tdomstrdup ("-Infinity"); case StringResult: pc = MALLOC(rs->string_len +1); memmove(pc, rs->string, rs->string_len); *(pc + rs->string_len) = '\0'; return pc; case xNodeSetResult: if (rs->nr_nodes == 0) { pc = tdomstrdup (""); } else { pc = xpathGetStringValue (rs->nodes[0], &len); } return pc; default: return (tdomstrdup ("")); } } /*---------------------------------------------------------------------------- | xpathFuncStringForNode | \---------------------------------------------------------------------------*/ char * xpathFuncStringForNode ( domNode *node ) { domLength len; return xpathGetStringValue (node, &len); } /*---------------------------------------------------------------------------- | xpathArity | \---------------------------------------------------------------------------*/ static int xpathArity ( ast step ) { int parms = 0; step = step->child; while (step) { parms++; step = step->next; } return parms; } /*---------------------------------------------------------------------------- | xpathArityCheck | \---------------------------------------------------------------------------*/ static int xpathArityCheck ( ast step, int arity, char **errMsg ) { int parms = 0; step = step->child; while (step) { parms++; step = step->next; } if (arity!=parms) { *errMsg = tdomstrdup("wrong number of parameters!"); return 1; } return 0; } #define XPATH_ARITYCHECK(s,a,m) if (xpathArityCheck(s,a,m)) return XPATH_EVAL_ERR /*---------------------------------------------------------------------------- | xpathRound | \---------------------------------------------------------------------------*/ domLength xpathRound (double r) { if (r < 0.0) { return (domLength)floor (r + 0.5); } else { return (domLength)(r + 0.5); } } /*---------------------------------------------------------------------------- | idSplitAndAdd | \---------------------------------------------------------------------------*/ static void idSplitAndAdd ( char *idStr, Tcl_HashTable *ids, xpathResultSet *result ) { int pwhite; char *pfrom, *pto; Tcl_HashEntry *entryPtr; domNode *node; pwhite = 0; pfrom = pto = idStr; while (*pto) { switch (*pto) { case ' ' : case '\n': case '\r': case '\t': if (pwhite) { pto++; continue; } *pto = '\0'; entryPtr = Tcl_FindHashEntry (ids, pfrom); if (entryPtr) { node = (domNode*) Tcl_GetHashValue (entryPtr); /* Don't report nodes out of the fragment list */ if (node->parentNode != NULL || (node == node->ownerDocument->documentElement)) { rsAddNode (result, node); } } pwhite = 1; pto++; continue; default: if (pwhite) { pfrom = pto; pwhite = 0; } pto++; } } if (!pwhite) { entryPtr = Tcl_FindHashEntry (ids, pfrom); if (entryPtr) { node = (domNode*) Tcl_GetHashValue (entryPtr); /* Don't report nodes out of the fragment list */ if (node->parentNode != NULL || (node == node->ownerDocument->documentElement)) { rsAddNode (result, node); } } } } /*---------------------------------------------------------------------------- | xpathEvalFunction | \---------------------------------------------------------------------------*/ static int xpathEvalFunction ( ast step, domNode *ctxNode, domNode *exprContext, domLength position, xpathResultSet *nodeList, xpathCBs *cbs, xpathResultSet *result, int *docOrder, char **errMsg ) { xpathResultSet leftResult, rightResult, replaceResult; int rc, pwhite, NaN, attrcount, argc, savedDocOrder, found, utfCharLen, untilEnd, left = 0; domLength len, lenstr, fromlen, i, j, from; char *replaceStr, *pfrom, *pto, tmp[80], tmp1[80], *leftStr = NULL, *rightStr = NULL, utfBuf[TCL_UTF_MAX]; domNode *node; domAttrNode *attr; double leftReal, dRight = 0.0; ast nextStep; xpathResultSets *args; xpathResultSet *arg; Tcl_HashTable *ids; Tcl_HashEntry *entryPtr; const char *str; Tcl_DString dStr, tstr, tfrom, tto, tresult; Tcl_UniChar *ufStr, *upfrom, unichar; switch (step->intvalue) { case f_position: XPATH_ARITYCHECK(step,0,errMsg); if (*docOrder) { rsSetLong (result, position+1); } else { rsSetLong (result, nodeList->nr_nodes - position); } break; case f_last: XPATH_ARITYCHECK(step,0,errMsg); rsSetLong (result, nodeList->nr_nodes); break; case f_number: xpathRSInit (&leftResult); if (xpathArity(step) == 0) { /* no parameter, the context node is the nodeset to * operate with */ rsAddNodeFast( &leftResult, ctxNode); } else { XPATH_ARITYCHECK(step,1,errMsg); xpathRSInit (&leftResult); rc = xpathEvalStep( step->child, ctxNode, exprContext, position, nodeList, cbs, &leftResult, docOrder, errMsg); if (rc) { xpathRSFree( &leftResult ); return rc; } } leftReal = xpathFuncNumber(&leftResult, &NaN); if (NaN) { if (NaN == 2) rsSetNaN (result); else if (NaN == 1) rsSetInf (result); else rsSetNInf (result); } else { rsSetReal (result, leftReal); } xpathRSFree( &leftResult ); break; case f_floor: case f_ceiling: case f_round: XPATH_ARITYCHECK(step,1,errMsg); xpathRSInit (&leftResult); rc = xpathEvalStep( step->child, ctxNode, exprContext, position, nodeList, cbs, &leftResult, docOrder, errMsg); if (rc) { xpathRSFree( &leftResult ); return rc; } leftReal = xpathFuncNumber(&leftResult, &NaN); if (NaN) { if (NaN == 2) rsSetNaN (result); else if (NaN == 1) rsSetInf (result); else rsSetNInf (result); } else { if (step->intvalue == f_floor) leftReal = floor(leftReal); else if (step->intvalue == f_ceiling) leftReal = ceil(leftReal); else leftReal = (double)xpathRound(leftReal); rsSetReal2 (result, leftReal); } xpathRSFree( &leftResult ); break; case f_boolean: XPATH_ARITYCHECK(step,1,errMsg); xpathRSInit (&leftResult); rc = xpathEvalStep( step->child, ctxNode, exprContext, position, nodeList, cbs, &leftResult, docOrder, errMsg); if (rc) { xpathRSFree( &leftResult ); return rc; } left = xpathFuncBoolean(&leftResult); rsSetBool (result, left); xpathRSFree( &leftResult ); break; case f_string: case f_normalizeSpace: case f_stringLength: case f_laststring: xpathRSInit (&leftResult); if (step->child == NULL) { /* no parameter, the context node is the nodeset to * operate with */ rsAddNodeFast( &leftResult, ctxNode); } else { XPATH_ARITYCHECK(step,1,errMsg); xpathRSInit (&leftResult); rc = xpathEvalStep( step->child, ctxNode, exprContext, position, nodeList, cbs, &leftResult, docOrder, errMsg); if (rc) { xpathRSFree( &leftResult ); return rc; } DBG(fprintf(stderr, "normalize-space: \n"); rsPrint(&leftResult); ) } if (step->intvalue == f_laststring) { if (leftResult.type == xNodeSetResult) { if (leftResult.nr_nodes == 0) { leftStr = tdomstrdup (""); } else { leftStr = xpathGetStringValue ( leftResult.nodes[leftResult.nr_nodes-1], &len); } } else { leftStr = xpathFuncString (&leftResult ); } } else { leftStr = xpathFuncString (&leftResult ); } xpathRSFree( &leftResult ); DBG(fprintf(stderr, "leftStr='%s'\n", leftStr);) if (step->intvalue == f_string) rsSetString (result, leftStr); else if (step->intvalue == f_stringLength) { pto = leftStr; len = 0; while (*pto) { len++; i = UTF8_CHAR_LEN (*pto); if (!i) { FREE (leftStr); *errMsg = tdomstrdup("Can only handle UTF-8 chars up " "to 4 bytes length"); return XPATH_I18N_ERR; } pto += i; } rsSetLong (result, len); } else { pwhite = 1; pfrom = pto = leftStr; while (*pfrom) { switch (*pfrom) { case ' ' : case '\n': case '\r': case '\t': if (!pwhite) { *pto++ = ' '; pwhite = 1; } break; default: *pto++ = *pfrom; pwhite = 0; break; } pfrom++; } if ((pto > leftStr) && (*(pto-1) == ' ')) { pto--; /* cut last empty space */ } *pto = '\0'; rsSetString (result, leftStr); } FREE(leftStr); break; case f_not: XPATH_ARITYCHECK(step,1,errMsg); xpathRSInit (&leftResult); rc = xpathEvalStep( step->child, ctxNode, exprContext, position, nodeList, cbs, &leftResult, docOrder, errMsg); if (rc) { xpathRSFree (&leftResult); return rc; } left = xpathFuncBoolean(&leftResult); xpathRSFree (&leftResult); rsSetBool (result, !left); break; case f_true: XPATH_ARITYCHECK(step,0,errMsg); rsSetBool (result, 1); break; case f_false: XPATH_ARITYCHECK(step,0,errMsg); rsSetBool (result, 0); break; case f_id: XPATH_ARITYCHECK(step,1,errMsg); if (ctxNode->nodeType == ATTRIBUTE_NODE) { ids = ((domAttrNode*)ctxNode)->parentNode->ownerDocument->ids; } else { ids = ctxNode->ownerDocument->ids; } if (!ids) { break; } xpathRSInit (&leftResult); rc = xpathEvalStep( step->child, ctxNode, exprContext, position, nodeList, cbs, &leftResult, docOrder, errMsg); if (rc) { xpathRSFree( &leftResult ); return rc; } DBG(fprintf(stderr, "id: \n"); rsPrint(&leftResult); ) if (leftResult.type == EmptyResult) { xpathRSFree (&leftResult); return XPATH_OK; } if (leftResult.type == xNodeSetResult) { for (i=0; i < leftResult.nr_nodes; i++) { leftStr = xpathFuncStringForNode (leftResult.nodes[i]); idSplitAndAdd (leftStr, ids, result); FREE(leftStr); } } else { leftStr = xpathFuncString (&leftResult); idSplitAndAdd (leftStr, ids, result); FREE(leftStr); } sortByDocOrder (result); xpathRSFree (&leftResult); break; case f_sum: XPATH_ARITYCHECK(step,1,errMsg); xpathRSInit (&leftResult); rc = xpathEvalStep( step->child, ctxNode, exprContext, position, nodeList, cbs, &leftResult, docOrder, errMsg); if (rc) { xpathRSFree( &leftResult ); return rc; } if (leftResult.type != xNodeSetResult) { if (leftResult.type == EmptyResult) { rsSetLong (result, 0); return XPATH_OK; } else { xpathRSFree( &leftResult ); *errMsg = tdomstrdup("sum() requires a node set!"); xpathRSFree( &leftResult ); return XPATH_EVAL_ERR; } } xpathRSInit(&rightResult); rightResult.nr_nodes = 1; rightResult.type = leftResult.type; leftReal = 0.0; for (i=0; ichild, ctxNode, exprContext, position, nodeList, cbs, &leftResult, docOrder, errMsg); if (rc) { xpathRSFree (&leftResult); return rc; } leftStr = xpathFuncString (&leftResult); if (ctxNode->nodeType != ELEMENT_NODE) { if (ctxNode->nodeType == ATTRIBUTE_NODE) { node = ((domAttrNode*)ctxNode)->parentNode; } else { node = ctxNode->parentNode; } } else { node = ctxNode; } while (node) { attr = node->firstAttr; while (attr) { if (strcmp (attr->nodeName, "xml:lang")!=0) { attr = attr->nextSibling; continue; } tcldom_tolower (attr->nodeValue, tmp, 80); tcldom_tolower (leftStr, tmp1, 80); if (strcmp (tmp, tmp1)==0) { rsSetBool (result, 1); FREE(leftStr); xpathRSFree (&leftResult); return XPATH_OK; } else { pfrom = tmp; i = 0; while (*pfrom && i < 79) { if (*pfrom == '-') { *pfrom = '\0'; break; } pfrom++; i++; } if (strcmp (tmp, tmp1)==0) { rsSetBool (result, 1); FREE(leftStr); xpathRSFree (&leftResult); return XPATH_OK; } else { rsSetBool (result, 0); FREE(leftStr); xpathRSFree (&leftResult); return XPATH_OK; } } } node = node->parentNode; } rsSetBool (result, 0); FREE(leftStr); xpathRSFree (&leftResult); break; case f_startsWith: case f_contains: case f_substringBefore: case f_substringAfter: XPATH_ARITYCHECK(step,2,errMsg); xpathRSInit (&leftResult); xpathRSInit (&rightResult); savedDocOrder = *docOrder; rc = xpathEvalStep( step->child, ctxNode, exprContext, position, nodeList, cbs, &leftResult, docOrder, errMsg); CHECK_RC; *docOrder = savedDocOrder; rc = xpathEvalStep( step->child->next, ctxNode, exprContext, position, nodeList, cbs, &rightResult, docOrder, errMsg); CHECK_RC; *docOrder = savedDocOrder; DBG(fprintf(stderr, "\nsubstring-* left,right:\n"); rsPrint(&leftResult); rsPrint(&rightResult); ) leftStr = xpathFuncString( &leftResult ); rightStr = xpathFuncString( &rightResult ); DBG(fprintf(stderr, "substring-* '%s' '%s' \n", leftStr, rightStr);) if (step->intvalue == f_contains) { if (strstr(leftStr, rightStr) != NULL) { rsSetBool (result, 1); } else { rsSetBool (result, 0); } } else if (step->intvalue == f_substringBefore) { pfrom = strstr(leftStr, rightStr); if (pfrom != NULL) { DBG(fprintf(stderr, "substring-before '%s' '%s' : ", leftStr, rightStr);) *pfrom = '\0'; DBG(fprintf(stderr, "'%s' \n", leftStr);) rsSetString (result, leftStr); } else { rsSetString (result, ""); } } else if (step->intvalue == f_substringAfter) { pfrom = strstr(leftStr, rightStr); if (pfrom != NULL) { rsSetString (result, pfrom + strlen (rightStr)); } else { rsSetString (result, ""); } } else { /* starts-with */ i = (domLength)strlen(rightStr); if(strncmp(leftStr, rightStr, i)==0) { rsSetBool (result, 1); } else { rsSetBool (result, 0); } } xpathRSFree (&leftResult); xpathRSFree (&rightResult); FREE(rightStr); FREE(leftStr); break; case f_concat: if (xpathArity(step) < 2) { *errMsg = tdomstrdup("wrong number of parameters!"); return XPATH_EVAL_ERR; } nextStep = step->child; pto = MALLOC(1); *pto = '\0'; len = 0; while (nextStep) { xpathRSInit (&leftResult); savedDocOrder = *docOrder; rc = xpathEvalStep( nextStep, ctxNode, exprContext, position, nodeList, cbs, &leftResult, docOrder, errMsg); if (rc) { FREE (pto); return rc; } *docOrder = savedDocOrder; leftStr = xpathFuncString( &leftResult ); pto = (char*)REALLOC(pto, 1+len+strlen(leftStr)); memmove(pto + len, leftStr, strlen(leftStr)); len += (domLength)strlen(leftStr); *(pto + len) = '\0'; xpathRSFree( &leftResult ); FREE(leftStr); nextStep = nextStep->next; } rsSetString (result, pto); FREE(pto); break; case f_substring: i = xpathArity(step); if (i != 2 && i != 3) { *errMsg = tdomstrdup("wrong number of parameters!"); return XPATH_EVAL_ERR; } xpathRSInit (&leftResult); savedDocOrder = *docOrder; rc = xpathEvalStep( step->child, ctxNode, exprContext, position, nodeList, cbs, &leftResult, docOrder, errMsg); CHECK_RC; *docOrder = savedDocOrder; xpathRSInit (&rightResult); rc = xpathEvalStep( step->child->next, ctxNode, exprContext, position, nodeList, cbs, &rightResult, docOrder, errMsg); CHECK_RC; *docOrder = savedDocOrder; leftStr = xpathFuncString( &leftResult ); xpathRSFree (&leftResult); from = xpathRound(xpathFuncNumber(&rightResult, &NaN))-1; xpathRSFree( &rightResult ); if (NaN) { FREE(leftStr); rsSetString (result, ""); return XPATH_OK; } if (step->child->next->next) { untilEnd = 0; xpathRSInit (&rightResult); savedDocOrder = *docOrder; rc = xpathEvalStep( step->child->next->next, ctxNode, exprContext, position, nodeList, cbs, &rightResult, docOrder, errMsg); if (rc) { FREE (leftStr); return rc; } *docOrder = savedDocOrder; dRight = xpathFuncNumber (&rightResult, &NaN); len = xpathRound(dRight); xpathRSFree (&rightResult); if (NaN) { if (NaN == 1) { untilEnd = 1; } else { FREE(leftStr); rsSetString (result, ""); return XPATH_OK; } } xpathRSFree (&rightResult); if (from < 0) { len = len + from; if (len <= 0) { FREE(leftStr); rsSetString (result, ""); return XPATH_OK; } from = 0; } } else { if (from < 0) from = 0; untilEnd = 1; } pfrom = leftStr; while (*pfrom && (from > 0)) { i = UTF8_CHAR_LEN (*pfrom); if (!i) { FREE (leftStr); *errMsg = tdomstrdup("Can only handle UTF-8 chars up " "to 4 bytes length"); return XPATH_I18N_ERR; } pfrom += i; from--; } if (!untilEnd) { pto = pfrom; while (*pto && (len > 0)) { i = UTF8_CHAR_LEN (*pto); if (!i) { FREE (leftStr); *errMsg = tdomstrdup("Can only handle UTF-8 chars up " "to 4 bytes length"); return XPATH_I18N_ERR; } pto += i; len--; } *pto = '\0'; } rsSetString (result, pfrom); FREE(leftStr); break; case f_translate: XPATH_ARITYCHECK(step,3,errMsg); xpathRSInit (&leftResult); savedDocOrder = *docOrder; rc = xpathEvalStep( step->child, ctxNode, exprContext, position, nodeList, cbs, &leftResult, docOrder, errMsg); CHECK_RC; *docOrder = savedDocOrder; xpathRSInit (&rightResult); rc = xpathEvalStep( step->child->next, ctxNode, exprContext, position, nodeList, cbs, &rightResult, docOrder, errMsg); CHECK_RC; *docOrder = savedDocOrder; xpathRSInit (&replaceResult); rc = xpathEvalStep( step->child->next->next, ctxNode, exprContext, position, nodeList, cbs, &replaceResult, docOrder, errMsg); CHECK_RC; *docOrder = savedDocOrder; leftStr = xpathFuncString( &leftResult ); rightStr = xpathFuncString( &rightResult ); replaceStr = xpathFuncString( &replaceResult ); Tcl_DStringInit (&tstr); Tcl_DStringInit (&tfrom); Tcl_DStringInit (&tto); Tcl_DStringInit (&tresult); Tcl_UtfToUniCharDString (leftStr, -1, &tstr); Tcl_UtfToUniCharDString (rightStr, -1, &tfrom); Tcl_UtfToUniCharDString (replaceStr, -1, &tto); lenstr = Tcl_DStringLength (&tstr) / sizeof (Tcl_UniChar); fromlen = Tcl_DStringLength (&tfrom) / sizeof (Tcl_UniChar); len = Tcl_DStringLength (&tto) / sizeof (Tcl_UniChar); upfrom = (Tcl_UniChar *)Tcl_DStringValue (&tstr); for (i = 0; i < lenstr; i++) { found = 0; ufStr = (Tcl_UniChar *)Tcl_DStringValue (&tfrom); for (j = 0; j < fromlen; j++) { if (*ufStr == *upfrom) { found = 1; break; } ufStr++; } if (found) { if (j < len) { unichar = Tcl_UniCharAtIndex (replaceStr, j); utfCharLen = (int)Tcl_UniCharToUtf (unichar, utfBuf); Tcl_DStringAppend (&tresult, utfBuf, utfCharLen); } } else { utfCharLen = (int)Tcl_UniCharToUtf (*upfrom, utfBuf); Tcl_DStringAppend (&tresult, utfBuf, utfCharLen); } upfrom++; } rsSetString (result, Tcl_DStringValue (&tresult)); Tcl_DStringFree (&tstr); Tcl_DStringFree (&tfrom); Tcl_DStringFree (&tto); Tcl_DStringFree (&tresult); xpathRSFree( &replaceResult ); xpathRSFree( &rightResult ); xpathRSFree( &leftResult ); FREE(leftStr); FREE(rightStr); FREE(replaceStr); break; case f_count: XPATH_ARITYCHECK(step,1,errMsg); xpathRSInit (&leftResult); rc = xpathEvalStep( step->child, ctxNode, exprContext, position, nodeList, cbs, &leftResult, docOrder, errMsg); if (rc) { xpathRSFree( &leftResult ); return rc; } if (leftResult.type == EmptyResult) { rsSetLong (result, 0); return XPATH_OK; } if (leftResult.type != xNodeSetResult) { *errMsg = tdomstrdup("count() requires a node set!"); xpathRSFree( &leftResult ); return XPATH_EVAL_ERR; } rsSetLong (result, leftResult.nr_nodes); xpathRSFree (&leftResult); break; case f_unparsedEntityUri: XPATH_ARITYCHECK(step,1,errMsg); if (!ctxNode->ownerDocument->unparsedEntities) { break; } xpathRSInit (&leftResult); rc = xpathEvalStep( step->child, ctxNode, exprContext, position, nodeList, cbs, &leftResult, docOrder, errMsg); if (rc) { xpathRSFree( &leftResult ); return rc; } leftStr = xpathFuncString (&leftResult); entryPtr = Tcl_FindHashEntry (ctxNode->ownerDocument->unparsedEntities, leftStr); if (entryPtr) { rsSetString (result, (char *)Tcl_GetHashValue (entryPtr)); } else { rsSetString (result, ""); } FREE(leftStr); xpathRSFree (&leftResult); break; case f_localName: case f_name: case f_namespaceUri: case f_generateId: xpathRSInit (&leftResult); if (step->child == NULL) { /* no parameter, the context node is the nodeset to * operate with */ rsAddNodeFast( &leftResult, ctxNode); } else { XPATH_ARITYCHECK(step,1,errMsg); xpathRSInit (&leftResult); rc = xpathEvalStep( step->child, ctxNode, exprContext, position, nodeList, cbs, &leftResult, docOrder, errMsg); if (rc) { xpathRSFree( &leftResult ); return rc; } } if (leftResult.type == EmptyResult) { rsSetString (result, ""); return XPATH_OK; } if (step->intvalue == f_generateId) { if (leftResult.type != xNodeSetResult) { *errMsg = tdomstrdup("generate-id() requires a nodeset or no argument!"); xpathRSFree (&leftResult); return XPATH_EVAL_ERR; } if (leftResult.nodes[0]->nodeType == ATTRIBUTE_NODE) { node = ((domAttrNode*)leftResult.nodes[0])->parentNode; attrcount = 0; attr = node->firstAttr; while (attr) { if ((domNode*)attr == leftResult.nodes[0]) break; attr = attr->nextSibling; attrcount++; } sprintf(tmp,"id%p-%d", (void *)node, attrcount); } else { sprintf(tmp,"id%p", (void *)leftResult.nodes[0]); } rsSetString (result, tmp); } else if (step->intvalue == f_namespaceUri) { if (leftResult.type != xNodeSetResult) { *errMsg = tdomstrdup("namespace-uri() requires a node set!"); xpathRSFree( &leftResult ); return XPATH_EVAL_ERR; } if ( (leftResult.nr_nodes <= 0) || ( leftResult.nodes[0]->nodeType != ELEMENT_NODE && leftResult.nodes[0]->nodeType != ATTRIBUTE_NODE ) ) { rsSetString (result, ""); } else { rsSetString (result, domNamespaceURI(leftResult.nodes[0])); } } else if (step->intvalue == f_localName) { if (leftResult.type != xNodeSetResult) { *errMsg = tdomstrdup("local-name() requires a node set!"); xpathRSFree( &leftResult ); return XPATH_EVAL_ERR; } if (leftResult.nodes[0]->nodeType == ELEMENT_NODE) { if (leftResult.nodes[0] == leftResult.nodes[0]->ownerDocument->rootNode) { rsSetString (result, ""); } else { rsSetString (result, domGetLocalName(leftResult.nodes[0]->nodeName)); } } else if (leftResult.nodes[0]->nodeType == ATTRIBUTE_NODE) { str = domGetLocalName(((domAttrNode*)leftResult.nodes[0])->nodeName); if (str[0] == 'x' && strcmp(str, "xmlns")==0) { rsSetString (result, ""); } else { rsSetString (result, str); } } else if (leftResult.nodes[0]->nodeType == PROCESSING_INSTRUCTION_NODE) { if (((domProcessingInstructionNode*)leftResult.nodes[0])->targetLength > 79) { memmove(tmp, ((domProcessingInstructionNode*)leftResult.nodes[0])->targetValue, 79); tmp[79]= '\0'; } else { memmove(tmp, ((domProcessingInstructionNode*)leftResult.nodes[0])->targetValue, ((domProcessingInstructionNode*)leftResult.nodes[0])->targetLength); tmp[((domProcessingInstructionNode*)leftResult.nodes[0])->targetLength] = '\0'; } rsSetString (result, tmp); } else { rsSetString (result, ""); } } else if (step->intvalue == f_name) { if ( leftResult.type != xNodeSetResult ) { *errMsg = tdomstrdup("name() requires a node set!"); xpathRSFree( &leftResult ); return XPATH_EVAL_ERR; } if (leftResult.nodes[0]->nodeType == ELEMENT_NODE) { if (leftResult.nodes[0] == leftResult.nodes[0]->ownerDocument->rootNode) { rsSetString (result, ""); } else { rsSetString (result, leftResult.nodes[0]->nodeName); } } else if (leftResult.nodes[0]->nodeType == ATTRIBUTE_NODE) { if (leftResult.nodes[0]->nodeFlags & IS_NS_NODE) { if (((domAttrNode *)leftResult.nodes[0])->nodeName[5] == '\0') { rsSetString (result, ""); } else { rsSetString (result, &((domAttrNode*)leftResult.nodes[0])->nodeName[6]); } } else { rsSetString (result, ((domAttrNode*)leftResult.nodes[0])->nodeName ); } } else if (leftResult.nodes[0]->nodeType == PROCESSING_INSTRUCTION_NODE) { if (((domProcessingInstructionNode*)leftResult.nodes[0])->targetLength > 79) { memmove(tmp, ((domProcessingInstructionNode*)leftResult.nodes[0])->targetValue, 79); tmp[79]= '\0'; } else { memmove(tmp, ((domProcessingInstructionNode*)leftResult.nodes[0])->targetValue, ((domProcessingInstructionNode*)leftResult.nodes[0])->targetLength); tmp[((domProcessingInstructionNode*)leftResult.nodes[0])->targetLength] = '\0'; } rsSetString (result, tmp); } else { rsSetString (result, ""); } } xpathRSFree( &leftResult ); break; case f_fqfunction: Tcl_DStringInit (&dStr); if (cbs->funcCB == NULL) { Tcl_DStringAppend (&dStr, "Unknown function ", -1); } Tcl_DStringAppend (&dStr, step->strvalue, -1); Tcl_DStringAppend (&dStr, "::", 2); nextStep = step->child; Tcl_DStringAppend (&dStr, nextStep->strvalue, -1); if (cbs->funcCB == NULL) { *errMsg = tdomstrdup (Tcl_DStringValue (&dStr)); Tcl_DStringFree (&dStr); return XPATH_EVAL_ERR; } /* fall through */ default: if (cbs->funcCB == NULL) { if (strlen(step->strvalue)>50) *(step->strvalue + 50) = '\0'; sprintf(tmp, "Unknown function '%s'!", step->strvalue); *errMsg = tdomstrdup(tmp); return XPATH_EVAL_ERR; } /* count number of arguments (to be able to allocate later) */ argc = 0; if (step->intvalue == f_fqfunction) { nextStep = step->child->next; } else { nextStep = step->child; } while (nextStep) { argc++; nextStep = nextStep->next; } args = (xpathResultSets*)MALLOC((argc+1) * sizeof(xpathResultSets)); args[0] = NULL; argc = 0; if (step->intvalue == f_fqfunction) { nextStep = step->child->next; } else { nextStep = step->child; } savedDocOrder = *docOrder; while (nextStep) { arg = (xpathResultSet*)MALLOC(sizeof(xpathResultSet)); args[argc++] = arg; args[argc] = NULL; xpathRSInit (arg); rc = xpathEvalStep( nextStep, ctxNode, exprContext, position, nodeList, cbs, arg, docOrder, errMsg); if (rc) goto unknownfunccleanup; *docOrder = savedDocOrder; nextStep = nextStep->next; } if (step->intvalue == f_fqfunction) { rc = (cbs->funcCB) (cbs->funcClientData, Tcl_DStringValue (&dStr), ctxNode, position, nodeList, exprContext, argc, args, result, errMsg); } else { rc = (cbs->funcCB) (cbs->funcClientData, step->strvalue, ctxNode, position, nodeList, exprContext, argc, args, result, errMsg); } unknownfunccleanup: argc = 0; while ( args[argc] != NULL) { xpathRSFree( args[argc] ); FREE((char*)args[argc++]); } FREE((char*)args); if (step->intvalue == f_fqfunction) { Tcl_DStringFree (&dStr); } return rc; } return XPATH_OK; } /*---------------------------------------------------------------------------- | xpathEvalStep | \---------------------------------------------------------------------------*/ static int xpathEvalStep ( ast step, domNode *ctxNode, domNode *exprContext, domLength position, xpathResultSet *nodeList, xpathCBs *cbs, xpathResultSet *result, int *docOrder, char **errMsg ) { xpathResultSet leftResult, rightResult; xpathResultSet *pleftResult, *prightResult, tResult; int rc, res, NaN, NaN1, switchResult; domLength i, j, k, count = 0; domNode *node, *child, *startingNode, *ancestor; domAttrNode *attr; int savedDocOrder, predLimit; int left = 0, right = 0, useFastAdd, wildcard = 0; double dLeft = 0.0, dRight = 0.0, dTmp; char *leftStr = NULL, *rightStr = NULL; astType savedAstType; domNS *ns; if (result->type == EmptyResult) useFastAdd = 1; else useFastAdd = 0; switch (step->type) { case AxisChild: DBG(fprintf(stderr, "AxisChild ctxNode->nodeType = %d \n", ctxNode->nodeType);) *docOrder = 1; if (ctxNode->nodeType != ELEMENT_NODE) return XPATH_OK; DBG(fprintf(stderr, "AxisChild: scanning \n");) child = ctxNode->firstChild; if (step->intvalue) { while (child && (count < step->intvalue)) { DBG(fprintf(stderr, "AxisChild: child '%s' domNode%p \n", child->nodeName, child);) if (xpathNodeTest(child, step)) { DBG(fprintf(stderr, "AxisChild: after node taking child '%s' domNode%p \n", child->nodeName, child);) checkRsAddNode( result, child); count++; } child = child->nextSibling; } } else { while (child) { DBG(fprintf(stderr, "AxisChild: child '%s' domNode%p \n", child->nodeName, child);) if (xpathNodeTest(child, step)) { DBG(fprintf(stderr, "AxisChild: after node taking child '%s' domNode%p \n", child->nodeName, child);) checkRsAddNode( result, child); } child = child->nextSibling; } } DBG( fprintf(stderr,"AxisChild result:\n"); rsPrint(result); ) break; case SlashSlash: xpathRSInit (&tResult); node = ctxNode->firstChild; while (node) { if (node->nodeType == ELEMENT_NODE) { rc = xpathEvalStep (step, node, exprContext, position, nodeList, cbs, result, docOrder, errMsg); if (rc) { xpathRSFree (&tResult); return rc; } } if (xpathNodeTest(node, step)) { rsAddNodeFast( &tResult, node); } node = node->nextSibling; } rc = xpathEvalPredicate (step->next, exprContext, result, &tResult, cbs, docOrder, errMsg); xpathRSFree (&tResult); CHECK_RC; break; case AxisDescendant: case AxisDescendantOrSelf: if (step->next && step->next->type == Pred) { *docOrder = 1; if (ctxNode->nodeType == ATTRIBUTE_NODE && step->type == AxisDescendantOrSelf) { if (xpathNodeTest(ctxNode, step)) { checkRsAddNode( result, ctxNode); } break; } if (ctxNode->nodeType != ELEMENT_NODE) return XPATH_OK; if (step->type == AxisDescendantOrSelf) { if (xpathNodeTest(ctxNode, step)) { xpathRSInit (&tResult); rsAddNodeFast( &tResult, ctxNode); rc = xpathEvalPredicate (step->next, exprContext, result, &tResult, cbs, docOrder, errMsg); xpathRSFree (&tResult); CHECK_RC; } } savedAstType = step->type; step->type = SlashSlash; rc = xpathEvalStep (step, ctxNode, exprContext, position, nodeList, cbs, result, docOrder, errMsg); step->type = savedAstType; CHECK_RC; break; } /* without following Pred step, // is the same as AxisDescendantOrSelf */ /* fall through */ case AxisDescendantLit: case AxisDescendantOrSelfLit: *docOrder = 1; if (step->intvalue && (step->type == AxisDescendantLit || step->type == AxisDescendantOrSelfLit)) predLimit = 1; else predLimit = 0; if (ctxNode->nodeType == ATTRIBUTE_NODE && (step->type == AxisDescendantOrSelf || step->type == AxisDescendantOrSelfLit)) { if (xpathNodeTest(ctxNode, step)) { checkRsAddNode( result, ctxNode); } break; } if (ctxNode->nodeType != ELEMENT_NODE) return XPATH_OK; if (step->type == AxisDescendantOrSelf || step->type == AxisDescendantOrSelfLit) { if (xpathNodeTest(ctxNode, step)) { checkRsAddNode( result, ctxNode); if (predLimit) { count++; } } } startingNode = ctxNode; node = ctxNode->firstChild; while (node && node != startingNode) { if (xpathNodeTest(node, step)) { checkRsAddNode( result, node); if (predLimit) { count++; if (count >= step->intvalue) break; } } if ((node->nodeType == ELEMENT_NODE) && (node->firstChild)) { node = node->firstChild; continue; } if (node->nextSibling) { node = node->nextSibling; continue; } while ( node->parentNode && (node->parentNode != startingNode) && (node->parentNode->nextSibling == NULL) ) { node = node->parentNode; } if ((node != startingNode) && (node->parentNode) && (node->parentNode != startingNode) ) { node = node->parentNode->nextSibling; } else { break; } } break; case AxisSelf: *docOrder = 1; DBG(fprintf(stderr, "AxisSelf :: \n");) if (xpathNodeTest(ctxNode, step)) { rsAddNode( result, ctxNode); } break; case GetContextNode: rsAddNode( result, ctxNode); break; case AxisAttribute: *docOrder = 1; DBG(fprintf(stderr, "AxisAttribute %s \n", step->child->strvalue);) if (ctxNode->nodeType != ELEMENT_NODE) return XPATH_OK; if (step->child->type == IsElement) { step->child->type = IsAttr; } if (step->child->type == IsAttr) { if (strcmp(step->child->strvalue, "*")==0) { attr = ctxNode->firstAttr; while (attr) { if (!(attr->nodeFlags & IS_NS_NODE)) { checkRsAddNode (result, (domNode *)attr); } attr = attr->nextSibling; } } else { attr = ctxNode->firstAttr; while (attr && (attr->nodeFlags & IS_NS_NODE)) attr = attr->nextSibling; while (attr) { if (xpathNodeTest( (domNode*)attr, step)) { checkRsAddNode (result, (domNode *)attr); } attr = attr->nextSibling; } } } else if (step->child->type == IsNSAttr) { attr = ctxNode->firstAttr; while (attr && (attr->nodeFlags & IS_NS_NODE)) attr = attr->nextSibling; while (attr) { if (xpathNodeTest ( (domNode*)attr, step)) { checkRsAddNode (result, (domNode *)attr); } attr = attr->nextSibling; } } break; case AxisParent: *docOrder = 1; if (ctxNode->nodeType == ATTRIBUTE_NODE) { if (xpathNodeTest(((domAttrNode *)ctxNode)->parentNode, step)) { rsAddNode(result,((domAttrNode *)ctxNode)->parentNode); } } else { if (ctxNode->parentNode) { if (xpathNodeTest(ctxNode->parentNode, step)) { rsAddNode(result,ctxNode->parentNode); } } else { if (ctxNode->ownerDocument->rootNode != ctxNode && xpathNodeTest (ctxNode->ownerDocument->rootNode, step)) { rsAddNode (result, ctxNode->ownerDocument->rootNode); } } } break; case GetParentNode: if (ctxNode->nodeType == ATTRIBUTE_NODE) { rsAddNode(result,((domAttrNode*)ctxNode)->parentNode); } else { if (ctxNode->parentNode) { rsAddNode(result,ctxNode->parentNode); } else { if (ctxNode != ctxNode->ownerDocument->rootNode) { rsAddNode (result, ctxNode->ownerDocument->rootNode); } } } break; case AxisAncestor: case AxisAncestorOrSelf: *docOrder = 0; xpathRSInit (&tResult); if (step->type == AxisAncestorOrSelf) { if (xpathNodeTest(ctxNode, step)) { rsAddNodeFast(&tResult, ctxNode); } } if (ctxNode->nodeType == ATTRIBUTE_NODE) { ctxNode = ((domAttrNode *)ctxNode)->parentNode; if (xpathNodeTest(ctxNode, step)) { rsAddNodeFast(&tResult, ctxNode); } } startingNode = ctxNode; while (ctxNode->parentNode) { ctxNode = ctxNode->parentNode; if (xpathNodeTest(ctxNode, step)) { rsAddNodeFast(&tResult, ctxNode); } } if (startingNode != ctxNode->ownerDocument->rootNode) { if (xpathNodeTest (ctxNode->ownerDocument->rootNode, step)) { rsAddNodeFast (&tResult, ctxNode->ownerDocument->rootNode); } } for (i = tResult.nr_nodes - 1; i >= 0; i--) { checkRsAddNode (result, tResult.nodes[i]); } xpathRSFree (&tResult); break; case AxisFollowingSibling: *docOrder = 1; if (ctxNode->nodeType == ATTRIBUTE_NODE) { return XPATH_OK; } if (step->intvalue) { while (ctxNode->nextSibling && (count < step->intvalue)) { ctxNode = ctxNode->nextSibling; if (xpathNodeTest(ctxNode, step)) { checkRsAddNode(result, ctxNode); count++; } } } else { while (ctxNode->nextSibling) { ctxNode = ctxNode->nextSibling; if (xpathNodeTest(ctxNode, step)) { checkRsAddNode(result, ctxNode); } } } break; case AxisPrecedingSibling: *docOrder = 0; if (ctxNode->nodeType == ATTRIBUTE_NODE) { return XPATH_OK; } if (step->intvalue) { node = ctxNode->previousSibling; xpathRSInit (&tResult); while (node && (count < step->intvalue)) { if (xpathNodeTest (node, step)) { rsAddNodeFast (&tResult, node); count++; } node = node->previousSibling; } for (i = tResult.nr_nodes -1; i >= 0; i--) { checkRsAddNode (result, tResult.nodes[i]); } xpathRSFree (&tResult); } else { startingNode = ctxNode; if (startingNode->parentNode) { node = (startingNode->parentNode)->firstChild; } else { if (ctxNode == ctxNode->ownerDocument->rootNode) return XPATH_OK; node = startingNode->ownerDocument->rootNode->firstChild; } while (node && (node != startingNode)) { if (xpathNodeTest(node, step)) { checkRsAddNode(result, node); } node = node->nextSibling; } } break; case AxisFollowing: *docOrder = 1; if (ctxNode->nodeType == ATTRIBUTE_NODE) { node = ((domAttrNode *)ctxNode)->parentNode->firstChild; } else { node = ctxNode; if (node->nextSibling) { node = node->nextSibling; } else { while (node->parentNode) { node = node->parentNode; if (node->nextSibling) break; } if (!node->nextSibling) return XPATH_OK; else node = node->nextSibling; } } while (1) { if (xpathNodeTest (node, step)) { checkRsAddNode (result, node); if (step->intvalue) { count++; if (count >= step->intvalue) break; } } if (node->nodeType == ELEMENT_NODE && node->firstChild) { node = node->firstChild; } else if (node->nextSibling) { node = node->nextSibling; } else { while (node->parentNode) { node = node->parentNode; if (node->nextSibling) break; } if (!node->nextSibling) break; node = node->nextSibling; } } break; case AxisPreceding: *docOrder = 0; if (ctxNode->nodeType == ATTRIBUTE_NODE) { ancestor = node = ((domAttrNode *)ctxNode)->parentNode; } else { ancestor = node = ctxNode; } i = 0; while (node->parentNode) { ancestor = node; node = node->parentNode; i++; } startingNode = node->firstChild; for (; i > 0; i--) { if (!startingNode) continue; if (startingNode->nodeType == ELEMENT_NODE) { node = startingNode->firstChild; } else { node = NULL; } while (startingNode != ancestor) { if (xpathNodeTest(startingNode, step)) { checkRsAddNode(result, startingNode); } while ((node) && (node != startingNode)) { if (xpathNodeTest(node, step)) { checkRsAddNode(result, node); } if ((node->nodeType == ELEMENT_NODE) && (node->firstChild)) { node = node->firstChild; continue; } if (node->nextSibling) { node = node->nextSibling; continue; } while ((node->parentNode != startingNode) && (node->parentNode->nextSibling == NULL)) { node = node->parentNode; } if (node->parentNode != startingNode) { node = node->parentNode->nextSibling; } else { break; } } startingNode = startingNode->nextSibling; if (startingNode->nodeType == ELEMENT_NODE) { node = startingNode->firstChild; } else { node = NULL; } } if (ctxNode->nodeType == ATTRIBUTE_NODE) { node = ((domAttrNode *)ctxNode)->parentNode; } else { node = ctxNode; } for (j = 0; j < i - 1 ; j++) { ancestor = node; node = node->parentNode; } if (node->nodeType == ELEMENT_NODE) { startingNode = node->firstChild; } else { startingNode = NULL; } } break; case AxisNamespace: *docOrder = 1; /* XPath rec 2.2: "the namespace axis contains the namespace * nodes of the context node; the axis will be empty unless * the context node is an element */ if (ctxNode->nodeType != ELEMENT_NODE) { return XPATH_OK; } node = ctxNode; ns = NULL; /* The namespace axis is special because it resolves the * prefix not in the expression context but in the context * node, which may make a difference in case of xslt. */ if (step->child->type == IsElement) { if (step->child->strvalue[0] != '*') { ns = domLookupPrefix (node, step->child->strvalue); if (!ns) { /* The prefix doesn't resolve, there is nothing to * select. */ return XPATH_OK; } } else { wildcard = 1; } } if (!ns && !wildcard) return XPATH_OK; while (node) { attr = node->firstAttr; /* fprintf (stderr, "AxisNamespace: step->child->strvalue %s\n", */ /* step->child->strvalue); */ while (attr && (attr->nodeFlags & IS_NS_NODE)) { if (step->child->type == IsElement) { if (!wildcard) { if (strcmp(attr->nodeValue, ns->uri) != 0) { attr = attr->nextSibling; continue; } } } rc = 0; for (i = 0; i < result->nr_nodes; i++) { if (result->nodes[i]->nodeType != ATTRIBUTE_NODE) continue; if (strcmp (attr->nodeName, ((domAttrNode*)result->nodes[i])->nodeName)==0) { rc = 1; break; } } if (rc) {attr = attr->nextSibling; continue;} checkRsAddNode (result, (domNode *)attr); attr = attr->nextSibling; } if (node == node->ownerDocument->documentElement) { if (ctxNode != ctxNode->ownerDocument->rootNode) { node = ctxNode->ownerDocument->rootNode; } else { node = NULL; } } else { node = node->parentNode; } } break; case GetFQVar: case GetVar: if (cbs->varCB) { if (step->type == GetFQVar) { leftStr = step->child->strvalue; rightStr = step->strvalue; } else { leftStr = step->strvalue; rightStr = NULL; } rc = (cbs->varCB)(cbs->varClientData, leftStr, rightStr, result, errMsg); CHECK_RC; } break; case Literal: rsSetString (result, step->strvalue); break; case Int: rsSetLong (result, step->intvalue); break; case Real: rsSetReal (result, step->realvalue); break; case Add: case Subtract: case Mult: case Div: case Mod: xpathRSInit (&leftResult); xpathRSInit (&rightResult); savedDocOrder = *docOrder; rc = xpathEvalStep( step->child, ctxNode, exprContext, position, nodeList, cbs, &leftResult, docOrder, errMsg); CHECK_RC; DBG( fprintf(stderr,"left:\n"); rsPrint(&leftResult); ) *docOrder = savedDocOrder; rc = xpathEvalStep( step->child->next, ctxNode, exprContext, position, nodeList, cbs, &rightResult, docOrder, errMsg); CHECK_RC; *docOrder = savedDocOrder; DBG( fprintf(stderr,"right:\n"); rsPrint(&rightResult); ) if ((&leftResult)->type == RealResult) { dLeft = (&leftResult)->realvalue; NaN = 0; if (IS_NAN(dLeft)) NaN = 2; else if (IS_INF(dLeft)!=0) NaN = IS_INF(dLeft); } else { dLeft = xpathFuncNumber(&leftResult, &NaN); } if ((&rightResult)->type == RealResult) { dRight = (&rightResult)->realvalue; NaN1 = 0; if (IS_NAN(dRight)) NaN1= 2; else if (IS_INF(dRight) !=0) NaN1 = IS_INF(dRight); } else { dRight = xpathFuncNumber(&rightResult, &NaN1); } if (NaN || NaN1) { if ((NaN == 2) || (NaN1 == 2)) { rsSetNaN (result); } else { switch (step->type) { case Subtract: NaN1 = -1 * NaN1; /* fall through */ case Add: if (NaN == NaN1) { if (NaN == 1) rsSetInf (result); else rsSetNInf (result); } else if ((rc = NaN + NaN1) != 0) { if (rc == 1) rsSetInf (result); else rsSetNInf (result); } else { rsSetNaN (result); } break; case Mult: if ((dLeft == 0.0) || (dRight == 0.0)) rsSetNaN (result); else if (NaN && NaN1) { rc = NaN * NaN1; if (rc == 1) rsSetInf (result); else rsSetNInf (result); } else { if (NaN) dTmp = NaN * dRight; else dTmp = NaN1 * dLeft; if (dTmp > 0.0) rsSetInf (result); else rsSetNInf (result); } break; case Div: if (NaN && NaN1) rsSetNaN (result); else if (NaN1) rsSetLong (result, 0); else { if (dRight == 0.0) dTmp = NaN; else dTmp = NaN * dRight; if (dTmp > 0.0) rsSetInf (result); else rsSetNInf (result); } break; case Mod: rsSetNaN (result); break; default: break; } } xpathRSFree (&rightResult); xpathRSFree (&leftResult); return XPATH_OK; } switch (step->type) { case Add: rsSetReal (result, dLeft + dRight); break; case Subtract: rsSetReal (result, dLeft - dRight); break; case Mult: rsSetReal (result, dLeft * dRight); break; case Div: if (dRight == 0.0) { if (dLeft == 0.0) { rsSetNaN (result); } else { if (dLeft > 0) { rsSetInf (result); } else { rsSetNInf (result); } } } else { rsSetReal (result, dLeft / dRight); } break; case Mod: if ((int)dRight == 0) { rsSetNaN (result); } else { if (dRight < (double)LONG_MIN - 0.1 || dRight > (double)LONG_MAX + 0.1 || dLeft < (double)LONG_MIN - 0.1 || dLeft > (double)LONG_MAX + 0.1) { rsSetNaN (result); } else { rsSetLong (result, ((long)dLeft) % ((long)dRight)); } } break; default: break; } xpathRSFree (&rightResult); xpathRSFree (&leftResult); return XPATH_OK; case CombineSets: xpathRSInit (&leftResult); xpathRSInit (&rightResult); savedDocOrder = *docOrder; rc = xpathEvalStep (step->child, ctxNode, exprContext, position, nodeList, cbs, &leftResult, docOrder, errMsg); CHECK_RC; DBG( fprintf(stderr,"left:\n"); rsPrint(&leftResult); ) *docOrder = savedDocOrder; rc = xpathEvalStep( step->child->next, ctxNode, exprContext, position, nodeList, cbs, &rightResult, docOrder, errMsg); CHECK_RC; *docOrder = savedDocOrder; DBG( fprintf(stderr,"right:\n"); rsPrint(&rightResult); ) if (((leftResult.type != xNodeSetResult) && (leftResult.type != EmptyResult)) || ((rightResult.type != xNodeSetResult) && (rightResult.type != EmptyResult))) { *errMsg = tdomstrdup("| requires node sets!"); xpathRSFree (&rightResult); xpathRSFree (&leftResult); return XPATH_EVAL_ERR; } if (leftResult.type == EmptyResult) { rsCopy (result, &rightResult); goto combineSetCleanup; } if (rightResult.type == EmptyResult) { rsCopy (result, &leftResult); goto combineSetCleanup; } *docOrder = 1; j = k = 0; for (i=0; i<(leftResult.nr_nodes+rightResult.nr_nodes); i++) { if (leftResult.nodes[j] == rightResult.nodes[k]) { rsAddNodeFast (result, leftResult.nodes[j]); j++; k++; if (j == leftResult.nr_nodes) break; if (k == rightResult.nr_nodes) break; i++; continue; } if (domPrecedes (leftResult.nodes[j], rightResult.nodes[k])) { rsAddNodeFast (result, leftResult.nodes[j]); j++; if (j == leftResult.nr_nodes) break; } else { rsAddNodeFast (result, rightResult.nodes[k]); k++; if (k == rightResult.nr_nodes) break; } } if (j < leftResult.nr_nodes) { for (i=j; i< leftResult.nr_nodes; i++) { rsAddNodeFast ( result, leftResult.nodes[i]); } } else { for (i=k; i< rightResult.nr_nodes; i++) { rsAddNodeFast ( result, rightResult.nodes[i]); } } combineSetCleanup: xpathRSFree (&rightResult); xpathRSFree (&leftResult); return XPATH_OK; case And: case Or: case Equal: case NotEqual: xpathRSInit (&leftResult); xpathRSInit (&rightResult); savedDocOrder = *docOrder; rc = xpathEvalStep( step->child, ctxNode, exprContext, position, nodeList, cbs, &leftResult, docOrder, errMsg); CHECK_RC; *docOrder = savedDocOrder; DBG( fprintf(stderr,"left:\n"); rsPrint(&leftResult); ) /*---------------------------------------------- | short circuit evaluation for AND/OR \---------------------------------------------*/ if (step->type == And) { left = xpathFuncBoolean(&leftResult); if (!left) { /* left result is false, so AND result is also false */ rsSetBool (result, left); xpathRSFree (&leftResult); return XPATH_OK; } } if (step->type == Or) { left = xpathFuncBoolean(&leftResult); if (left) { /* left result is true, so OR result is also true */ rsSetBool (result, left); xpathRSFree (&leftResult); return XPATH_OK; } } rc = xpathEvalStep( step->child->next, ctxNode, exprContext, position, nodeList, cbs, &rightResult, docOrder, errMsg); CHECK_RC; *docOrder = savedDocOrder; DBG( fprintf(stderr,"right:\n"); rsPrint(&rightResult); ) res = 0; if ((step->type == And) || (step->type == Or)) { right = xpathFuncBoolean(&rightResult); if (step->type == And) res = (left && right); if (step->type == Or) res = (left || right); rsSetBool (result, res); xpathRSFree (&rightResult); xpathRSFree (&leftResult); return XPATH_OK; } if ( leftResult.type == xNodeSetResult || rightResult.type == xNodeSetResult) { if (leftResult.type == xNodeSetResult) { pleftResult = &leftResult; prightResult = &rightResult; } else { pleftResult = &rightResult; prightResult = &leftResult; } switch (prightResult->type) { case EmptyResult: res = 0; break; case xNodeSetResult: JDBG( fprintf(stderr,"\nleft+right result:\n"); rsPrint(pleftResult); rsPrint(prightResult); ) for (i=0; i < pleftResult->nr_nodes; i++) { leftStr = xpathFuncStringForNode (pleftResult->nodes[i]); for (j=0; j < prightResult->nr_nodes; j++) { rightStr = xpathFuncStringForNode (prightResult->nodes[j]); JDBG(fprintf(stderr, "leftStr='%s' rightStr='%s'\n", leftStr, rightStr);) res = strcmp (leftStr, rightStr); if (step->type == Equal) res = (res==0); else if (step->type == NotEqual) res = (res!=0); FREE(rightStr); if (res) break; } FREE(leftStr); if (res) break; } break; case BoolResult: if (step->type == Equal) res = (prightResult->intvalue != 0); else res = (prightResult->intvalue == 0); break; case IntResult: case RealResult: dRight = xpathFuncNumber (prightResult, &NaN); if (NaN) { /* The real value of a node could never be inf/-inf */ /* And NaN is always != NaN (and != everything else) */ if (step->type == Equal) res = 0; else res = 1; break; } for (i=0; i < pleftResult->nr_nodes; i++) { leftStr = xpathFuncStringForNode (pleftResult->nodes[i]); dLeft = xpathStringToNumber (leftStr, &NaN); FREE(leftStr); if (NaN) continue; if (step->type == Equal) res = (dLeft == dRight); else res = (dLeft != dRight); if (res) break; } break; case NaNResult: case InfResult: case NInfResult: res = 0; break; case StringResult: rightStr = xpathFuncString (prightResult); for (i=0; i < pleftResult->nr_nodes; i++) { leftStr = xpathFuncStringForNode (pleftResult->nodes[i]); res = strcmp (leftStr, rightStr); if (step->type == Equal) res = (res == 0); else res = (res != 0); FREE(leftStr); if (res) break; } FREE(rightStr); break; default: Tcl_Panic("Invalid xpathResultType %s in xpathEvalStep!", xpathResultType2string(prightResult->type)); break; } } else if (leftResult.type == BoolResult || rightResult.type == BoolResult) { left = xpathFuncBoolean (&leftResult); right = xpathFuncBoolean (&rightResult); if (step->type == Equal) res = (left == right); else res = (left != right); } else if ( leftResult.type == IntResult || leftResult.type == RealResult || rightResult.type == IntResult || rightResult.type == RealResult || rightResult.type == NaNResult || rightResult.type == InfResult || rightResult.type == NInfResult || leftResult.type == NaNResult || leftResult.type == InfResult || leftResult.type == NInfResult ) { if ( leftResult.type == EmptyResult || rightResult.type == EmptyResult) { res = 0; } else { dLeft = xpathFuncNumber (&leftResult, &NaN); dRight = xpathFuncNumber (&rightResult, &NaN1); if (NaN || NaN1) { if (NaN == NaN1) { if (NaN != 2) { if (step->type == Equal) res = 1; } else { if (step->type == NotEqual) res = 1; } } else { if (step->type == NotEqual) res = 1; } } else { if (step->type == Equal) res = (dLeft == dRight); else res = (dLeft != dRight); } } } else { if ( leftResult.type == EmptyResult || rightResult.type == EmptyResult) { res = 0; } else { leftStr = xpathFuncString (&leftResult); rightStr = xpathFuncString (&rightResult); res = strcmp (leftStr, rightStr); if (step->type == Equal) res = (res == 0); else res = (res != 0); FREE(leftStr); FREE(rightStr); } } rsSetBool (result, res); xpathRSFree (&rightResult); xpathRSFree (&leftResult); return XPATH_OK; case Less: case LessOrEq: case Greater: case GreaterOrEq: xpathRSInit (&leftResult); xpathRSInit (&rightResult); savedDocOrder = *docOrder; rc = xpathEvalStep( step->child, ctxNode, exprContext, position, nodeList, cbs, &leftResult, docOrder, errMsg); CHECK_RC; *docOrder = savedDocOrder; DBG( fprintf(stderr,"left:\n"); rsPrint(&leftResult); ) rc = xpathEvalStep( step->child->next, ctxNode, exprContext, position, nodeList, cbs, &rightResult, docOrder, errMsg); CHECK_RC; *docOrder = savedDocOrder; DBG( fprintf(stderr,"right:\n"); rsPrint(&rightResult); ) res = 0; if ( leftResult.type == xNodeSetResult || rightResult.type == xNodeSetResult) { if (leftResult.type == xNodeSetResult) { pleftResult = &leftResult; prightResult = &rightResult; switchResult = 0; } else { pleftResult = &rightResult; prightResult = &leftResult; switchResult = 1; } switch (prightResult->type) { case EmptyResult: res = 0; break; case xNodeSetResult: JDBG( fprintf(stderr,"\nleft+right result:\n"); rsPrint(pleftResult); rsPrint(prightResult); ) for (i=0; i < pleftResult->nr_nodes; i++) { leftStr = xpathFuncStringForNode (pleftResult->nodes[i]); dLeft = xpathStringToNumber (leftStr, &NaN); FREE(leftStr); if (NaN) continue; for (j=0; j < prightResult->nr_nodes; j++) { rightStr = xpathFuncStringForNode (prightResult->nodes[j]); dRight = xpathStringToNumber (rightStr, &NaN); FREE(rightStr); if (NaN) continue; if (switchResult) { dTmp = dLeft; dLeft = dRight; dRight = dTmp; } if (step->type == Less) res = (dLeft < dRight); else if (step->type == LessOrEq) res = (dLeft <= dRight); else if (step->type == Greater) res = (dLeft > dRight); else res = (dLeft >= dRight); if (res) break; } if (res) break; } break; case BoolResult: /* pleftResult is a nonempty nodeset, therefore: */ dLeft = 1.0; dRight = xpathFuncNumber (prightResult, &NaN); if (NaN) break; if (step->type == Less) res = (dLeft < dRight); else if (step->type == LessOrEq) res = (dLeft <= dRight); else if (step->type == Greater) res = (dLeft > dRight); else res = (dLeft >= dRight); if (switchResult) { res = !res; } break; case NaNResult: break; case InfResult: case NInfResult: case IntResult: case RealResult: case StringResult: dRight = xpathFuncNumber (prightResult, &NaN); if (NaN) { if (NaN == 2) break; #ifdef DBL_MAX if (NaN == 1) dRight = DBL_MAX; else dRight = -DBL_MAX; #endif } for (i=0; i < pleftResult->nr_nodes; i++) { leftStr = xpathFuncStringForNode (pleftResult->nodes[i]); dLeft = xpathStringToNumber (leftStr, &NaN); FREE (leftStr); if (NaN) continue; if (switchResult) { dTmp = dLeft; dLeft = dRight; dRight = dTmp; } if (step->type == Less) res = (dLeft < dRight); else if (step->type == LessOrEq) res = (dLeft <= dRight); else if (step->type == Greater) res = (dLeft > dRight); else res = (dLeft >= dRight); if (res) break; } break; default: Tcl_Panic("Invalid xpathResultType %s in xpathEvalStep!", xpathResultType2string(prightResult->type)); break; } } else { if ( leftResult.type == EmptyResult || rightResult.type == EmptyResult) { res = 0; } else { dLeft = xpathFuncNumber (&leftResult, &NaN); if (NaN) { if (NaN == 2) goto compareFinish; #ifdef DBL_MAX if (NaN == 1) dLeft = DBL_MAX; else dLeft = -DBL_MAX; #endif } dRight = xpathFuncNumber (&rightResult, &NaN); if (NaN) { if (NaN == 2) goto compareFinish; #ifdef DBL_MAX if (NaN == 1) dRight = DBL_MAX; else dRight = -DBL_MAX; #endif } if (step->type == Less) res = (dLeft < dRight); else if (step->type == LessOrEq) res = (dLeft <= dRight); else if (step->type == Greater) res = (dLeft > dRight); else res = (dLeft >= dRight); } } compareFinish: rsSetBool (result, res); xpathRSFree (&rightResult); xpathRSFree (&leftResult); return XPATH_OK; case SelectRoot: if (ctxNode->nodeType == ATTRIBUTE_NODE) { node = ((domAttrNode *)ctxNode)->parentNode; checkRsAddNode(result, node->ownerDocument->rootNode); } else { checkRsAddNode(result, ctxNode->ownerDocument->rootNode); } break; case UnaryMinus: xpathRSInit (&leftResult); rc = xpathEvalSteps (step->child, nodeList, ctxNode, exprContext, position, docOrder,cbs, &leftResult, errMsg); CHECK_RC; dLeft = xpathFuncNumber (&leftResult, &NaN); if (NaN) { if (NaN == 2) rsSetNaN (result); else if (NaN == 1) rsSetNInf (result); else rsSetInf (result); } else rsSetReal (result , -1 * dLeft); xpathRSFree (&leftResult); break; case EvalSteps: rc = xpathEvalSteps (step->child, nodeList, ctxNode, exprContext, position, docOrder,cbs, &leftResult, errMsg); CHECK_RC; if ((result->type != EmptyResult) && (leftResult.type != result->type)) { DBG( fprintf (stderr, "EvalSteps:\nresult:\n"); rsPrint (result); fprintf (stderr, "leftResult:\n"); rsPrint (&leftResult); ) *errMsg = tdomstrdup("can not merge different result types!"); return XPATH_EVAL_ERR; } switch (leftResult.type) { case xNodeSetResult: for (i=0; itype]); return XPATH_EVAL_ERR; } return XPATH_OK; } /* xpathEvalStep */ /*---------------------------------------------------------------------------- | xpathEvalPredicate | \---------------------------------------------------------------------------*/ static int xpathEvalPredicate ( ast step, domNode *exprContext, xpathResultSet *result, xpathResultSet *stepResult, xpathCBs *cbs, int *docOrder, char **errMsg ) { xpathResultSet predResult, tmpResult; int rc, savedDocOrder, useFastAdd; domLength i; if (result->nr_nodes == 0) useFastAdd = 1; else useFastAdd = 0; savedDocOrder = *docOrder; while (step && step->type == Pred) { xpathRSInit (&tmpResult); if (step->child->type == Int) { if (stepResult->nr_nodes >= step->child->intvalue && step->child->intvalue > 0) { if (*docOrder) { rsAddNode (&tmpResult, stepResult->nodes[step->child->intvalue - 1]); } else { rsAddNode (&tmpResult, stepResult->nodes[stepResult->nr_nodes - step->child->intvalue]); } } goto nextPred; } for (i=0; inr_nodes; i++) { xpathRSInit (&predResult); rc = xpathEvalStep( step->child, stepResult->nodes[i], exprContext, i, stepResult, cbs, &predResult, docOrder, errMsg); CHECK_RC; *docOrder = savedDocOrder; DBG( fprintf(stderr, "after eval for Predicate: \n"); ) DBG( rsPrint( &predResult); ) if (predResult.type == RealResult) { predResult.type = IntResult; predResult.intvalue = xpathRound(predResult.realvalue); } if (predResult.type == IntResult) { if (predResult.intvalue < 0) { predResult.intvalue = stepResult->nr_nodes + predResult.intvalue; } if (savedDocOrder) { if (predResult.intvalue == (i+1)) { rsAddNodeFast (&tmpResult, stepResult->nodes[i]); } } else { if (predResult.intvalue == (stepResult->nr_nodes - i)){ rsAddNodeFast (&tmpResult, stepResult->nodes[i]); } } } else if (xpathFuncBoolean(&predResult)) { rsAddNodeFast (&tmpResult, stepResult->nodes[i]); } xpathRSFree (&predResult); } nextPred: DBG( fprintf(stderr, "result after Predicate: \n"); ) DBG( rsPrint( &tmpResult); ) xpathRSFree( stepResult ); *stepResult = tmpResult; step = step->next; } /* add remaining result set to overall result set */ for (i=0; inr_nodes; i++) { checkRsAddNode (result, stepResult->nodes[i]); } return 0; } /*---------------------------------------------------------------------------- | xpathEvalStepAndPredicates | \---------------------------------------------------------------------------*/ static int xpathEvalStepAndPredicates ( ast steps, xpathResultSet *nodeList, domNode *currentNode, domNode *exprContext, domLength currentPos, int *docOrder, xpathCBs *cbs, xpathResultSet *result, char **errMsg ) { xpathResultSet stepResult; int rc; /* For AxisDescendantOrSelf/AxisDescendant, the predicate filtering is already done 'inlined' during xpathEvalStep, to do the filtering "with respect to the child axis" (XPath rec. 3.3) in an efficienter way, then up to now. */ if ( steps->next && steps->next->type == Pred && steps->type != AxisDescendantOrSelf && steps->type != AxisDescendant) { xpathRSInit (&stepResult); rc = xpathEvalStep( steps, currentNode, exprContext, currentPos, nodeList, cbs, &stepResult, docOrder, errMsg); if (rc) { xpathRSFree (&stepResult); return rc; } rc = xpathEvalPredicate (steps->next, exprContext, result, &stepResult, cbs, docOrder, errMsg); xpathRSFree (&stepResult); CHECK_RC; } else { /* for steps not followed by a predicate immediately add to the final result set */ rc = xpathEvalStep( steps, currentNode, exprContext, currentPos, nodeList, cbs, result, docOrder, errMsg); CHECK_RC; DBG( rsPrint( result); ) } return 0; } /*---------------------------------------------------------------------------- | xpathEvalSteps | \---------------------------------------------------------------------------*/ int xpathEvalSteps ( ast steps, xpathResultSet *nodeList, domNode *currentNode, domNode *exprContext, domLength currentPos, int *docOrder, xpathCBs *cbs, xpathResultSet *result, char **errMsg ) { int rc, first = 1; domLength i; xpathResultSet savedContext; DBG (fprintf (stderr, "xpathEvalSteps start\n");) savedContext = *nodeList; xpathRSInit (result); while (steps) { DBG (fprintf (stderr, "xpathEvalSteps: eval step '%s'\n", astType2str[steps->type]);) if (steps->type == Pred) { *errMsg = "Pred step not expected now!"; return XPATH_EVAL_ERR; } if (first) { rc = xpathEvalStepAndPredicates (steps, nodeList, currentNode, exprContext, currentPos, docOrder, cbs, result, errMsg); CHECK_RC; first = 0; } else { DBG( fprintf(stderr, "doing location step nodeList->nr_nodes=%ld \n", nodeList->nr_nodes); ) if (result->type != xNodeSetResult) { xpathRSFree (result); xpathRSInit (result); *nodeList = savedContext; return 0; } *nodeList = *result; xpathRSInit (result); for (i=0; inr_nodes; i++) { rc = xpathEvalStepAndPredicates (steps, nodeList, nodeList->nodes[i], exprContext, i, docOrder, cbs, result, errMsg); if (rc) { xpathRSFree (result); xpathRSFree (nodeList); return rc; } } xpathRSFree (nodeList); } DBG( fprintf(stderr, "result after location step: \n"); ) DBG( rsPrint( result); ) steps = steps->next; /* skip the already processed Predicate parts */ while (steps && steps->type == Pred) steps = steps->next; *docOrder = 1; } *nodeList = savedContext; return 0; } /*---------------------------------------------------------------------------- | xpathEval | \---------------------------------------------------------------------------*/ int xpathEval ( domNode * node, domNode * exprContext, char * xpath, char ** prefixMappings, xpathCBs * cbs, xpathParseVarCB * parseVarCB, Tcl_HashTable * cache, char ** errMsg, xpathResultSet * result ) { xpathResultSet nodeList; int rc, hnew = 1, docOrder = 1; ast t; Tcl_HashEntry *h = NULL; *errMsg = NULL; if (cache) { h = Tcl_CreateHashEntry (cache, xpath, &hnew); } if (hnew) { rc = xpathParse(xpath, exprContext, XPATH_EXPR, prefixMappings, parseVarCB, &t, errMsg); if (rc) { if (h != NULL) { Tcl_DeleteHashEntry(h); } return rc; } if (cache) { Tcl_SetHashValue(h, t); } } else { t = (ast)Tcl_GetHashValue(h); } xpathRSInit( &nodeList); rsAddNodeFast( &nodeList, node); rc = xpathEvalSteps( t, &nodeList, node, exprContext, 0, &docOrder, cbs, result, errMsg); if (!cache) { freeAst(t); } xpathRSFree( &nodeList ); CHECK_RC; DBG(rsPrint( result );) return 0; } /* xpathEval */ int xpathEvalAst ( ast t, xpathResultSet *nodeList, domNode *node, xpathCBs * cbs, xpathResultSet *rs, char **errMsg ) { int rc, first = 1, docOrder = 1; domLength i; xpathResultSet savedContext; savedContext = *nodeList; while (t) { DBG (fprintf (stderr, "xpathEvalAst: eval step '%s'\n", astType2str[t->type]);) if (t->type == Pred) { *errMsg = "Pred step not expected now!"; return XPATH_EVAL_ERR; } if (first) { rc = xpathEvalStepAndPredicates (t, nodeList, node, node, 0, &docOrder, cbs, rs, errMsg); CHECK_RC; first = 0; } else { DBG( fprintf(stderr, "doing location step nodeList->nr_nodes=%ld \n", nodeList->nr_nodes); ) if (rs->type != xNodeSetResult) { *nodeList = savedContext; return 0; } *nodeList = *rs; xpathRSReset (rs, NULL); for (i=0; i < nodeList->nr_nodes; i++) { rc = xpathEvalStepAndPredicates (t, nodeList, nodeList->nodes[i], node, i, &docOrder, NULL, rs, errMsg); if (rc) { *nodeList = savedContext; return rc; } } } DBG( fprintf(stderr, "result after location step: \n"); ) DBG( rsPrint( result); ) t = t->next; /* skip the already processed Predicate parts */ while (t && t->type == Pred) t = t->next; docOrder = 1; } *nodeList = savedContext; return 0; } /*---------------------------------------------------------------------------- | xpathMatches | \---------------------------------------------------------------------------*/ int xpathMatches ( ast step, domNode * exprContext, domNode * nodeToMatch, xpathCBs * cbs, char ** errMsg ) { xpathResultSet stepResult, nodeList, newNodeList; ast childSteps; int rc, nodeMatches, docOrder = 1; domLength currentPos = 0, i, j; int useFastAdd; const char *localName = NULL, *nodeUri; domAttrNode *attr; domNode *child; DBG(printAst(3,step)); xpathRSInit (&nodeList); while (step) { TRACE1("xpathMatches type=%d \n", step->type); if (nodeList.nr_nodes == 0) useFastAdd = 1; else useFastAdd = 0; switch (step->type) { case AxisAttribute: if (step->child->type != IsAttr && step->child->type != IsNSAttr) { if (step->child->type == IsElement) { step->child->type = IsAttr; } else { DBG(fprintf(stderr, "strange: AxisAttribute with no IsAttr below!\n");) xpathRSFree (&nodeList); return 0; } } attr = NULL; if (nodeToMatch->nodeType == ATTRIBUTE_NODE) { rc = xpathMatches (step->child, exprContext, nodeToMatch, cbs, errMsg); DBG(fprintf(stderr, "rc=%d attribute match\n", rc); ) if (rc != 1) { xpathRSFree (&nodeList); return 0; } attr = (domAttrNode*) nodeToMatch; } else { xpathRSFree (&nodeList); return 0; } if (attr == NULL) { xpathRSFree (&nodeList); return 0; } break; case AxisChild: if (step->child->type == IsElement) { if (nodeToMatch->nodeType != ELEMENT_NODE) { xpathRSFree (&nodeList); return 0; } if (nodeToMatch == nodeToMatch->ownerDocument->rootNode) { xpathRSFree (&nodeList); return 0; } if ((step->child->strvalue[0] != '*') || (step->child->strvalue[1] != '\0') || (step->child->intvalue != 0)) { if (nodeToMatch->namespace) return 0; if (strcmp(nodeToMatch->nodeName, step->child->strvalue)!=0) { xpathRSFree (&nodeList); return 0; } } break; } if (step->child->type == IsFQElement) { if (nodeToMatch->nodeType != ELEMENT_NODE) { xpathRSFree (&nodeList); return 0; } nodeUri = domNamespaceURI (nodeToMatch); if (!nodeUri) { xpathRSFree (&nodeList); return 0; } if (strcmp (step->child->strvalue, nodeUri) != 0) { xpathRSFree (&nodeList); return 0; } localName = domGetLocalName (nodeToMatch->nodeName); if (!localName) { xpathRSFree (&nodeList); return 0; } if (strcmp (step->child->child->strvalue, localName)!=0) { xpathRSFree (&nodeList); return 0; } break; } if (step->child->type == IsNSElement) { nodeUri = domNamespaceURI (nodeToMatch); if (!nodeUri) { xpathRSFree (&nodeList); return 0; } if (strcmp (step->child->strvalue, nodeUri)!=0) { xpathRSFree (&nodeList); return 0; } break; } DBG(fprintf(stderr, "strange: AxisChild with no IsElement, IsFQElement or IsNSElement below!\n");) xpathRSFree (&nodeList); return 0; case IsElement: if (nodeToMatch->nodeType != ELEMENT_NODE) { xpathRSFree (&nodeList); return 0; } if (nodeToMatch == nodeToMatch->ownerDocument->rootNode) { xpathRSFree (&nodeList); return 0; } if ((step->strvalue[0] != '*') || (step->strvalue[1] != '\0') || (step->intvalue != 0)) { if (nodeToMatch->namespace) return 0; if (strcmp(nodeToMatch->nodeName, step->strvalue)!=0) { xpathRSFree (&nodeList); return 0; } } break; case IsFQElement: if (nodeToMatch->nodeType != ELEMENT_NODE) { xpathRSFree (&nodeList); return 0; } nodeUri = domNamespaceURI (nodeToMatch); if (!nodeUri) { xpathRSFree (&nodeList); return 0; } if (strcmp (step->strvalue, nodeUri) != 0) { xpathRSFree (&nodeList); return 0; } localName = domGetLocalName (nodeToMatch->nodeName); if (!localName) { xpathRSFree (&nodeList); return 0; } if (strcmp (step->child->strvalue, localName)!=0) { xpathRSFree (&nodeList); return 0; } break; case IsNSElement: nodeUri = domNamespaceURI (nodeToMatch); if (!nodeUri) { xpathRSFree (&nodeList); return 0; } if (strcmp (step->strvalue, nodeUri)!=0) { xpathRSFree (&nodeList); return 0; } break; case IsAttr: if ((nodeToMatch->nodeType != ATTRIBUTE_NODE) || (nodeToMatch->nodeFlags & IS_NS_NODE)) { xpathRSFree (&nodeList); return 0; } if (!((step->strvalue[0] == '*') && (step->strvalue[1] == '\0'))) { if (strcmp( ((domAttrNode*)nodeToMatch)->nodeName, step->strvalue)!=0) { xpathRSFree (&nodeList); return 0; } } break; case IsNSAttr: if ((nodeToMatch->nodeType != ATTRIBUTE_NODE) || (nodeToMatch->nodeFlags & IS_NS_NODE)) { xpathRSFree (&nodeList); return 0; } nodeUri = domNamespaceURI (nodeToMatch); if (!nodeUri) { xpathRSFree (&nodeList); return 0; } if (strcmp (step->strvalue, nodeUri) != 0) { xpathRSFree (&nodeList); return 0; } if (strcmp (step->child->strvalue, "*")==0) break; localName = domGetLocalName (((domAttrNode *)nodeToMatch)->nodeName); if (!localName) { xpathRSFree (&nodeList); return 0; } if (strcmp (step->child->strvalue, localName)!=0) { xpathRSFree (&nodeList); return 0; } break; case IsNode: DBG(fprintf(stderr, "IsNode: nodeTpye=%d \n", nodeToMatch->nodeType);) if (nodeToMatch->nodeType == ATTRIBUTE_NODE) { xpathRSFree (&nodeList); return 0; } if ((nodeToMatch->nodeType == ELEMENT_NODE) && (nodeToMatch->ownerDocument->rootNode == nodeToMatch)) { xpathRSFree (&nodeList); return 0; } break; case IsText: if (nodeToMatch->nodeType != TEXT_NODE) { xpathRSFree (&nodeList); return 0; } break; case IsPI: if (nodeToMatch->nodeType != PROCESSING_INSTRUCTION_NODE) { xpathRSFree (&nodeList); return 0; } break; case IsSpecificPI: if (nodeToMatch->nodeType != PROCESSING_INSTRUCTION_NODE) { xpathRSFree (&nodeList); return 0; } if (strncmp(((domProcessingInstructionNode*)nodeToMatch)->targetValue, step->strvalue, ((domProcessingInstructionNode*)nodeToMatch)->targetLength) != 0) { xpathRSFree (&nodeList); return 0; } break; case IsComment: if (nodeToMatch->nodeType != COMMENT_NODE) { xpathRSFree (&nodeList); return 0; } break; case IsRoot: if (nodeToMatch->nodeType == ATTRIBUTE_NODE) { xpathRSFree (&nodeList); return 0; } if (nodeToMatch != nodeToMatch->ownerDocument->rootNode) { xpathRSFree (&nodeList); return 0; } break; case ToParent: if (nodeToMatch->nodeType == ATTRIBUTE_NODE) { nodeToMatch = ((domAttrNode *)nodeToMatch)->parentNode; break; } if (nodeToMatch == nodeToMatch->ownerDocument->rootNode) { xpathRSFree (&nodeList); return 0; } if (nodeToMatch->parentNode) { nodeToMatch = nodeToMatch->parentNode; } else { nodeToMatch = nodeToMatch->ownerDocument->rootNode; } break; case ToAncestors: if (step->next == NULL) { xpathRSFree (&nodeList); return 1;} while (1) { if (nodeToMatch->nodeType == ATTRIBUTE_NODE) { nodeToMatch = ((domAttrNode *)nodeToMatch)->parentNode; } else { if (nodeToMatch == nodeToMatch->ownerDocument->rootNode) { xpathRSFree (&nodeList); return 0; } if (nodeToMatch->parentNode) { nodeToMatch = nodeToMatch->parentNode; } else { nodeToMatch = nodeToMatch->ownerDocument->rootNode; } } if (step->next == NULL) { xpathRSFree (&nodeList); return 0; } rc = xpathMatches (step->next, exprContext, nodeToMatch, cbs, errMsg); if (rc == 1) break; } break; case FillWithCurrentNode: checkRsAddNode( &nodeList, nodeToMatch); currentPos = 0; DBG( fprintf(stderr, "FillWithCurrentNode:\n"); rsPrint(&nodeList); ) break; case FillNodeList: if (nodeToMatch->nodeType == ATTRIBUTE_NODE) { child = (domNode*) ((domAttrNode*)nodeToMatch)->parentNode->firstAttr; DBG(fprintf(stderr, "FillNodeList all attribute\n");) } else { if (nodeToMatch->ownerDocument->rootNode == nodeToMatch) { xpathRSFree (&nodeList); return 0; } DBG(if (nodeToMatch->parentNode) { fprintf(stderr, "FillNodeList on %s/%s...\n", nodeToMatch->parentNode->nodeName,nodeToMatch->nodeName); } else { fprintf(stderr, "FillNodeList on (null)/%s...\n", nodeToMatch->nodeName); } fprintf (stderr, "Current nodeList is:\n"); rsPrint (&nodeList); ) if (nodeToMatch->parentNode == NULL) { child = nodeToMatch->ownerDocument->rootNode->firstChild; } else { child = nodeToMatch->parentNode->firstChild; } } currentPos = -1; i = 0; while (child) { rc = xpathMatches (step->child, exprContext, child, cbs, errMsg); if (rc == 1) { checkRsAddNode( &nodeList, child); if (child == nodeToMatch) currentPos = i; i++; if (step->intvalue && i >= step->intvalue) break; } if (child->nodeType == ATTRIBUTE_NODE) { child = (domNode*) ((domAttrNode*)child)->nextSibling; } else { child = child->nextSibling; } } DBG( rsPrint(&nodeList); fprintf(stderr, "currentPos = %d \n", currentPos); ) break; case Pred: xpathRSInit (&stepResult); DBG(fprintf(stderr, "Before Pred inner EvalStep. currentPos = %d\n", currentPos);) rc = xpathEvalStep (step->child, nodeToMatch, exprContext, currentPos, &nodeList, cbs, &stepResult, &docOrder, errMsg); CHECK_RC; DBG( fprintf(stderr, "Pred inner EvalStep returned\n"); rsPrint(&stepResult); ) nodeMatches = 0; if (stepResult.type == RealResult) { stepResult.type = IntResult; stepResult.intvalue = xpathRound(stepResult.realvalue); } if (stepResult.type == IntResult) { if (stepResult.intvalue < 0) { stepResult.intvalue = nodeList.nr_nodes + stepResult.intvalue; } if ((stepResult.intvalue > 0 ) && (stepResult.intvalue <= nodeList.nr_nodes) && (stepResult.intvalue == (currentPos+1)) ) { nodeMatches = 1; } } else if (xpathFuncBoolean(&stepResult)) { nodeMatches = 1; } xpathRSFree (&stepResult); /* if nodeMatches == false we don't have to continue to filter */ if (!nodeMatches) { xpathRSFree (&nodeList); return 0; } /* if the nr_nodes of nodeList is > 1 (i.e. we filter a FillNodeList step, not only a FillWithCurrentNode step), build the resulting nodeList context after this predicate */ if (nodeList.nr_nodes > 1) { xpathRSInit (&newNodeList); currentPos = -1; j = 0; for (i = 0; i < nodeList.nr_nodes; i++) { xpathRSInit (&stepResult); docOrder = 1; rc = xpathEvalStep (step->child, nodeList.nodes[i], exprContext, i, &nodeList, cbs, &stepResult, &docOrder, errMsg); if (rc) { xpathRSFree (&stepResult); xpathRSFree (&newNodeList); xpathRSFree (&nodeList); return rc; } nodeMatches = 0; if (stepResult.type == RealResult) { stepResult.type = IntResult; stepResult.intvalue = xpathRound(stepResult.realvalue); } if (stepResult.type == IntResult) { if (stepResult.intvalue < 0) { stepResult.intvalue = nodeList.nr_nodes + stepResult.intvalue; } if ((stepResult.intvalue > 0 ) && (stepResult.intvalue <= nodeList.nr_nodes) && (stepResult.intvalue == (currentPos+1)) ) { nodeMatches = 1; } } else if (xpathFuncBoolean(&stepResult)) { nodeMatches = 1; } if (nodeMatches) { checkRsAddNode (&newNodeList, nodeList.nodes[i]); if (nodeList.nodes[i] == nodeToMatch) { currentPos = j; } j++; } xpathRSFree (&stepResult); } xpathRSFree (&nodeList); nodeList = newNodeList; } break; case CombinePath: childSteps = step->child; while (childSteps) { rc = xpathMatches (childSteps->child, exprContext, nodeToMatch, cbs, errMsg); if (rc == 1) break; childSteps = childSteps->next; } if (childSteps == NULL) { xpathRSFree (&nodeList); return 0; } break; case ExecIdKey: xpathRSInit (&stepResult); rc = xpathEvalStep (step, nodeToMatch, exprContext, currentPos, &nodeList, cbs, &stepResult, &docOrder, errMsg); CHECK_RC; if (stepResult.type != xNodeSetResult) { xpathRSFree (&stepResult); xpathRSFree (&nodeList); return 0; } nodeMatches = 0; for (i = 0; i < stepResult.nr_nodes; i++) { if (nodeToMatch == stepResult.nodes[i]) { nodeMatches = 1; break; } } xpathRSFree (&stepResult); if (!nodeMatches) { xpathRSFree (&nodeList); return 0; } break; default: DBG( fprintf(stderr, "wrong type %d for xpathMatches \n", step->type); fprintf(stderr, "AST:\n"); ) printAst (0, step); xpathRSFree (&nodeList); return 0; break; } step = step->next; } xpathRSFree (&nodeList); return 1; } /*---------------------------------------------------------------------------- | xpathGetPrio | \---------------------------------------------------------------------------*/ double xpathGetPrio ( ast steps ) { if (!steps) return 0.0; DBG(printAst(0, steps);) if (steps->next == NULL) { if (steps->type == IsElement) { if (strcmp(steps->strvalue, "*")==0 && steps->intvalue==0) { return -0.5; } else { return 0.0; } } else if (steps->type == IsFQElement) { return 0.0; } else if (steps->type == IsNSElement) { return -0.25; } else if (steps->type == IsAttr) { if (strcmp(steps->strvalue, "*")==0) { return -0.5; } else { return 0.0; } } else if (steps->type == IsNSAttr) { if (strcmp(steps->child->strvalue, "*")==0) { return -0.25; } else { return 0.0; } } else if (steps->type == IsSpecificPI) { return 0.0; } else if ( steps->type == IsNode || steps->type == IsText || steps->type == IsPI || steps->type == IsComment ) { return -0.5; } else if ( steps->type == AxisChild || steps->type == AxisAttribute || steps->type == EvalSteps ) { return (xpathGetPrio (steps->child)); } } return 0.5; } /* xpathGetPrio */ /*---------------------------------------------------------------------------- | nodeToXPath - returns a XPath addressing exactly the given node | \---------------------------------------------------------------------------*/ static void nodeToXPath ( domNode * node, char ** xpath, domLength * xpathLen, domLength * xpathAllocated, int legacy ) { domNode *parent, *child; char step[200], *nTest; domLength len; int sameNodes, nodeIndex; parent = node->parentNode; if (parent == NULL) { parent = node->ownerDocument->rootNode; } else { nodeToXPath (parent, xpath, xpathLen, xpathAllocated, legacy); } step[0] = '\0'; switch (node->nodeType) { case ELEMENT_NODE: nodeIndex = 0; sameNodes = 0; child = parent->firstChild; if (node->namespace && !legacy) { while (child) { if (child->nodeType == ELEMENT_NODE) { sameNodes++; if (node == child) { nodeIndex = sameNodes; if (sameNodes > 1) break; } } child = child->nextSibling; } if (sameNodes == 1) { sprintf(step, "/*"); } else { sprintf(step, "/*[%d]", nodeIndex); } } else { while (child) { if (strcmp(child->nodeName, node->nodeName)==0) { sameNodes++; if (node == child) nodeIndex = sameNodes; if ((nodeIndex != 0) && (sameNodes > 2)) break; } child = child->nextSibling; } if (sameNodes == 1) { sprintf(step, "/%s", node->nodeName); } else { sprintf(step, "/%s[%d]", node->nodeName, nodeIndex); } } break; case TEXT_NODE: case COMMENT_NODE: case PROCESSING_INSTRUCTION_NODE: nodeIndex = 0; sameNodes = 0; child = parent->firstChild; while (child) { if (child->nodeType == node->nodeType) { sameNodes++; if (node == child) nodeIndex = sameNodes; if ((nodeIndex != 0) && (sameNodes > 2)) break; } child = child->nextSibling; } switch (node->nodeType) { case TEXT_NODE: nTest = "text()"; break; case COMMENT_NODE: nTest = "comment()"; break; case PROCESSING_INSTRUCTION_NODE: nTest = "processing-instruction()"; break; default: nTest = "unknownNodeType()"; } if (sameNodes == 1) { sprintf(step, "/%s", nTest); } else { sprintf(step, "/%s[%d]", nTest, nodeIndex); } break; default: break; } len = (domLength)strlen(step); if ( (len + *xpathLen) > *xpathAllocated ) { *xpathAllocated = *xpathAllocated * 2; *xpath = REALLOC(*xpath, *xpathAllocated + 1); } strcpy( *xpath + *xpathLen, step); *xpathLen += len; } /* nodeToXPath */ /*---------------------------------------------------------------------------- | xpathNodeToXPath | \---------------------------------------------------------------------------*/ char * xpathNodeToXPath ( domNode *node, int legacy ) { char * xpath; domLength xpathLen, xpathAllocated; xpathAllocated = 100; xpathLen = 0; xpath = MALLOC(xpathAllocated + 1); nodeToXPath (node, &xpath, &xpathLen, &xpathAllocated, legacy); return xpath; } /* xpathNodeToXPath */ tdom-0.9.6-src/generic/tdom.decls0000644000175000017500000000445715025767703015365 0ustar rolfrolf# tdom.decls -- # # This file contains the declarations for all supported public # functions that are exported by the tDOM library via the stubs table. # # Copyright (c) 2002 Rolf Ade. library tdom interface tdom #hooks {} declare 0 generic { int TclExpatObjCmd (ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) } declare 1 generic { int CheckExpatParserObj (Tcl_Interp *interp, Tcl_Obj *const nameObj) } declare 2 generic { int CHandlerSetInstall (Tcl_Interp *interp, Tcl_Obj *const expatObj, CHandlerSet *handlerSet) } declare 3 generic { int CHandlerSetRemove (Tcl_Interp *interp, Tcl_Obj *const expatObj, char *handlerSetName) } declare 4 generic { CHandlerSet * CHandlerSetCreate (const char *name) } declare 5 generic { CHandlerSet * CHandlerSetGet (Tcl_Interp *interp, Tcl_Obj *const expatObj, char *handlerSetName) } declare 6 generic { void * CHandlerSetGetUserData (Tcl_Interp *interp, Tcl_Obj *const expatObj, char *handlerSetName) } declare 7 generic { TclGenExpatInfo * GetExpatInfo (Tcl_Interp *interp, Tcl_Obj *const expatObj) } declare 8 generic { XML_Size XML_GetCurrentLineNumber(XML_Parser parser) } declare 9 generic { XML_Size XML_GetCurrentColumnNumber(XML_Parser parser) } declare 10 generic { XML_Index XML_GetCurrentByteIndex(XML_Parser parser) } declare 11 generic { int XML_GetCurrentByteCount(XML_Parser parser) } declare 12 generic { enum XML_Status XML_SetBase(XML_Parser parser, const XML_Char *base) } declare 13 generic { const XML_Char * XML_GetBase(XML_Parser parser) } declare 14 generic { int XML_GetSpecifiedAttributeCount(XML_Parser parser) } declare 15 generic { int XML_GetIdAttributeIndex(XML_Parser parser) } declare 16 generic { domNode * tcldom_getNodeFromName(Tcl_Interp *interp, char *nodeName, char **errMsg) } declare 17 generic { domDocument * tcldom_getDocumentFromName (Tcl_Interp *interp, char *docName, char **errMsg) } declare 18 generic { SchemaData * tdomGetSchemadata (void) } tdom-0.9.6-src/generic/tdomStubInit.c0000644000175000017500000000171515025767703016171 0ustar rolfrolf /* This is generated by the getStubs.tcl tool (see the Tcl distribution) out of the tdom.decls file */ #ifdef USE_TCL_STUBS #include /* !BEGIN!: Do not edit below this line. */ const TdomStubs tdomStubs = { TCL_STUB_MAGIC, 0, TclExpatObjCmd, /* 0 */ CheckExpatParserObj, /* 1 */ CHandlerSetInstall, /* 2 */ CHandlerSetRemove, /* 3 */ CHandlerSetCreate, /* 4 */ CHandlerSetGet, /* 5 */ CHandlerSetGetUserData, /* 6 */ GetExpatInfo, /* 7 */ XML_GetCurrentLineNumber, /* 8 */ XML_GetCurrentColumnNumber, /* 9 */ XML_GetCurrentByteIndex, /* 10 */ XML_GetCurrentByteCount, /* 11 */ XML_SetBase, /* 12 */ XML_GetBase, /* 13 */ XML_GetSpecifiedAttributeCount, /* 14 */ XML_GetIdAttributeIndex, /* 15 */ tcldom_getNodeFromName, /* 16 */ tcldom_getDocumentFromName, /* 17 */ tdomGetSchemadata, /* 18 */ }; /* !END!: Do not edit above this line. */ #endif /* USE_TCL_STUBS */ tdom-0.9.6-src/generic/domhtml5.c0000644000175000017500000003154015025767703015274 0ustar rolfrolf/*---------------------------------------------------------------------------- | Copyright (c) 2017 Rolf Ade (rolf@pointsman.de) |----------------------------------------------------------------------------- | | | The contents of this file are subject to the Mozilla Public License | Version 2.0 (the "License"); you may not use this file except in | compliance with the License. You may obtain a copy of the License at | http://www.mozilla.org/MPL/ | | Software distributed under the License is distributed on an "AS IS" | basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the | License for the specific language governing rights and limitations | under the License. | | Contributor(s): | | | written by Rolf Ade | March 2017 | \---------------------------------------------------------------------------*/ #ifdef TDOM_HAVE_GUMBO #define MAX_TAG_LEN 201 /*---------------------------------------------------------------------------- | Includes | \---------------------------------------------------------------------------*/ #include #include #include "gumbo.h" #include static const char *xhtml = "http://www.w3.org/1999/xhtml"; static const char *svg = "http://www.w3.org/2000/svg"; static const char *mathml = "http://www.w3.org/1998/Math/MathML"; static const char *xlink = "http://www.w3.org/1999/xlink"; #ifdef DEBUG # define DBG(x) x #else # define DBG(x) #endif static void convertGumboToDom ( domNode *parent, GumboNode *gumboParent, int ignoreWhiteSpaces, int ignorexmlns ) { int hnew; unsigned int i, j; GumboVector *children = &gumboParent->v.element.children; GumboNode *child; GumboElement *gumboElm; GumboAttribute *gumboAtt; const char *tag; const char *attValue; const char *attUri = NULL; char buf[MAX_TAG_LEN]; domNode *node; domNS *ns; domNodeType nodeType = ALL_NODES; domAttrNode *attr = NULL; Tcl_HashEntry *h; const char *elmns = NULL; for (i = 0; i < children->length; ++i) { child = (GumboNode*) (children->data[i]); switch (child->type) { case GUMBO_NODE_DOCUMENT: assert(false && "This gumbo node type can't happen here."); break; case GUMBO_NODE_ELEMENT: case GUMBO_NODE_TEMPLATE: gumboElm = &child->v.element; tag = gumbo_normalized_tagname(gumboElm->tag); if (!domIsNAME(tag)) { gumbo_tag_from_original_text(&gumboElm->original_tag); if (gumboElm->original_tag.length < MAX_TAG_LEN - 1) { strncpy(&buf[0], gumboElm->original_tag.data, gumboElm->original_tag.length); buf[gumboElm->original_tag.length] = '\0'; Tcl_UtfToLower(&buf[0]); if (!domIsNAME(&buf[0])) { DBG(fprintf (stderr, "invalid tag name '%s'\n", tag);); continue; } tag = &buf[0]; } else { /* Just skip this subtree */ DBG(fprintf(stderr, "long tag: %d bytes\n", gumboElm->original_tag.length);); continue; } } if (!ignorexmlns) { switch (gumboElm->tag_namespace) { case GUMBO_NAMESPACE_HTML: elmns = xhtml; break; case GUMBO_NAMESPACE_SVG: elmns = svg; break; case GUMBO_NAMESPACE_MATHML: elmns = mathml; break; default: /* do nothing */ break; } } if (elmns == NULL) { node = domNewElementNode (parent->ownerDocument, tag); } else { DBG(fprintf (stderr, "namespaced node %s\n", tag);); node = domNewElementNodeNS (parent->ownerDocument, tag, elmns); } domAppendChild(parent, node); for (j = 0; j < gumboElm->attributes.length; ++j) { gumboAtt = gumboElm->attributes.data[j]; /* This is to ensure the same behavior as the -html * parser: if there is just the attribute name given * in the source (as 'selected' on a checkbox) then do * it the XHTML style (att value is the att name, * selected="selected"). If there is any value given * in the source, including the empty string, use * that. See gumbo.h for the details why/how this * works.*/ if (gumboAtt->original_value.data[0] != '"' && gumboAtt->original_value.data[0] != '\'') { attValue = gumboAtt->name; } else { attValue = gumboAtt->value; } if (ignorexmlns) { if (gumboAtt->attr_namespace != GUMBO_ATTR_NAMESPACE_NONE) { if (gumboAtt->original_name.length < MAX_TAG_LEN - 1) { strncpy(&buf[0], gumboAtt->original_name.data, gumboAtt->original_name.length); buf[gumboAtt->original_name.length] = '\0'; Tcl_UtfToLower(&buf[0]); DBG(fprintf (stderr, "original att name: %s\n", &buf[0]);); if (!domIsNAME(&buf[0])) { DBG(fprintf (stderr, "invalid att name '%s'\n", tag);); continue; } domSetAttribute(node, &buf[0], attValue); } else { continue; } } else { attr = domSetAttribute (node, gumboAtt->name, attValue); } } else { attUri = NULL; switch (gumboAtt->attr_namespace) { case GUMBO_ATTR_NAMESPACE_XLINK: DBG(fprintf (stderr, "GUMBO_ATTR_NAMESPACE_XLINK\n");); attUri = xlink; break; case GUMBO_ATTR_NAMESPACE_XMLNS: DBG(fprintf (stderr, "GUMBO_ATTR_NAMESPACE_XMLNS\n");); if (attValue[5] == ':') { ns = domLookupPrefix (node, &(attValue[6])); } else { ns = domLookupPrefix (node, ""); } DBG(fprintf (stderr, "xmns att name: %s\n att value %s\n", gumboAtt->name, attValue);); if (ns) { if (strcmp(ns->uri, attValue) == 0) { /* Namespace already in scope. Skip * this attribute to prevent invalid * double attributes and unnecessary * namespace declarations. */ DBG(fprintf (stderr, "namespace %s already in scope\n", attValue);); continue; } } if (gumboAtt->original_name.length < MAX_TAG_LEN - 1) { strncpy(&buf[0], gumboAtt->original_name.data, gumboAtt->original_name.length); buf[gumboAtt->original_name.length] = '\0'; Tcl_UtfToLower(&buf[0]); DBG(fprintf (stderr, "original att name: %s\n", &buf[0]);); if (!domIsNAME(&buf[0])) { DBG(fprintf (stderr, "invalid att name '%s'\n", tag);); continue; } domSetAttributeNS(node, &buf[0], attValue, NULL, 1); } continue; case GUMBO_ATTR_NAMESPACE_XML: /* The XML namespace is always in scope, nothing * to do. */ continue; default: break; } if (attUri) { if (gumboAtt->original_name.length < MAX_TAG_LEN - 1) { strncpy(&buf[0], gumboAtt->original_name.data, gumboAtt->original_name.length); buf[gumboAtt->original_name.length] = '\0'; Tcl_UtfToLower(&buf[0]); DBG(fprintf (stderr, "original att name: %s\n", &buf[0]);); if (!domIsNAME(&buf[0])) { DBG(fprintf (stderr, "invalid att name '%s'\n", tag);); continue; } } else { continue; } DBG(fprintf (stderr, "name: %s value %s\n", &buf[0], attValue);); attr = domSetAttributeNS (node, &buf[0], attValue, xlink, 0); DBG(fprintf(stderr, "attr: %p\n", attr);); } else { attr = domSetAttribute (node, gumboAtt->name, attValue); } } if (attr) { if (strcmp(gumboAtt->name, "id") == 0) { if (!node->ownerDocument->ids) { node->ownerDocument->ids = (Tcl_HashTable *) MALLOC (sizeof (Tcl_HashTable)); Tcl_InitHashTable ( node->ownerDocument->ids, TCL_STRING_KEYS); } h = Tcl_CreateHashEntry ( node->ownerDocument->ids, gumboAtt->value, &hnew); /* How to resolve in case of duplicates? We follow, what the core dom building code does: the first value in document order wins. */ if (hnew) { Tcl_SetHashValue (h, node); attr->nodeFlags |= IS_ID_ATTRIBUTE; } } } } convertGumboToDom(node, child, ignoreWhiteSpaces, ignorexmlns); break; case GUMBO_NODE_WHITESPACE: if (ignoreWhiteSpaces) { continue; } /* fall through */; case GUMBO_NODE_CDATA: case GUMBO_NODE_TEXT: nodeType = TEXT_NODE /* fall through */; case GUMBO_NODE_COMMENT: if (nodeType == ALL_NODES) nodeType = COMMENT_NODE; node = (domNode*)domNewTextNode(parent->ownerDocument, child->v.text.text, strlen(child->v.text.text), nodeType); domAppendChild(parent, node); break; default: assert(false && "unknown node type"); } } } domDocument * HTML_GumboParseDocument ( char *html, /* Complete text of the XML being parsed. */ int ignoreWhiteSpaces, int ignorexmlns ) { domDocument *doc = domCreateDoc(NULL, 0); GumboOutput *output = gumbo_parse(html); GumboDocument* doctype = & output->document->v.document; /* Generate and populate doctype info. */ doc->doctype = (domDocInfo *)MALLOC(sizeof(domDocInfo)); memset(doc->doctype, 0,(sizeof(domDocInfo))); doc->doctype->publicId = tdomstrdup(doctype->public_identifier); doc->doctype->systemId = tdomstrdup(doctype->system_identifier); convertGumboToDom (doc->rootNode, output->document, ignoreWhiteSpaces, ignorexmlns); domSetDocumentElement (doc); gumbo_destroy_output(&kGumboDefaultOptions, output); return doc; } #else typedef int make_pedantic_compiler_happy; #endif tdom-0.9.6-src/generic/aolstub.cpp0000644000175000017500000000434415025767703015556 0ustar rolfrolf/* * aolstub.cpp -- * * Adds interface for loading the extension into the AOLserver. * * See the file "LICENSE" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * Rcsid: @(#)$Id$ * --------------------------------------------------------------------------- */ #if defined (NS_AOLSERVER) #include int Ns_ModuleVersion = 1; /* * Structure to pass to NsThread_Init. This holds the module * and virtual server name for proper interp initializations. * This is valid only for AOLservers 4.x or later. */ struct mydata { char *modname; char *server; }; /* *---------------------------------------------------------------------------- * * NsTdom_Init -- * * Loads the package in the Tcl interpreter. * * Results: * Standard Tcl result * * Side effects: * Package initialized. Tcl commands created. * *---------------------------------------------------------------------------- */ static int NsTdom_Init (Tcl_Interp *interp, void *cd) { struct mydata *md = (struct mydata*)cd; int ret = Tdom_Init(interp); if (ret != TCL_OK) { Ns_Log(Warning, "can't load module %s: %s", md->modname, Tcl_GetStringResult(interp)); } Tcl_SetAssocData(interp, "tdom:nsd", NULL, (ClientData)md); return TCL_OK; } /* *---------------------------------------------------------------------------- * * Ns_ModuleInit -- * * Called by the AOLserver when loading shared object file. * * Results: * Standard AOLserver result * * Side effects: * Many. Depends on the package. * *---------------------------------------------------------------------------- */ int Ns_ModuleInit(char *srv, char *mod) { struct mydata *md = NULL; md = (struct mydata*)ns_malloc(sizeof(struct mydata)); md->modname = strcpy(ns_malloc(strlen(mod)+1), mod); md->server = strcpy(ns_malloc(strlen(srv)+1), srv); return (Ns_TclInitInterps(srv, NsTdom_Init, (void*)md) == TCL_OK) ? NS_OK : NS_ERROR; } #endif /* NS_AOLSERVER */ /* EOF $RCSfile$ */ /* Emacs Setup Variables */ /* Local Variables: */ /* mode: C */ /* indent-tabs-mode: nil */ /* c-basic-offset: 4 */ /* End: */ tdom-0.9.6-src/generic/HTML5ent.inc0000644000175000017500000033437015025767703015441 0ustar rolfrolfcase 9: AE(" "); break; /* \t */ case 10: AE(" "); break; /* \n */ case 33: AE("!"); break; /* ! */ /* quot aka QUOT */ case 34: AE("""); break; /* " */ case 35: AE("#"); break; /* # */ case 36: AE("$"); break; /* $ */ case 37: AE("%"); break; /* % */ /* amp aka AMP */ case 38: AE("&"); break; /* & */ case 39: AE("'"); break; /* ' */ case 40: AE("("); break; /* ( */ case 41: AE(")"); break; /* ) */ /* ast aka midast */ case 42: AE("*"); break; /* * */ case 43: AE("+"); break; /* + */ case 44: AE(","); break; /* , */ case 46: AE("."); break; /* . */ case 47: AE("/"); break; /* / */ case 58: AE(":"); break; /* : */ case 59: AE(";"); break; /* ; */ case 60: TWOCPE; if (clen2 && uniChar2 == 8402) { AE("<⃒"); MCP; /* <⃒ */ } else { /* lt aka LT */ AE("<"); /* < */ }; break; case 61: TWOCPE; if (clen2 && uniChar2 == 8421) { AE("=⃥"); MCP; /* =⃥ */ } else { AE("="); /* = */ }; break; case 62: TWOCPE; if (clen2 && uniChar2 == 8402) { AE(">⃒"); MCP; /* >⃒ */ } else { /* gt aka GT */ AE(">"); /* > */ }; break; case 63: AE("?"); break; /* ? */ case 64: AE("@"); break; /* @ */ /* lsqb aka lbrack */ case 91: AE("["); break; /* [ */ case 92: AE("\"); break; /* \ */ /* rsqb aka rbrack */ case 93: AE("]"); break; /* ] */ case 94: AE("^"); break; /* ^ */ /* lowbar aka UnderBar */ case 95: AE("_"); break; /* _ */ /* grave aka DiacriticalGrave */ case 96: AE("`"); break; /* ` */ case 102: TWOCPE; if (uniChar2 == 106) { AE("fj"); MCP; /* fj */ } else {charDone = 0;}; break; /* lcub aka lbrace */ case 123: AE("{"); break; /* { */ /* vert aka VerticalLine or verbar */ case 124: AE("|"); break; /* | */ /* rcub aka rbrace */ case 125: AE("}"); break; /* } */ /* nbsp aka NonBreakingSpace */ case 160: AE(" "); break; /*   */ case 161: AE("¡"); break; /* ¡ */ case 162: AE("¢"); break; /* ¢ */ case 163: AE("£"); break; /* £ */ case 164: AE("¤"); break; /* ¤ */ case 165: AE("¥"); break; /* ¥ */ case 166: AE("¦"); break; /* ¦ */ case 167: AE("§"); break; /* § */ /* die aka Dot or DoubleDot or uml */ case 168: AE("¨"); break; /* ¨ */ /* copy aka COPY */ case 169: AE("©"); break; /* © */ case 170: AE("ª"); break; /* ª */ case 171: AE("«"); break; /* « */ case 172: AE("¬"); break; /* ¬ */ case 173: AE("­"); break; /* ­ */ /* reg aka REG or circledR */ case 174: AE("®"); break; /* ® */ /* macr aka strns */ case 175: AE("¯"); break; /* ¯ */ case 176: AE("°"); break; /* ° */ /* pm aka PlusMinus or plusmn */ case 177: AE("±"); break; /* ± */ case 178: AE("²"); break; /* ² */ case 179: AE("³"); break; /* ³ */ /* acute aka DiacriticalAcute */ case 180: AE("´"); break; /* ´ */ case 181: AE("µ"); break; /* µ */ case 182: AE("¶"); break; /* ¶ */ /* middot aka CenterDot or centerdot */ case 183: AE("·"); break; /* · */ /* cedil aka Cedilla */ case 184: AE("¸"); break; /* ¸ */ case 185: AE("¹"); break; /* ¹ */ case 186: AE("º"); break; /* º */ case 187: AE("»"); break; /* » */ case 188: AE("¼"); break; /* ¼ */ /* half aka frac12 */ case 189: AE("½"); break; /* ½ */ case 190: AE("¾"); break; /* ¾ */ case 191: AE("¿"); break; /* ¿ */ case 192: AE("À"); break; /* À */ case 193: AE("Á"); break; /* Á */ case 194: AE("Â"); break; /*  */ case 195: AE("Ã"); break; /* à */ case 196: AE("Ä"); break; /* Ä */ /* angst aka Aring */ case 197: AE("Å"); break; /* Å */ case 198: AE("Æ"); break; /* Æ */ case 199: AE("Ç"); break; /* Ç */ case 200: AE("È"); break; /* È */ case 201: AE("É"); break; /* É */ case 202: AE("Ê"); break; /* Ê */ case 203: AE("Ë"); break; /* Ë */ case 204: AE("Ì"); break; /* Ì */ case 205: AE("Í"); break; /* Í */ case 206: AE("Î"); break; /* Î */ case 207: AE("Ï"); break; /* Ï */ case 208: AE("Ð"); break; /* Ð */ case 209: AE("Ñ"); break; /* Ñ */ case 210: AE("Ò"); break; /* Ò */ case 211: AE("Ó"); break; /* Ó */ case 212: AE("Ô"); break; /* Ô */ case 213: AE("Õ"); break; /* Õ */ case 214: AE("Ö"); break; /* Ö */ case 215: AE("×"); break; /* × */ case 216: AE("Ø"); break; /* Ø */ case 217: AE("Ù"); break; /* Ù */ case 218: AE("Ú"); break; /* Ú */ case 219: AE("Û"); break; /* Û */ case 220: AE("Ü"); break; /* Ü */ case 221: AE("Ý"); break; /* Ý */ case 222: AE("Þ"); break; /* Þ */ case 223: AE("ß"); break; /* ß */ case 224: AE("à"); break; /* à */ case 225: AE("á"); break; /* á */ case 226: AE("â"); break; /* â */ case 227: AE("ã"); break; /* ã */ case 228: AE("ä"); break; /* ä */ case 229: AE("å"); break; /* å */ case 230: AE("æ"); break; /* æ */ case 231: AE("ç"); break; /* ç */ case 232: AE("è"); break; /* è */ case 233: AE("é"); break; /* é */ case 234: AE("ê"); break; /* ê */ case 235: AE("ë"); break; /* ë */ case 236: AE("ì"); break; /* ì */ case 237: AE("í"); break; /* í */ case 238: AE("î"); break; /* î */ case 239: AE("ï"); break; /* ï */ case 240: AE("ð"); break; /* ð */ case 241: AE("ñ"); break; /* ñ */ case 242: AE("ò"); break; /* ò */ case 243: AE("ó"); break; /* ó */ case 244: AE("ô"); break; /* ô */ case 245: AE("õ"); break; /* õ */ case 246: AE("ö"); break; /* ö */ /* div aka divide */ case 247: AE("÷"); break; /* ÷ */ case 248: AE("ø"); break; /* ø */ case 249: AE("ù"); break; /* ù */ case 250: AE("ú"); break; /* ú */ case 251: AE("û"); break; /* û */ case 252: AE("ü"); break; /* ü */ case 253: AE("ý"); break; /* ý */ case 254: AE("þ"); break; /* þ */ case 255: AE("ÿ"); break; /* ÿ */ case 256: AE("Ā"); break; /* Ā */ case 257: AE("ā"); break; /* ā */ case 258: AE("Ă"); break; /* Ă */ case 259: AE("ă"); break; /* ă */ case 260: AE("Ą"); break; /* Ą */ case 261: AE("ą"); break; /* ą */ case 262: AE("Ć"); break; /* Ć */ case 263: AE("ć"); break; /* ć */ case 264: AE("Ĉ"); break; /* Ĉ */ case 265: AE("ĉ"); break; /* ĉ */ case 266: AE("Ċ"); break; /* Ċ */ case 267: AE("ċ"); break; /* ċ */ case 268: AE("Č"); break; /* Č */ case 269: AE("č"); break; /* č */ case 270: AE("Ď"); break; /* Ď */ case 271: AE("ď"); break; /* ď */ case 272: AE("Đ"); break; /* Đ */ case 273: AE("đ"); break; /* đ */ case 274: AE("Ē"); break; /* Ē */ case 275: AE("ē"); break; /* ē */ case 278: AE("Ė"); break; /* Ė */ case 279: AE("ė"); break; /* ė */ case 280: AE("Ę"); break; /* Ę */ case 281: AE("ę"); break; /* ę */ case 282: AE("Ě"); break; /* Ě */ case 283: AE("ě"); break; /* ě */ case 284: AE("Ĝ"); break; /* Ĝ */ case 285: AE("ĝ"); break; /* ĝ */ case 286: AE("Ğ"); break; /* Ğ */ case 287: AE("ğ"); break; /* ğ */ case 288: AE("Ġ"); break; /* Ġ */ case 289: AE("ġ"); break; /* ġ */ case 290: AE("Ģ"); break; /* Ģ */ case 292: AE("Ĥ"); break; /* Ĥ */ case 293: AE("ĥ"); break; /* ĥ */ case 294: AE("Ħ"); break; /* Ħ */ case 295: AE("ħ"); break; /* ħ */ case 296: AE("Ĩ"); break; /* Ĩ */ case 297: AE("ĩ"); break; /* ĩ */ case 298: AE("Ī"); break; /* Ī */ case 299: AE("ī"); break; /* ī */ case 302: AE("Į"); break; /* Į */ case 303: AE("į"); break; /* į */ case 304: AE("İ"); break; /* İ */ /* imath aka inodot */ case 305: AE("ı"); break; /* ı */ case 306: AE("IJ"); break; /* IJ */ case 307: AE("ij"); break; /* ij */ case 308: AE("Ĵ"); break; /* Ĵ */ case 309: AE("ĵ"); break; /* ĵ */ case 310: AE("Ķ"); break; /* Ķ */ case 311: AE("ķ"); break; /* ķ */ case 312: AE("ĸ"); break; /* ĸ */ case 313: AE("Ĺ"); break; /* Ĺ */ case 314: AE("ĺ"); break; /* ĺ */ case 315: AE("Ļ"); break; /* Ļ */ case 316: AE("ļ"); break; /* ļ */ case 317: AE("Ľ"); break; /* Ľ */ case 318: AE("ľ"); break; /* ľ */ case 319: AE("Ŀ"); break; /* Ŀ */ case 320: AE("ŀ"); break; /* ŀ */ case 321: AE("Ł"); break; /* Ł */ case 322: AE("ł"); break; /* ł */ case 323: AE("Ń"); break; /* Ń */ case 324: AE("ń"); break; /* ń */ case 325: AE("Ņ"); break; /* Ņ */ case 326: AE("ņ"); break; /* ņ */ case 327: AE("Ň"); break; /* Ň */ case 328: AE("ň"); break; /* ň */ case 329: AE("ʼn"); break; /* ʼn */ case 330: AE("Ŋ"); break; /* Ŋ */ case 331: AE("ŋ"); break; /* ŋ */ case 332: AE("Ō"); break; /* Ō */ case 333: AE("ō"); break; /* ō */ case 336: AE("Ő"); break; /* Ő */ case 337: AE("ő"); break; /* ő */ case 338: AE("Œ"); break; /* Œ */ case 339: AE("œ"); break; /* œ */ case 340: AE("Ŕ"); break; /* Ŕ */ case 341: AE("ŕ"); break; /* ŕ */ case 342: AE("Ŗ"); break; /* Ŗ */ case 343: AE("ŗ"); break; /* ŗ */ case 344: AE("Ř"); break; /* Ř */ case 345: AE("ř"); break; /* ř */ case 346: AE("Ś"); break; /* Ś */ case 347: AE("ś"); break; /* ś */ case 348: AE("Ŝ"); break; /* Ŝ */ case 349: AE("ŝ"); break; /* ŝ */ case 350: AE("Ş"); break; /* Ş */ case 351: AE("ş"); break; /* ş */ case 352: AE("Š"); break; /* Š */ case 353: AE("š"); break; /* š */ case 354: AE("Ţ"); break; /* Ţ */ case 355: AE("ţ"); break; /* ţ */ case 356: AE("Ť"); break; /* Ť */ case 357: AE("ť"); break; /* ť */ case 358: AE("Ŧ"); break; /* Ŧ */ case 359: AE("ŧ"); break; /* ŧ */ case 360: AE("Ũ"); break; /* Ũ */ case 361: AE("ũ"); break; /* ũ */ case 362: AE("Ū"); break; /* Ū */ case 363: AE("ū"); break; /* ū */ case 364: AE("Ŭ"); break; /* Ŭ */ case 365: AE("ŭ"); break; /* ŭ */ case 366: AE("Ů"); break; /* Ů */ case 367: AE("ů"); break; /* ů */ case 368: AE("Ű"); break; /* Ű */ case 369: AE("ű"); break; /* ű */ case 370: AE("Ų"); break; /* Ų */ case 371: AE("ų"); break; /* ų */ case 372: AE("Ŵ"); break; /* Ŵ */ case 373: AE("ŵ"); break; /* ŵ */ case 374: AE("Ŷ"); break; /* Ŷ */ case 375: AE("ŷ"); break; /* ŷ */ case 376: AE("Ÿ"); break; /* Ÿ */ case 377: AE("Ź"); break; /* Ź */ case 378: AE("ź"); break; /* ź */ case 379: AE("Ż"); break; /* Ż */ case 380: AE("ż"); break; /* ż */ case 381: AE("Ž"); break; /* Ž */ case 382: AE("ž"); break; /* ž */ case 402: AE("ƒ"); break; /* ƒ */ case 437: AE("Ƶ"); break; /* Ƶ */ case 501: AE("ǵ"); break; /* ǵ */ case 567: AE("ȷ"); break; /* ȷ */ case 710: AE("ˆ"); break; /* ˆ */ /* caron aka Hacek */ case 711: AE("ˇ"); break; /* ˇ */ /* breve aka Breve */ case 728: AE("˘"); break; /* ˘ */ /* dot aka DiacriticalDot */ case 729: AE("˙"); break; /* ˙ */ case 730: AE("˚"); break; /* ˚ */ case 731: AE("˛"); break; /* ˛ */ /* tilde aka DiacriticalTilde */ case 732: AE("˜"); break; /* ˜ */ /* dblac aka DiacriticalDoubleAcute */ case 733: AE("˝"); break; /* ˝ */ case 785: AE("̑"); break; /* ̑ */ case 913: AE("Α"); break; /* Α */ case 914: AE("Β"); break; /* Β */ case 915: AE("Γ"); break; /* Γ */ case 916: AE("Δ"); break; /* Δ */ case 917: AE("Ε"); break; /* Ε */ case 918: AE("Ζ"); break; /* Ζ */ case 919: AE("Η"); break; /* Η */ case 920: AE("Θ"); break; /* Θ */ case 921: AE("Ι"); break; /* Ι */ case 922: AE("Κ"); break; /* Κ */ case 923: AE("Λ"); break; /* Λ */ case 924: AE("Μ"); break; /* Μ */ case 925: AE("Ν"); break; /* Ν */ case 926: AE("Ξ"); break; /* Ξ */ case 927: AE("Ο"); break; /* Ο */ case 928: AE("Π"); break; /* Π */ case 929: AE("Ρ"); break; /* Ρ */ case 931: AE("Σ"); break; /* Σ */ case 932: AE("Τ"); break; /* Τ */ case 933: AE("Υ"); break; /* Υ */ case 934: AE("Φ"); break; /* Φ */ case 935: AE("Χ"); break; /* Χ */ case 936: AE("Ψ"); break; /* Ψ */ /* ohm aka Omega */ case 937: AE("Ω"); break; /* Ω */ case 945: AE("α"); break; /* α */ case 946: AE("β"); break; /* β */ case 947: AE("γ"); break; /* γ */ case 948: AE("δ"); break; /* δ */ /* epsi aka epsilon */ case 949: AE("ε"); break; /* ε */ case 950: AE("ζ"); break; /* ζ */ case 951: AE("η"); break; /* η */ case 952: AE("θ"); break; /* θ */ case 953: AE("ι"); break; /* ι */ case 954: AE("κ"); break; /* κ */ case 955: AE("λ"); break; /* λ */ case 956: AE("μ"); break; /* μ */ case 957: AE("ν"); break; /* ν */ case 958: AE("ξ"); break; /* ξ */ case 959: AE("ο"); break; /* ο */ case 960: AE("π"); break; /* π */ case 961: AE("ρ"); break; /* ρ */ /* sigmaf aka sigmav or varsigma */ case 962: AE("ς"); break; /* ς */ case 963: AE("σ"); break; /* σ */ case 964: AE("τ"); break; /* τ */ /* upsi aka upsilon */ case 965: AE("υ"); break; /* υ */ case 966: AE("φ"); break; /* φ */ case 967: AE("χ"); break; /* χ */ case 968: AE("ψ"); break; /* ψ */ case 969: AE("ω"); break; /* ω */ /* thetav aka thetasym or vartheta */ case 977: AE("ϑ"); break; /* ϑ */ /* Upsi aka upsih */ case 978: AE("ϒ"); break; /* ϒ */ /* phiv aka straightphi or varphi */ case 981: AE("ϕ"); break; /* ϕ */ /* piv aka varpi */ case 982: AE("ϖ"); break; /* ϖ */ case 988: AE("Ϝ"); break; /* Ϝ */ /* gammad aka digamma */ case 989: AE("ϝ"); break; /* ϝ */ /* kappav aka varkappa */ case 1008: AE("ϰ"); break; /* ϰ */ /* rhov aka varrho */ case 1009: AE("ϱ"); break; /* ϱ */ /* epsiv aka straightepsilon or varepsilon */ case 1013: AE("ϵ"); break; /* ϵ */ /* bepsi aka backepsilon */ case 1014: AE("϶"); break; /* ϶ */ case 1025: AE("Ё"); break; /* Ё */ case 1026: AE("Ђ"); break; /* Ђ */ case 1027: AE("Ѓ"); break; /* Ѓ */ case 1028: AE("Є"); break; /* Є */ case 1029: AE("Ѕ"); break; /* Ѕ */ case 1030: AE("І"); break; /* І */ case 1031: AE("Ї"); break; /* Ї */ case 1032: AE("Ј"); break; /* Ј */ case 1033: AE("Љ"); break; /* Љ */ case 1034: AE("Њ"); break; /* Њ */ case 1035: AE("Ћ"); break; /* Ћ */ case 1036: AE("Ќ"); break; /* Ќ */ case 1038: AE("Ў"); break; /* Ў */ case 1039: AE("Џ"); break; /* Џ */ case 1040: AE("А"); break; /* А */ case 1041: AE("Б"); break; /* Б */ case 1042: AE("В"); break; /* В */ case 1043: AE("Г"); break; /* Г */ case 1044: AE("Д"); break; /* Д */ case 1045: AE("Е"); break; /* Е */ case 1046: AE("Ж"); break; /* Ж */ case 1047: AE("З"); break; /* З */ case 1048: AE("И"); break; /* И */ case 1049: AE("Й"); break; /* Й */ case 1050: AE("К"); break; /* К */ case 1051: AE("Л"); break; /* Л */ case 1052: AE("М"); break; /* М */ case 1053: AE("Н"); break; /* Н */ case 1054: AE("О"); break; /* О */ case 1055: AE("П"); break; /* П */ case 1056: AE("Р"); break; /* Р */ case 1057: AE("С"); break; /* С */ case 1058: AE("Т"); break; /* Т */ case 1059: AE("У"); break; /* У */ case 1060: AE("Ф"); break; /* Ф */ case 1061: AE("Х"); break; /* Х */ case 1062: AE("Ц"); break; /* Ц */ case 1063: AE("Ч"); break; /* Ч */ case 1064: AE("Ш"); break; /* Ш */ case 1065: AE("Щ"); break; /* Щ */ case 1066: AE("Ъ"); break; /* Ъ */ case 1067: AE("Ы"); break; /* Ы */ case 1068: AE("Ь"); break; /* Ь */ case 1069: AE("Э"); break; /* Э */ case 1070: AE("Ю"); break; /* Ю */ case 1071: AE("Я"); break; /* Я */ case 1072: AE("а"); break; /* а */ case 1073: AE("б"); break; /* б */ case 1074: AE("в"); break; /* в */ case 1075: AE("г"); break; /* г */ case 1076: AE("д"); break; /* д */ case 1077: AE("е"); break; /* е */ case 1078: AE("ж"); break; /* ж */ case 1079: AE("з"); break; /* з */ case 1080: AE("и"); break; /* и */ case 1081: AE("й"); break; /* й */ case 1082: AE("к"); break; /* к */ case 1083: AE("л"); break; /* л */ case 1084: AE("м"); break; /* м */ case 1085: AE("н"); break; /* н */ case 1086: AE("о"); break; /* о */ case 1087: AE("п"); break; /* п */ case 1088: AE("р"); break; /* р */ case 1089: AE("с"); break; /* с */ case 1090: AE("т"); break; /* т */ case 1091: AE("у"); break; /* у */ case 1092: AE("ф"); break; /* ф */ case 1093: AE("х"); break; /* х */ case 1094: AE("ц"); break; /* ц */ case 1095: AE("ч"); break; /* ч */ case 1096: AE("ш"); break; /* ш */ case 1097: AE("щ"); break; /* щ */ case 1098: AE("ъ"); break; /* ъ */ case 1099: AE("ы"); break; /* ы */ case 1100: AE("ь"); break; /* ь */ case 1101: AE("э"); break; /* э */ case 1102: AE("ю"); break; /* ю */ case 1103: AE("я"); break; /* я */ case 1105: AE("ё"); break; /* ё */ case 1106: AE("ђ"); break; /* ђ */ case 1107: AE("ѓ"); break; /* ѓ */ case 1108: AE("є"); break; /* є */ case 1109: AE("ѕ"); break; /* ѕ */ case 1110: AE("і"); break; /* і */ case 1111: AE("ї"); break; /* ї */ case 1112: AE("ј"); break; /* ј */ case 1113: AE("љ"); break; /* љ */ case 1114: AE("њ"); break; /* њ */ case 1115: AE("ћ"); break; /* ћ */ case 1116: AE("ќ"); break; /* ќ */ case 1118: AE("ў"); break; /* ў */ case 1119: AE("џ"); break; /* џ */ case 8194: AE(" "); break; /*   */ case 8195: AE(" "); break; /*   */ case 8196: AE(" "); break; /*   */ case 8197: AE(" "); break; /*   */ case 8199: AE(" "); break; /*   */ case 8200: AE(" "); break; /*   */ /* thinsp aka ThinSpace */ case 8201: AE(" "); break; /*   */ /* hairsp aka VeryThinSpace */ case 8202: AE(" "); break; /*   */ /* ZeroWidthSpace aka NegativeMediumSpace or NegativeThickSpace or NegativeThinSpace or NegativeVeryThinSpace */ case 8203: AE("​"); break; /* ​ */ case 8204: AE("‌"); break; /* ‌ */ case 8205: AE("‍"); break; /* ‍ */ case 8206: AE("‎"); break; /* ‎ */ case 8207: AE("‏"); break; /* ‏ */ /* dash aka hyphen */ case 8208: AE("‐"); break; /* ‐ */ case 8211: AE("–"); break; /* – */ case 8212: AE("—"); break; /* — */ case 8213: AE("―"); break; /* ― */ /* Vert aka Verbar */ case 8214: AE("‖"); break; /* ‖ */ /* lsquo aka OpenCurlyQuote */ case 8216: AE("‘"); break; /* ‘ */ /* rsquo aka CloseCurlyQuote or rsquor */ case 8217: AE("’"); break; /* ’ */ /* sbquo aka lsquor */ case 8218: AE("‚"); break; /* ‚ */ /* ldquo aka OpenCurlyDoubleQuote */ case 8220: AE("“"); break; /* “ */ /* rdquo aka CloseCurlyDoubleQuote or rdquor */ case 8221: AE("”"); break; /* ” */ /* bdquo aka ldquor */ case 8222: AE("„"); break; /* „ */ case 8224: AE("†"); break; /* † */ /* Dagger aka ddagger */ case 8225: AE("‡"); break; /* ‡ */ /* bull aka bullet */ case 8226: AE("•"); break; /* • */ case 8229: AE("‥"); break; /* ‥ */ /* mldr aka hellip */ case 8230: AE("…"); break; /* … */ case 8240: AE("‰"); break; /* ‰ */ case 8241: AE("‱"); break; /* ‱ */ case 8242: AE("′"); break; /* ′ */ case 8243: AE("″"); break; /* ″ */ case 8244: AE("‴"); break; /* ‴ */ /* bprime aka backprime */ case 8245: AE("‵"); break; /* ‵ */ case 8249: AE("‹"); break; /* ‹ */ case 8250: AE("›"); break; /* › */ /* oline aka OverBar */ case 8254: AE("‾"); break; /* ‾ */ case 8257: AE("⁁"); break; /* ⁁ */ case 8259: AE("⁃"); break; /* ⁃ */ case 8260: AE("⁄"); break; /* ⁄ */ case 8271: AE("⁏"); break; /* ⁏ */ case 8279: AE("⁗"); break; /* ⁗ */ case 8287: TWOCPE; if (clen2 && uniChar2 == 8202) { AE("  "); MCP; /*    */ } else { AE(" "); /*   */ }; break; case 8288: AE("⁠"); break; /* ⁠ */ /* af aka ApplyFunction */ case 8289: AE("⁡"); break; /* ⁡ */ /* it aka InvisibleTimes */ case 8290: AE("⁢"); break; /* ⁢ */ /* ic aka InvisibleComma */ case 8291: AE("⁣"); break; /* ⁣ */ case 8364: AE("€"); break; /* € */ /* tdot aka TripleDot */ case 8411: AE("⃛"); break; /* ⃛ */ case 8412: AE("⃜"); break; /* ⃜ */ /* Copf aka complexes */ case 8450: AE("ℂ"); break; /* ℂ */ case 8453: AE("℅"); break; /* ℅ */ case 8458: AE("ℊ"); break; /* ℊ */ /* Hscr aka HilbertSpace or hamilt */ case 8459: AE("ℋ"); break; /* ℋ */ /* Hfr aka Poincareplane */ case 8460: AE("ℌ"); break; /* ℌ */ /* Hopf aka quaternions */ case 8461: AE("ℍ"); break; /* ℍ */ case 8462: AE("ℎ"); break; /* ℎ */ /* hbar aka hslash or planck or plankv */ case 8463: AE("ℏ"); break; /* ℏ */ /* Iscr aka imagline */ case 8464: AE("ℐ"); break; /* ℐ */ /* Im aka Ifr or image or imagpart */ case 8465: AE("ℑ"); break; /* ℑ */ /* Lscr aka Laplacetrf or lagran */ case 8466: AE("ℒ"); break; /* ℒ */ case 8467: AE("ℓ"); break; /* ℓ */ /* Nopf aka naturals */ case 8469: AE("ℕ"); break; /* ℕ */ case 8470: AE("№"); break; /* № */ case 8471: AE("℗"); break; /* ℗ */ /* wp aka weierp */ case 8472: AE("℘"); break; /* ℘ */ /* Popf aka primes */ case 8473: AE("ℙ"); break; /* ℙ */ /* Qopf aka rationals */ case 8474: AE("ℚ"); break; /* ℚ */ /* Rscr aka realine */ case 8475: AE("ℛ"); break; /* ℛ */ /* Re aka Rfr or real or realpart */ case 8476: AE("ℜ"); break; /* ℜ */ /* Ropf aka reals */ case 8477: AE("ℝ"); break; /* ℝ */ case 8478: AE("℞"); break; /* ℞ */ /* trade aka TRADE */ case 8482: AE("™"); break; /* ™ */ /* Zopf aka integers */ case 8484: AE("ℤ"); break; /* ℤ */ case 8487: AE("℧"); break; /* ℧ */ /* Zfr aka zeetrf */ case 8488: AE("ℨ"); break; /* ℨ */ case 8489: AE("℩"); break; /* ℩ */ /* Bscr aka Bernoullis or bernou */ case 8492: AE("ℬ"); break; /* ℬ */ /* Cfr aka Cayleys */ case 8493: AE("ℭ"); break; /* ℭ */ case 8495: AE("ℯ"); break; /* ℯ */ /* Escr aka expectation */ case 8496: AE("ℰ"); break; /* ℰ */ /* Fscr aka Fouriertrf */ case 8497: AE("ℱ"); break; /* ℱ */ /* Mscr aka Mellintrf or phmmat */ case 8499: AE("ℳ"); break; /* ℳ */ /* oscr aka order or orderof */ case 8500: AE("ℴ"); break; /* ℴ */ /* aleph aka alefsym */ case 8501: AE("ℵ"); break; /* ℵ */ case 8502: AE("ℶ"); break; /* ℶ */ case 8503: AE("ℷ"); break; /* ℷ */ case 8504: AE("ℸ"); break; /* ℸ */ /* DD aka CapitalDifferentialD */ case 8517: AE("ⅅ"); break; /* ⅅ */ /* dd aka DifferentialD */ case 8518: AE("ⅆ"); break; /* ⅆ */ /* ee aka ExponentialE or exponentiale */ case 8519: AE("ⅇ"); break; /* ⅇ */ /* ii aka ImaginaryI */ case 8520: AE("ⅈ"); break; /* ⅈ */ case 8531: AE("⅓"); break; /* ⅓ */ case 8532: AE("⅔"); break; /* ⅔ */ case 8533: AE("⅕"); break; /* ⅕ */ case 8534: AE("⅖"); break; /* ⅖ */ case 8535: AE("⅗"); break; /* ⅗ */ case 8536: AE("⅘"); break; /* ⅘ */ case 8537: AE("⅙"); break; /* ⅙ */ case 8538: AE("⅚"); break; /* ⅚ */ case 8539: AE("⅛"); break; /* ⅛ */ case 8540: AE("⅜"); break; /* ⅜ */ case 8541: AE("⅝"); break; /* ⅝ */ case 8542: AE("⅞"); break; /* ⅞ */ /* larr aka LeftArrow or ShortLeftArrow or leftarrow or slarr */ case 8592: AE("←"); break; /* ← */ /* uarr aka ShortUpArrow or UpArrow or uparrow */ case 8593: AE("↑"); break; /* ↑ */ /* rarr aka RightArrow or ShortRightArrow or rightarrow or srarr */ case 8594: AE("→"); break; /* → */ /* darr aka DownArrow or ShortDownArrow or downarrow */ case 8595: AE("↓"); break; /* ↓ */ /* harr aka LeftRightArrow or leftrightarrow */ case 8596: AE("↔"); break; /* ↔ */ /* varr aka UpDownArrow or updownarrow */ case 8597: AE("↕"); break; /* ↕ */ /* nwarr aka UpperLeftArrow or nwarrow */ case 8598: AE("↖"); break; /* ↖ */ /* nearr aka UpperRightArrow or nearrow */ case 8599: AE("↗"); break; /* ↗ */ /* searr aka LowerRightArrow or searrow */ case 8600: AE("↘"); break; /* ↘ */ /* swarr aka LowerLeftArrow or swarrow */ case 8601: AE("↙"); break; /* ↙ */ /* nlarr aka nleftarrow */ case 8602: AE("↚"); break; /* ↚ */ /* nrarr aka nrightarrow */ case 8603: AE("↛"); break; /* ↛ */ case 8605: TWOCPE; if (clen2 && uniChar2 == 824) { AE("↝̸"); MCP; /* ↝̸ */ } else { /* rarrw aka rightsquigarrow */ AE("↝"); /* ↝ */ }; break; /* Larr aka twoheadleftarrow */ case 8606: AE("↞"); break; /* ↞ */ case 8607: AE("↟"); break; /* ↟ */ /* Rarr aka twoheadrightarrow */ case 8608: AE("↠"); break; /* ↠ */ case 8609: AE("↡"); break; /* ↡ */ /* larrtl aka leftarrowtail */ case 8610: AE("↢"); break; /* ↢ */ /* rarrtl aka rightarrowtail */ case 8611: AE("↣"); break; /* ↣ */ /* mapstoleft aka LeftTeeArrow */ case 8612: AE("↤"); break; /* ↤ */ /* mapstoup aka UpTeeArrow */ case 8613: AE("↥"); break; /* ↥ */ /* map aka RightTeeArrow or mapsto */ case 8614: AE("↦"); break; /* ↦ */ /* mapstodown aka DownTeeArrow */ case 8615: AE("↧"); break; /* ↧ */ /* larrhk aka hookleftarrow */ case 8617: AE("↩"); break; /* ↩ */ /* rarrhk aka hookrightarrow */ case 8618: AE("↪"); break; /* ↪ */ /* larrlp aka looparrowleft */ case 8619: AE("↫"); break; /* ↫ */ /* rarrlp aka looparrowright */ case 8620: AE("↬"); break; /* ↬ */ /* harrw aka leftrightsquigarrow */ case 8621: AE("↭"); break; /* ↭ */ /* nharr aka nleftrightarrow */ case 8622: AE("↮"); break; /* ↮ */ /* lsh aka Lsh */ case 8624: AE("↰"); break; /* ↰ */ /* rsh aka Rsh */ case 8625: AE("↱"); break; /* ↱ */ case 8626: AE("↲"); break; /* ↲ */ case 8627: AE("↳"); break; /* ↳ */ case 8629: AE("↵"); break; /* ↵ */ /* cularr aka curvearrowleft */ case 8630: AE("↶"); break; /* ↶ */ /* curarr aka curvearrowright */ case 8631: AE("↷"); break; /* ↷ */ /* olarr aka circlearrowleft */ case 8634: AE("↺"); break; /* ↺ */ /* orarr aka circlearrowright */ case 8635: AE("↻"); break; /* ↻ */ /* lharu aka LeftVector or leftharpoonup */ case 8636: AE("↼"); break; /* ↼ */ /* lhard aka DownLeftVector or leftharpoondown */ case 8637: AE("↽"); break; /* ↽ */ /* uharr aka RightUpVector or upharpoonright */ case 8638: AE("↾"); break; /* ↾ */ /* uharl aka LeftUpVector or upharpoonleft */ case 8639: AE("↿"); break; /* ↿ */ /* rharu aka RightVector or rightharpoonup */ case 8640: AE("⇀"); break; /* ⇀ */ /* rhard aka DownRightVector or rightharpoondown */ case 8641: AE("⇁"); break; /* ⇁ */ /* dharr aka RightDownVector or downharpoonright */ case 8642: AE("⇂"); break; /* ⇂ */ /* dharl aka LeftDownVector or downharpoonleft */ case 8643: AE("⇃"); break; /* ⇃ */ /* rlarr aka RightArrowLeftArrow or rightleftarrows */ case 8644: AE("⇄"); break; /* ⇄ */ /* udarr aka UpArrowDownArrow */ case 8645: AE("⇅"); break; /* ⇅ */ /* lrarr aka LeftArrowRightArrow or leftrightarrows */ case 8646: AE("⇆"); break; /* ⇆ */ /* llarr aka leftleftarrows */ case 8647: AE("⇇"); break; /* ⇇ */ /* uuarr aka upuparrows */ case 8648: AE("⇈"); break; /* ⇈ */ /* rrarr aka rightrightarrows */ case 8649: AE("⇉"); break; /* ⇉ */ /* ddarr aka downdownarrows */ case 8650: AE("⇊"); break; /* ⇊ */ /* lrhar aka ReverseEquilibrium or leftrightharpoons */ case 8651: AE("⇋"); break; /* ⇋ */ /* rlhar aka Equilibrium or rightleftharpoons */ case 8652: AE("⇌"); break; /* ⇌ */ /* nlArr aka nLeftarrow */ case 8653: AE("⇍"); break; /* ⇍ */ /* nhArr aka nLeftrightarrow */ case 8654: AE("⇎"); break; /* ⇎ */ /* nrArr aka nRightarrow */ case 8655: AE("⇏"); break; /* ⇏ */ /* lArr aka DoubleLeftArrow or Leftarrow */ case 8656: AE("⇐"); break; /* ⇐ */ /* uArr aka DoubleUpArrow or Uparrow */ case 8657: AE("⇑"); break; /* ⇑ */ /* rArr aka DoubleRightArrow or Implies or Rightarrow */ case 8658: AE("⇒"); break; /* ⇒ */ /* dArr aka DoubleDownArrow or Downarrow */ case 8659: AE("⇓"); break; /* ⇓ */ /* iff aka DoubleLeftRightArrow or Leftrightarrow or hArr */ case 8660: AE("⇔"); break; /* ⇔ */ /* vArr aka DoubleUpDownArrow or Updownarrow */ case 8661: AE("⇕"); break; /* ⇕ */ case 8662: AE("⇖"); break; /* ⇖ */ case 8663: AE("⇗"); break; /* ⇗ */ case 8664: AE("⇘"); break; /* ⇘ */ case 8665: AE("⇙"); break; /* ⇙ */ /* lAarr aka Lleftarrow */ case 8666: AE("⇚"); break; /* ⇚ */ /* rAarr aka Rrightarrow */ case 8667: AE("⇛"); break; /* ⇛ */ case 8669: AE("⇝"); break; /* ⇝ */ /* larrb aka LeftArrowBar */ case 8676: AE("⇤"); break; /* ⇤ */ /* rarrb aka RightArrowBar */ case 8677: AE("⇥"); break; /* ⇥ */ /* duarr aka DownArrowUpArrow */ case 8693: AE("⇵"); break; /* ⇵ */ case 8701: AE("⇽"); break; /* ⇽ */ case 8702: AE("⇾"); break; /* ⇾ */ case 8703: AE("⇿"); break; /* ⇿ */ /* forall aka ForAll */ case 8704: AE("∀"); break; /* ∀ */ /* comp aka complement */ case 8705: AE("∁"); break; /* ∁ */ case 8706: TWOCPE; if (clen2 && uniChar2 == 824) { AE("∂̸"); MCP; /* ∂̸ */ } else { /* part aka PartialD */ AE("∂"); /* ∂ */ }; break; /* exist aka Exists */ case 8707: AE("∃"); break; /* ∃ */ /* nexist aka NotExists or nexists */ case 8708: AE("∄"); break; /* ∄ */ /* empty aka emptyset or emptyv or varnothing */ case 8709: AE("∅"); break; /* ∅ */ /* Del aka nabla */ case 8711: AE("∇"); break; /* ∇ */ /* in aka Element or isin or isinv */ case 8712: AE("∈"); break; /* ∈ */ /* notin aka NotElement or notinva */ case 8713: AE("∉"); break; /* ∉ */ /* ni aka ReverseElement or SuchThat or niv */ case 8715: AE("∋"); break; /* ∋ */ /* notni aka NotReverseElement or notniva */ case 8716: AE("∌"); break; /* ∌ */ /* prod aka Product */ case 8719: AE("∏"); break; /* ∏ */ /* coprod aka Coproduct */ case 8720: AE("∐"); break; /* ∐ */ /* sum aka Sum */ case 8721: AE("∑"); break; /* ∑ */ case 8722: AE("−"); break; /* − */ /* mp aka MinusPlus or mnplus */ case 8723: AE("∓"); break; /* ∓ */ /* plusdo aka dotplus */ case 8724: AE("∔"); break; /* ∔ */ /* setmn aka Backslash or setminus or smallsetminus or ssetmn */ case 8726: AE("∖"); break; /* ∖ */ case 8727: AE("∗"); break; /* ∗ */ /* compfn aka SmallCircle */ case 8728: AE("∘"); break; /* ∘ */ /* Sqrt aka radic */ case 8730: AE("√"); break; /* √ */ /* prop aka Proportional or propto or varpropto or vprop */ case 8733: AE("∝"); break; /* ∝ */ case 8734: AE("∞"); break; /* ∞ */ case 8735: AE("∟"); break; /* ∟ */ case 8736: TWOCPE; if (clen2 && uniChar2 == 8402) { AE("∠⃒"); MCP; /* ∠⃒ */ } else { /* ang aka angle */ AE("∠"); /* ∠ */ }; break; /* angmsd aka measuredangle */ case 8737: AE("∡"); break; /* ∡ */ case 8738: AE("∢"); break; /* ∢ */ /* mid aka VerticalBar or shortmid or smid */ case 8739: AE("∣"); break; /* ∣ */ /* nmid aka NotVerticalBar or nshortmid or nsmid */ case 8740: AE("∤"); break; /* ∤ */ /* par aka DoubleVerticalBar or parallel or shortparallel or spar */ case 8741: AE("∥"); break; /* ∥ */ /* npar aka NotDoubleVerticalBar or nparallel or nshortparallel or nspar */ case 8742: AE("∦"); break; /* ∦ */ /* and aka wedge */ case 8743: AE("∧"); break; /* ∧ */ /* or aka vee */ case 8744: AE("∨"); break; /* ∨ */ case 8745: TWOCPE; if (clen2 && uniChar2 == 65024) { AE("∩︀"); MCP; /* ∩︀ */ } else { AE("∩"); /* ∩ */ }; break; case 8746: TWOCPE; if (clen2 && uniChar2 == 65024) { AE("∪︀"); MCP; /* ∪︀ */ } else { AE("∪"); /* ∪ */ }; break; /* int aka Integral */ case 8747: AE("∫"); break; /* ∫ */ case 8748: AE("∬"); break; /* ∬ */ /* tint aka iiint */ case 8749: AE("∭"); break; /* ∭ */ /* oint aka ContourIntegral or conint */ case 8750: AE("∮"); break; /* ∮ */ /* Conint aka DoubleContourIntegral */ case 8751: AE("∯"); break; /* ∯ */ case 8752: AE("∰"); break; /* ∰ */ case 8753: AE("∱"); break; /* ∱ */ /* cwconint aka ClockwiseContourIntegral */ case 8754: AE("∲"); break; /* ∲ */ /* awconint aka CounterClockwiseContourIntegral */ case 8755: AE("∳"); break; /* ∳ */ /* there4 aka Therefore or therefore */ case 8756: AE("∴"); break; /* ∴ */ /* becaus aka Because or because */ case 8757: AE("∵"); break; /* ∵ */ case 8758: AE("∶"); break; /* ∶ */ /* Colon aka Proportion */ case 8759: AE("∷"); break; /* ∷ */ /* minusd aka dotminus */ case 8760: AE("∸"); break; /* ∸ */ case 8762: AE("∺"); break; /* ∺ */ case 8763: AE("∻"); break; /* ∻ */ case 8764: TWOCPE; if (clen2 && uniChar2 == 8402) { AE("∼⃒"); MCP; /* ∼⃒ */ } else { /* sim aka Tilde or thicksim or thksim */ AE("∼"); /* ∼ */ }; break; case 8765: TWOCPE; if (clen2 && uniChar2 == 817) { AE("∽̱"); MCP; /* ∽̱ */ } else { /* bsim aka backsim */ AE("∽"); /* ∽ */ }; break; case 8766: TWOCPE; if (clen2 && uniChar2 == 819) { AE("∾̳"); MCP; /* ∾̳ */ } else { /* ac aka mstpos */ AE("∾"); /* ∾ */ }; break; case 8767: AE("∿"); break; /* ∿ */ /* wr aka VerticalTilde or wreath */ case 8768: AE("≀"); break; /* ≀ */ /* nsim aka NotTilde */ case 8769: AE("≁"); break; /* ≁ */ case 8770: TWOCPE; if (clen2 && uniChar2 == 824) { /* esim aka NotEqualTilde */ AE("≂̸"); MCP; /* ≂̸ */ } else { /* esim aka EqualTilde or eqsim */ AE("≂"); /* ≂ */ }; break; /* sime aka TildeEqual or simeq */ case 8771: AE("≃"); break; /* ≃ */ /* nsime aka NotTildeEqual or nsimeq */ case 8772: AE("≄"); break; /* ≄ */ /* cong aka TildeFullEqual */ case 8773: AE("≅"); break; /* ≅ */ case 8774: AE("≆"); break; /* ≆ */ /* ncong aka NotTildeFullEqual */ case 8775: AE("≇"); break; /* ≇ */ /* ap aka TildeTilde or approx or asymp or thickapprox or thkap */ case 8776: AE("≈"); break; /* ≈ */ /* nap aka NotTildeTilde or napprox */ case 8777: AE("≉"); break; /* ≉ */ /* ape aka approxeq */ case 8778: AE("≊"); break; /* ≊ */ case 8779: TWOCPE; if (clen2 && uniChar2 == 824) { AE("≋̸"); MCP; /* ≋̸ */ } else { AE("≋"); /* ≋ */ }; break; /* bcong aka backcong */ case 8780: AE("≌"); break; /* ≌ */ case 8781: TWOCPE; if (clen2 && uniChar2 == 8402) { AE("≍⃒"); MCP; /* ≍⃒ */ } else { /* CupCap aka asympeq */ AE("≍"); /* ≍ */ }; break; case 8782: TWOCPE; if (clen2 && uniChar2 == 824) { /* bump aka NotHumpDownHump */ AE("≎̸"); MCP; /* ≎̸ */ } else { /* bump aka Bumpeq or HumpDownHump */ AE("≎"); /* ≎ */ }; break; case 8783: TWOCPE; if (clen2 && uniChar2 == 824) { /* bumpe aka NotHumpEqual */ AE("≏̸"); MCP; /* ≏̸ */ } else { /* bumpe aka HumpEqual or bumpeq */ AE("≏"); /* ≏ */ }; break; case 8784: TWOCPE; if (clen2 && uniChar2 == 824) { AE("≐̸"); MCP; /* ≐̸ */ } else { /* doteq aka DotEqual or esdot */ AE("≐"); /* ≐ */ }; break; /* eDot aka doteqdot */ case 8785: AE("≑"); break; /* ≑ */ /* efDot aka fallingdotseq */ case 8786: AE("≒"); break; /* ≒ */ /* erDot aka risingdotseq */ case 8787: AE("≓"); break; /* ≓ */ /* Assign aka colone or coloneq */ case 8788: AE("≔"); break; /* ≔ */ /* ecolon aka eqcolon */ case 8789: AE("≕"); break; /* ≕ */ /* ecir aka eqcirc */ case 8790: AE("≖"); break; /* ≖ */ /* cire aka circeq */ case 8791: AE("≗"); break; /* ≗ */ case 8793: AE("≙"); break; /* ≙ */ case 8794: AE("≚"); break; /* ≚ */ /* trie aka triangleq */ case 8796: AE("≜"); break; /* ≜ */ /* equest aka questeq */ case 8799: AE("≟"); break; /* ≟ */ /* ne aka NotEqual */ case 8800: AE("≠"); break; /* ≠ */ case 8801: TWOCPE; if (clen2 && uniChar2 == 8421) { AE("≡⃥"); MCP; /* ≡⃥ */ } else { /* equiv aka Congruent */ AE("≡"); /* ≡ */ }; break; /* nequiv aka NotCongruent */ case 8802: AE("≢"); break; /* ≢ */ case 8804: TWOCPE; if (clen2 && uniChar2 == 8402) { AE("≤⃒"); MCP; /* ≤⃒ */ } else { /* le aka leq */ AE("≤"); /* ≤ */ }; break; case 8805: TWOCPE; if (clen2 && uniChar2 == 8402) { AE("≥⃒"); MCP; /* ≥⃒ */ } else { /* ge aka GreaterEqual or geq */ AE("≥"); /* ≥ */ }; break; case 8806: TWOCPE; if (clen2 && uniChar2 == 824) { /* lE aka nleqq */ AE("≦̸"); MCP; /* ≦̸ */ } else { /* lE aka LessFullEqual or leqq */ AE("≦"); /* ≦ */ }; break; case 8807: TWOCPE; if (clen2 && uniChar2 == 824) { /* gE aka NotGreaterFullEqual or ngeqq */ AE("≧̸"); MCP; /* ≧̸ */ } else { /* gE aka GreaterFullEqual or geqq */ AE("≧"); /* ≧ */ }; break; case 8808: TWOCPE; if (clen2 && uniChar2 == 65024) { /* lnE aka lvertneqq */ AE("≨︀"); MCP; /* ≨︀ */ } else { /* lnE aka lneqq */ AE("≨"); /* ≨ */ }; break; case 8809: TWOCPE; if (clen2 && uniChar2 == 65024) { /* gnE aka gvertneqq */ AE("≩︀"); MCP; /* ≩︀ */ } else { /* gnE aka gneqq */ AE("≩"); /* ≩ */ }; break; case 8810: TWOCPE; if (clen2 && uniChar2 == 824) { /* nLtv aka NotLessLess */ AE("≪̸"); MCP; /* ≪̸ */ } else if (clen2 && uniChar2 == 8402) { AE("≪⃒"); MCP; /* ≪⃒ */ } else { /* ll aka Lt or NestedLessLess */ AE("≪"); /* ≪ */ }; break; case 8811: TWOCPE; if (clen2 && uniChar2 == 824) { /* nGtv aka NotGreaterGreater */ AE("≫̸"); MCP; /* ≫̸ */ } else if (clen2 && uniChar2 == 8402) { AE("≫⃒"); MCP; /* ≫⃒ */ } else { /* gg aka Gt or NestedGreaterGreater */ AE("≫"); /* ≫ */ }; break; /* twixt aka between */ case 8812: AE("≬"); break; /* ≬ */ case 8813: AE("≭"); break; /* ≭ */ /* nlt aka NotLess or nless */ case 8814: AE("≮"); break; /* ≮ */ /* ngt aka NotGreater or ngtr */ case 8815: AE("≯"); break; /* ≯ */ /* nle aka NotLessEqual or nleq */ case 8816: AE("≰"); break; /* ≰ */ /* nge aka NotGreaterEqual or ngeq */ case 8817: AE("≱"); break; /* ≱ */ /* lsim aka LessTilde or lesssim */ case 8818: AE("≲"); break; /* ≲ */ /* gsim aka GreaterTilde or gtrsim */ case 8819: AE("≳"); break; /* ≳ */ /* nlsim aka NotLessTilde */ case 8820: AE("≴"); break; /* ≴ */ /* ngsim aka NotGreaterTilde */ case 8821: AE("≵"); break; /* ≵ */ /* lg aka LessGreater or lessgtr */ case 8822: AE("≶"); break; /* ≶ */ /* gl aka GreaterLess or gtrless */ case 8823: AE("≷"); break; /* ≷ */ /* ntlg aka NotLessGreater */ case 8824: AE("≸"); break; /* ≸ */ /* ntgl aka NotGreaterLess */ case 8825: AE("≹"); break; /* ≹ */ /* pr aka Precedes or prec */ case 8826: AE("≺"); break; /* ≺ */ /* sc aka Succeeds or succ */ case 8827: AE("≻"); break; /* ≻ */ /* prcue aka PrecedesSlantEqual or preccurlyeq */ case 8828: AE("≼"); break; /* ≼ */ /* sccue aka SucceedsSlantEqual or succcurlyeq */ case 8829: AE("≽"); break; /* ≽ */ /* prsim aka PrecedesTilde or precsim */ case 8830: AE("≾"); break; /* ≾ */ case 8831: TWOCPE; if (clen2 && uniChar2 == 824) { AE("≿̸"); MCP; /* ≿̸ */ } else { /* scsim aka SucceedsTilde or succsim */ AE("≿"); /* ≿ */ }; break; /* npr aka NotPrecedes or nprec */ case 8832: AE("⊀"); break; /* ⊀ */ /* nsc aka NotSucceeds or nsucc */ case 8833: AE("⊁"); break; /* ⊁ */ case 8834: TWOCPE; if (clen2 && uniChar2 == 8402) { /* sub aka NotSubset or nsubset */ AE("⊂⃒"); MCP; /* ⊂⃒ */ } else { /* sub aka subset */ AE("⊂"); /* ⊂ */ }; break; case 8835: TWOCPE; if (clen2 && uniChar2 == 8402) { /* sup aka NotSuperset or nsupset */ AE("⊃⃒"); MCP; /* ⊃⃒ */ } else { /* sup aka Superset or supset */ AE("⊃"); /* ⊃ */ }; break; case 8836: AE("⊄"); break; /* ⊄ */ case 8837: AE("⊅"); break; /* ⊅ */ /* sube aka SubsetEqual or subseteq */ case 8838: AE("⊆"); break; /* ⊆ */ /* supe aka SupersetEqual or supseteq */ case 8839: AE("⊇"); break; /* ⊇ */ /* nsube aka NotSubsetEqual or nsubseteq */ case 8840: AE("⊈"); break; /* ⊈ */ /* nsupe aka NotSupersetEqual or nsupseteq */ case 8841: AE("⊉"); break; /* ⊉ */ case 8842: TWOCPE; if (clen2 && uniChar2 == 65024) { /* subne aka varsubsetneq */ AE("⊊︀"); MCP; /* ⊊︀ */ } else { /* subne aka subsetneq */ AE("⊊"); /* ⊊ */ }; break; case 8843: TWOCPE; if (clen2 && uniChar2 == 65024) { /* supne aka varsupsetneq */ AE("⊋︀"); MCP; /* ⊋︀ */ } else { /* supne aka supsetneq */ AE("⊋"); /* ⊋ */ }; break; case 8845: AE("⊍"); break; /* ⊍ */ /* uplus aka UnionPlus */ case 8846: AE("⊎"); break; /* ⊎ */ case 8847: TWOCPE; if (clen2 && uniChar2 == 824) { AE("⊏̸"); MCP; /* ⊏̸ */ } else { /* sqsub aka SquareSubset or sqsubset */ AE("⊏"); /* ⊏ */ }; break; case 8848: TWOCPE; if (clen2 && uniChar2 == 824) { AE("⊐̸"); MCP; /* ⊐̸ */ } else { /* sqsup aka SquareSuperset or sqsupset */ AE("⊐"); /* ⊐ */ }; break; /* sqsube aka SquareSubsetEqual or sqsubseteq */ case 8849: AE("⊑"); break; /* ⊑ */ /* sqsupe aka SquareSupersetEqual or sqsupseteq */ case 8850: AE("⊒"); break; /* ⊒ */ case 8851: TWOCPE; if (clen2 && uniChar2 == 65024) { AE("⊓︀"); MCP; /* ⊓︀ */ } else { /* sqcap aka SquareIntersection */ AE("⊓"); /* ⊓ */ }; break; case 8852: TWOCPE; if (clen2 && uniChar2 == 65024) { AE("⊔︀"); MCP; /* ⊔︀ */ } else { /* sqcup aka SquareUnion */ AE("⊔"); /* ⊔ */ }; break; /* oplus aka CirclePlus */ case 8853: AE("⊕"); break; /* ⊕ */ /* ominus aka CircleMinus */ case 8854: AE("⊖"); break; /* ⊖ */ /* otimes aka CircleTimes */ case 8855: AE("⊗"); break; /* ⊗ */ case 8856: AE("⊘"); break; /* ⊘ */ /* odot aka CircleDot */ case 8857: AE("⊙"); break; /* ⊙ */ /* ocir aka circledcirc */ case 8858: AE("⊚"); break; /* ⊚ */ /* oast aka circledast */ case 8859: AE("⊛"); break; /* ⊛ */ /* odash aka circleddash */ case 8861: AE("⊝"); break; /* ⊝ */ /* plusb aka boxplus */ case 8862: AE("⊞"); break; /* ⊞ */ /* minusb aka boxminus */ case 8863: AE("⊟"); break; /* ⊟ */ /* timesb aka boxtimes */ case 8864: AE("⊠"); break; /* ⊠ */ /* sdotb aka dotsquare */ case 8865: AE("⊡"); break; /* ⊡ */ /* vdash aka RightTee */ case 8866: AE("⊢"); break; /* ⊢ */ /* dashv aka LeftTee */ case 8867: AE("⊣"); break; /* ⊣ */ /* top aka DownTee */ case 8868: AE("⊤"); break; /* ⊤ */ /* bot aka UpTee or bottom or perp */ case 8869: AE("⊥"); break; /* ⊥ */ case 8871: AE("⊧"); break; /* ⊧ */ /* vDash aka DoubleRightTee */ case 8872: AE("⊨"); break; /* ⊨ */ case 8873: AE("⊩"); break; /* ⊩ */ case 8874: AE("⊪"); break; /* ⊪ */ case 8875: AE("⊫"); break; /* ⊫ */ case 8876: AE("⊬"); break; /* ⊬ */ case 8877: AE("⊭"); break; /* ⊭ */ case 8878: AE("⊮"); break; /* ⊮ */ case 8879: AE("⊯"); break; /* ⊯ */ case 8880: AE("⊰"); break; /* ⊰ */ /* vltri aka LeftTriangle or vartriangleleft */ case 8882: AE("⊲"); break; /* ⊲ */ /* vrtri aka RightTriangle or vartriangleright */ case 8883: AE("⊳"); break; /* ⊳ */ case 8884: TWOCPE; if (clen2 && uniChar2 == 8402) { AE("⊴⃒"); MCP; /* ⊴⃒ */ } else { /* ltrie aka LeftTriangleEqual or trianglelefteq */ AE("⊴"); /* ⊴ */ }; break; case 8885: TWOCPE; if (clen2 && uniChar2 == 8402) { AE("⊵⃒"); MCP; /* ⊵⃒ */ } else { /* rtrie aka RightTriangleEqual or trianglerighteq */ AE("⊵"); /* ⊵ */ }; break; case 8886: AE("⊶"); break; /* ⊶ */ case 8887: AE("⊷"); break; /* ⊷ */ /* mumap aka multimap */ case 8888: AE("⊸"); break; /* ⊸ */ case 8889: AE("⊹"); break; /* ⊹ */ /* intcal aka intercal */ case 8890: AE("⊺"); break; /* ⊺ */ case 8891: AE("⊻"); break; /* ⊻ */ case 8893: AE("⊽"); break; /* ⊽ */ case 8894: AE("⊾"); break; /* ⊾ */ case 8895: AE("⊿"); break; /* ⊿ */ /* Wedge aka bigwedge or xwedge */ case 8896: AE("⋀"); break; /* ⋀ */ /* Vee aka bigvee or xvee */ case 8897: AE("⋁"); break; /* ⋁ */ /* xcap aka Intersection or bigcap */ case 8898: AE("⋂"); break; /* ⋂ */ /* xcup aka Union or bigcup */ case 8899: AE("⋃"); break; /* ⋃ */ /* diam aka Diamond or diamond */ case 8900: AE("⋄"); break; /* ⋄ */ case 8901: AE("⋅"); break; /* ⋅ */ /* Star aka sstarf */ case 8902: AE("⋆"); break; /* ⋆ */ /* divonx aka divideontimes */ case 8903: AE("⋇"); break; /* ⋇ */ case 8904: AE("⋈"); break; /* ⋈ */ case 8905: AE("⋉"); break; /* ⋉ */ case 8906: AE("⋊"); break; /* ⋊ */ /* lthree aka leftthreetimes */ case 8907: AE("⋋"); break; /* ⋋ */ /* rthree aka rightthreetimes */ case 8908: AE("⋌"); break; /* ⋌ */ /* bsime aka backsimeq */ case 8909: AE("⋍"); break; /* ⋍ */ /* cuvee aka curlyvee */ case 8910: AE("⋎"); break; /* ⋎ */ /* cuwed aka curlywedge */ case 8911: AE("⋏"); break; /* ⋏ */ /* Sub aka Subset */ case 8912: AE("⋐"); break; /* ⋐ */ /* Sup aka Supset */ case 8913: AE("⋑"); break; /* ⋑ */ case 8914: AE("⋒"); break; /* ⋒ */ case 8915: AE("⋓"); break; /* ⋓ */ /* fork aka pitchfork */ case 8916: AE("⋔"); break; /* ⋔ */ case 8917: AE("⋕"); break; /* ⋕ */ /* ltdot aka lessdot */ case 8918: AE("⋖"); break; /* ⋖ */ /* gtdot aka gtrdot */ case 8919: AE("⋗"); break; /* ⋗ */ case 8920: TWOCPE; if (clen2 && uniChar2 == 824) { AE("⋘̸"); MCP; /* ⋘̸ */ } else { AE("⋘"); /* ⋘ */ }; break; case 8921: TWOCPE; if (clen2 && uniChar2 == 824) { AE("⋙̸"); MCP; /* ⋙̸ */ } else { /* Gg aka ggg */ AE("⋙"); /* ⋙ */ }; break; case 8922: TWOCPE; if (clen2 && uniChar2 == 65024) { AE("⋚︀"); MCP; /* ⋚︀ */ } else { /* leg aka LessEqualGreater or lesseqgtr */ AE("⋚"); /* ⋚ */ }; break; case 8923: TWOCPE; if (clen2 && uniChar2 == 65024) { AE("⋛︀"); MCP; /* ⋛︀ */ } else { /* gel aka GreaterEqualLess or gtreqless */ AE("⋛"); /* ⋛ */ }; break; /* cuepr aka curlyeqprec */ case 8926: AE("⋞"); break; /* ⋞ */ /* cuesc aka curlyeqsucc */ case 8927: AE("⋟"); break; /* ⋟ */ /* nprcue aka NotPrecedesSlantEqual */ case 8928: AE("⋠"); break; /* ⋠ */ /* nsccue aka NotSucceedsSlantEqual */ case 8929: AE("⋡"); break; /* ⋡ */ /* nsqsube aka NotSquareSubsetEqual */ case 8930: AE("⋢"); break; /* ⋢ */ /* nsqsupe aka NotSquareSupersetEqual */ case 8931: AE("⋣"); break; /* ⋣ */ case 8934: AE("⋦"); break; /* ⋦ */ case 8935: AE("⋧"); break; /* ⋧ */ /* prnsim aka precnsim */ case 8936: AE("⋨"); break; /* ⋨ */ /* scnsim aka succnsim */ case 8937: AE("⋩"); break; /* ⋩ */ /* nltri aka NotLeftTriangle or ntriangleleft */ case 8938: AE("⋪"); break; /* ⋪ */ /* nrtri aka NotRightTriangle or ntriangleright */ case 8939: AE("⋫"); break; /* ⋫ */ /* nltrie aka NotLeftTriangleEqual or ntrianglelefteq */ case 8940: AE("⋬"); break; /* ⋬ */ /* nrtrie aka NotRightTriangleEqual or ntrianglerighteq */ case 8941: AE("⋭"); break; /* ⋭ */ case 8942: AE("⋮"); break; /* ⋮ */ case 8943: AE("⋯"); break; /* ⋯ */ case 8944: AE("⋰"); break; /* ⋰ */ case 8945: AE("⋱"); break; /* ⋱ */ case 8946: AE("⋲"); break; /* ⋲ */ case 8947: AE("⋳"); break; /* ⋳ */ case 8948: AE("⋴"); break; /* ⋴ */ case 8949: TWOCPE; if (clen2 && uniChar2 == 824) { AE("⋵̸"); MCP; /* ⋵̸ */ } else { AE("⋵"); /* ⋵ */ }; break; case 8950: AE("⋶"); break; /* ⋶ */ case 8951: AE("⋷"); break; /* ⋷ */ case 8953: TWOCPE; if (clen2 && uniChar2 == 824) { AE("⋹̸"); MCP; /* ⋹̸ */ } else { AE("⋹"); /* ⋹ */ }; break; case 8954: AE("⋺"); break; /* ⋺ */ case 8955: AE("⋻"); break; /* ⋻ */ case 8956: AE("⋼"); break; /* ⋼ */ case 8957: AE("⋽"); break; /* ⋽ */ case 8958: AE("⋾"); break; /* ⋾ */ /* barwed aka barwedge */ case 8965: AE("⌅"); break; /* ⌅ */ /* Barwed aka doublebarwedge */ case 8966: AE("⌆"); break; /* ⌆ */ /* lceil aka LeftCeiling */ case 8968: AE("⌈"); break; /* ⌈ */ /* rceil aka RightCeiling */ case 8969: AE("⌉"); break; /* ⌉ */ /* lfloor aka LeftFloor */ case 8970: AE("⌊"); break; /* ⌊ */ /* rfloor aka RightFloor */ case 8971: AE("⌋"); break; /* ⌋ */ case 8972: AE("⌌"); break; /* ⌌ */ case 8973: AE("⌍"); break; /* ⌍ */ case 8974: AE("⌎"); break; /* ⌎ */ case 8975: AE("⌏"); break; /* ⌏ */ case 8976: AE("⌐"); break; /* ⌐ */ case 8978: AE("⌒"); break; /* ⌒ */ case 8979: AE("⌓"); break; /* ⌓ */ case 8981: AE("⌕"); break; /* ⌕ */ case 8982: AE("⌖"); break; /* ⌖ */ /* ulcorn aka ulcorner */ case 8988: AE("⌜"); break; /* ⌜ */ /* urcorn aka urcorner */ case 8989: AE("⌝"); break; /* ⌝ */ /* dlcorn aka llcorner */ case 8990: AE("⌞"); break; /* ⌞ */ /* drcorn aka lrcorner */ case 8991: AE("⌟"); break; /* ⌟ */ /* frown aka sfrown */ case 8994: AE("⌢"); break; /* ⌢ */ /* smile aka ssmile */ case 8995: AE("⌣"); break; /* ⌣ */ case 9005: AE("⌭"); break; /* ⌭ */ case 9006: AE("⌮"); break; /* ⌮ */ case 9014: AE("⌶"); break; /* ⌶ */ case 9021: AE("⌽"); break; /* ⌽ */ case 9023: AE("⌿"); break; /* ⌿ */ case 9084: AE("⍼"); break; /* ⍼ */ /* lmoust aka lmoustache */ case 9136: AE("⎰"); break; /* ⎰ */ /* rmoust aka rmoustache */ case 9137: AE("⎱"); break; /* ⎱ */ /* tbrk aka OverBracket */ case 9140: AE("⎴"); break; /* ⎴ */ /* bbrk aka UnderBracket */ case 9141: AE("⎵"); break; /* ⎵ */ case 9142: AE("⎶"); break; /* ⎶ */ case 9180: AE("⏜"); break; /* ⏜ */ case 9181: AE("⏝"); break; /* ⏝ */ case 9182: AE("⏞"); break; /* ⏞ */ case 9183: AE("⏟"); break; /* ⏟ */ case 9186: AE("⏢"); break; /* ⏢ */ case 9191: AE("⏧"); break; /* ⏧ */ case 9251: AE("␣"); break; /* ␣ */ /* oS aka circledS */ case 9416: AE("Ⓢ"); break; /* Ⓢ */ /* boxh aka HorizontalLine */ case 9472: AE("─"); break; /* ─ */ case 9474: AE("│"); break; /* │ */ case 9484: AE("┌"); break; /* ┌ */ case 9488: AE("┐"); break; /* ┐ */ case 9492: AE("└"); break; /* └ */ case 9496: AE("┘"); break; /* ┘ */ case 9500: AE("├"); break; /* ├ */ case 9508: AE("┤"); break; /* ┤ */ case 9516: AE("┬"); break; /* ┬ */ case 9524: AE("┴"); break; /* ┴ */ case 9532: AE("┼"); break; /* ┼ */ case 9552: AE("═"); break; /* ═ */ case 9553: AE("║"); break; /* ║ */ case 9554: AE("╒"); break; /* ╒ */ case 9555: AE("╓"); break; /* ╓ */ case 9556: AE("╔"); break; /* ╔ */ case 9557: AE("╕"); break; /* ╕ */ case 9558: AE("╖"); break; /* ╖ */ case 9559: AE("╗"); break; /* ╗ */ case 9560: AE("╘"); break; /* ╘ */ case 9561: AE("╙"); break; /* ╙ */ case 9562: AE("╚"); break; /* ╚ */ case 9563: AE("╛"); break; /* ╛ */ case 9564: AE("╜"); break; /* ╜ */ case 9565: AE("╝"); break; /* ╝ */ case 9566: AE("╞"); break; /* ╞ */ case 9567: AE("╟"); break; /* ╟ */ case 9568: AE("╠"); break; /* ╠ */ case 9569: AE("╡"); break; /* ╡ */ case 9570: AE("╢"); break; /* ╢ */ case 9571: AE("╣"); break; /* ╣ */ case 9572: AE("╤"); break; /* ╤ */ case 9573: AE("╥"); break; /* ╥ */ case 9574: AE("╦"); break; /* ╦ */ case 9575: AE("╧"); break; /* ╧ */ case 9576: AE("╨"); break; /* ╨ */ case 9577: AE("╩"); break; /* ╩ */ case 9578: AE("╪"); break; /* ╪ */ case 9579: AE("╫"); break; /* ╫ */ case 9580: AE("╬"); break; /* ╬ */ case 9600: AE("▀"); break; /* ▀ */ case 9604: AE("▄"); break; /* ▄ */ case 9608: AE("█"); break; /* █ */ case 9617: AE("░"); break; /* ░ */ case 9618: AE("▒"); break; /* ▒ */ case 9619: AE("▓"); break; /* ▓ */ /* squ aka Square or square */ case 9633: AE("□"); break; /* □ */ /* squf aka FilledVerySmallSquare or blacksquare or squarf */ case 9642: AE("▪"); break; /* ▪ */ case 9643: AE("▫"); break; /* ▫ */ case 9645: AE("▭"); break; /* ▭ */ case 9646: AE("▮"); break; /* ▮ */ case 9649: AE("▱"); break; /* ▱ */ /* xutri aka bigtriangleup */ case 9651: AE("△"); break; /* △ */ /* utrif aka blacktriangle */ case 9652: AE("▴"); break; /* ▴ */ /* utri aka triangle */ case 9653: AE("▵"); break; /* ▵ */ /* rtrif aka blacktriangleright */ case 9656: AE("▸"); break; /* ▸ */ /* rtri aka triangleright */ case 9657: AE("▹"); break; /* ▹ */ /* xdtri aka bigtriangledown */ case 9661: AE("▽"); break; /* ▽ */ /* dtrif aka blacktriangledown */ case 9662: AE("▾"); break; /* ▾ */ /* dtri aka triangledown */ case 9663: AE("▿"); break; /* ▿ */ /* ltrif aka blacktriangleleft */ case 9666: AE("◂"); break; /* ◂ */ /* ltri aka triangleleft */ case 9667: AE("◃"); break; /* ◃ */ /* loz aka lozenge */ case 9674: AE("◊"); break; /* ◊ */ case 9675: AE("○"); break; /* ○ */ case 9708: AE("◬"); break; /* ◬ */ /* xcirc aka bigcirc */ case 9711: AE("◯"); break; /* ◯ */ case 9720: AE("◸"); break; /* ◸ */ case 9721: AE("◹"); break; /* ◹ */ case 9722: AE("◺"); break; /* ◺ */ case 9723: AE("◻"); break; /* ◻ */ case 9724: AE("◼"); break; /* ◼ */ /* starf aka bigstar */ case 9733: AE("★"); break; /* ★ */ case 9734: AE("☆"); break; /* ☆ */ case 9742: AE("☎"); break; /* ☎ */ case 9792: AE("♀"); break; /* ♀ */ case 9794: AE("♂"); break; /* ♂ */ /* spades aka spadesuit */ case 9824: AE("♠"); break; /* ♠ */ /* clubs aka clubsuit */ case 9827: AE("♣"); break; /* ♣ */ /* hearts aka heartsuit */ case 9829: AE("♥"); break; /* ♥ */ /* diams aka diamondsuit */ case 9830: AE("♦"); break; /* ♦ */ case 9834: AE("♪"); break; /* ♪ */ case 9837: AE("♭"); break; /* ♭ */ /* natur aka natural */ case 9838: AE("♮"); break; /* ♮ */ case 9839: AE("♯"); break; /* ♯ */ /* check aka checkmark */ case 10003: AE("✓"); break; /* ✓ */ case 10007: AE("✗"); break; /* ✗ */ /* malt aka maltese */ case 10016: AE("✠"); break; /* ✠ */ case 10038: AE("✶"); break; /* ✶ */ case 10072: AE("❘"); break; /* ❘ */ case 10098: AE("❲"); break; /* ❲ */ case 10099: AE("❳"); break; /* ❳ */ case 10184: AE("⟈"); break; /* ⟈ */ case 10185: AE("⟉"); break; /* ⟉ */ /* lobrk aka LeftDoubleBracket */ case 10214: AE("⟦"); break; /* ⟦ */ /* robrk aka RightDoubleBracket */ case 10215: AE("⟧"); break; /* ⟧ */ /* lang aka LeftAngleBracket or langle */ case 10216: AE("⟨"); break; /* ⟨ */ /* rang aka RightAngleBracket or rangle */ case 10217: AE("⟩"); break; /* ⟩ */ case 10218: AE("⟪"); break; /* ⟪ */ case 10219: AE("⟫"); break; /* ⟫ */ case 10220: AE("⟬"); break; /* ⟬ */ case 10221: AE("⟭"); break; /* ⟭ */ /* xlarr aka LongLeftArrow or longleftarrow */ case 10229: AE("⟵"); break; /* ⟵ */ /* xrarr aka LongRightArrow or longrightarrow */ case 10230: AE("⟶"); break; /* ⟶ */ /* xharr aka LongLeftRightArrow or longleftrightarrow */ case 10231: AE("⟷"); break; /* ⟷ */ /* xlArr aka DoubleLongLeftArrow or Longleftarrow */ case 10232: AE("⟸"); break; /* ⟸ */ /* xrArr aka DoubleLongRightArrow or Longrightarrow */ case 10233: AE("⟹"); break; /* ⟹ */ /* xhArr aka DoubleLongLeftRightArrow or Longleftrightarrow */ case 10234: AE("⟺"); break; /* ⟺ */ /* xmap aka longmapsto */ case 10236: AE("⟼"); break; /* ⟼ */ case 10239: AE("⟿"); break; /* ⟿ */ case 10498: AE("⤂"); break; /* ⤂ */ case 10499: AE("⤃"); break; /* ⤃ */ case 10500: AE("⤄"); break; /* ⤄ */ case 10501: AE("⤅"); break; /* ⤅ */ case 10508: AE("⤌"); break; /* ⤌ */ /* rbarr aka bkarow */ case 10509: AE("⤍"); break; /* ⤍ */ case 10510: AE("⤎"); break; /* ⤎ */ /* rBarr aka dbkarow */ case 10511: AE("⤏"); break; /* ⤏ */ /* RBarr aka drbkarow */ case 10512: AE("⤐"); break; /* ⤐ */ case 10513: AE("⤑"); break; /* ⤑ */ case 10514: AE("⤒"); break; /* ⤒ */ case 10515: AE("⤓"); break; /* ⤓ */ case 10518: AE("⤖"); break; /* ⤖ */ case 10521: AE("⤙"); break; /* ⤙ */ case 10522: AE("⤚"); break; /* ⤚ */ case 10523: AE("⤛"); break; /* ⤛ */ case 10524: AE("⤜"); break; /* ⤜ */ case 10525: AE("⤝"); break; /* ⤝ */ case 10526: AE("⤞"); break; /* ⤞ */ case 10527: AE("⤟"); break; /* ⤟ */ case 10528: AE("⤠"); break; /* ⤠ */ case 10531: AE("⤣"); break; /* ⤣ */ case 10532: AE("⤤"); break; /* ⤤ */ /* searhk aka hksearow */ case 10533: AE("⤥"); break; /* ⤥ */ /* swarhk aka hkswarow */ case 10534: AE("⤦"); break; /* ⤦ */ case 10535: AE("⤧"); break; /* ⤧ */ /* toea aka nesear */ case 10536: AE("⤨"); break; /* ⤨ */ /* tosa aka seswar */ case 10537: AE("⤩"); break; /* ⤩ */ case 10538: AE("⤪"); break; /* ⤪ */ case 10547: TWOCPE; if (clen2 && uniChar2 == 824) { AE("⤳̸"); MCP; /* ⤳̸ */ } else { AE("⤳"); /* ⤳ */ }; break; case 10549: AE("⤵"); break; /* ⤵ */ case 10550: AE("⤶"); break; /* ⤶ */ case 10551: AE("⤷"); break; /* ⤷ */ case 10552: AE("⤸"); break; /* ⤸ */ case 10553: AE("⤹"); break; /* ⤹ */ case 10556: AE("⤼"); break; /* ⤼ */ case 10557: AE("⤽"); break; /* ⤽ */ case 10565: AE("⥅"); break; /* ⥅ */ case 10568: AE("⥈"); break; /* ⥈ */ case 10569: AE("⥉"); break; /* ⥉ */ case 10570: AE("⥊"); break; /* ⥊ */ case 10571: AE("⥋"); break; /* ⥋ */ case 10574: AE("⥎"); break; /* ⥎ */ case 10575: AE("⥏"); break; /* ⥏ */ case 10576: AE("⥐"); break; /* ⥐ */ case 10577: AE("⥑"); break; /* ⥑ */ case 10578: AE("⥒"); break; /* ⥒ */ case 10579: AE("⥓"); break; /* ⥓ */ case 10580: AE("⥔"); break; /* ⥔ */ case 10581: AE("⥕"); break; /* ⥕ */ case 10582: AE("⥖"); break; /* ⥖ */ case 10583: AE("⥗"); break; /* ⥗ */ case 10584: AE("⥘"); break; /* ⥘ */ case 10585: AE("⥙"); break; /* ⥙ */ case 10586: AE("⥚"); break; /* ⥚ */ case 10587: AE("⥛"); break; /* ⥛ */ case 10588: AE("⥜"); break; /* ⥜ */ case 10589: AE("⥝"); break; /* ⥝ */ case 10590: AE("⥞"); break; /* ⥞ */ case 10591: AE("⥟"); break; /* ⥟ */ case 10592: AE("⥠"); break; /* ⥠ */ case 10593: AE("⥡"); break; /* ⥡ */ case 10594: AE("⥢"); break; /* ⥢ */ case 10595: AE("⥣"); break; /* ⥣ */ case 10596: AE("⥤"); break; /* ⥤ */ case 10597: AE("⥥"); break; /* ⥥ */ case 10598: AE("⥦"); break; /* ⥦ */ case 10599: AE("⥧"); break; /* ⥧ */ case 10600: AE("⥨"); break; /* ⥨ */ case 10601: AE("⥩"); break; /* ⥩ */ case 10602: AE("⥪"); break; /* ⥪ */ case 10603: AE("⥫"); break; /* ⥫ */ case 10604: AE("⥬"); break; /* ⥬ */ case 10605: AE("⥭"); break; /* ⥭ */ /* udhar aka UpEquilibrium */ case 10606: AE("⥮"); break; /* ⥮ */ /* duhar aka ReverseUpEquilibrium */ case 10607: AE("⥯"); break; /* ⥯ */ case 10608: AE("⥰"); break; /* ⥰ */ case 10609: AE("⥱"); break; /* ⥱ */ case 10610: AE("⥲"); break; /* ⥲ */ case 10611: AE("⥳"); break; /* ⥳ */ case 10612: AE("⥴"); break; /* ⥴ */ case 10613: AE("⥵"); break; /* ⥵ */ case 10614: AE("⥶"); break; /* ⥶ */ case 10616: AE("⥸"); break; /* ⥸ */ case 10617: AE("⥹"); break; /* ⥹ */ case 10619: AE("⥻"); break; /* ⥻ */ case 10620: AE("⥼"); break; /* ⥼ */ case 10621: AE("⥽"); break; /* ⥽ */ case 10622: AE("⥾"); break; /* ⥾ */ case 10623: AE("⥿"); break; /* ⥿ */ case 10629: AE("⦅"); break; /* ⦅ */ case 10630: AE("⦆"); break; /* ⦆ */ case 10635: AE("⦋"); break; /* ⦋ */ case 10636: AE("⦌"); break; /* ⦌ */ case 10637: AE("⦍"); break; /* ⦍ */ case 10638: AE("⦎"); break; /* ⦎ */ case 10639: AE("⦏"); break; /* ⦏ */ case 10640: AE("⦐"); break; /* ⦐ */ case 10641: AE("⦑"); break; /* ⦑ */ case 10642: AE("⦒"); break; /* ⦒ */ case 10643: AE("⦓"); break; /* ⦓ */ case 10644: AE("⦔"); break; /* ⦔ */ case 10645: AE("⦕"); break; /* ⦕ */ case 10646: AE("⦖"); break; /* ⦖ */ case 10650: AE("⦚"); break; /* ⦚ */ case 10652: AE("⦜"); break; /* ⦜ */ case 10653: AE("⦝"); break; /* ⦝ */ case 10660: AE("⦤"); break; /* ⦤ */ case 10661: AE("⦥"); break; /* ⦥ */ case 10662: AE("⦦"); break; /* ⦦ */ case 10663: AE("⦧"); break; /* ⦧ */ case 10664: AE("⦨"); break; /* ⦨ */ case 10665: AE("⦩"); break; /* ⦩ */ case 10666: AE("⦪"); break; /* ⦪ */ case 10667: AE("⦫"); break; /* ⦫ */ case 10668: AE("⦬"); break; /* ⦬ */ case 10669: AE("⦭"); break; /* ⦭ */ case 10670: AE("⦮"); break; /* ⦮ */ case 10671: AE("⦯"); break; /* ⦯ */ case 10672: AE("⦰"); break; /* ⦰ */ case 10673: AE("⦱"); break; /* ⦱ */ case 10674: AE("⦲"); break; /* ⦲ */ case 10675: AE("⦳"); break; /* ⦳ */ case 10676: AE("⦴"); break; /* ⦴ */ case 10677: AE("⦵"); break; /* ⦵ */ case 10678: AE("⦶"); break; /* ⦶ */ case 10679: AE("⦷"); break; /* ⦷ */ case 10681: AE("⦹"); break; /* ⦹ */ case 10683: AE("⦻"); break; /* ⦻ */ case 10684: AE("⦼"); break; /* ⦼ */ case 10686: AE("⦾"); break; /* ⦾ */ case 10687: AE("⦿"); break; /* ⦿ */ case 10688: AE("⧀"); break; /* ⧀ */ case 10689: AE("⧁"); break; /* ⧁ */ case 10690: AE("⧂"); break; /* ⧂ */ case 10691: AE("⧃"); break; /* ⧃ */ case 10692: AE("⧄"); break; /* ⧄ */ case 10693: AE("⧅"); break; /* ⧅ */ case 10697: AE("⧉"); break; /* ⧉ */ case 10701: AE("⧍"); break; /* ⧍ */ case 10702: AE("⧎"); break; /* ⧎ */ case 10703: TWOCPE; if (clen2 && uniChar2 == 824) { AE("⧏̸"); MCP; /* ⧏̸ */ } else { AE("⧏"); /* ⧏ */ }; break; case 10704: TWOCPE; if (clen2 && uniChar2 == 824) { AE("⧐̸"); MCP; /* ⧐̸ */ } else { AE("⧐"); /* ⧐ */ }; break; case 10716: AE("⧜"); break; /* ⧜ */ case 10717: AE("⧝"); break; /* ⧝ */ case 10718: AE("⧞"); break; /* ⧞ */ case 10723: AE("⧣"); break; /* ⧣ */ case 10724: AE("⧤"); break; /* ⧤ */ case 10725: AE("⧥"); break; /* ⧥ */ /* lozf aka blacklozenge */ case 10731: AE("⧫"); break; /* ⧫ */ case 10740: AE("⧴"); break; /* ⧴ */ case 10742: AE("⧶"); break; /* ⧶ */ /* xodot aka bigodot */ case 10752: AE("⨀"); break; /* ⨀ */ /* xoplus aka bigoplus */ case 10753: AE("⨁"); break; /* ⨁ */ /* xotime aka bigotimes */ case 10754: AE("⨂"); break; /* ⨂ */ /* xuplus aka biguplus */ case 10756: AE("⨄"); break; /* ⨄ */ /* xsqcup aka bigsqcup */ case 10758: AE("⨆"); break; /* ⨆ */ /* qint aka iiiint */ case 10764: AE("⨌"); break; /* ⨌ */ case 10765: AE("⨍"); break; /* ⨍ */ case 10768: AE("⨐"); break; /* ⨐ */ case 10769: AE("⨑"); break; /* ⨑ */ case 10770: AE("⨒"); break; /* ⨒ */ case 10771: AE("⨓"); break; /* ⨓ */ case 10772: AE("⨔"); break; /* ⨔ */ case 10773: AE("⨕"); break; /* ⨕ */ case 10774: AE("⨖"); break; /* ⨖ */ case 10775: AE("⨗"); break; /* ⨗ */ case 10786: AE("⨢"); break; /* ⨢ */ case 10787: AE("⨣"); break; /* ⨣ */ case 10788: AE("⨤"); break; /* ⨤ */ case 10789: AE("⨥"); break; /* ⨥ */ case 10790: AE("⨦"); break; /* ⨦ */ case 10791: AE("⨧"); break; /* ⨧ */ case 10793: AE("⨩"); break; /* ⨩ */ case 10794: AE("⨪"); break; /* ⨪ */ case 10797: AE("⨭"); break; /* ⨭ */ case 10798: AE("⨮"); break; /* ⨮ */ case 10799: AE("⨯"); break; /* ⨯ */ case 10800: AE("⨰"); break; /* ⨰ */ case 10801: AE("⨱"); break; /* ⨱ */ case 10803: AE("⨳"); break; /* ⨳ */ case 10804: AE("⨴"); break; /* ⨴ */ case 10805: AE("⨵"); break; /* ⨵ */ case 10806: AE("⨶"); break; /* ⨶ */ case 10807: AE("⨷"); break; /* ⨷ */ case 10808: AE("⨸"); break; /* ⨸ */ case 10809: AE("⨹"); break; /* ⨹ */ case 10810: AE("⨺"); break; /* ⨺ */ case 10811: AE("⨻"); break; /* ⨻ */ /* iprod aka intprod */ case 10812: AE("⨼"); break; /* ⨼ */ case 10815: AE("⨿"); break; /* ⨿ */ case 10816: AE("⩀"); break; /* ⩀ */ case 10818: AE("⩂"); break; /* ⩂ */ case 10819: AE("⩃"); break; /* ⩃ */ case 10820: AE("⩄"); break; /* ⩄ */ case 10821: AE("⩅"); break; /* ⩅ */ case 10822: AE("⩆"); break; /* ⩆ */ case 10823: AE("⩇"); break; /* ⩇ */ case 10824: AE("⩈"); break; /* ⩈ */ case 10825: AE("⩉"); break; /* ⩉ */ case 10826: AE("⩊"); break; /* ⩊ */ case 10827: AE("⩋"); break; /* ⩋ */ case 10828: AE("⩌"); break; /* ⩌ */ case 10829: AE("⩍"); break; /* ⩍ */ case 10832: AE("⩐"); break; /* ⩐ */ case 10835: AE("⩓"); break; /* ⩓ */ case 10836: AE("⩔"); break; /* ⩔ */ case 10837: AE("⩕"); break; /* ⩕ */ case 10838: AE("⩖"); break; /* ⩖ */ case 10839: AE("⩗"); break; /* ⩗ */ case 10840: AE("⩘"); break; /* ⩘ */ case 10842: AE("⩚"); break; /* ⩚ */ case 10843: AE("⩛"); break; /* ⩛ */ case 10844: AE("⩜"); break; /* ⩜ */ case 10845: AE("⩝"); break; /* ⩝ */ case 10847: AE("⩟"); break; /* ⩟ */ case 10854: AE("⩦"); break; /* ⩦ */ case 10858: AE("⩪"); break; /* ⩪ */ case 10861: TWOCPE; if (clen2 && uniChar2 == 824) { AE("⩭̸"); MCP; /* ⩭̸ */ } else { AE("⩭"); /* ⩭ */ }; break; case 10862: AE("⩮"); break; /* ⩮ */ case 10863: AE("⩯"); break; /* ⩯ */ case 10864: TWOCPE; if (clen2 && uniChar2 == 824) { AE("⩰̸"); MCP; /* ⩰̸ */ } else { AE("⩰"); /* ⩰ */ }; break; case 10865: AE("⩱"); break; /* ⩱ */ case 10866: AE("⩲"); break; /* ⩲ */ case 10867: AE("⩳"); break; /* ⩳ */ case 10868: AE("⩴"); break; /* ⩴ */ case 10869: AE("⩵"); break; /* ⩵ */ /* eDDot aka ddotseq */ case 10871: AE("⩷"); break; /* ⩷ */ case 10872: AE("⩸"); break; /* ⩸ */ case 10873: AE("⩹"); break; /* ⩹ */ case 10874: AE("⩺"); break; /* ⩺ */ case 10875: AE("⩻"); break; /* ⩻ */ case 10876: AE("⩼"); break; /* ⩼ */ case 10877: TWOCPE; if (clen2 && uniChar2 == 824) { /* les aka NotLessSlantEqual or nleqslant */ AE("⩽̸"); MCP; /* ⩽̸ */ } else { /* les aka LessSlantEqual or leqslant */ AE("⩽"); /* ⩽ */ }; break; case 10878: TWOCPE; if (clen2 && uniChar2 == 824) { /* ges aka NotGreaterSlantEqual or ngeqslant */ AE("⩾̸"); MCP; /* ⩾̸ */ } else { /* ges aka GreaterSlantEqual or geqslant */ AE("⩾"); /* ⩾ */ }; break; case 10879: AE("⩿"); break; /* ⩿ */ case 10880: AE("⪀"); break; /* ⪀ */ case 10881: AE("⪁"); break; /* ⪁ */ case 10882: AE("⪂"); break; /* ⪂ */ case 10883: AE("⪃"); break; /* ⪃ */ case 10884: AE("⪄"); break; /* ⪄ */ /* lap aka lessapprox */ case 10885: AE("⪅"); break; /* ⪅ */ /* gap aka gtrapprox */ case 10886: AE("⪆"); break; /* ⪆ */ /* lne aka lneq */ case 10887: AE("⪇"); break; /* ⪇ */ /* gne aka gneq */ case 10888: AE("⪈"); break; /* ⪈ */ /* lnap aka lnapprox */ case 10889: AE("⪉"); break; /* ⪉ */ /* gnap aka gnapprox */ case 10890: AE("⪊"); break; /* ⪊ */ /* lEg aka lesseqqgtr */ case 10891: AE("⪋"); break; /* ⪋ */ /* gEl aka gtreqqless */ case 10892: AE("⪌"); break; /* ⪌ */ case 10893: AE("⪍"); break; /* ⪍ */ case 10894: AE("⪎"); break; /* ⪎ */ case 10895: AE("⪏"); break; /* ⪏ */ case 10896: AE("⪐"); break; /* ⪐ */ case 10897: AE("⪑"); break; /* ⪑ */ case 10898: AE("⪒"); break; /* ⪒ */ case 10899: AE("⪓"); break; /* ⪓ */ case 10900: AE("⪔"); break; /* ⪔ */ /* els aka eqslantless */ case 10901: AE("⪕"); break; /* ⪕ */ /* egs aka eqslantgtr */ case 10902: AE("⪖"); break; /* ⪖ */ case 10903: AE("⪗"); break; /* ⪗ */ case 10904: AE("⪘"); break; /* ⪘ */ case 10905: AE("⪙"); break; /* ⪙ */ case 10906: AE("⪚"); break; /* ⪚ */ case 10909: AE("⪝"); break; /* ⪝ */ case 10910: AE("⪞"); break; /* ⪞ */ case 10911: AE("⪟"); break; /* ⪟ */ case 10912: AE("⪠"); break; /* ⪠ */ case 10913: TWOCPE; if (clen2 && uniChar2 == 824) { AE("⪡̸"); MCP; /* ⪡̸ */ } else { AE("⪡"); /* ⪡ */ }; break; case 10914: TWOCPE; if (clen2 && uniChar2 == 824) { AE("⪢̸"); MCP; /* ⪢̸ */ } else { AE("⪢"); /* ⪢ */ }; break; case 10916: AE("⪤"); break; /* ⪤ */ case 10917: AE("⪥"); break; /* ⪥ */ case 10918: AE("⪦"); break; /* ⪦ */ case 10919: AE("⪧"); break; /* ⪧ */ case 10920: AE("⪨"); break; /* ⪨ */ case 10921: AE("⪩"); break; /* ⪩ */ case 10922: AE("⪪"); break; /* ⪪ */ case 10923: AE("⪫"); break; /* ⪫ */ case 10924: TWOCPE; if (clen2 && uniChar2 == 65024) { AE("⪬︀"); MCP; /* ⪬︀ */ } else { AE("⪬"); /* ⪬ */ }; break; case 10925: TWOCPE; if (clen2 && uniChar2 == 65024) { AE("⪭︀"); MCP; /* ⪭︀ */ } else { AE("⪭"); /* ⪭ */ }; break; case 10926: AE("⪮"); break; /* ⪮ */ case 10927: TWOCPE; if (clen2 && uniChar2 == 824) { /* pre aka NotPrecedesEqual or npreceq */ AE("⪯̸"); MCP; /* ⪯̸ */ } else { /* pre aka PrecedesEqual or preceq */ AE("⪯"); /* ⪯ */ }; break; case 10928: TWOCPE; if (clen2 && uniChar2 == 824) { /* sce aka NotSucceedsEqual or nsucceq */ AE("⪰̸"); MCP; /* ⪰̸ */ } else { /* sce aka SucceedsEqual or succeq */ AE("⪰"); /* ⪰ */ }; break; case 10931: AE("⪳"); break; /* ⪳ */ case 10932: AE("⪴"); break; /* ⪴ */ /* prnE aka precneqq */ case 10933: AE("⪵"); break; /* ⪵ */ /* scnE aka succneqq */ case 10934: AE("⪶"); break; /* ⪶ */ /* prap aka precapprox */ case 10935: AE("⪷"); break; /* ⪷ */ /* scap aka succapprox */ case 10936: AE("⪸"); break; /* ⪸ */ /* prnap aka precnapprox */ case 10937: AE("⪹"); break; /* ⪹ */ /* scnap aka succnapprox */ case 10938: AE("⪺"); break; /* ⪺ */ case 10939: AE("⪻"); break; /* ⪻ */ case 10940: AE("⪼"); break; /* ⪼ */ case 10941: AE("⪽"); break; /* ⪽ */ case 10942: AE("⪾"); break; /* ⪾ */ case 10943: AE("⪿"); break; /* ⪿ */ case 10944: AE("⫀"); break; /* ⫀ */ case 10945: AE("⫁"); break; /* ⫁ */ case 10946: AE("⫂"); break; /* ⫂ */ case 10947: AE("⫃"); break; /* ⫃ */ case 10948: AE("⫄"); break; /* ⫄ */ case 10949: TWOCPE; if (clen2 && uniChar2 == 824) { /* subE aka nsubseteqq */ AE("⫅̸"); MCP; /* ⫅̸ */ } else { /* subE aka subseteqq */ AE("⫅"); /* ⫅ */ }; break; case 10950: TWOCPE; if (clen2 && uniChar2 == 824) { /* supE aka nsupseteqq */ AE("⫆̸"); MCP; /* ⫆̸ */ } else { /* supE aka supseteqq */ AE("⫆"); /* ⫆ */ }; break; case 10951: AE("⫇"); break; /* ⫇ */ case 10952: AE("⫈"); break; /* ⫈ */ case 10955: TWOCPE; if (clen2 && uniChar2 == 65024) { /* subnE aka varsubsetneqq */ AE("⫋︀"); MCP; /* ⫋︀ */ } else { /* subnE aka subsetneqq */ AE("⫋"); /* ⫋ */ }; break; case 10956: TWOCPE; if (clen2 && uniChar2 == 65024) { /* supnE aka varsupsetneqq */ AE("⫌︀"); MCP; /* ⫌︀ */ } else { /* supnE aka supsetneqq */ AE("⫌"); /* ⫌ */ }; break; case 10959: AE("⫏"); break; /* ⫏ */ case 10960: AE("⫐"); break; /* ⫐ */ case 10961: AE("⫑"); break; /* ⫑ */ case 10962: AE("⫒"); break; /* ⫒ */ case 10963: AE("⫓"); break; /* ⫓ */ case 10964: AE("⫔"); break; /* ⫔ */ case 10965: AE("⫕"); break; /* ⫕ */ case 10966: AE("⫖"); break; /* ⫖ */ case 10967: AE("⫗"); break; /* ⫗ */ case 10968: AE("⫘"); break; /* ⫘ */ case 10969: AE("⫙"); break; /* ⫙ */ case 10970: AE("⫚"); break; /* ⫚ */ case 10971: AE("⫛"); break; /* ⫛ */ /* Dashv aka DoubleLeftTee */ case 10980: AE("⫤"); break; /* ⫤ */ case 10982: AE("⫦"); break; /* ⫦ */ case 10983: AE("⫧"); break; /* ⫧ */ case 10984: AE("⫨"); break; /* ⫨ */ case 10985: AE("⫩"); break; /* ⫩ */ case 10987: AE("⫫"); break; /* ⫫ */ case 10988: AE("⫬"); break; /* ⫬ */ case 10989: AE("⫭"); break; /* ⫭ */ case 10990: AE("⫮"); break; /* ⫮ */ case 10991: AE("⫯"); break; /* ⫯ */ case 10992: AE("⫰"); break; /* ⫰ */ case 10993: AE("⫱"); break; /* ⫱ */ case 10994: AE("⫲"); break; /* ⫲ */ case 10995: AE("⫳"); break; /* ⫳ */ case 11005: TWOCPE; if (clen2 && uniChar2 == 8421) { AE("⫽⃥"); MCP; /* ⫽⃥ */ } else { AE("⫽"); /* ⫽ */ }; break; case 64256: AE("ff"); break; /* ff */ case 64257: AE("fi"); break; /* fi */ case 64258: AE("fl"); break; /* fl */ case 64259: AE("ffi"); break; /* ffi */ case 64260: AE("ffl"); break; /* ffl */ case 119964: AE("𝒜"); break; /* 𝒜 */ case 119966: AE("𝒞"); break; /* 𝒞 */ case 119967: AE("𝒟"); break; /* 𝒟 */ case 119970: AE("𝒢"); break; /* 𝒢 */ case 119973: AE("𝒥"); break; /* 𝒥 */ case 119974: AE("𝒦"); break; /* 𝒦 */ case 119977: AE("𝒩"); break; /* 𝒩 */ case 119978: AE("𝒪"); break; /* 𝒪 */ case 119979: AE("𝒫"); break; /* 𝒫 */ case 119980: AE("𝒬"); break; /* 𝒬 */ case 119982: AE("𝒮"); break; /* 𝒮 */ case 119983: AE("𝒯"); break; /* 𝒯 */ case 119984: AE("𝒰"); break; /* 𝒰 */ case 119985: AE("𝒱"); break; /* 𝒱 */ case 119986: AE("𝒲"); break; /* 𝒲 */ case 119987: AE("𝒳"); break; /* 𝒳 */ case 119988: AE("𝒴"); break; /* 𝒴 */ case 119989: AE("𝒵"); break; /* 𝒵 */ case 119990: AE("𝒶"); break; /* 𝒶 */ case 119991: AE("𝒷"); break; /* 𝒷 */ case 119992: AE("𝒸"); break; /* 𝒸 */ case 119993: AE("𝒹"); break; /* 𝒹 */ case 119995: AE("𝒻"); break; /* 𝒻 */ case 119997: AE("𝒽"); break; /* 𝒽 */ case 119998: AE("𝒾"); break; /* 𝒾 */ case 119999: AE("𝒿"); break; /* 𝒿 */ case 120000: AE("𝓀"); break; /* 𝓀 */ case 120001: AE("𝓁"); break; /* 𝓁 */ case 120002: AE("𝓂"); break; /* 𝓂 */ case 120003: AE("𝓃"); break; /* 𝓃 */ case 120005: AE("𝓅"); break; /* 𝓅 */ case 120006: AE("𝓆"); break; /* 𝓆 */ case 120007: AE("𝓇"); break; /* 𝓇 */ case 120008: AE("𝓈"); break; /* 𝓈 */ case 120009: AE("𝓉"); break; /* 𝓉 */ case 120010: AE("𝓊"); break; /* 𝓊 */ case 120011: AE("𝓋"); break; /* 𝓋 */ case 120012: AE("𝓌"); break; /* 𝓌 */ case 120013: AE("𝓍"); break; /* 𝓍 */ case 120014: AE("𝓎"); break; /* 𝓎 */ case 120015: AE("𝓏"); break; /* 𝓏 */ case 120068: AE("𝔄"); break; /* 𝔄 */ case 120069: AE("𝔅"); break; /* 𝔅 */ case 120071: AE("𝔇"); break; /* 𝔇 */ case 120072: AE("𝔈"); break; /* 𝔈 */ case 120073: AE("𝔉"); break; /* 𝔉 */ case 120074: AE("𝔊"); break; /* 𝔊 */ case 120077: AE("𝔍"); break; /* 𝔍 */ case 120078: AE("𝔎"); break; /* 𝔎 */ case 120079: AE("𝔏"); break; /* 𝔏 */ case 120080: AE("𝔐"); break; /* 𝔐 */ case 120081: AE("𝔑"); break; /* 𝔑 */ case 120082: AE("𝔒"); break; /* 𝔒 */ case 120083: AE("𝔓"); break; /* 𝔓 */ case 120084: AE("𝔔"); break; /* 𝔔 */ case 120086: AE("𝔖"); break; /* 𝔖 */ case 120087: AE("𝔗"); break; /* 𝔗 */ case 120088: AE("𝔘"); break; /* 𝔘 */ case 120089: AE("𝔙"); break; /* 𝔙 */ case 120090: AE("𝔚"); break; /* 𝔚 */ case 120091: AE("𝔛"); break; /* 𝔛 */ case 120092: AE("𝔜"); break; /* 𝔜 */ case 120094: AE("𝔞"); break; /* 𝔞 */ case 120095: AE("𝔟"); break; /* 𝔟 */ case 120096: AE("𝔠"); break; /* 𝔠 */ case 120097: AE("𝔡"); break; /* 𝔡 */ case 120098: AE("𝔢"); break; /* 𝔢 */ case 120099: AE("𝔣"); break; /* 𝔣 */ case 120100: AE("𝔤"); break; /* 𝔤 */ case 120101: AE("𝔥"); break; /* 𝔥 */ case 120102: AE("𝔦"); break; /* 𝔦 */ case 120103: AE("𝔧"); break; /* 𝔧 */ case 120104: AE("𝔨"); break; /* 𝔨 */ case 120105: AE("𝔩"); break; /* 𝔩 */ case 120106: AE("𝔪"); break; /* 𝔪 */ case 120107: AE("𝔫"); break; /* 𝔫 */ case 120108: AE("𝔬"); break; /* 𝔬 */ case 120109: AE("𝔭"); break; /* 𝔭 */ case 120110: AE("𝔮"); break; /* 𝔮 */ case 120111: AE("𝔯"); break; /* 𝔯 */ case 120112: AE("𝔰"); break; /* 𝔰 */ case 120113: AE("𝔱"); break; /* 𝔱 */ case 120114: AE("𝔲"); break; /* 𝔲 */ case 120115: AE("𝔳"); break; /* 𝔳 */ case 120116: AE("𝔴"); break; /* 𝔴 */ case 120117: AE("𝔵"); break; /* 𝔵 */ case 120118: AE("𝔶"); break; /* 𝔶 */ case 120119: AE("𝔷"); break; /* 𝔷 */ case 120120: AE("𝔸"); break; /* 𝔸 */ case 120121: AE("𝔹"); break; /* 𝔹 */ case 120123: AE("𝔻"); break; /* 𝔻 */ case 120124: AE("𝔼"); break; /* 𝔼 */ case 120125: AE("𝔽"); break; /* 𝔽 */ case 120126: AE("𝔾"); break; /* 𝔾 */ case 120128: AE("𝕀"); break; /* 𝕀 */ case 120129: AE("𝕁"); break; /* 𝕁 */ case 120130: AE("𝕂"); break; /* 𝕂 */ case 120131: AE("𝕃"); break; /* 𝕃 */ case 120132: AE("𝕄"); break; /* 𝕄 */ case 120134: AE("𝕆"); break; /* 𝕆 */ case 120138: AE("𝕊"); break; /* 𝕊 */ case 120139: AE("𝕋"); break; /* 𝕋 */ case 120140: AE("𝕌"); break; /* 𝕌 */ case 120141: AE("𝕍"); break; /* 𝕍 */ case 120142: AE("𝕎"); break; /* 𝕎 */ case 120143: AE("𝕏"); break; /* 𝕏 */ case 120144: AE("𝕐"); break; /* 𝕐 */ case 120146: AE("𝕒"); break; /* 𝕒 */ case 120147: AE("𝕓"); break; /* 𝕓 */ case 120148: AE("𝕔"); break; /* 𝕔 */ case 120149: AE("𝕕"); break; /* 𝕕 */ case 120150: AE("𝕖"); break; /* 𝕖 */ case 120151: AE("𝕗"); break; /* 𝕗 */ case 120152: AE("𝕘"); break; /* 𝕘 */ case 120153: AE("𝕙"); break; /* 𝕙 */ case 120154: AE("𝕚"); break; /* 𝕚 */ case 120155: AE("𝕛"); break; /* 𝕛 */ case 120156: AE("𝕜"); break; /* 𝕜 */ case 120157: AE("𝕝"); break; /* 𝕝 */ case 120158: AE("𝕞"); break; /* 𝕞 */ case 120159: AE("𝕟"); break; /* 𝕟 */ case 120160: AE("𝕠"); break; /* 𝕠 */ case 120161: AE("𝕡"); break; /* 𝕡 */ case 120162: AE("𝕢"); break; /* 𝕢 */ case 120163: AE("𝕣"); break; /* 𝕣 */ case 120164: AE("𝕤"); break; /* 𝕤 */ case 120165: AE("𝕥"); break; /* 𝕥 */ case 120166: AE("𝕦"); break; /* 𝕦 */ case 120167: AE("𝕧"); break; /* 𝕧 */ case 120168: AE("𝕨"); break; /* 𝕨 */ case 120169: AE("𝕩"); break; /* 𝕩 */ case 120170: AE("𝕪"); break; /* 𝕪 */ case 120171: AE("𝕫"); break; /* 𝕫 */ tdom-0.9.6-src/generic/domxpath.h0000644000175000017500000002026715025767703015400 0ustar rolfrolf/*---------------------------------------------------------------------------- | Copyright (c) 1999 Jochen Loewer (loewerj@hotmail.com) |----------------------------------------------------------------------------- | | A (partial) XPath implementation (lexer/parser/evaluator) for tDOM, | the DOM implementation for Tcl. | Based on the August 13 working draft of the W3C | (http://www.w3.org/1999/08/WD-xpath-19990813.html) | | | The contents of this file are subject to the Mozilla Public License | Version 2.0 (the "License"); you may not use this file except in | compliance with the License. You may obtain a copy of the License at | http://www.mozilla.org/MPL/ | | Software distributed under the License is distributed on an "AS IS" | basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the | License for the specific language governing rights and limitations | under the License. | | The Original Code is tDOM. | | The Initial Developer of the Original Code is Jochen Loewer | Portions created by Jochen Loewer are Copyright (C) 1998, 1999 | Jochen Loewer. All Rights Reserved. | | Contributor(s): | | | | written by Jochen Loewer | July, 1999 | \---------------------------------------------------------------------------*/ #ifndef __DOMXPATH_H__ #define __DOMXPATH_H__ #include #include /*---------------------------------------------------------------------------- | Macros | \---------------------------------------------------------------------------*/ #define XPATH_OK 0 #define XPATH_LEX_ERR -1 #define XPATH_SYNTAX_ERR -2 #define XPATH_EVAL_ERR -3 #define XPATH_VAR_NOT_FOUND -4 #define XPATH_I18N_ERR -5 /* * Macros for testing floating-point values for certain special cases. Test * for not-a-number by comparing a value against itself; test for infinity * by comparing against the largest floating-point value. */ #define IS_NAN(v) ((v) != (v)) #ifdef DBL_MAX # define IS_INF(v) ((v) > DBL_MAX ? 1 : ((v) < -DBL_MAX ? -1 : 0)) #else # define IS_INF(v) 0 #endif #if TCL_MAJOR_VERSION > 8 # define dom_minl domLength #else # define dom_minl long #endif /*---------------------------------------------------------------------------- | Types for abstract syntax trees | \---------------------------------------------------------------------------*/ typedef enum { Int, Real, Mult, Div, Mod, UnaryMinus, IsNSElement, IsNode, IsComment, IsText, IsPI, IsSpecificPI, IsElement, IsFQElement, GetVar, GetFQVar, Literal, ExecFunction, Pred, EvalSteps, SelectRoot, CombineSets, Add, Subtract, Less, LessOrEq, Greater, GreaterOrEq, Equal, NotEqual, And, Or, IsNSAttr, IsAttr, AxisAncestor, AxisAncestorOrSelf, AxisAttribute, AxisChild, AxisDescendant, AxisDescendantOrSelf, AxisFollowing, AxisFollowingSibling, AxisNamespace, AxisParent, AxisPreceding, AxisPrecedingSibling, AxisSelf, GetContextNode, GetParentNode, AxisDescendantOrSelfLit, AxisDescendantLit, SlashSlash, CombinePath, IsRoot, ToParent, ToAncestors, FillNodeList, FillWithCurrentNode, ExecIdKey } astType; typedef struct astElem { astType type; struct astElem *child; struct astElem *next; char *strvalue; dom_minl intvalue; double realvalue; } astElem; typedef astElem *ast; /*---------------------------------------------------------------------------- | Types for XPath result set | \---------------------------------------------------------------------------*/ typedef enum { UnknownResult = 0, EmptyResult, BoolResult, IntResult, RealResult, StringResult, xNodeSetResult, NaNResult, InfResult, NInfResult, NodesResult, AttrnodesResult, MixedResult } xpathResultType; typedef struct xpathResultSet { xpathResultType type; char *string; domLength string_len; dom_minl intvalue; double realvalue; domNode **nodes; domLength nr_nodes; domLength allocated; } xpathResultSet; typedef xpathResultSet *xpathResultSets; typedef int (*xpathFuncCallback) (void *clientData, char *functionName, domNode *ctxNode, domLength position, xpathResultSet *nodeList, domNode *exprContext, int argc, xpathResultSets *args, xpathResultSet *result, char **errMsg); typedef int (*xpathVarCallback) (void *clientData, char *variableName, char *varURI, xpathResultSet *result, char **errMsg); typedef struct xpathCBs { /* all xpath callbacks + clientData */ xpathVarCallback varCB; void * varClientData; xpathFuncCallback funcCB; void * funcClientData; } xpathCBs; typedef char * (*xpathParseVarCallback) (void *clientData, char *strToParse, domLength *offset, char **errMsg); typedef struct xpathParseVarCB { xpathParseVarCallback parseVarCB; void * parseVarClientData; } xpathParseVarCB; /* XPath expr/pattern types */ typedef enum { XPATH_EXPR, XPATH_FORMAT_PATTERN, XPATH_TEMPMATCH_PATTERN, XPATH_KEY_USE_EXPR, XPATH_KEY_MATCH_PATTERN } xpathExprType; /*---------------------------------------------------------------------------- | Prototypes | \---------------------------------------------------------------------------*/ int xpathParse (char *xpath, domNode *exprContext, xpathExprType type, char **prefixMappings, xpathParseVarCB *varParseCB, ast *t, char **errMsg); void xpathFreeAst (ast t); double xpathGetPrio (ast t); int xpathEval (domNode *node, domNode *exprContext, char *xpath, char **prefixMappings, xpathCBs *cbs, xpathParseVarCB *parseVarCB, Tcl_HashTable *catch, char **errMsg, xpathResultSet *rs); int xpathEvalAst (ast t, xpathResultSet *nodeList, domNode *node, xpathCBs *cbs, xpathResultSet *rs, char **errMsg); int xpathMatches (ast steps, domNode * exprContext, domNode *nodeToMatch, xpathCBs *cbs, char **errMsg ); int xpathEvalSteps (ast steps, xpathResultSet *nodeList, domNode *currentNode, domNode *exprContext, domLength currentPos, int *docOrder, xpathCBs *cbs, xpathResultSet *result, char **errMsg); #define xpathRSInit(x) (x)->type = EmptyResult; \ (x)->intvalue = 0; \ (x)->nr_nodes = 0; void xpathRSFree (xpathResultSet *rs); void xpathRSReset (xpathResultSet *rs, domNode *ode); int xpathFuncBoolean (xpathResultSet *rs); double xpathFuncNumber (xpathResultSet *rs, int *NaN); char * xpathFuncString (xpathResultSet *rs); char * xpathFuncStringForNode (domNode *node); domLength xpathRound (double r); char * xpathGetStringValue (domNode *node, domLength *strLen); char * xpathNodeToXPath (domNode *node, int legacy); void rsSetBool ( xpathResultSet *rs, dom_minl i ); void rsSetLong ( xpathResultSet *rs, dom_minl i ); void rsSetReal ( xpathResultSet *rs, double d ); void rsSetReal2 ( xpathResultSet *rs, double d ); void rsSetString ( xpathResultSet *rs, const char *s ); void rsAddNode ( xpathResultSet *rs, domNode *node ); void rsAddNodeFast ( xpathResultSet *rs, domNode *node ); void rsCopy ( xpathResultSet *to, xpathResultSet *from ); /* This function is only used for debugging code */ void rsPrint ( xpathResultSet *rs ); const char * xpathResultType2string (xpathResultType type); /* This function is used (outside of tcldom.c) only by schema.c. It * has to have a prototype somewhere. */ int tcldom_xpathFuncCallBack ( void *clientData, char *functionName, domNode *ctxNode, domLength position, xpathResultSet *nodeList, domNode *exprContext, int argc, xpathResultSets *args, xpathResultSet *result, char **errMsg ); #endif tdom-0.9.6-src/generic/tdomDecls.h0000644000175000017500000001227715025767703015474 0ustar rolfrolf /* This is generated by the genStubs.tcl tool (see the tcl distribution) out of the tdom.decls file */ /* !BEGIN!: Do not edit below this line. */ #ifdef __cplusplus extern "C" { #endif /* * Exported function declarations: */ /* 0 */ EXTERN int TclExpatObjCmd(ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); /* 1 */ EXTERN int CheckExpatParserObj(Tcl_Interp *interp, Tcl_Obj *const nameObj); /* 2 */ EXTERN int CHandlerSetInstall(Tcl_Interp *interp, Tcl_Obj *const expatObj, CHandlerSet *handlerSet); /* 3 */ EXTERN int CHandlerSetRemove(Tcl_Interp *interp, Tcl_Obj *const expatObj, char *handlerSetName); /* 4 */ EXTERN CHandlerSet * CHandlerSetCreate(const char *name); /* 5 */ EXTERN CHandlerSet * CHandlerSetGet(Tcl_Interp *interp, Tcl_Obj *const expatObj, char *handlerSetName); /* 6 */ EXTERN void * CHandlerSetGetUserData(Tcl_Interp *interp, Tcl_Obj *const expatObj, char *handlerSetName); /* 7 */ EXTERN TclGenExpatInfo * GetExpatInfo(Tcl_Interp *interp, Tcl_Obj *const expatObj); /* 8 */ EXTERN XML_Size XML_GetCurrentLineNumber(XML_Parser parser); /* 9 */ EXTERN XML_Size XML_GetCurrentColumnNumber(XML_Parser parser); /* 10 */ EXTERN XML_Index XML_GetCurrentByteIndex(XML_Parser parser); /* 11 */ EXTERN int XML_GetCurrentByteCount(XML_Parser parser); /* 12 */ EXTERN enum XML_Status XML_SetBase(XML_Parser parser, const XML_Char *base); /* 13 */ EXTERN const XML_Char * XML_GetBase(XML_Parser parser); /* 14 */ EXTERN int XML_GetSpecifiedAttributeCount(XML_Parser parser); /* 15 */ EXTERN int XML_GetIdAttributeIndex(XML_Parser parser); /* 16 */ EXTERN domNode * tcldom_getNodeFromName(Tcl_Interp *interp, char *nodeName, char **errMsg); /* 17 */ EXTERN domDocument * tcldom_getDocumentFromName(Tcl_Interp *interp, char *docName, char **errMsg); /* 18 */ EXTERN SchemaData * tdomGetSchemadata(Tcl_Interp *interp); typedef struct TdomStubs { int magic; void *hooks; int (*tclExpatObjCmd) (ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); /* 0 */ int (*checkExpatParserObj) (Tcl_Interp *interp, Tcl_Obj *const nameObj); /* 1 */ int (*cHandlerSetInstall) (Tcl_Interp *interp, Tcl_Obj *const expatObj, CHandlerSet *handlerSet); /* 2 */ int (*cHandlerSetRemove) (Tcl_Interp *interp, Tcl_Obj *const expatObj, char *handlerSetName); /* 3 */ CHandlerSet * (*cHandlerSetCreate) (const char *name); /* 4 */ CHandlerSet * (*cHandlerSetGet) (Tcl_Interp *interp, Tcl_Obj *const expatObj, char *handlerSetName); /* 5 */ void * (*cHandlerSetGetUserData) (Tcl_Interp *interp, Tcl_Obj *const expatObj, char *handlerSetName); /* 6 */ TclGenExpatInfo * (*getExpatInfo) (Tcl_Interp *interp, Tcl_Obj *const expatObj); /* 7 */ XML_Size (*xML_GetCurrentLineNumber) (XML_Parser parser); /* 8 */ XML_Size (*xML_GetCurrentColumnNumber) (XML_Parser parser); /* 9 */ XML_Index (*xML_GetCurrentByteIndex) (XML_Parser parser); /* 10 */ int (*xML_GetCurrentByteCount) (XML_Parser parser); /* 11 */ enum XML_Status (*xML_SetBase) (XML_Parser parser, const XML_Char *base); /* 12 */ const XML_Char * (*xML_GetBase) (XML_Parser parser); /* 13 */ int (*xML_GetSpecifiedAttributeCount) (XML_Parser parser); /* 14 */ int (*xML_GetIdAttributeIndex) (XML_Parser parser); /* 15 */ domNode * (*tcldom_getNodeFromName) (Tcl_Interp *interp, char *nodeName, char **errMsg); /* 16 */ domDocument * (*tcldom_getDocumentFromName) (Tcl_Interp *interp, char *docName, char **errMsg); /* 17 */ SchemaData * (*tdomGetSchemadata) (Tcl_Interp *interp); /* 18 */ } TdomStubs; extern const TdomStubs *tdomStubsPtr; #ifdef __cplusplus } #endif #if defined(USE_TDOM_STUBS) /* * Inline function declarations: */ #define TclExpatObjCmd \ (tdomStubsPtr->tclExpatObjCmd) /* 0 */ #define CheckExpatParserObj \ (tdomStubsPtr->checkExpatParserObj) /* 1 */ #define CHandlerSetInstall \ (tdomStubsPtr->cHandlerSetInstall) /* 2 */ #define CHandlerSetRemove \ (tdomStubsPtr->cHandlerSetRemove) /* 3 */ #define CHandlerSetCreate \ (tdomStubsPtr->cHandlerSetCreate) /* 4 */ #define CHandlerSetGet \ (tdomStubsPtr->cHandlerSetGet) /* 5 */ #define CHandlerSetGetUserData \ (tdomStubsPtr->cHandlerSetGetUserData) /* 6 */ #define GetExpatInfo \ (tdomStubsPtr->getExpatInfo) /* 7 */ #define XML_GetCurrentLineNumber \ (tdomStubsPtr->xML_GetCurrentLineNumber) /* 8 */ #define XML_GetCurrentColumnNumber \ (tdomStubsPtr->xML_GetCurrentColumnNumber) /* 9 */ #define XML_GetCurrentByteIndex \ (tdomStubsPtr->xML_GetCurrentByteIndex) /* 10 */ #define XML_GetCurrentByteCount \ (tdomStubsPtr->xML_GetCurrentByteCount) /* 11 */ #define XML_SetBase \ (tdomStubsPtr->xML_SetBase) /* 12 */ #define XML_GetBase \ (tdomStubsPtr->xML_GetBase) /* 13 */ #define XML_GetSpecifiedAttributeCount \ (tdomStubsPtr->xML_GetSpecifiedAttributeCount) /* 14 */ #define XML_GetIdAttributeIndex \ (tdomStubsPtr->xML_GetIdAttributeIndex) /* 15 */ #define tcldom_getNodeFromName \ (tdomStubsPtr->tcldom_getNodeFromName) /* 16 */ #define tcldom_getDocumentFromName \ (tdomStubsPtr->tcldom_getDocumentFromName) /* 17 */ #define tdomGetSchemadata \ (tdomStubsPtr->tdomGetSchemadata) /* 18 */ #endif /* defined(USE_TDOM_STUBS) */ /* !END!: Do not edit above this line. */ tdom-0.9.6-src/generic/domjson.c0000644000175000017500000007621015025767703015217 0ustar rolfrolf/*---------------------------------------------------------------------------- | Copyright (c) 2017 Rolf Ade (rolf@pointsman.de) |----------------------------------------------------------------------------- | | | The contents of this file are subject to the Mozilla Public License | Version 2.0 (the "License"); you may not use this file except in | compliance with the License. You may obtain a copy of the License at | http://www.mozilla.org/MPL/ | | Software distributed under the License is distributed on an "AS IS" | basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the | License for the specific language governing rights and limitations | under the License. | | Contributor(s): | | | written by Rolf Ade | April 2017 | \---------------------------------------------------------------------------*/ /* Some parts of the following are inspired, derivated or, for a few * smaller pieces, even verbatim copied from the (public domain) * sqlite JSON parser * (https://www.sqlite.org/src/artifact/312b4ddf4c7399dc) */ #include #include #include #include static const char jsonIsSpace[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; #define skipspace(x) while (jsonIsSpace[(unsigned char)json[(x)]]) { (x)++; } #define rc(i) if (jparse->state != JSON_OK) return (i); /* The meaning of parse state values */ typedef enum { JSON_OK, JSON_MAX_NESTING_REACHED, JSON_SYNTAX_ERR, } JSONParseState; /* Error string constants, indexed by JSONParseState. */ static const char *JSONParseStateStr[] = { "OK", "Maximum JSON object/array nesting depth exceeded", "JSON syntax error", }; typedef struct { JSONParseState state; JSONWithin within; int nestingDepth; int maxnesting; char *arrItemElm; char *buf; domLength len; } JSONParse; #define SetResult(str) Tcl_ResetResult(interp); \ Tcl_SetStringObj(Tcl_GetObjResult(interp), (str), -1) #define SetResult3(str1,str2,str3) Tcl_ResetResult(interp); \ Tcl_AppendResult(interp, (str1), (str2), (str3), NULL) #define errReturn(i,j) {jparse->state = j; return (i);} /* #define DEBUG */ #ifdef DEBUG # define DBG(x) x #else # define DBG(x) #endif /* ** Return true if z[] begins with 4 (or more) hexadecimal digits */ static int jsonIs4Hex(const char *z){ int i; for (i=0; i<4; i++) if (!isxdigit(z[i])) return 0; return 1; } /* Parse the single JSON string which begins (with the starting '"') * at json[i]. Return the index of the closing '"' of the string * parsed. */ static domLength jsonParseString ( char *json, domLength i, JSONParse *jparse ) { unsigned char c; int clen; domLength j, k, savedStart; unsigned int u, u2; DBG(fprintf(stderr, "jsonParseString start: '%s'\n", &json[i]);); if (jparse->len) jparse->buf[0] = '\0'; savedStart = i; if (json[i] != '"') { errReturn(i,JSON_SYNTAX_ERR); } i++; if (json[i] == '"') { return i; } for(;;) { c = json[i]; DBG(fprintf (stderr, "Looking at '%d'\n", c);); /* Unescaped control characters are not allowed in JSON * strings. */ if (c <= 0x1f) { errReturn(i,JSON_SYNTAX_ERR); } if (c == '\\') { goto unescape; } if (c == '"') { return i; } if (c == 0xC0 && (unsigned char)json[i+1] == 0x80) errReturn(i,JSON_SYNTAX_ERR); if ((clen = UTF8_CHAR_LEN(c)) == 0) errReturn(i,JSON_SYNTAX_ERR); i += clen; } unescape: DBG(fprintf (stderr, "Continue with unescaping ..\n");); /* If we here, then i points to the first backslash in the string * to parse */ if (i - savedStart + 200 > jparse->len) { jparse->buf = REALLOC(jparse->buf, i-savedStart+200); jparse->len = i-savedStart+200; } memcpy (jparse->buf, &json[savedStart+1], i-savedStart); j = i-savedStart-1; for(;;) { c = json[i]; DBG(fprintf (stderr, "Looking at '%c'\n", c);); /* Unescaped control characters are not allowed in JSON * strings. */ if (c <= 0x1f) errReturn(i,JSON_SYNTAX_ERR); if (jparse->len - j < 14) { jparse->buf = REALLOC (jparse->buf, jparse->len * 2); jparse->len *= 2; } if (c == '\\') { c = json[i+1]; if (c == 'u' && jsonIs4Hex(&json[i+2])) { u = 0; for (k = 2; k < 6; k++) { c = json[i+k]; if (c <= '9') u = u*16 + c - '0'; else if (c <= 'F') u = u*16 + c - 'A' + 10; else u = u*16 + c - 'a' + 10; } if (u <= 0x7f) { if (u == 0) { jparse->buf[j++] = (char)0xC0; jparse->buf[j++] = (char)0x80; } else { jparse->buf[j++] = (char)u; } } else if (u <= 0x7ff) { jparse->buf[j++] = (char)(0xc0 | (u>>6)); jparse->buf[j++] = 0x80 | (u&0x3f); } else { if ((u&0xfc00)==0xd800 && (char)json[i+6] == '\\' && (char)json[i+7] == 'u' && jsonIs4Hex(&json[i+8])) { /* A surrogate pair */ u2 = 0; for (k = 8; k < 12; k++) { c = json[i+k]; if (c <= '9') u2 = u2*16 + c - '0'; else if (c <= 'F') u2 = u2*16 + c - 'A' + 10; else u2 = u2*16 + c - 'a' + 10; } u = ((u&0x3ff)<<10) + (u2&0x3ff) + 0x10000; i += 6; jparse->buf[j++] = 0xf0 | (u>>18); jparse->buf[j++] = 0x80 | ((u>>12)&0x3f); jparse->buf[j++] = 0x80 | ((u>>6)&0x3f); jparse->buf[j++] = 0x80 | (u&0x3f); } else { jparse->buf[j++] = (char)(0xe0 | (u>>12)); jparse->buf[j++] = 0x80 | ((u>>6)&0x3f); jparse->buf[j++] = 0x80 | (u&0x3f); } } i += 6; } else { if (c == '\\') { c = '\\'; } else if (c == '"') { c = '"'; } else if (c == '/') { c = '/'; } else if (c == 'b') { c = '\b'; } else if (c == 'f') { c = '\f'; } else if (c == 'n') { c = '\n'; } else if (c == 'r') { c = '\r'; } else if (c == 't') { c = '\t'; } else { errReturn(i+1,JSON_SYNTAX_ERR); } jparse->buf[j++] = c; i += 2; } continue; } if (c == '"') { jparse->buf[j] = '\0'; return i; } if ((clen = UTF8_CHAR_LEN(json[i])) == 0) errReturn(i,JSON_SYNTAX_ERR); for (k = 0; k < clen; k++) { jparse->buf[j++] = json[i+k]; } i += clen; } } /* Parse a single JSON value which begins at json[i]. Return the index * of the first character past the end of the value parsed. */ static domLength jsonParseValue ( domNode *parent, char *json, domLength i, JSONParse *jparse ) { char c, save; domLength j; domNode *node; domTextNode *newTextNode; JSONWithin savedWithin = jparse->within; DBG(fprintf(stderr, "jsonParseValue start: '%s'\n", &json[i]);); if (jparse->len) jparse->buf[0] = 0; skipspace(i); if ((c = json[i]) == '{' ) { /* Parse object */ if (++jparse->nestingDepth > jparse->maxnesting) errReturn(i,JSON_MAX_NESTING_REACHED); i++; if (jparse->within == JSON_ARRAY) { node = domNewElementNode (parent->ownerDocument, JSON_OBJECT_CONTAINER); node->info = JSON_OBJECT; domAppendChild(parent, node); parent = node; } else { parent->info = JSON_OBJECT; } skipspace(i); if (json[i] == '}') { /* Empty object. */ jparse->nestingDepth--; return i+1; } jparse->within = JSON_WITHIN_OBJECT; for (;;) { j = jsonParseString (json, i, jparse); rc(j); if (jparse->len && jparse->buf[0]) { DBG(fprintf(stderr, "New object member '%s'\n", jparse->buf);); node = domNewElementNode (parent->ownerDocument, jparse->buf); domAppendChild (parent, node); jparse->buf[0] = 0; } else { save = json[j]; json[j] = '\0'; DBG(fprintf(stderr, "New object member '%s'\n", jparse->buf);); DBG(fprintf(stderr, "New object member '%s'\n", &json[i+1]);); node = domNewElementNode (parent->ownerDocument, &json[i+1]); domAppendChild (parent, node); json[j] = save; } i = j+1; skipspace(i); if (json[i] != ':') errReturn(i,JSON_SYNTAX_ERR); i++; skipspace(i); j = jsonParseValue (node, json, i, jparse); rc(j); i = j; skipspace(i); if (json[i] == '}') { jparse->nestingDepth--; jparse->within = savedWithin; return i+1; } if (json[i] == ',') { i++; skipspace(i); continue; } errReturn(i,JSON_SYNTAX_ERR); } } else if (c == '[') { /* Parse array */ if (++jparse->nestingDepth > jparse->maxnesting) errReturn(i,JSON_MAX_NESTING_REACHED); i++; skipspace(i); parent->info = JSON_ARRAY; if (jparse->within == JSON_WITHIN_ARRAY) { node = domNewElementNode (parent->ownerDocument, JSON_ARRAY_CONTAINER); node->info = JSON_ARRAY; domAppendChild(parent, node); } else { node = parent; } if (json[i] == ']') { /* empty array */ DBG(fprintf(stderr,"Empty JSON array.\n");); jparse->nestingDepth--; return i+1; } jparse->within = JSON_WITHIN_ARRAY; for (;;) { DBG(fprintf(stderr, "Next array value node '%s'\n", &json[i]);); skipspace(i); i = jsonParseValue (node, json, i, jparse); rc(i); skipspace(i); if (json[i] == ']') { jparse->within = savedWithin; jparse->nestingDepth--; return i+1; } if (json[i] == ',') { i++; continue; } errReturn(i,JSON_SYNTAX_ERR); } } else if (c == '"') { /* Parse string */ j = jsonParseString (json, i, jparse); rc(j); if (jparse->len && jparse->buf[0]) { DBG(fprintf(stderr, "New unescaped text node '%s'\n", jparse->buf)); newTextNode = domNewTextNode (parent->ownerDocument, jparse->buf, (domLength)strlen(jparse->buf), TEXT_NODE); domAppendChild (parent, (domNode *) newTextNode); } else { DBG(save = json[j];json[j] = '\0';fprintf(stderr, "New text node '%s'\n", &json[i+1]);json[j] = save;); newTextNode = domNewTextNode (parent->ownerDocument, &json[i+1], j-i-1, TEXT_NODE); domAppendChild (parent, (domNode *) newTextNode); } newTextNode->info = JSON_STRING; return j+1; } else if (c == 'n' && strncmp (json+i, "null", 4) == 0 && !isalnum(json[i+4])) { newTextNode = domNewTextNode (parent->ownerDocument, "null", 4, TEXT_NODE); newTextNode->info = JSON_NULL; domAppendChild (parent, (domNode *) newTextNode); return i+4; } else if (c == 't' && strncmp (json+i, "true", 4) == 0 && !isalnum(json[i+4])) { newTextNode = domNewTextNode (parent->ownerDocument, "true", 4, TEXT_NODE); newTextNode->info = JSON_TRUE; domAppendChild (parent, (domNode *) newTextNode); return i+4; } else if (c == 'f' && strncmp (json+i, "false", 5) == 0 && !isalnum(json[i+5])) { newTextNode = domNewTextNode (parent->ownerDocument, "false", 5, TEXT_NODE); newTextNode->info = JSON_FALSE; domAppendChild (parent, (domNode *) newTextNode); return i+5; } else if (c == '-' || (c>='0' && c<='9')) { /* Parse number */ int seenDP = 0; int seenE = 0; if (c<='0') { j = (c == '-' ? i+1 : i); if (json[j] == '0' && json[j+1] >= '0' && json[j+1] <= '9') errReturn(j+1,JSON_SYNTAX_ERR); } j = i+1; for (;; j++) { c = json[j]; if (c >= '0' && c <= '9') continue; if (c == '.') { if (json[j-1] == '-') errReturn(j,JSON_SYNTAX_ERR); if (seenDP) errReturn(j,JSON_SYNTAX_ERR); seenDP = 1; continue; } if (c == 'e' || c == 'E') { if (json[j-1] < '0') errReturn(j,JSON_SYNTAX_ERR); if (seenE) errReturn(j,JSON_SYNTAX_ERR); seenDP = seenE = 1; c = json[j+1]; if (c == '+' || c == '-') { j++; c = json[j+1]; } if (c < '0' || c > '9') errReturn(j,JSON_SYNTAX_ERR); continue; } break; } /* Catches a plain '-' without following digits */ if( json[j-1]<'0' ) errReturn(j-1,JSON_SYNTAX_ERR); DBG(save = json[j];json[j] = '\0';fprintf(stderr, "New text node '%s'\n", &json[i]);json[j] = save;); newTextNode = domNewTextNode (parent->ownerDocument, &json[i], j-i, TEXT_NODE); newTextNode->info = JSON_NUMBER; domAppendChild(parent, (domNode *) newTextNode); return j; } else if (c == '\0') { return 0; /* End of input */ } else { errReturn(i,JSON_SYNTAX_ERR); } } /* Helper function which checks if a given string is a JSON number. */ int isJSONNumber ( char *num, domLength numlen ) { domLength i; int seenDP, seenE; unsigned char c; if (numlen == 0) return 0; seenDP = 0; seenE = 0; i = 0; c = num[0]; if (!(c == '-' || (c>='0' && c<='9'))) return 0; if (c<='0') { i = (c == '-' ? i+1 : i); if (i+1 < numlen) { if (num[i] == '0' && num[i+1] >= '0' && num[i+1] <= '9') { return 0; } } } i = 1; for (; i < numlen; i++) { c = num[i]; if (c >= '0' && c <= '9') continue; if (c == '.') { if (num[i-1] == '-') return 0; if (seenDP) return 0; seenDP = 1; continue; } if (c == 'e' || c == 'E') { if (num[i-1] < '0') return 0; if (seenE) return 0; seenDP = seenE = 1; c = num[i+1]; if (c == '+' || c == '-') { i++; c = num[i+1]; } if (c < '0' || c > '9') return 0; continue; } break; } /* Catches a plain '-' without following digits */ if (num[i-1] < '0') return 0; /* Catches trailing chars */ if (i < numlen) return 0; return 1; } static TDOM_INLINE int getJSONTypeFromList ( Tcl_Interp *interp, Tcl_Obj *list, Tcl_Obj **typeValue ) { Tcl_Obj *symbol; char *s; domLength slen, llen; if (Tcl_ListObjIndex (interp, list, 0, &symbol) != TCL_OK) { return -1; } if (!symbol) { /* Empty lists are not allowed. */ SetResult ("Empty list."); return -1; } Tcl_ListObjLength (interp, list, &llen); if (llen > 2) { SetResult ("Too much list elements."); return -1; } Tcl_ListObjIndex (interp, list, 1, typeValue); s = Tcl_GetStringFromObj (symbol, &slen); if (strcmp (s, "STRING") == 0) { if (*typeValue == NULL) { SetResult ("Missing value for STRING."); return -1; } return JSON_STRING; } else if (strcmp (s, "OBJECT") == 0) { if (*typeValue == NULL) { SetResult ("Missing value for OBJECT."); return -1; } return JSON_OBJECT; } else if (strcmp (s, "NUMBER") == 0) { if (*typeValue == NULL) { SetResult ("Missing value for NUMBER."); return -1; } s = Tcl_GetStringFromObj (*typeValue, &slen); if (!isJSONNumber (s, slen)) { SetResult ("Not a valid NUMBER value."); return -1; } return JSON_NUMBER; } else if (strcmp (s, "ARRAY") == 0) { if (*typeValue == NULL) { SetResult ("Missing value for ARRAY."); return -1; } return JSON_ARRAY; } else if (strcmp (s, "TRUE") == 0) { if (*typeValue != NULL) { SetResult ("No value expected for TRUE."); return -1; } return JSON_TRUE; } else if (strcmp (s, "FALSE") == 0) { if (*typeValue != NULL) { SetResult ("No value expected for FALSE."); return -1; } return JSON_FALSE; } else if (strcmp (s, "NULL") == 0) { if (*typeValue != NULL) { SetResult ("No value expected for NULL."); return -1; } return JSON_NULL; } else { SetResult3 ("Unkown symbol \"", s, "\"."); return -1; } } static void objectErrMsg ( Tcl_Interp *interp, domNode *node ) { Tcl_Obj *msg; msg = Tcl_GetObjResult (interp); Tcl_IncrRefCount (msg); Tcl_ResetResult (interp); Tcl_AppendResult (interp, "object property \"", node->nodeName, "\": ", Tcl_GetString (msg), (char *)NULL); Tcl_DecrRefCount (msg); } static void arrayErrMsg ( Tcl_Interp *interp, domLength i ) { Tcl_Obj *msg; char buf[20]; msg = Tcl_GetObjResult (interp); Tcl_IncrRefCount (msg); Tcl_ResetResult (interp); sprintf (buf, domLengthConversion, i + 1); Tcl_AppendResult (interp, "array element ", buf, ": ", Tcl_GetString (msg), (char *) NULL); Tcl_DecrRefCount (msg); } static int TypedList2DOMWorker ( Tcl_Interp *interp, domNode *parent, Tcl_Obj *value ) { Tcl_Obj *property, *pvalue, *pdetail, *aelm, *adetail; domLength llen, i, strl; domNode *pnode, *container; domTextNode *textNode; char *str; int jsonType; switch (parent->info) { case JSON_OBJECT: if (Tcl_ListObjLength (interp, value, &llen) != TCL_OK) { return TCL_ERROR; } if (llen % 2 != 0) { SetResult ("An OBJECT value must be a Tcl list with an even " "number of elements."); return TCL_ERROR; } for (i = 0; i < llen; i += 2) { /* Since we loop over all elements every element is * present and there is no need to check property or * pvalue for NULL. */ Tcl_ListObjIndex (interp, value, i, &property); Tcl_ListObjIndex (interp, value, i+1, &pvalue); pnode = domAppendNewElementNode (parent, Tcl_GetString (property), NULL); jsonType = getJSONTypeFromList (interp, pvalue, &pdetail); if (jsonType < 0) { objectErrMsg (interp, pnode); return TCL_ERROR; } if (jsonType < 3) { /* JSON_OBJECT or JSON_ARRAY */ pnode->info = jsonType; if (TypedList2DOMWorker (interp, pnode, pdetail) != TCL_OK) { objectErrMsg (interp, pnode); return TCL_ERROR; } } else { /* The other json types are represented by a text node.*/ switch (jsonType) { case JSON_NUMBER: case JSON_STRING: str = Tcl_GetStringFromObj (pdetail, &strl); break; default: str = ""; strl = 0; break; } textNode = domNewTextNode (parent->ownerDocument, str, strl, TEXT_NODE); textNode->info = jsonType; domAppendChild (pnode, (domNode *) textNode); } } break; case JSON_ARRAY: if (Tcl_ListObjLength (interp, value, &llen) != TCL_OK) { return TCL_ERROR; } for (i = 0; i < llen; i++) { Tcl_ListObjIndex (interp, value, i, &aelm); jsonType = getJSONTypeFromList (interp, aelm, &adetail); if (jsonType < 0) { arrayErrMsg (interp, i); return TCL_ERROR; } switch (jsonType) { case JSON_OBJECT: container = domAppendNewElementNode (parent, JSON_OBJECT_CONTAINER, NULL); container->info = JSON_OBJECT; if (TypedList2DOMWorker (interp, container, adetail) != TCL_OK) { arrayErrMsg (interp, i); return TCL_ERROR; } break; case JSON_ARRAY: container = domAppendNewElementNode (parent, JSON_ARRAY_CONTAINER, NULL); container->info = JSON_ARRAY; if (TypedList2DOMWorker (interp, container, adetail) != TCL_OK) { arrayErrMsg (interp, i); return TCL_ERROR; } break; default: /* The other json types are represented by a text node.*/ switch (jsonType) { case JSON_NUMBER: case JSON_STRING: str = Tcl_GetStringFromObj (adetail, &strl); break; default: str = ""; strl = 0; break; } textNode = domNewTextNode (parent->ownerDocument, str, strl, TEXT_NODE); textNode->info = jsonType; domAppendChild (parent, (domNode *) textNode); break; } } break; default: /* Every "text node" JSON values are either done directly by * TypedList2DOM() or inline in the OBJECT and ARRAY cases in * this function. */ SetResult ("Internal error. Please report."); return TCL_ERROR; } return TCL_OK; } domDocument * TypedList2DOM ( Tcl_Interp *interp, Tcl_Obj *typedList ) { domDocument *doc; domNode *rootNode; domTextNode *textNode; Tcl_Obj *value, *msg; char *str; domLength strl; int jsonType; jsonType = getJSONTypeFromList (interp, typedList, &value); if (jsonType < 0) { msg = Tcl_GetObjResult (interp); Tcl_IncrRefCount (msg); Tcl_ResetResult (interp); Tcl_AppendResult (interp, "Invalid typed list format: ", Tcl_GetString (msg), (char *) NULL); Tcl_DecrRefCount (msg); return NULL; } doc = domCreateDoc (NULL, 0); rootNode = doc->rootNode; if (jsonType < 3) { /* JSON_OBJECT or JSON_ARRAY */ rootNode->info = jsonType; if (TypedList2DOMWorker (interp, rootNode, value) != TCL_OK) { msg = Tcl_GetObjResult (interp); Tcl_IncrRefCount (msg); domFreeDocument(doc, NULL, interp); Tcl_ResetResult (interp); Tcl_AppendResult (interp, "Invalid typed list format: ", Tcl_GetString (msg), (char *) NULL); Tcl_DecrRefCount (msg); return NULL; } } else { /* The other json types are represented by a text node.*/ if (jsonType > 5) { /* JSON_STRING or JSON_NUMBER */ str = Tcl_GetStringFromObj (value, &strl); } else { str = ""; strl = 0; } textNode = domNewTextNode (doc, str, strl, TEXT_NODE); textNode->info = jsonType; domAppendChild (rootNode, (domNode *) textNode); } return doc; } #define initescape(esc,esclen) *changed = 1; Tcl_DStringInit(escapedStr); \ Tcl_DStringAppend (escapedStr, str, (domLength)(p-str)); \ Tcl_DStringAppend (escapedStr, (esc), (esclen)); \ p += clen; str = p; break; #define escape(esc,esclen) Tcl_DStringAppend (escapedStr, str, (domLength)(p-str)); \ Tcl_DStringAppend (escapedStr, (esc), (esclen)); \ p += clen; str = p; continue; int jsonEscape ( Tcl_Interp *interp, char *str, Tcl_DString *escapedStr, int *changed ) { char *p; int clen; char buf[6] = "\\u00"; *changed = 0; p = str; while (*p) { /* The loop is left at the first character in the input string * which must be escaped (by a break in the initescape * define. */ clen = UTF8_CHAR_LEN(*p); if (!clen) { SetResult ("invalid internal string representation"); return TCL_ERROR; } if (clen == 1) { if (*p == '\\') { initescape("\\\\",2); } else if (*p == '"') { initescape("\\\"",2); } else if (*p == '\b') { initescape("\\b",2); } else if (*p == '\f') { initescape("\\f",2); } else if (*p == '\n') { initescape("\\n",2); } else if (*p == '\r') { initescape("\\r",2); } else if (*p == '\t') { initescape("\\t",2); } else if ((unsigned char)*p < 0x20) { buf[4] = '0' + (*p>>4); buf[5] = "0123456789abcdef"[*p&0xf]; initescape(buf,6); } p++; } else { if ((unsigned char)*p == 0xC0 && (unsigned char)*(p+1) == 0x80) { initescape("\\u0000",6); p++;p++; } else { p += clen; } } } if (!*changed) { return TCL_OK; } /* There was already a character to escape. We process the * remaning of the string and return the build up Tcl_DString. */ while (*p) { clen = UTF8_CHAR_LEN(*p); if (!clen) { SetResult ("invalid internal string representation"); return TCL_ERROR; } if (clen == 1) { if (*p == '\\') { escape("\\\\",2); } else if (*p == '"') { escape("\\\"",2); } else if (*p == '\b') { escape("\\b",2); } else if (*p == '\f') { escape("\\f",2); } else if (*p == '\n') { escape("\\n",2); } else if (*p == '\r') { escape("\\r",2); } else if (*p == '\t') { escape("\\t",2); } else if ((unsigned char)*p < 0x20) { buf[4] = '0' + (*p>>4); buf[5] = "0123456789abcdef"[*p&0xf]; escape(buf,6); } p++; } else { if ((unsigned char)*p == 0xC0 && (unsigned char)*(p+1) == 0x80) { escape("\\u0000",6); p++;p++; } else { p += clen; } } } Tcl_DStringAppend (escapedStr, str, (domLength)(p-str)); return TCL_OK; } domDocument * JSON_Parse ( char *json, /* Complete text of the json string being parsed */ char *documentElement, /* name of the root element, may be NULL */ int maxnesting, char **errStr, domLength *byteIndex ) { domDocument *doc = domCreateDoc (NULL, 0); domNode *root; Tcl_HashEntry *h; JSONParse jparse; int hnew; domLength pos = 0; h = Tcl_CreateHashEntry(&HASHTAB(doc, tdom_tagNames), "item", &hnew); jparse.state = JSON_OK; jparse.within = JSON_START; jparse.nestingDepth = 0; jparse.maxnesting = maxnesting; jparse.arrItemElm = (char*)&h->key; jparse.buf = NULL; jparse.len = 0; skipspace(pos); if (json[pos] == '\0') { *byteIndex = pos; jparse.state = JSON_SYNTAX_ERR; goto reportError; } if (documentElement) { root = domNewElementNode(doc, documentElement); domAppendChild(doc->rootNode, root); } else { root = doc->rootNode; } *byteIndex = jsonParseValue (root, json, pos, &jparse ); if (jparse.state != JSON_OK) goto reportError; if (*byteIndex > 0) { pos = *byteIndex; skipspace(pos); } if (json[pos] != '\0') { *byteIndex = pos; jparse.state = JSON_SYNTAX_ERR; goto reportError; } if (jparse.len > 0) { FREE (jparse.buf); } domSetDocumentElement (doc); return doc; reportError: if (jparse.len > 0) { FREE (jparse.buf); } domFreeDocument (doc, NULL, NULL); doc = NULL; *errStr = (char *)JSONParseStateStr[jparse.state]; return doc; } tdom-0.9.6-src/generic/expat_config.h0000644000175000017500000000005015025767703016206 0ustar rolfrolf/* an empty/fake config.h for expat */ tdom-0.9.6-src/generic/nodecmd.h0000644000175000017500000000516415025767703015164 0ustar rolfrolf/*---------------------------------------------------------------------------- | Copyright (C) 1999 Jochen C. Loewer (loewerj@hotmail.com) +----------------------------------------------------------------------------- | | The contents of this file are subject to the Mozilla Public License | Version 2.0 (the "License"); you may not use this file except in | compliance with the License. You may obtain a copy of the License at | http://www.mozilla.org/MPL/ | | Software distributed under the License is distributed on an "AS IS" | basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the | License for the specific language governing rights and limitations | under the License. | | The Original Code is tDOM. | | The Initial Developer of the Original Code is Jochen Loewer | | Portions created by Jochen Loewer are Copyright (C) 1998, 1999 | Jochen Loewer. All Rights Reserved. | | Portions created by Zoran Vasiljevic are Copyright (C) 2000-2002 | Zoran Vasiljevic. All Rights Reserved. | | Portions created by Rolf Ade are Copyright (C) 1999-2002 | Rolf Ade. All Rights Reserved. | | Written by Zoran Vasiljevic | July 12, 2000 | \---------------------------------------------------------------------------*/ /* append/insertbeforeFromScript related flags */ #define FS_ATT_NO_NAMESPACED 1 #define FS_NOT_EMPTY 2 int nodecmd_createNodeCmd (Tcl_Interp * interp, int objc, Tcl_Obj *const objv[], int checkName, int checkCharData); int nodecmd_appendFromScript (Tcl_Interp *interp, domNode *node, Tcl_Obj *cmdObj); int nodecmd_insertBeforeFromScript (Tcl_Interp *interp, domNode *node, Tcl_Obj *cmdObj, domNode *refChild); int nodecmd_processAttributes (Tcl_Interp *interp, domNode *node, int type, int objc, Tcl_Obj *const objv[], Tcl_Obj **cmdObj, int flags); domNode * nodecmd_currentNode (Tcl_Interp *interp); void nodecmd_init (Tcl_Interp *interp); /* EOF $RCSfile $ */ /* Emacs Setup Variables */ /* Local Variables: */ /* mode: C */ /* indent-tabs-mode: nil */ /* c-basic-offset: 4 */ /* End: */ tdom-0.9.6-src/generic/domalloc.c0000644000175000017500000005006415025767703015337 0ustar rolfrolf/*--------------------------------------------------------------------------- | Copyright (C) 1999-2000 Jochen C. Loewer (loewerj@hotmail.com) +---------------------------------------------------------------------------- | | A special memory allocator, which uses preallocated / bit masked | based administration of memory blocks with fixed sizes, like | DOM nodes. This will hopefully save some memory. | | | The contents of this file are subject to the Mozilla Public License | Version 2.0 (the "License"); you may not use this file except in | compliance with the License. You may obtain a copy of the License at | http://www.mozilla.org/MPL/ | | Software distributed under the License is distributed on an "AS IS" | basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the | License for the specific language governing rights and limitations | under the License. | | The Original Code is tDOM. | | The Initial Developer of the Original Code is Jochen Loewer | Portions created by Jochen Loewer are Copyright (C) 1998, 1999 | Jochen Loewer. All Rights Reserved. | | Contributor(s): | | | written by Jochen Loewer | October, 2000 | \--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------- | Includes | \--------------------------------------------------------------------------*/ #include #include #include #include /*--------------------------------------------------------------------------- | Defines | \--------------------------------------------------------------------------*/ #define DBG(x) #define MAX_BINS 256 #define BIN_HASH_SIZE 512 #define BIN_HASH_MASK 0x01FF #define CACHE_SIZE 4 #define BLOCK_DATA_SIZE 31000 #define BLOCK_SIZE_BITS 16 /*--------------------------------------------------------------------------- | Typedefs | \--------------------------------------------------------------------------*/ typedef struct domAllocBlock { struct domAllocBin * bin; void * end; struct domAllocBlock * prev; struct domAllocBlock * next; int hashIndex1; struct domAllocBlock * hashNext1; int hashIndex2; struct domAllocBlock * hashNext2; int slots; int freeSlots; int bitmaps; int freePos; int freeBit; unsigned int freeMask; } domAllocBlock; typedef struct domAllocBin { int size; int nrSlots; int freeSlots; int nrBlocks; domAllocBlock * freeBlocks; domAllocBlock * usedBlocks; } domAllocBin; typedef struct domAllocBins { struct domAllocBin * bin[MAX_BINS]; struct domAllocBlock * hashedBlocks[BIN_HASH_SIZE]; struct domAllocBlock * blockCache[CACHE_SIZE]; } domAllocBins; /*--------------------------------------------------------------------------- | Globals. This is a "single-threaded" allocator. | \--------------------------------------------------------------------------*/ static domAllocBins bins; #ifdef TCL_THREADS # define TDomThreaded(x) x static Tcl_Mutex binMutex; #else # define TDomThreaded(x) #endif /*--------------------------------------------------------------------------- | domAllocInit | \--------------------------------------------------------------------------*/ void domAllocInit() { int i; DBG(fprintf(stderr, "domAllocInit...\n");) for (i=0; i < MAX_BINS; i++) bins.bin[i] = NULL; for (i=0; i < CACHE_SIZE; i++) bins.blockCache[i] = NULL; for (i=0; i < BIN_HASH_SIZE; i++) bins.hashedBlocks[i] = NULL; } /*-------------------------------------------------------------------------- | fillHashTable | \--------------------------------------------------------------------------*/ static void fillHashTable ( domAllocBlock * block, void * mem ) { domAllocBlock * hashedBlock; unsigned int i; i = ( (unsigned int)mem >> BLOCK_SIZE_BITS) & BIN_HASH_MASK; hashedBlock = bins.hashedBlocks[i]; while (hashedBlock != NULL) { if (hashedBlock == block) { /* all is fine, block is already in hash table */ return; } if (hashedBlock->hashIndex1 == (int)i) hashedBlock = hashedBlock->hashNext1; else if (hashedBlock->hashIndex2 == (int)i) hashedBlock = hashedBlock->hashNext2; else hashedBlock = NULL; } /* add block in hash table */ if (block->hashIndex1 == -1) { block->hashIndex1 = i; block->hashNext1 = bins.hashedBlocks[i]; } else if (block->hashIndex2 == -1) { block->hashIndex2 = i; block->hashNext2 = bins.hashedBlocks[i]; } else { DBG( fprintf(stderr, "\ntoo many hash entries for %x %x->%d %d,%d!\n", (unsigned int)block, (unsigned int)mem, i, block->hashIndex1, block->hashIndex2);) } bins.hashedBlocks[i] = block; } /*-------------------------------------------------------------------------- | domAlloc | \--------------------------------------------------------------------------*/ void * domAlloc ( int size ) { domAllocBin * bin; domAllocBlock * block; domAllocBlock * hashedBlock; int i, j, slots, bitmaps, blockSize; unsigned int mask; char * mem; unsigned int * usedBitmap; DBG(fprintf(stderr, "\ndomAlloc %d \n", size);) if (size >= MAX_BINS) { DBG(fprintf(stderr, "\nSize too large as used for bin!\n");) return NULL; } /*------------------------------------------------- | FIXME | | Rewrite with TSD-based bins to avoid mutex | contention. Threads are going to step on | each other toes here which is not what we | would like to have, don't we ? (zv) \------------------------------------------------*/ TDomThreaded(Tcl_MutexLock(&binMutex);) /* LOCK !*/ if (bins.bin[size] == NULL) { /*------------------------------------------------- | create new bin \------------------------------------------------*/ bin = (domAllocBin *)malloc(sizeof(domAllocBin)); bin->size = size; bin->nrSlots = 0; bin->freeSlots = 0; bin->nrBlocks = 0; bin->freeBlocks = NULL; bin->usedBlocks = NULL; bins.bin[size] = bin; } else { bin = bins.bin[size]; } if (bin->freeSlots == 0) { DBG(fprintf(stderr, "allocating new block ... \n");) /*---------------------------------------------------------------- | allocate and initialize a new block | \---------------------------------------------------------------*/ bitmaps = (BLOCK_DATA_SIZE / size) / 32; slots = bitmaps * 32; blockSize = sizeof(domAllocBlock) + bitmaps*4 + slots*size; block = (domAllocBlock *)malloc( blockSize ); block->bin = bin; block->end = (char*)block + blockSize; block->slots = slots; block->freeSlots = slots; block->bitmaps = bitmaps; block->freePos = 0; block->freeBit = 0; block->freeMask = 0x80000000; block->hashIndex1 = -1; block->hashNext1 = NULL; block->hashIndex2 = -1; block->hashNext2 = NULL; usedBitmap = (unsigned int *) ((char*)block + sizeof(domAllocBlock)); memset(usedBitmap, 0, bitmaps * 4); bin->nrSlots += slots; bin->freeSlots += slots; bin->nrBlocks++; block->prev = NULL; /* prepend this new block to free list */ block->next = bin->freeBlocks; bin->freeBlocks = block; /*--------------------------------------------------------- | enter block in 'hash' table: | first and last memory location could have different | hash entries due to different upper address bits \--------------------------------------------------------*/ mem = (char*)usedBitmap + bitmaps * 4; fillHashTable (block, mem); mem += (slots-1) * size; fillHashTable (block, mem); } else { block = bin->freeBlocks; } /*------------------------------------------------------------------------ | find free slot in (partial) free block | \-----------------------------------------------------------------------*/ usedBitmap = (unsigned int *) ((char*)block + sizeof(domAllocBlock)); i = block->freePos; /* start at old pos to quickly find a free slot */ j = block->freeBit; mask = block->freeMask; do { DBG(fprintf(stderr, "looking %d slot i=%d j=%d %x mask %x\n", size, i, j, usedBitmap[i], mask); ) if (usedBitmap[i] != 0xFFFFFFFF) { do { if ((usedBitmap[i] & mask)==0) { DBG(fprintf(stderr, "found free slot i=%d j=%d %x mask %x\n", i, j, usedBitmap[i], mask); ) mem = ((char*)usedBitmap) + (4*block->bitmaps) + ((i*32)+j) * size; usedBitmap[i] |= mask; block->freeSlots--; bin->freeSlots--; if (block->freeSlots == 0) { DBG(fprintf(stderr, "freeSlots == 0\n");) if (block->prev == NULL) { /* remove block from free list */ bin->freeBlocks = block->next; } else { block->prev->next = block->next; } if (block->next) block->next->prev = block->prev; block->next = bin->usedBlocks; /* add block to used list */ if (block->next) block->next->prev = block; block->prev = NULL; bin->usedBlocks = block; /* check consistency */ hashedBlock = block->bin->freeBlocks; while (hashedBlock) { if (hashedBlock == block) { DBG(fprintf(stderr, "strange block still in free list \n");) } hashedBlock = hashedBlock->next; } } /* keep found free position for later, * so that next slots can be found quickly */ block->freePos = i; j++; mask = mask >> 1; if (j >= 32) { j = 0; mask = 0x80000000; } block->freeBit = j; block->freeMask = mask; TDomThreaded(Tcl_MutexUnlock(&binMutex);) /* UNLOCK !*/ return mem; } j++; mask = mask >> 1; if (j >= 32) { j = 0; mask = 0x80000000; } } while (j != block->freeBit); } i++; if (i >= block->bitmaps) i = 0; } while (i != block->freePos); /* TDomThreaded(Tcl_MutexUnlock(&binMutex);) */ DBG(fprintf(stderr, "\ndomAlloc: can't happen! \n");) *((char*)0) = 0; /* Use Tcl_Panic() for this ? */ return NULL; } /*--------------------------------------------------------------------------- | domFree | \--------------------------------------------------------------------------*/ void domFree ( void * mem ) { domAllocBlock * block; domAllocBlock * hashedBlock; domAllocBlock * prevBlock; domLength slotNr, i, foundInCache; unsigned int * usedBitmap; unsigned int mask; DBG(fprintf(stderr, "domFree...\n");) if (mem == NULL) return; /*------------------------------------------------- | FIXME (see domAlloc comments) | \------------------------------------------------*/ TDomThreaded(Tcl_MutexLock(&binMutex);) /*------------------------------------------------------------------- | Find the block, which corresponds to the given memory location | | - First try to look in the memory range cache. | \------------------------------------------------------------------*/ block = NULL; foundInCache = 0; for (i=0; i < CACHE_SIZE; i++) { if ((bins.blockCache[i] != NULL) && (mem > (void*)(bins.blockCache[i])) && (mem < (void*)(bins.blockCache[i]->end))) { block = bins.blockCache[i]; foundInCache = 1; break; } } /*------------------------------------------------------------------- | - Otherwise try to lookup corresponding block in hashtable | \------------------------------------------------------------------*/ if (!foundInCache) { i = ( (unsigned int)mem >> BLOCK_SIZE_BITS) & BIN_HASH_MASK; block = bins.hashedBlocks[i]; while (block != NULL) { if ((mem > (void*)block) && (mem < (void*)(block->end))) break; if (block->hashIndex1 == i) block = block->hashNext1; else if (block->hashIndex2 == i) block = block->hashNext2; else block = NULL; } } if (block == NULL) { DBG(fprintf(stderr, "\n unable to free mem %x !\n", (unsigned int)mem);) TDomThreaded(Tcl_MutexUnlock(&binMutex);) return; } /*------------------------------------------------------------------- | clear the allocation bit \------------------------------------------------------------------*/ usedBitmap = (unsigned int *) ((char*)block + sizeof(domAllocBlock)); slotNr = ( (char*)mem - (char*)usedBitmap - block->bitmaps*4 ) / block->bin->size; DBG( if (slotNr >= block->slots) { fprintf(stderr, "assertion failed: slotNr = %d \n", slotNr); }) i = slotNr >> 5 ; /* slotNr / 32 */ mask = 0x80000000 >> (slotNr % 32); usedBitmap[i] &= ~mask; block->freeSlots++; block->bin->freeSlots++; DBG( if ((block->freeSlots < 1) || (block->freeSlots > block->slots)) { fprintf(stderr, "assertion failed: freeSlots = %d \n", block->freeSlots); }) /*------------------------------------------------------------------- | update free/used lists \------------------------------------------------------------------*/ if (block->freeSlots == 1) { if (block->prev == NULL) { /* remove block from used list */ block->bin->usedBlocks = block->next; } else { block->prev->next = block->next; } if (block->next) block->next->prev = block->prev; block->next = block->bin->freeBlocks; /* add block to free list */ if (block->next) block->next->prev = block; block->prev = NULL; block->bin->freeBlocks = block; DBG( /* check consistency */ hashedBlock = block->bin->usedBlocks; while (hashedBlock) { if (hashedBlock == block) { fprintf(stderr, "strange block still in used list \n"); } hashedBlock = hashedBlock->next; } ) } /*------------------------------------------------------------------- | free the whole block, when all slots are freed \------------------------------------------------------------------*/ if (block->freeSlots == block->slots) { DBG(fprintf(stderr, "block completely freed %x\n", (unsigned int)block);) if (block->prev == NULL) { /* remove block from free list */ block->bin->freeBlocks = block->next; } else { block->prev->next = block->next; } if (block->next) block->next->prev = block->prev; block->bin->nrSlots -= block->slots; block->bin->freeSlots -= block->slots; block->bin->nrBlocks--; /*-------------------------------------------------------------------- | remove block from (two) hash lists \-------------------------------------------------------------------*/ i = block->hashIndex1; if (i != -1) { DBG(fprintf(stderr, "remove from hash list %d \n", i);) prevBlock = NULL; hashedBlock = bins.hashedBlocks[i]; while (hashedBlock) { if (hashedBlock == block) break; prevBlock = hashedBlock; if (hashedBlock->hashIndex1 == i) hashedBlock = hashedBlock->hashNext1; else if (hashedBlock->hashIndex2 == i) hashedBlock = hashedBlock->hashNext2; else hashedBlock = NULL; } if (prevBlock == NULL) { bins.hashedBlocks[i] = block->hashNext1; } else { if (prevBlock->hashIndex1 == i) prevBlock->hashNext1 = block->hashNext1; else if (prevBlock->hashIndex2 == i) prevBlock->hashNext2 = block->hashNext1; } } i = block->hashIndex2; if (i != -1) { DBG(fprintf(stderr, "remove from hash list %d \n", i);) prevBlock = NULL; hashedBlock = bins.hashedBlocks[i]; while (hashedBlock) { if (hashedBlock == block) break; prevBlock = hashedBlock; if (hashedBlock->hashIndex1 == i) hashedBlock = hashedBlock->hashNext1; else if (hashedBlock->hashIndex2 == i) hashedBlock = hashedBlock->hashNext2; else hashedBlock = NULL; } if (prevBlock == NULL) { bins.hashedBlocks[i] = block->hashNext2; } else { if (prevBlock->hashIndex1 == i) prevBlock->hashNext1 = block->hashNext2; else if (prevBlock->hashIndex2 == i) prevBlock->hashNext2 = block->hashNext2; } } /*------------------------------------------------------ | remove block from cache, if found \-----------------------------------------------------*/ for (i=0; i < CACHE_SIZE; i++) { if (bins.blockCache[i] == block) { bins.blockCache[i] = NULL; } } DBG( /* check consistency */ for (i=0; i < block->bitmaps; i++) { if (usedBitmap[i] != 0) { fprintf(stderr, "strange bitmap %d is %x \n", i, usedBitmap[i]); } } for (i=0; i < BIN_HASH_SIZE; i++) { hashedBlock = bins.hashedBlocks[i]; while (hashedBlock) { if (hashedBlock == block) { fprintf(stderr, "strange block %d still in hash table \n", i); } if (hashedBlock->hashIndex1 == i) hashedBlock = hashedBlock->hashNext1; else if (hashedBlock->hashIndex2 == i) hashedBlock = hashedBlock->hashNext2; else hashedBlock = NULL; } } hashedBlock = block->bin->freeBlocks; while (hashedBlock) { if (hashedBlock == block) { fprintf(stderr, "strange block still in free list \n"); } hashedBlock = hashedBlock->next; } hashedBlock = block->bin->usedBlocks; while (hashedBlock) { if (hashedBlock == block) { fprintf(stderr, "strange block still in used list \n"); } hashedBlock = hashedBlock->next; } ) free((char*)block); } else { /*----------------------------------------------------------- | update cache \----------------------------------------------------------*/ if (!foundInCache) { /* remove oldest entry and add this block */ for (i=1; i < CACHE_SIZE; i++) { bins.blockCache[i-1] = bins.blockCache[i]; } bins.blockCache[CACHE_SIZE-1] = block; } } TDomThreaded(Tcl_MutexUnlock(&binMutex);) /* UNLOCK !*/ } tdom-0.9.6-src/generic/tdom.h0000644000175000017500000000037115025767703014511 0ustar rolfrolf #define __TDOM_H #include "tcl.h" #include #include #undef TCL_STORAGE_CLASS #ifdef BUILD_tdom # define TCL_STORAGE_CLASS DLLEXPORT #else # define TCL_STORAGE_CLASS DLLIMPORT #endif #include "dom.h" #include "tdomDecls.h" tdom-0.9.6-src/generic/tcldom.h0000644000175000017500000000677015025767703015041 0ustar rolfrolf/*---------------------------------------------------------------------------- | Copyright (c) 1999 Jochen Loewer (loewerj@hotmail.com) +----------------------------------------------------------------------------- | | A DOM implementation for Tcl using James Clark's expat XML parser | | | The contents of this file are subject to the Mozilla Public License | Version 2.0 (the "License"); you may not use this file except in | compliance with the License. You may obtain a copy of the License at | http://www.mozilla.org/MPL/ | | Software distributed under the License is distributed on an "AS IS" | basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the | License for the specific language governing rights and limitations | under the License. | | The Original Code is tDOM. | | The Initial Developer of the Original Code is Jochen Loewer | Portions created by Jochen Loewer are Copyright (C) 1998, 1999 | Jochen Loewer. All Rights Reserved. | | Contributor(s): | | | written by Jochen Loewer | April, 1999 | \---------------------------------------------------------------------------*/ #ifndef __TCLDOM_H_INCLUDE__ #define __TCLDOM_H_INCLUDE__ #include #ifdef __cplusplus extern "C" { #endif /* The following procs are defined in tcldom.c - since they are used * in nodecmd.c these need a prototype somewhere. The prototypes can * live here for now. */ int tcldom_textCheck(Tcl_Interp *interp, char *text, char *errText); int tcldom_commentCheck(Tcl_Interp *interp, char *text); int tcldom_CDATACheck(Tcl_Interp *interp, char *text); int tcldom_PIValueCheck(Tcl_Interp *interp, char *text); int tcldom_PINameCheck(Tcl_Interp *interp, char *name); int tcldom_nameCheck(Tcl_Interp *interp, char *name, char *nameType, int isFQName); void tcldom_createNodeObj(Tcl_Interp * interp, domNode *node, char *objCmdName); domNode * tcldom_getNodeFromObj(Tcl_Interp *interp, Tcl_Obj *nodeObj); #ifndef __TDOM_H domDocument * tcldom_getDocumentFromName(Tcl_Interp *interp, char *docName, char **errMsg); #endif int tcldom_prefixNSlist (char ***prefixnsPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], const char *methodName); int tcldom_setInterpAndReturnVar (Tcl_Interp *interp, domNode *node, Tcl_Obj *var_name); void tcldom_initialize(void); void tcldom_deleteDoc (Tcl_Interp *interp, domDocument *doc); Tcl_ObjCmdProc tcldom_DomObjCmd; Tcl_ObjCmdProc tcldom_DocObjCmd; Tcl_ObjCmdProc tcldom_NodeObjCmd; Tcl_ObjCmdProc tcldom_unknownCmd; Tcl_ObjCmdProc TclTdomObjCmd; int tDOM_fsnewNodeCmd (ClientData clientData, Tcl_Interp * interp, int objc, Tcl_Obj *const objv[]); int tDOM_fsinsertNodeCmd (ClientData clientData, Tcl_Interp * interp, int objc, Tcl_Obj *const objv[]); void tcldom_reportErrorLocation ( Tcl_Interp *interp, int before, int after, XML_Size line, XML_Size column, char *xmlstring, const char *entity, XML_Index byteIndex, const char *errStr ); #ifdef __cplusplus } #endif #if defined(_MSC_VER) || defined(__MINGW32__) # undef TCL_STORAGE_CLASS # define TCL_STORAGE_CLASS DLLEXPORT #endif #define STR_TDOM_VERSION(v) (VERSION) EXTERN int Tdom_Init (Tcl_Interp *interp); EXTERN int Tdom_SafeInit (Tcl_Interp *interp); #endif tdom-0.9.6-src/generic/tclexpat.c0000644000175000017500000044726415025767703015405 0ustar rolfrolf/* * tclexpat.c -- * * A Tcl interface to James Clark's expat XML parser * * Copyright (c) 1998 Steve Ball, Zveno Pty Ltd * * with modifications * by Jochen Loewer(loewerj@hotmail.com) (July 1999) * by ericm@scriptics.com, 1999.6.25 * by Rolf Ade (rolf@pointsman.de) (2000, 2001) * * * Zveno Pty Ltd makes this software and associated documentation * available free of charge for any purpose. You may make copies * of the software but you must include all of this notice on any copy. * * Zveno Pty Ltd does not warrant that this software is error free * or fit for any purpose. Zveno Pty Ltd disclaims any liability for * all claims, expenses, losses, damages and costs any user may incur * as a result of using, copying or modifying the software. * * Jochen Loewer does not warrant that this software is error free * or fit for any purpose. Jochen Loewer disclaims any liability for * all claims, expenses, losses, damages and costs any user may incur * as a result of using, copying or modifying the software. * * 2001-2024 Rolf Ade All changes and enhancements. * */ /*---------------------------------------------------------------------------- | Includes | \---------------------------------------------------------------------------*/ #include #include #include #include #include #include #ifdef _MSC_VER #include #else #include #endif /* Used internal als status, like TCL_OK, TCL_ERROR etc. As a consequence, application specific error codes must be at least greater than 5 */ #define ERROR_IN_EXTREFHANDLER 5 #ifndef TDOM_EXPAT_READ_SIZE # define TDOM_EXPAT_READ_SIZE (1024*8) #endif #ifndef O_BINARY #ifdef _O_BINARY #define O_BINARY _O_BINARY #else #define O_BINARY 0 #endif #endif /*---------------------------------------------------------------------------- | Macros | \---------------------------------------------------------------------------*/ #define DBG(x) #define SetResult(interp,str) \ (Tcl_SetStringObj (Tcl_GetObjResult (interp), (str), -1)) #define SetIntResult(interp,i) \ (Tcl_SetDomLengthObj (Tcl_GetObjResult (interp), (i) )) #define AppendResult(interp,str) \ (Tcl_AppendToObj (Tcl_GetObjResult (interp), (str), -1)) #define CheckArgs(min,max,n,msg) \ if ((objc < min) || (objc >max)) { \ Tcl_WrongNumArgs(interp, n, objv, msg); \ return TCL_ERROR; \ } #define CheckDefaultTclHandlerSet \ if (!activeTclHandlerSet) { \ activeTclHandlerSet = CreateTclHandlerSet("default");\ tmpTclHandlerSet = expat->firstTclHandlerSet; \ expat->firstTclHandlerSet = activeTclHandlerSet; \ activeTclHandlerSet->nextHandlerSet = tmpTclHandlerSet; \ } #define SetResult3(str1,str2,str3) Tcl_ResetResult(interp); \ Tcl_AppendResult(interp, (str1), (str2), (str3), NULL) /*---------------------------------------------------------------------------- | typedefs | \---------------------------------------------------------------------------*/ typedef enum { EXPAT_INPUT_STRING, EXPAT_INPUT_CHANNEL, EXPAT_INPUT_FILENAME } TclExpat_InputType; /*---------------------------------------------------------------------------- | local globals | \---------------------------------------------------------------------------*/ static int uniqueCounter = 0; /* Counter to generate unique command names */ TDomThreaded(static Tcl_Mutex counterMutex;) /* Protect the counter (zv) */ /*---------------------------------------------------------------------------- | Prototypes for procedures defined later in this file: | \---------------------------------------------------------------------------*/ int TclExpatObjCmd (ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); static int TclExpatInstanceCmd (ClientData dummy, Tcl_Interp *interp, int objc, struct Tcl_Obj *const objv[]); static void TclExpatDeleteCmd (ClientData clientData); static Tcl_Obj* FindUniqueCmdName (Tcl_Interp *interp); static int TclExpatCheckWhiteData (char *pc, domLength len); static int TclExpatInitializeParser (Tcl_Interp *interp, TclGenExpatInfo *expat, int resetOptions ); static void TclExpatFreeParser (TclGenExpatInfo *expat); static int TclExpatParse (Tcl_Interp *interp, TclGenExpatInfo *expat, char *data, domLength len, TclExpat_InputType type); static int TclExpatConfigure (Tcl_Interp *interp, TclGenExpatInfo *expat, int objc, Tcl_Obj *const objv[]); static int TclExpatCget (Tcl_Interp *interp, TclGenExpatInfo *expat, int objc, Tcl_Obj *const objv[]); static int TclExpatGet (Tcl_Interp *interp, TclGenExpatInfo *expat, int objc, Tcl_Obj *const objv[]); static void TclExpatDispatchPCDATA (TclGenExpatInfo *expat); static void TclGenExpatElementStartHandler (void *userdata, const XML_Char *name, const XML_Char **atts); static void TclGenExpatElementEndHandler (void *userData, const XML_Char *name); static void TclGenExpatCharacterDataHandler (void *userData, const XML_Char *s, int len); static void TclGenExpatProcessingInstructionHandler ( void *userData, const XML_Char *target, const XML_Char *data); static int TclGenExpatExternalEntityRefHandler ( XML_Parser parser, const XML_Char *openEntityNames, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId); static void TclGenExpatDefaultHandler (void *userData, const XML_Char *s, int len); static void TclGenExpatNotationDeclHandler (void *userData, const XML_Char *notationName, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId); static int TclGenExpatUnknownEncodingHandler ( void *encodingHandlerData, const XML_Char *name, XML_Encoding *info); static void TclGenExpatStartNamespaceDeclHandler (void *userdata, const XML_Char *prefix, const XML_Char *uri); static void TclGenExpatEndNamespaceDeclHandler (void *userData, const XML_Char *prefix); /* Following added by ericm@scriptics, 1999.6.25 */ /* Prototype definition for the TclExpat comment handler */ static void TclGenExpatCommentHandler (void *userData, const XML_Char *data); /* Prototype for TclExpat Not Standalone Handler */ static int TclGenExpatNotStandaloneHandler (void *userData); /* Prototype for TclExpat {Start|End}CdataSectionHandler */ static void TclGenExpatStartCdataSectionHandler (void *userData); static void TclGenExpatEndCdataSectionHandler (void *userData); /* Added by ericm@scriptics.com, 1999.09.13 */ /* Prototype for TclExpat (Element|Attlist) Declaration Handlers */ static void TclGenExpatElementDeclHandler (void *userData, const XML_Char *name, XML_Content *model); static void TclGenExpatAttlistDeclHandler (void *userData, const XML_Char *elname, const XML_Char *name, const XML_Char *type, const XML_Char *dflt, int isrequired); /* Prototypes for the TclExpat Doctype Decl handlers */ static void TclGenExpatStartDoctypeDeclHandler ( void *userData, const XML_Char *doctypeName, const XML_Char *sysid, const XML_Char *pubid, int has_internal_subset); static void TclGenExpatEndDoctypeDeclHandler (void *userData); static void TclGenExpatXmlDeclHandler (void *userData, const XML_Char *version, const XML_Char *encoding, int standalone); static void TclGenExpatEntityDeclHandler (void *userData, const XML_Char *entityname, int is_param, const XML_Char *value, int length, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId, const XML_Char *notationName); /* *---------------------------------------------------------------------------- * * CreateTclHandlerSet -- * * Malloc's and initializes a tclHandlerSet. * * Results: * None. * * Side effects: * Mallocs memory for the structure and the 'name' field, sets all * handler scripts to NULL and inits some other fields. * *---------------------------------------------------------------------------- */ static TclHandlerSet* CreateTclHandlerSet ( char *name ) { TclHandlerSet *handlerSet; handlerSet = (TclHandlerSet*) MALLOC (sizeof (TclHandlerSet)); \ handlerSet->name = tdomstrdup (name); handlerSet->ignoreWhiteCDATAs = 0; handlerSet->status = TCL_OK; handlerSet->continueCount = 0; handlerSet->nextHandlerSet = NULL; handlerSet->fastCall = 0; handlerSet->elementstartcommand = NULL; handlerSet->elementendcommand = NULL; handlerSet->startnsdeclcommand = NULL; handlerSet->endnsdeclcommand = NULL; handlerSet->datacommand = NULL; handlerSet->picommand = NULL; handlerSet->defaultcommand = NULL; handlerSet->notationcommand = NULL; handlerSet->externalentitycommand = NULL; handlerSet->unknownencodingcommand = NULL; handlerSet->commentCommand = NULL; handlerSet->notStandaloneCommand = NULL; handlerSet->startCdataSectionCommand = NULL; handlerSet->endCdataSectionCommand = NULL; handlerSet->elementDeclCommand = NULL; handlerSet->attlistDeclCommand = NULL; handlerSet->startDoctypeDeclCommand = NULL; handlerSet->endDoctypeDeclCommand = NULL; handlerSet->xmlDeclCommand = NULL; handlerSet->entityDeclCommand = NULL; return handlerSet; } /* *---------------------------------------------------------------------------- * * CHandlerSetCreate -- * * Initializes a CHandlerSet. * * Results: * None. * * Side effects: * Mallocs memory for the 'name' of the structure, sets all * handler functions to NULL and inits some other fields. * *---------------------------------------------------------------------------- */ CHandlerSet* CHandlerSetCreate ( char *name ) { CHandlerSet *handlerSet; handlerSet = (CHandlerSet *) MALLOC (sizeof (CHandlerSet)); handlerSet->name = tdomstrdup (name); handlerSet->ignoreWhiteCDATAs = 0; handlerSet->nextHandlerSet = NULL; handlerSet->userData = NULL; handlerSet->resetProc = NULL; handlerSet->freeProc = NULL; handlerSet->initParseProc = NULL; handlerSet->parserResetProc = NULL; handlerSet->elementstartcommand = NULL; handlerSet->elementendcommand = NULL; handlerSet->startnsdeclcommand = NULL; handlerSet->endnsdeclcommand = NULL; handlerSet->datacommand = NULL; handlerSet->picommand = NULL; handlerSet->defaultcommand = NULL; handlerSet->notationcommand = NULL; handlerSet->externalentitycommand = NULL; handlerSet->unknownencodingcommand = NULL; handlerSet->commentCommand = NULL; handlerSet->notStandaloneCommand = NULL; handlerSet->startCdataSectionCommand = NULL; handlerSet->endCdataSectionCommand = NULL; handlerSet->elementDeclCommand = NULL; handlerSet->attlistDeclCommand = NULL; handlerSet->startDoctypeDeclCommand = NULL; handlerSet->endDoctypeDeclCommand = NULL; handlerSet->xmlDeclCommand = NULL; handlerSet->entityDeclCommand = NULL; return handlerSet; } /* *---------------------------------------------------------------------------- * * TclExpatObjCmd -- * * Creation command for expat class. * * Results: * The name of the newly created parser instance. * * Side effects: * This creates an expat parser. * *---------------------------------------------------------------------------- */ int TclExpatObjCmd( ClientData UNUSED(dummy), Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] ) { TclGenExpatInfo *genexpat; /* * Create the data structures for this parser. */ if (!(genexpat = (TclGenExpatInfo *) MALLOC(sizeof(TclGenExpatInfo)))) { FREE( (char*) genexpat); Tcl_SetResult(interp, "unable to create parser", NULL); return TCL_ERROR; } memset (genexpat, 0, sizeof (TclGenExpatInfo)); genexpat->interp = interp; genexpat->final = 1; /* * Find unique command name */ if (objc < 2) { genexpat->name = FindUniqueCmdName(interp); } else { genexpat->name = objv[1]; if (*(Tcl_GetString(genexpat->name)) != '-') { Tcl_IncrRefCount(genexpat->name); objv++; objc--; } else { genexpat->name = FindUniqueCmdName(interp); } } genexpat->paramentityparsing = XML_PARAM_ENTITY_PARSING_NEVER; genexpat->nsSeparator = ':'; genexpat->maximumAmplification = 0.0; genexpat->activationThreshold = 0; if (objc > 0) { /* * Handle configuration options */ if (TclExpatConfigure(interp, genexpat, objc - 1, objv + 1) != TCL_OK) { TclExpatDeleteCmd (genexpat); return TCL_ERROR; } } if (TclExpatInitializeParser(interp, genexpat, 0) != TCL_OK) { TclExpatDeleteCmd (genexpat); return TCL_ERROR; } /* * Register a Tcl command for this parser instance. */ Tcl_CreateObjCommand(interp, Tcl_GetString(genexpat->name), TclExpatInstanceCmd, (ClientData) genexpat, TclExpatDeleteCmd); Tcl_SetObjResult(interp, genexpat->name); return TCL_OK; } /* *---------------------------------------------------------------------------- * * FindUniqueCmdName -- * * Generate new command name in caller's namespace. * * Results: * Returns newly allocated Tcl object containing name. * * Side effects: * Allocates Tcl object. * *---------------------------------------------------------------------------- */ static Tcl_Obj * FindUniqueCmdName( Tcl_Interp *interp ) { Tcl_Obj *name; Tcl_CmdInfo info; char s[20]; name = Tcl_NewStringObj("", 0); Tcl_IncrRefCount(name); do { TDomThreaded(Tcl_MutexLock(&counterMutex);) sprintf(s, "xmlparser%d", uniqueCounter++); TDomThreaded(Tcl_MutexUnlock(&counterMutex);) Tcl_SetStringObj(name, s, -1); } while (Tcl_GetCommandInfo(interp, Tcl_GetString(name), &info)); return name; } /* *---------------------------------------------------------------------------- * * TclExpatInitializeParser -- * * Create or re-initializes (if it already exists) the expat * parser and initialize (some of) the TclExpatInfo structure. * * Note that callback commands are not affected by this routine, * to allow a reset to leave these intact. * * Results: * A flag, signaling success or error. * * Side effects: * Creates or reset an expat parser. * Modifies TclExpatInfo fields. * *---------------------------------------------------------------------------- */ static int TclExpatInitializeParser( Tcl_Interp *interp, TclGenExpatInfo *expat, int resetOptions ) { CHandlerSet *activeCHandlerSet; ExpatElemContent *eContent, *eContentSave; if (expat->parser) { XML_ParserReset (expat->parser, NULL); activeCHandlerSet = expat->firstCHandlerSet; while (activeCHandlerSet) { if (activeCHandlerSet->resetProc) { activeCHandlerSet->resetProc (expat->interp, activeCHandlerSet->userData); } activeCHandlerSet = activeCHandlerSet->nextHandlerSet; } } else { if (expat->ns_mode) { if (!(expat->parser = XML_ParserCreate_MM(NULL, MEM_SUITE, &expat->nsSeparator))) { Tcl_SetResult(interp, "unable to create expat parserNs", NULL); return TCL_ERROR; } } else { if (!(expat->parser = XML_ParserCreate_MM(NULL, MEM_SUITE, NULL))) { Tcl_SetResult(interp, "unable to create expat parser", NULL); return TCL_ERROR; } } #if defined(XML_DTD) && (XML_MAJOR_VERSION == 2) && (XML_MINOR_VERSION >= 4) if (expat->maximumAmplification >= 1.0f) { if (XML_SetBillionLaughsAttackProtectionMaximumAmplification ( expat->parser, expat->maximumAmplification) == XML_FALSE) { XML_ParserFree(expat->parser); Tcl_SetResult(interp, "The option \"" "-billionLaughsAttackProtectionMaximumAmplification" "\" requires a float >= 1.0 as argument.", NULL); return TCL_ERROR; } } if (expat->activationThreshold > 0) { if (XML_SetBillionLaughsAttackProtectionActivationThreshold ( expat->parser, expat->activationThreshold) == XML_FALSE) { XML_ParserFree(expat->parser); Tcl_SetResult(interp, "The \"" "-billionLaughsAttackProtectionActivationThreshold" "\" requires a long > 0 as argument.", NULL); return TCL_ERROR; } } #endif } expat->status = TCL_OK; if (expat->result) { Tcl_DecrRefCount (expat->result); expat->result = NULL; } if (expat->cdata) { Tcl_DecrRefCount (expat->cdata); } expat->cdata = NULL; eContent = expat->eContents; while (eContent) { XML_FreeContentModel (expat->parser, eContent->content); eContentSave = eContent; eContent = eContent->next; FREE((char *) eContentSave); } expat->eContents = NULL; expat->finished = 0; expat->parsingState = 0; #ifndef TDOM_NO_SCHEMA if (expat->sdata) { tDOM_schemaReset (expat->sdata); } #endif if (resetOptions) { expat->final = 1; expat->needWSCheck = 0; expat->noexpand = 0; expat->useForeignDTD = 0; expat->paramentityparsing = XML_PARAM_ENTITY_PARSING_NEVER; if (expat->baseURI) { Tcl_DecrRefCount (expat->baseURI); expat->baseURI = NULL; } } if (expat->baseURI) { XML_SetBase (expat->parser, Tcl_GetString (expat->baseURI)); Tcl_DecrRefCount (expat->baseURI); expat->baseURI = NULL; } XML_SetParamEntityParsing(expat->parser, expat->paramentityparsing); XML_UseForeignDTD (expat->parser, (unsigned char)expat->useForeignDTD); /* * Set handlers for the parser to routines in this module. */ XML_SetElementHandler(expat->parser, TclGenExpatElementStartHandler, TclGenExpatElementEndHandler); XML_SetNamespaceDeclHandler(expat->parser, TclGenExpatStartNamespaceDeclHandler, TclGenExpatEndNamespaceDeclHandler); XML_SetCharacterDataHandler(expat->parser, TclGenExpatCharacterDataHandler); XML_SetProcessingInstructionHandler(expat->parser, TclGenExpatProcessingInstructionHandler); XML_SetDefaultHandlerExpand(expat->parser, TclGenExpatDefaultHandler); XML_SetNotationDeclHandler(expat->parser, TclGenExpatNotationDeclHandler); XML_SetExternalEntityRefHandler(expat->parser, TclGenExpatExternalEntityRefHandler); XML_SetUnknownEncodingHandler(expat->parser, TclGenExpatUnknownEncodingHandler, (void *) expat); XML_SetCommentHandler(expat->parser, TclGenExpatCommentHandler); XML_SetNotStandaloneHandler(expat->parser, TclGenExpatNotStandaloneHandler); XML_SetCdataSectionHandler(expat->parser, TclGenExpatStartCdataSectionHandler, TclGenExpatEndCdataSectionHandler); XML_SetElementDeclHandler(expat->parser, TclGenExpatElementDeclHandler); XML_SetAttlistDeclHandler(expat->parser, TclGenExpatAttlistDeclHandler); XML_SetDoctypeDeclHandler(expat->parser, TclGenExpatStartDoctypeDeclHandler, TclGenExpatEndDoctypeDeclHandler); XML_SetXmlDeclHandler (expat->parser, TclGenExpatXmlDeclHandler); XML_SetEntityDeclHandler (expat->parser, TclGenExpatEntityDeclHandler); if (expat->noexpand) { XML_SetDefaultHandler(expat->parser, TclGenExpatDefaultHandler); } else { XML_SetDefaultHandlerExpand(expat->parser, TclGenExpatDefaultHandler); } XML_SetUserData(expat->parser, (void *) expat); return TCL_OK; } /* *---------------------------------------------------------------------------- * * TclExpatFreeParser -- * * Destroy the expat parser structure and frees the stored content models, * if there one. * * Results: * None. * * Side effects: * Frees any memory allocated for the XML parser and (if still present) * the stored content models. * *---------------------------------------------------------------------------- */ static void TclExpatFreeParser( TclGenExpatInfo *expat ) { ExpatElemContent *eContent, *eContentSave; eContent = expat->eContents; while (eContent) { XML_FreeContentModel (expat->parser, eContent->content); eContentSave = eContent; eContent = eContent->next; FREE((char *) eContentSave); } expat->eContents = NULL; XML_ParserFree(expat->parser); expat->parser = NULL; } /* *---------------------------------------------------------------------------- * * CurrentmarkupCommand -- * * Set as defaultHandler prior to XML_Currentmarkup() call. * * Results: * None. * * Side effects: * Stores the markup context in expat->currentmarkup. * *---------------------------------------------------------------------------- */ static void CurrentmarkupCommand ( void *userData, const char *s, int len ) { TclGenExpatInfo *expat = (TclGenExpatInfo *) userData; if (expat->status != TCL_OK) { return; } if (expat->cdata) { /* TclGenExpatCharacterDataHandler() was called and * initialized expat->cdata, but expat->cdata isn't reset by * TclExpatDispatchPCDATA(), so we're called from * -characterdatacommand and return the empty string by * definition. */ expat->currentmarkup = NULL; expat->currentmarkuplen = 0; return; } expat->currentmarkup = s; expat->currentmarkuplen = len; return; } /* *---------------------------------------------------------------------------- * * TclExpatInstanceCmd -- * * Implements instance command for expat class objects. * * Results: * Depends on the method. * * Side effects: * Depends on the method. * *---------------------------------------------------------------------------- */ static int TclExpatInstanceCmd ( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] ) { TclGenExpatInfo *expat = (TclGenExpatInfo *) clientData; char *data; int optionIndex, result = TCL_OK; domLength len = 0; #ifndef TDOM_NO_SCHEMA int resetsdata = 0; #endif static const char *options[] = { "configure", "cget", "currentmarkup", "free", "get", "parse", "parsechannel", "parsefile", "reset", "delete", NULL }; enum options { EXPAT_CONFIGURE, EXPAT_CGET, EXPAT_CURRENTMARKUP, EXPAT_FREE, EXPAT_GET, EXPAT_PARSE, EXPAT_PARSECHANNEL, EXPAT_PARSEFILE, EXPAT_RESET, EXPAT_DELETE }; if (objc < 2) { Tcl_SetResult (interp, "wrong # args: should be \"parserCmd method ?arg ...?\"", TCL_STATIC); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[1], options, "option", 0, &optionIndex) != TCL_OK) { return TCL_ERROR; } switch ((enum options) optionIndex) { case EXPAT_CONFIGURE: if (objc < 3) { Tcl_SetResult (interp, "wrong # args: should be " "\"parserCmd configure