Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | 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). |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | domlocalkey |
Files: | files | file ages | folders |
SHA3-256: |
f645e5dfe14b0b43d40e0b25d01767e3 |
User & Date: | rolf 2019-05-21 16:21:31.289 |
Context
2019-05-21
| ||
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 | |
2019-05-14
| ||
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 | |
Changes
Changes to generic/dom.c.
︙ | ︙ | |||
45 46 47 48 49 50 51 52 53 54 55 56 57 58 | /*--------------------------------------------------------------------------- | Includes | \--------------------------------------------------------------------------*/ #include <tcl.h> #include <dom.h> #include <domxpath.h> #include <tclexpat.h> /* #define DEBUG */ /*---------------------------------------------------------------------------- | Debug Macros | | > | 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | /*--------------------------------------------------------------------------- | Includes | \--------------------------------------------------------------------------*/ #include <tcl.h> #include <dom.h> #include <domxpath.h> #include <schema.h> #include <tclexpat.h> /* #define DEBUG */ /*---------------------------------------------------------------------------- | Debug Macros | |
︙ | ︙ |
Changes to generic/dom.h.
︙ | ︙ | |||
38 39 40 41 42 43 44 | #include <tcl.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <expat.h> #include <domalloc.h> | < | 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | #include <tcl.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <expat.h> #include <domalloc.h> /* * tDOM provides it's own memory allocator which is optimized for * low heap usage. It uses the native Tcl allocator underneath, * though, but it is not very MT-friendly. Therefore, you might * use the (normal) Tcl allocator with USE_NORMAL_ALLOCATOR * defined during compile time. Actually, the symbols name is |
︙ | ︙ | |||
699 700 701 702 703 704 705 706 707 708 709 710 711 712 | /*-------------------------------------------------------------------------- | domAddCallback | \-------------------------------------------------------------------------*/ typedef int (*domAddCallback) (domNode * node, void * clientData); typedef void (*domFreeCallback) (domNode * node, void * clientData); /*-------------------------------------------------------------------------- | Function prototypes | \-------------------------------------------------------------------------*/ const char * domException2String (domException exception); | > > > > > > | 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 | /*-------------------------------------------------------------------------- | domAddCallback | \-------------------------------------------------------------------------*/ typedef int (*domAddCallback) (domNode * node, void * clientData); typedef void (*domFreeCallback) (domNode * node, void * clientData); /*-------------------------------------------------------------------------- | Forward declaration | \-------------------------------------------------------------------------*/ typedef struct SchemaData_ SchemaData; /*-------------------------------------------------------------------------- | Function prototypes | \-------------------------------------------------------------------------*/ const char * domException2String (domException exception); |
︙ | ︙ |
Changes to generic/domxpath.c.
︙ | ︙ | |||
260 261 262 263 264 265 266 267 268 269 270 271 272 273 | rs->nr_nodes = 0; } else if (rs->type == StringResult) { if (rs->string) FREE((char*)rs->string); } rs->type = EmptyResult; } void rsPrint ( xpathResultSet *rs ) { int i = 0,l; char tmp[80]; switch (rs->type) { case EmptyResult: fprintf(stderr, "empty result \n"); break; | > > > > > > > > > > > > > > > > > > > > > > | 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 | rs->nr_nodes = 0; } else if (rs->type == StringResult) { if (rs->string) FREE((char*)rs->string); } rs->type = EmptyResult; } void xpathRSReset ( xpathResultSet *rs, domNode *node ) { if (rs->type == StringResult) FREE(rs->string); if (node) { if (!rs->nodes) { rs->nodes = (domNode**)MALLOC( INITIAL_SIZE*sizeof(domNode*)); rs->allocated = INITIAL_SIZE; } rs->nodes[0] = node; rs->nr_nodes = 1; rs->type = xNodeSetResult; } else { rs->nr_nodes = 0; if (rs->nodes) rs->type = xNodeSetResult; else rs->type = EmptyResult; } } void rsPrint ( xpathResultSet *rs ) { int i = 0,l; char tmp[80]; switch (rs->type) { case EmptyResult: fprintf(stderr, "empty result \n"); break; |
︙ | ︙ | |||
5222 5223 5224 5225 5226 5227 5228 5229 5230 5231 5232 5233 5234 5235 | CHECK_RC; DBG(rsPrint( result );) return 0; } /* xpathEval */ /*---------------------------------------------------------------------------- | xpathMatches | \---------------------------------------------------------------------------*/ int xpathMatches ( ast step, domNode * exprContext, | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 5244 5245 5246 5247 5248 5249 5250 5251 5252 5253 5254 5255 5256 5257 5258 5259 5260 5261 5262 5263 5264 5265 5266 5267 5268 5269 5270 5271 5272 5273 5274 5275 5276 5277 5278 5279 5280 5281 5282 5283 5284 5285 5286 5287 5288 5289 5290 5291 5292 5293 5294 5295 5296 5297 5298 5299 5300 5301 5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 5314 5315 5316 5317 5318 | CHECK_RC; DBG(rsPrint( result );) return 0; } /* xpathEval */ int xpathEvalAst ( ast t, xpathResultSet *nodeList, domNode *node, xpathResultSet *rs, char **errMsg ) { int i, rc, first = 1, docOrder = 1; xpathResultSet savedContext; savedContext = *nodeList; while (t) { DBG (fprintf (stderr, "xpathEvalAst: eval step '%s'\n", astType2str[t->type]);) if (t->type == Pred) { *errMsg = "Pred step not expected now!"; return XPATH_EVAL_ERR; } if (first) { rc = xpathEvalStepAndPredicates (t, nodeList, node, node, 0, &docOrder, NULL, rs, errMsg); CHECK_RC; first = 0; } else { DBG( fprintf(stderr, "doing location step nodeList->nr_nodes=%d \n", nodeList->nr_nodes); ) if (rs->type != xNodeSetResult) { *nodeList = savedContext; return 0; } *nodeList = *rs; xpathRSReset (rs, NULL); for (i=0; i < nodeList->nr_nodes; i++) { rc = xpathEvalStepAndPredicates (t, nodeList, nodeList->nodes[i], node, i, &docOrder, NULL, rs, errMsg); if (rc) { *nodeList = savedContext; return rc; } } } DBG( fprintf(stderr, "result after location step: \n"); ) DBG( rsPrint( result); ) t = t->next; /* skip the already processed Predicate parts */ while (t && t->type == Pred) t = t->next; docOrder = 1; } *nodeList = savedContext; return 0; } /*---------------------------------------------------------------------------- | xpathMatches | \---------------------------------------------------------------------------*/ int xpathMatches ( ast step, domNode * exprContext, |
︙ | ︙ |
Changes to generic/domxpath.h.
︙ | ︙ | |||
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 | ast *t, char **errMsg); void xpathFreeAst (ast t); double xpathGetPrio (ast t); int xpathEval (domNode *node, domNode *exprContext, char *xpath, char **prefixMappings, xpathCBs *cbs, xpathParseVarCB *parseVarCB, Tcl_HashTable *catch, char **errMsg, xpathResultSet *rs); int xpathMatches (ast steps, domNode * exprContext, domNode *nodeToMatch, xpathCBs *cbs, char **errMsg ); int xpathEvalSteps (ast steps, xpathResultSet *nodeList, domNode *currentNode, domNode *exprContext, int currentPos, int *docOrder, xpathCBs *cbs, xpathResultSet *result, char **errMsg); #define xpathRSInit(x) (x)->type = EmptyResult; \ (x)->intvalue = 0; \ (x)->nr_nodes = 0; | > > | > | 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 | ast *t, char **errMsg); void xpathFreeAst (ast t); double xpathGetPrio (ast t); int xpathEval (domNode *node, domNode *exprContext, char *xpath, char **prefixMappings, xpathCBs *cbs, xpathParseVarCB *parseVarCB, Tcl_HashTable *catch, char **errMsg, xpathResultSet *rs); int xpathEvalAst (ast t, xpathResultSet *nodeList, domNode *node, xpathResultSet *rs, char **errMsg); int xpathMatches (ast steps, domNode * exprContext, domNode *nodeToMatch, xpathCBs *cbs, char **errMsg ); int xpathEvalSteps (ast steps, xpathResultSet *nodeList, domNode *currentNode, domNode *exprContext, int currentPos, int *docOrder, xpathCBs *cbs, xpathResultSet *result, char **errMsg); #define xpathRSInit(x) (x)->type = EmptyResult; \ (x)->intvalue = 0; \ (x)->nr_nodes = 0; void xpathRSFree (xpathResultSet *rs); void xpathRSReset (xpathResultSet *rs, domNode *ode); int xpathFuncBoolean (xpathResultSet *rs); double xpathFuncNumber (xpathResultSet *rs, int *NaN); char * xpathFuncString (xpathResultSet *rs); char * xpathFuncStringForNode (domNode *node); int xpathRound (double r); |
︙ | ︙ |
Changes to generic/schema.c.
︙ | ︙ | |||
21 22 23 24 25 26 27 28 29 30 31 32 33 34 | | \---------------------------------------------------------------------------*/ #ifndef TDOM_NO_SCHEMA #include <tdom.h> #include <tcldom.h> #include <schema.h> /* #define DEBUG */ /* #define DDEBUG */ /*---------------------------------------------------------------------------- | Debug Macros | | > | 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | | \---------------------------------------------------------------------------*/ #ifndef TDOM_NO_SCHEMA #include <tdom.h> #include <tcldom.h> #include <domxpath.h> #include <schema.h> /* #define DEBUG */ /* #define DDEBUG */ /*---------------------------------------------------------------------------- | Debug Macros | |
︙ | ︙ | |||
367 368 369 370 371 372 373 374 375 376 377 378 379 380 | se = se->down; } fprintf (stderr, "++++ Stack bottom\n"); } ) /* DBG end */ static void freeSchemaCP ( SchemaCP *pattern ) { int i; SchemaConstraint *sc; | > > > > > > > > > > > > > > > > > > > > | 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 | se = se->down; } fprintf (stderr, "++++ Stack bottom\n"); } ) /* DBG end */ static void freedomKeyConstraints ( domKeyConstraint *kc ) { 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; } } static void freeSchemaCP ( SchemaCP *pattern ) { int i; SchemaConstraint *sc; |
︙ | ︙ | |||
403 404 405 406 407 408 409 410 411 412 413 414 415 416 | FREE (pattern->quants); if (pattern->attrs) { for (i = 0; i < pattern->numAttr; i++) { FREE (pattern->attrs[i]); } FREE (pattern->attrs); } break; } FREE (pattern); } static SchemaData* initSchemaData ( | > | 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 | FREE (pattern->quants); if (pattern->attrs) { for (i = 0; i < pattern->numAttr; i++) { FREE (pattern->attrs[i]); } FREE (pattern->attrs); } freedomKeyConstraints (pattern->domKeys); break; } FREE (pattern); } static SchemaData* initSchemaData ( |
︙ | ︙ | |||
2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 | } XML_ParserFree (parser); Tcl_DStringFree (&cdata); FREE (vdata.uri); while (sdata->stack) popStack (sdata); return result; } static int validateDOM ( Tcl_Interp *interp, SchemaData *sdata, domNode *node ) | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 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 2201 2202 2203 2204 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 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 | } XML_ParserFree (parser); Tcl_DStringFree (&cdata); FREE (vdata.uri); while (sdata->stack) popStack (sdata); return result; } static void schemaxpathRSFree ( xpathResultSet *rs ) { if (rs->type == StringResult) FREE (rs->string); FREE (rs->nodes); } static int checkdomKeyConstraints ( Tcl_Interp *interp, SchemaData *sdata, domNode *node ) { 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)); rs.type = EmptyResult; memset (&frs, 0, sizeof (xpathResultSet)); frs.type = EmptyResult; Tcl_DStringInit (&dStr); while (kc) { xpathRSReset (&rs, NULL); xpathRSReset (&nodeList, node); Tcl_InitHashTable (&htable, TCL_STRING_KEYS); rc = xpathEvalAst (kc->selector, &nodeList, node, &rs, &errMsg); if (rc) { if (recover (interp, sdata, S("INVALID_DOM_KEYCONSTRAINT"))) { goto nextConstraint; } goto errorCleanup; } if (rs.type == EmptyResult) goto nextConstraint; if (rs.type != xNodeSetResult) { if (recover (interp, sdata, S("INVALID_DOM_KEYCONSTRAINT"))) { goto nextConstraint; } SetResult ("INVALID_DOM_KEYCONSTRAINT"); goto errorCleanup; } for (i = 0; i < rs.nr_nodes; i++) { n = rs.nodes[i]; if (n->nodeType != ELEMENT_NODE) { if (recover (interp, sdata, S("INVALID_DOM_KEYCONSTRAINT"))) { break; } SetResult ("INVALID_DOM_KEYCONSTRAINT"); goto errorCleanup; } xpathRSReset (&nodeList, n); if (kc->nrFields == 1) { xpathRSReset (&frs, NULL); rc = xpathEvalAst (kc->fields[0], &nodeList, n, &frs, &errMsg); if (rc) { if (recover (interp, sdata, S("INVALID_DOM_KEYCONSTRAINT"))) { break; } SetResult ("INVALID_DOM_KEYCONSTRAINT"); goto errorCleanup; } if (frs.type != xNodeSetResult && frs.type != EmptyResult) { 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; } continue; } if (frs.nr_nodes != 1) { if (recover (interp, sdata, S("DOM_KEYCONSTRAINT"))) { break; } SetResult ("DOM_KEYCONSTRAINT"); goto errorCleanup; } if (frs.nodes[0]->nodeType != ELEMENT_NODE && frs.nodes[0]->nodeType != ATTRIBUTE_NODE) { if (recover (interp, sdata, S("INVALID_DOM_KEYCONSTRAINT"))) { break; } SetResult ("INVALID_DOM_KEYCONSTRAINT"); goto errorCleanup; } if (frs.nodes[0]->nodeType == ATTRIBUTE_NODE) { attr = (domAttrNode *) frs.nodes[0]; Tcl_CreateHashEntry (&htable, attr->nodeValue, &hnew); if (!hnew) { if (recover (interp, sdata, S("DOM_KEYCONSTRAINT"))) { break; } SetResult ("DOM_KEYCONSTRAINT"); goto errorCleanup; } } else { keystr = xpathGetStringValue (frs.nodes[0], &len); Tcl_CreateHashEntry (&htable, attr->nodeValue, &hnew); FREE(keystr); if (!hnew) { if (recover (interp, sdata, S("DOM_KEYCONSTRAINT"))) { break; } 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; break; } SetResult ("INVALID_DOM_KEYCONSTRAINT"); goto errorCleanup; } if (frs.type != xNodeSetResult && frs.type != EmptyResult) { if (recover (interp, sdata, S("INVALID_DOM_KEYCONSTRAINT"))) { 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; break; } SetResult ("DOM_KEYCONSTRAINT"); goto errorCleanup; } if (frs.nodes[0]->nodeType != ELEMENT_NODE && frs.nodes[0]->nodeType != ATTRIBUTE_NODE) { if (recover (interp, sdata, S("INVALID_DOM_KEYCONSTRAINT"))) { skip = 1; break; } SetResult ("INVALID_DOM_KEYCONSTRAINT"); goto errorCleanup; } if (first) first = 0; else Tcl_DStringAppend (&dStr, ":", 1); if (frs.nodes[0]->nodeType == ATTRIBUTE_NODE) { attr = (domAttrNode *) frs.nodes[0]; Tcl_DStringAppend (&dStr, attr->nodeValue, attr->valueLength); } else { keystr = xpathGetStringValue (frs.nodes[0], &len); Tcl_DStringAppend (&dStr, keystr, len); } } if (skip) break; Tcl_CreateHashEntry (&htable, Tcl_DStringValue (&dStr), &hnew); if (!hnew) { if (recover (interp, sdata, S("DOM_KEYCONSTRAINT"))) { break; } SetResult ("DOM_KEYCONSTRAINT"); goto errorCleanup; } } } nextConstraint: Tcl_DeleteHashTable (&htable); kc = kc->next; } schemaxpathRSFree (&frs); schemaxpathRSFree (&rs); schemaxpathRSFree (&nodeList); return TCL_OK; errorCleanup: Tcl_DeleteHashTable (&htable); schemaxpathRSFree (&frs); schemaxpathRSFree (&rs); schemaxpathRSFree (&nodeList); return TCL_ERROR; } static int validateDOM ( Tcl_Interp *interp, SchemaData *sdata, domNode *node ) |
︙ | ︙ | |||
2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 | /* probeDomAttributes fills interp result with a msg which * required attributes are missing. */ probeDomAttributes (interp, sdata, NULL); return TCL_ERROR; } } node = node->firstChild; while (node) { switch (node->nodeType) { case ELEMENT_NODE: if (Tcl_DStringLength (sdata->cdata)) { if (probeText (interp, sdata, Tcl_DStringValue (sdata->cdata)) != TCL_OK) | > > > > > | 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 | /* probeDomAttributes fills interp result with a msg which * required attributes are missing. */ probeDomAttributes (interp, sdata, NULL); return TCL_ERROR; } } if (sdata->stack->pattern->domKeys) { if (checkdomKeyConstraints (interp, sdata, node) != TCL_OK) return TCL_ERROR; } node = node->firstChild; while (node) { switch (node->nodeType) { case ELEMENT_NODE: if (Tcl_DStringLength (sdata->cdata)) { if (probeText (interp, sdata, Tcl_DStringValue (sdata->cdata)) != TCL_OK) |
︙ | ︙ | |||
3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 | pattern->content[i-1] = (SchemaCP *) objv[i]; Tcl_IncrRefCount (objv[i]); } pattern->nc = objc; addToContent (sdata, pattern, SCHEMA_CQUANT_ONE, 0, 0); return TCL_OK; } static int integerImpl ( Tcl_Interp *interp, void *constraintData, char *text ) | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 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 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 | pattern->content[i-1] = (SchemaCP *) objv[i]; Tcl_IncrRefCount (objv[i]); } pattern->nc = objc; addToContent (sdata, pattern, SCHEMA_CQUANT_ONE, 0, 0); return TCL_OK; } static int domuniquePatternCmd ( ClientData clientData, Tcl_Interp *interp, int objc, 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); xpathFreeAst (t); freedomKeyConstraints (kc); return TCL_ERROR; } kc->fields[i] = t; } if (objc == 4) { kc->name = tdomstrdup (Tcl_GetString (objv[3])); } kc->next = sdata->cp->domKeys; sdata->cp->domKeys = kc; return TCL_OK; } static int integerImpl ( Tcl_Interp *interp, void *constraintData, char *text ) |
︙ | ︙ | |||
4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 4722 4723 4724 4725 | NamespacePatternObjCmd, NULL, NULL); Tcl_CreateObjCommand (interp, "tdom::schema::text", TextPatternObjCmd, NULL, NULL); /* The 'virtual' "tcl" definition command */ Tcl_CreateObjCommand (interp, "tdom::schema::tcl", VirtualPatternObjCmd, NULL, NULL); /* The text constraint commands */ Tcl_CreateObjCommand (interp,"tdom::schema::text::integer", integerTCObjCmd, NULL, NULL); Tcl_CreateObjCommand (interp, "tdom::schema::text::tcl", tclTCObjCmd, NULL, NULL); Tcl_CreateObjCommand (interp, "tdom::schema::text::fixed", | > > > > | 5022 5023 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 5036 5037 5038 5039 | NamespacePatternObjCmd, NULL, NULL); Tcl_CreateObjCommand (interp, "tdom::schema::text", TextPatternObjCmd, NULL, NULL); /* The 'virtual' "tcl" definition command */ Tcl_CreateObjCommand (interp, "tdom::schema::tcl", VirtualPatternObjCmd, NULL, NULL); /* XPath contraints for DOM validation */ Tcl_CreateObjCommand (interp,"tdom::schema::domunique", domuniquePatternCmd, NULL, NULL); /* The text constraint commands */ Tcl_CreateObjCommand (interp,"tdom::schema::text::integer", integerTCObjCmd, NULL, NULL); Tcl_CreateObjCommand (interp, "tdom::schema::text::tcl", tclTCObjCmd, NULL, NULL); Tcl_CreateObjCommand (interp, "tdom::schema::text::fixed", |
︙ | ︙ |
Changes to generic/schema.h.
︙ | ︙ | |||
20 21 22 23 24 25 26 27 28 29 30 31 32 33 | | Nov, Dec 2018 | \---------------------------------------------------------------------------*/ #ifndef __SCHEMA_H__ #define __SCHEMA_H__ typedef enum { SCHEMA_CTYPE_ANY, SCHEMA_CTYPE_NAME, SCHEMA_CTYPE_CHOICE, SCHEMA_CTYPE_INTERLEAVE, SCHEMA_CTYPE_PATTERN, SCHEMA_CTYPE_TEXT, | > > > | 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | | Nov, Dec 2018 | \---------------------------------------------------------------------------*/ #ifndef __SCHEMA_H__ #define __SCHEMA_H__ #include <tcldom.h> #include <domxpath.h> typedef enum { SCHEMA_CTYPE_ANY, SCHEMA_CTYPE_NAME, SCHEMA_CTYPE_CHOICE, SCHEMA_CTYPE_INTERLEAVE, SCHEMA_CTYPE_PATTERN, SCHEMA_CTYPE_TEXT, |
︙ | ︙ | |||
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | /* The SchemaFlags flags */ #define FORWARD_PATTERN_DEF 1 #define PLACEHOLDER_PATTERN_DEF 2 #define AMBIGUOUS_PATTERN 4 #define LOCAL_DEFINED_ELEMENT 8 #define CONSTRAINT_TEXT_CHILD 16 #define MIXED_CONTENT 32 typedef struct SchemaCP { Schema_CP_Type type; char *namespace; char *name; struct SchemaCP *next; SchemaFlags flags; struct SchemaCP **content; SchemaQuant *quants; unsigned int nc; SchemaAttr **attrs; unsigned int numAttr; unsigned int numReqAttr; } SchemaCP; typedef struct SchemaValidationStack { SchemaCP *pattern; struct SchemaValidationStack *next; struct SchemaValidationStack *down; | > > > > > > > > > | 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | /* The SchemaFlags flags */ #define FORWARD_PATTERN_DEF 1 #define PLACEHOLDER_PATTERN_DEF 2 #define AMBIGUOUS_PATTERN 4 #define LOCAL_DEFINED_ELEMENT 8 #define CONSTRAINT_TEXT_CHILD 16 #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; char *name; struct SchemaCP *next; SchemaFlags flags; struct SchemaCP **content; SchemaQuant *quants; unsigned int nc; SchemaAttr **attrs; unsigned int numAttr; unsigned int numReqAttr; domKeyConstraint *domKeys; } SchemaCP; typedef struct SchemaValidationStack { SchemaCP *pattern; struct SchemaValidationStack *next; struct SchemaValidationStack *down; |
︙ | ︙ | |||
106 107 108 109 110 111 112 | typedef struct { Tcl_HashTable ids; int unknownIDrefs; } SchemaDocKey; | | | 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | typedef struct { Tcl_HashTable ids; int unknownIDrefs; } SchemaDocKey; typedef struct SchemaData_ { Tcl_Obj *self; char *start; char *startNamespace; Tcl_HashTable element; Tcl_HashTable namespace; Tcl_HashEntry *emptyNamespace; |
︙ | ︙ |
Changes to tests/schema.test.
︙ | ︙ | |||
4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 | proc postValidation {g xml} { set doc [dom parse $xml] set rc [$g domvalidate $doc errMsg] $doc delete return $rc } } | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644 4645 4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659 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 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 | proc postValidation {g xml} { set doc [dom parse $xml] set rc [$g domvalidate $doc errMsg] $doc delete return $rc } test schema-20.1 {domunique} { set schema { prefixns {ns1 http://tdom.org/test} defelement doc { domunique ${::schema-20.1} @ref } } set result [list] foreach ::schema-20.1 { a ./../a /foo a/b {a | b} a|b (a|b) {a/b/c | b/c/d | c/d/e} .//a //a a/@ref a/b/c {a//b[1]/c} (.//b|a)/c ns1:a a/.//b/c {} { } " " } { tdom::schema s lappend result [catch {s define $schema} errMsg] #puts $errMsg s delete } set result } {0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1} test schema-20.2 {domunique} { tdom::schema s s define { defelement doc { domunique item @ref 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>} } { 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 * { attribute ref ? } domunique item @ref } } } set result [list] foreach xml { {<doc><items><item ref="1"/><item ref="foo"/></items></doc>} {<doc><items><item ref="1"/><item ref="1"/></items></doc>} {<doc><items><item ref="1"/><item ref="foo"/></items><items><item ref="1"/><item ref="foo"/></items></doc>} {<doc><items><item ref="1"/><item ref="foo"/></items><items><item ref="1"/><item ref="bar"/></items></doc>} {<doc><items><item ref="1"/><item ref="foo"/></items><items><item ref="2"/><item ref="bar"/></items></doc>} {<doc><items><item ref="1"/><item ref="foo"/></items><items><item ref="bar"/><item ref="bar"/></items></doc>} } { lappend result [postValidation s $xml] } s delete set result } {1 0 1 1 1 0} 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>} {<doc><item ref="1" id="a"/><item ref="foo" id="a"/></doc>} {<doc><item ref="1" id="a"/><item ref="1" id="a"/></doc>} {<doc><item ref="1" id="a"/><item ref="1" id="b"/></doc>} } { lappend result [postValidation s $xml] } s delete set result } {1 0 1 0 1} } |