tDOM

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

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

Overview
Comment:Done.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | wip
Files: files | file ages | folders
SHA3-256: 9a631db3686fdf0a07e582c7428ca37fb3d3647a6a05f6d3e33a58500f7b032a
User & Date: rolf 2019-05-02 12:11:25
Context
2019-05-02
12:14
Added new text constraint command split, which splits the text to check into a list and cecks the elements of that list against the given constraints. check-in: 77cf4c7090 user: rolf tags: schema
12:11
Done. Closed-Leaf check-in: 9a631db368 user: rolf tags: wip
2019-05-01
23:55
wip check-in: a155f2862c user: rolf tags: wip
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
...
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
...
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
...
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
...
477
478
479
480
481
482
483
484



















485



486


487
488
489
490
491
492
493
494
<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="#SECTid0x564bf296cb30">NAME</a> · <a href="#SECTid0x564bf296d160">SYNOPSIS</a> · <a href="#SECTid0x564bf29675d0">DESCRIPTION </a> · <a href="#SECTid0x564bf29c0fc0">Schema definition scripts</a> · <a href="#SECTid0x564bf29c92f0">Quantity specifier</a> · <a href="#SECTid0x564bf29cb180">Text constraint scripts</a> · <a href="#SECTid0x564bf29d1480">Exampels</a>
</div><hr class="navsep">
</div><div class="body">
  <h2><a name="SECTid0x564bf296cb30">NAME</a></h2><p class="namesection">
<b class="names">tdom::schema - </b><br>Create a schema validation command</p>

  <h2><a name="SECTid0x564bf296d160">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="SECTid0x564bf29675d0">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="SECTid0x564bf29c0fc0">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="SECTid0x564bf29c92f0">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="SECTid0x564bf29cb180">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">strip</b> <i class="m">&lt;constraint script&gt;</i>
</dt>
        <dd>This text constraint command tests all text constraints
        in the evaluated <i class="m">constraint script&gt;</i> with the text to
        test striped of all white space at start and end.</dd>
      



















    </dl>



  


  <h2><a name="SECTid0x564bf29d1480">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
...
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
...
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
...
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
...
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
<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="#SECTid0x55d81f852b30">NAME</a> · <a href="#SECTid0x55d81f853160">SYNOPSIS</a> · <a href="#SECTid0x55d81f84d5d0">DESCRIPTION </a> · <a href="#SECTid0x55d81f8ab7e0">Schema definition scripts</a> · <a href="#SECTid0x55d81f8b3b10">Quantity specifier</a> · <a href="#SECTid0x55d81f8b59a0">Text constraint scripts</a> · <a href="#SECTid0x55d81f8bcfc0">Exampels</a>
</div><hr class="navsep">
</div><div class="body">
  <h2><a name="SECTid0x55d81f852b30">NAME</a></h2><p class="namesection">
<b class="names">tdom::schema - </b><br>Create a schema validation command</p>

  <h2><a name="SECTid0x55d81f853160">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="SECTid0x55d81f84d5d0">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="SECTid0x55d81f8ab7e0">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="SECTid0x55d81f8b3b10">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="SECTid0x55d81f8b59a0">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">strip</b> <i class="m">&lt;constraint script&gt;</i>
</dt>
        <dd>This text constraint command tests all text constraints
        in the evaluated <i class="m">constraint script&gt;</i> with the text to
        test striped of all white space at start and end.</dd>
      
      
        <dt>
<b class="cmd">split</b> <i class="m">?type ?args??</i><i class="m">&lt;constraint script&gt;</i>
</dt>
        <dd>
<p>This text constraint command splits the text to test
        into a list of values and tests all elements of that list for
        the text constraints in the evaluated <i class="m">constraint
        script&gt;</i>.</p>
        <p>The available types are:</p>
        <dl>
            <dt>whitespace</dt><dd>The text to split is striped of all
            white space at start and end splited into a list at any
            successive white space.</dd>
            <dt>tcl tclcmd ?arg ...?</dt><dd>The text to split is
            handed to the <i class="m">tclcmd</i>, which is evaluated on global
            level, appended with every given arg and the text to split
            as last argument. This call must return a valid tcl list,
            which elements are tested..</dd>
        </dl>
        <p>The default in case no split type argument is given is
        <i class="m">whitespace</i>.</p>
</dd>
      
    </dl>
  
  <h2><a name="SECTid0x55d81f8bcfc0">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.

495
496
497
498
499
500
501



























