tDOM

Check-in [db1bcdb342]
Login
Bounty program for improvements to Tcl and certain Tcl packages.

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

Overview
Comment:Merged from schema.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | localkey
Files: files | file ages | folders
SHA3-256: db1bcdb342d097577603ab3f9d6d244bd09e8020609c63dee61866ce93d1d1cd
User & Date: rolf 2019-05-10 13:05:49
Context
2019-05-10
13:41
Merge from schema. check-in: 4bf39f2571 user: rolf tags: localkey
13:05
Merged from schema. check-in: db1bcdb342 user: rolf tags: localkey
13:04
Futher work on prefixns: allow it als top level command in define script. Changed semantic to first prefix/namespace mapping in prefixUriList wins, if there are several prefixes mapping to different namespaces. check-in: a70c1d6c6e user: rolf tags: schema
00:49
Use the new schema feature prefixns for namespace prefix resolution in local key constraint XPath expressions. check-in: e407c9fd00 user: rolf tags: localkey
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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
...
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
...
301
302
303
304
305
306
307











308
309
310
311
312
313
314
...
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
...
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
...
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
<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="#SECTid0x55dce5c8db10">NAME</a> · <a href="#SECTid0x55dce5c8e170">SYNOPSIS</a> · <a href="#SECTid0x55dce5c885f0">DESCRIPTION </a> · <a href="#SECTid0x55dce5ce7e60">Schema definition scripts</a> · <a href="#SECTid0x55dce5cf0190">Quantity specifier</a> · <a href="#SECTid0x55dce5cf2020">Text constraint scripts</a> · <a href="#SECTid0x55dce5cfa430">Exampels</a>
</div><hr class="navsep">
</div><div class="body">
  <h2><a name="SECTid0x55dce5c8db10">NAME</a></h2><p class="namesection">
<b class="names">tdom::schema - </b><br>Create a schema validation command</p>

  <h2><a name="SECTid0x55dce5c8e170">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="SECTid0x55dce5c885f0">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">prefixns</b> <i class="m">?prefixUriList?</i>
</dt>

          <dd>This method gives control to a prefix (or
          abbreviation) to namespace URI mapping. Everywhere a
          namespace argument is expected in the schema command methods
          you may use the "prefix" pointing to the namespace
          URI in the current prefixUriList, set by this method. If the
          list map the same prefix to different namespace URIs the
          last won win. If there isn't such a prefix the namespace
          argument is used literally as namespace URI. If the method
          is called without argument it returns the current
          prefixUriList. If the method is called with the empty list
          any namespace URI arguments are used literally. This is the
          default.
          </dd>
      

      
        <dt>
................................................................................
        <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="SECTid0x55dce5ce7e60">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">
................................................................................
      
        <dt>
<b class="method">namespace</b> <i class="m">uri</i> <i class="m">&lt;definition script&gt;</i>
</dt>
        <dd>Evaluates the <i class="m">definition script</i> with context namespace <i class="m">uri</i>. Every element or ref command name will be looked up in the namespace <i class="m">uri</i> and local defined element will be in that namespace.</dd>
      
      











      
        <dt>
<b class="method">defelement</b> <i class="m">name</i> <i class="m">?namespace?</i> <i class="m">&lt;definition script&gt;</i>
</dt>
        <dd>This defines an element type exactly as a <i>schemacmd
        defelement</i> call. This is meant as toplevel command of a
        <i>schemacmd define</i> script. This command is not allowed
................................................................................
        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="SECTid0x55dce5cf0190">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="SECTid0x55dce5cf2020">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="SECTid0x55dce5cfa430">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
26
27
28

29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
...
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
...
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
...
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
...
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">prefixns</b> <i class="m">?prefixUriList?</i>
</dt>

          <dd>This method gives control to a prefix (or
          abbreviation) to namespace URI mapping. Everywhere a
          namespace argument is expected in the schema command methods
          you may use the "prefix" pointing to the namespace
          URI in the current prefixUriList, set by this method. If the
          list map the same prefix to different namespace URIs the
          frist one win. If there isn't such a prefix the namespace
          argument is used literally as namespace URI. If the method
          is called without argument it returns the current
          prefixUriList. If the method is called with the empty string
          any namespace URI arguments are used literally. This is the
          default.
          </dd>
      

      
        <dt>
................................................................................
        <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">
................................................................................
      
        <dt>
<b class="method">namespace</b> <i class="m">uri</i> <i class="m">&lt;definition script&gt;</i>
</dt>
        <dd>Evaluates the <i class="m">definition script</i> with context namespace <i class="m">uri</i>. Every element or ref command name will be looked up in the namespace <i class="m">uri</i> and local defined element will be in that namespace.</dd>
      
      
      
        <dt>
