mirror of
				https://gitlab.gnome.org/GNOME/libxslt
				synced 2025-11-04 00:53:12 +03:00 
			
		
		
		
	fixed bug #171488 with cascading select in patterns. added test provided
* libxslt/pattern.c: fixed bug #171488 with cascading select in patterns. * tests/general/bug-161.*, tests/general/Makefile.am, tests/docs/bug-161.*, tests/docs/Makefile.am: added test provided by Ben Ko Daniel
This commit is contained in:
		@@ -1,3 +1,11 @@
 | 
			
		||||
Thu Mar 31 11:54:31 CEST 2005
 | 
			
		||||
 | 
			
		||||
	* libxslt/pattern.c: fixed bug #171488 with cascading select in
 | 
			
		||||
	  patterns.
 | 
			
		||||
	* tests/general/bug-161.*, tests/general/Makefile.am,
 | 
			
		||||
	  tests/docs/bug-161.*, tests/docs/Makefile.am: added test provided
 | 
			
		||||
	  by Ben Ko
 | 
			
		||||
	
 | 
			
		||||
Thu Mar 31 00:28:38 CEST 2005 Daniel Veillard <daniel@veillard.com>
 | 
			
		||||
 | 
			
		||||
	* tests/plugins/Makefile.am: fixed build outside of source tree
 | 
			
		||||
 
 | 
			
		||||
