tDOM

Check-in [508a776b44]
Login
Bounty program for improvements to Tcl and certain Tcl packages.
Tcl 2019 Conference, Houston/TX, US, Nov 4-8
Send your abstracts to [email protected]
or submit via the online form by Sep 9.

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Merge from schema.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | localkey
Files: files | file ages | folders
SHA3-256: 508a776b444fb4fbea66e688ae8ea16f2480a0b42602d2547976fa816548a0dc
User & Date: rolf 2019-05-10 00:40:52
Context
2019-05-10
00:49
Use the new schema feature prefixns for namespace prefix resolution in local key constraint XPath expressions. check-in: e407c9fd00 user: rolf tags: localkey
00:40
Merge from schema. check-in: 508a776b44 user: rolf tags: localkey
00:36
Added method prefixns to schema cmds. This allows to point to namespace URIs by shortcuts or prefixes. check-in: 74a399d84f user: rolf tags: schema
2019-05-09
19:16
Merged from schema. check-in: 4879bb492b user: rolf tags: localkey
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to doc/domDoc.xml.

   318    318   asterisk ('*'), then the method returns an unordered list of all
   319    319   element names of the document, for which the text node children will be
   320    320   serialized as CDATA section nodes.</desc>
   321    321         </commanddef>
   322    322   
   323    323         <commanddef>
   324    324           <command><method>selectNodesNamespaces</method> <option>?prefixUriList?</option></command>
   325         -        <desc>This method allows one to control a document global prefix
   326         -        to namespace URI mapping, which will be used for selectNodes
          325  +        <desc>This method gives control to a document global prefix to
          326  +        namespace URI mapping, which will be used for selectNodes
   327    327           method calls (on document as well as on all nodes, which
   328         -        belongs to the document) if it is not overwritten by using
   329         -        the -namespaces option of the selectNodes method. Any
   330         -        namespace prefix within an xpath expression will be first
   331         -        resolved against this list. If the list binds the same prefix
   332         -        to different namespaces, then the first binding will win. If a
          328  +        belongs to the document) if it is not overwritten by using the
          329  +        -namespaces option of the selectNodes method. Any namespace
          330  +        prefix within an xpath expression will be first resolved
          331  +        against this list. If the list binds the same prefix to
          332  +        different namespaces, then the first binding will win. If a
   333    333           prefix could not resolved against the document global prefix /
   334    334           namespaces list, then the namespace definitions in scope of
   335    335           the context node will be used to resolve the prefix, as usual.
   336    336           If the optional argument <m>prefixUriList</m> is given, then
   337    337           the global prefix / namespace list is set to this list and
   338    338           returns it. Without the optional argument the method returns
   339    339           the current list. The default is the empty list.</desc>

Changes to doc/schema.html.

     1      1   <html>
     2      2   <head>
     3      3   <link rel="stylesheet" href="manpage.css"><title>tDOM manual: schema</title><meta name="xsl-processor" content="Jochen Loewer ([email protected]), Rolf Ade ([email protected]) et. al."><meta name="generator" content="$RCSfile: tmml-html.xsl,v $ $Revision: 1.11 $"><meta charset="utf-8">
     4      4   </head><body>
     5      5   <div class="header">
     6      6   <div class="navbar" align="center">
     7         -<a href="#SECTid0x5563b3e4fb10">NAME</a> · <a href="#SECTid0x5563b3e50170">SYNOPSIS</a> · <a href="#SECTid0x5563b3e4a5f0">DESCRIPTION </a> · <a href="#SECTid0x5563b3ea8fc0">Schema definition scripts</a> · <a href="#SECTid0x5563b3eb12f0">Quantity specifier</a> · <a href="#SECTid0x5563b3eb3180">Text constraint scripts</a> · <a href="#SECTid0x5563b3ebb590">Exampels</a>
            7  +<a href="#SECTid0x55dce5c8db10">NAME</a> · <a href="#SECTid0x55dce5c8e170">SYNOPSIS</a> · <a href="#SECTid0x55dce5c885f0">DESCRIPTION </a> · <a href="#SECTid0x55dce5ce7e60">Schema definition scripts</a> · <a href="#SECTid0x55dce5cf0190">Quantity specifier</a> · <a href="#SECTid0x55dce5cf2020">Text constraint scripts</a> · <a href="#SECTid0x55dce5cfa430">Exampels</a>
     8      8   </div><hr class="navsep">
     9      9   </div><div class="body">
    10         -  <h2><a name="SECTid0x5563b3e4fb10">NAME</a></h2><p class="namesection">
           10  +  <h2><a name="SECTid0x55dce5c8db10">NAME</a></h2><p class="namesection">
    11     11   <b class="names">tdom::schema - </b><br>Create a schema validation command</p>
    12     12   
    13         -  <h2><a name="SECTid0x5563b3e50170">SYNOPSIS</a></h2><pre class="syntax">package require tdom
           13  +  <h2><a name="SECTid0x55dce5c8e170">SYNOPSIS</a></h2><pre class="syntax">package require tdom
    14     14   
    15     15   <b class="cmd">tdom::schema</b> <i class="m">?create?</i> <i class="m">cmdName</i>
    16     16       </pre>
    17     17   
    18         -  <h2><a name="SECTid0x5563b3e4a5f0">DESCRIPTION </a></h2><p>This command creates validation commands with a simple API. The
           18  +  <h2><a name="SECTid0x55dce5c885f0">DESCRIPTION </a></h2><p>This command creates validation commands with a simple API. The
    19     19       validation commands have methods to define a schema and are able
    20     20       to validate XML or DOM trees (and to some degree other kind of
    21     21       hierarchical data) against this schema.</p><p>Additionally, a validation command may be used as argument to
    22     22       the <i class="m">-validateCmd</i> option of the <i class="m">dom parse</i> and the
    23     23       <i class="m">expat</i> commands to enable validation additional to what they
    24     24       otherwise do.</p><p>The valid methods of the created commands are:</p><dl class="commandlist">
           25  +      
           26  +          <dt>
           27  +<b class="method">prefixns</b> <i class="m">?prefixUriList?</i>
           28  +</dt>
           29  +
           30  +          <dd>This method gives control to a prefix (or
           31  +          abbreviation) to namespace URI mapping. Everywhere a
           32  +          namespace argument is expected in the schema command methods
           33  +          you may use the "prefix" pointing to the namespace
           34  +          URI in the current prefixUriList, set by this method. If the
           35  +          list map the same prefix to different namespace URIs the
           36  +          last won win. If there isn't such a prefix the namespace
           37  +          argument is used literally as namespace URI. If the method
           38  +          is called without argument it returns the current
           39  +          prefixUriList. If the method is called with the empty list
           40  +          any namespace URI arguments are used literally. This is the
           41  +          default.
           42  +          </dd>
           43  +      
           44  +
    25     45         
    26     46           <dt>
    27     47   <b class="method">defelement</b> <i class="m">name</i> <i class="m">?namespace?</i> <i class="m">&lt;definition script&gt;</i>
    28     48   </dt>
    29     49           <dd>This method defines the element <i class="m">name</i> (optional in
    30     50           the namespace <i class="m">namespace</i>) in the schema. The
    31     51           <i class="m">definition script</i> is evaluated and defines the content