<b class="method">prefixns</b> <i class="m">?prefixUriList?</i>
</dt>
        <dd>This defines a prefix to namespace URI mapping exactly
        as a <i>schemacmd prefixns</i> 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>
      

      
        <dt>
<b class="method">defelement</b> <i class="m">name</i> <i class="m">?namespace?</i> <i class="m">&lt;definition script&gt;</i>
</dt>
        <dd>This defines an element type exactly as a <i>schemacmd
        defelement</i> call. This is meant as toplevel command of a
        <i>schemacmd define</i> script. This command is not allowed
................................................................................
        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.

Changes to doc/schema.n.

186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
...
367
368
369
370
371
372
373







374
375
376
377
378
379
380
\&\fB\fBprefixns\fP \fI?prefixUriList?\fB
\&\fRThis method gives control to a prefix (or
abbreviation) to namespace URI mapping. Everywhere a
namespace argument is expected in the schema command methods
you may use the "prefix" pointing to the namespace
URI in the current prefixUriList, set by this method. If the
list map the same prefix to different namespace URIs the
last won win. If there isn't such a prefix the namespace
argument is used literally as namespace URI. If the method
is called without argument it returns the current
prefixUriList. If the method is called with the empty list
any namespace URI arguments are used literally. This is the
default.
.TP
\&\fB\fBdefelement\fP \fIname\fB \fI?namespace?\fB \fI<definition script>\fB
\&\fRThis method defines the element \fIname\fR (optional in
the namespace \fInamespace\fR) in the schema. The
\&\fIdefinition script\fR is evaluated and defines the content
................................................................................
text type name.
.TP
\&\fB\fBnsattribute\fP \fIname\fB \fInamespace\fB \fI?quant?\fB \fI(?<constraint script>|\*(lqtype\*(lq typename?)\fB
\&\fRThis command does the same as the command \fIattribute\fR, just for the attribute \fIname\fR in the namespace \fInamespace\fR.
.TP
\&\fB\fBnamespace\fP \fIuri\fB \fI<definition script>\fB
\&\fREvaluates the \fIdefinition script\fR with context namespace \fIuri\fR. Every element or ref command name will be looked up in the namespace \fIuri\fR and local defined element will be in that namespace.







.TP
\&\fB\fBdefelement\fP \fIname\fB \fI?namespace?\fB \fI<definition script>\fB
\&\fRThis defines an element type exactly as a \fIschemacmd
defelement\fR call. This is meant as toplevel command of a
\&\fIschemacmd define\fR script. This command is not allowed
nested in an other definition script command and will raise
error, if you call it there.






|


|







 







>
>
>
>
>
>
>







186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
...
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
\&\fB\fBprefixns\fP \fI?prefixUriList?\fB
\&\fRThis method gives control to a prefix (or
abbreviation) to namespace URI mapping. Everywhere a
namespace argument is expected in the schema command methods
you may use the "prefix" pointing to the namespace
URI in the current prefixUriList, set by this method. If the
list map the same prefix to different namespace URIs the
frist one win. If there isn't such a prefix the namespace
argument is used literally as namespace URI. If the method
is called without argument it returns the current
prefixUriList. If the method is called with the empty string
any namespace URI arguments are used literally. This is the
default.
.TP
\&\fB\fBdefelement\fP \fIname\fB \fI?namespace?\fB \fI<definition script>\fB
\&\fRThis method defines the element \fIname\fR (optional in
the namespace \fInamespace\fR) in the schema. The
\&\fIdefinition script\fR is evaluated and defines the content
................................................................................
text type name.
.TP
\&\fB\fBnsattribute\fP \fIname\fB \fInamespace\fB \fI?quant?\fB \fI(?<constraint script>|\*(lqtype\*(lq typename?)\fB
\&\fRThis command does the same as the command \fIattribute\fR, just for the attribute \fIname\fR in the namespace \fInamespace\fR.
.TP
\&\fB\fBnamespace\fP \fIuri\fB \fI<definition script>\fB
\&\fREvaluates the \fIdefinition script\fR with context namespace \fIuri\fR. Every element or ref command name will be looked up in the namespace \fIuri\fR and local defined element will be in that namespace.
.TP
\&\fB\fBprefixns\fP \fI?prefixUriList?\fB
\&\fRThis defines a prefix to namespace URI mapping exactly
as a \fIschemacmd prefixns\fR call. This is meant as toplevel
command of a \fIschemacmd define\fR script. This command is
not allowed nested in an other definition script command and
will raise error, if you call it there.
.TP
\&\fB\fBdefelement\fP \fIname\fB \fI?namespace?\fB \fI<definition script>\fB
\&\fRThis defines an element type exactly as a \fIschemacmd
defelement\fR call. This is meant as toplevel command of a
\&\fIschemacmd define\fR script. This command is not allowed
nested in an other definition script command and will raise
error, if you call it there.

Changes to doc/schema.xml.

26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
...
273
274
275
276
277
278
279









280
281
282
283
284
285
286
    otherwise do.</p>

    <p>The valid methods of the created commands are:</p>

    <commandlist>
      <commanddef>
          <command><method>prefixns</method> <m>?prefixUriList?</m></command>

          <desc>This method gives control to a prefix (or
          abbreviation) to namespace URI mapping. Everywhere a
          namespace argument is expected in the schema command methods
          you may use the &quot;prefix&quot; pointing to the namespace
          URI in the current prefixUriList, set by this method. If the
          list map the same prefix to different namespace URIs the
          last won win. If there isn't such a prefix the namespace
          argument is used literally as namespace URI. If the method
          is called without argument it returns the current
          prefixUriList. If the method is called with the empty list
          any namespace URI arguments are used literally. This is the
          default.
          </desc>
      </commanddef>

      <commanddef>
        <command><method>defelement</method> <m>name</m> <m>?namespace?</m> <m>&lt;definition script></m></command>
................................................................................
      </commanddef>

      <commanddef>
        <command><method>namespace</method> <m>uri</m> <m>&lt;definition script></m></command>
        <desc>Evaluates the <m>definition script</m> with context namespace <m>uri</m>. Every element or ref command name will be looked up in the namespace <m>uri</m> and local defined element will be in that namespace.</desc>
      </commanddef>
      









      <commanddef>
        <command><method>defelement</method> <m>name</m> <m>?namespace?</m> <m>&lt;definition script></m></command>
        <desc>This defines an element type exactly as a <i>schemacmd
        defelement</i> 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.</desc>






<






|


|







 







>
>
>
>
>
>
>
>
>







26
27
28
29
30
31
32

33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
...
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
    otherwise do.</p>

    <p>The valid methods of the created commands are:</p>

    <commandlist>
      <commanddef>
          <command><method>prefixns</method> <m>?prefixUriList?</m></command>

          <desc>This method gives control to a prefix (or
          abbreviation) to namespace URI mapping. Everywhere a
          namespace argument is expected in the schema command methods
          you may use the &quot;prefix&quot; pointing to the namespace
          URI in the current prefixUriList, set by this method. If the
          list map the same prefix to different namespace URIs the
          frist one win. If there isn't such a prefix the namespace
          argument is used literally as namespace URI. If the method
          is called without argument it returns the current
          prefixUriList. If the method is called with the empty string
          any namespace URI arguments are used literally. This is the
          default.
          </desc>
      </commanddef>

      <commanddef>
        <command><method>defelement</method> <m>name</m> <m>?namespace?</m> <m>&lt;definition script></m></command>
................................................................................
      </commanddef>

      <commanddef>
        <command><method>namespace</method> <m>uri</m> <m>&lt;definition script></m></command>
        <desc>Evaluates the <m>definition script</m> with context namespace <m>uri</m>. Every element or ref command name will be looked up in the namespace <m>uri</m> and local defined element will be in that namespace.</desc>
      </commanddef>
      
      <commanddef>
        <command><method>prefixns</method> <m>?prefixUriList?</m></command>
        <desc>This defines a prefix to namespace URI mapping exactly
        as a <i>schemacmd prefixns</i> 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.</desc>
      </commanddef>

      <commanddef>
        <command><method>defelement</method> <m>name</m> <m>?namespace?</m> <m>&lt;definition script></m></command>
        <desc>This defines an element type exactly as a <i>schemacmd
        defelement</i> 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.</desc>

Changes to generic/schema.c.

2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
....
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299

2300
2301
2302
2303
2304
2305
2306
2307





2308
2309
2310
2311
2312
2313
2314
....
2647
2648
2649
2650
2651
2652
2653










2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664


2665
2666
2667


2668
2669
2670
2671
2672
2673
2674
2675
....
4606
4607
4608
4609
4610
4611
4612


4613
4614
4615
4616
4617
4618
4619
    ClientData clientData,
    Tcl_Interp *interp,
    int objc,
    Tcl_Obj *const objv[]
    )
{
    int            methodIndex, keywordIndex, hnew, patternIndex;
    int            result = TCL_OK, forwardDef = 0, i = 0;
    int            savedDefineToplevel, type, len;
    unsigned int   savedNumPatternList;
    SchemaData    *savedsdata = NULL, *sdata = (SchemaData *) clientData;
    Tcl_HashTable *hashTable;
    Tcl_HashEntry *h, *h1;
    SchemaCP      *pattern, *current = NULL;
    void          *namespacePtr, *savedNamespacePtr;
................................................................................
    };

    enum eventKeyword
    {
        k_elementstart, k_elementend, k_text
    };

    if (objc < 2) {
        Tcl_WrongNumArgs (interp, 1, objv, "subcommand ?arguments?");
        return TCL_ERROR;
    }

    if (sdata == NULL) {
        /* Inline defined defelement, defpattern, deftext or start */

        sdata = GETASI;
        CHECK_SI;
        if (!sdata->defineToplevel && sdata->currentEvals > 1) {
            SetResult ("Method not allowed in nested schema define script");
            return TCL_ERROR;
        }
        i = 1;
    }






    if (Tcl_GetIndexFromObj (interp, objv[1-i], schemaInstanceMethods,
                             "method", 0, &methodIndex)
        != TCL_OK) {
        return TCL_ERROR;
    }

................................................................................
            Tcl_DecrRefCount (sdata->reportCmd);
        }
        sdata->reportCmd = objv[2];
        Tcl_IncrRefCount (sdata->reportCmd);
        break;

    case m_prefixns:










        result = tcldom_prefixNSlist (&sdata->prefixns, interp, objc, objv,
                                      "prefixns");
        if (sdata->prefix.numBuckets) {
            Tcl_DeleteHashTable (&sdata->prefix);
            Tcl_InitHashTable (&sdata->prefix, TCL_STRING_KEYS);
        }
        if (result == TCL_OK && sdata->prefixns) {
            i = 0;
            while (sdata->prefixns[i]) {
                h = Tcl_CreateHashEntry (&sdata->namespace,
                                         sdata->prefixns[i+1], &hnew);


                h1 = Tcl_CreateHashEntry (&sdata->prefix,
                                          sdata->prefixns[i], &hnew);
                Tcl_SetHashValue (h1, Tcl_GetHashKey (&sdata->namespace, h));


                i += 2;
            }
        }
        break;
        
    default:
        Tcl_SetResult (interp, "unknown method", NULL);
        result = TCL_ERROR;
................................................................................
    Tcl_CreateObjCommand (interp, "tdom::schema::defelement",
                          schemaInstanceCmd, NULL, NULL);
    Tcl_CreateObjCommand (interp, "tdom::schema::defpattern",
                          schemaInstanceCmd, NULL, NULL);
    Tcl_CreateObjCommand (interp, "tdom::schema::deftext",
                          schemaInstanceCmd, NULL, NULL);
    Tcl_CreateObjCommand (interp, "tdom::schema::start",


                          schemaInstanceCmd, NULL, NULL);

    /* The "any" definition command. */
    Tcl_CreateObjCommand (interp, "tdom::schema::any",
                          AnyPatternObjCmd, NULL, NULL);

    /* The named pattern commands "element" and "ref". */






|







 







<
<
<
<
<

|
>








>
>
>
>
>







 







>
>
>
>
>
>
>
>
>
>







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







 







>
>







2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
....
2286
2287
2288
2289
2290
2291
2292





2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
....
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
....
4621
4622
4623
4624
4625
4626
4627
4628
4629
4630
4631
4632
4633
4634
4635
4636
    ClientData clientData,
    Tcl_Interp *interp,
    int objc,
    Tcl_Obj *const objv[]
    )
{
    int            methodIndex, keywordIndex, hnew, patternIndex;
    int            result = TCL_OK, forwardDef = 0, i = 0, j;
    int            savedDefineToplevel, type, len;
    unsigned int   savedNumPatternList;
    SchemaData    *savedsdata = NULL, *sdata = (SchemaData *) clientData;
    Tcl_HashTable *hashTable;
    Tcl_HashEntry *h, *h1;
    SchemaCP      *pattern, *current = NULL;
    void          *namespacePtr, *savedNamespacePtr;
................................................................................
    };

    enum eventKeyword
    {
        k_elementstart, k_elementend, k_text
    };






    if (sdata == NULL) {
        /* Inline defined defelement, defpattern, deftext, start or
         * prefixns */
        sdata = GETASI;
        CHECK_SI;
        if (!sdata->defineToplevel && sdata->currentEvals > 1) {
            SetResult ("Method not allowed in nested schema define script");
            return TCL_ERROR;
        }
        i = 1;
    }
    if (objc + i < 2) {
        Tcl_WrongNumArgs (interp, 1, objv, "subcommand ?arguments?");
        return TCL_ERROR;
    }


    if (Tcl_GetIndexFromObj (interp, objv[1-i], schemaInstanceMethods,
                             "method", 0, &methodIndex)
        != TCL_OK) {
        return TCL_ERROR;
    }

................................................................................
            Tcl_DecrRefCount (sdata->reportCmd);
        }
        sdata->reportCmd = objv[2];
        Tcl_IncrRefCount (sdata->reportCmd);
        break;

    case m_prefixns:
        CHECK_RECURSIVE_CALL
        if (clientData == NULL && !sdata->defineToplevel) {
            SetResult ("Command only allowed at lop level");
            return TCL_ERROR;
        }
        if (objc != 2-i && objc != 3-i) {
            Tcl_WrongNumArgs (interp, 2-i, objv, "?prefixUriList?");
            return TCL_ERROR;
        }
        if (!i) {objc--; objv++;}
        result = tcldom_prefixNSlist (&sdata->prefixns, interp, objc, objv,
                                      "prefixns");
        if (sdata->prefix.numBuckets) {
            Tcl_DeleteHashTable (&sdata->prefix);
            Tcl_InitHashTable (&sdata->prefix, TCL_STRING_KEYS);
        }
        if (result == TCL_OK && sdata->prefixns) {
            j = 0;
            while (sdata->prefixns[j]) {
                h1 = Tcl_CreateHashEntry (&sdata->prefix,
                                          sdata->prefixns[j], &hnew);
                /* This means: First prefix mapping wins */
                if (hnew) {
                    h = Tcl_CreateHashEntry (&sdata->namespace,
                                             sdata->prefixns[j+1], &hnew);
                    Tcl_SetHashValue (h1, Tcl_GetHashKey (&sdata->namespace,
                                                          h));
                }
                j += 2;
            }
        }
        break;
        
    default:
        Tcl_SetResult (interp, "unknown method", NULL);
        result = TCL_ERROR;
