tDOM

Check-in [43cf45b772]
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 sub tree local uniqueness and foreign key contents.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | schema
Files: files | file ages | folders
SHA3-256: 43cf45b77293eb5aa10ea4affbced09e6b8e0ed8329ec636b63fae2cc99ab87f
User & Date: rolf 2019-05-31 00:05:12
Context
2019-05-31
17:00
Small editorial corrections. check-in: 09863d4ab7 user: rolf tags: schema
00:05
Added sub tree local uniqueness and foreign key contents. check-in: 43cf45b772 user: rolf tags: schema
2019-05-30
23:54
Adapt the example section to what is actually implemented. Closed-Leaf check-in: ebb73c9257 user: rolf tags: keyspaces
2019-05-21
22:30
Added dom tree validation specific unique key contraints along the lines of xsd unqiue with selector and list of fields but with no restrictions on the XPath expressions (other then resulting a node set in case of selector and a result set with one node in case of field XPath expression). check-in: ba6bd2bb7c user: rolf tags: schema
Changes
Hide Diffs Unified Diffs Ignore Whitespace 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
...
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
...
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
...
390
391
392
393
394
395
396


397
398
399
400
401
402
403
404
...
553
554
555
556
557
558
559
560




































561
562
563
564
565
566
567
568
<html>
<head>
<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">
</head><body>
<div class="header">
<div class="navbar" align="center">
<a href="#SECTid0x55ce24033b10">NAME</a> · <a href="#SECTid0x55ce24034170">SYNOPSIS</a> · <a href="#SECTid0x55ce2402e5f0">DESCRIPTION </a> · <a href="#SECTid0x55ce2408e1e0">Schema definition scripts</a> · <a href="#SECTid0x55ce24096d00">Quantity specifier</a> · <a href="#SECTid0x55ce24098b90">Text constraint scripts</a> · <a href="#SECTid0x55ce240a0fa0">Exampels</a>
</div><hr class="navsep">
</div><div class="body">
  <h2><a name="SECTid0x55ce24033b10">NAME</a></h2><p class="namesection">
<b class="names">tdom::schema - </b><br>Create a schema validation command</p>

  <h2><a name="SECTid0x55ce24034170">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="SECTid0x55ce2402e5f0">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="SECTid0x55ce2408e1e0">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="SECTid0x55ce24096d00">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="SECTid0x55ce24098b90">Text constraint scripts</a></h2><p></p><p>The text constraint commands are:</p><dl class="commandlist">
      
        <dt><b class="cmd">isint</b></dt>
        <dd></dd>
      

      
        <dt>
................................................................................
      
      
        <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="SECTid0x55ce240a0fa0">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
...
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
...
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
...
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
...
555
556
557
558
559
560
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
602
603
604
605
606
<html>
<head>
<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">
</head><body>
<div class="header">
<div class="navbar" align="center">
<a href="#SECTid0x555cbefafb30">NAME</a> · <a href="#SECTid0x555cbefb0160">SYNOPSIS</a> · <a href="#SECTid0x555cbefaa5d0">DESCRIPTION </a> · <a href="#SECTid0x555cbf00a680">Schema definition scripts</a> · <a href="#SECTid0x555cbf0131a0">Quantity specifier</a> · <a href="#SECTid0x555cbf015030">Text constraint scripts</a> · <a href="#SECTid0x555cbf01d520">Local key constraints</a> · <a href="#SECTid0x555cbf01f330">Exampels</a>
</div><hr class="navsep">
</div><div class="body">
  <h2><a name="SECTid0x555cbefafb30">NAME</a></h2><p class="namesection">
<b class="names">tdom::schema - </b><br>Create a schema validation command</p>

  <h2><a name="SECTid0x555cbefb0160">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="SECTid0x555cbefaa5d0">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="SECTid0x555cbf00a680">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="SECTid0x555cbf0131a0">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="SECTid0x555cbf015030">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">isint</b></dt>
        <dd></dd>
      

      
        <dt>
................................................................................
      
      
        <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="SECTid0x555cbf01d520">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>
            <dd>Any number of keyspaces are possible. A keyspace is
            either active or not. An inside a <i class="m">constraint
            script&gt;</i> called keyspace with the same name does
            nothing.</dd>
        
    </dl><p>This text constraint commands work with keyspaces:</p><dl class="commandlist">
        
            <dt>
<b class="cmd">key</b> <i class="m">name&gt;</i>
</dt>
            <dd>If the keyspace with the name <i class="m">name&gt;</i> is not
            active always matches. If the keyspace is active then
            reports error if there is already a key with the value.
            Otherwise, stores the value as key in this keyspace and
            matches.</dd>
        
        
            <dt>
<b class="cmd">keyref</b> <i class="m">name&gt;</i>
</dt>
            <dd>If the keyspace with the name <i class="m">name&gt;</i> is not
            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="SECTid0x555cbf01f330">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.

428
429
430
431
432
433
434



435
436
437
438
439
440
441
...
560
561
562
563
564
565
566




























567
568
569
570
571
572
573
quantifier must be a tcl list with two elements. Both elements
must be integers, with n >= 0 and n < m.
.PP
If an optional quantifier is not given then it defaults to * in
case of the mixed command and to ! for all other commands.
.SH "Text constraint scripts"
.PP



.PP
The text constraint commands are:
.TP
\&\fB\fBisint\fP
\&\fR
.TP
\&\fB\fBfixed\fP \fIvalue\fB
................................................................................
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
RFC 4648.




























.SH Exampels
.PP
.UR "https://www.w3.org/TR/xmlschema-0/"
<URL: https://www.w3.org/TR/xmlschema-0/>
.UE
The XML Schema Part 0: Primer Second Edition
() starts with this






>
>
>







 







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







428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
...
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
602
603
604
quantifier must be a tcl list with two elements. Both elements
must be integers, with n >= 0 and n < m.
.PP
If an optional quantifier is not given then it defaults to * in
case of the mixed command and to ! for all other commands.
.SH "Text constraint scripts"
.PP
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.
.PP
The text constraint commands are:
.TP
\&\fB\fBisint\fP
\&\fR
.TP
\&\fB\fBfixed\fP \fIvalue\fB
................................................................................
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
RFC 4648.
.SH "Local key constraints"
.PP
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.
.TP
\&\fB\fBkeyspace\fP \fInames list>\fB \fI<constraint script>\fB
\&\fRAny number of keyspaces are possible. A keyspace is
either active or not. An inside a \fIconstraint
script>\fR called keyspace with the same name does
nothing.
.PP
This text constraint commands work with keyspaces:
.TP
\&\fB\fBkey\fP \fIname>\fB
\&\fRIf the keyspace with the name \fIname>\fR is not
active always matches. If the keyspace is active then
reports error if there is already a key with the value.
Otherwise, stores the value as key in this keyspace and
matches.
.TP
\&\fB\fBkeyref\fP \fIname>\fB
\&\fRIf the keyspace with the name \fIname>\fR is not
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 \fIname>\fR. Otherwise it
matches.
.SH Exampels
.PP
.UR "https://www.w3.org/TR/xmlschema-0/"
<URL: https://www.w3.org/TR/xmlschema-0/>
.UE
The XML Schema Part 0: Primer Second Edition
() starts with this

Changes to doc/schema.xml.

367
368
369
370
371
372
373


374
375
376
377
378
379
380
381
...
509
510
511
512
513
514
515
516









































517
518
519
520
521
522
523
...
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
    <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>
  </section>

  <section>
    <title>Text constraint scripts</title>



    <p></p>

    <p>The text constraint commands are:</p>

    <commandlist>
      <commanddef>
        <command><cmd>isint</cmd></command>
        <desc></desc>
................................................................................
      <commanddef>
        <command><cmd>base64</cmd></command>
        <desc>This text constraint match if text is valid according to
        RFC 4648.</desc>
      </commanddef>
    </commandlist>
  </section>
  









































  <section>
    <title>Exampels</title>

    <p>The XML Schema Part 0: Primer Second Edition
    (<url>https://www.w3.org/TR/xmlschema-0/</url>) starts with this
    example schema:</p>

................................................................................
    # Copyright 2000 Example.com. All rights reserved.

    element purchaseOrder {ref PurchaseOrderType}

    element comment {text}

    defpattern PurchaseOrderType {
        element shipTo {ref USAddress}
        element billTo {ref USAddress}
        element comment ?
        element items
        attribute orderDate
    }

    defpattern USAddress {
        element name ! {text}
        element street ! {text}
        element city ! {text}
        element state ! {text}
        element zip ! {text isNumber}
        attribute country ! {text {fixed "US"}}
    }

    defelement items {
        element item * {
            element product ! {text}
            element quntity ! {text {maxExcluse 100}}
            element USPrice ! {text isNumber}
            element comment
            element shipDate ? {text isDate}
            attribute partNum ! {text {pattern "\d{3}-[A-Z]{2}"}}
        }
    }
}
      
    </example>

    <p>The RELAX NG Tutorial






