XSLT_OP_PREDICATE
} xsltOp;
+typedef struct _xsltStepState xsltStepState;
+typedef xsltStepState *xsltStepStatePtr;
+struct _xsltStepState {
+ int step;
+ xmlNodePtr node;
+};
+
+typedef struct _xsltStepStates xsltStepStates;
+typedef xsltStepStates *xsltStepStatesPtr;
+struct _xsltStepStates {
+ int nbstates;
+ int maxstates;
+ xsltStepStatePtr states;
+};
typedef struct _xsltStepOp xsltStepOp;
typedef xsltStepOp *xsltStepOpPtr;
const xmlChar *modeURI; /* the mode URI */
xsltTemplatePtr template; /* the associated template */
+ int direct;
/* TODO fix the statically allocated size steps[] */
int nbStep;
int maxStep;
cur = (xsltCompMatchPtr) xmlMalloc(sizeof(xsltCompMatch));
if (cur == NULL) {
- xsltPrintErrorContext(NULL, NULL, NULL);
- xsltGenericError(xsltGenericErrorContext,
+ xsltTransformError(NULL, NULL, NULL,
"xsltNewCompMatch : malloc failed\n");
return(NULL);
}
cur->maxStep = 40;
cur->nsNr = 0;
cur->nsList = NULL;
+ cur->direct = 0;
return(cur);
}
return;
if (comp->pattern != NULL)
xmlFree((xmlChar *)comp->pattern);
- if (comp->mode != NULL)
- xmlFree((xmlChar *)comp->mode);
- if (comp->modeURI != NULL)
- xmlFree((xmlChar *)comp->modeURI);
if (comp->nsList != NULL)
xmlFree(comp->nsList);
for (i = 0;i < comp->nbStep;i++) {
}
/**
+ * xsltNormalizeCompSteps:
+ * @payload: pointer to template hash table entry
+ * @data: pointer to the stylesheet
+ * @name: template match name
+ *
+ * This is a hashtable scanner function to normalize the compiled
+ * steps of an imported stylesheet.
+ */
+void xsltNormalizeCompSteps(void *payload,
+ void *data, const xmlChar *name ATTRIBUTE_UNUSED) {
+ xsltCompMatchPtr comp = payload;
+ xsltStylesheetPtr style = data;
+ int ix;
+
+ for (ix = 0; ix < comp->nbStep; ix++) {
+ comp->steps[ix].previousExtra += style->extrasNr;
+ comp->steps[ix].indexExtra += style->extrasNr;
+ comp->steps[ix].lenExtra += style->extrasNr;
+ }
+}
+
+/**
* xsltNewParserContext:
* @style: the stylesheet
* @ctxt: the transformation context, if done at run-time
cur = (xsltParserContextPtr) xmlMalloc(sizeof(xsltParserContext));
if (cur == NULL) {
- xsltPrintErrorContext(NULL, NULL, NULL);
- xsltGenericError(xsltGenericErrorContext,
+ xsltTransformError(NULL, NULL, NULL,
"xsltNewParserContext : malloc failed\n");
return(NULL);
}
xsltOp op, xmlChar * value, xmlChar * value2)
{
if (comp->nbStep >= 40) {
- xsltPrintErrorContext(NULL, NULL, NULL); /* TODO */
- xsltGenericError(xsltGenericErrorContext,
+ xsltTransformError(NULL, NULL, NULL,
"xsltCompMatchAdd: overflow\n");
return (-1);
}
xsltAllocateExtra(ctxt->style);
}
if (op == XSLT_OP_PREDICATE) {
- comp->steps[comp->nbStep].comp = xmlXPathCompile(value);
+ xmlXPathContextPtr xctxt;
+
+ if (ctxt->style != NULL)
+ xctxt = xmlXPathNewContext(ctxt->style->doc);
+ else
+ xctxt = xmlXPathNewContext(NULL);
+#ifdef XML_XPATH_NOVAR
+ xctxt->flags = XML_XPATH_NOVAR;
+#endif
+ if (ctxt->style != NULL)
+ xctxt->dict = ctxt->style->dict;
+ comp->steps[comp->nbStep].comp = xmlXPathCtxtCompile(xctxt, value);
+ xmlXPathFreeContext(xctxt);
+ if (comp->steps[comp->nbStep].comp == NULL) {
+ xsltTransformError(NULL, ctxt->style, ctxt->elem,
+ "Failed to compile predicate\n");
+ ctxt->style->errors++;
+ }
}
comp->nbStep++;
return (0);
i++;
}
comp->steps[comp->nbStep++].op = XSLT_OP_END;
+ /*
+ * detect consecutive XSLT_OP_PREDICATE indicating a direct
+ * matching should be done.
+ */
+ for (i = 0;i < comp->nbStep - 1;i++) {
+ if ((comp->steps[i].op == XSLT_OP_PREDICATE) &&
+ (comp->steps[i + 1].op == XSLT_OP_PREDICATE)) {
+
+ comp->direct = 1;
+ if (comp->pattern[0] != '/') {
+ xmlChar *query;
+
+ query = xmlStrdup((const xmlChar *)"//");
+ query = xmlStrcat(query, comp->pattern);
+
+ xmlFree((xmlChar *) comp->pattern);
+ comp->pattern = query;
+ }
+ break;
+ }
+ }
}
/************************************************************************
* *
************************************************************************/
+static int
+xsltPatPushState(xsltStepStates *states, int step, xmlNodePtr node) {
+ if ((states->states == NULL) || (states->maxstates <= 0)) {
+ states->maxstates = 4;
+ states->nbstates = 0;
+ states->states = xmlMalloc(4 * sizeof(xsltStepState));
+ }
+ else if (states->maxstates <= states->nbstates) {
+ xsltStepState *tmp;
+
+ tmp = (xsltStepStatePtr) xmlRealloc(states->states,
+ 2 * states->maxstates * sizeof(xsltStepState));
+ if (tmp == NULL)
+ return(-1);
+ states->states = tmp;
+ states->maxstates *= 2;
+ }
+ states->states[states->nbstates].step = step;
+ states->states[states->nbstates++].node = node;
+#if 0
+ fprintf(stderr, "Push: %d, %s\n", step, node->name);
+#endif
+ return(0);
+}
+
+/**
+ * xsltTestCompMatchDirect:
+ * @ctxt: a XSLT process context
+ * @comp: the precompiled pattern
+ * @node: a node
+ *
+ * Test whether the node matches the pattern, do a direct evalutation
+ * and not a step by step evaluation.
+ *
+ * Returns 1 if it matches, 0 if it doesn't and -1 in case of failure
+ */
+static int
+xsltTestCompMatchDirect(xsltTransformContextPtr ctxt, xsltCompMatchPtr comp,
+ xmlNodePtr node) {
+ xsltStepOpPtr sel = NULL;
+ xmlDocPtr prevdoc;
+ xmlDocPtr doc;
+ xmlXPathObjectPtr list;
+ int ix, j;
+ int nocache = 0;
+ int isRVT;
+
+ doc = node->doc;
+ if ((doc != NULL) &&
+ (doc->name != NULL) &&
+ (doc->name[0] == ' ') &&
+ (xmlStrEqual(BAD_CAST doc->name,
+ BAD_CAST " fake node libxslt")))
+ isRVT = 1;
+ else
+ isRVT = 0;
+ sel = &comp->steps[0]; /* store extra in first step arbitrarily */
+
+ prevdoc = (xmlDocPtr)
+ XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr);
+ ix = XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival);
+ list = (xmlXPathObjectPtr)
+ XSLT_RUNTIME_EXTRA_LST(ctxt, sel->lenExtra);
+
+ if ((list == NULL) || (prevdoc != doc)) {
+ xmlXPathObjectPtr newlist;
+ xmlNodePtr parent = node->parent;
+ xmlDocPtr olddoc;
+ xmlNodePtr oldnode;
+
+ oldnode = ctxt->xpathCtxt->node;
+ olddoc = ctxt->xpathCtxt->doc;
+ ctxt->xpathCtxt->node = node;
+ ctxt->xpathCtxt->doc = doc;
+ newlist = xmlXPathEval(comp->pattern, ctxt->xpathCtxt);
+ ctxt->xpathCtxt->node = oldnode;
+ ctxt->xpathCtxt->doc = olddoc;
+ if (newlist == NULL)
+ return(-1);
+ if (newlist->type != XPATH_NODESET) {
+ xmlXPathFreeObject(newlist);
+ return(-1);
+ }
+ ix = 0;
+
+ if ((parent == NULL) || (node->doc == NULL) || isRVT)
+ nocache = 1;
+
+ if (nocache == 0) {
+ if (list != NULL)
+ xmlXPathFreeObject(list);
+ list = newlist;
+
+ XSLT_RUNTIME_EXTRA_LST(ctxt, sel->lenExtra) =
+ (void *) list;
+ XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr) =
+ (void *) doc;
+ XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) =
+ 0;
+ XSLT_RUNTIME_EXTRA_FREE(ctxt, sel->lenExtra) =
+ (xmlFreeFunc) xmlXPathFreeObject;
+ } else
+ list = newlist;
+ }
+ if ((list->nodesetval == NULL) ||
+ (list->nodesetval->nodeNr <= 0)) {
+ if (nocache == 1)
+ xmlXPathFreeObject(list);
+ return(0);
+ }
+ /* TODO: store the index and use it for the scan */
+ if (ix == 0) {
+ for (j = 0;j < list->nodesetval->nodeNr;j++) {
+ if (list->nodesetval->nodeTab[j] == node) {
+ if (nocache == 1)
+ xmlXPathFreeObject(list);
+ return(1);
+ }
+ }
+ } else {
+ }
+ if (nocache == 1)
+ xmlXPathFreeObject(list);
+ return(0);
+}
+
/**
* xsltTestCompMatch:
* @ctxt: a XSLT process context
* @mode: the mode name or NULL
* @modeURI: the mode URI or NULL
*
- * Test wether the node matches the pattern
+ * Test whether the node matches the pattern
*
* Returns 1 if it matches, 0 if it doesn't and -1 in case of failure
*/
xmlNodePtr node, const xmlChar *mode,
const xmlChar *modeURI) {
int i;
- xsltStepOpPtr step, select = NULL;
+ xsltStepOpPtr step, sel = NULL;
+ xsltStepStates states = {0, 0, NULL}; /* // may require backtrack */
if ((comp == NULL) || (node == NULL) || (ctxt == NULL)) {
- xsltPrintErrorContext(ctxt, NULL, node);
- xsltGenericError(xsltGenericErrorContext,
+ xsltTransformError(ctxt, NULL, node,
"xsltTestCompMatch: null arg\n");
return(-1);
}
if (mode != NULL) {
if (comp->mode == NULL)
return(0);
- if ((comp->mode != mode) && (!xmlStrEqual(comp->mode, mode)))
+ /*
+ * both mode strings must be interned on the stylesheet dictionary
+ */
+ if (comp->mode != mode)
return(0);
} else {
if (comp->mode != NULL)
if (modeURI != NULL) {
if (comp->modeURI == NULL)
return(0);
- if ((comp->modeURI != modeURI) &&
- (!xmlStrEqual(comp->modeURI, modeURI)))
+ /*
+ * both modeURI strings must be interned on the stylesheet dictionary
+ */
+ if (comp->modeURI != modeURI)
return(0);
} else {
if (comp->modeURI != NULL)
return(0);
}
- for (i = 0;i < comp->nbStep;i++) {
+
+ i = 0;
+restart:
+ for (;i < comp->nbStep;i++) {
step = &comp->steps[i];
if (step->op != XSLT_OP_PREDICATE)
- select = step;
+ sel = step;
switch (step->op) {
case XSLT_OP_END:
- return(1);
+ goto found;
case XSLT_OP_ROOT:
if ((node->type == XML_DOCUMENT_NODE) ||
#ifdef LIBXML_DOCB_ENABLED
#endif
(node->type == XML_HTML_DOCUMENT_NODE))
continue;
- return(0);
+ if ((node->type == XML_ELEMENT_NODE) && (node->name[0] == ' '))
+ continue;
+ goto rollback;
case XSLT_OP_ELEM:
if (node->type != XML_ELEMENT_NODE)
- return(0);
+ goto rollback;
if (step->value == NULL)
continue;
if (step->value[0] != node->name[0])
- return(0);
+ goto rollback;
if (!xmlStrEqual(step->value, node->name))
- return(0);
+ goto rollback;
/* Namespace test */
if (node->ns == NULL) {
if (step->value2 != NULL)
- return(0);
+ goto rollback;
} else if (node->ns->href != NULL) {
if (step->value2 == NULL)
- return(0);
+ goto rollback;
if (!xmlStrEqual(step->value2, node->ns->href))
- return(0);
+ goto rollback;
}
continue;
case XSLT_OP_CHILD: {
(node->type != XML_DOCB_DOCUMENT_NODE) &&
#endif
(node->type != XML_HTML_DOCUMENT_NODE))
- return(0);
+ goto rollback;
lst = node->children;
if (lst != NULL)
continue;
}
- return(0);
+ goto rollback;
}
case XSLT_OP_ATTR:
if (node->type != XML_ATTRIBUTE_NODE)
- return(0);
+ goto rollback;
if (step->value != NULL) {
if (step->value[0] != node->name[0])
- return(0);
+ goto rollback;
if (!xmlStrEqual(step->value, node->name))
- return(0);
+ goto rollback;
}
/* Namespace test */
if (node->ns == NULL) {
if (step->value2 != NULL)
- return(0);
+ goto rollback;
} else if (step->value2 != NULL) {
if (!xmlStrEqual(step->value2, node->ns->href))
- return(0);
+ goto rollback;
}
continue;
case XSLT_OP_PARENT:
(node->type == XML_DOCB_DOCUMENT_NODE) ||
#endif
(node->type == XML_NAMESPACE_DECL))
- return(0);
+ goto rollback;
node = node->parent;
if (node == NULL)
- return(0);
+ goto rollback;
if (step->value == NULL)
continue;
if (step->value[0] != node->name[0])
- return(0);
+ goto rollback;
if (!xmlStrEqual(step->value, node->name))
- return(0);
+ goto rollback;
/* Namespace test */
if (node->ns == NULL) {
if (step->value2 != NULL)
- return(0);
+ goto rollback;
} else if (node->ns->href != NULL) {
if (step->value2 == NULL)
- return(0);
+ goto rollback;
if (!xmlStrEqual(step->value2, node->ns->href))
- return(0);
+ goto rollback;
}
continue;
case XSLT_OP_ANCESTOR:
/* TODO: implement coalescing of ANCESTOR/NODE ops */
if (step->value == NULL) {
- i++;
- step = &comp->steps[i];
+ step = &comp->steps[i+1];
if (step->op == XSLT_OP_ROOT)
- return(1);
- if (step->op != XSLT_OP_ELEM)
- return(0);
- if (step->value == NULL)
- return(-1);
+ goto found;
+ /* added NS, ID and KEY as a result of bug 168208 */
+ if ((step->op != XSLT_OP_ELEM) &&
+ (step->op != XSLT_OP_ALL) &&
+ (step->op != XSLT_OP_NS) &&
+ (step->op != XSLT_OP_ID) &&
+ (step->op != XSLT_OP_KEY))
+ goto rollback;
}
if (node == NULL)
- return(0);
+ goto rollback;
if ((node->type == XML_DOCUMENT_NODE) ||
(node->type == XML_HTML_DOCUMENT_NODE) ||
#ifdef LIBXML_DOCB_ENABLED
(node->type == XML_DOCB_DOCUMENT_NODE) ||
#endif
(node->type == XML_NAMESPACE_DECL))
- return(0);
+ goto rollback;
node = node->parent;
+ if ((step->op != XSLT_OP_ELEM) && step->op != XSLT_OP_ALL) {
+ xsltPatPushState(&states, i, node);
+ continue;
+ }
+ i++;
+ if (step->value == NULL) {
+ xsltPatPushState(&states, i - 1, node);
+ continue;
+ }
while (node != NULL) {
if (node == NULL)
- return(0);
+ goto rollback;
if ((node->type == XML_ELEMENT_NODE) &&
(step->value[0] == node->name[0]) &&
(xmlStrEqual(step->value, node->name))) {
node = node->parent;
}
if (node == NULL)
- return(0);
+ goto rollback;
+ xsltPatPushState(&states, i - 1, node);
continue;
case XSLT_OP_ID: {
/* TODO Handle IDs decently, must be done differently */
xmlAttrPtr id;
if (node->type != XML_ELEMENT_NODE)
- return(0);
+ goto rollback;
id = xmlGetID(node->doc, step->value);
if ((id == NULL) || (id->parent != node))
- return(0);
+ goto rollback;
break;
}
case XSLT_OP_KEY: {
list = xsltGetKey(ctxt, step->value,
step->value3, step->value2);
if (list == NULL)
- return(0);
+ goto rollback;
for (indx = 0;indx < list->nodeNr;indx++)
if (list->nodeTab[indx] == node)
break;
if (indx >= list->nodeNr)
- return(0);
+ goto rollback;
break;
}
case XSLT_OP_NS:
if (node->type != XML_ELEMENT_NODE)
- return(0);
+ goto rollback;
if (node->ns == NULL) {
if (step->value != NULL)
- return(0);
+ goto rollback;
} else if (node->ns->href != NULL) {
if (step->value == NULL)
- return(0);
+ goto rollback;
if (!xmlStrEqual(step->value, node->ns->href))
- return(0);
+ goto rollback;
}
break;
case XSLT_OP_ALL:
if (node->type != XML_ELEMENT_NODE)
- return(0);
+ goto rollback;
break;
case XSLT_OP_PREDICATE: {
xmlNodePtr oldNode;
+ xmlDocPtr doc;
int oldCS, oldCP;
int pos = 0, len = 0;
+ int isRVT;
+
/*
- * The simple existing predicate code cannot handle
- * properly cascaded predicates. If in this situation
- * compute directly the full node list once and check
- * if the node is in the result list.
+ * when there is cascading XSLT_OP_PREDICATE, then use a
+ * direct computation approach. It's not done directly
+ * at the beginning of the routine to filter out as much
+ * as possible this costly computation.
*/
- if (comp->steps[i + 1].op == XSLT_OP_PREDICATE) {
- xmlDocPtr prevdoc, doc;
- xmlXPathObjectPtr list;
- int index, j;
- int nocache = 0;
-
- prevdoc = (xmlDocPtr)
- XSLT_RUNTIME_EXTRA(ctxt, select->previousExtra);
- index = (int)
- XSLT_RUNTIME_EXTRA(ctxt, select->indexExtra);
- list = (xmlXPathObjectPtr)
- XSLT_RUNTIME_EXTRA(ctxt, select->lenExtra);
-
- doc = node->doc;
- if ((list == NULL) || (prevdoc != doc)) {
- xmlChar *query;
- xmlXPathObjectPtr newlist;
- xmlNodePtr parent = node->parent;
-
- if (comp->pattern[0] == '/')
- query = xmlStrdup(comp->pattern);
- else {
- query = xmlStrdup((const xmlChar *)"//");
- query = xmlStrcat(query, comp->pattern);
- }
- newlist = xmlXPathEval(query, ctxt->xpathCtxt);
- xmlFree(query);
- if (newlist == NULL)
- return(-1);
- if (newlist->type != XPATH_NODESET) {
- xmlXPathFreeObject(newlist);
- return(-1);
- }
-
- if ((parent == NULL) || (node->doc == NULL))
- nocache = 1;
- else {
- while (parent->parent != NULL)
- parent = parent->parent;
- if (((parent->type != XML_DOCUMENT_NODE) &&
- (parent->type != XML_HTML_DOCUMENT_NODE)) ||
- (parent != (xmlNodePtr) node->doc))
- nocache = 1;
- }
- if (nocache == 0) {
- if (list != NULL)
- xmlXPathFreeObject(list);
- list = newlist;
-
- XSLT_RUNTIME_EXTRA(ctxt, select->lenExtra) =
- (void *) list;
- XSLT_RUNTIME_EXTRA(ctxt, select->previousExtra) =
- (void *) doc;
- XSLT_RUNTIME_EXTRA_FREE(ctxt, select->lenExtra) =
- (xmlFreeFunc) xmlXPathFreeObject;
- }
- }
- if ((list->nodesetval == NULL) ||
- (list->nodesetval->nodeNr <= 0))
- return(0);
- /* TODO: store the index and use it for the scan */
- if (index == 0) {
- for (j = 0;j < list->nodesetval->nodeNr;j++) {
- if (list->nodesetval->nodeTab[j] == node) {
- if (nocache == 1)
- xmlXPathFreeObject(list);
- return(1);
- }
- }
- } else {
+ if (comp->direct) {
+ if (states.states != NULL) {
+ /* Free the rollback states */
+ xmlFree(states.states);
}
- if (nocache == 1)
- xmlXPathFreeObject(list);
- return(0);
+ return(xsltTestCompMatchDirect(ctxt, comp, node));
}
+
+ doc = node->doc;
+ if ((doc != NULL) &&
+ (doc->name != NULL) &&
+ (doc->name[0] == ' ') &&
+ (xmlStrEqual(BAD_CAST doc->name,
+ BAD_CAST " fake node libxslt")))
+ isRVT = 1;
+ else
+ isRVT = 0;
+
/*
* Depending on the last selection, one may need to
* recompute contextSize and proximityPosition.
- *
- * TODO: make this thread safe !
*/
oldCS = ctxt->xpathCtxt->contextSize;
oldCP = ctxt->xpathCtxt->proximityPosition;
- if ((select != NULL) &&
- (select->op == XSLT_OP_ELEM) &&
- (select->value != NULL) &&
+ if ((sel != NULL) &&
+ (sel->op == XSLT_OP_ELEM) &&
+ (sel->value != NULL) &&
(node->type == XML_ELEMENT_NODE) &&
(node->parent != NULL)) {
xmlNodePtr previous;
- int index, nocache = 0;
+ int ix, nocache = 0;
previous = (xmlNodePtr)
- XSLT_RUNTIME_EXTRA(ctxt, select->previousExtra);
- index = (int)
- XSLT_RUNTIME_EXTRA(ctxt, select->indexExtra);
+ XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr);
+ ix = XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival);
if ((previous != NULL) &&
(previous->parent == node->parent)) {
/*
while (sibling != NULL) {
if (sibling == previous)
break;
- if ((node->type == XML_ELEMENT_NODE) &&
- (node->name[0] == sibling->name[0]) &&
- (xmlStrEqual(node->name, sibling->name))) {
- if ((select->value2 == NULL) ||
+ if ((previous->type == XML_ELEMENT_NODE) &&
+ (previous->name != NULL) &&
+ (sibling->name != NULL) &&
+ (previous->name[0] == sibling->name[0]) &&
+ (xmlStrEqual(previous->name, sibling->name))) {
+ if ((sel->value2 == NULL) ||
((sibling->ns != NULL) &&
- (xmlStrEqual(select->value2,
+ (xmlStrEqual(sel->value2,
sibling->ns->href))))
indx++;
}
while (sibling != NULL) {
if (sibling == previous)
break;
- if ((select->value2 == NULL) ||
+ if ((sel->value2 == NULL) ||
((sibling->ns != NULL) &&
- (xmlStrEqual(select->value2,
+ (xmlStrEqual(sel->value2,
sibling->ns->href))))
indx--;
sibling = sibling->next;
}
}
if (sibling != NULL) {
- pos = index + indx;
+ pos = ix + indx;
/*
- * If the node is in a Value Tree we cannot
- * cache it !
+ * If the node is in a Value Tree we need to
+ * save len, but cannot cache the node!
+ * (bugs 153137 and 158840)
*/
if (node->doc != NULL) {
- len = (int)
- XSLT_RUNTIME_EXTRA(ctxt, select->lenExtra);
- XSLT_RUNTIME_EXTRA(ctxt,
- select->previousExtra) = node;
- XSLT_RUNTIME_EXTRA(ctxt, select->indexExtra) =
- (void *) pos;
+ len = XSLT_RUNTIME_EXTRA(ctxt,
+ sel->lenExtra, ival);
+ if (!isRVT) {
+ XSLT_RUNTIME_EXTRA(ctxt,
+ sel->previousExtra, ptr) = node;
+ XSLT_RUNTIME_EXTRA(ctxt,
+ sel->indexExtra, ival) = pos;
+ }
}
- index = pos;
+ ix = pos;
} else
pos = 0;
} else {
if (siblings == node) {
len++;
pos = len;
- } else if ((node->name[0] == siblings->name[0])
- && (xmlStrEqual(node->name, siblings->name))) {
- if ((select->value2 == NULL) ||
+ } else if ((node->name != NULL) &&
+ (siblings->name != NULL) &&
+ (node->name[0] == siblings->name[0]) &&
+ (xmlStrEqual(node->name, siblings->name))) {
+ if ((sel->value2 == NULL) ||
((siblings->ns != NULL) &&
- (xmlStrEqual(select->value2,
+ (xmlStrEqual(sel->value2,
siblings->ns->href))))
len++;
}
* If the node is in a Value Tree we cannot
* cache it !
*/
- if ((node->doc != NULL) && (nocache == 0)) {
- XSLT_RUNTIME_EXTRA(ctxt, select->previousExtra) =
+ if ((!isRVT) && (node->doc != NULL) &&
+ (nocache == 0)) {
+ XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr) =
node;
- XSLT_RUNTIME_EXTRA(ctxt, select->indexExtra) =
- (void *) pos;
- XSLT_RUNTIME_EXTRA(ctxt, select->lenExtra) =
- (void *) len;
+ XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) =
+ pos;
+ XSLT_RUNTIME_EXTRA(ctxt, sel->lenExtra, ival) =
+ len;
}
}
- } else if ((select != NULL) && (select->op == XSLT_OP_ALL) &&
+ } else if ((sel != NULL) && (sel->op == XSLT_OP_ALL) &&
(node->type == XML_ELEMENT_NODE)) {
xmlNodePtr previous;
- int index, nocache = 0;
+ int ix, nocache = 0;
previous = (xmlNodePtr)
- XSLT_RUNTIME_EXTRA(ctxt, select->previousExtra);
- index = (int)
- XSLT_RUNTIME_EXTRA(ctxt, select->indexExtra);
+ XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr);
+ ix = XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival);
if ((previous != NULL) &&
(previous->parent == node->parent)) {
/*
}
}
if (sibling != NULL) {
- pos = index + indx;
+ pos = ix + indx;
/*
* If the node is in a Value Tree we cannot
* cache it !
*/
- if (node->doc != NULL) {
- len = (int)
- XSLT_RUNTIME_EXTRA(ctxt, select->lenExtra);
+ if ((node->doc != NULL) && !isRVT) {
+ len = XSLT_RUNTIME_EXTRA(ctxt,
+ sel->lenExtra, ival);
+ XSLT_RUNTIME_EXTRA(ctxt,
+ sel->previousExtra, ptr) = node;
XSLT_RUNTIME_EXTRA(ctxt,
- select->previousExtra) = node;
- XSLT_RUNTIME_EXTRA(ctxt, select->indexExtra) =
- (void *) pos;
+ sel->indexExtra, ival) = pos;
}
} else
pos = 0;
* If the node is in a Value Tree we cannot
* cache it !
*/
- if ((node->doc != NULL) && (nocache == 0)) {
- XSLT_RUNTIME_EXTRA(ctxt, select->previousExtra) =
+ if ((node->doc != NULL) && (nocache == 0) && !isRVT) {
+ XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr) =
node;
- XSLT_RUNTIME_EXTRA(ctxt, select->indexExtra) =
- (void *) pos;
- XSLT_RUNTIME_EXTRA(ctxt, select->lenExtra) =
- (void *) len;
+ XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) =
+ pos;
+ XSLT_RUNTIME_EXTRA(ctxt, sel->lenExtra, ival) =
+ len;
}
}
}
ctxt->xpathCtxt->proximityPosition = oldCP;
}
ctxt->node = oldNode;
- return(0);
+ goto rollback;
}
case XSLT_OP_PI:
if (node->type != XML_PI_NODE)
- return(0);
+ goto rollback;
if (step->value != NULL) {
if (!xmlStrEqual(step->value, node->name))
- return(0);
+ goto rollback;
}
break;
case XSLT_OP_COMMENT:
if (node->type != XML_COMMENT_NODE)
- return(0);
+ goto rollback;
break;
case XSLT_OP_TEXT:
if ((node->type != XML_TEXT_NODE) &&
(node->type != XML_CDATA_SECTION_NODE))
- return(0);
+ goto rollback;
break;
case XSLT_OP_NODE:
switch (node->type) {
- case XML_DOCUMENT_NODE:
- case XML_HTML_DOCUMENT_NODE:
-#ifdef LIBXML_DOCB_ENABLED
- case XML_DOCB_DOCUMENT_NODE:
-#endif
case XML_ELEMENT_NODE:
case XML_CDATA_SECTION_NODE:
case XML_PI_NODE:
case XML_COMMENT_NODE:
case XML_TEXT_NODE:
- case XML_ATTRIBUTE_NODE:
break;
default:
- return(0);
+ goto rollback;
}
break;
}
}
+found:
+ if (states.states != NULL) {
+ /* Free the rollback states */
+ xmlFree(states.states);
+ }
return(1);
+rollback:
+ /* got an error try to rollback */
+ if (states.states == NULL)
+ return(0);
+ if (states.nbstates <= 0) {
+ xmlFree(states.states);
+ return(0);
+ }
+ states.nbstates--;
+ i = states.states[states.nbstates].step;
+ node = states.states[states.nbstates].node;
+#if 0
+ fprintf(stderr, "Pop: %d, %s\n", i, node->name);
+#endif
+ goto restart;
}
/**
* @node: a node
* @comp: the precompiled pattern list
*
- * Test wether the node matches one of the patterns in the list
+ * Test whether the node matches one of the patterns in the list
*
* Returns 1 if it matches, 0 if it doesn't and -1 in case of failure
*/
#define CUR_PTR ctxt->cur
#define SKIP_BLANKS \
- while (IS_BLANK(CUR)) NEXT
+ while (IS_BLANK_CH(CUR)) NEXT
#define CURRENT (*ctxt->cur)
#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
xmlChar *lit2 = NULL;
if (CUR != '(') {
- xsltPrintErrorContext(NULL, NULL, NULL); /* TODO */
- xsltGenericError(xsltGenericErrorContext,
+ xsltTransformError(NULL, NULL, NULL,
"xsltCompileIdKeyPattern : ( expected\n");
ctxt->error = 1;
return;
return;
SKIP_BLANKS;
if (CUR != ')') {
- xsltPrintErrorContext(NULL, NULL, NULL); /* TODO */
- xsltGenericError(xsltGenericErrorContext,
+ xsltTransformError(NULL, NULL, NULL,
"xsltCompileIdKeyPattern : ) expected\n");
ctxt->error = 1;
return;
return;
SKIP_BLANKS;
if (CUR != ',') {
- xsltPrintErrorContext(NULL, NULL, NULL); /* TODO */
- xsltGenericError(xsltGenericErrorContext,
+ xsltTransformError(NULL, NULL, NULL,
"xsltCompileIdKeyPattern : , expected\n");
ctxt->error = 1;
return;
return;
SKIP_BLANKS;
if (CUR != ')') {
- xsltPrintErrorContext(NULL, NULL, NULL); /* TODO */
- xsltGenericError(xsltGenericErrorContext,
+ xsltTransformError(NULL, NULL, NULL,
"xsltCompileIdKeyPattern : ) expected\n");
ctxt->error = 1;
return;
return;
SKIP_BLANKS;
if (CUR != ')') {
- xsltPrintErrorContext(NULL, NULL, NULL); /* TODO */
- xsltGenericError(xsltGenericErrorContext,
+ xsltTransformError(NULL, NULL, NULL,
"xsltCompileIdKeyPattern : ) expected\n");
ctxt->error = 1;
return;
NEXT;
SKIP_BLANKS;
if (CUR != ')') {
- xsltPrintErrorContext(NULL, NULL, NULL); /* TODO */
- xsltGenericError(xsltGenericErrorContext,
+ xsltTransformError(NULL, NULL, NULL,
"xsltCompileIdKeyPattern : ) expected\n");
ctxt->error = 1;
return;
NEXT;
SKIP_BLANKS;
if (CUR != ')') {
- xsltPrintErrorContext(NULL, NULL, NULL); /* TODO */
- xsltGenericError(xsltGenericErrorContext,
+ xsltTransformError(NULL, NULL, NULL,
"xsltCompileIdKeyPattern : ) expected\n");
ctxt->error = 1;
return;
NEXT;
SKIP_BLANKS;
if (CUR != ')') {
- xsltPrintErrorContext(NULL, NULL, NULL); /* TODO */
- xsltGenericError(xsltGenericErrorContext,
+ xsltTransformError(NULL, NULL, NULL,
"xsltCompileIdKeyPattern : ) expected\n");
ctxt->error = 1;
return;
NEXT;
PUSH(XSLT_OP_NODE, NULL, NULL);
} else if (aid) {
- xsltPrintErrorContext(NULL, NULL, NULL); /* TODO */
- xsltGenericError(xsltGenericErrorContext,
+ xsltTransformError(NULL, NULL, NULL,
"xsltCompileIdKeyPattern : expecting 'key' or 'id' or node type\n");
ctxt->error = 1;
return;
} else {
- xsltPrintErrorContext(NULL, NULL, NULL); /* TODO */
- xsltGenericError(xsltGenericErrorContext,
+ xsltTransformError(NULL, NULL, NULL,
"xsltCompileIdKeyPattern : node type\n");
ctxt->error = 1;
return;
if (CUR == '*') {
NEXT;
PUSH(XSLT_OP_ATTR, NULL, NULL);
- return;
+ goto parse_predicate;
}
token = xsltScanQName(ctxt, &prefix);
if (prefix != NULL) {
ns = xmlSearchNs(ctxt->doc, ctxt->elem, prefix);
if (ns == NULL) {
- xsltPrintErrorContext(NULL, NULL, NULL); /* TODO */
- xsltGenericError(xsltGenericErrorContext,
+ xsltTransformError(NULL, NULL, NULL,
"xsltCompileStepPattern : no namespace bound to prefix %s\n",
prefix);
} else {
PUSH(XSLT_OP_ATTR, NULL, URL);
return;
}
- xsltPrintErrorContext(NULL, NULL, NULL); /* TODO */
- xsltGenericError(xsltGenericErrorContext,
+ xsltTransformError(NULL, NULL, NULL,
"xsltCompileStepPattern : Name expected\n");
ctxt->error = 1;
goto error;
PUSH(XSLT_OP_ALL, token, NULL);
goto parse_predicate;
} else {
- xsltPrintErrorContext(NULL, NULL, NULL); /* TODO */
- xsltGenericError(xsltGenericErrorContext,
+ xsltTransformError(NULL, NULL, NULL,
"xsltCompileStepPattern : Name expected\n");
ctxt->error = 1;
goto error;
token = xsltScanName(ctxt);
ns = xmlSearchNs(ctxt->doc, ctxt->elem, prefix);
if (ns == NULL) {
- xsltPrintErrorContext(NULL, NULL, NULL); /* TODO */
- xsltGenericError(xsltGenericErrorContext,
+ xsltTransformError(NULL, NULL, NULL,
"xsltCompileStepPattern : no namespace bound to prefix %s\n",
prefix);
ctxt->error = 1;
NEXT;
PUSH(XSLT_OP_NS, URL, NULL);
} else {
- xsltPrintErrorContext(NULL, NULL, NULL); /* TODO */
- xsltGenericError(xsltGenericErrorContext,
+ xsltTransformError(NULL, NULL, NULL,
"xsltCompileStepPattern : Name expected\n");
ctxt->error = 1;
goto error;
PUSH(XSLT_OP_ALL, token, NULL);
goto parse_predicate;
} else {
- xsltPrintErrorContext(NULL, NULL, NULL); /* TODO */
- xsltGenericError(xsltGenericErrorContext,
+ xsltTransformError(NULL, NULL, NULL,
"xsltCompileStepPattern : QName expected\n");
ctxt->error = 1;
goto error;
xmlFree(token);
token = xsltScanName(ctxt);
if (token == NULL) {
- xsltPrintErrorContext(NULL, NULL, NULL); /* TODO */
- xsltGenericError(xsltGenericErrorContext,
+ xsltTransformError(NULL, NULL, NULL,
"xsltCompileStepPattern : QName expected\n");
ctxt->error = 1;
goto error;
}
PUSH(XSLT_OP_ATTR, name, URL);
} else {
- xsltPrintErrorContext(NULL, NULL, NULL); /* TODO */
- xsltGenericError(xsltGenericErrorContext,
+ xsltTransformError(NULL, NULL, NULL,
"xsltCompileStepPattern : 'child' or 'attribute' expected\n");
ctxt->error = 1;
goto error;
NEXT;
}
if (CUR == 0) {
- xsltPrintErrorContext(NULL, NULL, NULL); /* TODO */
- xsltGenericError(xsltGenericErrorContext,
+ xsltTransformError(NULL, NULL, NULL,
"xsltCompileStepPattern : ']' expected\n");
ctxt->error = 1;
- goto error;
+ return;
}
ret = xmlStrndup(q, CUR_PTR - q);
PUSH(XSLT_OP_PREDICATE, ret, NULL);
PUSH(XSLT_OP_PARENT, NULL, NULL);
NEXT;
SKIP_BLANKS;
- if ((CUR != 0) || (CUR == '|')) {
+ if ((CUR != 0) && (CUR != '|')) {
xsltCompileRelativePathPattern(ctxt, NULL);
}
} else {
*/
NEXT;
NEXT;
+ ctxt->comp->priority = 0.5; /* '//' means not 0 priority */
xsltCompileRelativePathPattern(ctxt, NULL);
} else if (CUR == '/') {
/*
NEXT;
SKIP_BLANKS;
PUSH(XSLT_OP_ROOT, NULL, NULL);
- if ((CUR != 0) || (CUR == '|')) {
+ if ((CUR != 0) && (CUR != '|')) {
PUSH(XSLT_OP_PARENT, NULL, NULL);
xsltCompileRelativePathPattern(ctxt, NULL);
}
xmlChar *name;
name = xsltScanName(ctxt);
if (name == NULL) {
- xsltPrintErrorContext(NULL, NULL, NULL); /* TODO */
- xsltGenericError(xsltGenericErrorContext,
+ xsltTransformError(NULL, NULL, NULL,
"xsltCompileLocationPathPattern : Name expected\n");
ctxt->error = 1;
return;
int current, start, end, level, j;
if (pattern == NULL) {
- xsltPrintErrorContext(NULL, NULL, node); /* TODO */
- xsltGenericError(xsltGenericErrorContext,
+ xsltTransformError(NULL, NULL, node,
"xsltCompilePattern : NULL pattern\n");
return(NULL);
}
current = end = 0;
while (pattern[current] != 0) {
start = current;
- while (IS_BLANK(pattern[current]))
+ while (IS_BLANK_CH(pattern[current]))
current++;
end = current;
level = 0;
end++;
}
if (current == end) {
- xsltPrintErrorContext(NULL, NULL, node); /* TODO */
- xsltGenericError(xsltGenericErrorContext,
+ xsltTransformError(NULL, NULL, node,
"xsltCompilePattern : NULL pattern\n");
goto error;
}
"xsltCompilePattern : parsing '%s'\n",
element->pattern);
#endif
+ /*
+ Preset default priority to be zero.
+ This may be changed by xsltCompileLocationPathPattern.
+ */
+ element->priority = 0;
xsltCompileLocationPathPattern(ctxt);
if (ctxt->error) {
- xsltPrintErrorContext(NULL, style, node);
- xsltGenericError(xsltGenericErrorContext,
+ xsltTransformError(NULL, style, node,
"xsltCompilePattern : failed to compile '%s'\n",
element->pattern);
- style->errors++;
+ if (style != NULL) style->errors++;
goto error;
}
/*
* Set-up the priority
*/
- if (((element->steps[0].op == XSLT_OP_ELEM) ||
- (element->steps[0].op == XSLT_OP_ATTR)) &&
- (element->steps[0].value != NULL) &&
- (element->steps[1].op == XSLT_OP_END)) {
- element->priority = 0;
-#if 0
- } else if ((element->steps[0].op == XSLT_OP_ROOT) &&
- (element->steps[1].op == XSLT_OP_END)) {
- element->priority = 0;
-#endif
- } else if ((element->steps[0].op == XSLT_OP_PI) &&
- (element->steps[0].value != NULL) &&
- (element->steps[1].op == XSLT_OP_END)) {
- element->priority = 0;
- } else if ((element->steps[0].op == XSLT_OP_ATTR) &&
- (element->steps[0].value2 != NULL) &&
- (element->steps[1].op == XSLT_OP_END)) {
- element->priority = -0.25;
- } else if ((element->steps[0].op == XSLT_OP_NS) &&
- (element->steps[0].value != NULL) &&
- (element->steps[1].op == XSLT_OP_END)) {
- element->priority = -0.25;
- } else if ((element->steps[0].op == XSLT_OP_ATTR) &&
- (element->steps[0].value == NULL) &&
- (element->steps[0].value2 == NULL) &&
- (element->steps[1].op == XSLT_OP_END)) {
- element->priority = -0.5;
- } else if (((element->steps[0].op == XSLT_OP_PI) ||
- (element->steps[0].op == XSLT_OP_TEXT) ||
- (element->steps[0].op == XSLT_OP_ALL) ||
- (element->steps[0].op == XSLT_OP_NODE) ||
- (element->steps[0].op == XSLT_OP_COMMENT)) &&
- (element->steps[1].op == XSLT_OP_END)) {
- element->priority = -0.5;
- } else {
- element->priority = 0.5;
+ if (element->priority == 0) { /* if not yet determined */
+ if (((element->steps[0].op == XSLT_OP_ELEM) ||
+ (element->steps[0].op == XSLT_OP_ATTR) ||
+ (element->steps[0].op == XSLT_OP_PI)) &&
+ (element->steps[0].value != NULL) &&
+ (element->steps[1].op == XSLT_OP_END)) {
+ ; /* previously preset */
+ } else if ((element->steps[0].op == XSLT_OP_ATTR) &&
+ (element->steps[0].value2 != NULL) &&
+ (element->steps[1].op == XSLT_OP_END)) {
+ element->priority = -0.25;
+ } else if ((element->steps[0].op == XSLT_OP_NS) &&
+ (element->steps[0].value != NULL) &&
+ (element->steps[1].op == XSLT_OP_END)) {
+ element->priority = -0.25;
+ } else if ((element->steps[0].op == XSLT_OP_ATTR) &&
+ (element->steps[0].value == NULL) &&
+ (element->steps[0].value2 == NULL) &&
+ (element->steps[1].op == XSLT_OP_END)) {
+ element->priority = -0.5;
+ } else if (((element->steps[0].op == XSLT_OP_PI) ||
+ (element->steps[0].op == XSLT_OP_TEXT) ||
+ (element->steps[0].op == XSLT_OP_ALL) ||
+ (element->steps[0].op == XSLT_OP_NODE) ||
+ (element->steps[0].op == XSLT_OP_COMMENT)) &&
+ (element->steps[1].op == XSLT_OP_END)) {
+ element->priority = -0.5;
+ } else {
+ element->priority = 0.5;
+ }
}
#ifdef WITH_XSLT_DEBUG_PATTERN
xsltGenericDebug(xsltGenericDebugContext,
current = end;
}
if (end == 0) {
- xsltPrintErrorContext(NULL, NULL, node); /* TODO */
- xsltGenericError(xsltGenericErrorContext,
+ xsltTransformError(NULL, style, node,
"xsltCompilePattern : NULL pattern\n");
- style->errors++;
+ if (style != NULL) style->errors++;
goto error;
}
pat->template = cur;
if (mode != NULL)
- pat->mode = xmlStrdup(mode);
+ pat->mode = xmlDictLookup(style->dict, mode, -1);
if (modeURI != NULL)
- pat->modeURI = xmlStrdup(modeURI);
+ pat->modeURI = xmlDictLookup(style->dict, modeURI, -1);
if (priority != XSLT_PAT_NO_PRIORITY)
pat->priority = priority;
break;
case XSLT_OP_END:
case XSLT_OP_PREDICATE:
- xsltPrintErrorContext(NULL, style, NULL);
- xsltGenericError(xsltGenericErrorContext,
+ xsltTransformError(NULL, style, NULL,
"xsltAddTemplate: invalid compiled pattern\n");
xsltFreeCompMatch(pat);
return(-1);
list->next = pat;
}
} else {
- xsltPrintErrorContext(NULL, style, NULL);
- xsltGenericError(xsltGenericErrorContext,
+ xsltTransformError(NULL, style, NULL,
"xsltAddTemplate: invalid compiled pattern\n");
xsltFreeCompMatch(pat);
return(-1);
const xmlChar *name = NULL;
xsltCompMatchPtr list = NULL;
float priority;
+ int keyed = 0;
if ((ctxt == NULL) || (node == NULL))
return(NULL);
*/
switch (node->type) {
case XML_ELEMENT_NODE:
+ if (node->name[0] == ' ')
+ break;
case XML_ATTRIBUTE_NODE:
case XML_PI_NODE:
name = node->name;
}
if (name != NULL) {
/*
- * find the list of appliable expressions based on the name
+ * find the list of applicable expressions based on the name
*/
list = (xsltCompMatchPtr) xmlHashLookup3(curstyle->templatesHash,
name, ctxt->mode, ctxt->modeURI);
*/
switch (node->type) {
case XML_ELEMENT_NODE:
- list = curstyle->elemMatch;
+ if (node->name[0] == ' ')
+ list = curstyle->rootMatch;
+ else
+ list = curstyle->elemMatch;
+ if (node->psvi != NULL) keyed = 1;
break;
- case XML_ATTRIBUTE_NODE:
+ case XML_ATTRIBUTE_NODE: {
+ xmlAttrPtr attr;
+
list = curstyle->attrMatch;
+ attr = (xmlAttrPtr) node;
+ if (attr->psvi != NULL) keyed = 1;
break;
+ }
case XML_PI_NODE:
list = curstyle->piMatch;
+ if (node->psvi != NULL) keyed = 1;
break;
case XML_DOCUMENT_NODE:
- case XML_HTML_DOCUMENT_NODE:
+ case XML_HTML_DOCUMENT_NODE: {
+ xmlDocPtr doc;
+
list = curstyle->rootMatch;
+ doc = (xmlDocPtr) node;
+ if (doc->psvi != NULL) keyed = 1;
break;
+ }
case XML_TEXT_NODE:
case XML_CDATA_SECTION_NODE:
list = curstyle->textMatch;
+ if (node->psvi != NULL) keyed = 1;
break;
case XML_COMMENT_NODE:
list = curstyle->commentMatch;
+ if (node->psvi != NULL) keyed = 1;
break;
case XML_ENTITY_REF_NODE:
case XML_ENTITY_NODE:
break;
default:
break;
-
}
while ((list != NULL) &&
((ret == NULL) || (list->priority > priority))) {
* Some of the tests for elements can also apply to documents
*/
if ((node->type == XML_DOCUMENT_NODE) ||
- (node->type == XML_HTML_DOCUMENT_NODE)) {
+ (node->type == XML_HTML_DOCUMENT_NODE) ||
+ (node->type == XML_TEXT_NODE)) {
+ list = curstyle->elemMatch;
+ while ((list != NULL) &&
+ ((ret == NULL) || (list->priority > priority))) {
+ if (xsltTestCompMatch(ctxt, list, node,
+ ctxt->mode, ctxt->modeURI)) {
+ ret = list->template;
+ priority = list->priority;
+ break;
+ }
+ list = list->next;
+ }
+ } else if ((node->type == XML_PI_NODE) ||
+ (node->type == XML_COMMENT_NODE)) {
list = curstyle->elemMatch;
while ((list != NULL) &&
((ret == NULL) || (list->priority > priority))) {
}
}
- if (node->_private != NULL) {
+ if (keyed) {
list = curstyle->keyMatch;
while ((list != NULL) &&
((ret == NULL) || (list->priority > priority))) {
xsltFreeCompMatchList(style->commentMatch);
}
-#if 0
-/**
- * xsltMatchPattern
- * @node: a node in the source tree
- * @pattern: an XSLT pattern
- * @ctxtdoc: context document (for namespaces)
- * @ctxtnode: context node (for namespaces)
- *
- * Determine if a node matches a pattern.
- */
-int
-xsltMatchPattern(xsltTransformContextPtr context,
- xmlNodePtr node,
- const xmlChar *pattern,
- xmlDocPtr ctxtdoc,
- xmlNodePtr ctxtnode)
-{
- int match = 0;
- xsltCompMatchPtr first, comp;
-
- if ((context != NULL) && (pattern != NULL)) {
- first = xsltCompilePattern(pattern, ctxtdoc, ctxtnode);
- for (comp = first; comp != NULL; comp = comp->next) {
- match = xsltTestCompMatch(context, comp, node, NULL, NULL);
- if (match)
- break; /* for */
- }
- if (first)
- xsltFreeCompMatchList(first);
- }
- return match;
-}
-#endif