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

Overview
Comment:Respect "ignore" return value from recover script in case of END_EVENT, enabling to get further recover calls for other missing mandantory content particle of the current content model.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | wip
Files: files | file ages | folders
SHA3-256: 42c54de7e79319352b81b9bd2a21cfd3af23336cd367cd69b4aad1a891e0f9fc
User & Date: rolf 2020-07-30 13:16:46
Context
2020-07-30
14:33
Integrated further improvements and features to recovering. check-in: 0e98933aa6 user: rolf tags: schema
13:16
Respect "ignore" return value from recover script in case of END_EVENT, enabling to get further recover calls for other missing mandantory content particle of the current content model. Closed-Leaf check-in: 42c54de7e7 user: rolf tags: wip
2020-07-23
23:50
Merged from schema. check-in: 227e773285 user: rolf tags: wip
Changes

Changes to generic/schema.c.

399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
...
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
....
2206
2207
2208
2209
2210
2211
2212















2213
2214
2215
2216
2217
2218
2219
....
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
....
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
....
2337
2338
2339
2340
2341
2342
2343




2344
2345
2346
2347
2348
2349
2350
....
2351
2352
2353
2354
2355
2356
2357

2358
2359



2360
2361





2362
2363

2364







2365
2366
2367
2368
2369




2370
2371
2372
2373
2374
2375
2376
....
2484
2485
2486
2487
2488
2489
2490

2491
2492
2493
2494
2495
2496
2497




2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512


2513
2514
2515
2516
2517
2518
2519
        ac += + 1;                                \
        hm = 0;                                   \
    }                                             \


#define updateStack(sdata,se,ac)                        \
    if (!(sdata->recoverFlags & RECOVER_FLAG_REWIND)) { \
        se->activeChild = ac;                 \
        se->hasMatched = 1;                   \
    }                                                   \


#ifndef TCL_THREADS
SchemaData *
tdomGetSchemadata (Tcl_Interp *interp) 
{
................................................................................
static void
pushToStack (
    SchemaData *sdata,
    SchemaCP *pattern
    )
{
    SchemaValidationStack *se, *nextse;

    DBG(fprintf(stderr, "push to Stack:\n");serializeCP(pattern));
    if (pattern->type == SCHEMA_CTYPE_NAME && sdata->lastMatchse) {
        se = sdata->lastMatchse;
        while (se) {
            nextse = se->down;
            repoolStackElement (sdata, se);
            se = nextse;
................................................................................
    if (reqAttr != cp->numReqAttr) {
        SetResult ("Missing mandatory attribute(s)");
        return TCL_ERROR;
    }
    return TCL_OK;
}
















static int checkElementEnd (
    Tcl_Interp *interp,
    SchemaData *sdata
    )
{
    SchemaValidationStack *se;
    SchemaCP *cp, *ic;
................................................................................
        if (ac < cp->nc && (hasMatched (cp->quants[ac], hm))) {
            DBG(fprintf (stderr, "ac %d has matched, skiping to next ac\n", ac));
            ac++; hm = 0;
        }
        while (ac < cp->nc) {
            DBG(fprintf (stderr, "ac %d hm %d mayMiss: %d\n",
                         ac, hm, mayMiss (cp->quants[ac])));
            if (se->interleaveState) {
                if (se->interleaveState[ac]) {
                    ac++; continue;
                }
            }
            if (mayMiss (cp->quants[ac])) {
                ac++; continue;
            }
            switch (cp->content[ac]->type) {
            case SCHEMA_CTYPE_KEYSPACE_END:
                /* Don't happen as INTERLEAVE child */
................................................................................
                        if (recursivePattern (se, ic)) {
                            thismayskip = 1;
                            break;
                        }
                        /* fall throu */
                    case SCHEMA_CTYPE_INTERLEAVE:
                        pushToStack (sdata, ic);
                        if (checkElementEnd (interp, sdata)) {
                            thismayskip = 1;
                        }
                        popStack (sdata);
                        break;
                        
                    case SCHEMA_CTYPE_KEYSPACE_END:
                    case SCHEMA_CTYPE_KEYSPACE:
................................................................................
                    if (thismayskip) break;
                }
                if (thismayskip) break;
                if (!recover (interp, sdata, MISSING_ELEMENT_MATCH_END, NULL,
                              NULL, NULL, 0)) {
                    return 0;
                }




                break;
                
            case SCHEMA_CTYPE_VIRTUAL:
                if (evalVirtual (interp, sdata, ac)) break;
                else return 0;
                
            case SCHEMA_CTYPE_PATTERN:
................................................................................
                if (recursivePattern (se, cp->content[ac])) {
                    break;
                }
                /* fall throu */
            case SCHEMA_CTYPE_INTERLEAVE:
                pushToStack (sdata, cp->content[ac]);
                rc = checkElementEnd (interp, sdata);

                popStack (sdata);
                if (rc) break;



                if (recover (interp, sdata, MISSING_ELEMENT_MATCH_END,
                             NULL, NULL, NULL, 0)) {





                    break;
                }

                return 0;







                
            case SCHEMA_CTYPE_ANY:
            case SCHEMA_CTYPE_NAME:
                if (recover (interp, sdata, MISSING_ELEMENT_MATCH_END,
                             NULL, NULL, NULL, 0)) {




                    break;
                }
                return 0;
            }
            ac++;
        }
        if (se->interleaveState) {
................................................................................
        SetResult ("No validation started");
        return TCL_ERROR;
    }
    if (sdata->validationState == VALIDATION_ERROR) {
        return TCL_ERROR;
    }


    rc = checkElementEnd (interp, sdata);
    while (rc == -1) {
        popStack (sdata);
        rc = checkElementEnd (interp, sdata);
    }
    sdata->recoverFlags &= ~RECOVER_FLAG_DONT_REPORT;
    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;
            }
            /*  We have successfully finished validation */
            sdata->validationState = VALIDATION_FINISHED;
        }
        DBG(
            fprintf(stderr, "probeElementEnd: _CAN_ end here.\n");
            serializeStack (sdata);
            );
        return TCL_OK;


    }
    SetResultV ("Missing mandatory content");
    sdata->validationState = VALIDATION_ERROR;
    DBG(
        fprintf(stderr, "probeElementEnd: CAN'T end here.\n");
        serializeStack (sdata);
        );







