tDOM

Check-in [6a51d9897b]
Login
Bounty program for improvements to Tcl and certain Tcl packages.
Tcl 2019 Conference, Houston/TX, US, Nov 4-8
Send your abstracts to [email protected]
or submit via the online form by Sep 9.

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

Overview
Comment:Added optional flag argument to domunique. Currently only flag controls, if empty field node sets are ignored (or seen as the empty string).
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | domlocalkey
Files: files | file ages | folders
SHA3-256: 6a51d9897b925cf9f5927ed0d16da73495ed384a3767991e777e8e399ce335fd
User & Date: rolf 2019-05-21 22:24:06
Original Comment: Added optional flag argument to domunique. Currently only flag controls, if empty field not sets are ignored (or seen as the empty string).
Context
2019-05-21
22:30
Added dom tree validation specific unique key contraints along the lines of xsd unqiue with selector and list of fields but with no restrictions on the XPath expressions (other then resulting a node set in case of selector and a result set with one node in case of field XPath expression). check-in: ba6bd2bb7c user: rolf tags: schema
22:24
Added optional flag argument to domunique. Currently only flag controls, if empty field node sets are ignored (or seen as the empty string). Closed-Leaf check-in: 6a51d9897b user: rolf tags: domlocalkey
16:21
Adding DOM tree postvalidation (only) local key constraints along the lines of xsd unqiue with selector and list of fields but with no restrictions on the XPath expressions (other then resulting a node set in case of selector and a result set with one node in case of field XPath expression). check-in: f645e5dfe1 user: rolf tags: domlocalkey
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to generic/schema.c.

82
83
84
85
86
87
88







89
90
91
92
93
94
95
..
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
...
368
369
370
371
372
373
374

375
376
377
378
379
380
381
....
2160
2161
2162
2163
2164
2165
2166



2167
2168
2169
2170
2171
2172
2173
....
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
....
2233
2234
2235
2236
2237
2238
2239



2240
2241
2242
2243
2244
2245
2246
....
3665
3666
3667
3668
3669
3670
3671
3672
3673
3674
3675
3676
3677
3678
3679
3680
























3681
3682
3683
3684
3685
3686
3687
3688
3689
3690
3691
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706

3707
3708
3709
3710
3711
3712
3713
    Tcl_Interp    *interp;
    XML_Parser     parser;
    Tcl_DString   *cdata;
    int            onlyWhiteSpace;
    char          *uri;
    int            maxUriLen;
} ValidateMethodData;








/*----------------------------------------------------------------------------
|   Macros
|
\---------------------------------------------------------------------------*/
#define TMALLOC(t) (t*)MALLOC(sizeof(t))

................................................................................
#define SetResult3(str1,str2,str3) Tcl_ResetResult(interp);     \
                     Tcl_AppendResult(interp, (str1), (str2), (str3), NULL)
#define SetIntResult(i) Tcl_ResetResult(interp);                        \
                     Tcl_SetIntObj(Tcl_GetObjResult(interp), (i))
#define SetBooleanResult(i) Tcl_ResetResult(interp); \
                     Tcl_SetBooleanObj(Tcl_GetObjResult(interp), (i))

#define SPACE(c) ((c) == ' ' || (c) == '\n' || (c )== '\t' || (c) == '\r')
    
#define checkNrArgs(l,h,err) if (objc < l || objc > h) {      \
        SetResult (err);                                      \
        return TCL_ERROR;                                     \
    }

#if defined(DEBUG) || defined(DDEBUG)
................................................................................
        se = se->down;
    }
    fprintf (stderr, "++++ Stack bottom\n");
}
)

/* DBG end */