>
>
|







 







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







 







|
|


|








|





|
|

|
|







367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
...
511
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
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
...
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
    <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>
  </section>

  <section>
    <title>Text constraint scripts</title>

    <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>

    <commandlist>
      <commanddef>
        <command><cmd>isint</cmd></command>
        <desc></desc>
................................................................................
      <commanddef>
        <command><cmd>base64</cmd></command>
        <desc>This text constraint match if text is valid according to
        RFC 4648.</desc>
      </commanddef>
    </commandlist>
  </section>

  <section>
    <title>Local key constraints</title>

    <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>

    <commandlist>
        <commanddef>
            <command><cmd>keyspace</cmd> <m>&kt;names list></m> <m>&lt;constraint script></m></command>
            <desc>Any number of keyspaces are possible. A keyspace is
            either active or not. An inside a <m>constraint
            script></m> called keyspace with the same name does
            nothing.</desc>
        </commanddef>
    </commandlist>

    <p>This text constraint commands work with keyspaces:</p>

    <commandlist>
        <commanddef>
            <command><cmd>key</cmd> <m>name></m></command>
            <desc>If the keyspace with the name <m>name></m> is not
            active always matches. If the keyspace is active then
            reports error if there is already a key with the value.
            Otherwise, stores the value as key in this keyspace and
            matches.</desc>
        </commanddef>
        <commanddef>
            <command><cmd>keyref</cmd> <m>name></m></command>
            <desc>If the keyspace with the name <m>name></m> is not
            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 <m>name></m>. Otherwise it
            matches.</desc>
        </commanddef>
    </commandlist>
    
  </section>

  <section>
    <title>Exampels</title>

    <p>The XML Schema Part 0: Primer Second Edition
    (<url>https://www.w3.org/TR/xmlschema-0/</url>) starts with this
    example schema:</p>

................................................................................
    # Copyright 2000 Example.com. All rights reserved.

    element purchaseOrder {ref PurchaseOrderType}

    element comment {text}

    defpattern PurchaseOrderType {
        element shipTo ! {ref USAddress}
        element billTo ! {ref USAddress}
        element comment ?
        element items
        attribute orderDate isodate
    }

    defpattern USAddress {
        element name ! {text}
        element street ! {text}
        element city ! {text}
        element state ! {text}
        element zip ! {text isNumber}
        attribute country ! {fixed "US"}
    }

    defelement items {
        element item * {
            element product ! {text}
            element quantity ! {text {maxExcluse 100}}
            element USPrice ! {text integer}
            element comment
            element shipDate ? {text isodate}
            attribute partNum ! {pattern "\d{3}-[A-Z]{2}"}
        }
    }
}
      
    </example>

    <p>The RELAX NG Tutorial

Changes to generic/schema.c.

293
294
295
296
297
298
299




300
301
302
303
304
305
306
...
310
311
312
313
314
315
316




317
318
319
320
321
322
323
324
325
326
327
...
486
487
488
489
490
491
492

493
494
495
496
497
498
499
500
501
502
503
504
505

506
507
508
509
510
511
512
...
564
565
566
567
568
569
570










571
572
573
574
575
576
577
...
923
924
925
926
927
928
929




930
931
932
933
934
935
936
...
950
951
952
953
954
955
956
957
958




























959
960
961
962
963
964
965
...
976
977
978
979
980
981
982


983
984
985
986
987
988
989
....
1035
1036
1037
1038
1039
1040
1041






1042
1043
1044
1045
1046
1047
1048
....
1465
1466
1467
1468
1469
1470
1471
























1472
1473
1474
1475
1476
1477
1478
....
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515


1516

1517
1518
1519
1520
1521
1522
1523
1524
....
1545
1546
1547
1548
1549
1550
1551


1552
1553
1554
1555
1556
1557
1558
....
1719
1720
1721
1722
1723
1724
1725

1726
1727
1728
1729
1730
1731
1732
....
1757
1758
1759
1760
1761
1762
1763




1764
1765
1766
1767
1768
1769
1770
....
1782
1783
1784
1785
1786
1787
1788
























1789
1790
1791
1792
1793
1794
1795
....
1801
1802
1803
1804
1805
1806
1807


1808
1809
1810
1811
1812
1813
1814
....
1838
1839
1840
1841
1842
1843
1844




1845
1846
1847
1848
1849

1850
1851
1852
1853
1854
1855
1856
....
2421
2422
2423
2424
2425
2426
2427

2428
2429
2430
2431
2432
2433
2434
....
2443
2444
2445
2446
2447
2448
2449













2450
2451
2452
2453
2454
2455
2456
....
3642
3643
3644
3645
3646
3647
3648
3649
3650
3651
3652
3653
3654
3655
3656
3657
3658
3659
3660
....
3668
3669
3670
3671
3672
3673
3674
3675
3676
3677
3678
3679
3680
3681
3682
....
3749
3750
3751
3752
3753
3754
3755

































































3756
3757
3758
3759
3760
3761
3762
....
4939
4940
4941
4942
4943
4944
4945
















































































































4946
4947
4948
4949
4950
4951
4952
....
5038
5039
5040
5041
5042
5043
5044
5045

5046
5047
5048
5049
5050
5051
5052
....
5054
5055
5056
5057
5058
5059
5060




5061
5062
5063
5064
5065
5066
5067
5068
....
5097
5098
5099
5100
5101
5102
5103




5104
5105
5106
5107
        pattern->quants = (SchemaQuant*) MALLOC (
            sizeof (SchemaQuant) * CONTENT_ARRAY_SIZE_INIT
            );
        break;
    case SCHEMA_CTYPE_TEXT:
        /* content/quant will be allocated, if the cp in fact has
         * constraints */




        break;
    case SCHEMA_CTYPE_VIRTUAL:
    case SCHEMA_CTYPE_ANY:
        /* Do nothing */
        break;
    }
    return pattern;
................................................................................
static void serializeCP (
    SchemaCP *pattern
    )
{
    fprintf (stderr, "CP %p type: %s\n",
             pattern, Schema_CP_Type2str[pattern->type]);
    switch (pattern->type) {




    case SCHEMA_CTYPE_NAME:
    case SCHEMA_CTYPE_PATTERN:
        fprintf (stderr, "\tName: '%s' Namespace: '%s'\n",
                 pattern->name,pattern->namespace);
        if (pattern->flags & FORWARD_PATTERN_DEF) {
            fprintf (stderr, "\tAnonymously defined NAME\n");
        }
        if (pattern->flags & PLACEHOLDER_PATTERN_DEF) {
            fprintf (stderr, "\tAs placeholder defined NAME\n");
        }
        if (pattern->flags & LOCAL_DEFINED_ELEMENT) {
................................................................................
    sdata->textStub[2] = Tcl_NewStringObj("::tdom::schema::text", 20);
    Tcl_IncrRefCount (sdata->textStub[2]);
    sdata->cdata = TMALLOC (Tcl_DString);
    Tcl_DStringInit (sdata->cdata);
    Tcl_InitHashTable (&sdata->ids, TCL_STRING_KEYS);
    sdata->unknownIDrefs = 0;
    Tcl_InitHashTable (&sdata->idTables, TCL_STRING_KEYS);

    return sdata;
}

static void schemaInstanceDelete (
    ClientData clientData
    )
{
    SchemaData *sdata = (SchemaData *) clientData;
    unsigned int i;
    SchemaValidationStack *down;
    Tcl_HashEntry *h;
    Tcl_HashSearch search;
    SchemaDocKey *dk;


    /* Protect the clientData to be freed inside (even nested)
     * Tcl_Eval*() calls to avoid invalid mem access and postpone the
     * cleanup until the Tcl_Eval*() calls are finished (done in
     * schemaInstanceCmd(). */
    if (sdata->currentEvals) {
        sdata->cleanupAfterEval = 1;
................................................................................
         h != NULL;
         h = Tcl_NextHashEntry (&search)) {
        dk = Tcl_GetHashValue (h);
        Tcl_DeleteHashTable (&dk->ids);
        FREE (dk);
    }
    Tcl_DeleteHashTable (&sdata->idTables);










    FREE (sdata);
}

static void
cleanupLastPattern (
    SchemaData *sdata,
    unsigned int from
................................................................................
                        popStack (sdata);
                        if (rc == -1) mayskip = 1;
                        break;

                    case SCHEMA_CTYPE_VIRTUAL:
                        Tcl_Panic ("Virtual constrain in MIXED or CHOICE");
                        




                    }
                    if (!mayskip && mayMiss (candidate->quants[i]))
                        mayskip = 1;
                }
                break;

            case SCHEMA_CTYPE_VIRTUAL:
................................................................................
                pushToStack (sdata, candidate);
                rc = matchElementStart (interp, sdata, name, namespace);
                if (rc == 1) {
                    updateStack (se, cp, ac);
                    return 1;
                }
                popStack (sdata);

                break;




























            }
            if (!mayskip && mustMatch (cp->quants[ac], hm)) {
                if (recover (interp, sdata, S("MISSING_CP"))) {
                    /* Skip the just opened element tag and the following
                     * content of the current. */
                    sdata->skipDeep = 2;
                    return 1;
................................................................................
                sdata->skipDeep = 2;
                return 1;
            }
            return 0;
        }
        return -1;



    case SCHEMA_CTYPE_VIRTUAL:
    case SCHEMA_CTYPE_CHOICE:
    case SCHEMA_CTYPE_TEXT:
    case SCHEMA_CTYPE_ANY:
        /* Never pushed onto stack */
        Tcl_Panic ("Invalid CTYPE onto the validation stack!");