|
|







 







<







 







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







 







|
<
|
<







 







|







 







>
>
>
>







 







>
|
<
>
>
>
|
|
>
>
>
>
>
|
|
>
|
>
>
>
>
>
>
>





>
>
>
>







 







>
|
|
|
|
|
|
|
>
>
>
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>
>







399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
...
976
977
978
979
980
981
982

983
984
985
986
987
988
989
....
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
....
2251
2252
2253
2254
2255
2256
2257
2258

2259

2260
2261
2262
2263
2264
2265
2266
....
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
....
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
....
2367
2368
2369
2370
2371
2372
2373
2374
2375

2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
....
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
        ac += + 1;                                \
        hm = 0;                                   \
    }                                             \


#define updateStack(sdata,se,ac)                        \
    if (!(sdata->recoverFlags & RECOVER_FLAG_REWIND)) { \
        se->activeChild = ac;                           \
        se->hasMatched = 1;                             \
    }                                                   \


#ifndef TCL_THREADS
SchemaData *
tdomGetSchemadata (Tcl_Interp *interp) 
{
................................................................................
static void
pushToStack (
    SchemaData *sdata,
    SchemaCP *pattern
    )
{
    SchemaValidationStack *se, *nextse;

    DBG(fprintf(stderr, "push to Stack:\n");serializeCP(pattern));
    if (pattern->type == SCHEMA_CTYPE_NAME && sdata->lastMatchse) {
        se = sdata->lastMatchse;
        while (se) {
            nextse = se->down;
            repoolStackElement (sdata, se);
            se = nextse;
................................................................................
    if (reqAttr != cp->numReqAttr) {
        SetResult ("Missing mandatory attribute(s)");
        return TCL_ERROR;
    }
    return TCL_OK;
}

/* Returns either -1, 0, 1, 2

   -1 means a pattern or an interleave ended may end, look further at
   parents next sibling.

   0 means rewind with validation error.

   1 means element content may end here.

   2 means recovering requested further error reporting about missing childs
   in the current element. To be able to to answer a [info expected] on
   the occasion of the next error, we update the stack in this case
   and let probeElementEnd restart checkElementEnd again with this
   stack state.
*/
static int checkElementEnd (
    Tcl_Interp *interp,
    SchemaData *sdata
    )
{
    SchemaValidationStack *se;
    SchemaCP *cp, *ic;
................................................................................
        if (ac < cp->nc && (hasMatched (cp->quants[ac], hm))) {
            DBG(fprintf (stderr, "ac %d has matched, skiping to next ac\n", ac));
            ac++; hm = 0;
        }
        while (ac < cp->nc) {
            DBG(fprintf (stderr, "ac %d hm %d mayMiss: %d\n",
                         ac, hm, mayMiss (cp->quants[ac])));
            if (se->interleaveState && se->interleaveState[ac]) {

                ac++; continue;

            }
            if (mayMiss (cp->quants[ac])) {
                ac++; continue;
            }
            switch (cp->content[ac]->type) {
            case SCHEMA_CTYPE_KEYSPACE_END:
                /* Don't happen as INTERLEAVE child */
................................................................................
                        if (recursivePattern (se, ic)) {
                            thismayskip = 1;
                            break;
                        }
                        /* fall throu */
                    case SCHEMA_CTYPE_INTERLEAVE:
                        pushToStack (sdata, ic);
                        if (checkElementEnd (interp, sdata) == -1) {
                            thismayskip = 1;
                        }
                        popStack (sdata);
                        break;
                        
                    case SCHEMA_CTYPE_KEYSPACE_END:
                    case SCHEMA_CTYPE_KEYSPACE:
................................................................................
                    if (thismayskip) break;
                }
                if (thismayskip) break;
                if (!recover (interp, sdata, MISSING_ELEMENT_MATCH_END, NULL,
                              NULL, NULL, 0)) {
                    return 0;
                }
                if (sdata->recoverFlags & RECOVER_FLAG_MATCH_END_CONTINUE) {
                    updateStack (sdata, se, ac);
                    return 2;
                }
                break;
                
            case SCHEMA_CTYPE_VIRTUAL:
                if (evalVirtual (interp, sdata, ac)) break;
                else return 0;
                
            case SCHEMA_CTYPE_PATTERN:
................................................................................
                if (recursivePattern (se, cp->content[ac])) {
                    break;
                }
                /* fall throu */
            case SCHEMA_CTYPE_INTERLEAVE:
                pushToStack (sdata, cp->content[ac]);
                rc = checkElementEnd (interp, sdata);
                if (rc == 0) {
                    popStack (sdata);

                    if (sdata->stack->pattern->type == SCHEMA_CTYPE_NAME
                        || sdata->stack->activeChild
                        || sdata->stack->hasMatched) {
                        if (recover (interp, sdata, MISSING_ELEMENT_MATCH_END,
                                     NULL, NULL, NULL, 0)) {
                            if (sdata->recoverFlags &
                                RECOVER_FLAG_MATCH_END_CONTINUE) {
                                updateStack (sdata, se, ac);
                                return 2;
                            }
                            break;
                        }
                    }
                    return 0;
                }
                if (rc == 2) {
                    updateStack (sdata, se, ac);
                    return 2;
                }
                popStack (sdata);
                break;
                
            case SCHEMA_CTYPE_ANY:
            case SCHEMA_CTYPE_NAME:
                if (recover (interp, sdata, MISSING_ELEMENT_MATCH_END,
                             NULL, NULL, NULL, 0)) {
                    if (sdata->recoverFlags & RECOVER_FLAG_MATCH_END_CONTINUE) {
                        updateStack (sdata, se, ac);
                        return 2;
                    }
                    break;
                }
                return 0;
            }
            ac++;
        }
        if (se->interleaveState) {
................................................................................
        SetResult ("No validation started");
        return TCL_ERROR;
    }
    if (sdata->validationState == VALIDATION_ERROR) {
        return TCL_ERROR;
    }

    while (1) {
        rc = checkElementEnd (interp, sdata);
        while (rc == -1) {
            popStack (sdata);
            rc = checkElementEnd (interp, sdata);
        }
        sdata->recoverFlags &= ~RECOVER_FLAG_DONT_REPORT;
        if (rc == 2) {
            sdata->recoverFlags &= ~RECOVER_FLAG_MATCH_END_CONTINUE;
            continue;
        }
        if (rc == 1) {
            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;
                }
                /*  We have successfully finished validation */
                sdata->validationState = VALIDATION_FINISHED;
            }
            DBG(
                fprintf(stderr, "probeElementEnd: _CAN_ end here.\n");
                serializeStack (sdata);
                );
            return TCL_OK;
        }
        break;
    }
    SetResultV ("Missing mandatory content");
    sdata->validationState = VALIDATION_ERROR;
    DBG(
        fprintf(stderr, "probeElementEnd: CAN'T end here.\n");
        serializeStack (sdata);
        );

Changes to tests/schema.test.

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
....
8202
8203
8204
8205
8206
8207
8208
8209
8210
8211
8212
8213
8214
8215
8216
8217
8218
8219
8220
8221
8222
8223
8224





8225
8226
8227






























8228
8229
8230
8231
8232
8233
8234
8235
8236
8237
8238
8239
8240
8241
        }
        s delete
        incr defnr
    }
    set result
} {0/0: 1 {END_EVENT expecting a} 0/1: 1 {END_EVENT expecting b} 0/2: 1 {matching b} {expecting a} {END_EVENT expecting c} 0/3: 1 {matching c} {expecting a} {matching c} {expecting b} 0/4: 1 {END_EVENT expecting c} 0/5: 1 {matching c} {expecting b} 0/6: 1 {matching b} {expecting a} 0/7: 1 {matching unknown} {expecting a} {matching unknown} {expecting b} {matching unknown} {expecting c} {matching unknown} {expecting {<elementend> {}}} 0/8: 1 {matching unknown} {expecting b} {matching unknown} {expecting c} {matching unknown} {expecting {<elementend> {}}}}