................................................................................
    Tcl_CreateObjCommand (interp, "tdom::schema::defelement",
                          schemaInstanceCmd, NULL, NULL);
    Tcl_CreateObjCommand (interp, "tdom::schema::defpattern",
                          schemaInstanceCmd, NULL, NULL);
    Tcl_CreateObjCommand (interp, "tdom::schema::deftext",
                          schemaInstanceCmd, NULL, NULL);
    Tcl_CreateObjCommand (interp, "tdom::schema::start",
                          schemaInstanceCmd, NULL, NULL);
    Tcl_CreateObjCommand (interp, "tdom::schema::prefixns",
                          schemaInstanceCmd, NULL, NULL);

    /* The "any" definition command. */
    Tcl_CreateObjCommand (interp, "tdom::schema::any",
                          AnyPatternObjCmd, NULL, NULL);

    /* The named pattern commands "element" and "ref". */

Changes to generic/tcldom.c.

3956
3957
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
3978
3979
3980
3981
3982
3983
3984
3985
3986
3987
3988
....
3994
3995
3996
3997
3998
3999
4000
4001
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
4012
....
5931
5932
5933
5934
5935
5936
5937

5938

5939
5940
5941
5942
5943
5944
5945
5946
    const char  *methodName
    )
{
    char   **prefixns = *prefixnsPtr;
    int      len, i, result;
    Tcl_Obj *objPtr, *listPtr;

    CheckArgs (2,3,2, "?prefixUriList?");
    i = 0;
    if (objc == 2) {
        if (!prefixns) return TCL_OK;
        listPtr = Tcl_NewListObj (0, NULL);
        i = 0;
        while (prefixns[i]) {
            Tcl_ListObjAppendElement (
                interp, listPtr, Tcl_NewStringObj (prefixns[i], -1)
                );
            i++;
        }
        Tcl_SetObjResult (interp, listPtr);
        return TCL_OK;
    }
    result = Tcl_ListObjLength (interp, objv[2], &len);
    if (result != TCL_OK || (len % 2) != 0) {
        SetResult3 ("The optional argument to the ", methodName, 
                   " method must be a 'prefix namespace' pairs list");
        return TCL_ERROR;
    }
    if (prefixns) {
        while (prefixns[i]) {
            FREE (prefixns[i]);
            i++;
        }
................................................................................
    }
    if (i < len + 1) {
        if (prefixns) FREE (prefixns);
        prefixns = MALLOC (sizeof (char*) * (len+1));
        *prefixnsPtr = prefixns;
    }
    for (i = 0; i < len; i++) {
        Tcl_ListObjIndex (interp, objv[2], i, &objPtr);
        prefixns[i] = tdomstrdup (Tcl_GetString (objPtr));
    }
    prefixns[len] = NULL;
    Tcl_SetObjResult (interp, objv[2]);
    return TCL_OK;
}

