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

Overview
Comment:Fixed bug introduced with prefixns: the shortcuts from prefixns are only used for schema definiton; they mean nothing for prefix/namespace in the xml input.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | schema
Files: files | file ages | folders
SHA3-256: 40671ee8c38a593046f959a1c79e80ea44a1e2633d72ed5a48acf112c37bca8c
User & Date: rolf 2019-08-06 23:11:33
Context
2019-08-06
23:31
Removed cruft for versions not supported anymore. check-in: 13fe3aff35 user: rolf tags: schema
23:11
Fixed bug introduced with prefixns: the shortcuts from prefixns are only used for schema definiton; they mean nothing for prefix/namespace in the xml input. check-in: 40671ee8c3 user: rolf tags: schema
2019-08-02
23:52
The comment is correct, adjusted the code to do what it say. check-in: 4d478f979b user: rolf tags: schema
Changes
Hide Diffs Unified Diffs Show Whitespace Changes Patch

Changes to doc/schema.html.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
...
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
...
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
...
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
...
561
562
563
564
565
566
567
568

569
570
571
572




573
574
575

576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
...
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
<html>
<head>
<link rel="stylesheet" href="manpage.css"><title>tDOM manual: schema</title><meta name="xsl-processor" content="Jochen Loewer (loewerj@hotmail.com), Rolf Ade (rolf@pointsman.de) et. al."><meta name="generator" content="$RCSfile: tmml-html.xsl,v $ $Revision: 1.11 $"><meta charset="utf-8">
</head><body>
<div class="header">
<div class="navbar" align="center">
<a href="#SECTid0x55cd0c9deb30">NAME</a> · <a href="#SECTid0x55cd0c9df160">SYNOPSIS</a> · <a href="#SECTid0x55cd0c9d95d0">DESCRIPTION </a> · <a href="#SECTid0x55cd0ca3a0f0">Schema definition scripts</a> · <a href="#SECTid0x55cd0ca43030">Quantity specifier</a> · <a href="#SECTid0x55cd0ca44ec0">Text constraint scripts</a> · <a href="#SECTid0x55cd0ca4d9c0">Local key constraints</a> · <a href="#SECTid0x55cd0ca4f7d0">Exampels</a>
</div><hr class="navsep">
</div><div class="body">
  <h2><a name="SECTid0x55cd0c9deb30">NAME</a></h2><p class="namesection">
<b class="names">tdom::schema - </b><br>Create a schema validation command</p>

  <h2><a name="SECTid0x55cd0c9df160">SYNOPSIS</a></h2><pre class="syntax">package require tdom

<b class="cmd">tdom::schema</b> <i class="m">?create?</i> <i class="m">cmdName</i>
    </pre>

  <h2><a name="SECTid0x55cd0c9d95d0">DESCRIPTION </a></h2><p>This command creates validation commands with a simple API. The
    validation commands have methods to define a schema and are able
    to validate XML or DOM trees (and to some degree other kind of
    hierarchical data) against this schema.</p><p>Additionally, a validation command may be used as argument to
    the <i class="m">-validateCmd</i> option of the <i class="m">dom parse</i> and the
    <i class="m">expat</i> commands to enable validation additional to what they
    otherwise do.</p><p>The valid methods of the created commands are:</p><dl class="commandlist">
      
................................................................................
        <dt><b class="method">reset</b></dt>
        <dd>This method resets the validation command into state
        READY (while preserving the defined grammer).</dd>
      

    </dl>

  <h2><a name="SECTid0x55cd0ca3a0f0">Schema definition scripts</a></h2><p>Schema definition scripts are ordinary Tcl scripts that are
    evaluatend in the namespace tdom::schema. The below listed schema
    definition commands in this tcl namespace allow to define a wide
    variety of document structures. Every schema definition command
    establish a validation constraint on the content which has to
    match or must be optional to render the content as valid. It is a
    validation error if the element in the XML source has additional
    (not matched) content.</p><p>The schema definition commands are:</p><dl class="commandlist">
