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

Overview
Comment:Added text constraint command whitespace.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | schema
Files: files | file ages | folders
SHA3-256: 567b33a968dac886c49fba76006747104c64d812f4d2666d29009492a7510a0e
User & Date: rolf 2020-06-27 00:09:17
Context
2020-07-03
11:56
Merged from trunk. check-in: c8e5101f6a user: rolf tags: schema
2020-06-27
00:09
Added text constraint command whitespace. check-in: 567b33a968 user: rolf tags: schema
00:07
Fixed whitespaceImplReplace - correct mistakenly double test for \n and handle (the semi-hidden, because of the end-of-line handling by the parser) \r also. More tests. Closed-Leaf check-in: 2e024420ae user: rolf tags: xsdwhitespace
2020-06-11
00:52
Merged from trunk. check-in: f782953f52 user: rolf tags: schema
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to doc/schema.xml.

793
794
795
796
797
798
799















800
801
802
803
804
805
806
...
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
        is <m>tcl</m> everthing that returns TCL_OK if feeded into
        Tcl_GetInt() matches. If the optional argument to the command
        is <m>xsd</m> then the constraint match if the value is a
        valid xsd:integer. Without argument <m>xsd</m> is the
        default.</desc>
      </commanddef>
















      <commanddef>
        <command><cmd>negativeInteger</cmd> <m>?(xsd|tcl)?</m></command>
        <desc>This text constraint match the same text values as the
        <m>integer</m> text constraint (see there) with the additional
        constraint that the value must be &lt; zero.</desc>
      </commanddef>
      
................................................................................
            <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>
      <commanddef>
        <command><cmd>id</cmd> <m>?keySpace?</m></command>
        <desc>This text constraint command marks the text as a







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







 







|