................................................................................
                popStack (sdata);
                if (mayskip && rc != -1) mayskip = 0;
                break;

            case SCHEMA_CTYPE_VIRTUAL:
                Tcl_Panic ("Virtual constraint child of INTERLEAVE");
                break;






            }

        }
                
        if (mayskip) break;
        if (recover (interp, sdata, S("UNCOMPLET_CP"))) {
            sdata->skipDeep = 2;
................................................................................
            DBG(fprintf (stderr, "ac %d hm %d mayMiss: %d\n",
                         ac, hm, mayMiss (cp->quants[ac])));
            if (mayMiss (cp->quants[ac])) {
                ac++; continue;
            }
            
            switch (cp->content[ac]->type) {
























            case SCHEMA_CTYPE_TEXT:
                if (cp->content[ac]->nc) {
                    if (!checkText (interp, cp->content[ac], "")) {
                        if (recover (interp, sdata, S("MISSING_TEXT"))) {
                            break;
                        }
                        return 0;
................................................................................
                            if (!checkText (interp, ic, "")) {
                                continue;
                            }
                        }
                        mayMiss = 1;
                        break;

                    case SCHEMA_CTYPE_CHOICE:
                        /* Can't happen */
                    case SCHEMA_CTYPE_NAME:
                    case SCHEMA_CTYPE_ANY:
                        continue;
                        
                    case SCHEMA_CTYPE_INTERLEAVE:
                    case SCHEMA_CTYPE_PATTERN:
                        pushToStack (sdata, ic);
                        if (checkElementEnd (interp, sdata)) {
                            mayMiss = 1;
                        }
                        popStack (sdata);
                        break;
                        


                    case SCHEMA_CTYPE_VIRTUAL:

                        Tcl_Panic ("Virtual constrain in MIXED or CHOICE");
                        
                    }
                    if (mayMiss) break;
                }
                if (mayMiss) break;
                if (!recover (interp, sdata, S("MISSING_ONE_OF_CHOICE"))) {
                    return 0;
................................................................................
                return 0;
            }
            ac++;
        }
        if (isName) return 1;
        return -1;



    case SCHEMA_CTYPE_VIRTUAL:
    case SCHEMA_CTYPE_CHOICE:
    case SCHEMA_CTYPE_TEXT:
    case SCHEMA_CTYPE_ANY:
        /* Never pushed onto stack */
        Tcl_Panic ("Invalid CTYPE onto the validation stack!");
        return 0;
................................................................................
                    if (checkText (interp, candidate, text)) {
                        updateStack (se, cp, ac);
                        return 1;
                    }
                    if (!sdata->evalError) {
                        SetResult ("Invalid text content");
                    }

                    return 0;

                case SCHEMA_CTYPE_CHOICE:
                    if (candidate->flags & MIXED_CONTENT) {
                        updateStack (se, cp, ac);
                        return 1;
                    }
................................................................................
                        case SCHEMA_CTYPE_VIRTUAL:
                            if (!evalVirtual (interp, sdata, ic)) return 0;
                            break;
                            
                        case SCHEMA_CTYPE_CHOICE:
                            Tcl_Panic ("MIXED or CHOICE child of MIXED or CHOICE");





                        }
                    }
                    if (mustMatch (cp->quants[ac], hm)) {
                        SetResult ("Unexpected text content");
                        return 0;
                    }
                    break;
................................................................................
                        return 0;
                    }
                    break;

                case SCHEMA_CTYPE_VIRTUAL:
                    if (!evalVirtual (interp, sdata, candidate)) return 0;
                    break;
























                    
                case SCHEMA_CTYPE_NAME:
                case SCHEMA_CTYPE_ANY:
                    if (mustMatch (cp->quants[ac], hm)) {
                        SetResult ("Unexpected text content");
                        return 0;
                    }
................................................................................
            if (isName) {
                SetResult ("Unexpected text content");
                return 0;
            }
            popStack (sdata);
            continue;



        case SCHEMA_CTYPE_VIRTUAL:
        case SCHEMA_CTYPE_CHOICE:
        case SCHEMA_CTYPE_TEXT:
        case SCHEMA_CTYPE_ANY:
            /* Never pushed onto stack */
            Tcl_Panic ("Invalid CTYPE onto the validation stack!");
            break;
................................................................................
                    }
                    popStack (sdata);
                    break;

                case SCHEMA_CTYPE_CHOICE:
                    Tcl_Panic ("MIXED or CHOICE child of INTERLEAVE");





                case SCHEMA_CTYPE_VIRTUAL:
                    break;
                    
                }
            }

        }
        break;
    }
    return 0;
}

int
................................................................................
schemaReset (
    SchemaData *sdata
    )
{
    Tcl_HashEntry *h;
    Tcl_HashSearch search;
    SchemaDocKey *dk;

    
    while (sdata->stack) popStack (sdata);
    sdata->validationState = VALIDATION_READY;
    sdata->skipDeep = 0;
    sdata->evalError = 0;
    Tcl_DStringSetLength (sdata->cdata, 0);
    if (sdata->ids.numEntries) {
................................................................................
            dk = Tcl_GetHashValue (h);
            if (&dk->ids.numEntries) {
                Tcl_DeleteHashTable (&dk->ids);
                Tcl_InitHashTable (&dk->ids, TCL_STRING_KEYS);
                dk->unknownIDrefs = 0;
            }
        }













    }
}

static int
evalConstraints (
    Tcl_Interp *interp,
    SchemaData *sdata,
................................................................................
    CHECK_SI
    CHECK_TOPLEVEL
    if (objc < 2) {
        SetResult ("Expected: <tclcmd> ?arg? ?arg? ...");
        return TCL_ERROR;
    }

    switch (sdata->cp->type) {
    case SCHEMA_CTYPE_NAME:
    case SCHEMA_CTYPE_PATTERN:
        break;
    default:
        SetResult ("The \"tcl\" schema definition command is only "
                   "allowed in sequential context (defelement, "
                   "element or defpattern)");
        return TCL_ERROR;
    }

    pattern = initSchemaCP (SCHEMA_CTYPE_VIRTUAL, NULL, NULL);
................................................................................
    }
    pattern->nc = objc;
    addToContent (sdata, pattern, SCHEMA_CQUANT_ONE, 0, 0);
    return TCL_OK;
}

static int
domuniquePatternCmd (
    ClientData clientData,
    Tcl_Interp *interp,
    int objc,
    Tcl_Obj *const objv[]
    )
{
    SchemaData *sdata = GETASI;
................................................................................
    if (objc == 4) {
        kc->name = tdomstrdup (Tcl_GetString (objv[3]));
    }
    kc->next = sdata->cp->domKeys;
    sdata->cp->domKeys = kc;
    return TCL_OK;
}


































































static int
integerImpl (
    Tcl_Interp *interp,
    void *constraintData,
    char *text
    )
................................................................................
            dk = Tcl_GetHashValue (h);
        }
        sc->constraint = docidrefImpl;
        sc->constraintData = (void *)dk;
    }
    return TCL_OK;
}

















































































































static int
base64Impl (
    Tcl_Interp *interp,
    void *constraintData,
    char *text
    )
