ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

pattern.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.