................................................................................
        call. This is meant as toplevel command of a <i>schemacmd
        define</i> script. This command is not allowed nested in an
        other definition script command and will raise error, if you
        call it there.</dd>
      
    </dl>

  <h2><a name="SECTid0x55cd0ca43030">Quantity specifier</a></h2><p>Serveral schema definition commands expects a quantifier as
    one of their arguments, which specifies how often the content
    particle specified by the command is expected. The valid values
    for a <i class="m">quant</i> argument are:</p><dl class="optlist">
      
        <dt><b>!</b></dt>
        <dd>The content particle must occur exactly once in valid
        documents. This is the default, if a quantifier is
................................................................................
        n to m times (both inclusive) in a row in valid documents. The
        quantifier must be a tcl list with two elements. Both elements
        must be integers, with n &gt;= 0 and n &lt; m.</dd>
      
    </dl><p>If an optional quantifier is not given then it defaults to * in
    case of the mixed command and to ! for all other commands.</p>

  <h2><a name="SECTid0x55cd0ca44ec0">Text constraint scripts</a></h2><p>Text - parsed character data, as XML calles it - must sometimes
    have to be of a certain kind, must comply to some rules etc to be
    valid.</p><p>The text constraint commands are:</p><dl class="commandlist">
      
        <dt>
<b class="cmd">integer</b> <i class="m">?(xsd|tcl)?</i>
</dt>
        <dd>This text constraint match if the text value could be
................................................................................
            which elements are tested..</dd>
        </dl>
        <p>The default in case no split type argument is given is
        <i class="m">whitespace</i>.</p>
</dd>
      
      
        <dt><b class="cmd">id</b></dt>

        <dd>This text constraint command marks the text as a
        document wide ID (to be referenced by an idref). Every ID
        value within a document must be unique. It isn't an error if
        the ID isn't actually referenced within the document.</dd>




      
      
        <dt><b class="cmd">idref</b></dt>

        <dd>This text constraint command expects the text to be a
        reference to an ID within the document. The referenced ID may
        be later in the document, that the reference. Several
        references within the document to one ID are possible.</dd>
      
      
        <dt><b class="cmd">base64</b></dt>
        <dd>This text constraint match if text is valid according to
        RFC 4648.</dd>
      
    </dl>

  <h2><a name="SECTid0x55cd0ca4d9c0">Local key constraints</a></h2><p>Document wide uniqueness and foreign key constraints are
    available with the text constraint commands id and idref.
    Keyspaces allow for sub-tree local uniqueness and foreign key
    constraints.</p><dl class="commandlist">
        
            <dt>