/*----------------------------------------------------------------------------
|   renameNodes
|
\---------------------------------------------------------------------------*/
................................................................................
            SetResult("DOCUMENT_NODE");
            return TCL_OK;

        case m_cdataSectionElements:
            return cdataSectionElements (doc, interp, objc, objv);

        case m_selectNodesNamespaces:

            return tcldom_prefixNSlist (&(doc->prefixNSMappings), interp, objc,

                                        objv, "selectNodesNamespaces");
            
        case m_renameNode:
            return renameNodes (doc, interp, objc, objv);
            
        case m_deleteXPathCache:
            return deleteXPathCache (doc, interp, objc, objv);







<

|












|

|
|







 







|



|







 







>
|
>
|







3956
3957
3958
3959
3960
3961
3962

3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
3978
3979
3980
3981
3982
3983
3984
3985
3986
3987
....
3993
3994
3995
3996
3997
3998
3999
4000
4001
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
....
5930
5931
5932
5933
5934
5935
5936
5937
5938
5939
5940
5941
5942
5943
5944
5945
5946
5947
    const char  *methodName
    )
{
    char   **prefixns = *prefixnsPtr;
    int      len, i, result;
    Tcl_Obj *objPtr, *listPtr;


    i = 0;
    if (objc == 1) {
        if (!prefixns) return TCL_OK;
        listPtr = Tcl_NewListObj (0, NULL);
        i = 0;
        while (prefixns[i]) {
            Tcl_ListObjAppendElement (
                interp, listPtr, Tcl_NewStringObj (prefixns[i], -1)
                );
            i++;
        }
        Tcl_SetObjResult (interp, listPtr);
        return TCL_OK;
    }
    result = Tcl_ListObjLength (interp, objv[1], &len);
    if (result != TCL_OK || (len % 2) != 0) {
        SetResult3 ("The optional argument to ", methodName, 
                   " must be a 'prefix namespace' pairs list");
        return TCL_ERROR;
    }
    if (prefixns) {
        while (prefixns[i]) {
            FREE (prefixns[i]);
            i++;
        }
................................................................................
    }
    if (i < len + 1) {
        if (prefixns) FREE (prefixns);
        prefixns = MALLOC (sizeof (char*) * (len+1));
        *prefixnsPtr = prefixns;
    }
    for (i = 0; i < len; i++) {
        Tcl_ListObjIndex (interp, objv[1], i, &objPtr);
        prefixns[i] = tdomstrdup (Tcl_GetString (objPtr));
    }
    prefixns[len] = NULL;
    Tcl_SetObjResult (interp, objv[1]);
    return TCL_OK;
}