@@ -99,6 +99,7 @@ struct _xsltCompMatch {
 | 
			
		||||
    const xmlChar *modeURI;      /* the mode URI */
 | 
			
		||||
    xsltTemplatePtr template;    /* the associated template */
 | 
			
		||||
 | 
			
		||||
    int direct;
 | 
			
		||||
    /* TODO fix the statically allocated size steps[] */
 | 
			
		||||
    int nbStep;
 | 
			
		||||
    int maxStep;
 | 
			
		||||
@@ -147,6 +148,7 @@ xsltNewCompMatch(void) {
 | 
			
		||||
    cur->maxStep = 40;
 | 
			
		||||
    cur->nsNr = 0;
 | 
			
		||||
    cur->nsList = NULL;
 | 
			
		||||
    cur->direct = 0;
 | 
			
		||||
    return(cur);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -367,6 +369,27 @@ xsltReverseCompMatch(xsltCompMatchPtr comp) {
 | 
			
		||||
	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;
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/************************************************************************
 | 
			
		||||
@@ -400,6 +423,107 @@ xsltPatPushState(xsltStepStates *states, int step, xmlNodePtr node) {
 | 
			
		||||
    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
 | 
			
		||||
@@ -449,6 +573,7 @@ xsltTestCompMatch(xsltTransformContextPtr ctxt, xsltCompMatchPtr comp,
 | 
			
		||||
	if (comp->modeURI != NULL)
 | 
			
		||||
	    return(0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    i = 0;
 | 
			
		||||
restart:
 | 
			
		||||
    for (;i < comp->nbStep;i++) {
 | 
			
		||||
@@ -667,6 +792,20 @@ restart:
 | 
			
		||||
		int pos = 0, len = 0;
 | 
			
		||||
		int isRVT;
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 * 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->direct) {
 | 
			
		||||
		    if (states.states != NULL) {
 | 
			
		||||
			/* Free the rollback states */
 | 
			
		||||
			xmlFree(states.states);
 | 
			
		||||
		    }
 | 
			
		||||
		    return(xsltTestCompMatchDirect(ctxt, comp, node));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		doc = node->doc;
 | 
			
		||||
		if ((doc != NULL) &&
 | 
			
		||||
		    (doc->name != NULL) &&
 | 
			
		||||
@@ -676,98 +815,10 @@ restart:
 | 
			
		||||
		    isRVT = 1;
 | 
			
		||||
		else
 | 
			
		||||
		    isRVT = 0;
 | 
			
		||||
		/*
 | 
			
		||||
		 * 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.
 | 
			
		||||
		 */
 | 
			
		||||
		if (comp->steps[i + 1].op == XSLT_OP_PREDICATE) {
 | 
			
		||||
		    xmlDocPtr prevdoc;
 | 
			
		||||
		    xmlXPathObjectPtr list;
 | 
			
		||||
		    int ix, j;
 | 
			
		||||
		    int nocache = 0;
 | 
			
		||||
 | 
			
		||||
		    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)) {
 | 
			
		||||
			xmlChar *query;
 | 
			
		||||
			xmlXPathObjectPtr newlist;
 | 
			
		||||
			xmlNodePtr parent = node->parent;
 | 
			
		||||
			xmlDocPtr olddoc;
 | 
			
		||||
			xmlNodePtr oldnode;
 | 
			
		||||
 | 
			
		||||
			if (comp->pattern[0] == '/')
 | 
			
		||||
			    query = xmlStrdup(comp->pattern);
 | 
			
		||||
			else {
 | 
			
		||||
			    query = xmlStrdup((const xmlChar *)"//");
 | 
			
		||||
			    query = xmlStrcat(query, comp->pattern);
 | 
			
		||||
			}
 | 
			
		||||
			oldnode = ctxt->xpathCtxt->node;
 | 
			
		||||
			olddoc = ctxt->xpathCtxt->doc;
 | 
			
		||||
			ctxt->xpathCtxt->node = node;
 | 
			
		||||
			ctxt->xpathCtxt->doc = doc;
 | 
			
		||||
			newlist = xmlXPathEval(query, ctxt->xpathCtxt);
 | 
			
		||||
			ctxt->xpathCtxt->node = oldnode;
 | 
			
		||||
			ctxt->xpathCtxt->doc = olddoc;
 | 
			
		||||
			xmlFree(query);
 | 
			
		||||
			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);
 | 
			
		||||
			goto rollback;
 | 
			
		||||
		    }
 | 
			
		||||
		    /* 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);
 | 
			
		||||
				goto found;
 | 
			
		||||
			    }
 | 
			
		||||
			}
 | 
			
		||||
		    } else {
 | 
			
		||||
		    }
 | 
			
		||||
		    if (nocache == 1)
 | 
			
		||||
			xmlXPathFreeObject(list);
 | 
			
		||||
		    goto rollback;
 | 
			
		||||
		}
 | 
			
		||||
		/*
 | 
			
		||||
		 * 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;
 | 
			
		||||
 
 | 
			
		||||
@@ -44,7 +44,7 @@ extern "C" {
 | 
			
		||||
 *
 | 
			
		||||
 * extra version information, used to show a CVS compilation
 | 
			
		||||
 */
 | 
			
		||||
#define LIBXSLT_VERSION_EXTRA "-CVS1006"
 | 
			
		||||
#define LIBXSLT_VERSION_EXTRA "-CVS1008"
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * WITH_XSLT_DEBUG:
 | 
			
		||||
 
 | 
			
		||||
@@ -160,6 +160,7 @@ EXTRA_DIST =	\
 | 
			
		||||
	bug-158.xml bug-158.doc \
 | 
			
		||||
	bug-159.xml \
 | 
			
		||||
	bug-160.xml \
 | 
			
		||||
	bug-161.xml \
 | 
			
		||||
	character.xml \
 | 
			
		||||
	array.xml \
 | 
			
		||||
	items.xml
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										5
									
								
								tests/docs/bug-161.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								tests/docs/bug-161.xml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
<orderedlist>
 | 
			
		||||
<listitem><para>test</para></listitem>
 | 
			
		||||
<listitem><para>test</para></listitem>
 | 
			
		||||
<listitem><para>test</para></listitem>
 | 
			
		||||
</orderedlist>
 | 
			
		||||
@@ -169,6 +169,7 @@ EXTRA_DIST = \
 | 
			
		||||
    bug-158.out bug-158.xsl \
 | 
			
		||||
    bug-159.out bug-159.xsl \
 | 
			
		||||
    bug-160.out bug-160.xsl \
 | 
			
		||||
    bug-161.out bug-161.xsl \
 | 
			
		||||
    character.out character.xsl \
 | 
			
		||||
    character2.out character2.xsl \
 | 
			
		||||
    itemschoose.out itemschoose.xsl \
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										6
									
								
								tests/general/bug-161.out
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								tests/general/bug-161.out
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
<?xml version="1.0"?>
 | 
			
		||||
 | 
			
		||||
test
 | 
			
		||||
test
 | 
			
		||||
First element of last item of orderedlist<para>test</para>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										18
									
								
								tests/general/bug-161.xsl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								tests/general/bug-161.xsl
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
			
		||||
<xsl:stylesheet
 | 
			
		||||
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 | 
			
		||||
    version="1.0">
 | 
			
		||||
 | 
			
		||||
<xsl:output method="xml" /> 
 | 
			
		||||
 | 
			
		||||
<!--match first element of last item of any orderedlist-->
 | 
			
		||||
<!-- <xsl:template match="orderedlist/listitem[position()!=1][position()=last()]/*[1]"> -->
 | 
			
		||||
<xsl:template match="orderedlist/listitem[position()!=1][position()=last()]/*[1]">
 | 
			
		||||
   <xsl:text>First element of last item of orderedlist</xsl:text>
 | 
			
		||||
   <xsl:copy>
 | 
			
		||||
     <xsl:apply-templates select="@*|node()"/>
 | 
			
		||||
   </xsl:copy>
 | 
			
		||||
</xsl:template>
 | 
			
		||||
 | 
			
		||||
</xsl:stylesheet>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user