tDOM

Check-in [74a399d84f]
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:Added method prefixns to schema cmds. This allows to point to namespace URIs by shortcuts or prefixes.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | schema
Files: files | file ages | folders
SHA3-256: 74a399d84f2fa99e070a1f8fd4460990c7d092bf535d50d30c8c9737db787695
User & Date: rolf 2019-05-10 00:36:44
Context
2019-05-10
13:04
Futher work on prefixns: allow it als top level command in define script. Changed semantic to first prefix/namespace mapping in prefixUriList wins, if there are several prefixes mapping to different namespaces. check-in: a70c1d6c6e user: rolf tags: schema
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:13
Fixed merge error. check-in: 89fbb30347 user: rolf tags: schema
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.

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

Changes to generic/schema.h.

   108    108   {
   109    109       Tcl_Obj *self;
   110    110       char *start;
   111    111       char *startNamespace;
   112    112       Tcl_HashTable element;
   113    113       Tcl_HashTable namespace;
   114    114       Tcl_HashEntry *emptyNamespace;
          115  +    char **prefixns;
          116  +    Tcl_HashTable prefix;
   115    117       Tcl_HashTable pattern;
   116    118       Tcl_HashTable attrNames;
   117    119       Tcl_HashTable textDef;
   118    120       SchemaCP **patternList; 
   119    121       unsigned int numPatternList;
   120    122       unsigned int patternListSize;
   121    123       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>