502
503
504
505
506
507
508
useful mostly together with the \fIoneOf\fR text constraint
commmand.
.TP
\&\fB\fBstrip\fP \fI<constraint script>\fB
\&\fRThis text constraint command tests all text constraints
in the evaluated \fIconstraint script>\fR with the text to
test striped of all white space at start and end.



























.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






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







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
useful mostly together with the \fIoneOf\fR text constraint
commmand.
.TP
\&\fB\fBstrip\fP \fI<constraint script>\fB
\&\fRThis text constraint command tests all text constraints
in the evaluated \fIconstraint script>\fR with the text to
test striped of all white space at start and end.
.TP
\&\fB\fBsplit\fP \fI?type ?args??\fB\fI<constraint script>\fB
\&\fR
.RS
.PP
This text constraint command splits the text to test
into a list of values and tests all elements of that list for
the text constraints in the evaluated \fIconstraint
script>\fR.
.PP
The available types are:
.TP
whitespace
The text to split is striped of all
white space at start and end splited into a list at any
successive white space.
.TP
tcl tclcmd ?arg ...?
The text to split is
handed to the \fItclcmd\fR, which is evaluated on global
level, appended with every given arg and the text to split
as last argument. This call must return a valid tcl list,
which elements are tested..
.PP
The default in case no split type argument is given is
\&\fIwhitespace\fR.
.RE
.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.

441
442
443
444
445
446
447




















448
449
450
451
452
453
454
      </commanddef>
      <commanddef>
        <command><cmd>strip</cmd> <m>&lt;constraint script></m></command>
        <desc>This text constraint command tests all text constraints
        in the evaluated <m>constraint script></m> with the text to
        test striped of all white space at start and end.</desc>
      </commanddef>




















    </commandlist>
  </section>
  
  <section>
    <title>Exampels</title>

    <p>The XML Schema Part 0: Primer Second Edition






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







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
      </commanddef>
      <commanddef>
        <command><cmd>strip</cmd> <m>&lt;constraint script></m></command>
        <desc>This text constraint command tests all text constraints
        in the evaluated <m>constraint script></m> with the text to
        test striped of all white space at start and end.</desc>
      </commanddef>
      <commanddef>
        <command><cmd>split</cmd> <m>?type ?args??</m><m>&lt;constraint script></m></command>
        <desc><p>This text constraint command splits the text to test
        into a list of values and tests all elements of that list for
        the text constraints in the evaluated <m>constraint
        script></m>.</p>
        <p>The available types are:</p>
        <dl>
            <dt>whitespace</dt><dd>The text to split is striped of all
            white space at start and end splited into a list at any
            successive white space.</dd>
            <dt>tcl tclcmd ?arg ...?</dt><dd>The text to split is
            handed to the <m>tclcmd</m>, which is evaluated on global
            level, appended with every given arg and the text to split
            as last argument. This call must return a valid tcl list,
            which elements are tested..</dd>
        </dl>
        <p>The default in case no split type argument is given is
        <m>whitespace</m>.</p></desc>
      </commanddef>
    </commandlist>
  </section>
  
  <section>
    <title>Exampels</title>

    <p>The XML Schema Part 0: Primer Second Edition

Changes to generic/schema.c.

1592
1593
1594
1595
1596
1597
1598

1599

1600
1601
1602
1603
1604
1605
1606
....
1771
1772
1773
1774
1775
1776
1777
1778

1779

1780
1781
1782
1783
1784
1785
1786
....
4163
4164
4165
4166
4167
4168
4169
4170
4171
4172
4173
4174
4175
4176
4177
4178
....
4293
4294
4295
4296
4297
4298
4299
4300
4301
4302
4303
4304
4305
4306
4307
4308
                candidate = cp->content[ac];
                switch (candidate->type) {
                case SCHEMA_CTYPE_TEXT:
                    if (checkText (interp, candidate, text)) {
                        updateStack (se, cp, ac);
                        return 1;
                    }

                    SetResult ("Invalid text content");

                    return 0;

                case SCHEMA_CTYPE_CHOICE:
                    if (candidate->flags & MIXED_CONTENT) {
                        updateStack (se, cp, ac);
                        return 1;
                    }
................................................................................
        if (only_whites)  return TCL_OK;
        if (matchText (interp, sdata, text)) {
            return TCL_OK;
        }
    }
    if (recover (interp, sdata, S("WRONG_VALUE"))) {
        return TCL_OK;
    }            

    SetResult ("Text content doesn't match");

    return TCL_ERROR;
}

static void
startElement(
    void         *userData,
    const char   *name,
................................................................................
        if (!rc) break;
    }
    return rc;
}