793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
...
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
        is <m>tcl</m> everthing that returns TCL_OK if feeded into
        Tcl_GetInt() matches. If the optional argument to the command
        is <m>xsd</m> then the constraint match if the value is a
        valid xsd:integer. Without argument <m>xsd</m> is the
        default.</desc>
      </commanddef>

      <commanddef>
        <command><cmd>whitespace</cmd> <m>(preserve|replace|collapse)</m> <m>&lt;constraint script></m></command>
        <desc>This text constraint command does whitespace (#x20
        (space, ' '), #x9 (tab, \t), #xA (linefeed, \n), and #xD
        (carriage return, \r) normalization to the text value and
        checks the resulting text with the text constraints of the
        constraint script argument. The normalization method
        <m>preserve</m> keeps everything as it is; this is another way
        to say <m>allOf</m>. The <m>replace</m> normalization method
        replaces any single whitespace character (as above) to a
        space. The <m>collapse</m> normalization method removes all
        leading and trailing whitespace and all the other sequences of
        contiguous whitespace are replaced by a single space.</desc>
      </commanddef>

      <commanddef>
        <command><cmd>negativeInteger</cmd> <m>?(xsd|tcl)?</m></command>
        <desc>This text constraint match the same text values as the
        <m>integer</m> text constraint (see there) with the additional
        constraint that the value must be &lt; zero.</desc>
      </commanddef>
      
................................................................................
            <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>
      <commanddef>
        <command><cmd>id</cmd> <m>?keySpace?</m></command>
        <desc>This text constraint command marks the text as a

Changes to generic/schema.c.

80
81
82
83
84
85
86



87
88
89
90
91
92
93
...
765
766
767
768
769
770
771



772
773
774
775
776
777
778
....
5579
5580
5581
5582
5583
5584
5585
5586
5587
5588
5589
5590
5591
5592
5593
....
7977
7978
7979
7980
7981
7982
7983

























































































































































7984
7985
7986
7987
7988
7989
7990
....
8126
8127
8128
8129
8130
8131
8132


8133
8134
8135
8136
#endif
#ifndef URI_BUFFER_LEN_INIT
#  define URI_BUFFER_LEN_INIT 128
#endif
#ifndef ATTR_ARRAY_INIT
#  define ATTR_ARRAY_INIT 4
#endif




/*----------------------------------------------------------------------------
|   Local defines
|
\---------------------------------------------------------------------------*/
#ifndef O_BINARY
# ifdef _O_BINARY
................................................................................
        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
................................................................................
            REMEMBER_PATTERN (pattern);
            Tcl_SetHashValue (h, pattern);
        }
        addToContent (sdata, pattern, quant, n, m);
    } else {
        /* Local definition of this element */
        if (hnew) {
            pattern = initSchemaCP (
                SCHEMA_CTYPE_NAME,
                sdata->currentNamespace,
                Tcl_GetHashKey (hashTable, h)
                );
            pattern->flags |= PLACEHOLDER_PATTERN_DEF;
            REMEMBER_PATTERN (pattern);
            Tcl_SetHashValue (h, pattern);
................................................................................
    checkNrArgs (2,2,"<tcl variable name>");
    ADD_CONSTRAINT (sdata, sc)
    sc->constraint = setvarImpl;
    sc->freeData = setvarImplFree;
    sc->constraintData = tdomstrdup (Tcl_GetString (objv[1]));
    return TCL_OK;
}


























































































































































void
tDOM_SchemaInit (
    Tcl_Interp *interp
    )
{
    Tcl_CreateObjCommand (interp, "tdom::schema", tDOM_SchemaObjCmd,
................................................................................
                          unsignedIntTypesTCObjCmd, (ClientData) 1, NULL);
    Tcl_CreateObjCommand (interp,"tdom::schema::text::unsignedInt",
                          unsignedIntTypesTCObjCmd, (ClientData) 2, NULL);
    Tcl_CreateObjCommand (interp,"tdom::schema::text::unsignedLong",
                          unsignedIntTypesTCObjCmd, (ClientData) 3, NULL);
    Tcl_CreateObjCommand (interp,"tdom::schema::text::setvar",
                          setvarTCObjCmd, (ClientData) 3, NULL);


}


#endif  /* #ifndef TDOM_NO_SCHEMA */







>
>
>







 







>
>
>







 







|







 







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







 







>
>




80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
...
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
....
5585
5586
5587
5588
5589
5590
5591
5592
5593
5594
5595
5596
5597
5598
5599
....
7983
7984
7985
7986
7987
7988
7989
7990
7991
7992
7993
7994
7995
7996
7997
7998
7999
8000
8001
8002
8003
8004
8005
8006
8007
8008
8009
8010
8011
8012
8013
8014
8015
8016
8017
8018
8019
8020
8021
8022
8023
8024
8025
8026
8027
8028
8029
8030
8031
8032
8033
8034
8035
8036
8037
8038
8039
8040
8041
8042
8043
8044
8045
8046
8047
8048
8049
8050
8051
8052
8053
8054
8055
8056
8057
8058
8059
8060
8061
8062
8063
8064
8065
8066
8067
8068
8069
8070
8071
8072
8073
8074
8075
8076
8077
8078
8079
8080
8081
8082
8083
8084
8085
8086
8087
8088
8089
8090
8091
8092
8093
8094
8095
8096
8097
8098
8099
8100
8101
8102
8103
8104
8105
8106
8107
8108
8109
8110
8111
8112
8113
8114
8115
8116
8117
8118
8119
8120
8121
8122
8123
8124
8125
8126
8127
8128
8129
8130
8131
8132
8133
8134
8135
8136
8137
8138
8139
8140
8141
8142
8143
8144
8145
8146
8147
8148
8149
....
8285
8286
8287
8288
8289
8290
8291
8292
8293
8294
8295
8296
8297
#endif
#ifndef URI_BUFFER_LEN_INIT
#  define URI_BUFFER_LEN_INIT 128
#endif
#ifndef ATTR_ARRAY_INIT
#  define ATTR_ARRAY_INIT 4
#endif
#ifndef WHITESPACETC_BUFFER_LEN_INIT
#  define WHITESPACETC_BUFFER_LEN_INIT 200
#endif

/*----------------------------------------------------------------------------
|   Local defines
|
\---------------------------------------------------------------------------*/
#ifndef O_BINARY
# ifdef _O_BINARY
................................................................................
        ks = Tcl_GetHashValue (h);
        if (ks->active) {
            Tcl_DeleteHashTable (&ks->ids);
        }
        FREE (ks);
    }
    Tcl_DeleteHashTable (&sdata->keySpaces);
    if (sdata->wsbufLen) {
        FREE (sdata->wsbuf);
    }
    FREE (sdata);
}