................................................................................
   165    185           <dt><b class="method">reset</b></dt>
   166    186           <dd>This method resets the validation command into state
   167    187           READY (while preserving the defined grammer).</dd>
   168    188         
   169    189   
   170    190       </dl>
   171    191   
   172         -  <h2><a name="SECTid0x5563b3ea8fc0">Schema definition scripts</a></h2><p>Schema definition scripts are ordinary Tcl scripts that are
          192  +  <h2><a name="SECTid0x55dce5ce7e60">Schema definition scripts</a></h2><p>Schema definition scripts are ordinary Tcl scripts that are
   173    193       evaluatend in the namespace tdom::schema. The below listed schema
   174    194       definition commands in this tcl namespace allow to define a wide
   175    195       variety of document structures. Every schema definition command
   176    196       establish a validation constraint on the content which has to
   177    197       match or must be optional to render the content as valid. It is a
   178    198       validation error if the element in the XML source has additional
   179    199       (not matched) content.</p><p>The schema definition commands are:</p><dl class="commandlist">
................................................................................
   315    335           call. This is meant as toplevel command of a <i>schemacmd
   316    336           define</i> script. This command is not allowed nested in an
   317    337           other definition script command and will raise error, if you
   318    338           call it there.</dd>
   319    339         
   320    340       </dl>
   321    341   
   322         -  <h2><a name="SECTid0x5563b3eb12f0">Quantity specifier</a></h2><p>Serveral schema definition commands expects a quantifier as
          342  +  <h2><a name="SECTid0x55dce5cf0190">Quantity specifier</a></h2><p>Serveral schema definition commands expects a quantifier as
   323    343       one of their arguments, which specifies how often the content
   324    344       particle specified by the command is expected. The valid values
   325    345       for a <i class="m">quant</i> argument are:</p><dl class="optlist">
   326    346         
   327    347           <dt><b>!</b></dt>
   328    348           <dd>The content particle must occur exactly once in valid
   329    349           documents. This is the default, if a quantifier is
................................................................................
   360    380           n to m times (both inclusive) in a row in valid documents. The
   361    381           quantifier must be a tcl list with two elements. Both elements
   362    382           must be integers, with n &gt;= 0 and n &lt; m.</dd>
   363    383         
   364    384       </dl><p>If an optional quantifier is not given then it defaults to * in
   365    385       case of the mixed command and to ! for all other commands.</p>
   366    386   
   367         -  <h2><a name="SECTid0x5563b3eb3180">Text constraint scripts</a></h2><p></p><p>The text constraint commands are:</p><dl class="commandlist">
          387  +  <h2><a name="SECTid0x55dce5cf2020">Text constraint scripts</a></h2><p></p><p>The text constraint commands are:</p><dl class="commandlist">
   368    388         
   369    389           <dt><b class="cmd">isint</b></dt>
   370    390           <dd></dd>
   371    391         
   372    392   
   373    393         
   374    394           <dt>