................................................................................
    Tcl_CreateObjCommand (interp, "tdom::schema::mixed",
                          AnonPatternObjCmd, (ClientData) 1, NULL);
    Tcl_CreateObjCommand (interp, "tdom::schema::interleave",
                          AnonPatternObjCmd, (ClientData) 2, NULL);
    Tcl_CreateObjCommand (interp, "tdom::schema::group",
                          AnonPatternObjCmd, (ClientData) 3, NULL);

    /* The "attribute", "nsattribute", "namespace" and "text" definition commands. */

    Tcl_CreateObjCommand (interp, "tdom::schema::attribute",
                          AttributePatternObjCmd, NULL, NULL);
    Tcl_CreateObjCommand (interp, "tdom::schema::nsattribute",
                          AttributePatternObjCmd, (ClientData) 1, NULL);
    Tcl_CreateObjCommand (interp, "tdom::schema::namespace",
                          NamespacePatternObjCmd, NULL, NULL);
    Tcl_CreateObjCommand (interp, "tdom::schema::text",
................................................................................

    /* The 'virtual' "tcl" definition command */
    Tcl_CreateObjCommand (interp, "tdom::schema::tcl",
                          VirtualPatternObjCmd, NULL, NULL);

    /* XPath contraints for DOM validation */
    Tcl_CreateObjCommand (interp,"tdom::schema::domunique",




                          domuniquePatternCmd, NULL, NULL);
    
    /* The text constraint commands */
    Tcl_CreateObjCommand (interp,"tdom::schema::text::integer",
                          integerTCObjCmd, NULL, NULL);
    Tcl_CreateObjCommand (interp, "tdom::schema::text::tcl",
                          tclTCObjCmd, NULL, NULL);
    Tcl_CreateObjCommand (interp, "tdom::schema::text::fixed",
................................................................................
                          splitTCObjCmd, NULL, NULL);
    Tcl_CreateObjCommand (interp,"tdom::schema::text::id",
                          idTCObjCmd, NULL, NULL);
    Tcl_CreateObjCommand (interp,"tdom::schema::text::idref",
                          idrefTCObjCmd, NULL, NULL);
    Tcl_CreateObjCommand (interp,"tdom::schema::text::base64",
                          base64TCObjCmd, NULL, NULL);




}


#endif  /* #ifndef TDOM_NO_SCHEMA */






>
>
>
>







 







>
>
>
>



|







 







>













>







 







>
>
>
>
>
>
>
>
>
>







 







>
>
>
>







 







<

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







 







>
>







 







>
>
>
>
>
>







 







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







 







<
<













>
>

>
|







 







>
>







 







>







 







>
>
>
>







 







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







 







>
>







 







>
>
>
>





>







 







>







 







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







 







<
|
|
<
<







 







|







 







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







 







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







 







|
>







 







>
>
>
>
|







 







>
>
>
>




293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
...
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
...
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
...
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
...
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
...
974
975
976
977
978
979
980

981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
....
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
....
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
....
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
....
1577
1578
1579
1580
1581
1582
1583


1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
....
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
....
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
....
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
....
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
....
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
....
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
....
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
....
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
....
3778
3779
3780
3781
3782
3783
3784

3785
3786


3787
3788
3789
3790
3791
3792
3793
....
3801
3802
3803
3804
3805
3806
3807
3808
3809
3810
3811
3812
3813
3814
3815
....
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915
3916
3917
3918
3919
3920
3921
3922
3923
3924
3925
3926
3927
3928
3929
3930
3931
3932
3933
3934
3935
3936
3937
3938
3939
3940
3941
3942
3943
3944
3945
3946
3947
3948
3949
3950
3951
3952
3953
3954
3955
3956
3957
3958
3959
3960
....
5137
5138
5139
5140
5141
5142
5143
5144
5145
5146
5147
5148
5149
5150
5151
5152
5153
5154
5155
5156
5157
5158
5159
5160
5161
5162
5163
5164
5165
5166
5167
5168
5169
5170
5171
5172
5173
5174
5175
5176
5177
5178
5179
5180
5181
5182
5183
5184
5185
5186
5187
5188
5189
5190
5191
5192
5193
5194
5195
5196
5197
5198
5199
5200
5201
5202
5203
5204
5205
5206
5207
5208
5209
5210
5211
5212
5213
5214
5215
5216
5217
5218
5219
5220
5221
5222
5223
5224
5225
5226
5227
5228
5229
5230
5231
5232
5233
5234
5235
5236
5237
5238
5239
5240
5241
5242
5243
5244
5245
5246
5247
5248
5249
5250
5251
5252
5253
5254
5255
5256
5257
5258
5259
5260
5261
5262
....
5348
5349
5350
5351
5352
5353
5354
5355
5356
5357
5358
5359
5360
5361
5362
5363
....
5365
5366
5367
5368
5369
5370
5371
5372
5373
5374
5375
5376
5377
5378
5379
5380
5381
5382
5383
....
5412
5413
5414
5415
5416
5417
5418
5419
5420
5421
5422
5423
5424
5425
5426
        pattern->quants = (SchemaQuant*) MALLOC (
            sizeof (SchemaQuant) * CONTENT_ARRAY_SIZE_INIT
            );
        break;
    case SCHEMA_CTYPE_TEXT:
        /* content/quant will be allocated, if the cp in fact has
         * constraints */
        break;
    case SCHEMA_CTYPE_KEYSPACE_END:
    case SCHEMA_CTYPE_KEYSPACE:
        pattern->name = name;
        break;
    case SCHEMA_CTYPE_VIRTUAL:
    case SCHEMA_CTYPE_ANY:
        /* Do nothing */
        break;
    }
    return pattern;
................................................................................
static void serializeCP (
    SchemaCP *pattern
    )
{
    fprintf (stderr, "CP %p type: %s\n",
             pattern, Schema_CP_Type2str[pattern->type]);
    switch (pattern->type) {
    case SCHEMA_CTYPE_KEYSPACE_END:
    case SCHEMA_CTYPE_KEYSPACE:
        fprintf (stderr, "\tName: '%s'\n", pattern->name);
        break;
    case SCHEMA_CTYPE_NAME:
    case SCHEMA_CTYPE_PATTERN:
        fprintf (stderr, "\tName: '%s' Namespace: '%s'\n",
                 pattern->name, pattern->namespace);
        if (pattern->flags & FORWARD_PATTERN_DEF) {
            fprintf (stderr, "\tAnonymously defined NAME\n");
        }
        if (pattern->flags & PLACEHOLDER_PATTERN_DEF) {
            fprintf (stderr, "\tAs placeholder defined NAME\n");
        }
        if (pattern->flags & LOCAL_DEFINED_ELEMENT) {
................................................................................
    sdata->textStub[2] = Tcl_NewStringObj("::tdom::schema::text", 20);
    Tcl_IncrRefCount (sdata->textStub[2]);
    sdata->cdata = TMALLOC (Tcl_DString);
    Tcl_DStringInit (sdata->cdata);
    Tcl_InitHashTable (&sdata->ids, TCL_STRING_KEYS);
    sdata->unknownIDrefs = 0;
    Tcl_InitHashTable (&sdata->idTables, TCL_STRING_KEYS);
    Tcl_InitHashTable (&sdata->keySpaces, TCL_STRING_KEYS);
    return sdata;
}

static void schemaInstanceDelete (
    ClientData clientData
    )
{
    SchemaData *sdata = (SchemaData *) clientData;
    unsigned int i;
    SchemaValidationStack *down;
    Tcl_HashEntry *h;
    Tcl_HashSearch search;
    SchemaDocKey *dk;
    SchemaKeySpace *ks;

    /* Protect the clientData to be freed inside (even nested)
     * Tcl_Eval*() calls to avoid invalid mem access and postpone the
     * cleanup until the Tcl_Eval*() calls are finished (done in
     * schemaInstanceCmd(). */
    if (sdata->currentEvals) {
        sdata->cleanupAfterEval = 1;
................................................................................
         h != NULL;
         h = Tcl_NextHashEntry (&search)) {
        dk = Tcl_GetHashValue (h);
        Tcl_DeleteHashTable (&dk->ids);
        FREE (dk);
    }
    Tcl_DeleteHashTable (&sdata->idTables);
    for (h = Tcl_FirstHashEntry (&sdata->keySpaces, &search);
         h != NULL;
         h = Tcl_NextHashEntry (&search)) {
        ks = Tcl_GetHashValue (h);
        if (ks->active) {
            Tcl_DeleteHashTable (&ks->ids);
        }
        FREE (ks);
    }
    Tcl_DeleteHashTable (&sdata->keySpaces);
    FREE (sdata);
}

static void
cleanupLastPattern (
    SchemaData *sdata,
    unsigned int from
................................................................................
                        popStack (sdata);
                        if (rc == -1) mayskip = 1;
                        break;

                    case SCHEMA_CTYPE_VIRTUAL:
                        Tcl_Panic ("Virtual constrain in MIXED or CHOICE");
                        
                    case SCHEMA_CTYPE_KEYSPACE_END:
                    case SCHEMA_CTYPE_KEYSPACE:
                        Tcl_Panic ("Keyspace constrain in MIXED or CHOICE");
                        
                    }
                    if (!mayskip && mayMiss (candidate->quants[i]))
                        mayskip = 1;
                }
                break;

            case SCHEMA_CTYPE_VIRTUAL:
................................................................................
                pushToStack (sdata, candidate);
                rc = matchElementStart (interp, sdata, name, namespace);
                if (rc == 1) {
                    updateStack (se, cp, ac);
                    return 1;
                }
                popStack (sdata);

                break;

            case SCHEMA_CTYPE_KEYSPACE_END:
                candidate->keySpace->active--;
                if (!candidate->keySpace->active) {
                    if (candidate->keySpace->unknownIDrefs) {
                        if (!recover (interp, sdata, S("UNKNOWN_KEYREF"))) {
                            return 0;
                        }
                        candidate->keySpace->unknownIDrefs = 0;
                    }
                    Tcl_DeleteHashTable (&candidate->keySpace->ids);
                }
                ac++;
                hm = 0;
                continue;

            case SCHEMA_CTYPE_KEYSPACE:
                if (!candidate->keySpace->active) {
                    Tcl_InitHashTable (&candidate->keySpace->ids,
                                       TCL_STRING_KEYS);
                    candidate->keySpace->active = 1;
                    candidate->keySpace->unknownIDrefs = 0;
                } else {
                    candidate->keySpace->active++;
                }
                ac++;
                hm = 0;
                continue;
            }
            if (!mayskip && mustMatch (cp->quants[ac], hm)) {
                if (recover (interp, sdata, S("MISSING_CP"))) {
                    /* Skip the just opened element tag and the following
                     * content of the current. */
                    sdata->skipDeep = 2;
                    return 1;
................................................................................
                sdata->skipDeep = 2;
                return 1;
            }
            return 0;
        }
        return -1;

    case SCHEMA_CTYPE_KEYSPACE:
    case SCHEMA_CTYPE_KEYSPACE_END:
    case SCHEMA_CTYPE_VIRTUAL:
    case SCHEMA_CTYPE_CHOICE:
    case SCHEMA_CTYPE_TEXT:
    case SCHEMA_CTYPE_ANY:
        /* Never pushed onto stack */
        Tcl_Panic ("Invalid CTYPE onto the validation stack!");