<b class="cmd">keyspace</b> <i class="m">names list&gt;</i> <i class="m">&lt;constraint script&gt;</i>
</dt>
................................................................................
            active always matches. If the keyspace is active then
            reports error if there is still no key as the value at the
            end of the keyspace <i class="m">name&gt;</i>. Otherwise it
            matches.</dd>
        
    </dl>

  <h2><a name="SECTid0x55cd0ca4f7d0">Exampels</a></h2><p>The XML Schema Part 0: Primer Second Edition
    (<a href="https://www.w3.org/TR/xmlschema-0/">https://www.w3.org/TR/xmlschema-0/</a>) starts with this
    example schema:</p><pre class="example">
&lt;xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"&gt;

  &lt;xsd:annotation&gt;
    &lt;xsd:documentation xml:lang="en"&gt;
     Purchase order schema for Example.com.






|


|


|




|







 







|







 







|







 







|







 







|
>



|
>
>
>
>


|
>












|







 







|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
...
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
...
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
...
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
...
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
...
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
<html>
<head>
<link rel="stylesheet" href="manpage.css"><title>tDOM manual: schema</title><meta name="xsl-processor" content="Jochen Loewer (loewerj@hotmail.com), Rolf Ade (rolf@pointsman.de) et. al."><meta name="generator" content="$RCSfile: tmml-html.xsl,v $ $Revision: 1.11 $"><meta charset="utf-8">
</head><body>
<div class="header">
<div class="navbar" align="center">
<a href="#SECTid0x55bd61f17b30">NAME</a> · <a href="#SECTid0x55bd61f18190">SYNOPSIS</a> · <a href="#SECTid0x55bd61f12610">DESCRIPTION </a> · <a href="#SECTid0x55bd61f6f140">Schema definition scripts</a> · <a href="#SECTid0x55bd61f78080">Quantity specifier</a> · <a href="#SECTid0x55bd61f79f10">Text constraint scripts</a> · <a href="#SECTid0x55bd61f82e70">Local key constraints</a> · <a href="#SECTid0x55bd61f84c80">Exampels</a>
</div><hr class="navsep">
</div><div class="body">
  <h2><a name="SECTid0x55bd61f17b30">NAME</a></h2><p class="namesection">
<b class="names">tdom::schema - </b><br>Create a schema validation command</p>

  <h2><a name="SECTid0x55bd61f18190">SYNOPSIS</a></h2><pre class="syntax">package require tdom

<b class="cmd">tdom::schema</b> <i class="m">?create?</i> <i class="m">cmdName</i>
    </pre>

  <h2><a name="SECTid0x55bd61f12610">DESCRIPTION </a></h2><p>This command creates validation commands with a simple API. The
    validation commands have methods to define a schema and are able
    to validate XML or DOM trees (and to some degree other kind of
    hierarchical data) against this schema.</p><p>Additionally, a validation command may be used as argument to
    the <i class="m">-validateCmd</i> option of the <i class="m">dom parse</i> and the
    <i class="m">expat</i> commands to enable validation additional to what they
    otherwise do.</p><p>The valid methods of the created commands are:</p><dl class="commandlist">
      
................................................................................
        <dt><b class="method">reset</b></dt>
        <dd>This method resets the validation command into state
        READY (while preserving the defined grammer).</dd>
      

    </dl>

  <h2><a name="SECTid0x55bd61f6f140">Schema definition scripts</a></h2><p>Schema definition scripts are ordinary Tcl scripts that are
    evaluatend in the namespace tdom::schema. The below listed schema
    definition commands in this tcl namespace allow to define a wide
    variety of document structures. Every schema definition command
    establish a validation constraint on the content which has to
    match or must be optional to render the content as valid. It is a
    validation error if the element in the XML source has additional
    (not matched) content.</p><p>The schema definition commands are:</p><dl class="commandlist">
................................................................................
        call. This is meant as toplevel command of a <i>schemacmd
        define</i> script. This command is not allowed nested in an
        other definition script command and will raise error, if you
        call it there.</dd>
      
    </dl>

  <h2><a name="SECTid0x55bd61f78080">Quantity specifier</a></h2><p>Serveral schema definition commands expects a quantifier as
    one of their arguments, which specifies how often the content
    particle specified by the command is expected. The valid values
    for a <i class="m">quant</i> argument are:</p><dl class="optlist">
      
        <dt><b>!</b></dt>
        <dd>The content particle must occur exactly once in valid
        documents. This is the default, if a quantifier is
................................................................................
        n to m times (both inclusive) in a row in valid documents. The
        quantifier must be a tcl list with two elements. Both elements
        must be integers, with n &gt;= 0 and n &lt; m.</dd>
      
    </dl><p>If an optional quantifier is not given then it defaults to * in
    case of the mixed command and to ! for all other commands.</p>

  <h2><a name="SECTid0x55bd61f79f10">Text constraint scripts</a></h2><p>Text - parsed character data, as XML calles it - must sometimes
    have to be of a certain kind, must comply to some rules etc to be
    valid.</p><p>The text constraint commands are:</p><dl class="commandlist">
      
        <dt>
<b class="cmd">integer</b> <i class="m">?(xsd|tcl)?</i>
</dt>
        <dd>This text constraint match if the text value could be
................................................................................
            which elements are tested..</dd>
        </dl>
        <p>The default in case no split type argument is given is
        <i class="m">whitespace</i>.</p>
</dd>
      
      
        <dt><b class="cmd">id <i class="m">?keySpace?</i>
</b></dt>
        <dd>This text constraint command marks the text as a
        document wide ID (to be referenced by an idref). Every ID
        value within a document must be unique. It isn't an error if
        the ID isn't actually referenced within the document. The
        optional argument <i class="m">keySpace</i> does all this for a named
        key space. The key space "" (the empty sting) is another key
        space as the <i class="m">id</i> command without keySpace
        argument.</dd>
      
      
        <dt><b class="cmd">idref <i class="m">?keySpace?</i>
</b></dt>
        <dd>This text constraint command expects the text to be a
        reference to an ID within the document. The referenced ID may
        be later in the document, that the reference. Several
        references within the document to one ID are possible.</dd>
      
      
        <dt><b class="cmd">base64</b></dt>
        <dd>This text constraint match if text is valid according to
        RFC 4648.</dd>
      
    </dl>

  <h2><a name="SECTid0x55bd61f82e70">Local key constraints</a></h2><p>Document wide uniqueness and foreign key constraints are
    available with the text constraint commands id and idref.
    Keyspaces allow for sub-tree local uniqueness and foreign key
    constraints.</p><dl class="commandlist">
        
            <dt>
<b class="cmd">keyspace</b> <i class="m">names list&gt;</i> <i class="m">&lt;constraint script&gt;</i>
</dt>
................................................................................
            active always matches. If the keyspace is active then
            reports error if there is still no key as the value at the
            end of the keyspace <i class="m">name&gt;</i>. Otherwise it
            matches.</dd>
        
    </dl>

  <h2><a name="SECTid0x55bd61f84c80">Exampels</a></h2><p>The XML Schema Part 0: Primer Second Edition
    (<a href="https://www.w3.org/TR/xmlschema-0/">https://www.w3.org/TR/xmlschema-0/</a>) starts with this
    example schema:</p><pre class="example">
&lt;xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"&gt;

  &lt;xsd:annotation&gt;
    &lt;xsd:documentation xml:lang="en"&gt;
     Purchase order schema for Example.com.

Changes to doc/schema.n.

564
565
566
567
568
569
570
571
572
573
574
575




576
577
578
579
580
581
582
583
584
as last argument. This call must return a valid tcl list,
which elements are tested..
.PP
The default in case no split type argument is given is
\&\fIwhitespace\fR.
.RE
.TP
\&\fB\fBid\fP
\&\fRThis text constraint command marks the text as a
document wide ID (to be referenced by an idref). Every ID
value within a document must be unique. It isn't an error if
the ID isn't actually referenced within the document.




.TP
\&\fB\fBidref\fP
\&\fRThis text constraint command expects the text to be a
reference to an ID within the document. The referenced ID may
be later in the document, that the reference. Several
references within the document to one ID are possible.
.TP
\&\fB\fBbase64\fP
\&\fRThis text constraint match if text is valid according to







|



|
>
>
>
>

|







564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
as last argument. This call must return a valid tcl list,
which elements are tested..
.PP
The default in case no split type argument is given is
\&\fIwhitespace\fR.
.RE
.TP
\&\fB\fBid \fI?keySpace?\fB\fP
\&\fRThis text constraint command marks the text as a
document wide ID (to be referenced by an idref). Every ID
value within a document must be unique. It isn't an error if
the ID isn't actually referenced within the document. The
optional argument \fIkeySpace\fR does all this for a named
key space. The key space "" (the empty sting) is another key
space as the \fIid\fR command without keySpace
argument.
.TP
\&\fB\fBidref \fI?keySpace?\fB\fP
\&\fRThis text constraint command expects the text to be a
reference to an ID within the document. The referenced ID may
be later in the document, that the reference. Several
references within the document to one ID are possible.
.TP
\&\fB\fBbase64\fP
\&\fRThis text constraint match if text is valid according to

Changes to doc/schema.xml.

512
513
514
515
516
517
518
519
520
521
522
523




524
525
526
527
528
529
530
531
532
533
            as last argument. This call must return a valid tcl list,
            which elements are tested..</dd>
        </dl>
        <p>The default in case no split type argument is given is
        <m>whitespace</m>.</p></desc>
      </commanddef>
      <commanddef>
        <command><cmd>id</cmd></command>
        <desc>This text constraint command marks the text as a
        document wide ID (to be referenced by an idref). Every ID
        value within a document must be unique. It isn't an error if
        the ID isn't actually referenced within the document.</desc>




      </commanddef>
      <commanddef>
        <command><cmd>idref</cmd></command>
        <desc>This text constraint command expects the text to be a
        reference to an ID within the document. The referenced ID may
        be later in the document, that the reference. Several
        references within the document to one ID are possible.</desc>
      </commanddef>
      <commanddef>
        <command><cmd>base64</cmd></command>







|



|
>
>
>
>


|







512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
            as last argument. This call must return a valid tcl list,
            which elements are tested..</dd>
        </dl>
        <p>The default in case no split type argument is given is
        <m>whitespace</m>.</p></desc>
      </commanddef>
      <commanddef>
        <command><cmd>id <m>?keySpace?</m></cmd></command>
        <desc>This text constraint command marks the text as a
        document wide ID (to be referenced by an idref). Every ID
        value within a document must be unique. It isn't an error if
        the ID isn't actually referenced within the document. The
        optional argument <m>keySpace</m> does all this for a named
        key space. The key space "" (the empty sting) is another key
        space as the <m>id</m> command without keySpace
        argument.</desc>
      </commanddef>
      <commanddef>
        <command><cmd>idref <m>?keySpace?</m></cmd></command>
        <desc>This text constraint command expects the text to be a
        reference to an ID within the document. The referenced ID may
        be later in the document, that the reference. Several
        references within the document to one ID are possible.</desc>
      </commanddef>
      <commanddef>
        <command><cmd>base64</cmd></command>

Changes to generic/schema.c.

605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
...
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
....
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
....
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
....
1176
1177
1178
1179
1180
1181
1182


















1183






1184
1185
1186
1187
1188
1189

1190
1191
1192
1193
1194
1195
1196
....
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
....
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485
3486
....
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
cleanupLastPattern (
    SchemaData *sdata,
    unsigned int from
    )
{
    unsigned int i;
    Tcl_HashTable *hashTable;
    Tcl_HashEntry *entryPtr;

    SchemaCP *this, *previous, *current;

    for (i = from; i < sdata->numPatternList; i++) {
        this = sdata->patternList[i];
        hashTable = NULL;
        if (this->type == SCHEMA_CTYPE_NAME) {
................................................................................
        if (this->type == SCHEMA_CTYPE_PATTERN) {
            hashTable = &sdata->pattern;
        }
        if (this->name && hashTable) {
            if (this->flags & FORWARD_PATTERN_DEF) {
                sdata->forwardPatternDefs--;
            }
            entryPtr = Tcl_FindHashEntry (hashTable, this->name);
            previous = NULL;
            current = Tcl_GetHashValue (entryPtr);
            while (current != NULL && current != this) {
                previous = current;
                current = current->next;
            }
            if (previous) {
                if (current->next) {
                    previous->next = current->next;
                } else {
                    previous->next = NULL;
                }
            } else {
                if (current) {
                    Tcl_SetHashValue (entryPtr, current->next);
                } else {
                    Tcl_DeleteHashEntry (entryPtr);
                }
            }
        }
        freeSchemaCP (sdata->patternList[i]);
    }
    sdata->numPatternList = from;
}
................................................................................

            case SCHEMA_CTYPE_KEYSPACE_END:
            case SCHEMA_CTYPE_KEYSPACE:
                Tcl_Panic ("Keyspace constraint child of INTERLEAVE");
                break;

            }

        }
                
        if (mayskip) break;
        if (recover (interp, sdata, S("UNCOMPLET_CP"))) {
            sdata->skipDeep = 2;
            return 1;
        }
................................................................................
probeElement (
    Tcl_Interp *interp,
    SchemaData *sdata,
    const char *name,
    void *namespace
    )
{
    Tcl_HashEntry *entryPtr;
    void *namespacePtr, *namePtr;
    SchemaCP *pattern;
    int rc;

    if (sdata->skipDeep) {
        sdata->skipDeep++;
        return TCL_OK;
    }
    if (sdata->validationState == VALIDATION_FINISHED) {
        SetResult ("Validation finished.");
................................................................................
    }

    DBG(
        fprintf (stderr, "probeElement: look if '%s' in ns '%s' match\n",
                 name, (char *)namespace);
        );



















    namespacePtr = getNamespacePtr (sdata, namespace);






    entryPtr = Tcl_FindHashEntry (&sdata->element, name);
    if (entryPtr) {
        namePtr = Tcl_GetHashKey (&sdata->element, entryPtr);
    } else {
        namePtr = NULL;
    }


    if (sdata->validationState == VALIDATION_READY) {
        /* The root of the tree to check. */
        if (sdata->start) {
            if (strcmp (name, sdata->start) != 0) {
                SetResult ("Root element doesn't match");
                return TCL_ERROR;
................................................................................
                if (sdata->startNamespace) {
                    SetResult ("Root element namespace doesn't match");
                    return TCL_ERROR;
                }
            }
        }
    }
    if (entryPtr) {
        pattern = (SchemaCP *) Tcl_GetHashValue (entryPtr);
        while (pattern) {
            if (pattern->namespace == namespacePtr) {
                break;
            }
            pattern = pattern->next;
        }
    } else {
................................................................................
    int objc,
    Tcl_Obj *const objv[]
    )
{
    SchemaData *sdata = GETASI;
    Schema_CP_Type patternType = (Schema_CP_Type) clientData;
    Tcl_HashTable *hashTable;
    Tcl_HashEntry *entryPtr;
    SchemaCP *pattern = NULL, *current;
    SchemaQuant quant;
    int hnew, n, m;

    CHECK_SI
    CHECK_TOPLEVEL
    if (patternType == SCHEMA_CTYPE_NAME) {
................................................................................
        hashTable = &sdata->pattern;
    }

    quant = getQuant (interp, sdata, objc == 2 ? NULL : objv[2], &n, &m);
    if (quant == SCHEMA_CQUANT_ERROR) {
        return TCL_ERROR;
    }
    entryPtr = Tcl_CreateHashEntry (hashTable,
                                    Tcl_GetString(objv[1]), &hnew);
    if (objc < 4) {
        /* Reference to an element or pattern */
        if (!hnew) {
            pattern = (SchemaCP *) Tcl_GetHashValue (entryPtr);
            while (pattern) {
                if (pattern->namespace == sdata->currentNamespace) {
                    break;
                }
                pattern = pattern->next;
            }
        }
        if (!pattern) {
            pattern = initSchemaCP (
                patternType,
                sdata->currentNamespace,
                Tcl_GetHashKey (hashTable, entryPtr)
                );
            pattern->flags |= FORWARD_PATTERN_DEF;
            sdata->forwardPatternDefs++;
            if (!hnew) {
                current = (SchemaCP *) Tcl_GetHashValue (entryPtr);
                pattern->next = current;
            }
            REMEMBER_PATTERN (pattern);
            Tcl_SetHashValue (entryPtr, pattern);
        }
        addToContent (sdata, pattern, quant, n, m);
    } else {
        /* Local definition of this element */
        if (hnew) {
            pattern = initSchemaCP (
                SCHEMA_CTYPE_NAME,
                sdata->currentNamespace,
                Tcl_GetHashKey (hashTable, entryPtr)
                );
            pattern->flags |= PLACEHOLDER_PATTERN_DEF;
            REMEMBER_PATTERN (pattern);
            Tcl_SetHashValue (entryPtr, pattern);
        }
        pattern = initSchemaCP (
            SCHEMA_CTYPE_NAME,
            sdata->currentNamespace,
            Tcl_GetHashKey (hashTable, entryPtr)
            );
        pattern->flags |= LOCAL_DEFINED_ELEMENT;
        return evalDefinition (interp, sdata, objv[3], pattern, quant, n, m);
    }
    return TCL_OK;
}








|







 







|

|












|

|







 







<







 







|


|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
|
|
|
|
|
|
>







 







|
|







 







|







 







|




|











|




|



|








|



|




|







605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
...
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
....
1115
1116
1117
1118
1119
1120
1121

1122
1123
1124
1125
1126
1127
1128
....
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
....
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
....
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
....
3496
3497
3498
3499
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510
....
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563
3564
3565
3566
3567
3568
3569
3570
3571
3572
3573
cleanupLastPattern (
    SchemaData *sdata,
    unsigned int from
    )
{
    unsigned int i;
    Tcl_HashTable *hashTable;
    Tcl_HashEntry *h;

    SchemaCP *this, *previous, *current;

    for (i = from; i < sdata->numPatternList; i++) {
        this = sdata->patternList[i];
        hashTable = NULL;
        if (this->type == SCHEMA_CTYPE_NAME) {
................................................................................
        if (this->type == SCHEMA_CTYPE_PATTERN) {
            hashTable = &sdata->pattern;
        }
        if (this->name && hashTable) {
            if (this->flags & FORWARD_PATTERN_DEF) {
                sdata->forwardPatternDefs--;
            }
            h = Tcl_FindHashEntry (hashTable, this->name);
            previous = NULL;
            current = Tcl_GetHashValue (h);
            while (current != NULL && current != this) {
                previous = current;
                current = current->next;
            }
            if (previous) {
                if (current->next) {
                    previous->next = current->next;
                } else {
                    previous->next = NULL;
                }
            } else {
                if (current) {
                    Tcl_SetHashValue (h, current->next);
                } else {
                    Tcl_DeleteHashEntry (h);
                }
            }
        }
        freeSchemaCP (sdata->patternList[i]);
    }
    sdata->numPatternList = from;
}
................................................................................

            case SCHEMA_CTYPE_KEYSPACE_END:
            case SCHEMA_CTYPE_KEYSPACE:
                Tcl_Panic ("Keyspace constraint child of INTERLEAVE");
                break;

            }

        }
                
        if (mayskip) break;
        if (recover (interp, sdata, S("UNCOMPLET_CP"))) {
            sdata->skipDeep = 2;
            return 1;
        }
................................................................................
probeElement (
    Tcl_Interp *interp,
    SchemaData *sdata,
    const char *name,
    void *namespace
    )
{
    Tcl_HashEntry *h;
    void *namespacePtr, *namePtr;
    SchemaCP *pattern;
    int rc = 1;

    if (sdata->skipDeep) {
        sdata->skipDeep++;
        return TCL_OK;
    }
    if (sdata->validationState == VALIDATION_FINISHED) {
        SetResult ("Validation finished.");
................................................................................
    }

    DBG(
        fprintf (stderr, "probeElement: look if '%s' in ns '%s' match\n",
                 name, (char *)namespace);
        );

    /* This is problematic. If feeded with continuously new namespaces */
    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;
        }
        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;
        }
    }
    
    if (sdata->validationState == VALIDATION_READY) {
        /* The root of the tree to check. */
        if (sdata->start) {
            if (strcmp (name, sdata->start) != 0) {
                SetResult ("Root element doesn't match");
                return TCL_ERROR;
................................................................................
                if (sdata->startNamespace) {
                    SetResult ("Root element namespace doesn't match");
                    return TCL_ERROR;
                }
            }
        }
    }
    if (h) {
        pattern = (SchemaCP *) Tcl_GetHashValue (h);
        while (pattern) {
            if (pattern->namespace == namespacePtr) {
                break;
            }
            pattern = pattern->next;
        }
    } else {
................................................................................
    int objc,
    Tcl_Obj *const objv[]
    )
{
    SchemaData *sdata = GETASI;
    Schema_CP_Type patternType = (Schema_CP_Type) clientData;
    Tcl_HashTable *hashTable;
    Tcl_HashEntry *h;
    SchemaCP *pattern = NULL, *current;
    SchemaQuant quant;
    int hnew, n, m;

    CHECK_SI
    CHECK_TOPLEVEL
    if (patternType == SCHEMA_CTYPE_NAME) {
................................................................................
        hashTable = &sdata->pattern;
    }

    quant = getQuant (interp, sdata, objc == 2 ? NULL : objv[2], &n, &m);
    if (quant == SCHEMA_CQUANT_ERROR) {
        return TCL_ERROR;
    }
    h = Tcl_CreateHashEntry (hashTable,
                                    Tcl_GetString(objv[1]), &hnew);
    if (objc < 4) {
        /* Reference to an element or pattern */
        if (!hnew) {
            pattern = (SchemaCP *) Tcl_GetHashValue (h);
            while (pattern) {
                if (pattern->namespace == sdata->currentNamespace) {
                    break;
                }
                pattern = pattern->next;
            }
        }
        if (!pattern) {
            pattern = initSchemaCP (
                patternType,
                sdata->currentNamespace,
                Tcl_GetHashKey (hashTable, 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);
    } else {
        /* Local definition of this element */
        if (hnew) {
            pattern = initSchemaCP (
                SCHEMA_CTYPE_NAME,
                sdata->currentNamespace,
                Tcl_GetHashKey (hashTable, h)
                );
            pattern->flags |= PLACEHOLDER_PATTERN_DEF;
            REMEMBER_PATTERN (pattern);
            Tcl_SetHashValue (h, pattern);
        }
        pattern = initSchemaCP (
            SCHEMA_CTYPE_NAME,
            sdata->currentNamespace,
            Tcl_GetHashKey (hashTable, h)
            );
        pattern->flags |= LOCAL_DEFINED_ELEMENT;
        return evalDefinition (interp, sdata, objv[3], pattern, quant, n, m);
    }
    return TCL_OK;
}

Changes to tests/schema.test.

596
597
598
599
600
601
602












603
604
605
606
607
608
609
....
2227
2228
2229
2230
2231
2232
2233

















2234
2235
2236
2237
2238
2239
2240
        }
    } errMsg]
    lappend result $errMsg
    s delete
    set result
} {1 {Command only allowed at lop level} 1 {Command only allowed at lop level} 1 {Method not allowed in nested schema define script} 1 {This recursive call is not allowed}}