................................................................................
   520    540           reference to an ID within the document. The referenced ID may
   521    541           be later in the document, that the reference. Several
   522    542           references within the document to one ID are possible.</dd>
   523    543         
   524    544         
   525    545           <dt><b class="cmd">base64</b></dt>
   526    546           <dd>This text constraint match if text is valid according to
   527         -        RFC 4648RFC 4648.</dd>
          547  +        RFC 4648.</dd>
   528    548         
   529    549       </dl>
   530    550     
   531         -  <h2><a name="SECTid0x5563b3ebb590">Exampels</a></h2><p>The XML Schema Part 0: Primer Second Edition
          551  +  <h2><a name="SECTid0x55dce5cfa430">Exampels</a></h2><p>The XML Schema Part 0: Primer Second Edition
   532    552       (<a href="https://www.w3.org/TR/xmlschema-0/">https://www.w3.org/TR/xmlschema-0/</a>) starts with this
   533    553       example schema:</p><pre class="example">
   534    554   &lt;xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"&gt;
   535    555   
   536    556     &lt;xsd:annotation&gt;
   537    557       &lt;xsd:documentation xml:lang="en"&gt;
   538    558        Purchase order schema for Example.com.

Changes to doc/schema.n.

   178    178   .PP
   179    179   Additionally, a validation command may be used as argument to
   180    180   the \fI-validateCmd\fR option of the \fIdom parse\fR and the
   181    181   \&\fIexpat\fR commands to enable validation additional to what they
   182    182   otherwise do.
   183    183   .PP
   184    184   The valid methods of the created commands are:
          185  +.TP
          186  +\&\fB\fBprefixns\fP \fI?prefixUriList?\fB
          187  +\&\fRThis method gives control to a prefix (or
          188  +abbreviation) to namespace URI mapping. Everywhere a
          189  +namespace argument is expected in the schema command methods
          190  +you may use the "prefix" pointing to the namespace
          191  +URI in the current prefixUriList, set by this method. If the
          192  +list map the same prefix to different namespace URIs the
          193  +last won win. If there isn't such a prefix the namespace
          194  +argument is used literally as namespace URI. If the method
          195  +is called without argument it returns the current
          196  +prefixUriList. If the method is called with the empty list
          197  +any namespace URI arguments are used literally. This is the
          198  +default.
   185    199   .TP
   186    200   \&\fB\fBdefelement\fP \fIname\fB \fI?namespace?\fB \fI<definition script>\fB
   187    201   \&\fRThis method defines the element \fIname\fR (optional in
   188    202   the namespace \fInamespace\fR) in the schema. The
   189    203   \&\fIdefinition script\fR is evaluated and defines the content
   190    204   model of the element. If the \fInamespace\fR argument is
   191    205   given, any \fIelement\fR or \fIref\fR references in the
................................................................................
   538    552   \&\fRThis text constraint command expects the text to be a
   539    553   reference to an ID within the document. The referenced ID may
   540    554   be later in the document, that the reference. Several
   541    555   references within the document to one ID are possible.
   542    556   .TP
   543    557   \&\fB\fBbase64\fP
   544    558   \&\fRThis text constraint match if text is valid according to
   545         -RFC 4648RFC 4648.
          559  +RFC 4648.
   546    560   .SH Exampels
   547    561   .PP
   548    562   .UR "https://www.w3.org/TR/xmlschema-0/"
   549    563   <URL: https://www.w3.org/TR/xmlschema-0/>
   550    564   .UE
   551    565   The XML Schema Part 0: Primer Second Edition
   552    566   () starts with this

Changes to doc/schema.xml.

    24     24       the <m>-validateCmd</m> option of the <m>dom parse</m> and the
    25     25       <m>expat</m> commands to enable validation additional to what they
    26     26       otherwise do.</p>
    27     27   
    28     28       <p>The valid methods of the created commands are:</p>
    29     29   
    30     30       <commandlist>
           31  +      <commanddef>
           32  +          <command><method>prefixns</method> <m>?prefixUriList?</m></command>
           33  +
           34  +          <desc>This method gives control to a prefix (or
           35  +          abbreviation) to namespace URI mapping. Everywhere a
           36  +          namespace argument is expected in the schema command methods
           37  +          you may use the &quot;prefix&quot; pointing to the namespace
           38  +          URI in the current prefixUriList, set by this method. If the
           39  +          list map the same prefix to different namespace URIs the
           40  +          last won win. If there isn't such a prefix the namespace
           41  +          argument is used literally as namespace URI. If the method
           42  +          is called without argument it returns the current
           43  +          prefixUriList. If the method is called with the empty list
           44  +          any namespace URI arguments are used literally. This is the
           45  +          default.
           46  +          </desc>
           47  +      </commanddef>
           48  +
    31     49         <commanddef>
    32     50           <command><method>defelement</method> <m>name</m> <m>?namespace?</m> <m>&lt;definition script></m></command>
    33     51           <desc>This method defines the element <m>name</m> (optional in
    34     52           the namespace <m>namespace</m>) in the schema. The
    35     53           <m>definition script</m> is evaluated and defines the content
    36     54           model of the element. If the <m>namespace</m> argument is
    37     55           given, any <m>element</m> or <m>ref</m> references in the
................................................................................
   479    497           reference to an ID within the document. The referenced ID may
   480    498           be later in the document, that the reference. Several
   481    499           references within the document to one ID are possible.</desc>
   482    500         </commanddef>
   483    501         <commanddef>
   484    502           <command><cmd>base64</cmd></command>
   485    503           <desc>This text constraint match if text is valid according to
   486         -        RFC 4648RFC 4648.</desc>
          504  +        RFC 4648.</desc>
   487    505         </commanddef>
   488    506       </commandlist>
   489    507     </section>
   490    508     
   491    509     <section>
   492    510       <title>Exampels</title>
   493    511   

Changes to generic/schema.c.

   423    423   
   424    424       sdata = TMALLOC (SchemaData);
   425    425       memset (sdata, 0, sizeof(SchemaData));
   426    426       name = Tcl_GetStringFromObj (cmdNameObj, &len);
   427    427       sdata->self = Tcl_NewStringObj (name, len);
   428    428       Tcl_IncrRefCount (sdata->self);
   429    429       Tcl_InitHashTable (&sdata->element, TCL_STRING_KEYS);
          430  +    Tcl_InitHashTable (&sdata->prefix, TCL_STRING_KEYS);
   430    431       Tcl_InitHashTable (&sdata->pattern, TCL_STRING_KEYS);
   431    432       Tcl_InitHashTable (&sdata->attrNames, TCL_STRING_KEYS);
   432    433       Tcl_InitHashTable (&sdata->namespace, TCL_STRING_KEYS);
   433    434       Tcl_InitHashTable (&sdata->textDef, TCL_STRING_KEYS);
   434    435       sdata->emptyNamespace = Tcl_CreateHashEntry (
   435    436           &sdata->namespace, "", &hnew);
   436    437       sdata->patternList = (SchemaCP **) MALLOC (
................................................................................
   477    478        * schemaInstanceCmd(). */
   478    479       if (sdata->currentEvals) {
   479    480           sdata->cleanupAfterEval = 1;
   480    481           return;
   481    482       }
   482    483       Tcl_DecrRefCount (sdata->self);
   483    484       if (sdata->start) FREE (sdata->start);
   484         -    if (sdata->startNamespace) FREE (sdata->startNamespace);
          485  +    if (sdata->prefixns) {
          486  +        i = 0;
          487  +        while (sdata->prefixns[i]) {
          488  +            FREE (sdata->prefixns[i]);
          489  +            i++;
          490  +        }
          491  +        FREE (sdata->prefixns);
          492  +    }
   485    493       Tcl_DeleteHashTable (&sdata->namespace);
   486    494       Tcl_DeleteHashTable (&sdata->element);
          495  +    Tcl_DeleteHashTable (&sdata->prefix);
   487    496       Tcl_DeleteHashTable (&sdata->pattern);
   488    497       Tcl_DeleteHashTable (&sdata->attrNames);
   489    498       Tcl_DeleteHashTable (&sdata->textDef);
   490    499       for (i = 0; i < sdata->numPatternList; i++) {
   491    500           freeSchemaCP (sdata->patternList[i]);
   492    501       }
   493    502       FREE (sdata->patternList);
................................................................................
   998   1007               sdata->skipDeep = 2;
   999   1008               return 1;
  1000   1009           }
  1001   1010       }
  1002   1011       
  1003   1012       return -1;
  1004   1013   }
         1014  +
         1015  +static void *
         1016  +getNamespacePtr (
         1017  +    SchemaData *sdata,
         1018  +    char *ns
         1019  +    )
         1020  +{
         1021  +    Tcl_HashEntry *h;
         1022  +    int hnew;
         1023  +
         1024  +    if (!ns) return NULL;
         1025  +    h = Tcl_FindHashEntry (&sdata->prefix, ns);
         1026  +    if (h) {
         1027  +        return Tcl_GetHashValue (h);
         1028  +    }
         1029  +    h = Tcl_CreateHashEntry (&sdata->namespace, ns, &hnew);
         1030  +    if (h != sdata->emptyNamespace) {
         1031  +        return Tcl_GetHashKey (&sdata->namespace, h);
         1032  +    }
         1033  +    return NULL;
         1034  +}
  1005   1035   
  1006   1036   int
  1007   1037   probeElement (
  1008   1038       Tcl_Interp *interp,
  1009   1039       SchemaData *sdata,
  1010   1040       const char *name,
  1011   1041       void *namespace
................................................................................
  1026   1056       }
  1027   1057   
  1028   1058       DBG(
  1029   1059           fprintf (stderr, "probeElement: look if '%s' in ns '%s' match\n",
  1030   1060                    name, (char *)namespace);
  1031   1061           );
  1032   1062   
  1033         -    if (namespace) {
  1034         -        entryPtr = Tcl_FindHashEntry (&sdata->namespace, (char *)namespace);
  1035         -        if (!entryPtr) {
  1036         -            SetResult ("No elements defined in this namespace");
  1037         -            return TCL_ERROR;
  1038         -        }
  1039         -        if (entryPtr == sdata->emptyNamespace) {
  1040         -            namespacePtr = NULL;
  1041         -        } else {
  1042         -            namespacePtr = Tcl_GetHashKey (&sdata->namespace, entryPtr);
  1043         -        }
  1044         -    } else {
  1045         -        namespacePtr = NULL;
  1046         -    }
         1063  +    namespacePtr = getNamespacePtr (sdata, namespace);
  1047   1064       entryPtr = Tcl_FindHashEntry (&sdata->element, name);
  1048   1065       if (entryPtr) {
  1049   1066           namePtr = Tcl_GetHashKey (&sdata->element, entryPtr);
  1050   1067       } else {
  1051   1068           namePtr = NULL;
  1052   1069       }
  1053   1070   