/*----------------------------------------------------------------------------
|   renameNodes
|
\---------------------------------------------------------------------------*/
................................................................................
            SetResult("DOCUMENT_NODE");
            return TCL_OK;

        case m_cdataSectionElements:
            return cdataSectionElements (doc, interp, objc, objv);

        case m_selectNodesNamespaces:
            CheckArgs (2,3,2, "?prefixUriList?");
            return tcldom_prefixNSlist (&(doc->prefixNSMappings), interp,
                                        --objc, ++objv,
                                        "selectNodesNamespaces");
            
        case m_renameNode:
            return renameNodes (doc, interp, objc, objv);
            
        case m_deleteXPathCache:
            return deleteXPathCache (doc, interp, objc, objv);

Changes to tests/domDoc.test.

1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
test domDoc-25.4 {selectNodesNamespaces} {
    set doc [dom createDocument foo]
    set result [catch {$doc selectNodesNamespaces wrong} errMsg]
    lappend result $errMsg
    $doc delete
    set result
} {1 {The optional argument to the selectNodesNamespaces method must be a 'prefix namespace' pairs list}}

test domDoc-25.5 {selectNodesNamespaces} {
    set doc [dom parse {<root xmlns="rootdefaultNS">
        <elem1 xmlns="elem1NS"><elem11/></elem1>
        <elem2 xmlns="elem2NS"/>
        </root>}]
    $doc selectNodesNamespaces {default1 rootdefaultNS}






|







1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
test domDoc-25.4 {selectNodesNamespaces} {
    set doc [dom createDocument foo]
    set result [catch {$doc selectNodesNamespaces wrong} errMsg]
    lappend result $errMsg
    $doc delete
    set result
} {1 {The optional argument to selectNodesNamespaces must be a 'prefix namespace' pairs list}}

test domDoc-25.5 {selectNodesNamespaces} {
    set doc [dom parse {<root xmlns="rootdefaultNS">
        <elem1 xmlns="elem1NS"><elem11/></elem1>
        <elem2 xmlns="elem2NS"/>
        </root>}]
    $doc selectNodesNamespaces {default1 rootdefaultNS}

Changes to tests/schema.test.

390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
...
412
413
414
415
416
417
418




















































































































































































419
420
421
422
423
424
425
....
3287
3288
3289
3290
3291
3292
3293









































3294
3295
3296
3297
3298
3299
3300
        lappend result [s2 validate $xml]
    }
    s2 delete
    s1 delete
    set result
} {s1 s2 1 0 0 1}