static void freedomKeyConstraints (
    domKeyConstraint *kc
    )
{
    domKeyConstraint *knext;
    int i;
................................................................................
                    if (recover (interp, sdata, S("INVALID_DOM_KEYCONSTRAINT"))) {
                        break;
                    }
                    SetResult ("INVALID_DOM_KEYCONSTRAINT");
                    goto errorCleanup;
                }
                if (frs.type == EmptyResult || frs.nr_nodes == 0) {



                    Tcl_CreateHashEntry (&htable, "", &hnew);
                    if (!hnew) {
                        if (recover (interp, sdata, S("DOM_KEYCONSTRAINT"))) {
                            break;
                        }
                        SetResult ("DOM_KEYCONSTRAINT");
                        goto errorCleanup;
................................................................................
                        }
                        SetResult ("DOM_KEYCONSTRAINT");
                        goto errorCleanup;
                    }
                }
            } else {
                Tcl_DStringSetLength (&dStr, 0);
                skip = 1;
                first = 0;
                for (j = 0; j < kc->nrFields; j++) {
                    xpathRSReset (&frs, NULL);
                    rc = xpathEvalAst (kc->fields[j], &nodeList, n, &frs,
                                       &errMsg);
                    if (rc) {
                        if (recover (interp, sdata, S("INVALID_DOM_KEYCONSTRAINT"))) {
                            skip = 1;
................................................................................
                            skip = 1;
                            break;
                        }
                        SetResult ("INVALID_DOM_KEYCONSTRAINT");
                        goto errorCleanup;
                    }
                    if (frs.type == EmptyResult || frs.nr_nodes == 0) {



                        if (first) first = 0;
                        else Tcl_DStringAppend (&dStr, ":", 1);
                        continue;
                    }
                    if (frs.nr_nodes != 1) {
                        if (recover (interp, sdata, S("DOM_KEYCONSTRAINT"))) {
                            skip = 1;
................................................................................
    Tcl_Obj *const objv[]
    )
{
    SchemaData *sdata = GETASI;
    ast t;
    char *errMsg = NULL;
    domKeyConstraint *kc;
    int i, nrFields;
    Tcl_Obj *elm;

    CHECK_SI
    CHECK_TOPLEVEL
    checkNrArgs (3,4,"Expected: <selector> <fieldlist> ?<name>?");
    if (sdata->cp->type != SCHEMA_CTYPE_NAME) {
        SetResult ("The domunique schema definition command is only "
                   "allowed as direct child of an element.");
























    }
    
    if (xpathParse (Tcl_GetString (objv[1]), NULL, XPATH_EXPR,
                    sdata->prefixns, NULL, &t, &errMsg) < 0) {
        SetResult3 ("Error in selector xpath: '", errMsg, "");
        FREE (errMsg);
        return TCL_ERROR;
    }

    if (Tcl_ListObjLength (interp, objv[2], &nrFields) != TCL_OK) {
        SetResult ("The <fieldlist> argument must be a valid tcl list");
        xpathFreeAst (t);
        return TCL_ERROR;
    }
    if (nrFields == 0) {
        SetResult ("Non empty fieldlist arugment expected.");
        xpathFreeAst (t);
        return TCL_ERROR;
    }
    
    kc = TMALLOC (domKeyConstraint);
    memset (kc, 0, sizeof (domKeyConstraint));
    kc->fields = MALLOC (sizeof (ast) * nrFields);
    memset (kc->fields, 0, sizeof (ast) * nrFields);
    kc->nrFields = nrFields;
    kc->selector = t;

    
    for (i = 0; i < nrFields; i++) {
        Tcl_ListObjIndex (interp, objv[2], i, &elm);
        if (xpathParse (Tcl_GetString (elm), NULL, XPATH_EXPR,
                        sdata->prefixns, NULL, &t, &errMsg) < 0) {
            SetResult3 ("Error in field xpath: '", errMsg, "");
            FREE (errMsg);






>
>
>
>
>
>
>







 







|







 







>







 







>
>
>







 







|
|







 







>
>
>







 







|




|



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









<
<
<
<
<
<
<
<
<
<







>







82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
...
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
...
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
....
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
....
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
....
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
....
3679
3680
3681
3682
3683
3684
3685
3686
3687
3688
3689
3690
3691
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709
3710
3711
3712
3713
3714
3715
3716
3717
3718
3719
3720
3721
3722
3723
3724
3725
3726
3727










3728
3729
3730
3731
3732
3733
3734
3735
3736
3737
3738
3739
3740
3741
3742
    Tcl_Interp    *interp;
    XML_Parser     parser;
    Tcl_DString   *cdata;
    int            onlyWhiteSpace;
    char          *uri;
    int            maxUriLen;
} ValidateMethodData;

/*----------------------------------------------------------------------------
|   domKeyConstraint related flage
|
\---------------------------------------------------------------------------*/

#define DKC_FLAG_IGNORE_EMPTY_FIELD_SET 1

/*----------------------------------------------------------------------------
|   Macros
|
\---------------------------------------------------------------------------*/
#define TMALLOC(t) (t*)MALLOC(sizeof(t))

................................................................................
#define SetResult3(str1,str2,str3) Tcl_ResetResult(interp);     \
                     Tcl_AppendResult(interp, (str1), (str2), (str3), NULL)
#define SetIntResult(i) Tcl_ResetResult(interp);                        \
                     Tcl_SetIntObj(Tcl_GetObjResult(interp), (i))
#define SetBooleanResult(i) Tcl_ResetResult(interp); \
                     Tcl_SetBooleanObj(Tcl_GetObjResult(interp), (i))

#define SPACE(c) ((c) == ' ' || (c) == '\n' || (c) == '\t' || (c) == '\r')
    
#define checkNrArgs(l,h,err) if (objc < l || objc > h) {      \
        SetResult (err);                                      \
        return TCL_ERROR;                                     \
    }

#if defined(DEBUG) || defined(DDEBUG)
................................................................................
        se = se->down;
    }
    fprintf (stderr, "++++ Stack bottom\n");
}
)

/* DBG end */


static void freedomKeyConstraints (
    domKeyConstraint *kc
    )
{
    domKeyConstraint *knext;
    int i;
................................................................................
                    if (recover (interp, sdata, S("INVALID_DOM_KEYCONSTRAINT"))) {
                        break;
                    }
                    SetResult ("INVALID_DOM_KEYCONSTRAINT");
                    goto errorCleanup;
                }
                if (frs.type == EmptyResult || frs.nr_nodes == 0) {
                    if (kc->flags & DKC_FLAG_IGNORE_EMPTY_FIELD_SET) {
                        continue;
                    }
                    Tcl_CreateHashEntry (&htable, "", &hnew);
                    if (!hnew) {
                        if (recover (interp, sdata, S("DOM_KEYCONSTRAINT"))) {
                            break;
                        }
                        SetResult ("DOM_KEYCONSTRAINT");
                        goto errorCleanup;
................................................................................
                        }
                        SetResult ("DOM_KEYCONSTRAINT");
                        goto errorCleanup;
                    }
                }
            } else {
                Tcl_DStringSetLength (&dStr, 0);
                skip = 0;
                first = 1;
                for (j = 0; j < kc->nrFields; j++) {
                    xpathRSReset (&frs, NULL);
                    rc = xpathEvalAst (kc->fields[j], &nodeList, n, &frs,
                                       &errMsg);
                    if (rc) {
                        if (recover (interp, sdata, S("INVALID_DOM_KEYCONSTRAINT"))) {
                            skip = 1;
................................................................................
                            skip = 1;
                            break;
                        }
                        SetResult ("INVALID_DOM_KEYCONSTRAINT");
                        goto errorCleanup;
                    }
                    if (frs.type == EmptyResult || frs.nr_nodes == 0) {
                        if (kc->flags & DKC_FLAG_IGNORE_EMPTY_FIELD_SET) {
                            continue;
                        }
                        if (first) first = 0;
                        else Tcl_DStringAppend (&dStr, ":", 1);
                        continue;
                    }
                    if (frs.nr_nodes != 1) {
                        if (recover (interp, sdata, S("DOM_KEYCONSTRAINT"))) {
                            skip = 1;
................................................................................
    Tcl_Obj *const objv[]
    )
{
    SchemaData *sdata = GETASI;
    ast t;
    char *errMsg = NULL;
    domKeyConstraint *kc;
    int i, nrFields, flags = 0, nrFlags;
    Tcl_Obj *elm;

    CHECK_SI
    CHECK_TOPLEVEL
    checkNrArgs (3, 5, "Expected: <selector> <fieldlist> ?<name>? ?flags?");
    if (sdata->cp->type != SCHEMA_CTYPE_NAME) {
        SetResult ("The domunique schema definition command is only "
                   "allowed as direct child of an element.");
    }
    if (Tcl_ListObjLength (interp, objv[2], &nrFields) != TCL_OK) {
        SetResult ("The <fieldlist> argument must be a valid tcl list");
        return TCL_ERROR;
    }
    if (nrFields == 0) {
        SetResult ("Non empty fieldlist arugment expected.");
        xpathFreeAst (t);
        return TCL_ERROR;
    }
    if (objc == 5) {
        if (Tcl_ListObjLength (interp, objv[4], &nrFlags) != TCL_OK) {
            SetResult ("The <flags> argument must be a valid tcl list");
            return TCL_ERROR;
        }
        for (i = 0; i < nrFlags; i++) {
            Tcl_ListObjIndex (interp, objv[4], i, &elm);
            if (strcmp ("IGNORE_EMPTY_FIELD_SET", Tcl_GetString (elm)) == 0) {
                flags |= DKC_FLAG_IGNORE_EMPTY_FIELD_SET;
                continue;
            }
            SetResult3 ("Unknown flag '", Tcl_GetString (elm), "'");
            return TCL_ERROR;
        }
    }
    
    if (xpathParse (Tcl_GetString (objv[1]), NULL, XPATH_EXPR,
                    sdata->prefixns, NULL, &t, &errMsg) < 0) {
        SetResult3 ("Error in selector xpath: '", errMsg, "");
        FREE (errMsg);
        return TCL_ERROR;
    }











    
    kc = TMALLOC (domKeyConstraint);
    memset (kc, 0, sizeof (domKeyConstraint));
    kc->fields = MALLOC (sizeof (ast) * nrFields);
    memset (kc->fields, 0, sizeof (ast) * nrFields);
    kc->nrFields = nrFields;
    kc->selector = t;
    kc->flags = flags;
    
    for (i = 0; i < nrFields; i++) {
        Tcl_ListObjIndex (interp, objv[2], i, &elm);
        if (xpathParse (Tcl_GetString (elm), NULL, XPATH_EXPR,
                        sdata->prefixns, NULL, &t, &errMsg) < 0) {
            SetResult3 ("Error in field xpath: '", errMsg, "");
            FREE (errMsg);

Changes to generic/schema.h.

76
77
78
79
80
81
82

83
84
85
86
87
88
89
#define MIXED_CONTENT          32 

typedef struct domKeyConstraint {
    char  *name;
    ast    selector;
    ast   *fields;
    int    nrFields;

    struct domKeyConstraint *next;
} domKeyConstraint;

typedef struct SchemaCP
{
    Schema_CP_Type    type;
    char             *namespace;






>







76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#define MIXED_CONTENT          32 

typedef struct domKeyConstraint {
    char  *name;
    ast    selector;
    ast   *fields;
    int    nrFields;
    int    flags;
    struct domKeyConstraint *next;
} domKeyConstraint;

typedef struct SchemaCP
{
    Schema_CP_Type    type;
    char             *namespace;

Changes to tests/schema.test.

4660
4661
4662
4663
4664
4665
4666

























4667
4668
4669
4670
4671
4672
4673
4674
4675
4676
4677
4678
4679
....
4701
4702
4703
4704
4705
4706
4707

4708
4709
4710
4711
4712
4713
4714
            }
        }
    }
    set result [list]
    foreach xml {
        {<doc><item ref="1"/><item ref="foo"/></doc>}
        {<doc><item ref="1"/><item ref="1"/></doc>}

























    } {
        lappend result [postValidation s $xml]
    }
    s delete
    set result
} {1 0}

test schema-20.3 {domunique} {
    tdom::schema s
    s define {
        defelement doc {
            element items * {
                element item * {
................................................................................
test schema-20.4 {domunique} {
    tdom::schema s
    s define {
        defelement doc {
            domunique item {@ref @id}
            element item * {
                attribute ref ?

            }
        }
    }
    set result [list]
    foreach xml {
        {<doc><item ref="1"/><item ref="foo"/></doc>}
        {<doc><item ref="1"/><item ref="1"/></doc>}






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





|







 







>







4660
4661
4662
4663
4664
4665
4666
4667
4668
4669
4670
4671
4672
4673
4674
4675
4676
4677
4678
4679
4680
4681
4682
4683
4684
4685
4686
4687
4688
4689
4690
4691
4692
4693
4694
4695
4696
4697
4698
4699
4700
4701
4702
4703
4704
....
4726
4727
4728
4729
4730
4731
4732
4733
4734
4735
4736
4737
4738
4739
4740
            }
        }
    }
    set result [list]
    foreach xml {
        {<doc><item ref="1"/><item ref="foo"/></doc>}
        {<doc><item ref="1"/><item ref="1"/></doc>}
        {<doc><item/><item ref="1"/></doc>}
        {<doc><item/><item/></doc>}
    } {
        lappend result [postValidation s $xml]
    }
    s delete
    set result
} {1 0 1 0}

test schema-20.2a {domunique} {
    tdom::schema s
    s define {
        defelement doc {
            domunique item @ref itemrefkey IGNORE_EMPTY_FIELD_SET
            element item * {
                attribute ref ?
            }
        }
    }
    set result [list]
    foreach xml {
        {<doc><item ref="1"/><item ref="foo"/></doc>}
        {<doc><item ref="1"/><item ref="1"/></doc>}
        {<doc><item/><item ref="1"/></doc>}
        {<doc><item/><item/></doc>}
    } {
        lappend result [postValidation s $xml]
    }
    s delete
    set result
} {1 0 1 1}

test schema-20.3 {domunique} {
    tdom::schema s
    s define {
        defelement doc {
            element items * {
                element item * {
................................................................................
test schema-20.4 {domunique} {
    tdom::schema s
    s define {
        defelement doc {
            domunique item {@ref @id}
            element item * {
                attribute ref ?
                attribute id ?
            }
        }
    }
    set result [list]
    foreach xml {
        {<doc><item ref="1"/><item ref="foo"/></doc>}
        {<doc><item ref="1"/><item ref="1"/></doc>}