Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenpattern.c
Go to the documentation of this file.
00001 /* 00002 * pattern.c: Implemetation of the template match compilation and lookup 00003 * 00004 * Reference: 00005 * http://www.w3.org/TR/1999/REC-xslt-19991116 00006 * 00007 * See Copyright for the status of this software. 00008 * 00009 * daniel@veillard.com 00010 */ 00011 00012 /* 00013 * TODO: handle pathological cases like *[*[@a="b"]] 00014 * TODO: detect [number] at compilation, optimize accordingly 00015 */ 00016 00017 #define IN_LIBXSLT 00018 #include "libxslt.h" 00019 00020 #include <string.h> 00021 00022 #include <libxml/xmlmemory.h> 00023 #include <libxml/tree.h> 00024 #include <libxml/valid.h> 00025 #include <libxml/hash.h> 00026 #include <libxml/xmlerror.h> 00027 #include <libxml/parserInternals.h> 00028 #include "xslt.h" 00029 #include "xsltInternals.h" 00030 #include "xsltutils.h" 00031 #include "imports.h" 00032 #include "templates.h" 00033 #include "keys.h" 00034 #include "pattern.h" 00035 #include "documents.h" 00036 00037 #ifdef WITH_XSLT_DEBUG 00038 #define WITH_XSLT_DEBUG_PATTERN 00039 #endif 00040 00041 /* 00042 * Types are private: 00043 */ 00044 00045 typedef enum { 00046 XSLT_OP_END=0, 00047 XSLT_OP_ROOT, 00048 XSLT_OP_ELEM, 00049 XSLT_OP_ATTR, 00050 XSLT_OP_PARENT, 00051 XSLT_OP_ANCESTOR, 00052 XSLT_OP_ID, 00053 XSLT_OP_KEY, 00054 XSLT_OP_NS, 00055 XSLT_OP_ALL, 00056 XSLT_OP_PI, 00057 XSLT_OP_COMMENT, 00058 XSLT_OP_TEXT, 00059 XSLT_OP_NODE, 00060 XSLT_OP_PREDICATE 00061 } xsltOp; 00062 00063 typedef enum { 00064 AXIS_CHILD=1, 00065 AXIS_ATTRIBUTE 00066 } xsltAxis; 00067 00068 typedef struct _xsltStepState xsltStepState; 00069 typedef xsltStepState *xsltStepStatePtr; 00070 struct _xsltStepState { 00071 int step; 00072 xmlNodePtr node; 00073 }; 00074 00075 typedef struct _xsltStepStates xsltStepStates; 00076 typedef xsltStepStates *xsltStepStatesPtr; 00077 struct _xsltStepStates { 00078 int nbstates; 00079 int maxstates; 00080 xsltStepStatePtr states; 00081 }; 00082 00083 typedef struct _xsltStepOp xsltStepOp; 00084 typedef xsltStepOp *xsltStepOpPtr; 00085 struct _xsltStepOp { 00086 xsltOp op; 00087 xmlChar *value; 00088 xmlChar *value2; 00089 xmlChar *value3; 00090 xmlXPathCompExprPtr comp; 00091 /* 00092 * Optimisations for count 00093 */ 00094 int previousExtra; 00095 int indexExtra; 00096 int lenExtra; 00097 }; 00098 00099 struct _xsltCompMatch { 00100 struct _xsltCompMatch *next; /* siblings in the name hash */ 00101 float priority; /* the priority */ 00102 const xmlChar *pattern; /* the pattern */ 00103 const xmlChar *mode; /* the mode */ 00104 const xmlChar *modeURI; /* the mode URI */ 00105 xsltTemplatePtr template; /* the associated template */ 00106 00107 int direct; 00108 /* TODO fix the statically allocated size steps[] */ 00109 int nbStep; 00110 int maxStep; 00111 xmlNsPtr *nsList; /* the namespaces in scope */ 00112 int nsNr; /* the number of namespaces in scope */ 00113 xsltStepOpPtr steps; /* ops for computation */ 00114 }; 00115 00116 typedef struct _xsltParserContext xsltParserContext; 00117 typedef xsltParserContext *xsltParserContextPtr; 00118 struct _xsltParserContext { 00119 xsltStylesheetPtr style; /* the stylesheet */ 00120 xsltTransformContextPtr ctxt; /* the transformation or NULL */ 00121 const xmlChar *cur; /* the current char being parsed */ 00122 const xmlChar *base; /* the full expression */ 00123 xmlDocPtr doc; /* the source document */ 00124 xmlNodePtr elem; /* the source element */ 00125 int error; /* error code */ 00126 xsltCompMatchPtr comp; /* the result */ 00127 }; 00128 00129 /************************************************************************ 00130 * * 00131 * Type functions * 00132 * * 00133 ************************************************************************/ 00134 00142 static xsltCompMatchPtr 00143 xsltNewCompMatch(void) { 00144 xsltCompMatchPtr cur; 00145 00146 cur = (xsltCompMatchPtr) xmlMalloc(sizeof(xsltCompMatch)); 00147 if (cur == NULL) { 00148 xsltTransformError(NULL, NULL, NULL, 00149 "xsltNewCompMatch : out of memory error\n"); 00150 return(NULL); 00151 } 00152 memset(cur, 0, sizeof(xsltCompMatch)); 00153 cur->maxStep = 10; 00154 cur->nbStep = 0; 00155 cur-> steps = (xsltStepOpPtr) xmlMalloc(sizeof(xsltStepOp) * 00156 cur->maxStep); 00157 if (cur->steps == NULL) { 00158 xsltTransformError(NULL, NULL, NULL, 00159 "xsltNewCompMatch : out of memory error\n"); 00160 xmlFree(cur); 00161 return(NULL); 00162 } 00163 cur->nsNr = 0; 00164 cur->nsList = NULL; 00165 cur->direct = 0; 00166 return(cur); 00167 } 00168 00175 static void 00176 xsltFreeCompMatch(xsltCompMatchPtr comp) { 00177 xsltStepOpPtr op; 00178 int i; 00179 00180 if (comp == NULL) 00181 return; 00182 if (comp->pattern != NULL) 00183 xmlFree((xmlChar *)comp->pattern); 00184 if (comp->nsList != NULL) 00185 xmlFree(comp->nsList); 00186 for (i = 0;i < comp->nbStep;i++) { 00187 op = &comp->steps[i]; 00188 if (op->value != NULL) 00189 xmlFree(op->value); 00190 if (op->value2 != NULL) 00191 xmlFree(op->value2); 00192 if (op->value3 != NULL) 00193 xmlFree(op->value3); 00194 if (op->comp != NULL) 00195 xmlXPathFreeCompExpr(op->comp); 00196 } 00197 xmlFree(comp->steps); 00198 memset(comp, -1, sizeof(xsltCompMatch)); 00199 xmlFree(comp); 00200 } 00201 00208 void 00209 xsltFreeCompMatchList(xsltCompMatchPtr comp) { 00210 xsltCompMatchPtr cur; 00211 00212 while (comp != NULL) { 00213 cur = comp; 00214 comp = comp->next; 00215 xsltFreeCompMatch(cur); 00216 } 00217 } 00218 00228 void xsltNormalizeCompSteps(void *payload, 00229 void *data, const xmlChar *name ATTRIBUTE_UNUSED) { 00230 xsltCompMatchPtr comp = payload; 00231 xsltStylesheetPtr style = data; 00232 int ix; 00233 00234 for (ix = 0; ix < comp->nbStep; ix++) { 00235 comp->steps[ix].previousExtra += style->extrasNr; 00236 comp->steps[ix].indexExtra += style->extrasNr; 00237 comp->steps[ix].lenExtra += style->extrasNr; 00238 } 00239 } 00240 00250 static xsltParserContextPtr 00251 xsltNewParserContext(xsltStylesheetPtr style, xsltTransformContextPtr ctxt) { 00252 xsltParserContextPtr cur; 00253 00254 cur = (xsltParserContextPtr) xmlMalloc(sizeof(xsltParserContext)); 00255 if (cur == NULL) { 00256 xsltTransformError(NULL, NULL, NULL, 00257 "xsltNewParserContext : malloc failed\n"); 00258 return(NULL); 00259 } 00260 memset(cur, 0, sizeof(xsltParserContext)); 00261 cur->style = style; 00262 cur->ctxt = ctxt; 00263 return(cur); 00264 } 00265 00272 static void 00273 xsltFreeParserContext(xsltParserContextPtr ctxt) { 00274 if (ctxt == NULL) 00275 return; 00276 memset(ctxt, -1, sizeof(xsltParserContext)); 00277 xmlFree(ctxt); 00278 } 00279 00292 static int 00293 xsltCompMatchAdd(xsltParserContextPtr ctxt, xsltCompMatchPtr comp, 00294 xsltOp op, xmlChar * value, xmlChar * value2, int novar) 00295 { 00296 if (comp->nbStep >= comp->maxStep) { 00297 xsltStepOpPtr tmp; 00298 00299 tmp = (xsltStepOpPtr) xmlRealloc(comp->steps, comp->maxStep * 2 * 00300 sizeof(xsltStepOp)); 00301 if (tmp == NULL) { 00302 xsltGenericError(xsltGenericErrorContext, 00303 "xsltCompMatchAdd: memory re-allocation failure.\n"); 00304 if (ctxt->style != NULL) 00305 ctxt->style->errors++; 00306 return (-1); 00307 } 00308 comp->maxStep *= 2; 00309 comp->steps = tmp; 00310 } 00311 comp->steps[comp->nbStep].op = op; 00312 comp->steps[comp->nbStep].value = value; 00313 comp->steps[comp->nbStep].value2 = value2; 00314 comp->steps[comp->nbStep].value3 = NULL; 00315 comp->steps[comp->nbStep].comp = NULL; 00316 if (ctxt->ctxt != NULL) { 00317 comp->steps[comp->nbStep].previousExtra = 00318 xsltAllocateExtraCtxt(ctxt->ctxt); 00319 comp->steps[comp->nbStep].indexExtra = 00320 xsltAllocateExtraCtxt(ctxt->ctxt); 00321 comp->steps[comp->nbStep].lenExtra = 00322 xsltAllocateExtraCtxt(ctxt->ctxt); 00323 } else { 00324 comp->steps[comp->nbStep].previousExtra = 00325 xsltAllocateExtra(ctxt->style); 00326 comp->steps[comp->nbStep].indexExtra = 00327 xsltAllocateExtra(ctxt->style); 00328 comp->steps[comp->nbStep].lenExtra = 00329 xsltAllocateExtra(ctxt->style); 00330 } 00331 if (op == XSLT_OP_PREDICATE) { 00332 xmlXPathContextPtr xctxt; 00333 00334 if (ctxt->style != NULL) 00335 xctxt = xmlXPathNewContext(ctxt->style->doc); 00336 else 00337 xctxt = xmlXPathNewContext(NULL); 00338 #ifdef XML_XPATH_NOVAR 00339 if (novar != 0) 00340 xctxt->flags = XML_XPATH_NOVAR; 00341 #endif 00342 if (ctxt->style != NULL) 00343 xctxt->dict = ctxt->style->dict; 00344 comp->steps[comp->nbStep].comp = xmlXPathCtxtCompile(xctxt, value); 00345 xmlXPathFreeContext(xctxt); 00346 if (comp->steps[comp->nbStep].comp == NULL) { 00347 xsltTransformError(NULL, ctxt->style, ctxt->elem, 00348 "Failed to compile predicate\n"); 00349 if (ctxt->style != NULL) 00350 ctxt->style->errors++; 00351 } 00352 } 00353 comp->nbStep++; 00354 return (0); 00355 } 00356 00363 static void 00364 xsltSwapTopCompMatch(xsltCompMatchPtr comp) { 00365 int i; 00366 int j = comp->nbStep - 1; 00367 00368 if (j > 0) { 00369 register xmlChar *tmp; 00370 register xsltOp op; 00371 register xmlXPathCompExprPtr expr; 00372 register int t; 00373 i = j - 1; 00374 tmp = comp->steps[i].value; 00375 comp->steps[i].value = comp->steps[j].value; 00376 comp->steps[j].value = tmp; 00377 tmp = comp->steps[i].value2; 00378 comp->steps[i].value2 = comp->steps[j].value2; 00379 comp->steps[j].value2 = tmp; 00380 tmp = comp->steps[i].value3; 00381 comp->steps[i].value3 = comp->steps[j].value3; 00382 comp->steps[j].value3 = tmp; 00383 op = comp->steps[i].op; 00384 comp->steps[i].op = comp->steps[j].op; 00385 comp->steps[j].op = op; 00386 expr = comp->steps[i].comp; 00387 comp->steps[i].comp = comp->steps[j].comp; 00388 comp->steps[j].comp = expr; 00389 t = comp->steps[i].previousExtra; 00390 comp->steps[i].previousExtra = comp->steps[j].previousExtra; 00391 comp->steps[j].previousExtra = t; 00392 t = comp->steps[i].indexExtra; 00393 comp->steps[i].indexExtra = comp->steps[j].indexExtra; 00394 comp->steps[j].indexExtra = t; 00395 t = comp->steps[i].lenExtra; 00396 comp->steps[i].lenExtra = comp->steps[j].lenExtra; 00397 comp->steps[j].lenExtra = t; 00398 } 00399 } 00400 00408 static void 00409 xsltReverseCompMatch(xsltParserContextPtr ctxt, xsltCompMatchPtr comp) { 00410 int i = 0; 00411 int j = comp->nbStep - 1; 00412 00413 while (j > i) { 00414 register xmlChar *tmp; 00415 register xsltOp op; 00416 register xmlXPathCompExprPtr expr; 00417 register int t; 00418 00419 tmp = comp->steps[i].value; 00420 comp->steps[i].value = comp->steps[j].value; 00421 comp->steps[j].value = tmp; 00422 tmp = comp->steps[i].value2; 00423 comp->steps[i].value2 = comp->steps[j].value2; 00424 comp->steps[j].value2 = tmp; 00425 tmp = comp->steps[i].value3; 00426 comp->steps[i].value3 = comp->steps[j].value3; 00427 comp->steps[j].value3 = tmp; 00428 op = comp->steps[i].op; 00429 comp->steps[i].op = comp->steps[j].op; 00430 comp->steps[j].op = op; 00431 expr = comp->steps[i].comp; 00432 comp->steps[i].comp = comp->steps[j].comp; 00433 comp->steps[j].comp = expr; 00434 t = comp->steps[i].previousExtra; 00435 comp->steps[i].previousExtra = comp->steps[j].previousExtra; 00436 comp->steps[j].previousExtra = t; 00437 t = comp->steps[i].indexExtra; 00438 comp->steps[i].indexExtra = comp->steps[j].indexExtra; 00439 comp->steps[j].indexExtra = t; 00440 t = comp->steps[i].lenExtra; 00441 comp->steps[i].lenExtra = comp->steps[j].lenExtra; 00442 comp->steps[j].lenExtra = t; 00443 j--; 00444 i++; 00445 } 00446 xsltCompMatchAdd(ctxt, comp, XSLT_OP_END, NULL, NULL, 0); 00447 00448 /* 00449 * detect consecutive XSLT_OP_PREDICATE indicating a direct 00450 * matching should be done. 00451 */ 00452 for (i = 0;i < comp->nbStep - 1;i++) { 00453 if ((comp->steps[i].op == XSLT_OP_PREDICATE) && 00454 (comp->steps[i + 1].op == XSLT_OP_PREDICATE)) { 00455 00456 comp->direct = 1; 00457 if (comp->pattern[0] != '/') { 00458 xmlChar *query; 00459 00460 query = xmlStrdup((const xmlChar *)"//"); 00461 query = xmlStrcat(query, comp->pattern); 00462 00463 xmlFree((xmlChar *) comp->pattern); 00464 comp->pattern = query; 00465 } 00466 break; 00467 } 00468 } 00469 } 00470 00471 /************************************************************************ 00472 * * 00473 * The interpreter for the precompiled patterns * 00474 * * 00475 ************************************************************************/ 00476 00477 static int 00478 xsltPatPushState(xsltTransformContextPtr ctxt, xsltStepStates *states, 00479 int step, xmlNodePtr node) { 00480 if ((states->states == NULL) || (states->maxstates <= 0)) { 00481 states->maxstates = 4; 00482 states->nbstates = 0; 00483 states->states = xmlMalloc(4 * sizeof(xsltStepState)); 00484 } 00485 else if (states->maxstates <= states->nbstates) { 00486 xsltStepState *tmp; 00487 00488 tmp = (xsltStepStatePtr) xmlRealloc(states->states, 00489 2 * states->maxstates * sizeof(xsltStepState)); 00490 if (tmp == NULL) { 00491 xsltGenericError(xsltGenericErrorContext, 00492 "xsltPatPushState: memory re-allocation failure.\n"); 00493 ctxt->state = XSLT_STATE_STOPPED; 00494 return(-1); 00495 } 00496 states->states = tmp; 00497 states->maxstates *= 2; 00498 } 00499 states->states[states->nbstates].step = step; 00500 states->states[states->nbstates++].node = node; 00501 #if 0 00502 fprintf(stderr, "Push: %d, %s\n", step, node->name); 00503 #endif 00504 return(0); 00505 } 00506 00520 static int 00521 xsltTestCompMatchDirect(xsltTransformContextPtr ctxt, xsltCompMatchPtr comp, 00522 xmlNodePtr node, xmlNsPtr *nsList, int nsNr) { 00523 xsltStepOpPtr sel = NULL; 00524 xmlDocPtr prevdoc; 00525 xmlDocPtr doc; 00526 xmlXPathObjectPtr list; 00527 int ix, j; 00528 int nocache = 0; 00529 int isRVT; 00530 00531 doc = node->doc; 00532 if (XSLT_IS_RES_TREE_FRAG(doc)) 00533 isRVT = 1; 00534 else 00535 isRVT = 0; 00536 sel = &comp->steps[0]; /* store extra in first step arbitrarily */ 00537 00538 prevdoc = (xmlDocPtr) 00539 XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr); 00540 ix = XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival); 00541 list = (xmlXPathObjectPtr) 00542 XSLT_RUNTIME_EXTRA_LST(ctxt, sel->lenExtra); 00543 00544 if ((list == NULL) || (prevdoc != doc)) { 00545 xmlXPathObjectPtr newlist; 00546 xmlNodePtr parent = node->parent; 00547 xmlDocPtr olddoc; 00548 xmlNodePtr oldnode; 00549 int oldNsNr; 00550 xmlNsPtr *oldNamespaces; 00551 00552 oldnode = ctxt->xpathCtxt->node; 00553 olddoc = ctxt->xpathCtxt->doc; 00554 oldNsNr = ctxt->xpathCtxt->nsNr; 00555 oldNamespaces = ctxt->xpathCtxt->namespaces; 00556 ctxt->xpathCtxt->node = node; 00557 ctxt->xpathCtxt->doc = doc; 00558 ctxt->xpathCtxt->namespaces = nsList; 00559 ctxt->xpathCtxt->nsNr = nsNr; 00560 newlist = xmlXPathEval(comp->pattern, ctxt->xpathCtxt); 00561 ctxt->xpathCtxt->node = oldnode; 00562 ctxt->xpathCtxt->doc = olddoc; 00563 ctxt->xpathCtxt->namespaces = oldNamespaces; 00564 ctxt->xpathCtxt->nsNr = oldNsNr; 00565 if (newlist == NULL) 00566 return(-1); 00567 if (newlist->type != XPATH_NODESET) { 00568 xmlXPathFreeObject(newlist); 00569 return(-1); 00570 } 00571 ix = 0; 00572 00573 if ((parent == NULL) || (node->doc == NULL) || isRVT) 00574 nocache = 1; 00575 00576 if (nocache == 0) { 00577 if (list != NULL) 00578 xmlXPathFreeObject(list); 00579 list = newlist; 00580 00581 XSLT_RUNTIME_EXTRA_LST(ctxt, sel->lenExtra) = 00582 (void *) list; 00583 XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr) = 00584 (void *) doc; 00585 XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) = 00586 0; 00587 XSLT_RUNTIME_EXTRA_FREE(ctxt, sel->lenExtra) = 00588 (xmlFreeFunc) xmlXPathFreeObject; 00589 } else 00590 list = newlist; 00591 } 00592 if ((list->nodesetval == NULL) || 00593 (list->nodesetval->nodeNr <= 0)) { 00594 if (nocache == 1) 00595 xmlXPathFreeObject(list); 00596 return(0); 00597 } 00598 /* TODO: store the index and use it for the scan */ 00599 if (ix == 0) { 00600 for (j = 0;j < list->nodesetval->nodeNr;j++) { 00601 if (list->nodesetval->nodeTab[j] == node) { 00602 if (nocache == 1) 00603 xmlXPathFreeObject(list); 00604 return(1); 00605 } 00606 } 00607 } else { 00608 } 00609 if (nocache == 1) 00610 xmlXPathFreeObject(list); 00611 return(0); 00612 } 00613 00626 static int 00627 xsltTestCompMatch(xsltTransformContextPtr ctxt, xsltCompMatchPtr comp, 00628 xmlNodePtr node, const xmlChar *mode, 00629 const xmlChar *modeURI) { 00630 int i; 00631 xsltStepOpPtr step, sel = NULL; 00632 xsltStepStates states = {0, 0, NULL}; /* // may require backtrack */ 00633 00634 if ((comp == NULL) || (node == NULL) || (ctxt == NULL)) { 00635 xsltTransformError(ctxt, NULL, node, 00636 "xsltTestCompMatch: null arg\n"); 00637 return(-1); 00638 } 00639 if (mode != NULL) { 00640 if (comp->mode == NULL) 00641 return(0); 00642 /* 00643 * both mode strings must be interned on the stylesheet dictionary 00644 */ 00645 if (comp->mode != mode) 00646 return(0); 00647 } else { 00648 if (comp->mode != NULL) 00649 return(0); 00650 } 00651 if (modeURI != NULL) { 00652 if (comp->modeURI == NULL) 00653 return(0); 00654 /* 00655 * both modeURI strings must be interned on the stylesheet dictionary 00656 */ 00657 if (comp->modeURI != modeURI) 00658 return(0); 00659 } else { 00660 if (comp->modeURI != NULL) 00661 return(0); 00662 } 00663 00664 i = 0; 00665 restart: 00666 for (;i < comp->nbStep;i++) { 00667 step = &comp->steps[i]; 00668 if (step->op != XSLT_OP_PREDICATE) 00669 sel = step; 00670 switch (step->op) { 00671 case XSLT_OP_END: 00672 goto found; 00673 case XSLT_OP_ROOT: 00674 if ((node->type == XML_DOCUMENT_NODE) || 00675 #ifdef LIBXML_DOCB_ENABLED 00676 (node->type == XML_DOCB_DOCUMENT_NODE) || 00677 #endif 00678 (node->type == XML_HTML_DOCUMENT_NODE)) 00679 continue; 00680 if ((node->type == XML_ELEMENT_NODE) && (node->name[0] == ' ')) 00681 continue; 00682 goto rollback; 00683 case XSLT_OP_ELEM: 00684 if (node->type != XML_ELEMENT_NODE) 00685 goto rollback; 00686 if (step->value == NULL) 00687 continue; 00688 if (step->value[0] != node->name[0]) 00689 goto rollback; 00690 if (!xmlStrEqual(step->value, node->name)) 00691 goto rollback; 00692 00693 /* Namespace test */ 00694 if (node->ns == NULL) { 00695 if (step->value2 != NULL) 00696 goto rollback; 00697 } else if (node->ns->href != NULL) { 00698 if (step->value2 == NULL) 00699 goto rollback; 00700 if (!xmlStrEqual(step->value2, node->ns->href)) 00701 goto rollback; 00702 } 00703 continue; 00704 case XSLT_OP_ATTR: 00705 if (node->type != XML_ATTRIBUTE_NODE) 00706 goto rollback; 00707 if (step->value != NULL) { 00708 if (step->value[0] != node->name[0]) 00709 goto rollback; 00710 if (!xmlStrEqual(step->value, node->name)) 00711 goto rollback; 00712 } 00713 /* Namespace test */ 00714 if (node->ns == NULL) { 00715 if (step->value2 != NULL) 00716 goto rollback; 00717 } else if (step->value2 != NULL) { 00718 if (!xmlStrEqual(step->value2, node->ns->href)) 00719 goto rollback; 00720 } 00721 continue; 00722 case XSLT_OP_PARENT: 00723 if ((node->type == XML_DOCUMENT_NODE) || 00724 (node->type == XML_HTML_DOCUMENT_NODE) || 00725 #ifdef LIBXML_DOCB_ENABLED 00726 (node->type == XML_DOCB_DOCUMENT_NODE) || 00727 #endif 00728 (node->type == XML_NAMESPACE_DECL)) 00729 goto rollback; 00730 node = node->parent; 00731 if (node == NULL) 00732 goto rollback; 00733 if (step->value == NULL) 00734 continue; 00735 if (step->value[0] != node->name[0]) 00736 goto rollback; 00737 if (!xmlStrEqual(step->value, node->name)) 00738 goto rollback; 00739 /* Namespace test */ 00740 if (node->ns == NULL) { 00741 if (step->value2 != NULL) 00742 goto rollback; 00743 } else if (node->ns->href != NULL) { 00744 if (step->value2 == NULL) 00745 goto rollback; 00746 if (!xmlStrEqual(step->value2, node->ns->href)) 00747 goto rollback; 00748 } 00749 continue; 00750 case XSLT_OP_ANCESTOR: 00751 /* TODO: implement coalescing of ANCESTOR/NODE ops */ 00752 if (step->value == NULL) { 00753 step = &comp->steps[i+1]; 00754 if (step->op == XSLT_OP_ROOT) 00755 goto found; 00756 /* added NS, ID and KEY as a result of bug 168208 */ 00757 if ((step->op != XSLT_OP_ELEM) && 00758 (step->op != XSLT_OP_ALL) && 00759 (step->op != XSLT_OP_NS) && 00760 (step->op != XSLT_OP_ID) && 00761 (step->op != XSLT_OP_KEY)) 00762 goto rollback; 00763 } 00764 if (node == NULL) 00765 goto rollback; 00766 if ((node->type == XML_DOCUMENT_NODE) || 00767 (node->type == XML_HTML_DOCUMENT_NODE) || 00768 #ifdef LIBXML_DOCB_ENABLED 00769 (node->type == XML_DOCB_DOCUMENT_NODE) || 00770 #endif 00771 (node->type == XML_NAMESPACE_DECL)) 00772 goto rollback; 00773 node = node->parent; 00774 if ((step->op != XSLT_OP_ELEM) && step->op != XSLT_OP_ALL) { 00775 xsltPatPushState(ctxt, &states, i, node); 00776 continue; 00777 } 00778 i++; 00779 if (step->value == NULL) { 00780 xsltPatPushState(ctxt, &states, i - 1, node); 00781 continue; 00782 } 00783 while (node != NULL) { 00784 if ((node->type == XML_ELEMENT_NODE) && 00785 (step->value[0] == node->name[0]) && 00786 (xmlStrEqual(step->value, node->name))) { 00787 /* Namespace test */ 00788 if (node->ns == NULL) { 00789 if (step->value2 == NULL) 00790 break; 00791 } else if (node->ns->href != NULL) { 00792 if ((step->value2 != NULL) && 00793 (xmlStrEqual(step->value2, node->ns->href))) 00794 break; 00795 } 00796 } 00797 node = node->parent; 00798 } 00799 if (node == NULL) 00800 goto rollback; 00801 xsltPatPushState(ctxt, &states, i - 1, node); 00802 continue; 00803 case XSLT_OP_ID: { 00804 /* TODO Handle IDs decently, must be done differently */ 00805 xmlAttrPtr id; 00806 00807 if (node->type != XML_ELEMENT_NODE) 00808 goto rollback; 00809 00810 id = xmlGetID(node->doc, step->value); 00811 if ((id == NULL) || (id->parent != node)) 00812 goto rollback; 00813 break; 00814 } 00815 case XSLT_OP_KEY: { 00816 xmlNodeSetPtr list; 00817 int indx; 00818 00819 list = xsltGetKey(ctxt, step->value, 00820 step->value3, step->value2); 00821 if (list == NULL) 00822 goto rollback; 00823 for (indx = 0;indx < list->nodeNr;indx++) 00824 if (list->nodeTab[indx] == node) 00825 break; 00826 if (indx >= list->nodeNr) 00827 goto rollback; 00828 break; 00829 } 00830 case XSLT_OP_NS: 00831 if (node->type != XML_ELEMENT_NODE) 00832 goto rollback; 00833 if (node->ns == NULL) { 00834 if (step->value != NULL) 00835 goto rollback; 00836 } else if (node->ns->href != NULL) { 00837 if (step->value == NULL) 00838 goto rollback; 00839 if (!xmlStrEqual(step->value, node->ns->href)) 00840 goto rollback; 00841 } 00842 break; 00843 case XSLT_OP_ALL: 00844 if (node->type != XML_ELEMENT_NODE) 00845 goto rollback; 00846 break; 00847 case XSLT_OP_PREDICATE: { 00848 xmlNodePtr oldNode; 00849 xmlDocPtr doc; 00850 int oldCS, oldCP; 00851 int pos = 0, len = 0; 00852 int isRVT; 00853 00854 /* 00855 * when there is cascading XSLT_OP_PREDICATE, then use a 00856 * direct computation approach. It's not done directly 00857 * at the beginning of the routine to filter out as much 00858 * as possible this costly computation. 00859 */ 00860 if (comp->direct) { 00861 if (states.states != NULL) { 00862 /* Free the rollback states */ 00863 xmlFree(states.states); 00864 } 00865 return(xsltTestCompMatchDirect(ctxt, comp, node, 00866 comp->nsList, comp->nsNr)); 00867 } 00868 00869 doc = node->doc; 00870 if (XSLT_IS_RES_TREE_FRAG(doc)) 00871 isRVT = 1; 00872 else 00873 isRVT = 0; 00874 00875 /* 00876 * Depending on the last selection, one may need to 00877 * recompute contextSize and proximityPosition. 00878 */ 00879 oldCS = ctxt->xpathCtxt->contextSize; 00880 oldCP = ctxt->xpathCtxt->proximityPosition; 00881 if ((sel != NULL) && 00882 (sel->op == XSLT_OP_ELEM) && 00883 (sel->value != NULL) && 00884 (node->type == XML_ELEMENT_NODE) && 00885 (node->parent != NULL)) { 00886 xmlNodePtr previous; 00887 int ix, nocache = 0; 00888 00889 previous = (xmlNodePtr) 00890 XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr); 00891 ix = XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival); 00892 if ((previous != NULL) && 00893 (previous->parent == node->parent)) { 00894 /* 00895 * just walk back to adjust the index 00896 */ 00897 int indx = 0; 00898 xmlNodePtr sibling = node; 00899 00900 while (sibling != NULL) { 00901 if (sibling == previous) 00902 break; 00903 if ((previous->type == XML_ELEMENT_NODE) && 00904 (previous->name != NULL) && 00905 (sibling->name != NULL) && 00906 (previous->name[0] == sibling->name[0]) && 00907 (xmlStrEqual(previous->name, sibling->name))) 00908 { 00909 if ((sel->value2 == NULL) || 00910 ((sibling->ns != NULL) && 00911 (xmlStrEqual(sel->value2, 00912 sibling->ns->href)))) 00913 indx++; 00914 } 00915 sibling = sibling->prev; 00916 } 00917 if (sibling == NULL) { 00918 /* hum going backward in document order ... */ 00919 indx = 0; 00920 sibling = node; 00921 while (sibling != NULL) { 00922 if (sibling == previous) 00923 break; 00924 if ((previous->type == XML_ELEMENT_NODE) && 00925 (previous->name != NULL) && 00926 (sibling->name != NULL) && 00927 (previous->name[0] == sibling->name[0]) && 00928 (xmlStrEqual(previous->name, sibling->name))) 00929 { 00930 if ((sel->value2 == NULL) || 00931 ((sibling->ns != NULL) && 00932 (xmlStrEqual(sel->value2, 00933 sibling->ns->href)))) 00934 { 00935 indx--; 00936 } 00937 } 00938 sibling = sibling->next; 00939 } 00940 } 00941 if (sibling != NULL) { 00942 pos = ix + indx; 00943 /* 00944 * If the node is in a Value Tree we need to 00945 * save len, but cannot cache the node! 00946 * (bugs 153137 and 158840) 00947 */ 00948 if (node->doc != NULL) { 00949 len = XSLT_RUNTIME_EXTRA(ctxt, 00950 sel->lenExtra, ival); 00951 if (!isRVT) { 00952 XSLT_RUNTIME_EXTRA(ctxt, 00953 sel->previousExtra, ptr) = node; 00954 XSLT_RUNTIME_EXTRA(ctxt, 00955 sel->indexExtra, ival) = pos; 00956 } 00957 } 00958 ix = pos; 00959 } else 00960 pos = 0; 00961 } else { 00962 /* 00963 * recompute the index 00964 */ 00965 xmlNodePtr parent = node->parent; 00966 xmlNodePtr siblings = NULL; 00967 00968 if (parent) siblings = parent->children; 00969 00970 while (siblings != NULL) { 00971 if (siblings->type == XML_ELEMENT_NODE) { 00972 if (siblings == node) { 00973 len++; 00974 pos = len; 00975 } else if ((node->name != NULL) && 00976 (siblings->name != NULL) && 00977 (node->name[0] == siblings->name[0]) && 00978 (xmlStrEqual(node->name, siblings->name))) { 00979 if ((sel->value2 == NULL) || 00980 ((siblings->ns != NULL) && 00981 (xmlStrEqual(sel->value2, 00982 siblings->ns->href)))) 00983 len++; 00984 } 00985 } 00986 siblings = siblings->next; 00987 } 00988 if ((parent == NULL) || (node->doc == NULL)) 00989 nocache = 1; 00990 else { 00991 while (parent->parent != NULL) 00992 parent = parent->parent; 00993 if (((parent->type != XML_DOCUMENT_NODE) && 00994 (parent->type != XML_HTML_DOCUMENT_NODE)) || 00995 (parent != (xmlNodePtr) node->doc)) 00996 nocache = 1; 00997 } 00998 } 00999 if (pos != 0) { 01000 ctxt->xpathCtxt->contextSize = len; 01001 ctxt->xpathCtxt->proximityPosition = pos; 01002 /* 01003 * If the node is in a Value Tree we cannot 01004 * cache it ! 01005 */ 01006 if ((!isRVT) && (node->doc != NULL) && 01007 (nocache == 0)) { 01008 XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr) = 01009 node; 01010 XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) = 01011 pos; 01012 XSLT_RUNTIME_EXTRA(ctxt, sel->lenExtra, ival) = 01013 len; 01014 } 01015 } 01016 } else if ((sel != NULL) && (sel->op == XSLT_OP_ALL) && 01017 (node->type == XML_ELEMENT_NODE)) { 01018 xmlNodePtr previous; 01019 int ix, nocache = 0; 01020 01021 previous = (xmlNodePtr) 01022 XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr); 01023 ix = XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival); 01024 if ((previous != NULL) && 01025 (previous->parent == node->parent)) { 01026 /* 01027 * just walk back to adjust the index 01028 */ 01029 int indx = 0; 01030 xmlNodePtr sibling = node; 01031 01032 while (sibling != NULL) { 01033 if (sibling == previous) 01034 break; 01035 if (sibling->type == XML_ELEMENT_NODE) 01036 indx++; 01037 sibling = sibling->prev; 01038 } 01039 if (sibling == NULL) { 01040 /* hum going backward in document order ... */ 01041 indx = 0; 01042 sibling = node; 01043 while (sibling != NULL) { 01044 if (sibling == previous) 01045 break; 01046 if (sibling->type == XML_ELEMENT_NODE) 01047 indx--; 01048 sibling = sibling->next; 01049 } 01050 } 01051 if (sibling != NULL) { 01052 pos = ix + indx; 01053 /* 01054 * If the node is in a Value Tree we cannot 01055 * cache it ! 01056 */ 01057 if ((node->doc != NULL) && !isRVT) { 01058 len = XSLT_RUNTIME_EXTRA(ctxt, 01059 sel->lenExtra, ival); 01060 XSLT_RUNTIME_EXTRA(ctxt, 01061 sel->previousExtra, ptr) = node; 01062 XSLT_RUNTIME_EXTRA(ctxt, 01063 sel->indexExtra, ival) = pos; 01064 } 01065 } else 01066 pos = 0; 01067 } else { 01068 /* 01069 * recompute the index 01070 */ 01071 xmlNodePtr parent = node->parent; 01072 xmlNodePtr siblings = NULL; 01073 01074 if (parent) siblings = parent->children; 01075 01076 while (siblings != NULL) { 01077 if (siblings->type == XML_ELEMENT_NODE) { 01078 len++; 01079 if (siblings == node) { 01080 pos = len; 01081 } 01082 } 01083 siblings = siblings->next; 01084 } 01085 if ((parent == NULL) || (node->doc == NULL)) 01086 nocache = 1; 01087 else { 01088 while (parent->parent != NULL) 01089 parent = parent->parent; 01090 if (((parent->type != XML_DOCUMENT_NODE) && 01091 (parent->type != XML_HTML_DOCUMENT_NODE)) || 01092 (parent != (xmlNodePtr) node->doc)) 01093 nocache = 1; 01094 } 01095 } 01096 if (pos != 0) { 01097 ctxt->xpathCtxt->contextSize = len; 01098 ctxt->xpathCtxt->proximityPosition = pos; 01099 /* 01100 * If the node is in a Value Tree we cannot 01101 * cache it ! 01102 */ 01103 if ((node->doc != NULL) && (nocache == 0) && !isRVT) { 01104 XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr) = 01105 node; 01106 XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) = 01107 pos; 01108 XSLT_RUNTIME_EXTRA(ctxt, sel->lenExtra, ival) = 01109 len; 01110 } 01111 } 01112 } 01113 oldNode = ctxt->node; 01114 ctxt->node = node; 01115 01116 if (step->value == NULL) 01117 goto wrong_index; 01118 if (step->comp == NULL) 01119 goto wrong_index; 01120 01121 if (!xsltEvalXPathPredicate(ctxt, step->comp, comp->nsList, 01122 comp->nsNr)) 01123 goto wrong_index; 01124 01125 if (pos != 0) { 01126 ctxt->xpathCtxt->contextSize = oldCS; 01127 ctxt->xpathCtxt->proximityPosition = oldCP; 01128 } 01129 ctxt->node = oldNode; 01130 break; 01131 wrong_index: 01132 if (pos != 0) { 01133 ctxt->xpathCtxt->contextSize = oldCS; 01134 ctxt->xpathCtxt->proximityPosition = oldCP; 01135 } 01136 ctxt->node = oldNode; 01137 goto rollback; 01138 } 01139 case XSLT_OP_PI: 01140 if (node->type != XML_PI_NODE) 01141 goto rollback; 01142 if (step->value != NULL) { 01143 if (!xmlStrEqual(step->value, node->name)) 01144 goto rollback; 01145 } 01146 break; 01147 case XSLT_OP_COMMENT: 01148 if (node->type != XML_COMMENT_NODE) 01149 goto rollback; 01150 break; 01151 case XSLT_OP_TEXT: 01152 if ((node->type != XML_TEXT_NODE) && 01153 (node->type != XML_CDATA_SECTION_NODE)) 01154 goto rollback; 01155 break; 01156 case XSLT_OP_NODE: 01157 switch (node->type) { 01158 case XML_ELEMENT_NODE: 01159 case XML_CDATA_SECTION_NODE: 01160 case XML_PI_NODE: 01161 case XML_COMMENT_NODE: 01162 case XML_TEXT_NODE: 01163 break; 01164 default: 01165 goto rollback; 01166 } 01167 break; 01168 } 01169 } 01170 found: 01171 if (states.states != NULL) { 01172 /* Free the rollback states */ 01173 xmlFree(states.states); 01174 } 01175 return(1); 01176 rollback: 01177 /* got an error try to rollback */ 01178 if (states.states == NULL) 01179 return(0); 01180 if (states.nbstates <= 0) { 01181 xmlFree(states.states); 01182 return(0); 01183 } 01184 states.nbstates--; 01185 i = states.states[states.nbstates].step; 01186 node = states.states[states.nbstates].node; 01187 #if 0 01188 fprintf(stderr, "Pop: %d, %s\n", i, node->name); 01189 #endif 01190 goto restart; 01191 } 01192 01203 int 01204 xsltTestCompMatchList(xsltTransformContextPtr ctxt, xmlNodePtr node, 01205 xsltCompMatchPtr comp) { 01206 int ret; 01207 01208 if ((ctxt == NULL) || (node == NULL)) 01209 return(-1); 01210 while (comp != NULL) { 01211 ret = xsltTestCompMatch(ctxt, comp, node, NULL, NULL); 01212 if (ret == 1) 01213 return(1); 01214 comp = comp->next; 01215 } 01216 return(0); 01217 } 01218 01219 /************************************************************************ 01220 * * 01221 * Dedicated parser for templates * 01222 * * 01223 ************************************************************************/ 01224 01225 #define CUR (*ctxt->cur) 01226 #define SKIP(val) ctxt->cur += (val) 01227 #define NXT(val) ctxt->cur[(val)] 01228 #define CUR_PTR ctxt->cur 01229 01230 #define SKIP_BLANKS \ 01231 while (IS_BLANK_CH(CUR)) NEXT 01232 01233 #define CURRENT (*ctxt->cur) 01234 #define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur) 01235 01236 01237 #define PUSH(op, val, val2, novar) \ 01238 if (xsltCompMatchAdd(ctxt, ctxt->comp, (op), (val), (val2), (novar))) goto error; 01239 01240 #define SWAP() \ 01241 xsltSwapTopCompMatch(ctxt->comp); 01242 01243 #define XSLT_ERROR(X) \ 01244 { xsltError(ctxt, __FILE__, __LINE__, X); \ 01245 ctxt->error = (X); return; } 01246 01247 #define XSLT_ERROR0(X) \ 01248 { xsltError(ctxt, __FILE__, __LINE__, X); \ 01249 ctxt->error = (X); return(0); } 01250 01263 static xmlChar * 01264 xsltScanLiteral(xsltParserContextPtr ctxt) { 01265 const xmlChar *q, *cur; 01266 xmlChar *ret = NULL; 01267 int val, len; 01268 01269 SKIP_BLANKS; 01270 if (CUR == '"') { 01271 NEXT; 01272 cur = q = CUR_PTR; 01273 val = xmlStringCurrentChar(NULL, cur, &len); 01274 while ((IS_CHAR(val)) && (val != '"')) { 01275 cur += len; 01276 val = xmlStringCurrentChar(NULL, cur, &len); 01277 } 01278 if (!IS_CHAR(val)) { 01279 ctxt->error = 1; 01280 return(NULL); 01281 } else { 01282 ret = xmlStrndup(q, cur - q); 01283 } 01284 cur += len; 01285 CUR_PTR = cur; 01286 } else if (CUR == '\'') { 01287 NEXT; 01288 cur = q = CUR_PTR; 01289 val = xmlStringCurrentChar(NULL, cur, &len); 01290 while ((IS_CHAR(val)) && (val != '\'')) { 01291 cur += len; 01292 val = xmlStringCurrentChar(NULL, cur, &len); 01293 } 01294 if (!IS_CHAR(val)) { 01295 ctxt->error = 1; 01296 return(NULL); 01297 } else { 01298 ret = xmlStrndup(q, cur - q); 01299 } 01300 cur += len; 01301 CUR_PTR = cur; 01302 } else { 01303 /* XP_ERROR(XPATH_START_LITERAL_ERROR); */ 01304 ctxt->error = 1; 01305 return(NULL); 01306 } 01307 return(ret); 01308 } 01309 01319 static xmlChar * 01320 xsltScanNCName(xsltParserContextPtr ctxt) { 01321 const xmlChar *q, *cur; 01322 xmlChar *ret = NULL; 01323 int val, len; 01324 01325 SKIP_BLANKS; 01326 01327 cur = q = CUR_PTR; 01328 val = xmlStringCurrentChar(NULL, cur, &len); 01329 if (!IS_LETTER(val) && (val != '_')) 01330 return(NULL); 01331 01332 while ((IS_LETTER(val)) || (IS_DIGIT(val)) || 01333 (val == '.') || (val == '-') || 01334 (val == '_') || 01335 (IS_COMBINING(val)) || 01336 (IS_EXTENDER(val))) { 01337 cur += len; 01338 val = xmlStringCurrentChar(NULL, cur, &len); 01339 } 01340 ret = xmlStrndup(q, cur - q); 01341 CUR_PTR = cur; 01342 return(ret); 01343 } 01344 01345 /* 01346 * xsltCompileIdKeyPattern: 01347 * @ctxt: the compilation context 01348 * @name: a preparsed name 01349 * @aid: whether id/key are allowed there 01350 * @novar: flag to prohibit xslt var 01351 * 01352 * Compile the XSLT LocationIdKeyPattern 01353 * [3] IdKeyPattern ::= 'id' '(' Literal ')' 01354 * | 'key' '(' Literal ',' Literal ')' 01355 * 01356 * also handle NodeType and PI from: 01357 * 01358 * [7] NodeTest ::= NameTest 01359 * | NodeType '(' ')' 01360 * | 'processing-instruction' '(' Literal ')' 01361 */ 01362 static void 01363 xsltCompileIdKeyPattern(xsltParserContextPtr ctxt, xmlChar *name, 01364 int aid, int novar, xsltAxis axis) { 01365 xmlChar *lit = NULL; 01366 xmlChar *lit2 = NULL; 01367 01368 if (CUR != '(') { 01369 xsltTransformError(NULL, NULL, NULL, 01370 "xsltCompileIdKeyPattern : ( expected\n"); 01371 ctxt->error = 1; 01372 return; 01373 } 01374 if ((aid) && (xmlStrEqual(name, (const xmlChar *)"id"))) { 01375 if (axis != 0) { 01376 xsltTransformError(NULL, NULL, NULL, 01377 "xsltCompileIdKeyPattern : NodeTest expected\n"); 01378 ctxt->error = 1; 01379 return; 01380 } 01381 NEXT; 01382 SKIP_BLANKS; 01383 lit = xsltScanLiteral(ctxt); 01384 if (ctxt->error) 01385 return; 01386 SKIP_BLANKS; 01387 if (CUR != ')') { 01388 xsltTransformError(NULL, NULL, NULL, 01389 "xsltCompileIdKeyPattern : ) expected\n"); 01390 ctxt->error = 1; 01391 return; 01392 } 01393 NEXT; 01394 PUSH(XSLT_OP_ID, lit, NULL, novar); 01395 } else if ((aid) && (xmlStrEqual(name, (const xmlChar *)"key"))) { 01396 if (axis != 0) { 01397 xsltTransformError(NULL, NULL, NULL, 01398 "xsltCompileIdKeyPattern : NodeTest expected\n"); 01399 ctxt->error = 1; 01400 return; 01401 } 01402 NEXT; 01403 SKIP_BLANKS; 01404 lit = xsltScanLiteral(ctxt); 01405 if (ctxt->error) 01406 return; 01407 SKIP_BLANKS; 01408 if (CUR != ',') { 01409 xsltTransformError(NULL, NULL, NULL, 01410 "xsltCompileIdKeyPattern : , expected\n"); 01411 ctxt->error = 1; 01412 return; 01413 } 01414 NEXT; 01415 SKIP_BLANKS; 01416 lit2 = xsltScanLiteral(ctxt); 01417 if (ctxt->error) 01418 return; 01419 SKIP_BLANKS; 01420 if (CUR != ')') { 01421 xsltTransformError(NULL, NULL, NULL, 01422 "xsltCompileIdKeyPattern : ) expected\n"); 01423 ctxt->error = 1; 01424 return; 01425 } 01426 NEXT; 01427 /* URGENT TODO: support namespace in keys */ 01428 PUSH(XSLT_OP_KEY, lit, lit2, novar); 01429 } else if (xmlStrEqual(name, (const xmlChar *)"processing-instruction")) { 01430 NEXT; 01431 SKIP_BLANKS; 01432 if (CUR != ')') { 01433 lit = xsltScanLiteral(ctxt); 01434 if (ctxt->error) 01435 return; 01436 SKIP_BLANKS; 01437 if (CUR != ')') { 01438 xsltTransformError(NULL, NULL, NULL, 01439 "xsltCompileIdKeyPattern : ) expected\n"); 01440 ctxt->error = 1; 01441 return; 01442 } 01443 } 01444 NEXT; 01445 PUSH(XSLT_OP_PI, lit, NULL, novar); 01446 } else if (xmlStrEqual(name, (const xmlChar *)"text")) { 01447 NEXT; 01448 SKIP_BLANKS; 01449 if (CUR != ')') { 01450 xsltTransformError(NULL, NULL, NULL, 01451 "xsltCompileIdKeyPattern : ) expected\n"); 01452 ctxt->error = 1; 01453 return; 01454 } 01455 NEXT; 01456 PUSH(XSLT_OP_TEXT, NULL, NULL, novar); 01457 } else if (xmlStrEqual(name, (const xmlChar *)"comment")) { 01458 NEXT; 01459 SKIP_BLANKS; 01460 if (CUR != ')') { 01461 xsltTransformError(NULL, NULL, NULL, 01462 "xsltCompileIdKeyPattern : ) expected\n"); 01463 ctxt->error = 1; 01464 return; 01465 } 01466 NEXT; 01467 PUSH(XSLT_OP_COMMENT, NULL, NULL, novar); 01468 } else if (xmlStrEqual(name, (const xmlChar *)"node")) { 01469 NEXT; 01470 SKIP_BLANKS; 01471 if (CUR != ')') { 01472 xsltTransformError(NULL, NULL, NULL, 01473 "xsltCompileIdKeyPattern : ) expected\n"); 01474 ctxt->error = 1; 01475 return; 01476 } 01477 NEXT; 01478 if (axis == AXIS_ATTRIBUTE) { 01479 PUSH(XSLT_OP_ATTR, NULL, NULL, novar); 01480 } 01481 else { 01482 PUSH(XSLT_OP_NODE, NULL, NULL, novar); 01483 } 01484 } else if (aid) { 01485 xsltTransformError(NULL, NULL, NULL, 01486 "xsltCompileIdKeyPattern : expecting 'key' or 'id' or node type\n"); 01487 ctxt->error = 1; 01488 return; 01489 } else { 01490 xsltTransformError(NULL, NULL, NULL, 01491 "xsltCompileIdKeyPattern : node type\n"); 01492 ctxt->error = 1; 01493 return; 01494 } 01495 error: 01496 if (name != NULL) 01497 xmlFree(name); 01498 } 01499 01522 static void 01523 xsltCompileStepPattern(xsltParserContextPtr ctxt, xmlChar *token, int novar) { 01524 xmlChar *name = NULL; 01525 const xmlChar *URI = NULL; 01526 xmlChar *URL = NULL; 01527 int level; 01528 xsltAxis axis = 0; 01529 01530 SKIP_BLANKS; 01531 if ((token == NULL) && (CUR == '@')) { 01532 NEXT; 01533 axis = AXIS_ATTRIBUTE; 01534 } 01535 parse_node_test: 01536 if (token == NULL) 01537 token = xsltScanNCName(ctxt); 01538 if (token == NULL) { 01539 if (CUR == '*') { 01540 NEXT; 01541 if (axis == AXIS_ATTRIBUTE) { 01542 PUSH(XSLT_OP_ATTR, NULL, NULL, novar); 01543 } 01544 else { 01545 PUSH(XSLT_OP_ALL, NULL, NULL, novar); 01546 } 01547 goto parse_predicate; 01548 } else { 01549 xsltTransformError(NULL, NULL, NULL, 01550 "xsltCompileStepPattern : Name expected\n"); 01551 ctxt->error = 1; 01552 goto error; 01553 } 01554 } 01555 01556 01557 SKIP_BLANKS; 01558 if (CUR == '(') { 01559 xsltCompileIdKeyPattern(ctxt, token, 0, novar, axis); 01560 if (ctxt->error) 01561 goto error; 01562 } else if (CUR == ':') { 01563 NEXT; 01564 if (CUR != ':') { 01565 xmlChar *prefix = token; 01566 xmlNsPtr ns; 01567 01568 /* 01569 * This is a namespace match 01570 */ 01571 token = xsltScanNCName(ctxt); 01572 ns = xmlSearchNs(ctxt->doc, ctxt->elem, prefix); 01573 if (ns == NULL) { 01574 xsltTransformError(NULL, NULL, NULL, 01575 "xsltCompileStepPattern : no namespace bound to prefix %s\n", 01576 prefix); 01577 xmlFree(prefix); 01578 ctxt->error = 1; 01579 goto error; 01580 } else { 01581 URL = xmlStrdup(ns->href); 01582 } 01583 xmlFree(prefix); 01584 if (token == NULL) { 01585 if (CUR == '*') { 01586 NEXT; 01587 if (axis == AXIS_ATTRIBUTE) { 01588 PUSH(XSLT_OP_ATTR, NULL, URL, novar); 01589 } 01590 else { 01591 PUSH(XSLT_OP_NS, URL, NULL, novar); 01592 } 01593 } else { 01594 xsltTransformError(NULL, NULL, NULL, 01595 "xsltCompileStepPattern : Name expected\n"); 01596 ctxt->error = 1; 01597 goto error; 01598 } 01599 } else { 01600 if (axis == AXIS_ATTRIBUTE) { 01601 PUSH(XSLT_OP_ATTR, token, URL, novar); 01602 } 01603 else { 01604 PUSH(XSLT_OP_ELEM, token, URL, novar); 01605 } 01606 } 01607 } else { 01608 if (axis != 0) { 01609 xsltTransformError(NULL, NULL, NULL, 01610 "xsltCompileStepPattern : NodeTest expected\n"); 01611 ctxt->error = 1; 01612 goto error; 01613 } 01614 NEXT; 01615 if (xmlStrEqual(token, (const xmlChar *) "child")) { 01616 axis = AXIS_CHILD; 01617 } else if (xmlStrEqual(token, (const xmlChar *) "attribute")) { 01618 axis = AXIS_ATTRIBUTE; 01619 } else { 01620 xsltTransformError(NULL, NULL, NULL, 01621 "xsltCompileStepPattern : 'child' or 'attribute' expected\n"); 01622 ctxt->error = 1; 01623 goto error; 01624 } 01625 xmlFree(token); 01626 SKIP_BLANKS; 01627 token = xsltScanNCName(ctxt); 01628 goto parse_node_test; 01629 } 01630 } else { 01631 URI = xsltGetQNameURI(ctxt->elem, &token); 01632 if (token == NULL) { 01633 ctxt->error = 1; 01634 goto error; 01635 } 01636 if (URI != NULL) 01637 URL = xmlStrdup(URI); 01638 if (axis == AXIS_ATTRIBUTE) { 01639 PUSH(XSLT_OP_ATTR, token, URL, novar); 01640 } 01641 else { 01642 PUSH(XSLT_OP_ELEM, token, URL, novar); 01643 } 01644 } 01645 parse_predicate: 01646 SKIP_BLANKS; 01647 level = 0; 01648 while (CUR == '[') { 01649 const xmlChar *q; 01650 xmlChar *ret = NULL; 01651 01652 level++; 01653 NEXT; 01654 q = CUR_PTR; 01655 while (CUR != 0) { 01656 /* Skip over nested predicates */ 01657 if (CUR == '[') 01658 level++; 01659 else if (CUR == ']') { 01660 level--; 01661 if (level == 0) 01662 break; 01663 } else if (CUR == '"') { 01664 NEXT; 01665 while ((CUR != 0) && (CUR != '"')) 01666 NEXT; 01667 } else if (CUR == '\'') { 01668 NEXT; 01669 while ((CUR != 0) && (CUR != '\'')) 01670 NEXT; 01671 } 01672 NEXT; 01673 } 01674 if (CUR == 0) { 01675 xsltTransformError(NULL, NULL, NULL, 01676 "xsltCompileStepPattern : ']' expected\n"); 01677 ctxt->error = 1; 01678 return; 01679 } 01680 ret = xmlStrndup(q, CUR_PTR - q); 01681 PUSH(XSLT_OP_PREDICATE, ret, NULL, novar); 01682 /* push the predicate lower than local test */ 01683 SWAP(); 01684 NEXT; 01685 SKIP_BLANKS; 01686 } 01687 return; 01688 error: 01689 if (token != NULL) 01690 xmlFree(token); 01691 if (name != NULL) 01692 xmlFree(name); 01693 } 01694 01708 static void 01709 xsltCompileRelativePathPattern(xsltParserContextPtr ctxt, xmlChar *token, int novar) { 01710 xsltCompileStepPattern(ctxt, token, novar); 01711 if (ctxt->error) 01712 goto error; 01713 SKIP_BLANKS; 01714 while ((CUR != 0) && (CUR != '|')) { 01715 if ((CUR == '/') && (NXT(1) == '/')) { 01716 PUSH(XSLT_OP_ANCESTOR, NULL, NULL, novar); 01717 NEXT; 01718 NEXT; 01719 SKIP_BLANKS; 01720 xsltCompileStepPattern(ctxt, NULL, novar); 01721 } else if (CUR == '/') { 01722 PUSH(XSLT_OP_PARENT, NULL, NULL, novar); 01723 NEXT; 01724 SKIP_BLANKS; 01725 if ((CUR != 0) && (CUR != '|')) { 01726 xsltCompileRelativePathPattern(ctxt, NULL, novar); 01727 } 01728 } else { 01729 ctxt->error = 1; 01730 } 01731 if (ctxt->error) 01732 goto error; 01733 SKIP_BLANKS; 01734 } 01735 error: 01736 return; 01737 } 01738 01751 static void 01752 xsltCompileLocationPathPattern(xsltParserContextPtr ctxt, int novar) { 01753 SKIP_BLANKS; 01754 if ((CUR == '/') && (NXT(1) == '/')) { 01755 /* 01756 * since we reverse the query 01757 * a leading // can be safely ignored 01758 */ 01759 NEXT; 01760 NEXT; 01761 ctxt->comp->priority = 0.5; /* '//' means not 0 priority */ 01762 xsltCompileRelativePathPattern(ctxt, NULL, novar); 01763 } else if (CUR == '/') { 01764 /* 01765 * We need to find root as the parent 01766 */ 01767 NEXT; 01768 SKIP_BLANKS; 01769 PUSH(XSLT_OP_ROOT, NULL, NULL, novar); 01770 if ((CUR != 0) && (CUR != '|')) { 01771 PUSH(XSLT_OP_PARENT, NULL, NULL, novar); 01772 xsltCompileRelativePathPattern(ctxt, NULL, novar); 01773 } 01774 } else if (CUR == '*') { 01775 xsltCompileRelativePathPattern(ctxt, NULL, novar); 01776 } else if (CUR == '@') { 01777 xsltCompileRelativePathPattern(ctxt, NULL, novar); 01778 } else { 01779 xmlChar *name; 01780 name = xsltScanNCName(ctxt); 01781 if (name == NULL) { 01782 xsltTransformError(NULL, NULL, NULL, 01783 "xsltCompileLocationPathPattern : Name expected\n"); 01784 ctxt->error = 1; 01785 return; 01786 } 01787 SKIP_BLANKS; 01788 if ((CUR == '(') && !xmlXPathIsNodeType(name)) { 01789 xsltCompileIdKeyPattern(ctxt, name, 1, novar, 0); 01790 if ((CUR == '/') && (NXT(1) == '/')) { 01791 PUSH(XSLT_OP_ANCESTOR, NULL, NULL, novar); 01792 NEXT; 01793 NEXT; 01794 SKIP_BLANKS; 01795 xsltCompileRelativePathPattern(ctxt, NULL, novar); 01796 } else if (CUR == '/') { 01797 PUSH(XSLT_OP_PARENT, NULL, NULL, novar); 01798 NEXT; 01799 SKIP_BLANKS; 01800 xsltCompileRelativePathPattern(ctxt, NULL, novar); 01801 } 01802 return; 01803 } 01804 xsltCompileRelativePathPattern(ctxt, name, novar); 01805 } 01806 error: 01807 return; 01808 } 01809 01827 static xsltCompMatchPtr 01828 xsltCompilePatternInternal(const xmlChar *pattern, xmlDocPtr doc, 01829 xmlNodePtr node, xsltStylesheetPtr style, 01830 xsltTransformContextPtr runtime, int novar) { 01831 xsltParserContextPtr ctxt = NULL; 01832 xsltCompMatchPtr element, first = NULL, previous = NULL; 01833 int current, start, end, level, j; 01834 01835 if (pattern == NULL) { 01836 xsltTransformError(NULL, NULL, node, 01837 "xsltCompilePattern : NULL pattern\n"); 01838 return(NULL); 01839 } 01840 01841 ctxt = xsltNewParserContext(style, runtime); 01842 if (ctxt == NULL) 01843 return(NULL); 01844 ctxt->doc = doc; 01845 ctxt->elem = node; 01846 current = end = 0; 01847 while (pattern[current] != 0) { 01848 start = current; 01849 while (IS_BLANK_CH(pattern[current])) 01850 current++; 01851 end = current; 01852 level = 0; 01853 while ((pattern[end] != 0) && ((pattern[end] != '|') || (level != 0))) { 01854 if (pattern[end] == '[') 01855 level++; 01856 else if (pattern[end] == ']') 01857 level--; 01858 else if (pattern[end] == '\'') { 01859 end++; 01860 while ((pattern[end] != 0) && (pattern[end] != '\'')) 01861 end++; 01862 } else if (pattern[end] == '"') { 01863 end++; 01864 while ((pattern[end] != 0) && (pattern[end] != '"')) 01865 end++; 01866 } 01867 end++; 01868 } 01869 if (current == end) { 01870 xsltTransformError(NULL, NULL, node, 01871 "xsltCompilePattern : NULL pattern\n"); 01872 goto error; 01873 } 01874 element = xsltNewCompMatch(); 01875 if (element == NULL) { 01876 goto error; 01877 } 01878 if (first == NULL) 01879 first = element; 01880 else if (previous != NULL) 01881 previous->next = element; 01882 previous = element; 01883 01884 ctxt->comp = element; 01885 ctxt->base = xmlStrndup(&pattern[start], end - start); 01886 if (ctxt->base == NULL) 01887 goto error; 01888 ctxt->cur = &(ctxt->base)[current - start]; 01889 element->pattern = ctxt->base; 01890 element->nsList = xmlGetNsList(doc, node); 01891 j = 0; 01892 if (element->nsList != NULL) { 01893 while (element->nsList[j] != NULL) 01894 j++; 01895 } 01896 element->nsNr = j; 01897 01898 01899 #ifdef WITH_XSLT_DEBUG_PATTERN 01900 xsltGenericDebug(xsltGenericDebugContext, 01901 "xsltCompilePattern : parsing '%s'\n", 01902 element->pattern); 01903 #endif 01904 /* 01905 Preset default priority to be zero. 01906 This may be changed by xsltCompileLocationPathPattern. 01907 */ 01908 element->priority = 0; 01909 xsltCompileLocationPathPattern(ctxt, novar); 01910 if (ctxt->error) { 01911 xsltTransformError(NULL, style, node, 01912 "xsltCompilePattern : failed to compile '%s'\n", 01913 element->pattern); 01914 if (style != NULL) style->errors++; 01915 goto error; 01916 } 01917 01918 /* 01919 * Reverse for faster interpretation. 01920 */ 01921 xsltReverseCompMatch(ctxt, element); 01922 01923 /* 01924 * Set-up the priority 01925 */ 01926 if (element->priority == 0) { /* if not yet determined */ 01927 if (((element->steps[0].op == XSLT_OP_ELEM) || 01928 (element->steps[0].op == XSLT_OP_ATTR) || 01929 (element->steps[0].op == XSLT_OP_PI)) && 01930 (element->steps[0].value != NULL) && 01931 (element->steps[1].op == XSLT_OP_END)) { 01932 ; /* previously preset */ 01933 } else if ((element->steps[0].op == XSLT_OP_ATTR) && 01934 (element->steps[0].value2 != NULL) && 01935 (element->steps[1].op == XSLT_OP_END)) { 01936 element->priority = -0.25; 01937 } else if ((element->steps[0].op == XSLT_OP_NS) && 01938 (element->steps[0].value != NULL) && 01939 (element->steps[1].op == XSLT_OP_END)) { 01940 element->priority = -0.25; 01941 } else if ((element->steps[0].op == XSLT_OP_ATTR) && 01942 (element->steps[0].value == NULL) && 01943 (element->steps[0].value2 == NULL) && 01944 (element->steps[1].op == XSLT_OP_END)) { 01945 element->priority = -0.5; 01946 } else if (((element->steps[0].op == XSLT_OP_PI) || 01947 (element->steps[0].op == XSLT_OP_TEXT) || 01948 (element->steps[0].op == XSLT_OP_ALL) || 01949 (element->steps[0].op == XSLT_OP_NODE) || 01950 (element->steps[0].op == XSLT_OP_COMMENT)) && 01951 (element->steps[1].op == XSLT_OP_END)) { 01952 element->priority = -0.5; 01953 } else { 01954 element->priority = 0.5; 01955 } 01956 } 01957 #ifdef WITH_XSLT_DEBUG_PATTERN 01958 xsltGenericDebug(xsltGenericDebugContext, 01959 "xsltCompilePattern : parsed %s, default priority %f\n", 01960 element->pattern, element->priority); 01961 #endif 01962 if (pattern[end] == '|') 01963 end++; 01964 current = end; 01965 } 01966 if (end == 0) { 01967 xsltTransformError(NULL, style, node, 01968 "xsltCompilePattern : NULL pattern\n"); 01969 if (style != NULL) style->errors++; 01970 goto error; 01971 } 01972 01973 xsltFreeParserContext(ctxt); 01974 return(first); 01975 01976 error: 01977 if (ctxt != NULL) 01978 xsltFreeParserContext(ctxt); 01979 if (first != NULL) 01980 xsltFreeCompMatchList(first); 01981 return(NULL); 01982 } 01983 02000 xsltCompMatchPtr 02001 xsltCompilePattern(const xmlChar *pattern, xmlDocPtr doc, 02002 xmlNodePtr node, xsltStylesheetPtr style, 02003 xsltTransformContextPtr runtime) { 02004 return (xsltCompilePatternInternal(pattern, doc, node, style, runtime, 0)); 02005 } 02006 02007 /************************************************************************ 02008 * * 02009 * Module interfaces * 02010 * * 02011 ************************************************************************/ 02012 02024 int 02025 xsltAddTemplate(xsltStylesheetPtr style, xsltTemplatePtr cur, 02026 const xmlChar *mode, const xmlChar *modeURI) { 02027 xsltCompMatchPtr pat, list, next; 02028 /* 02029 * 'top' will point to style->xxxMatch ptr - declaring as 'void' 02030 * avoids gcc 'type-punned pointer' warning. 02031 */ 02032 void **top = NULL; 02033 const xmlChar *name = NULL; 02034 float priority; /* the priority */ 02035 02036 if ((style == NULL) || (cur == NULL) || (cur->match == NULL)) 02037 return(-1); 02038 02039 priority = cur->priority; 02040 pat = xsltCompilePatternInternal(cur->match, style->doc, cur->elem, 02041 style, NULL, 1); 02042 if (pat == NULL) 02043 return(-1); 02044 while (pat) { 02045 next = pat->next; 02046 pat->next = NULL; 02047 name = NULL; 02048 02049 pat->template = cur; 02050 if (mode != NULL) 02051 pat->mode = xmlDictLookup(style->dict, mode, -1); 02052 if (modeURI != NULL) 02053 pat->modeURI = xmlDictLookup(style->dict, modeURI, -1); 02054 if (priority != XSLT_PAT_NO_PRIORITY) 02055 pat->priority = priority; 02056 02057 /* 02058 * insert it in the hash table list corresponding to its lookup name 02059 */ 02060 switch (pat->steps[0].op) { 02061 case XSLT_OP_ATTR: 02062 if (pat->steps[0].value != NULL) 02063 name = pat->steps[0].value; 02064 else 02065 top = &(style->attrMatch); 02066 break; 02067 case XSLT_OP_PARENT: 02068 case XSLT_OP_ANCESTOR: 02069 top = &(style->elemMatch); 02070 break; 02071 case XSLT_OP_ROOT: 02072 top = &(style->rootMatch); 02073 break; 02074 case XSLT_OP_KEY: 02075 top = &(style->keyMatch); 02076 break; 02077 case XSLT_OP_ID: 02078 /* TODO optimize ID !!! */ 02079 case XSLT_OP_NS: 02080 case XSLT_OP_ALL: 02081 top = &(style->elemMatch); 02082 break; 02083 case XSLT_OP_END: 02084 case XSLT_OP_PREDICATE: 02085 xsltTransformError(NULL, style, NULL, 02086 "xsltAddTemplate: invalid compiled pattern\n"); 02087 xsltFreeCompMatch(pat); 02088 return(-1); 02089 /* 02090 * TODO: some flags at the top level about type based patterns 02091 * would be faster than inclusion in the hash table. 02092 */ 02093 case XSLT_OP_PI: 02094 if (pat->steps[0].value != NULL) 02095 name = pat->steps[0].value; 02096 else 02097 top = &(style->piMatch); 02098 break; 02099 case XSLT_OP_COMMENT: 02100 top = &(style->commentMatch); 02101 break; 02102 case XSLT_OP_TEXT: 02103 top = &(style->textMatch); 02104 break; 02105 case XSLT_OP_ELEM: 02106 case XSLT_OP_NODE: 02107 if (pat->steps[0].value != NULL) 02108 name = pat->steps[0].value; 02109 else 02110 top = &(style->elemMatch); 02111 break; 02112 } 02113 if (name != NULL) { 02114 if (style->templatesHash == NULL) { 02115 style->templatesHash = xmlHashCreate(1024); 02116 if (style->templatesHash == NULL) { 02117 xsltFreeCompMatch(pat); 02118 return(-1); 02119 } 02120 xmlHashAddEntry3(style->templatesHash, name, mode, modeURI, pat); 02121 } else { 02122 list = (xsltCompMatchPtr) xmlHashLookup3(style->templatesHash, 02123 name, mode, modeURI); 02124 if (list == NULL) { 02125 xmlHashAddEntry3(style->templatesHash, name, 02126 mode, modeURI, pat); 02127 } else { 02128 /* 02129 * Note '<=' since one must choose among the matching 02130 * template rules that are left, the one that occurs 02131 * last in the stylesheet 02132 */ 02133 if (list->priority <= pat->priority) { 02134 pat->next = list; 02135 xmlHashUpdateEntry3(style->templatesHash, name, 02136 mode, modeURI, pat, NULL); 02137 } else { 02138 while (list->next != NULL) { 02139 if (list->next->priority <= pat->priority) 02140 break; 02141 list = list->next; 02142 } 02143 pat->next = list->next; 02144 list->next = pat; 02145 } 02146 } 02147 } 02148 } else if (top != NULL) { 02149 list = *top; 02150 if (list == NULL) { 02151 *top = pat; 02152 pat->next = NULL; 02153 } else if (list->priority <= pat->priority) { 02154 pat->next = list; 02155 *top = pat; 02156 } else { 02157 while (list->next != NULL) { 02158 if (list->next->priority <= pat->priority) 02159 break; 02160 list = list->next; 02161 } 02162 pat->next = list->next; 02163 list->next = pat; 02164 } 02165 } else { 02166 xsltTransformError(NULL, style, NULL, 02167 "xsltAddTemplate: invalid compiled pattern\n"); 02168 xsltFreeCompMatch(pat); 02169 return(-1); 02170 } 02171 #ifdef WITH_XSLT_DEBUG_PATTERN 02172 if (mode) 02173 xsltGenericDebug(xsltGenericDebugContext, 02174 "added pattern : '%s' mode '%s' priority %f\n", 02175 pat->pattern, pat->mode, pat->priority); 02176 else 02177 xsltGenericDebug(xsltGenericDebugContext, 02178 "added pattern : '%s' priority %f\n", 02179 pat->pattern, pat->priority); 02180 #endif 02181 02182 pat = next; 02183 } 02184 return(0); 02185 } 02186 02187 static int 02188 xsltComputeAllKeys(xsltTransformContextPtr ctxt, xmlNodePtr contextNode) 02189 { 02190 if ((ctxt == NULL) || (contextNode == NULL)) { 02191 xsltTransformError(ctxt, NULL, ctxt->inst, 02192 "Internal error in xsltComputeAllKeys(): " 02193 "Bad arguments.\n"); 02194 return(-1); 02195 } 02196 02197 if (ctxt->document == NULL) { 02198 /* 02199 * The document info will only be NULL if we have a RTF. 02200 */ 02201 if (contextNode->doc->_private != NULL) 02202 goto doc_info_mismatch; 02203 /* 02204 * On-demand creation of the document info (needed for keys). 02205 */ 02206 ctxt->document = xsltNewDocument(ctxt, contextNode->doc); 02207 if (ctxt->document == NULL) 02208 return(-1); 02209 } 02210 return xsltInitAllDocKeys(ctxt); 02211 02212 doc_info_mismatch: 02213 xsltTransformError(ctxt, NULL, ctxt->inst, 02214 "Internal error in xsltComputeAllKeys(): " 02215 "The context's document info doesn't match the " 02216 "document info of the current result tree.\n"); 02217 ctxt->state = XSLT_STATE_STOPPED; 02218 return(-1); 02219 } 02220 02232 xsltTemplatePtr 02233 xsltGetTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node, 02234 xsltStylesheetPtr style) 02235 { 02236 xsltStylesheetPtr curstyle; 02237 xsltTemplatePtr ret = NULL; 02238 const xmlChar *name = NULL; 02239 xsltCompMatchPtr list = NULL; 02240 float priority; 02241 int keyed = 0; 02242 02243 if ((ctxt == NULL) || (node == NULL)) 02244 return(NULL); 02245 02246 if (style == NULL) { 02247 curstyle = ctxt->style; 02248 } else { 02249 curstyle = xsltNextImport(style); 02250 } 02251 02252 while ((curstyle != NULL) && (curstyle != style)) { 02253 priority = XSLT_PAT_NO_PRIORITY; 02254 /* TODO : handle IDs/keys here ! */ 02255 if (curstyle->templatesHash != NULL) { 02256 /* 02257 * Use the top name as selector 02258 */ 02259 switch (node->type) { 02260 case XML_ELEMENT_NODE: 02261 if (node->name[0] == ' ') 02262 break; 02263 case XML_ATTRIBUTE_NODE: 02264 case XML_PI_NODE: 02265 name = node->name; 02266 break; 02267 case XML_DOCUMENT_NODE: 02268 case XML_HTML_DOCUMENT_NODE: 02269 case XML_TEXT_NODE: 02270 case XML_CDATA_SECTION_NODE: 02271 case XML_COMMENT_NODE: 02272 case XML_ENTITY_REF_NODE: 02273 case XML_ENTITY_NODE: 02274 case XML_DOCUMENT_TYPE_NODE: 02275 case XML_DOCUMENT_FRAG_NODE: 02276 case XML_NOTATION_NODE: 02277 case XML_DTD_NODE: 02278 case XML_ELEMENT_DECL: 02279 case XML_ATTRIBUTE_DECL: 02280 case XML_ENTITY_DECL: 02281 case XML_NAMESPACE_DECL: 02282 case XML_XINCLUDE_START: 02283 case XML_XINCLUDE_END: 02284 break; 02285 default: 02286 return(NULL); 02287 02288 } 02289 } 02290 if (name != NULL) { 02291 /* 02292 * find the list of applicable expressions based on the name 02293 */ 02294 list = (xsltCompMatchPtr) xmlHashLookup3(curstyle->templatesHash, 02295 name, ctxt->mode, ctxt->modeURI); 02296 } else 02297 list = NULL; 02298 while (list != NULL) { 02299 if (xsltTestCompMatch(ctxt, list, node, 02300 ctxt->mode, ctxt->modeURI)) { 02301 ret = list->template; 02302 priority = list->priority; 02303 break; 02304 } 02305 list = list->next; 02306 } 02307 list = NULL; 02308 02309 /* 02310 * find alternate generic matches 02311 */ 02312 switch (node->type) { 02313 case XML_ELEMENT_NODE: 02314 if (node->name[0] == ' ') 02315 list = curstyle->rootMatch; 02316 else 02317 list = curstyle->elemMatch; 02318 if (node->psvi != NULL) keyed = 1; 02319 break; 02320 case XML_ATTRIBUTE_NODE: { 02321 xmlAttrPtr attr; 02322 02323 list = curstyle->attrMatch; 02324 attr = (xmlAttrPtr) node; 02325 if (attr->psvi != NULL) keyed = 1; 02326 break; 02327 } 02328 case XML_PI_NODE: 02329 list = curstyle->piMatch; 02330 if (node->psvi != NULL) keyed = 1; 02331 break; 02332 case XML_DOCUMENT_NODE: 02333 case XML_HTML_DOCUMENT_NODE: { 02334 xmlDocPtr doc; 02335 02336 list = curstyle->rootMatch; 02337 doc = (xmlDocPtr) node; 02338 if (doc->psvi != NULL) keyed = 1; 02339 break; 02340 } 02341 case XML_TEXT_NODE: 02342 case XML_CDATA_SECTION_NODE: 02343 list = curstyle->textMatch; 02344 if (node->psvi != NULL) keyed = 1; 02345 break; 02346 case XML_COMMENT_NODE: 02347 list = curstyle->commentMatch; 02348 if (node->psvi != NULL) keyed = 1; 02349 break; 02350 case XML_ENTITY_REF_NODE: 02351 case XML_ENTITY_NODE: 02352 case XML_DOCUMENT_TYPE_NODE: 02353 case XML_DOCUMENT_FRAG_NODE: 02354 case XML_NOTATION_NODE: 02355 case XML_DTD_NODE: 02356 case XML_ELEMENT_DECL: 02357 case XML_ATTRIBUTE_DECL: 02358 case XML_ENTITY_DECL: 02359 case XML_NAMESPACE_DECL: 02360 case XML_XINCLUDE_START: 02361 case XML_XINCLUDE_END: 02362 break; 02363 default: 02364 break; 02365 } 02366 while ((list != NULL) && 02367 ((ret == NULL) || (list->priority > priority))) { 02368 if (xsltTestCompMatch(ctxt, list, node, 02369 ctxt->mode, ctxt->modeURI)) { 02370 ret = list->template; 02371 priority = list->priority; 02372 break; 02373 } 02374 list = list->next; 02375 } 02376 /* 02377 * Some of the tests for elements can also apply to documents 02378 */ 02379 if ((node->type == XML_DOCUMENT_NODE) || 02380 (node->type == XML_HTML_DOCUMENT_NODE) || 02381 (node->type == XML_TEXT_NODE)) { 02382 list = curstyle->elemMatch; 02383 while ((list != NULL) && 02384 ((ret == NULL) || (list->priority > priority))) { 02385 if (xsltTestCompMatch(ctxt, list, node, 02386 ctxt->mode, ctxt->modeURI)) { 02387 ret = list->template; 02388 priority = list->priority; 02389 break; 02390 } 02391 list = list->next; 02392 } 02393 } else if ((node->type == XML_PI_NODE) || 02394 (node->type == XML_COMMENT_NODE)) { 02395 list = curstyle->elemMatch; 02396 while ((list != NULL) && 02397 ((ret == NULL) || (list->priority > priority))) { 02398 if (xsltTestCompMatch(ctxt, list, node, 02399 ctxt->mode, ctxt->modeURI)) { 02400 ret = list->template; 02401 priority = list->priority; 02402 break; 02403 } 02404 list = list->next; 02405 } 02406 } 02407 02408 keyed_match: 02409 if (keyed) { 02410 list = curstyle->keyMatch; 02411 while ((list != NULL) && 02412 ((ret == NULL) || (list->priority > priority))) { 02413 if (xsltTestCompMatch(ctxt, list, node, 02414 ctxt->mode, ctxt->modeURI)) { 02415 ret = list->template; 02416 priority = list->priority; 02417 break; 02418 } 02419 list = list->next; 02420 } 02421 } 02422 else if (ctxt->hasTemplKeyPatterns && 02423 ((ctxt->document == NULL) || 02424 (ctxt->document->nbKeysComputed < ctxt->nbKeys))) 02425 { 02426 /* 02427 * Compute all remaining keys for this document. 02428 * 02429 * REVISIT TODO: I think this could be further optimized. 02430 */ 02431 if (xsltComputeAllKeys(ctxt, node) == -1) 02432 goto error; 02433 02434 switch (node->type) { 02435 case XML_ELEMENT_NODE: 02436 if (node->psvi != NULL) keyed = 1; 02437 break; 02438 case XML_ATTRIBUTE_NODE: 02439 if (((xmlAttrPtr) node)->psvi != NULL) keyed = 1; 02440 break; 02441 case XML_TEXT_NODE: 02442 case XML_CDATA_SECTION_NODE: 02443 case XML_COMMENT_NODE: 02444 case XML_PI_NODE: 02445 if (node->psvi != NULL) keyed = 1; 02446 break; 02447 case XML_DOCUMENT_NODE: 02448 case XML_HTML_DOCUMENT_NODE: 02449 if (((xmlDocPtr) node)->psvi != NULL) keyed = 1; 02450 break; 02451 default: 02452 break; 02453 } 02454 if (keyed) 02455 goto keyed_match; 02456 } 02457 if (ret != NULL) 02458 return(ret); 02459 02460 /* 02461 * Cycle on next curstylesheet import. 02462 */ 02463 curstyle = xsltNextImport(curstyle); 02464 } 02465 02466 error: 02467 return(NULL); 02468 } 02469 02477 void 02478 xsltCleanupTemplates(xsltStylesheetPtr style ATTRIBUTE_UNUSED) { 02479 } 02480 02487 void 02488 xsltFreeTemplateHashes(xsltStylesheetPtr style) { 02489 if (style->templatesHash != NULL) 02490 xmlHashFree((xmlHashTablePtr) style->templatesHash, 02491 (xmlHashDeallocator) xsltFreeCompMatchList); 02492 if (style->rootMatch != NULL) 02493 xsltFreeCompMatchList(style->rootMatch); 02494 if (style->keyMatch != NULL) 02495 xsltFreeCompMatchList(style->keyMatch); 02496 if (style->elemMatch != NULL) 02497 xsltFreeCompMatchList(style->elemMatch); 02498 if (style->attrMatch != NULL) 02499 xsltFreeCompMatchList(style->attrMatch); 02500 if (style->parentMatch != NULL) 02501 xsltFreeCompMatchList(style->parentMatch); 02502 if (style->textMatch != NULL) 02503 xsltFreeCompMatchList(style->textMatch); 02504 if (style->piMatch != NULL) 02505 xsltFreeCompMatchList(style->piMatch); 02506 if (style->commentMatch != NULL) 02507 xsltFreeCompMatchList(style->commentMatch); 02508 } 02509 Generated on Sat May 26 2012 04:18:27 for ReactOS by
1.7.6.1
|