................................................................................
                popStack (sdata);
                if (mayskip && rc != -1) mayskip = 0;
                break;

            case SCHEMA_CTYPE_VIRTUAL:
                Tcl_Panic ("Virtual constraint child of INTERLEAVE");
                break;

            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;
................................................................................
            DBG(fprintf (stderr, "ac %d hm %d mayMiss: %d\n",
                         ac, hm, mayMiss (cp->quants[ac])));
            if (mayMiss (cp->quants[ac])) {
                ac++; continue;
            }
            
            switch (cp->content[ac]->type) {
            case SCHEMA_CTYPE_KEYSPACE_END:
                cp->content[ac]->keySpace->active--;
                if (!cp->content[ac]->keySpace->active) {
                    if (cp->content[ac]->keySpace->unknownIDrefs) {
                        if (!recover (interp, sdata, S("UNKNOWN_KEYREF"))) {
                            return 0;
                        }
                        cp->content[ac]->keySpace->unknownIDrefs = 0;
                    }
                    Tcl_DeleteHashTable (&cp->content[ac]->keySpace->ids);
                }
                break;

            case SCHEMA_CTYPE_KEYSPACE:
                if (!cp->content[ac]->keySpace->active) {
                    Tcl_InitHashTable (&cp->content[ac]->keySpace->ids,
                                       TCL_STRING_KEYS);
                    cp->content[ac]->keySpace->active = 1;
                    cp->content[ac]->keySpace->unknownIDrefs = 0;
                } else {
                    cp->content[ac]->keySpace->active++;
                }
                break;
                
            case SCHEMA_CTYPE_TEXT:
                if (cp->content[ac]->nc) {
                    if (!checkText (interp, cp->content[ac], "")) {
                        if (recover (interp, sdata, S("MISSING_TEXT"))) {
                            break;
                        }
                        return 0;
................................................................................
                            if (!checkText (interp, ic, "")) {
                                continue;
                            }
                        }
                        mayMiss = 1;
                        break;



                    case SCHEMA_CTYPE_NAME:
                    case SCHEMA_CTYPE_ANY:
                        continue;
                        
                    case SCHEMA_CTYPE_INTERLEAVE:
                    case SCHEMA_CTYPE_PATTERN:
                        pushToStack (sdata, ic);
                        if (checkElementEnd (interp, sdata)) {
                            mayMiss = 1;
                        }
                        popStack (sdata);
                        break;
                        
                    case SCHEMA_CTYPE_KEYSPACE_END:
                    case SCHEMA_CTYPE_KEYSPACE:
                    case SCHEMA_CTYPE_VIRTUAL:
                    case SCHEMA_CTYPE_CHOICE:
                        Tcl_Panic ("Invalid CTYPE in MIXED or CHOICE");
                        
                    }
                    if (mayMiss) break;
                }
                if (mayMiss) break;
                if (!recover (interp, sdata, S("MISSING_ONE_OF_CHOICE"))) {
                    return 0;
................................................................................
                return 0;
            }
            ac++;
        }
        if (isName) return 1;
        return -1;

    case SCHEMA_CTYPE_KEYSPACE_END:
    case SCHEMA_CTYPE_KEYSPACE:
    case SCHEMA_CTYPE_VIRTUAL:
    case SCHEMA_CTYPE_CHOICE:
    case SCHEMA_CTYPE_TEXT:
    case SCHEMA_CTYPE_ANY:
        /* Never pushed onto stack */
        Tcl_Panic ("Invalid CTYPE onto the validation stack!");
        return 0;
................................................................................
                    if (checkText (interp, candidate, text)) {
                        updateStack (se, cp, ac);
                        return 1;
                    }
                    if (!sdata->evalError) {
                        SetResult ("Invalid text content");
                    }
                    updateStack (se, cp, ac);
                    return 0;

                case SCHEMA_CTYPE_CHOICE:
                    if (candidate->flags & MIXED_CONTENT) {
                        updateStack (se, cp, ac);
                        return 1;
                    }
................................................................................
                        case SCHEMA_CTYPE_VIRTUAL:
                            if (!evalVirtual (interp, sdata, ic)) return 0;
                            break;
                            
                        case SCHEMA_CTYPE_CHOICE:
                            Tcl_Panic ("MIXED or CHOICE child of MIXED or CHOICE");

                        case SCHEMA_CTYPE_KEYSPACE_END:
                        case SCHEMA_CTYPE_KEYSPACE:
                            Tcl_Panic ("Keyspace constrain in MIXED or CHOICE");
                            
                        }
                    }
                    if (mustMatch (cp->quants[ac], hm)) {
                        SetResult ("Unexpected text content");
                        return 0;
                    }
                    break;
................................................................................
                        return 0;
                    }
                    break;

                case SCHEMA_CTYPE_VIRTUAL:
                    if (!evalVirtual (interp, sdata, candidate)) return 0;
                    break;

                case SCHEMA_CTYPE_KEYSPACE:
                    if (!cp->content[ac]->keySpace->active) {
                        Tcl_InitHashTable (&cp->content[ac]->keySpace->ids,
                                           TCL_STRING_KEYS);
                        cp->content[ac]->keySpace->active = 1;
                        cp->content[ac]->keySpace->unknownIDrefs = 0;
                    } else {
                        cp->content[ac]->keySpace->active++;
                    }
                    break;
                    
                case SCHEMA_CTYPE_KEYSPACE_END:
                    cp->content[ac]->keySpace->active--;
                    if (!cp->content[ac]->keySpace->active) {
                        if (cp->content[ac]->keySpace->unknownIDrefs) {
                            if (!recover (interp, sdata, S("UNKNOWN_KEYREF"))) {
                                return 0;
                            }
                            cp->content[ac]->keySpace->unknownIDrefs = 0;
                        }
                        Tcl_DeleteHashTable (&cp->content[ac]->keySpace->ids);
                    }
                    break;
                    
                case SCHEMA_CTYPE_NAME:
                case SCHEMA_CTYPE_ANY:
                    if (mustMatch (cp->quants[ac], hm)) {
                        SetResult ("Unexpected text content");
                        return 0;
                    }
