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

Overview
Comment:Prevent call of the recovery report command in case of probed optional not matching pattern. Added recovery in a so far not handled case.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | schema
Files: files | file ages | folders
SHA3-256: 1ceabd63a5535d0191c65be0ff77b5929724a81ca92cb22d7d07f1feac928ae3
User & Date: rolf 2019-11-15 09:30:55
Context
2019-11-15
10:22
Moved schema command method nrForwardDefinitions as subcommand to info; it belongs more there. check-in: 05086c2182 user: rolf tags: schema
09:30
Prevent call of the recovery report command in case of probed optional not matching pattern. Added recovery in a so far not handled case. check-in: 1ceabd63a5 user: rolf tags: schema
2019-11-14
14:09
Added optional time zone check to text constraint isodate, making it fully xsd:date compliant. check-in: 7cf1968eb3 user: rolf tags: schema
Changes

Changes to generic/schema.c.

964
965
966
967
968
969
970









971
972
973
974
975
976
977
....
2005
2006
2007
2008
2009
2010
2011


2012


2013
2014
2015
2016
2017
2018
2019
....
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048

2049
2050
2051
2052
2053
2054
2055
....
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127

2128
2129
2130
2131
2132
2133
2134
....
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
    )
{
    Tcl_Obj *cmdPtr;
    int rc;
    SchemaValidationStack *se;

    if (!sdata->reportCmd || sdata->evalError) return 0;









    cmdPtr = Tcl_DuplicateObj (sdata->reportCmd);
    Tcl_IncrRefCount(cmdPtr);
    Tcl_ListObjAppendElement (interp, cmdPtr,
                              sdata->self);
    Tcl_ListObjAppendElement (
        interp, cmdPtr,
        Tcl_NewStringObj (ValidationErrorType2str[errorType], -1)
................................................................................
                
            case SCHEMA_CTYPE_INTERLEAVE:
            case SCHEMA_CTYPE_PATTERN:
                pushToStack (sdata, cp->content[ac], ac);
                rc = checkElementEnd (interp, sdata);
                popStack (sdata);
                if (rc) break;


                return 0;


                
            case SCHEMA_CTYPE_ANY:
            case SCHEMA_CTYPE_NAME:
                if (recover (interp, sdata, MISSING_ELEMENT_MATCH_END, NULL,
                             NULL, NULL, 0)) {
                    break;
                }
................................................................................
    case SCHEMA_CTYPE_KEYSPACE:
    case SCHEMA_CTYPE_VIRTUAL:
    case SCHEMA_CTYPE_CHOICE:
    case SCHEMA_CTYPE_TEXT:
    case SCHEMA_CTYPE_ANY:
        /* Never pushed onto stack */
        Tcl_Panic ("Invalid CTYPE onto the validation stack!");
        return 0;

    case SCHEMA_CTYPE_INTERLEAVE:
        for (i = 0; i < cp->nc; i++) {
            if (mustMatch (cp->quants[i], se->interleaveState[i])) {
                if (recover (interp, sdata, MISSING_ELEMENT_MATCH_END, NULL,
                             NULL, NULL, 0)) {
                    break;
                }
                return 0;
            }
        }
        return -1;
    }

    return 0;
}