typedef struct
{
    int        nrArg;
    Tcl_Obj  **evalStub;
    SchemaData *sdata;
    SchemaCP   *cp;
} splitTclTCData;


static int
splitTclImpl (
................................................................................
        sc->constraintData = cp;
        break;
    case m_tcl:
        sc->constraint = splitTclImpl;
        sc->freeData = splitTclImplFree;
        tcdata = TMALLOC (splitTclTCData);
        tcdata->nrArg = objc - 2;
        tcdata->evalStub = MALLOC (sizeof (Tcl_Obj*) * (objc-1));
        for (i = 2; i < objc; i++) {
            tcdata->evalStub[i-2] = objv[i];
            Tcl_IncrRefCount (tcdata->evalStub[i-2]);
        }
        tcdata->sdata = sdata;
        tcdata->cp = cp;
        sc->constraintData = tcdata;
    }






>
|
>







 







|
>
|
>







 







|
|







 







|
|







1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
....
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
....
4167
4168
4169
4170
4171
4172
4173
4174
4175
4176
4177
4178
4179
4180
4181
4182
....
4297
4298
4299
4300
4301
4302
4303
4304
4305
4306
4307
4308
4309
4310
4311
4312
                candidate = cp->content[ac];
                switch (candidate->type) {
                case SCHEMA_CTYPE_TEXT:
                    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;
                    }
................................................................................
        if (only_whites)  return TCL_OK;
        if (matchText (interp, sdata, text)) {
            return TCL_OK;
        }
    }
    if (recover (interp, sdata, S("WRONG_VALUE"))) {
        return TCL_OK;
    }
    if (!sdata->evalError) {
        SetResult ("Text content doesn't match");
    }
    return TCL_ERROR;
}

static void
startElement(
    void         *userData,
    const char   *name,
................................................................................
        if (!rc) break;
    }
    return rc;
}

typedef struct
{
    int         nrArg;
    Tcl_Obj   **evalStub;
    SchemaData *sdata;
    SchemaCP   *cp;
} splitTclTCData;


static int
splitTclImpl (
................................................................................
        sc->constraintData = cp;
        break;
    case m_tcl:
        sc->constraint = splitTclImpl;
        sc->freeData = splitTclImplFree;
        tcdata = TMALLOC (splitTclTCData);
        tcdata->nrArg = objc - 2;
        tcdata->evalStub = MALLOC (sizeof (Tcl_Obj*) * (objc-2));
        for (i = 2; i < objc -1; i++) {
            tcdata->evalStub[i-2] = objv[i];
            Tcl_IncrRefCount (tcdata->evalStub[i-2]);
        }
        tcdata->sdata = sdata;
        tcdata->cp = cp;
        sc->constraintData = tcdata;
    }

Changes to tests/schema.test.

3310
3311
3312
3313
3314
3315
3316








































3317
3318
3319
3320
3321
3322
3323
        {<doc><a>  </a></doc>}
        {<doc><a>-a</a></doc>}
        {<doc><a>1 2 3 -4.5</a></doc>}
    } {
        incr schema-14.24
        lappend result [s validate $xml errMsg]
    }








































    s delete
    set result
} {1 1 0}

test schema-15.1 {constraint cmd tcl} {
    tdom::schema s
    s define {






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







3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
        {<doc><a>  </a></doc>}
        {<doc><a>-a</a></doc>}
        {<doc><a>1 2 3 -4.5</a></doc>}
    } {
        incr schema-14.24
        lappend result [s validate $xml errMsg]
    }
    s delete
    set result
} {1 1 0}

proc schema-14.24a {arg1 arg2 text} {
    global schema-14.24a
    if {$arg1 ne "foo" || $arg2 ne "bar"} {
        error "Unexpected args"
    }
    switch ${schema-14.24a} {
        1 {return {1 2 3}}
        2 {return {-23.4 .5}}
        3 {return {0 a 5}}
        default {error "Unexpected value of the global var schema-14.24."}
    }
}

test schema-14.24a {split} {
    set schema-14.24a 0
    tdom::schema s
    s define {
        defelement doc {
            element a 1 {
                text {
                    split tcl schema-14.24a foo bar {
                        number
                    }
                }
            }
        }
    }
    set result [list]
    foreach xml {
        {<doc><a>  </a></doc>}
        {<doc><a>-a</a></doc>}
        {<doc><a>1 2 3 -4.5</a></doc>}
    } {
        incr schema-14.24a
        lappend result [s validate $xml]
    }
    s delete
    set result
} {1 1 0}

test schema-15.1 {constraint cmd tcl} {
    tdom::schema s
    s define {