................................................................................
  1055   1072           /* The root of the tree to check. */
  1056   1073           if (sdata->start) {
  1057   1074               if (strcmp (name, sdata->start) != 0) {
  1058   1075                   SetResult ("Root element doesn't match");
  1059   1076                   return TCL_ERROR;
  1060   1077               }
  1061   1078               if (namespace) {
  1062         -                if (!sdata->startNamespace ||
         1079  +                if (!sdata->startNamespace||
  1063   1080                       strcmp (namespace, sdata->startNamespace) != 0) {
  1064   1081                       SetResult ("Root element namespace doesn't match");
  1065   1082                       return TCL_ERROR;
  1066   1083                   }
  1067   1084               } else {
  1068   1085                   if (sdata->startNamespace) {
  1069   1086                       SetResult ("Root element namespace doesn't match");
................................................................................
  2240   2257   {
  2241   2258       int            methodIndex, keywordIndex, hnew, patternIndex;
  2242   2259       int            result = TCL_OK, forwardDef = 0, i = 0;
  2243   2260       int            savedDefineToplevel, type, len;
  2244   2261       unsigned int   savedNumPatternList;
  2245   2262       SchemaData    *savedsdata = NULL, *sdata = (SchemaData *) clientData;
  2246   2263       Tcl_HashTable *hashTable;
  2247         -    Tcl_HashEntry *h;
         2264  +    Tcl_HashEntry *h, *h1;
  2248   2265       SchemaCP      *pattern, *current = NULL;
  2249   2266       void          *namespacePtr, *savedNamespacePtr;
  2250   2267       char          *xmlstr, *errMsg;
  2251   2268       domDocument   *doc;
  2252   2269       domNode       *node;
  2253   2270   
  2254   2271       static const char *schemaInstanceMethods[] = {
  2255   2272           "defelement", "defpattern",  "start",   "event", "delete",
  2256   2273           "nrForwardDefinitions",      "state",   "reset", "define",
  2257   2274           "validate",   "domvalidate", "deftext", "info",  "reportcmd",
  2258         -        NULL
         2275  +        "prefixns",   NULL
  2259   2276       };
  2260   2277       enum schemaInstanceMethod {
  2261   2278           m_defelement,  m_defpattern,  m_start,   m_event, m_delete,
  2262   2279           m_nrForwardDefinitions,       m_state,   m_reset, m_define,
  2263         -        m_validate,    m_domvalidate, m_deftext, m_info,  m_reportcmd
         2280  +        m_validate,    m_domvalidate, m_deftext, m_info,  m_reportcmd,
         2281  +        m_prefixns
  2264   2282       };
  2265   2283   
  2266   2284       static const char *eventKeywords[] = {
  2267   2285           "start", "end", "text", NULL
  2268   2286       };
  2269   2287   
  2270   2288       enum eventKeyword
................................................................................
  2312   2330               type = SCHEMA_CTYPE_PATTERN;
  2313   2331           }
  2314   2332           savedNumPatternList = sdata->numPatternList;
  2315   2333           namespacePtr = NULL;
  2316   2334           patternIndex = 3-i;
  2317   2335           if (objc == 5-i) {
  2318   2336               patternIndex = 4-i;
  2319         -            h = Tcl_CreateHashEntry (&sdata->namespace,
  2320         -                                            Tcl_GetString (objv[3-i]), &hnew);
  2321         -            if (h != sdata->emptyNamespace) {
  2322         -                namespacePtr = Tcl_GetHashKey (&sdata->namespace, h);
  2323         -            }
         2337  +            namespacePtr = getNamespacePtr (sdata, Tcl_GetString (objv[3-i]));
  2324   2338           }
  2325   2339           h = Tcl_CreateHashEntry (hashTable, Tcl_GetString (objv[2-i]), &hnew);
  2326   2340           pattern = NULL;
  2327   2341           if (!hnew) {
  2328   2342               pattern = (SchemaCP *) Tcl_GetHashValue (h);
  2329   2343               while (pattern) {
  2330   2344                   if (pattern->namespace == namespacePtr) {
................................................................................
  2462   2476                                 " ?<namespace>?");
  2463   2477               return TCL_ERROR;
  2464   2478           }
  2465   2479           if (sdata->start) {
  2466   2480               FREE (sdata->start);
  2467   2481           }
  2468   2482           if (objc == 3-i && strcmp (Tcl_GetString (objv[2-i]), "") == 0) {
  2469         -            if (sdata->startNamespace) {
  2470         -                FREE (sdata->startNamespace);
  2471         -            }
         2483  +            sdata->startNamespace = NULL;
  2472   2484               sdata->start = NULL;
  2473   2485               break;
  2474   2486           }
  2475   2487           sdata->start = tdomstrdup (Tcl_GetString (objv[2-i]));
  2476   2488           if (objc == 4-i) {
  2477         -            if (sdata->startNamespace) {
  2478         -                FREE (sdata->startNamespace);
  2479         -            }
  2480   2489               sdata->startNamespace =
  2481         -                tdomstrdup (Tcl_GetString (objv[3-i]));
         2490  +                getNamespacePtr (sdata, Tcl_GetString (objv[3-i]));
  2482   2491           }
  2483   2492           break;
  2484   2493   
  2485   2494       case m_event:
  2486   2495           CHECK_EVAL
  2487   2496           if (objc < 3) {
  2488   2497               Tcl_WrongNumArgs (interp, 2, objv, "<eventType>"
................................................................................
  2497   2506           switch ((enum eventKeyword) keywordIndex) {
  2498   2507           case k_elementstart:
  2499   2508               if (objc < 4 && objc > 6) {
  2500   2509                   Tcl_WrongNumArgs (interp, 3, objv, "<elementname>"
  2501   2510                       "?<attInfo>? ?<namespace>?");
  2502   2511                   return TCL_ERROR;
  2503   2512               }
         2513  +            namespacePtr = NULL;
  2504   2514               if (objc == 6) {
  2505         -                h = Tcl_FindHashEntry (&sdata->namespace,
  2506         -                                              Tcl_GetString (objv[5]));
  2507         -                if (h && h != sdata->emptyNamespace) {
  2508         -                     namespacePtr = Tcl_GetHashKey (&sdata->namespace, h);
  2509         -                } else {
  2510         -                    namespacePtr = NULL;
  2511         -                }
  2512         -            } else {
  2513         -                namespacePtr = NULL;
         2515  +                namespacePtr = getNamespacePtr (sdata,
         2516  +                                                Tcl_GetString (objv[5]));
  2514   2517               }
  2515   2518               result = probeElement (interp, sdata, Tcl_GetString (objv[3]),
  2516   2519                                      namespacePtr);
  2517   2520               break;
  2518   2521           case k_elementend:
  2519   2522               if (objc != 3) {
  2520   2523                   Tcl_WrongNumArgs (interp, 3, objv, "No arguments expected.");
................................................................................
  2643   2646           if (sdata->reportCmd) {
  2644   2647               Tcl_DecrRefCount (sdata->reportCmd);
  2645   2648           }
  2646   2649           sdata->reportCmd = objv[2];
  2647   2650           Tcl_IncrRefCount (sdata->reportCmd);
  2648   2651           break;
  2649   2652   
         2653  +    case m_prefixns:
         2654  +        result = tcldom_prefixNSlist (&sdata->prefixns, interp, objc, objv,
         2655  +                                      "prefixns");
         2656  +        if (sdata->prefix.numBuckets) {
         2657  +            Tcl_DeleteHashTable (&sdata->prefix);
         2658  +            Tcl_InitHashTable (&sdata->prefix, TCL_STRING_KEYS);
         2659  +        }
         2660  +        if (result == TCL_OK && sdata->prefixns) {
         2661  +            i = 0;
         2662  +            while (sdata->prefixns[i]) {
         2663  +                h = Tcl_CreateHashEntry (&sdata->namespace,
         2664  +                                         sdata->prefixns[i+1], &hnew);
         2665  +                h1 = Tcl_CreateHashEntry (&sdata->prefix,
         2666  +                                          sdata->prefixns[i], &hnew);
         2667  +                Tcl_SetHashValue (h1, Tcl_GetHashKey (&sdata->namespace, h));
         2668  +                i += 2;
         2669  +            }
         2670  +        }
         2671  +        break;
         2672  +        
  2650   2673       default:
  2651   2674           Tcl_SetResult (interp, "unknown method", NULL);
  2652   2675           result = TCL_ERROR;
  2653   2676           break;
  2654   2677   
  2655   2678       }
  2656   2679       if (sdata->cleanupAfterEval && sdata->currentEvals == 0) {
................................................................................
  3042   3065       Tcl_Obj *namespaceObj,
  3043   3066       Tcl_Obj *scriptObj,
  3044   3067       int required,
  3045   3068       SchemaCP *type
  3046   3069       )
  3047   3070   {
  3048   3071       Tcl_HashEntry *h;
  3049         -    int hnew, hnew1, i, result = TCL_OK;
         3072  +    int hnew, i, result = TCL_OK;
  3050   3073       char *name, *namespace = NULL;
  3051   3074       SchemaAttr *attr;
  3052   3075       SchemaCP *cp;
  3053   3076   
  3054   3077       if (namespaceObj) {
  3055         -        h = Tcl_CreateHashEntry (&sdata->namespace,
  3056         -                                 Tcl_GetString (namespaceObj), &hnew1);
  3057         -        if (h != sdata->emptyNamespace) {
  3058         -            namespace = Tcl_GetHashKey (&sdata->namespace, h);
  3059         -        }
         3078  +        namespace = getNamespacePtr (sdata,
         3079  +                                     Tcl_GetString (namespaceObj));
  3060   3080       }
  3061   3081       h = Tcl_CreateHashEntry (&sdata->attrNames,
  3062   3082                                Tcl_GetString (nameObj), &hnew);
  3063   3083       name = Tcl_GetHashKey (&sdata->attrNames, h);
  3064   3084       if (!hnew) {
  3065   3085           /* Check, if there is already an attribute with this name
  3066   3086            * / namespace */
................................................................................
  3202   3222       Tcl_Interp *interp,
  3203   3223       int objc,
  3204   3224       Tcl_Obj *const objv[]
  3205   3225       )
  3206   3226   {
  3207   3227       SchemaData *sdata = GETASI;
  3208   3228       char *currentNamespace;
  3209         -    Tcl_HashEntry *entryPtr;
  3210         -    int hnew, result;
         3229  +    int result;
  3211   3230   
  3212   3231       CHECK_SI
  3213   3232       CHECK_TOPLEVEL
  3214   3233       checkNrArgs (3,3,"Expected: namespace pattern");
  3215   3234   
  3216   3235       currentNamespace = sdata->currentNamespace;
  3217         -    entryPtr = Tcl_CreateHashEntry (&sdata->namespace,
  3218         -                                    Tcl_GetString(objv[1]), &hnew);
  3219         -    if (entryPtr == sdata->emptyNamespace) {
  3220         -        sdata->currentNamespace = NULL;
  3221         -    } else {
  3222         -        sdata->currentNamespace = (char *)
  3223         -            Tcl_GetHashKey (&sdata->namespace, entryPtr);
  3224         -    }
         3236  +    sdata->currentNamespace =
         3237  +        getNamespacePtr (sdata, Tcl_GetString(objv[1]));
  3225   3238       sdata->currentEvals++;
  3226   3239       result = Tcl_EvalObjEx (interp, objv[2], TCL_EVAL_DIRECT);
  3227   3240       sdata->currentEvals--;
  3228   3241       sdata->currentNamespace = currentNamespace;
  3229   3242       return result;
  3230   3243   }
  3231   3244   

Changes to generic/schema.h.

   116    116   {
   117    117       Tcl_Obj *self;
   118    118       char *start;
   119    119       char *startNamespace;
   120    120       Tcl_HashTable element;
   121    121       Tcl_HashTable namespace;
   122    122       Tcl_HashEntry *emptyNamespace;
          123  +    char **prefixns;
          124  +    Tcl_HashTable prefix;
   123    125       Tcl_HashTable pattern;
   124    126       Tcl_HashTable attrNames;
   125    127       Tcl_HashTable textDef;
   126    128       SchemaCP **patternList; 
   127    129       unsigned int numPatternList;
   128    130       unsigned int patternListSize;
   129    131       unsigned int forwardPatternDefs;

Changes to tests/schema.test.

   228    228           {<doc><a/><b/></doc>}
   229    229       } {
   230    230           lappend result [s validate $xml]
   231    231       }
   232    232       s delete
   233    233       set result
   234    234   } {1 1 1 0}
          235  +
          236  +test schema-1.14a {define start w/ namespace} {
          237  +    tdom::schema create s
          238  +    s prefixns {ns1 http://foo.bar}
          239  +    s start doc ns1
          240  +    s defelement doc ns1 {
          241  +        element a
          242  +        element b
          243  +    }
          244  +    foreach elm {a b} {
          245  +        s defelement $elm ns1 {}
          246  +    }
          247  +    set result [list]
          248  +    foreach xml {
          249  +        {<doc xmlns="http://foo.bar"><a/><b/></doc>}
          250  +        {<a:doc xmlns:a="http://foo.bar"><a:a/><a:b/></a:doc>}
          251  +        {<a:doc xmlns:a="http://foo.bar"><a xmlns="http://foo.bar"/><a:b/></a:doc>}
          252  +        {<doc><a/><b/></doc>}
          253  +    } {
          254  +        lappend result [s validate $xml]
          255  +    }
          256  +    s delete
          257  +    set result
          258  +} {1 1 1 0}
   235    259   
   236    260   test schema-1.15 {call structure constraint outside define/defelement} {
   237    261       set result [catch {tdom::schema::element foo} errMsg]
   238    262       lappend result $errMsg
   239    263       tdom::schema create grammar
   240    264       lappend result [catch {tdom::schema::element foo} errMsg]
   241    265       lappend result $errMsg
................................................................................
  2200   2224               }
  2201   2225           }
  2202   2226       }
  2203   2227       set result [s validate {<doc><e foo="bar"/></doc>} errMsg]
  2204   2228       s delete
  2205   2229       lappend result $errMsg
  2206   2230   } {1 {}}
         2231  +
         2232  +test schema-11.4_1 {attribute} {
         2233  +    tdom::schema create s
         2234  +    s prefixns {1 http://www.w3.org/XML/1998/namespace}
         2235  +    s define {
         2236  +        defelement doc {
         2237  +            element e 1 {
         2238  +                attribute foo
         2239  +                nsattribute lang 1 ?
         2240  +            }
         2241  +        }
         2242  +    }
         2243  +    set result [s validate {<doc><e foo="bar"/></doc>} errMsg]
         2244  +    s delete
         2245  +    lappend result $errMsg
         2246  +} {1 {}}
  2207   2247   
  2208   2248   test schema-11.4a {attribute} {
  2209   2249       tdom::schema create s
  2210   2250       s define {
  2211   2251           defelement doc {
  2212   2252               element e 1 {
  2213   2253                   attribute foo
................................................................................
  2247   2287           }
  2248   2288       }
  2249   2289       set result [catch {set doc [dom parse -validateCmd s {<doc><e xml:lang="en" foo="bar"/></doc>}]}]
  2250   2290       s delete
  2251   2291       $doc delete
  2252   2292       set result
  2253   2293   } 0
         2294  +
         2295  +test schema-11.5a {nsattribute} {
         2296  +    tdom::schema create s
         2297  +    s prefixns {ns1 http://www.w3.org/XML/1998/namespace}
         2298  +    s define {
         2299  +        defelement doc {
         2300  +            element e 1 {
         2301  +                attribute foo
         2302  +                nsattribute lang ns1 ?
         2303  +            }
         2304  +        }
         2305  +    }
         2306  +    set result [catch {set doc [dom parse -validateCmd s {<doc><e xml:lang="en" foo="bar"/></doc>}]}]
         2307  +    s delete
         2308  +    $doc delete
         2309  +    set result
         2310  +} 0
  2254   2311   
  2255   2312   test schema-11.6 {nsattribute} {
  2256   2313       tdom::schema create s
  2257   2314       s define {
  2258   2315           defelement doc {
  2259   2316               element e 1 {
  2260   2317                   attribute foo
  2261   2318                   nsattribute lang http://www.w3.org/XML/1998/namespace
  2262   2319               }
  2263   2320           }
         2321  +    }
         2322  +    set result [list]
         2323  +    foreach xml {
         2324  +        {<doc><e foo="bar"/></doc>}
         2325  +        {<doc><e xml:lang="en"/></doc>}
         2326  +        {<doc><e unknown="some"/></doc>}
         2327  +        {<doc><e/></doc>}
         2328  +    } {
         2329  +        lappend result [catch {set doc [dom parse -validateCmd s $xml]} errMsg]
         2330  +        lappend result $errMsg
         2331  +        s reset
         2332  +    }
         2333  +    s delete
         2334  +    set result
         2335  +} {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}}
         2336  +
         2337  +test schema-11.6 {nsattribute} {
         2338  +    tdom::schema create s
         2339  +    s prefixns {ns1 http://www.w3.org/XML/1998/namespace}
         2340  +    s define {
         2341  +        defelement doc {
         2342  +            element e 1 {
         2343  +                attribute foo
         2344  +                nsattribute lang ns1
         2345  +            }
         2346  +        }
  2264   2347       }
  2265   2348       set result [list]
  2266   2349       foreach xml {
  2267   2350           {<doc><e foo="bar"/></doc>}
  2268   2351           {<doc><e xml:lang="en"/></doc>}
  2269   2352           {<doc><e unknown="some"/></doc>}
  2270   2353           {<doc><e/></doc>}
................................................................................
  2413   2496           defelement card http://foo.bar {
  2414   2497               element name
  2415   2498               element email
  2416   2499           }
  2417   2500           foreach e {name email} {
  2418   2501               defelement $e http://foo.bar {text}
  2419   2502           }
         2503  +    }
         2504  +    set doc [dom parse {
         2505  +<addressBook xmlns="http://foo.bar">
         2506  +  <card>
         2507  +    <name>John Smith</name>
         2508  +    <email>[email protected]</email>
         2509  +  </card>
         2510  +  <card>
         2511  +    <name>Fred Bloggs</name>
         2512  +    <email>[email protected]</email>
         2513  +  </card>
         2514  +</addressBook>        
         2515  +    }]
         2516  +    set result [s domvalidate $doc]
         2517  +    lappend result [s domvalidate [$doc documentElement]]
         2518  +    lappend result [s domvalidate [[$doc documentElement] firstChild]]
         2519  +    lappend result [s domvalidate [[[$doc documentElement] firstChild] firstChild]]
         2520  +    $doc delete
         2521  +    set doc [dom parse {
         2522  +<ns1:addressBook xmlns:ns1="http://foo.bar">
         2523  +  <ns1:card>
         2524  +    <ns1:name>John Smith</ns1:name>
         2525  +    <ns1:email>[email protected]</ns1:email>
         2526  +  </ns1:card>
         2527  +  <ns1:card>
         2528  +    <ns1:name>Fred Bloggs</ns1:name>
         2529  +    <ns1:email>[email protected]</ns1:email>
         2530  +  </ns1:card>
         2531  +</ns1:addressBook>        
         2532  +}]
         2533  +    lappend result [s domvalidate $doc]
         2534  +    lappend result [s domvalidate [$doc documentElement]]
         2535  +    lappend result [s domvalidate [[$doc documentElement] firstChild]]
         2536  +    lappend result [s domvalidate [[[$doc documentElement] firstChild] firstChild]]
         2537  +    $doc delete
         2538  +    s delete
         2539  +    set result
         2540  +} {1 1 1 1 1 1 1 1}
         2541  +
         2542  +test schema-12.5a {domvalidate doch w/ xml namespace} {
         2543  +    tdom::schema s 
         2544  +    s prefixns {fb http://foo.bar}
         2545  +    s define {
         2546  +        defelement addressBook fb {
         2547  +            element card *
         2548  +        }
         2549  +        defelement card fb {
         2550  +            element name
         2551  +            element email
         2552  +        }
         2553  +        foreach e {name email} {
         2554  +            defelement $e fb {text}
         2555  +        }
  2420   2556       }
  2421   2557       set doc [dom parse {
  2422   2558   <addressBook xmlns="http://foo.bar">
  2423   2559     <card>
  2424   2560       <name>John Smith</name>
  2425   2561       <email>[email protected]</email>
  2426   2562     </card>