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

Overview
Comment:For a domunique constraint now the key value of an empty fieldset node set result can be given.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | schema
Files: files | file ages | folders
SHA3-256: 426dea4ca8a156acdc0c2910e5ec6dd278c46e80dc3658a7f3d68c79c7082d23
User & Date: rolf 2020-05-27 00:20:25
Context
2020-05-27
00:34
Integrated bug fix branch: Handling of not per quantifier but per all childs optional content particle. check-in: 32945e114c user: rolf tags: schema
00:20
For a domunique constraint now the key value of an empty fieldset node set result can be given. check-in: 426dea4ca8 user: rolf tags: schema
2020-05-20
14:01
Fixed gross bug in info expected, which just was not triggered so far. check-in: 910d0dbb65 user: rolf tags: schema
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to doc/schema.xml.

615
616
617
618
619
620
621
622
623
624
625
626
627
628
629








630
631
632
633
634
635
636
        <m>data</m> with the currently defined content particle and
        may be requested in scripts evaluated while validating the
        content of that particle with the schema command method call
        <m>info stack associated</m>.</desc>
      </commanddef>

      <commanddef>
        <command><method>domunique</method> <m>selector</m> <m>fieldlist</m> <m>?name?</m> <m>?IGNORE_EMPTY_FIELD_SET?</m></command>
        <desc>If not postvalidating a DOM tree with <m>domvalidate</m>
        this constraint always match. If postvalidating this
        constraint resembles the xsd key/keyref mechanism. The
        <m>selector</m> argument may be any valid XPath expression
        (without the xsd limits). Several <m>domunique</m> command
        within one element definition are allowed. They are checked
        in definition order. </desc>








      </commanddef>

      <commanddef>
        <command><method>domxpathboolean</method> <m>XPath_expr</m> <m>?name?</m></command>
        <desc><p>If not postvalidating a DOM tree with
        <m>domvalidate</m> this constraint always match. If
        postvalidating this constraint matches if the result of the







|





|
|
>
>
>
>
>
>
>
>







615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
        <m>data</m> with the currently defined content particle and
        may be requested in scripts evaluated while validating the
        content of that particle with the schema command method call
        <m>info stack associated</m>.</desc>
      </commanddef>

      <commanddef>
        <command><method>domunique</method> <m>selector</m> <m>fieldlist</m> <m>?name?</m> <m>?"IGNORE_EMPTY_FIELD_SET"|("EMPTY_FIELD_SET_VALUE" emptyFieldSetValue)?</m></command>
        <desc>If not postvalidating a DOM tree with <m>domvalidate</m>
        this constraint always match. If postvalidating this
        constraint resembles the xsd key/keyref mechanism. The
        <m>selector</m> argument may be any valid XPath expression
        (without the xsd limits). Several <m>domunique</m> command
        within one element definition are allowed. They are checked in
        definition order. The argument name is avaliable in the
        recovering script per <m>info vaction name</m>. If the
        <m>fieldlist</m> doesn't select something for a node of the
        result set of the <m>selector</m> then the key value will be
        the empty string, by default. If the arguments
        <m>EMPTY_FIELD_SET_VALUE &lt;value></m> are given a empty node
        set will have the key value <m>value</m>. If instead the flag
        <m>IGNORE_EMPTY_FIELD_SET</m> flag is given then an empty node
        set result will not have any key value.</desc>
      </commanddef>

      <commanddef>
        <command><method>domxpathboolean</method> <m>XPath_expr</m> <m>?name?</m></command>
        <desc><p>If not postvalidating a DOM tree with
        <m>domvalidate</m> this constraint always match. If
        postvalidating this constraint matches if the result of the

Changes to generic/schema.c.

556
557
558
559
560
561
562

563
564
565
566
567
568
569
....
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
....
3229
3230
3231
3232
3233
3234
3235




3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
....
3300
3301
3302
3303
3304
3305
3306

3307
3308






3309
3310
3311
3312
3313
3314
3315
....
5926
5927
5928
5929
5930
5931
5932
5933
5934
5935
5936
5937
5938
5939
5940
5941
5942
5943
5944
5945
5946
5947
5948
5949
5950
5951
5952
5953
5954
5955
5956
5957
5958
5959
5960
5961