static int
checkDocKeys (
    Tcl_Interp *interp,
    SchemaData *sdata
................................................................................
probeElementEnd (
    Tcl_Interp *interp,
    SchemaData *sdata
    )
{
    int rc;
    
    DBG(
        fprintf (stderr, "probeElementEnd: look if current stack top can end "
                 " name: '%s' deep: %d\n",
                 sdata->stack->pattern->name, getDeep (sdata->stack));

        );

    if (sdata->skipDeep) {
        sdata->skipDeep--;
        return TCL_OK;
    }
    if (sdata->validationState == VALIDATION_FINISHED) {
................................................................................
    }

    rc = checkElementEnd (interp, sdata);
    while (rc == -1) {
        popStack (sdata);
        rc = checkElementEnd (interp, sdata);
    }

    if (rc) {
        popStack (sdata);
        if (sdata->stack == NULL) {
            /* End of the first pattern (the tree root) without error. */
            /* Check for unknown ID references */
            if (!checkDocKeys (interp, sdata)) {
                return TCL_ERROR;







>
>
>
>
>
>
>
>
>







 







>
>
|
>
>







 







<













>







 







|



>







 







<







964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
....
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
....
2041
2042
2043
2044
2045
2046
2047

2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
....
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
....
2158
2159
2160
2161
2162
2163
2164

2165
2166
2167
2168
2169
2170
2171
    )
{
    Tcl_Obj *cmdPtr;
    int rc;
    SchemaValidationStack *se;

    if (!sdata->reportCmd || sdata->evalError) return 0;
    /* If non SCHEMA_CTYPE_NAME and the pattern hasn't already matched
     * that's a pattern pushed on stack to look for (probe) if it
     * matches (or allows empty match). Even if the pattern fail it
     * may be optional; recovering is done at the caller level in case
     * the pattern isn't optional. */
    if (sdata->stack
        && sdata->stack->pattern->type != SCHEMA_CTYPE_NAME
        && sdata->stack->activeChild == 0
        && sdata->stack->hasMatched == 0) return 0;
    cmdPtr = Tcl_DuplicateObj (sdata->reportCmd);
    Tcl_IncrRefCount(cmdPtr);
    Tcl_ListObjAppendElement (interp, cmdPtr,
                              sdata->self);
    Tcl_ListObjAppendElement (
        interp, cmdPtr,
        Tcl_NewStringObj (ValidationErrorType2str[errorType], -1)
................................................................................
                
            case SCHEMA_CTYPE_INTERLEAVE:
            case SCHEMA_CTYPE_PATTERN:
                pushToStack (sdata, cp->content[ac], ac);
                rc = checkElementEnd (interp, sdata);
                popStack (sdata);
                if (rc) break;
                if (!recover (interp, sdata, MISSING_ELEMENT_MATCH_END, NULL,
                              NULL, NULL, 0)) {
                    return 0;
                }
                break;
                
            case SCHEMA_CTYPE_ANY:
            case SCHEMA_CTYPE_NAME:
                if (recover (interp, sdata, MISSING_ELEMENT_MATCH_END, NULL,
                             NULL, NULL, 0)) {
                    break;
                }
................................................................................
    case SCHEMA_CTYPE_KEYSPACE:
    case SCHEMA_CTYPE_VIRTUAL:
    case SCHEMA_CTYPE_CHOICE:
    case SCHEMA_CTYPE_TEXT:
    case SCHEMA_CTYPE_ANY:
        /* Never pushed onto stack */
        Tcl_Panic ("Invalid CTYPE onto the validation stack!");


    case SCHEMA_CTYPE_INTERLEAVE:
        for (i = 0; i < cp->nc; i++) {
            if (mustMatch (cp->quants[i], se->interleaveState[i])) {
                if (recover (interp, sdata, MISSING_ELEMENT_MATCH_END, NULL,
                             NULL, NULL, 0)) {
                    break;
                }
                return 0;
            }
        }
        return -1;
    }
    /* Not reached */
    return 0;
}

static int
checkDocKeys (
    Tcl_Interp *interp,
    SchemaData *sdata
................................................................................
probeElementEnd (
    Tcl_Interp *interp,
    SchemaData *sdata
    )
{
    int rc;
    
    DBG(if (sdata->stack) {
        fprintf (stderr, "probeElementEnd: look if current stack top can end "
                 " name: '%s' deep: %d\n",
                 sdata->stack->pattern->name, getDeep (sdata->stack));
        } else {fprintf (stderr, "stack is NULL\n");}
        );

    if (sdata->skipDeep) {
        sdata->skipDeep--;
        return TCL_OK;
    }
    if (sdata->validationState == VALIDATION_FINISHED) {
................................................................................
    }

    rc = checkElementEnd (interp, sdata);
    while (rc == -1) {
        popStack (sdata);
        rc = checkElementEnd (interp, sdata);
    }

    if (rc) {
        popStack (sdata);
        if (sdata->stack == NULL) {
            /* End of the first pattern (the tree root) without error. */
            /* Check for unknown ID references */
            if (!checkDocKeys (interp, sdata)) {
                return TCL_ERROR;

Changes to tests/schema.test.

6004
6005
6006
6007
6008
6009
6010






































6011
6012
6013
6014
6015
6016
6017
    s reportcmd ::tdom::_dontExists_
    set result [catch {s validate <doc/>} errMsg]
    lappend result $errMsg
    s delete
    set result
} {1 {error "invalid command name "::tdom::_dontExists_"" at line 1 character 6}}







































proc validatedSAX {g xml {keepEmpties 1}} {
    set args [list -validateCmd $g]
    if {!$keepEmpties} {
        lappend args -ignorewhitespace 1
    }
    xml::parser p {*}$args
    set rc [catch {p parse $xml} errMsg]







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







6004
6005
6006
6007
6008
6009
6010
6011
6012
6013
6014
6015
6016
6017
6018
6019
6020
6021
6022
6023
6024
6025
6026
6027
6028
6029
6030
6031
6032
6033
6034
6035
6036
6037
6038
6039
6040
6041
6042
6043
6044
6045
6046
6047
6048
6049
6050
6051
6052
6053
6054
6055
    s reportcmd ::tdom::_dontExists_
    set result [catch {s validate <doc/>} errMsg]
    lappend result $errMsg
    s delete
    set result
} {1 {error "invalid command name "::tdom::_dontExists_"" at line 1 character 6}}

proc 18-13 {scmd errType} {
    global result
    lappend result {reportcmd called}
}

test schema-18.13 {reportcmd} {
    tdom::schema s
    s define {
        defelement header {
            group {
                choice {
                    group  {
                        element prevlocs 
                        element latestloc ?
                    }
                    group  {
                        element latestloc 
                        element prevlocs ?
                    }
                }
            }
        }
    }
    s reportcmd 18-13
    set result [list]
    foreach xml {
        <header/>
        <header><prevlocs/></header>
        <header><latestloc/></header>
        <header><prevlocs/><latestloc/></header>
        <header><latestloc/><prevlocs/></header>
    } {
        lappend result [s validate $xml]
    }
    s delete
    set result
} {{reportcmd called} 1 1 1 1 1}

proc validatedSAX {g xml {keepEmpties 1}} {
    set args [list -validateCmd $g]
    if {!$keepEmpties} {
        lappend args -ignorewhitespace 1
    }
    xml::parser p {*}$args
    set rc [catch {p parse $xml} errMsg]