static void
cleanupLastPattern (
    SchemaData *sdata,
    unsigned int from
................................................................................
            REMEMBER_PATTERN (pattern);
            Tcl_SetHashValue (h, pattern);
        }
        addToContent (sdata, pattern, quant, n, m);
    } else {
        /* Local definition of this element */
        if (hnew) {
            pattern = initSchemaCP(
                SCHEMA_CTYPE_NAME,
                sdata->currentNamespace,
                Tcl_GetHashKey (hashTable, h)
                );
            pattern->flags |= PLACEHOLDER_PATTERN_DEF;
            REMEMBER_PATTERN (pattern);
            Tcl_SetHashValue (h, pattern);
................................................................................
    checkNrArgs (2,2,"<tcl variable name>");
    ADD_CONSTRAINT (sdata, sc)
    sc->constraint = setvarImpl;
    sc->freeData = setvarImplFree;
    sc->constraintData = tdomstrdup (Tcl_GetString (objv[1]));
    return TCL_OK;
}

typedef struct
{
    SchemaCP *cp;
    SchemaData *sdata;
} WhitespaceTCData;

static void
whitespaceImplFree (
    void *constraintData
    )
{
    WhitespaceTCData *wsdata = (WhitespaceTCData *) constraintData;

    FREE (wsdata);
}

static int
whitespaceImplReplace (
    Tcl_Interp *interp,
    void *constraintData,
    char *text
    )
{
    WhitespaceTCData *wsdata = (WhitespaceTCData *) constraintData;
    char *p, *c, *alloced;
    SchemaData *sdata;

    sdata = wsdata->sdata;
    p = text;
    c = sdata->wsbuf;
    alloced = sdata->wsbuf + sdata->wsbufLen;
    while (*p) {
        if (*p == '\t' || *p == '\n' || *p == '\r') {
            *c = ' ';
        } else {
            *c = *p;
        }
        c++;
        if (c == alloced) {
            sdata->wsbuf = REALLOC (sdata->wsbuf, 2 * sdata->wsbufLen);
            c = sdata->wsbuf + sdata->wsbufLen;
            sdata->wsbufLen *= 2;
            alloced = sdata->wsbuf + sdata->wsbufLen;
        }
        p++;
    }
    *c = '\0';
    return checkText (interp, wsdata->cp, sdata->wsbuf);
}

static int
whitespaceImplCollapse (
    Tcl_Interp *interp,
    void *constraintData,
    char *text
    )
{
    WhitespaceTCData *wsdata = (WhitespaceTCData *) constraintData;
    char *p, *c, *alloced;
    SchemaData *sdata;

    sdata = wsdata->sdata;
    p = text;
    c = sdata->wsbuf;
    alloced = sdata->wsbuf + sdata->wsbufLen;
    while (IS_XML_WHITESPACE(*p)) p++;
    while (*p) {
        if (IS_XML_WHITESPACE (*p)) {
            *c = ' ';
            c++;
            if (c == alloced) {
                sdata->wsbuf = REALLOC (sdata->wsbuf, 2 * sdata->wsbufLen);
                c = sdata->wsbuf + sdata->wsbufLen;
                sdata->wsbufLen *= 2;
                alloced = sdata->wsbuf + sdata->wsbufLen;
            }
            p++;
            while (IS_XML_WHITESPACE (*p)) p++;
            if (!*p) c--;
        } else {
            *c = *p;
            c++;
            if (c == alloced) {
                sdata->wsbuf = REALLOC (sdata->wsbuf, 2 * sdata->wsbufLen);
                c = sdata->wsbuf + sdata->wsbufLen;
                sdata->wsbufLen *= 2;
                alloced = sdata->wsbuf + sdata->wsbufLen;
            }
            p++;
        }
    }
    *c = '\0';
    return checkText (interp, wsdata->cp, wsdata->sdata->wsbuf);
}

static int
whitespaceTCObjCmd (
    ClientData clientData,
    Tcl_Interp *interp,
    int objc,
    Tcl_Obj *const objv[]
    )
{
    SchemaData *sdata = GETASI;
    SchemaCP *cp;
    SchemaConstraint *sc;
    int type;
    WhitespaceTCData *wsdata;

    static const char *types[] = {
        "preserve", "replace", "collapse", NULL
    };
    enum typeSyms {
        t_preserve, t_replace, t_collapse
    };
        
    CHECK_TI
    checkNrArgs (3,3,"(\"preserve\"|\"replace\"|\"collapse\") "
                 "<text constraint script>");
    if (Tcl_GetIndexFromObj (interp, objv[1], types, "type", 0, &type)
        != TCL_OK) {
        return TCL_ERROR;
    }
    cp = initSchemaCP (SCHEMA_CTYPE_CHOICE, NULL, NULL);
    cp->type = SCHEMA_CTYPE_TEXT;
    REMEMBER_PATTERN (cp)
    if (evalConstraints (interp, sdata, cp, objv[2]) != TCL_OK) {
        return TCL_ERROR;
    }
    if (type == t_preserve) {
        ADD_CONSTRAINT (sdata, sc)
        sc->constraint = checkText;
        sc->constraintData = (void *)cp;
        return TCL_OK;
    }
    ADD_CONSTRAINT (sdata, sc)
    sc->freeData = whitespaceImplFree;
    if (sdata->wsbufLen == 0) {
        sdata->wsbuf = (char *) MALLOC (WHITESPACETC_BUFFER_LEN_INIT);
        sdata->wsbufLen = WHITESPACETC_BUFFER_LEN_INIT;
    }
    wsdata = TMALLOC (WhitespaceTCData);
    wsdata->sdata = sdata;
    wsdata->cp = cp;
    sc->constraintData = (void *)wsdata;
    if (type == t_replace) {
        sc->constraint = whitespaceImplReplace;
    } else {
        sc->constraint = whitespaceImplCollapse;
    }
    return TCL_OK;
}

void
tDOM_SchemaInit (
    Tcl_Interp *interp
    )
{
    Tcl_CreateObjCommand (interp, "tdom::schema", tDOM_SchemaObjCmd,
................................................................................
                          unsignedIntTypesTCObjCmd, (ClientData) 1, NULL);
    Tcl_CreateObjCommand (interp,"tdom::schema::text::unsignedInt",
                          unsignedIntTypesTCObjCmd, (ClientData) 2, NULL);
    Tcl_CreateObjCommand (interp,"tdom::schema::text::unsignedLong",
                          unsignedIntTypesTCObjCmd, (ClientData) 3, NULL);
    Tcl_CreateObjCommand (interp,"tdom::schema::text::setvar",
                          setvarTCObjCmd, (ClientData) 3, NULL);
    Tcl_CreateObjCommand (interp,"tdom::schema::text::whitespace",
                          whitespaceTCObjCmd, (ClientData) 3, NULL);
}


#endif  /* #ifndef TDOM_NO_SCHEMA */

Changes to generic/schema.h.

194
195
196
197
198
199
200


201
202
203
204
205
206
207
    Tcl_HashTable idTables;
    Tcl_HashTable keySpaces;
    XML_Parser parser;
    domNode *node;
    domNode *insideNode;
    int choiceHashThreshold;
    int attributeHashThreshold;


} SchemaData;

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