5962
5963
5964
5965
5966
5967
5968
5969
5970
5971
5972
5973
5974
5975
5976
5977
5978
5979
5980
5981
5982
5983
5984
5985
5986
5987
5988
5989
5990
5991
5992
5993
5994
5995
5996
5997




5998
5999
6000
6001
6002
6003
6004
{
    domKeyConstraint *knext;
    int i;

    while (kc) {
        knext = kc->next;
        if (kc->name) FREE (kc->name);

        xpathFreeAst (kc->selector);
        for (i = 0; i < kc->nrFields; i++) {
            xpathFreeAst (kc->fields[i]);
        }
        FREE (kc->fields);
        FREE (kc);
        kc = knext;
................................................................................
    )
{
    xpathResultSet nodeList, rs, frs;
    domKeyConstraint *kc;
    domNode *n;
    domAttrNode *attr;
    int rc, i, j, hnew, len, skip, first;
    char *errMsg = NULL, *keystr;
    Tcl_HashTable htable;
    Tcl_DString dStr;

    kc = sdata->stack->pattern->domKeys;
    memset (&nodeList, 0, sizeof (xpathResultSet));
    nodeList.type = EmptyResult;
    memset (&rs, 0, sizeof (xpathResultSet));
................................................................................
                    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, DOM_KEYCONSTRAINT,
                                     kc->name, NULL, "", 0)) {
                            break;
                        }
                        SetResultV ("DOM_KEYCONSTRAINT");
                        goto errorCleanup;
                    }
                    continue;
                }