................................................................................
            if (isName) {
                SetResult ("Unexpected text content");
                return 0;
            }
            popStack (sdata);
            continue;

        case SCHEMA_CTYPE_KEYSPACE:
        case SCHEMA_CTYPE_KEYSPACE_END:
        case SCHEMA_CTYPE_VIRTUAL:
        case SCHEMA_CTYPE_CHOICE:
        case SCHEMA_CTYPE_TEXT:
        case SCHEMA_CTYPE_ANY:
            /* Never pushed onto stack */
            Tcl_Panic ("Invalid CTYPE onto the validation stack!");
            break;
................................................................................
                    }
                    popStack (sdata);
                    break;

                case SCHEMA_CTYPE_CHOICE:
                    Tcl_Panic ("MIXED or CHOICE child of INTERLEAVE");

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

                case SCHEMA_CTYPE_VIRTUAL:
                    break;
                    
                }
            }
            break;
        }
        break;
    }
    return 0;
}

int
................................................................................
schemaReset (
    SchemaData *sdata
    )
{
    Tcl_HashEntry *h;
    Tcl_HashSearch search;
    SchemaDocKey *dk;
    SchemaKeySpace *ks;
    
    while (sdata->stack) popStack (sdata);
    sdata->validationState = VALIDATION_READY;
    sdata->skipDeep = 0;
    sdata->evalError = 0;
    Tcl_DStringSetLength (sdata->cdata, 0);
    if (sdata->ids.numEntries) {
................................................................................
            dk = Tcl_GetHashValue (h);
            if (&dk->ids.numEntries) {
                Tcl_DeleteHashTable (&dk->ids);
                Tcl_InitHashTable (&dk->ids, TCL_STRING_KEYS);
                dk->unknownIDrefs = 0;
            }
        }
    }
    if (sdata->keySpaces.numEntries) {
        for (h = Tcl_FirstHashEntry (&sdata->keySpaces, &search);
             h != NULL;
             h = Tcl_NextHashEntry (&search)) {
            ks = Tcl_GetHashValue (h);
            if (ks->active && ks->ids.numEntries) {
                Tcl_DeleteHashTable (&ks->ids);
                Tcl_InitHashTable (&ks->ids, TCL_STRING_KEYS);
            }
            ks->unknownIDrefs = 0;
            ks->active = 0;
        }
    }
}

static int
evalConstraints (
    Tcl_Interp *interp,
    SchemaData *sdata,
................................................................................
    CHECK_SI
    CHECK_TOPLEVEL
    if (objc < 2) {
        SetResult ("Expected: <tclcmd> ?arg? ?arg? ...");
        return TCL_ERROR;
    }


    if (sdata->cp->type != SCHEMA_CTYPE_NAME
        && sdata->cp->type != SCHEMA_CTYPE_PATTERN) {


        SetResult ("The \"tcl\" schema definition command is only "
                   "allowed in sequential context (defelement, "
                   "element or defpattern)");
        return TCL_ERROR;
    }

    pattern = initSchemaCP (SCHEMA_CTYPE_VIRTUAL, NULL, NULL);
................................................................................
    }
    pattern->nc = objc;
    addToContent (sdata, pattern, SCHEMA_CQUANT_ONE, 0, 0);
    return TCL_OK;
}

static int
domuniquePatternObjCmd (
    ClientData clientData,
    Tcl_Interp *interp,
    int objc,
    Tcl_Obj *const objv[]
    )
{
    SchemaData *sdata = GETASI;
................................................................................
    if (objc == 4) {
        kc->name = tdomstrdup (Tcl_GetString (objv[3]));
    }
    kc->next = sdata->cp->domKeys;
    sdata->cp->domKeys = kc;
    return TCL_OK;
}

static int
keyspacePatternObjCmd (
    ClientData clientData,
    Tcl_Interp *interp,
    int objc,
    Tcl_Obj *const objv[]
    )
{
    SchemaData *sdata = GETASI;
    SchemaCP *pattern;
    int nrKeyspaces, i, hnew;
    Tcl_Obj *ksObj;
    SchemaKeySpace *ks;
    Tcl_HashEntry *h;
    
    CHECK_SI
    CHECK_TOPLEVEL
    checkNrArgs (3, 3, "Expected: <keyspace-name list> pattern");
    if (sdata->cp->type != SCHEMA_CTYPE_NAME
        && sdata->cp->type != SCHEMA_CTYPE_PATTERN) {
        SetResult ("The keyspace schema definition command is only "
                   "allowed in sequential context (defelement, "
                   "element or defpattern)");
        return TCL_ERROR;
    }
    if (Tcl_ListObjLength (interp, objv[1], &nrKeyspaces) != TCL_OK) {
        SetResult ("The <keyspace-name list> argument must be a valid tcl "
                   "list");
        return TCL_ERROR;
    }
    for (i = 0; i < nrKeyspaces; i++) {
        Tcl_ListObjIndex (interp, objv[1], i, &ksObj);
        h = Tcl_CreateHashEntry (&sdata->keySpaces,
                                 Tcl_GetString (ksObj), &hnew);
        if (hnew) {
            ks = TMALLOC (SchemaKeySpace);
            ks->active = 0;
            ks->unknownIDrefs = 0;
            Tcl_SetHashValue (h, ks);
        } else {
            ks = Tcl_GetHashValue (h);
        }
        pattern = initSchemaCP (SCHEMA_CTYPE_KEYSPACE,
                                Tcl_GetString (ksObj), NULL);
        pattern->keySpace = ks;
        REMEMBER_PATTERN (pattern);
        addToContent (sdata, pattern, SCHEMA_CQUANT_ONE, 0, 0);
    }
    sdata->currentEvals++;
    if (Tcl_EvalObjEx (interp, objv[2], TCL_EVAL_DIRECT) != TCL_OK) {
        return TCL_ERROR;
    }
    sdata->currentEvals--;
    for (i = 0; i < nrKeyspaces; i++) {
        Tcl_ListObjIndex (interp, objv[1], i, &ksObj);
        h = Tcl_FindHashEntry (&sdata->keySpaces, Tcl_GetString(ksObj));
        pattern = initSchemaCP (SCHEMA_CTYPE_KEYSPACE_END,
                                Tcl_GetString (ksObj), NULL);
        REMEMBER_PATTERN (pattern);
        pattern->keySpace = Tcl_GetHashValue (h);
        addToContent (sdata, pattern, SCHEMA_CQUANT_ONE, 0, 0);
    }
    return TCL_OK;
}

static int
integerImpl (
    Tcl_Interp *interp,
    void *constraintData,
    char *text
    )
................................................................................
            dk = Tcl_GetHashValue (h);
        }
        sc->constraint = docidrefImpl;
        sc->constraintData = (void *)dk;
    }
    return TCL_OK;
}

static int
keyImpl (
    Tcl_Interp *interp,
    void *constraintData,
    char *text
    )
{
    SchemaKeySpace *ks = (SchemaKeySpace *) constraintData;
    int hnew;
    Tcl_HashEntry *h;

    if (!ks->active) return 1;
    h = Tcl_CreateHashEntry (&ks->ids, text, &hnew);
    if (hnew) {
        Tcl_SetHashValue (h, 1);
        return 1;
    }
    if (Tcl_GetHashValue (h) == 0) {
        Tcl_SetHashValue (h, 1);
        ks->unknownIDrefs--;
        return 1;
    } else {
        /* Duplicate ID value */
        return 0;
    }
}

static int
keyTCObjCmd (
    ClientData clientData,
    Tcl_Interp *interp,
    int objc,
    Tcl_Obj *const objv[]
    )
{
    SchemaData *sdata = GETASI;
    SchemaConstraint *sc;
    Tcl_HashEntry *h;
    int hnew;
    SchemaKeySpace *ks;

    CHECK_TI
    CHECK_TOPLEVEL
    checkNrArgs (2,2,"key_space");
    ADD_CONSTRAINT (sdata, sc)
    h = Tcl_CreateHashEntry (&sdata->keySpaces, Tcl_GetString (objv[1]), &hnew);
    if (hnew) {
        ks = TMALLOC (SchemaKeySpace);
        ks->active = 0;
        ks->unknownIDrefs = 0;
        Tcl_SetHashValue (h, ks);
    } else {
        ks = Tcl_GetHashValue (h);
    }
    sc->constraint = keyImpl;
    sc->constraintData = (void *) ks;
    return TCL_OK;
}