test schema-1.22 {Call not toplevel cmd methods in definition script} {
    tdom::schema create s
    set result [list]
    s define {
        defelement e {
            lappend ::result [s nrForwardDefinitions]
            element e1
            lappend ::result [s nrForwardDefinitions]
................................................................................
            lappend ::result [s nrForwardDefinitions]
        }
    }
    s delete
    set result
} {0 1 1 2 1 0}





















































































































































































test schema-2.1 {grammar definition: ref} {
    tdom::schema create grammar
    grammar defpattern thisPattern {
        element a
        element b
    }
    grammar defpattern thatPattern {
................................................................................
        element e ! {
            nsattribute this http://tdom.org/test {
                minLength 2
                maxLength 4
            }
            nsattribute foo http://tdom.org/test ? type len2-4
        }









































    }
    set result [list]
    foreach xml {
        <doc><e/></doc>
        {<doc xmlns:ns1="http://tdom.org/test"><e ns1:foo="bar"/></doc>}
        {<doc xmlns:ns1="http://tdom.org/test"><e ns1:this="bar"/></doc>}
        {<doc xmlns:ns1="http://tdom.org/test"><e ns1:this=""/></doc>}






|







 







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







 







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







390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
...
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
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
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
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
....
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
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
        lappend result [s2 validate $xml]
    }
    s2 delete
    s1 delete
    set result
} {s1 s2 1 0 0 1}