................................................................................
                        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, DOM_KEYCONSTRAINT,
                                     kc->name, NULL, NULL, 0)) {
                            skip = 1;
                            break;
................................................................................
    Tcl_Obj *const objv[]
    )
{
    SchemaData *sdata = GETASI;
    ast t;
    char *errMsg = NULL;
    domKeyConstraint *kc, *kc1;
    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 argument expected.");
        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);
            xpathFreeAst (t);
            freedomKeyConstraints (kc);
            return TCL_ERROR;
        }
        kc->fields[i] = t;
    }
    if (objc == 4) {
        kc->name = tdomstrdup (Tcl_GetString (objv[3]));
    }




    /* Apppend to end so that the constraints are checked in
     * definition order */
    if (sdata->cp->domKeys) {
        kc1 = sdata->cp->domKeys;
        while (1) {
            if (kc1->next) kc1 = kc1->next;
            else break;







>







 







|







 







>
>
>
>
|


|







 







>
|
|
>
>
>
>
>
>







 







|




|













|
|


<
<
<
|
<
|
>
>
|










<








<












|


>
>
>
>







556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
....
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
....
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
....
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
....
5938
5939
5940
5941
5942
5943
5944
5945
5946
5947
5948
5949
5950
5951
5952
5953
5954
5955
5956
5957
5958
5959
5960
5961
5962
5963
5964
5965
5966
5967



5968

5969
5970
5971
5972
5973
5974
5975
5976
5977
5978
5979
5980
5981
5982

5983
5984
5985
5986
5987
5988
5989
5990

5991
5992
5993
5994
5995
5996
5997
5998
5999
6000
6001
6002
6003
6004
6005
6006
6007
6008
6009
6010
6011
6012
6013
6014
6015
6016
{
    domKeyConstraint *knext;
    int i;

    while (kc) {
        knext = kc->next;
        if (kc->name) FREE (kc->name);
        if (kc->emptyFieldSetValue) FREE (kc->emptyFieldSetValue);
        xpathFreeAst (kc->selector);
        for (i = 0; i < kc->nrFields; i++) {
            xpathFreeAst (kc->fields[i]);
        }
        FREE (kc->fields);
        FREE (kc);
        kc = knext;
................................................................................
    )
{
    xpathResultSet nodeList, rs, frs;
    domKeyConstraint *kc;
    domNode *n;
    domAttrNode *attr;
    int rc, i, j, hnew, len, skip, first;
    char *errMsg = NULL, *keystr, *efsv;
    Tcl_HashTable htable;
    Tcl_DString dStr;

    kc = sdata->stack->pattern->domKeys;
    memset (&nodeList, 0, sizeof (xpathResultSet));
    nodeList.type = EmptyResult;
    memset (&rs, 0, sizeof (xpathResultSet));
................................................................................
                    SetResult ("INVALID_DOM_KEYCONSTRAINT");
                    goto errorCleanup;
                }
                if (frs.type == EmptyResult || frs.nr_nodes == 0) {
                    if (kc->flags & DKC_FLAG_IGNORE_EMPTY_FIELD_SET) {
                        continue;
                    }
                    efsv = "";
                    if (kc->emptyFieldSetValue) {
                        efsv = kc->emptyFieldSetValue;
                    }
                    Tcl_CreateHashEntry (&htable, efsv, &hnew);
                    if (!hnew) {
                        if (recover (interp, sdata, DOM_KEYCONSTRAINT,
                                     kc->name, NULL, efsv, 0)) {
                            break;
                        }
                        SetResultV ("DOM_KEYCONSTRAINT");
                        goto errorCleanup;
                    }
                    continue;
                }
................................................................................
                        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 (kc->emptyFieldSetValue) {
                            if (first) first = 0;
                            else Tcl_DStringAppend (&dStr, ":", 1);
                            Tcl_DStringAppend (&dStr, kc->emptyFieldSetValue,
                                               kc->efsv_len);
                        } else {
                            if (first) first = 0;
                            else Tcl_DStringAppend (&dStr, ":", 1);
                        }
                        continue;
                    }
                    if (frs.nr_nodes != 1) {
                        if (recover (interp, sdata, DOM_KEYCONSTRAINT,
                                     kc->name, NULL, NULL, 0)) {
                            skip = 1;
                            break;
................................................................................
    Tcl_Obj *const objv[]
    )
{
    SchemaData *sdata = GETASI;
    ast t;
    char *errMsg = NULL;
    domKeyConstraint *kc, *kc1;
    int i, nrFields, flags = 0;
    Tcl_Obj *elm;

    CHECK_SI
    CHECK_TOPLEVEL
    checkNrArgs (3, 6, "Expected: <selector> <fieldlist> ?<name>? ?\"IGNORE_EMPTY_FIELD_SET\"|(?\"EMPTY_FIELD_SET_VALUE\" <emptyFieldSetValue?)");
    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 argument expected.");
        return TCL_ERROR;
    }
    if (objc == 5) {
        if (strcmp (Tcl_GetString (objv[4]), "IGNORE_EMPTY_FIELD_SET") != 0) {
            SetResult3 ("Unknown flag '", Tcl_GetString (objv[4]), "'");
            return TCL_ERROR;
        }



        flags |= DKC_FLAG_IGNORE_EMPTY_FIELD_SET;

    }
    if (objc == 6) {
        if (strcmp (Tcl_GetString (objv[4]), "EMPTY_FIELD_SET_VALUE") != 0) {
            SetResult3 ("Unknown flag '", Tcl_GetString (objv[4]), "'");
            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);
            xpathFreeAst (t);
            freedomKeyConstraints (kc);
            return TCL_ERROR;
        }
        kc->fields[i] = t;
    }
    if (objc >= 4) {
        kc->name = tdomstrdup (Tcl_GetString (objv[3]));
    }
    if (objc == 6) {
        kc->emptyFieldSetValue = tdomstrdup (Tcl_GetString (objv[5]));
        kc->efsv_len = strlen (kc->emptyFieldSetValue);
    }
    /* Apppend to end so that the constraints are checked in
     * definition order */
    if (sdata->cp->domKeys) {
        kc1 = sdata->cp->domKeys;
        while (1) {
            if (kc1->next) kc1 = kc1->next;
            else break;

Changes to generic/schema.h.

81
82
83
84
85
86
87


88
89
90
91
92
93
94

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


    struct domKeyConstraint *next;
} domKeyConstraint;

typedef struct 
{
    char *name;
    int active;







>
>







81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96

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

typedef struct 
{
    char *name;
    int active;

Changes to tests/schema.test.

8692
8693
8694
8695
8696
8697
8698























8699
8700
8701
8702
8703
8704
8705
        {<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 * {







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







8692
8693
8694
8695
8696
8697
8698
8699
8700
8701
8702
8703
8704
8705
8706
8707
8708
8709
8710
8711
8712
8713
8714
8715
8716
8717
8718
8719
8720
8721
8722
8723
8724
8725
8726
8727
8728
        {<doc><item/><item/></doc>}
    } {
        lappend result [postValidation s $xml]
    }
    s delete
    set result
} {1 0 1 1}

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

test schema-20.3 {domunique} {
    tdom::schema s
    s define {
        defelement doc {
            element items * {
                element item * {