static int
keyrefImpl (
    Tcl_Interp *interp,
    void *constraintData,
    char *text
    )
{
    SchemaKeySpace *ks = (SchemaKeySpace *) constraintData;
    int hnew;
    Tcl_HashEntry *h;

    if (!ks->active) return 1;
    h = Tcl_CreateHashEntry (&ks->ids, text, &hnew);
    if (hnew) {
        Tcl_SetHashValue (h, 0);
        ks->unknownIDrefs++;
    }
    return 1;
}

static int
keyrefTCObjCmd (
    ClientData clientData,
    Tcl_Interp *interp,
    int objc,
    Tcl_Obj *const objv[]
    )
{
    SchemaData *sdata = GETASI;
    SchemaConstraint *sc;
    Tcl_HashEntry *h;
    int hnew;
    SchemaKeySpace *ks;

    CHECK_TI
    CHECK_TOPLEVEL
    checkNrArgs (2,2,"key_space");
    ADD_CONSTRAINT (sdata, sc)
    h = Tcl_CreateHashEntry (&sdata->keySpaces, Tcl_GetString (objv[1]),
                             &hnew);
    if (hnew) {
        ks = TMALLOC (SchemaKeySpace);
        Tcl_InitHashTable (&ks->ids, TCL_STRING_KEYS);
        ks->unknownIDrefs = 0;
        Tcl_SetHashValue (h, ks);
    } else {
        ks = Tcl_GetHashValue (h);
    }
    sc->constraint = keyrefImpl;
    sc->constraintData = (void *)ks;
    return TCL_OK;
}

static int
base64Impl (
    Tcl_Interp *interp,
    void *constraintData,
    char *text
    )
................................................................................
    Tcl_CreateObjCommand (interp, "tdom::schema::mixed",
                          AnonPatternObjCmd, (ClientData) 1, NULL);
    Tcl_CreateObjCommand (interp, "tdom::schema::interleave",
                          AnonPatternObjCmd, (ClientData) 2, NULL);
    Tcl_CreateObjCommand (interp, "tdom::schema::group",
                          AnonPatternObjCmd, (ClientData) 3, NULL);

    /* The "attribute", "nsattribute", "namespace" and "text"
     * definition commands. */
    Tcl_CreateObjCommand (interp, "tdom::schema::attribute",
                          AttributePatternObjCmd, NULL, NULL);
    Tcl_CreateObjCommand (interp, "tdom::schema::nsattribute",
                          AttributePatternObjCmd, (ClientData) 1, NULL);
    Tcl_CreateObjCommand (interp, "tdom::schema::namespace",
                          NamespacePatternObjCmd, NULL, NULL);
    Tcl_CreateObjCommand (interp, "tdom::schema::text",
................................................................................

    /* The 'virtual' "tcl" definition command */
    Tcl_CreateObjCommand (interp, "tdom::schema::tcl",
                          VirtualPatternObjCmd, NULL, NULL);

    /* XPath contraints for DOM validation */
    Tcl_CreateObjCommand (interp,"tdom::schema::domunique",
                          domuniquePatternObjCmd, NULL, NULL);

    /* Local key constraints */
    Tcl_CreateObjCommand (interp, "tdom::schema::keyspace",
                          keyspacePatternObjCmd, NULL, NULL);
    
    /* The text constraint commands */
    Tcl_CreateObjCommand (interp,"tdom::schema::text::integer",
                          integerTCObjCmd, NULL, NULL);
    Tcl_CreateObjCommand (interp, "tdom::schema::text::tcl",
                          tclTCObjCmd, NULL, NULL);
    Tcl_CreateObjCommand (interp, "tdom::schema::text::fixed",
................................................................................
                          splitTCObjCmd, NULL, NULL);
    Tcl_CreateObjCommand (interp,"tdom::schema::text::id",
                          idTCObjCmd, NULL, NULL);
    Tcl_CreateObjCommand (interp,"tdom::schema::text::idref",
                          idrefTCObjCmd, NULL, NULL);
    Tcl_CreateObjCommand (interp,"tdom::schema::text::base64",
                          base64TCObjCmd, NULL, NULL);
    Tcl_CreateObjCommand (interp,"tdom::schema::text::key",
                          keyTCObjCmd, NULL, NULL);
    Tcl_CreateObjCommand (interp,"tdom::schema::text::keyref",
                          keyrefTCObjCmd, NULL, NULL);
}


#endif  /* #ifndef TDOM_NO_SCHEMA */

Changes to generic/schema.h.

30
31
32
33
34
35
36
37


38
39
40
41
42
43
44
..
80
81
82
83
84
85
86







87
88
89
90
91
92
93
..
94
95
96
97
98
99
100

101
102
103
104
105
106
107
...
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
...
163
164
165
166
167
168
169

170
171
172
173
174
175
176
typedef enum {
  SCHEMA_CTYPE_ANY,
  SCHEMA_CTYPE_NAME,
  SCHEMA_CTYPE_CHOICE,
  SCHEMA_CTYPE_INTERLEAVE,
  SCHEMA_CTYPE_PATTERN,
  SCHEMA_CTYPE_TEXT,
  SCHEMA_CTYPE_VIRTUAL


} Schema_CP_Type;

typedef enum {
  SCHEMA_CQUANT_ONE,
  SCHEMA_CQUANT_OPT,
  SCHEMA_CQUANT_REP,
  SCHEMA_CQUANT_PLUS,
................................................................................
    ast    selector;
    ast   *fields;
    int    nrFields;
    int    flags;
    struct domKeyConstraint *next;
} domKeyConstraint;








typedef struct SchemaCP
{
    Schema_CP_Type    type;
    char             *namespace;
    char             *name;
    struct SchemaCP  *next;
    SchemaFlags       flags;
................................................................................
    struct SchemaCP **content;
    SchemaQuant      *quants;
    unsigned int      nc;
    SchemaAttr      **attrs;
    unsigned int      numAttr;
    unsigned int      numReqAttr;
    domKeyConstraint *domKeys;

} SchemaCP;

typedef struct SchemaValidationStack
{
    SchemaCP *pattern;
    struct SchemaValidationStack *next;
    struct SchemaValidationStack *down;
................................................................................
} ValidationState;

typedef struct 
{
    Tcl_HashTable ids;
    int unknownIDrefs;
} SchemaDocKey;
    
typedef struct SchemaData_
{
    Tcl_Obj *self;
    char *start;
    char *startNamespace;
    Tcl_HashTable element;
    Tcl_HashTable namespace;
................................................................................
    SchemaValidationStack *stackPool;
    ValidationState validationState;
    unsigned int skipDeep;
    Tcl_DString *cdata;
    Tcl_HashTable ids;
    int unknownIDrefs;
    Tcl_HashTable idTables;

} SchemaData;