>
>







194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
    Tcl_HashTable idTables;
    Tcl_HashTable keySpaces;
    XML_Parser parser;
    domNode *node;
    domNode *insideNode;
    int choiceHashThreshold;
    int attributeHashThreshold;
    char *wsbuf;
    int wsbufLen;
} SchemaData;

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

Changes to tests/schema.test.

5741
5742
5743
5744
5745
5746
5747











































































































































































5748
5749
5750
5751
5752
5753
5754
        element a ! {text {setvar from_schema-14.44}}
        element b ! {text {setvar from_schema-14.44}}
    }
    set result [s validate "<doc><a>a</a><b>b</b></doc>"]
    s delete
    lappend result ${from_schema-14.44}
} {1 b}












































































































































































test schema-15.1 {constraint cmd tcl} {
    tdom::schema s
    s define {
        defelement a {
            tcl append ::schema-15.1 [self]
            element b







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







5741
5742
5743
5744
5745
5746
5747
5748
5749
5750
5751
5752
5753
5754
5755
5756
5757
5758
5759
5760
5761
5762
5763
5764
5765
5766
5767
5768
5769
5770
5771
5772
5773
5774
5775
5776
5777
5778
5779
5780
5781
5782
5783
5784
5785
5786
5787
5788
5789
5790
5791
5792
5793
5794
5795
5796
5797
5798
5799
5800
5801
5802
5803
5804
5805
5806
5807
5808
5809
5810
5811
5812
5813
5814
5815
5816
5817
5818
5819
5820
5821
5822
5823
5824
5825
5826
5827
5828
5829
5830
5831
5832
5833
5834
5835
5836
5837
5838
5839
5840
5841
5842
5843
5844
5845
5846
5847
5848
5849
5850
5851
5852
5853
5854
5855
5856
5857
5858
5859
5860
5861
5862
5863
5864
5865
5866
5867
5868
5869
5870
5871
5872
5873
5874
5875
5876
5877
5878
5879
5880
5881
5882
5883
5884
5885
5886
5887
5888
5889
5890
5891
5892
5893
5894
5895
5896
5897
5898
5899
5900
5901
5902
5903
5904
5905
5906
5907
5908
5909
5910
5911
5912
5913
5914
5915
5916
5917
5918
5919
5920
5921
5922
5923
5924
5925
        element a ! {text {setvar from_schema-14.44}}
        element b ! {text {setvar from_schema-14.44}}
    }
    set result [s validate "<doc><a>a</a><b>b</b></doc>"]
    s delete
    lappend result ${from_schema-14.44}
} {1 b}

test schema-14.45 {text constraint whitespace} {
    tdom::schema s
    s defelement doc {
        text {
            whitespace preserve {
                oneOf {
                    fixed foo
                    allOf {
                        minLength 5
                        integer
                    }
                }
            }
        }
    }
    set result [list]
    foreach xml {
        <doc/>
        <doc></doc>
        <doc>foo</doc>
        <doc>12345</doc>
        <doc>1234</doc>
        <doc>1234a</doc>
    } {
        lappend result [s validate $xml]
    }
    s delete
    set result
} {0 0 1 1 0 0}

test schema-14.46 {text constraint whitespace} {
    tdom::schema s
    s defelement doc {
        text {
            whitespace replace {
                fixed "foo bar"
            }
        }
    }
    set result [list]
    foreach xml {
        <doc/>
        <doc></doc>
        {<doc>foo bar</doc>}
        {<doc>foo
bar</doc>}
        {<doc>foo	bar</doc>}
        {<doc>foo	 bar</doc>}
    } {
        lappend result [s validate $xml]
    }
    s delete
    set result
} {0 0 1 1 1 0}

test schema-14.47 {text constraint whitespace} {
    tdom::schema s
    s defelement doc {
        text {
            whitespace collapse {
                fixed "foo bar"
            }
        }
    }
    set result [list]
    foreach xml {
        <doc/>
        <doc></doc>
        {<doc>foo bar</doc>}
        {<doc>foo
bar</doc>}
        {<doc>foo	bar</doc>}
        {<doc>foo	 bar</doc>}
        {<doc>  foo  bar  </doc>}
        {<doc>  foo  bar  rr</doc>}
    } {
        lappend result [s validate $xml]
    }
    s delete
    set result
} {0 0 1 1 1 1 1 0}

test schema-14.48 {text constraint whitespace} {
    tdom::schema s
    s defelement doc {
        text {
            whitespace preserve {
                fixed "foo[string repeat " " 300]bar"
            }
        }
    }
    set xmls {
        <doc/>
    }
    lappend xmls "<doc>foo[string repeat " " 300]bar</doc>"
    set result [list]
    foreach xml $xmls {
        lappend result [s validate $xml]
    }
    s delete
    set result
} {0 1}

test schema-14.49 {text constraint whitespace} {
    tdom::schema s
    s defelement doc {
        text {
            whitespace collapse {
                fixed "foo [string repeat "x" 1200]bar"
            }
        }
    }
    set xmls {
        <doc/>
    }
    lappend xmls "<doc>[string repeat " " 300]foo[string repeat " " 300][string repeat "x" 1200]bar[string repeat " " 300]</doc>"
    set result [list]
    foreach xml $xmls {
        lappend result [s validate $xml]
    }
    s delete
    set result
} {0 1}

test schema-14.50 {text constraint whitespace} {
    tdom::schema s
    s defelement doc {
        element b ! {
            text {
                whitespace replace {
                    fixed "foo[string repeat " " 400]bar"
                }
            }
        }
    }
    set xml <doc> 
    append xml <b> foo [string repeat "&#xA; \t&#xD;" 100] bar </b>
    append xml </doc>
    set result [s validate $xml]
    s delete
    set result
} 1

test schema-14.51 {text constraint whitespace} {
    tdom::schema s
    s defelement doc {
        element a ! {
            text {
                whitespace collapse {
                    fixed "foo [string repeat "x" 1200]bar"
                }
            }
        }
        element b ! {
            text {
                whitespace replace {
                    fixed "foo[string repeat " " 8000]bar"
                }
            }
        }
    }
    set xml <doc> 
    append xml <a> [string repeat " " 20] foo " " [string repeat x 1200] bar \
        [string repeat " " 8000] </a>
    append xml <b> foo [string repeat "&#xA; \t&#xD;" 2000] bar </b>
    append xml </doc>
    set result [s validate $xml]
    s delete
    set result
} 1

test schema-15.1 {constraint cmd tcl} {
    tdom::schema s
    s define {
        defelement a {
            tcl append ::schema-15.1 [self]
            element b