test schema-1.22 {nrForwardDefinitions} {
    tdom::schema create s
    set result [list]
    s define {
        defelement e {
            lappend ::result [s nrForwardDefinitions]
            element e1
            lappend ::result [s nrForwardDefinitions]
................................................................................
            lappend ::result [s nrForwardDefinitions]
        }
    }
    s delete
    set result
} {0 1 1 2 1 0}

test schema-1.23 {prefixns} {
    tdom::schema create s
    set result [list]
    lappend result [s prefixns]
    lappend result [s prefixns {a b}]
    lappend result [s prefixns]
    lappend result [s prefixns {a b a b c d}]
    lappend result [s prefixns {}]
    lappend result [s prefixns ""]
    lappend result [catch {s prefixns a b c} errMsg]
    lappend result $errMsg
    lappend result [catch {s prefixns {a b c}} errMsg]
    lappend result $errMsg
    lappend result [catch {s prefixns "a \{"} errMsg]
    lappend result $errMsg
    s delete
    set result
} {{} {a b} {a b} {a b a b c d} {} {} 1 {wrong # args: should be "s prefixns ?prefixUriList?"} 1 {The optional argument to prefixns must be a 'prefix namespace' pairs list} 1 {The optional argument to prefixns must be a 'prefix namespace' pairs list}}

test schema-1.24 {prefixns} {
    tdom::schema create s
    set result [list]
    lappend result [s define prefixns]
    lappend result [s define {prefixns {a b}}]
    lappend result [s define {prefixns}]
    lappend result [s define {prefixns {a b a b c d}}]
    lappend result [s define {prefixns {}}]
    lappend result [s define {prefixns ""}]
    lappend result [catch {s define {prefixns a b c}} errMsg]
    lappend result $errMsg
    lappend result [catch {s define {prefixns {a b c}}} errMsg]
    lappend result $errMsg
    lappend result [catch {s define {prefixns "a \{"}} errMsg]
    lappend result $errMsg
    s delete
    set result
} {{} {a b} {a b} {a b a b c d} {} {} 1 {wrong # args: should be "prefixns ?prefixUriList?"} 1 {The optional argument to prefixns must be a 'prefix namespace' pairs list} 1 {The optional argument to prefixns must be a 'prefix namespace' pairs list}}

test schema-1.25 {prefixns} {
    set result [list]
    set schema {
        defelement doc ns1 {
            element e
        }
    }
    set xml {<doc xmlns="http://tdom.org/test"><e/></doc>}
    # 1
    tdom::schema create s
    s define $schema
    lappend result [s validate $xml]
    s delete
    # 2
    tdom::schema create s
    s prefixns {ns1 http://tdom.org/test}
    s define $schema
    lappend result [s validate $xml]
    s delete
    # 3
    tdom::schema create s
    s prefixns {ns1 http://foo.bar}
    s define $schema
    lappend result [s validate $xml]
    s delete
    # 4
    tdom::schema create s
    s prefixns {ns1 http://tdom.org/test ns1 http://foo.bar}
    s define $schema
    lappend result [s validate $xml]
    s delete
    # 5
    tdom::schema create s
    s prefixns {ns1 http://foo.bar ns1 http://tdom.org/test}
    s define $schema
    lappend result [s validate $xml]
    s delete
    # 6
    tdom::schema create s
    s prefixns {ns1 http://foo.bar}
    s prefixns {ns1 http://tdom.org/test ns1 http://foo.bar}
    s define $schema
    lappend result [s validate $xml]
    s delete
    # 7
    tdom::schema create s
    s define {
        prefixns {ns1 http://tdom.org/test}
        defelement doc ns1 {
            element e
        }
        prefixns {ns2 http://foo.bar}
        defelement e ns2 {text {minLength 1}}
    }
    lappend result [s validate $xml]
    s delete
    # 8
    tdom::schema create s
    s define {
        prefixns {ns1 http://tdom.org/test}
        defelement doc ns1 {
            namespace http://foo.bar {
                element e 
            }
        }
        prefixns {ns2 http://foo.bar}
        defelement e ns2 {text {minLength 1}}
    }
    lappend result [s validate $xml]
    # 9
    lappend result [s validate {<doc xmlns="http://tdom.org/test"><e xmlns="http://foo.bar"/></doc>}]
    # 10
    lappend result [s validate {<doc xmlns="http://tdom.org/test"><e xmlns="http://foo.bar">foo</e></doc>}]
    s delete
    # 11 
    tdom::schema create s
    s define {
        prefixns {ns1 http://tdom.org/test ns2 http://foo.bar}
        defelement doc ns1 {
            namespace ns2 {
                element e 
            }
        }
        prefixns {ns2 http://foo.bar}
        defelement e ns2 {text {minLength 1}}
    }
    lappend result [s validate $xml]
    # 12
    lappend result [s validate {<doc xmlns="http://tdom.org/test"><e xmlns="http://foo.bar"/></doc>}]
    # 13
    lappend result [s validate {<doc xmlns="http://tdom.org/test"><e xmlns="http://foo.bar">foo</e></doc>}]
    s delete
    set result
} {0 1 0 1 0 1 1 0 0 1 0 0 1}

test schema-1.26 {prefixns} {
    tdom::schema create s
    set result [list]
    lappend result [catch {
        s defelement doc {
            prefixns {a http://foo.bar}
            namespace a {
                element e
            }
        }
    } errMsg]
    lappend result $errMsg
    lappend result [catch {
        s defelement doc {
            namespace a {
                element e
            }
            prefixns {a http://foo.bar}
        }
    } errMsg]
    lappend result $errMsg
    lappend result [catch {
        s define {
            defelement doc {
                prefixns {a http://foo.bar}
                namespace a {
                    element e
                }
            }
        }
    } errMsg]
    lappend result $errMsg
    lappend result [catch {
        s define {
            defelement doc {
                s prefixns {a http://foo.bar}
                namespace a {
                    element e
                }
            }
        }
    } errMsg]
    lappend result $errMsg
    s delete
    set result
} {1 {Command only allowed at lop level} 1 {Command only allowed at lop level} 1 {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 {
................................................................................
        element e ! {
            nsattribute this http://tdom.org/test {
                minLength 2
                maxLength 4
            }
            nsattribute foo http://tdom.org/test ? type len2-4
        }
    }
    set result [list]
    foreach xml {
        <doc><e/></doc>
        {<doc xmlns:ns1="http://tdom.org/test"><e ns1:foo="bar"/></doc>}
        {<doc xmlns:ns1="http://tdom.org/test"><e ns1:this="bar"/></doc>}
        {<doc xmlns:ns1="http://tdom.org/test"><e ns1:this=""/></doc>}
        {<doc xmlns:ns1="http://tdom.org/test"><e ns1:this="12" ns1:foo="bar"/></doc>}
        {<doc xmlns:ns1="http://tdom.org/test"><e ns1:this="12" ns1:foo="b"/></doc>}
        {<doc xmlns:ns1="http://tdom.org/test"><e ns1:this="1234"/></doc>}
        {<doc xmlns:ns1="http://tdom.org/test"><e ns1:this="12345"/></doc>}
        {<doc xmlns:ns1="http://tdom.org/test"><e ns1:this="12345alkajsdlfjkals" ns1:and="this"/></doc>}
        {<doc xmlns:ns1="http://tdom.org/test"><e ns1:and="this" ns1:this="12345alkajsdlfjkals"/></doc>}
    } {
        lappend result [s validate $xml]
    }
    s delete
    set result
} {0 0 1 0 1 0 1 0 0 0}

test schema-14.20a {deftext} {
    tdom::schema s
    s deftext len2-4 {
        minLength 2
        maxLength 4
    }
    s define {
        prefixns {
            ns2 http://tdom.org/test
            nsfoo http://foo.bar
            ns2 http://baz.boo
        }
        defelement doc {
            element e ! {
                nsattribute this ns2 {
                    minLength 2
                    maxLength 4
                }
                nsattribute foo ns2 ? type len2-4
            }
        }
    }
    set result [list]
    foreach xml {
        <doc><e/></doc>
        {<doc xmlns:ns1="http://tdom.org/test"><e ns1:foo="bar"/></doc>}
        {<doc xmlns:ns1="http://tdom.org/test"><e ns1:this="bar"/></doc>}
        {<doc xmlns:ns1="http://tdom.org/test"><e ns1:this=""/></doc>}