Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Enhanced the text constraint commands id/idref: Beside the one doc wide ID space there are now additional other named doc wide ID/IDREF spaces possible. Each of them work along the unnamed doc wide ID space. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | schema |
Files: | files | file ages | folders |
SHA3-256: |
6b550b98f8375f99016b8ab33987cdeb |
User & Date: | rolf 2019-05-14 20:02:51.721 |
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 | |
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 | |
2019-05-14
| ||
20:04 | Merge from schema. check-in: dc36b35000 user: rolf tags: localkey | |
20:02 | Enhanced the text constraint commands id/idref: Beside the one doc wide ID space there are now additional other named doc wide ID/IDREF spaces possible. Each of them work along the unnamed doc wide ID space. check-in: 6b550b98f8 user: rolf tags: schema | |
2019-05-10
| ||
13:40 | Fixed bug (invalid mem access) if a virtual constraint will be called under certain circumstances while looking if pcdata matches. check-in: 4cc96fcd33 user: rolf tags: schema | |
Changes
Changes to generic/schema.c.
︙ | ︙ | |||
436 437 438 439 440 441 442 | sdata->patternList = (SchemaCP **) MALLOC ( sizeof (SchemaCP*) * ANON_PATTERN_ARRAY_SIZE_INIT); sdata->patternListSize = ANON_PATTERN_ARRAY_SIZE_INIT; sdata->quants = (SchemaQuant *) MALLOC ( sizeof (SchemaQuant) * QUANTS_ARRAY_SIZE_INIT); sdata->quantsSize = QUANTS_ARRAY_SIZE_INIT; /* evalStub initialization */ | | | < > > > > | 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 | sdata->patternList = (SchemaCP **) MALLOC ( sizeof (SchemaCP*) * ANON_PATTERN_ARRAY_SIZE_INIT); sdata->patternListSize = ANON_PATTERN_ARRAY_SIZE_INIT; sdata->quants = (SchemaQuant *) MALLOC ( sizeof (SchemaQuant) * QUANTS_ARRAY_SIZE_INIT); sdata->quantsSize = QUANTS_ARRAY_SIZE_INIT; /* evalStub initialization */ sdata->evalStub = (Tcl_Obj **) MALLOC (sizeof (Tcl_Obj*) * 4); sdata->evalStub[0] = Tcl_NewStringObj("::namespace", 11); Tcl_IncrRefCount (sdata->evalStub[0]); sdata->evalStub[1] = Tcl_NewStringObj("eval", 4); Tcl_IncrRefCount (sdata->evalStub[1]); sdata->evalStub[2] = Tcl_NewStringObj("::tdom::schema", 14); Tcl_IncrRefCount (sdata->evalStub[2]); /* textStub initialization */ sdata->textStub = (Tcl_Obj **) MALLOC (sizeof (Tcl_Obj*) * 4); sdata->textStub[0] = Tcl_NewStringObj("::namespace", 11); Tcl_IncrRefCount (sdata->textStub[0]); sdata->textStub[1] = Tcl_NewStringObj("eval", 4); Tcl_IncrRefCount (sdata->textStub[1]); sdata->textStub[2] = Tcl_NewStringObj("::tdom::schema::text", 20); Tcl_IncrRefCount (sdata->textStub[2]); sdata->cdata = TMALLOC (Tcl_DString); Tcl_DStringInit (sdata->cdata); Tcl_InitHashTable (&sdata->ids, TCL_STRING_KEYS); sdata->unknownIDrefs = 0; Tcl_InitHashTable (&sdata->idTables, TCL_STRING_KEYS); return sdata; } static void schemaInstanceDelete ( ClientData clientData ) { SchemaData *sdata = (SchemaData *) clientData; unsigned int i; SchemaValidationStack *down; Tcl_HashEntry *h; Tcl_HashSearch search; SchemaDocKey *dk; /* Protect the clientData to be freed inside (even nested) * Tcl_Eval*() calls to avoid invalid mem access and postpone the * cleanup until the Tcl_Eval*() calls are finished (done in * schemaInstanceCmd(). */ if (sdata->currentEvals) { sdata->cleanupAfterEval = 1; |
︙ | ︙ | |||
523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 | FREE (sdata->textStub); Tcl_DStringFree (sdata->cdata); FREE (sdata->cdata); if (sdata->reportCmd) { Tcl_DecrRefCount (sdata->reportCmd); } Tcl_DeleteHashTable (&sdata->ids); FREE (sdata); } static void cleanupLastPattern ( SchemaData *sdata, unsigned int from ) { unsigned int i; Tcl_HashTable *hashTable; Tcl_HashEntry *entryPtr; SchemaCP *this, *previous, *current; for (i = from; i < sdata->numPatternList; i++) { this = sdata->patternList[i]; hashTable = NULL; if (this->type == SCHEMA_CTYPE_NAME) { hashTable = &sdata->element; | > > > > > > > > > | 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 | FREE (sdata->textStub); Tcl_DStringFree (sdata->cdata); FREE (sdata->cdata); if (sdata->reportCmd) { Tcl_DecrRefCount (sdata->reportCmd); } Tcl_DeleteHashTable (&sdata->ids); for (h = Tcl_FirstHashEntry (&sdata->idTables, &search); h != NULL; h = Tcl_NextHashEntry (&search)) { dk = Tcl_GetHashValue (h); Tcl_DeleteHashTable (&dk->ids); FREE (dk); } Tcl_DeleteHashTable (&sdata->idTables); FREE (sdata); } static void cleanupLastPattern ( SchemaData *sdata, unsigned int from ) { unsigned int i; Tcl_HashTable *hashTable; Tcl_HashEntry *entryPtr; SchemaCP *this, *previous, *current; for (i = from; i < sdata->numPatternList; i++) { this = sdata->patternList[i]; hashTable = NULL; if (this->type == SCHEMA_CTYPE_NAME) { hashTable = &sdata->element; |
︙ | ︙ | |||
1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 | return 0; } } return -1; } return 0; } int probeElementEnd ( Tcl_Interp *interp, SchemaData *sdata ) { | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 | return 0; } } return -1; } return 0; } static int checkDocKeys ( Tcl_Interp *interp, SchemaData *sdata ) { Tcl_HashEntry *h, *h1; Tcl_HashSearch search, search1; int haveErrMsg = 0; SchemaDocKey *dk; if (sdata->unknownIDrefs) { haveErrMsg = 1; SetResult ("References to unknown IDs:"); for (h = Tcl_FirstHashEntry (&sdata->ids, &search); h != NULL; h = Tcl_NextHashEntry (&search)) { if (Tcl_GetHashValue (h) == 0) { Tcl_AppendResult (interp, " '", Tcl_GetHashKey (&sdata->ids, h), "'", NULL); } } } if (sdata->idTables.numEntries) { for (h = Tcl_FirstHashEntry (&sdata->idTables, &search); h != NULL; h = Tcl_NextHashEntry (&search)) { dk = Tcl_GetHashValue (h); if (dk->unknownIDrefs) { if (haveErrMsg) { Tcl_AppendResult (interp, "\n", NULL); } else { haveErrMsg = 1; } Tcl_AppendResult (interp, "References to unknown IDs in ID space '", Tcl_GetHashKey (&sdata->idTables, h), "':", NULL); for (h1 = Tcl_FirstHashEntry (&dk->ids, &search1); h1 != NULL; h1 = Tcl_NextHashEntry (&search1)) { if (Tcl_GetHashValue (h1) == 0) { Tcl_AppendResult (interp, " '", Tcl_GetHashKey (&dk->ids, h1), "'", NULL); } } } } } if (haveErrMsg) { sdata->validationState = VALIDATION_ERROR; return 0; } return 1; } int probeElementEnd ( Tcl_Interp *interp, SchemaData *sdata ) { |
︙ | ︙ | |||
1566 1567 1568 1569 1570 1571 1572 | } if (rc) { popStack (sdata); if (sdata->stack == NULL) { /* End of the first pattern (the tree root) without error. */ /* Check for unknown ID references */ | < < < < < < < < | < < < < < | 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 | } 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 ended validation */ sdata->validationState = VALIDATION_FINISHED; } DBG( fprintf(stderr, "probeElementEnd: _CAN_ end here.\n"); |
︙ | ︙ | |||
2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 | } void schemaReset ( SchemaData *sdata ) { while (sdata->stack) popStack (sdata); sdata->validationState = VALIDATION_READY; sdata->skipDeep = 0; sdata->evalError = 0; Tcl_DStringSetLength (sdata->cdata, 0); if (sdata->ids.numEntries) { Tcl_DeleteHashTable (&sdata->ids); Tcl_InitHashTable (&sdata->ids, TCL_STRING_KEYS); sdata->unknownIDrefs = 0; } } static int evalConstraints ( Tcl_Interp *interp, SchemaData *sdata, | > > > > > > > > > > > > > > > > | 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 | } void schemaReset ( SchemaData *sdata ) { Tcl_HashEntry *h; Tcl_HashSearch search; SchemaDocKey *dk; while (sdata->stack) popStack (sdata); sdata->validationState = VALIDATION_READY; sdata->skipDeep = 0; sdata->evalError = 0; Tcl_DStringSetLength (sdata->cdata, 0); if (sdata->ids.numEntries) { Tcl_DeleteHashTable (&sdata->ids); Tcl_InitHashTable (&sdata->ids, TCL_STRING_KEYS); sdata->unknownIDrefs = 0; } if (sdata->idTables.numEntries) { for (h = Tcl_FirstHashEntry (&sdata->idTables, &search); h != NULL; h = Tcl_NextHashEntry (&search)) { dk = Tcl_GetHashValue (h); if (&dk->ids.numEntries) { Tcl_DeleteHashTable (&dk->ids); Tcl_InitHashTable (&dk->ids, TCL_STRING_KEYS); dk->unknownIDrefs = 0; } } } } static int evalConstraints ( Tcl_Interp *interp, SchemaData *sdata, |
︙ | ︙ | |||
2659 2660 2661 2662 2663 2664 2665 | if (objc != 2-i && objc != 3-i) { Tcl_WrongNumArgs (interp, 2-i, objv, "?prefixUriList?"); return TCL_ERROR; } if (!i) {objc--; objv++;} result = tcldom_prefixNSlist (&sdata->prefixns, interp, objc, objv, "prefixns"); | | | 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 | if (objc != 2-i && objc != 3-i) { Tcl_WrongNumArgs (interp, 2-i, objv, "?prefixUriList?"); return TCL_ERROR; } if (!i) {objc--; objv++;} result = tcldom_prefixNSlist (&sdata->prefixns, interp, objc, objv, "prefixns"); if (sdata->prefix.numEntries) { Tcl_DeleteHashTable (&sdata->prefix); Tcl_InitHashTable (&sdata->prefix, TCL_STRING_KEYS); } if (result == TCL_OK && sdata->prefixns) { j = 0; while (sdata->prefixns[j]) { h1 = Tcl_CreateHashEntry (&sdata->prefix, |
︙ | ︙ | |||
4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 | sdata->unknownIDrefs--; return 1; } else { /* Duplicate ID value */ return 0; } } static int idTCObjCmd ( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] ) { SchemaData *sdata = GETASI; SchemaConstraint *sc; CHECK_TI CHECK_TOPLEVEL | > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | | > > > > > > > > > > > > > > | 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 | sdata->unknownIDrefs--; return 1; } else { /* Duplicate ID value */ return 0; } } static int docidImpl ( Tcl_Interp *interp, void *constraintData, char *text ) { SchemaDocKey *dk = (SchemaDocKey *) constraintData; int hnew; Tcl_HashEntry *h; h = Tcl_CreateHashEntry (&dk->ids, text, &hnew); if (hnew) { Tcl_SetHashValue (h, 1); return 1; } if (Tcl_GetHashValue (h) == 0) { Tcl_SetHashValue (h, 1); dk->unknownIDrefs--; return 1; } /* Duplicate ID value */ return 0; } static int idTCObjCmd ( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] ) { SchemaData *sdata = GETASI; SchemaConstraint *sc; Tcl_HashEntry *h; int hnew; SchemaDocKey *dk; CHECK_TI CHECK_TOPLEVEL checkNrArgs (1,2,"?key_space?"); ADD_CONSTRAINT (sdata, sc) if (objc == 1) { sc->constraint = idImpl; sc->constraintData = (void *)sdata; } else { h = Tcl_CreateHashEntry (&sdata->idTables, Tcl_GetString (objv[1]), &hnew); if (hnew) { dk = TMALLOC (SchemaDocKey); Tcl_InitHashTable (&dk->ids, TCL_STRING_KEYS); dk->unknownIDrefs = 0; Tcl_SetHashValue (h, dk); } else { dk = Tcl_GetHashValue (h); } sc->constraint = docidImpl; sc->constraintData = (void *)dk; } return TCL_OK; } static int idrefImpl ( Tcl_Interp *interp, void *constraintData, |
︙ | ︙ | |||
4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 | h = Tcl_CreateHashEntry (&sdata->ids, text, &hnew); if (hnew) { Tcl_SetHashValue (h, 0); sdata->unknownIDrefs++; } return 1; } static int idrefTCObjCmd ( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] ) { SchemaData *sdata = GETASI; SchemaConstraint *sc; CHECK_TI CHECK_TOPLEVEL | > > > > > > > > > > > > > > > > > > > > > > | > | | > > > > > > > > > > > > > > | 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 | h = Tcl_CreateHashEntry (&sdata->ids, text, &hnew); if (hnew) { Tcl_SetHashValue (h, 0); sdata->unknownIDrefs++; } return 1; } static int docidrefImpl ( Tcl_Interp *interp, void *constraintData, char *text ) { SchemaDocKey *dk = (SchemaDocKey *) constraintData; int hnew; Tcl_HashEntry *h; h = Tcl_CreateHashEntry (&dk->ids, text, &hnew); if (hnew) { Tcl_SetHashValue (h, 0); dk->unknownIDrefs++; } return 1; } static int idrefTCObjCmd ( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] ) { SchemaData *sdata = GETASI; SchemaConstraint *sc; Tcl_HashEntry *h; int hnew; SchemaDocKey *dk; CHECK_TI CHECK_TOPLEVEL checkNrArgs (1,2,"?key_space?"); ADD_CONSTRAINT (sdata, sc) if (objc == 1) { sc->constraint = idrefImpl; sc->constraintData = (void *)sdata; } else { h = Tcl_CreateHashEntry (&sdata->idTables, Tcl_GetString (objv[1]), &hnew); if (hnew) { dk = TMALLOC (SchemaDocKey); Tcl_InitHashTable (&dk->ids, TCL_STRING_KEYS); dk->unknownIDrefs = 0; Tcl_SetHashValue (h, dk); } else { dk = Tcl_GetHashValue (h); } sc->constraint = docidrefImpl; sc->constraintData = (void *)dk; } return TCL_OK; } static int base64Impl ( Tcl_Interp *interp, void *constraintData, |
︙ | ︙ |
Changes to generic/schema.h.
︙ | ︙ | |||
101 102 103 104 105 106 107 108 109 110 111 112 113 114 | VALIDATION_READY, VALIDATION_STARTED, VALIDATION_ERROR, VALIDATION_FINISHED } ValidationState; typedef struct { Tcl_Obj *self; char *start; char *startNamespace; Tcl_HashTable element; Tcl_HashTable namespace; Tcl_HashEntry *emptyNamespace; | > > > > > > | 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 | VALIDATION_READY, VALIDATION_STARTED, VALIDATION_ERROR, VALIDATION_FINISHED } ValidationState; typedef struct { Tcl_HashTable ids; int unknownIDrefs; } SchemaDocKey; typedef struct { Tcl_Obj *self; char *start; char *startNamespace; Tcl_HashTable element; Tcl_HashTable namespace; Tcl_HashEntry *emptyNamespace; |
︙ | ︙ | |||
143 144 145 146 147 148 149 150 151 152 153 154 155 156 | SchemaValidationStack *stack; SchemaValidationStack *stackPool; ValidationState validationState; unsigned int skipDeep; Tcl_DString *cdata; Tcl_HashTable ids; int unknownIDrefs; } SchemaData; int schemaInstanceCmd ( ClientData clientData, Tcl_Interp *interp, int objc, | > | 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 | SchemaValidationStack *stack; SchemaValidationStack *stackPool; ValidationState validationState; unsigned int skipDeep; Tcl_DString *cdata; Tcl_HashTable ids; int unknownIDrefs; Tcl_HashTable idTables; } SchemaData; int schemaInstanceCmd ( ClientData clientData, Tcl_Interp *interp, int objc, |
︙ | ︙ |
Changes to tests/schema.test.
︙ | ︙ | |||
3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 | {<doc>===</doc>} } { lappend result [s validate $xml] } s delete set result } {1 1 1 0 1 1 0 0} test schema-15.1 {constraint cmd tcl} { tdom::schema s s define { defelement a { tcl append ::schema-15.1 element b | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 | {<doc>===</doc>} } { lappend result [s validate $xml] } s delete set result } {1 1 1 0 1 1 0 0} test schema-14.27 {element content id/idref} { tdom::schema s s define { defelement doc { interleave { element id * element idref * element ida * element idrefa * } } defelement id {text id} defelement idref {text idref} defelement ida {text {id a}} defelement idrefa {text {idref a}} } set result [list] foreach xml { <doc/> <doc><id>abc</id><ida>abc</ida></doc> <doc><idrefa>abc</idrefa></doc> <doc><idrefa>abc</idrefa><idref>abc</idref></doc> <doc><id>1</id><idrefa>abc</idrefa><idref>abc</idref><idrefa>foo</idrefa><idref>abc</idref></doc> <doc><id>abc</id><idref>abc</idref><ida>abc</ida><idrefa>abc</idrefa></doc> <doc><idref>abc</idref><id>abc</id><idrefa>abc</idrefa><ida>abc</ida></doc> } { lappend result [s validate $xml] } s delete set result } {1 1 0 0 0 1 1} test schema-14.28 {element content id/idref} { tdom::schema s s define { defelement doc { interleave { element id * element idref * element ida * element idrefa * } } defelement id {text {id b}} defelement idref {text {idref b}} defelement ida {text {id a}} defelement idrefa {text {idref a}} } set result [list] foreach xml { <doc/> <doc><id>abc</id><ida>abc</ida></doc> <doc><idrefa>abc</idrefa></doc> <doc><idrefa>abc</idrefa><idref>abc</idref></doc> <doc><id>1</id><idrefa>abc</idrefa><idref>abc</idref><idrefa>foo</idrefa><idref>abc</idref></doc> <doc><id>abc</id><idref>abc</idref><ida>abc</ida><idrefa>abc</idrefa></doc> <doc><idref>abc</idref><id>abc</id><idrefa>abc</idrefa><ida>abc</ida></doc> } { lappend result [s validate $xml] } s delete set result } {1 1 0 0 0 1 1} test schema-15.1 {constraint cmd tcl} { tdom::schema s s define { defelement a { tcl append ::schema-15.1 element b |
︙ | ︙ |