test schema-17.22a {return "ignore" from recover script for MISSING_ELEMENT_MATCH_START} {
    set defs {
        {
            interleave {
                element a
                element b
                element c
            }
            element d ?
        }
    }
    set xmlinput {
        <doc/>
        <doc><a/><d/></doc>
        <doc><b/><d/></doc>
        <doc><c/><d/>/doc>
        <doc><a/><b/><d/></doc>
        <doc><a/><c/><d/></doc>
        <doc><c/><b/><d/></doc>
        <doc><unknown/></doc>
        <doc><a/><unknown/></doc>
    }
    set result [list]
    set defnr 0
    foreach def $defs {
        tdom::schema s
        s defelement doc $def
        s reportcmd schema-17.22
        set xmlnr 0
        foreach xml $xmlinput {
            set fromReportCmd ""
            lappend result $defnr/$xmlnr: [s validate $xml errMsg]
            lappend result {*}$fromReportCmd
            incr xmlnr
        }
        s delete
        incr defnr
    }
    set result
} {}

proc schema-17.23 {scmd errorInfo} {
    global fromReportCmd
    if {[$scmd info vaction] eq "MATCH_ELEMENT_START"} {
        lappend fromReportCmd "matching [$scmd info vaction name]" "expecting [lsort [$scmd info expected]]"
        if {$errorInfo in {"MISSING_ELEMENT" "UNEXPECTED_ELEMENT"}} {
            return vanish
        }
................................................................................
}

test schema-17.26 {return "ignore" from recover handler for element end event} {
    tdom::schema s
    s define {
        defelement doc {
            element a
            ref b
            element d ?
        }
        defpattern b {
            element b
            ref c
        }
        defpattern c {
            element c +
        }
    }
    s reportcmd schema-17.26
    set result ""
    set xmlnr 0
    foreach xml {
        <doc/>





    } {
        set ::fromReportCmd ""
        lappend result $defnr/$xmlnr: [s validate $xml errMsg]






























        lappend result {*}$fromReportCmd
        incr xmlnr
    }
    s delete
    set result
} {0: 1 a b c {c d} d}
    
proc schema-18 {args} {
    lappend ::result {*}$args
}
test schema-18.1 {reportcmd} {
    tdom::schema s
    s define {
        defelement doc {







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







 







|
|

|












>
>
>
>
>


|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>





|
|







8052
8053
8054
8055
8056
8057
8058









































8059
8060
8061
8062
8063
8064
8065
....
8161
8162
8163
8164
8165
8166
8167
8168
8169
8170
8171
8172
8173
8174
8175
8176
8177
8178
8179
8180
8181
8182
8183
8184
8185
8186
8187
8188
8189
8190
8191
8192
8193
8194
8195
8196
8197
8198
8199
8200
8201
8202
8203
8204
8205
8206
8207
8208
8209
8210
8211
8212
8213
8214
8215
8216
8217
8218
8219
8220
8221
8222
8223
8224
8225
8226
8227
8228
8229
8230
8231
8232
8233
8234
8235
        }
        s delete
        incr defnr
    }
    set result
} {0/0: 1 {END_EVENT expecting a} 0/1: 1 {END_EVENT expecting b} 0/2: 1 {matching b} {expecting a} {END_EVENT expecting c} 0/3: 1 {matching c} {expecting a} {matching c} {expecting b} 0/4: 1 {END_EVENT expecting c} 0/5: 1 {matching c} {expecting b} 0/6: 1 {matching b} {expecting a} 0/7: 1 {matching unknown} {expecting a} {matching unknown} {expecting b} {matching unknown} {expecting c} {matching unknown} {expecting {<elementend> {}}} 0/8: 1 {matching unknown} {expecting b} {matching unknown} {expecting c} {matching unknown} {expecting {<elementend> {}}}}










































proc schema-17.23 {scmd errorInfo} {
    global fromReportCmd
    if {[$scmd info vaction] eq "MATCH_ELEMENT_START"} {
        lappend fromReportCmd "matching [$scmd info vaction name]" "expecting [lsort [$scmd info expected]]"
        if {$errorInfo in {"MISSING_ELEMENT" "UNEXPECTED_ELEMENT"}} {
            return vanish
        }
................................................................................
}

test schema-17.26 {return "ignore" from recover handler for element end event} {
    tdom::schema s
    s define {
        defelement doc {
            element a
            ref bpat
            element d
        }
        defpattern bpat {
            element b
            ref c
        }
        defpattern c {
            element c +
        }
    }
    s reportcmd schema-17.26
    set result ""
    set xmlnr 0
    foreach xml {
        <doc/>
        <doc><a/></doc>
        <doc><a/><b/></doc>
        <doc><a/><b/><d/></doc>
        <doc><a/><b/><c/><d/></doc>
        <doc><a/><b/><c/><c/><c/><d/></doc>
    } {
        set ::fromReportCmd ""
        lappend result $xmlnr: [s validate $xml errMsg]
        lappend result {*}$fromReportCmd
        incr xmlnr
    }
    s delete
    set result
} {0: 1 {END_EVENT doc} {expecting a} {END_EVENT doc} {expecting b} {END_EVENT doc} {expecting d} 1: 1 {END_EVENT doc} {expecting b} {END_EVENT doc} {expecting d} 2: 1 {END_EVENT doc} {expecting c} {END_EVENT doc} {expecting d} 3: 1 {MATCH_ELEMENT_START expecting c} 4: 1 5: 1}

test schema-17.27 {return "ignore" from recover handler for element end event} {
    tdom::schema s
    s define {
        defelement doc {
            element a
            element b
            element c
            element d
        }
    }
    s reportcmd schema-17.26
    set result ""
    set xmlnr 0
    foreach xml {
        <doc/>
        <doc><a/></doc>
        <doc><a/><b/></doc>
        <doc><a/><b/><d/></doc>
        <doc><a/><b/><c/><d/></doc>
        <doc><a/><b/><c/><c/><c/><d/></doc>
    } {
        set ::fromReportCmd ""
        lappend result $xmlnr: [s validate $xml errMsg]
        lappend result {*}$fromReportCmd
        incr xmlnr
    }
    s delete
    set result
} {0: 1 {END_EVENT doc} {expecting a} {END_EVENT doc} {expecting b} {END_EVENT doc} {expecting c} {END_EVENT doc} {expecting d} 1: 1 {END_EVENT doc} {expecting b} {END_EVENT doc} {expecting c} {END_EVENT doc} {expecting d} 2: 1 {END_EVENT doc} {expecting c} {END_EVENT doc} {expecting d} 3: 1 {MATCH_ELEMENT_START expecting c} 4: 1 5: 1 {MATCH_ELEMENT_START expecting d}}

proc schema-18 {args} {
    lappend ::result {*}$args
}
test schema-18.1 {reportcmd} {
    tdom::schema s
    s define {
        defelement doc {