test schema-2.1 {grammar definition: ref} {
    tdom::schema create grammar
    grammar defpattern thisPattern {
        element a
        element b
    }
    grammar defpattern thatPattern {
................................................................................
        {<doc xmlns:ns="http://foo.bar" xmlns:ns1="http://foo.grill"><a/><ns1:a/><ns:b>some</ns:b><b/></doc>}
    } {
        lappend result [s validate $xml]
    }
    s delete
    set result
} {0 0 0 0 1 1 0}


















test schema-11.1 {attribute} {
    tdom::schema create s
    s define {
        defelement doc {
            attribute attr1
            attribute attr2 ?







>
>
>
>
>
>
>
>
>
>
>
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
....
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
        }
    } errMsg]
    lappend result $errMsg
    s delete
    set result
} {1 {Command only allowed at lop level} 1 {Command only allowed at lop level} 1 {Method 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 {<b:doc xmlns:b="a"/>} errMsg]
    lappend result $errMsg
    s delete
    set result
} {0 {error "Unknown element" at line 1 character 20}}

test schema-2.1 {grammar definition: ref} {
    tdom::schema create grammar
    grammar defpattern thisPattern {
        element a
        element b
    }
    grammar defpattern thatPattern {
................................................................................
        {<doc xmlns:ns="http://foo.bar" xmlns:ns1="http://foo.grill"><a/><ns1:a/><ns:b>some</ns:b><b/></doc>}
    } {
        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 {
        {<doc><a:some xmlns:a="uri"/></doc>}
    } {
        lappend result [s validate $xml]
    }
    s delete
    set result
} {1}

test schema-11.1 {attribute} {
    tdom::schema create s
    s define {
        defelement doc {
            attribute attr1
            attribute attr2 ?