int 
schemaInstanceCmd (
    ClientData clientData,
    Tcl_Interp *interp,
    int objc,






|
>
>







 







>
>
>
>
>
>
>







 







>







 







|







 







>







30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
..
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
...
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
...
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
...
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
typedef enum {
  SCHEMA_CTYPE_ANY,
  SCHEMA_CTYPE_NAME,
  SCHEMA_CTYPE_CHOICE,
  SCHEMA_CTYPE_INTERLEAVE,
  SCHEMA_CTYPE_PATTERN,
  SCHEMA_CTYPE_TEXT,
  SCHEMA_CTYPE_VIRTUAL,
  SCHEMA_CTYPE_KEYSPACE,
  SCHEMA_CTYPE_KEYSPACE_END,
} Schema_CP_Type;

typedef enum {
  SCHEMA_CQUANT_ONE,
  SCHEMA_CQUANT_OPT,
  SCHEMA_CQUANT_REP,
  SCHEMA_CQUANT_PLUS,
................................................................................
    ast    selector;
    ast   *fields;
    int    nrFields;
    int    flags;
    struct domKeyConstraint *next;
} domKeyConstraint;

typedef struct 
{
    int active;
    Tcl_HashTable ids;
    int unknownIDrefs;
} SchemaKeySpace;

typedef struct SchemaCP
{
    Schema_CP_Type    type;
    char             *namespace;
    char             *name;
    struct SchemaCP  *next;
    SchemaFlags       flags;
................................................................................
    struct SchemaCP **content;
    SchemaQuant      *quants;
    unsigned int      nc;
    SchemaAttr      **attrs;
    unsigned int      numAttr;
    unsigned int      numReqAttr;
    domKeyConstraint *domKeys;
    SchemaKeySpace   *keySpace;
} SchemaCP;

typedef struct SchemaValidationStack
{
    SchemaCP *pattern;
    struct SchemaValidationStack *next;
    struct SchemaValidationStack *down;
................................................................................
} ValidationState;

typedef struct 
{
    Tcl_HashTable ids;
    int unknownIDrefs;
} SchemaDocKey;

typedef struct SchemaData_
{
    Tcl_Obj *self;
    char *start;
    char *startNamespace;
    Tcl_HashTable element;
    Tcl_HashTable namespace;
................................................................................
    SchemaValidationStack *stackPool;
    ValidationState validationState;
    unsigned int skipDeep;
    Tcl_DString *cdata;
    Tcl_HashTable ids;
    int unknownIDrefs;
    Tcl_HashTable idTables;
    Tcl_HashTable keySpaces;
} SchemaData;

int 
schemaInstanceCmd (
    ClientData clientData,
    Tcl_Interp *interp,
    int objc,

Changes to tests/schema.test.

4576
4577
4578
4579
4580
4581
4582
















































4583
4584
4585
4586
4587
4588
4589
....
4608
4609
4610
4611
4612
4613
4614



























































































4615
4616
4617
4618
4619
4620
4621
        set rc [s validate $xml]
        lappend result $rc
    }
    s delete
    set result
} {s UNKNOWN_ROOT_ELEMENT 1 s UNKNOWN_ROOT_ELEMENT 1 s UNKNOWN_ROOT_ELEMENT 1 s UNKNOWN_ROOT_ELEMENT 1}

















































proc validatedSAX {g xml {keepEmpties 1}} {
    set args [list -validateCmd $g]
    if {!$keepEmpties} {
        lappend args -ignorewhitespace 1
    }
    xml::parser p {*}$args
    set rc [catch {p parse $xml} errMsg]
................................................................................
proc postValidation {g xml} {
    set doc [dom parse $xml]
    set rc [$g domvalidate $doc errMsg]
    $doc delete
    return $rc
}




























































































test schema-20.1 {domunique} {
    set schema {
        prefixns {ns1 http://tdom.org/test}
        defelement doc {
            domunique ${::schema-20.1} @ref
        }
    }






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







 







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







4576
4577
4578
4579
4580
4581
4582
4583
4584
4585
4586
4587
4588
4589
4590
4591
4592
4593
4594
4595
4596
4597
4598
4599
4600
4601
4602
4603
4604
4605
4606
4607
4608
4609
4610
4611
4612
4613
4614
4615
4616
4617
4618
4619
4620
4621
4622
4623
4624
4625
4626
4627
4628
4629
4630
4631
4632
4633
4634
4635
4636
4637
....
4656
4657
4658
4659
4660
4661
4662
4663
4664
4665
4666
4667
4668
4669
4670
4671
4672
4673
4674
4675
4676
4677
4678
4679
4680
4681
4682
4683
4684
4685
4686
4687
4688
4689
4690
4691
4692
4693
4694
4695
4696
4697
4698
4699
4700
4701
4702
4703
4704
4705
4706
4707
4708
4709
4710
4711
4712
4713
4714
4715
4716
4717
4718
4719
4720
4721
4722
4723
4724
4725
4726
4727
4728
4729
4730
4731
4732
4733
4734
4735
4736
4737
4738
4739
4740
4741
4742
4743
4744
4745
4746
4747
4748
4749
4750
4751
4752
4753
4754
4755
4756
4757
4758
4759
4760
        set rc [s validate $xml]
        lappend result $rc
    }
    s delete
    set result
} {s UNKNOWN_ROOT_ELEMENT 1 s UNKNOWN_ROOT_ELEMENT 1 s UNKNOWN_ROOT_ELEMENT 1 s UNKNOWN_ROOT_ELEMENT 1}

test schema-18.4 {reportcmd} {
    tdom::schema s
    s define {
        defelement doc {
            element items * {
                element item * {
                    attribute ref {integer}
                }
            }
        }
    }
    s reportcmd schema-18
    set result [list]
    foreach xml {
        {<doc><items><item ref="1"/><item ref="1"/></items><items><item ref="1"/><item ref="1"/></items></doc>}
        {<doc><items><item ref="1"/><item ref="a"/></items><items><item ref="b"/><item ref="1"/></items></doc>}
    } {
        lappend result [s validate $xml]
    }
    s delete
    set result
} {1 s WRONG_ATTRIBUTE_VALUE s WRONG_ATTRIBUTE_VALUE 1}

test schema-18.5 {reportcmd} {
    tdom::schema s
    s define {
        defelement doc {
            element items * {
                element item * {
                    text {minLength 2}
                }
            }
        }
    }
    s reportcmd schema-18
    set result [list]
    foreach xml {
        {<doc><items><item>1</item></items></doc>}
        {<doc><items><item>1</item><item/></items></doc>}
        {<doc><items><item>>12</item><item>ab</item></items></doc>}

    } {
        lappend result [s validate $xml]
    }
    s delete
    set result
} {s WRONG_VALUE 1 s WRONG_VALUE s MISSING_TEXT 1 1}

proc validatedSAX {g xml {keepEmpties 1}} {
    set args [list -validateCmd $g]
    if {!$keepEmpties} {
        lappend args -ignorewhitespace 1
    }
    xml::parser p {*}$args
    set rc [catch {p parse $xml} errMsg]
................................................................................
proc postValidation {g xml} {
    set doc [dom parse $xml]
    set rc [$g domvalidate $doc errMsg]
    $doc delete
    return $rc
}

test schema-19.1 {keyspace} {
    tdom::schema s
    s define {
        defelement doc {
            element items * {
                keyspace ref {
                    element item * {
                        attribute ref ? {
                            key ref
                        }
                    }
                }
            }
        }
    }
    set result [list]
    foreach xml {
        {<doc><items><item ref="1"/><item ref="foo"/></items></doc>}
        {<doc><items><item ref="1"/><item ref="1"/></items></doc>}
        {<doc><items><item ref="1"/><item ref="foo"/></items><items><item ref="1"/><item ref="foo"/></items></doc>}
        {<doc><items><item ref="1"/><item ref="foo"/></items><items><item ref="1"/><item ref="bar"/></items></doc>}
        {<doc><items><item ref="1"/><item ref="foo"/></items><items><item ref="2"/><item ref="bar"/></items></doc>}
        {<doc><items><item ref="1"/><item ref="foo"/></items><items><item ref="bar"/><item ref="bar"/></items></doc>}
    } {
        lappend result [s validate $xml]
    }
    s delete
    set result
} {1 0 1 1 1 0}

test schema-19.2 {keyspace} {
    tdom::schema s
    s define {
        defelement doc {
            element items * {
                keyspace ref {
                    element item * {
                        attribute ref ? {
                            key ref
                        }
                    }
                }
            }
        }
    }
    s reportcmd schema-18
    set result [list]
    foreach xml {
        {<doc><items><item ref="1"/><item ref="1"/></items><items><item ref="1"/><item ref="1"/></items></doc>}
        {<doc><items><item ref="1"/><item ref="a"/></items><items><item ref="c"/><item ref="d"/></items></doc>}
    } {
        lappend result [s validate $xml]
    }
    s delete
    set result
} {s WRONG_ATTRIBUTE_VALUE s WRONG_ATTRIBUTE_VALUE 1 1}

test schema-19.3 {keyspace} {
    tdom::schema s
    s define {
        defelement doc {
            element items *
        }
        defelement items {
            keyspace my {
                element item *
            }
        }
        defelement item {
            attribute id ? {
                key my
            }
            attribute ref ? {
                keyref my
            }
        }
    }
    s reportcmd schema-18
    set result [list]
    foreach xml {
        {<doc><items><item ref="1"/><item id="1"/></items></doc>}
        {<doc><items><item ref="1" id="1"/></items></doc>}
        {<doc><items><item ref="a" id="1"/></items></doc>}
        {<doc><items><item ref="1"/><item id="1"/></items><items><item ref="1"/><item ref="1"/></items></doc>}
    } {
        lappend result [s validate $xml]
    }
    s delete
    set result
} {1 1 s UNKNOWN_KEYREF 1 s UNKNOWN_KEYREF 1}

test schema-20.1 {domunique} {
    set schema {
        prefixns {ns1 http://tdom.org/test}
        defelement doc {
            domunique ${::schema-20.1} @ref
        }
    }