diff --git a/ChangeLog b/ChangeLog index 493594fe..3d976f20 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +Wed Apr 30 22:44:49 CEST 2003 Daniel Veillard + + * libxslt/transform.c libxslt/variables.c libxslt/xsltInternals.h: + cleaning up Result Value Tree handling + * libexslt/functions.c libexslt/strings.c: fixed a pair of + implementations. + * tests/exslt/strings/Makefile.am tests/exslt/strings/tokenize.2.*: + added Mark Vakoc test combining for-each and exslt:tokenize + Wed Apr 30 15:23:33 CEST 2003 Daniel Veillard * libxslt/transform.c: fixing bug #111755 when a template is diff --git a/libexslt/functions.c b/libexslt/functions.c index f9fc7d27..b2f9da4a 100644 --- a/libexslt/functions.c +++ b/libexslt/functions.c @@ -511,21 +511,30 @@ exsltFuncResultElem (xsltTransformContextPtr ctxt, * one or more child nodes), then the content of the * func:result element specifies the value. */ - xmlNodePtr container, oldInsert; + xmlNodePtr oldInsert; + xmlDocPtr container; - container = xmlNewDocNode (ctxt->output, NULL, - (const xmlChar *) "fake", NULL); + container = xsltCreateRVT(ctxt); + if (container == NULL) { + xsltGenericError(xsltGenericErrorContext, + "exsltFuncResultElem: out of memory\n"); + data->error = 1; + return; + } + xsltRegisterTmpRVT(ctxt, container); oldInsert = ctxt->insert; - ctxt->insert = container; + ctxt->insert = (xmlNodePtr) container; xsltApplyOneTemplate (ctxt, ctxt->xpathCtxt->node, inst->children, NULL, NULL); ctxt->insert = oldInsert; - ret = xmlXPathNewValueTree(container); + ret = xmlXPathNewValueTree((xmlNodePtr) container); if (ret == NULL) { xsltGenericError(xsltGenericErrorContext, "exsltFuncResultElem: ret == NULL\n"); data->error = 1; + } else { + ret->boolval = 0; /* Freeing is not handled there anymore */ } } else { /* If the func:result element has empty content and does not diff --git a/libexslt/strings.c b/libexslt/strings.c index e013eebe..6c02ba9e 100644 --- a/libexslt/strings.c +++ b/libexslt/strings.c @@ -32,12 +32,12 @@ static void exsltStrTokenizeFunction(xmlXPathParserContextPtr ctxt, int nargs) { + xsltTransformContextPtr tctxt; xmlChar *str, *delimiters, *cur; const xmlChar *token, *delimiter; xmlNodePtr node; xmlDocPtr container; - - xmlXPathObjectPtr ret; + xmlXPathObjectPtr ret = NULL; if ((nargs < 1) || (nargs > 2)) { xmlXPathSetArityError(ctxt); @@ -61,17 +61,19 @@ exsltStrTokenizeFunction(xmlXPathParserContextPtr ctxt, int nargs) } /* Return a result tree fragment */ + tctxt = xsltXPathGetTransformContext(ctxt); + if (tctxt == NULL) { + xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, + "exslt:tokenize : internal error tctxt == NULL\n"); + goto fail; + } - container = xmlNewDoc(NULL); + container = xsltCreateRVT(tctxt); if (container != NULL) { - container->name = - (char *) xmlStrdup(BAD_CAST " fake node libxslt"); - container->doc = container; - ret = xmlXPathNewValueTree((xmlNodePtr) container); + xsltRegisterTmpRVT(tctxt, container); + ret = xmlXPathNewNodeSet(NULL); if (ret != NULL) { - /* Tag the subtree for removal once consumed */ - ret->boolval = 1; - ret->type = XPATH_XSLT_TREE; + ret->boolval = 0; /* Freeing is not handled there anymore */ for (cur = str, token = str; *cur != 0; cur++) { for (delimiter = delimiters; *delimiter != 0; delimiter++) { if (*cur == *delimiter) { @@ -83,6 +85,7 @@ exsltStrTokenizeFunction(xmlXPathParserContextPtr ctxt, int nargs) node = xmlNewChild((xmlNodePtr) container, NULL, (const xmlChar *) "token", token); + xmlXPathNodeSetAddUnique(ret->nodesetval, node); *cur = *delimiter; token = cur + 1; break; @@ -92,9 +95,11 @@ exsltStrTokenizeFunction(xmlXPathParserContextPtr ctxt, int nargs) node = xmlNewChild((xmlNodePtr) container, NULL, (const xmlChar *) "token", token); + xmlXPathNodeSetAddUnique(ret->nodesetval, node); } } +fail: if (str != NULL) xmlFree(str); if (delimiters != NULL) diff --git a/libxslt/transform.c b/libxslt/transform.c index 2dbec90b..7e6236a3 100644 --- a/libxslt/transform.c +++ b/libxslt/transform.c @@ -463,6 +463,7 @@ xsltFreeTransformContext(xsltTransformContextPtr ctxt) { xsltFreeGlobalVariables(ctxt); xsltFreeDocuments(ctxt); xsltFreeCtxtExts(ctxt); + xsltFreeRVTs(ctxt); memset(ctxt, -1, sizeof(xsltTransformContext)); xmlFree(ctxt); } @@ -1251,18 +1252,6 @@ xsltProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node, xsltTemplatePtr template; xmlNodePtr oldNode; -#if 0 - if (xmlStrEqual(node->name, BAD_CAST " fake node libxslt")) { - xmlNodePtr children; - - children = node->children; - while (children != NULL) { - xsltProcessOneNode(ctxt, children, params); - children = children->next; - } - return; - } -#endif template = xsltGetTemplate(ctxt, node, NULL); /* * If no template is found, apply the default rule. @@ -1336,6 +1325,7 @@ xsltApplyOneTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNodePtr oldInst = NULL; xmlAttrPtr attrs; int oldBase; + xmlDocPtr tmpRVT = NULL; int level = 0; @@ -1404,6 +1394,8 @@ xsltApplyOneTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node, start = xsltTimestamp(); profPush(ctxt, 0); } + tmpRVT = ctxt->tmpRVT; + ctxt->tmpRVT = NULL; templPush(ctxt, templ); #ifdef WITH_XSLT_DEBUG_PROCESS if (templ->name != NULL) @@ -1694,6 +1686,19 @@ xsltApplyOneTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node, if (templ != NULL) { ctxt->varsBase = oldBase; templPop(ctxt); + /* + * Free up all the unreferenced RVT + */ + if (ctxt->tmpRVT != NULL) { + xmlDocPtr tmp = ctxt->tmpRVT, next; + + while (tmp != NULL) { + next = (xmlDocPtr) tmp->next; + xmlFreeDoc(tmp); + tmp = next; + } + } + ctxt->tmpRVT = tmpRVT; if (ctxt->profile) { long spent, child, total, end; diff --git a/libxslt/variables.c b/libxslt/variables.c index e82d45a3..5e0f82b7 100644 --- a/libxslt/variables.c +++ b/libxslt/variables.c @@ -34,6 +34,106 @@ #define WITH_XSLT_DEBUG_VARIABLE #endif +/************************************************************************ + * * + * Result Value Tree interfaces * + * * + ************************************************************************/ + +/** + * xsltCreateRVT: + * @ctxt: an XSLT transformation context + * + * Create a result value tree + * + * Returns the result value tree or NULL in case of error + */ +xmlDocPtr +xsltCreateRVT(xsltTransformContextPtr ctxt) +{ + xmlDocPtr container; + + if (ctxt == NULL) return(NULL); + + container = xmlNewDoc(NULL); + if (container == NULL) + return(NULL); + + container->name = (char *) xmlStrdup(BAD_CAST " fake node libxslt"); + container->doc = container; + container->parent = NULL; + return(container); +} + +/** + * xsltRegisterTmpRVT: + * @ctxt: an XSLT transformation context + * @RVT: a result value tree + * + * Register the result value tree for destruction at the end of the context + * + * Returns 0 in case of success and -1 in case of error. + */ +int +xsltRegisterTmpRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT) +{ + if ((ctxt == NULL) || (RVT == NULL)) return(-1); + + RVT->next = (xmlNodePtr) ctxt->tmpRVT; + if (ctxt->tmpRVT != NULL) + ctxt->tmpRVT->prev = (xmlNodePtr) RVT; + ctxt->tmpRVT = RVT; + return(0); +} + +/** + * xsltRegisterPersistRVT: + * @ctxt: an XSLT transformation context + * @RVT: a result value tree + * + * Register the result value tree for destruction at the end of the processing + * + * Returns 0 in case of success and -1 in case of error. + */ +int +xsltRegisterPersistRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT) +{ + if ((ctxt == NULL) || (RVT == NULL)) return(-1); + + RVT->next = (xmlNodePtr) ctxt->persistRVT; + if (ctxt->persistRVT != NULL) + ctxt->persistRVT->prev = (xmlNodePtr) RVT; + ctxt->persistRVT = RVT; + return(0); +} + +/** + * xsltFreeRVTs: + * @ctxt: an XSLT transformation context + * + * Free all the registered result value tree of the transformation + */ +void +xsltFreeRVTs(xsltTransformContextPtr ctxt) +{ + xmlDocPtr cur, next; + + if (ctxt == NULL) return; + + cur = ctxt->tmpRVT; + while (cur != NULL) { + next = (xmlDocPtr) cur->next; + xmlFreeDoc(cur); + cur = next; + } + cur = ctxt->persistRVT; + while (cur != NULL) { + next = (xmlDocPtr) cur->next; + xmlFreeDoc(cur); + cur = next; + } +} + /************************************************************************ * * * Module interfaces * @@ -364,12 +464,13 @@ xsltEvalVariable(xsltTransformContextPtr ctxt, xsltStackElemPtr elem, xmlNodePtr oldInsert; xmlDocPtr oldoutput; - container = xmlNewDoc(NULL); + container = xsltCreateRVT(ctxt); if (container == NULL) return(NULL); - container->name = (char *) xmlStrdup(BAD_CAST " fake node libxslt"); - container->doc = container; - container->parent = NULL; + /* + * Tag the subtree for removal once consumed + */ + xsltRegisterTmpRVT(ctxt, container); oldoutput = ctxt->output; ctxt->output = container; @@ -383,10 +484,7 @@ xsltEvalVariable(xsltTransformContextPtr ctxt, xsltStackElemPtr elem, if (result == NULL) { result = xmlXPathNewCString(""); } else { - /* - * Tag the subtree for removal once consumed - */ - result->boolval = 1; + result->boolval = 0; /* Freeing is not handled there anymore */ } #ifdef WITH_XSLT_DEBUG_VARIABLE #ifdef LIBXML_DEBUG_ENABLED @@ -501,12 +599,13 @@ xsltEvalGlobalVariable(xsltStackElemPtr elem, xsltTransformContextPtr ctxt) { xmlNodePtr oldInsert; xmlDocPtr oldoutput; - container = xmlNewDoc(NULL); + container = xsltCreateRVT(ctxt); if (container == NULL) return(NULL); - container->name = (char *) xmlStrdup(BAD_CAST " fake node libxslt"); - container->doc = container; - container->parent = NULL; + /* + * Tag the subtree for removal once consumed + */ + xsltRegisterTmpRVT(ctxt, container); oldoutput = ctxt->output; ctxt->output = container; @@ -520,10 +619,7 @@ xsltEvalGlobalVariable(xsltStackElemPtr elem, xsltTransformContextPtr ctxt) { if (result == NULL) { result = xmlXPathNewCString(""); } else { - /* - * Tag the subtree for removal once consumed - */ - result->boolval = 1; + result->boolval = 0; /* Freeing is not handled there anymore */ } #ifdef WITH_XSLT_DEBUG_VARIABLE #ifdef LIBXML_DEBUG_ENABLED diff --git a/libxslt/xsltInternals.h b/libxslt/xsltInternals.h index ecdf878e..21ef2b89 100644 --- a/libxslt/xsltInternals.h +++ b/libxslt/xsltInternals.h @@ -498,6 +498,12 @@ struct _xsltTransformContext { void * errctx; /* context for the error handler */ xsltSortFunc sortfunc; /* a ctxt specific sort routine */ + + /* + * handling of temporary Result Value Tree + */ + xmlDocPtr tmpRVT; /* list of RVT without persistance */ + xmlDocPtr persistRVT; /* list of persistant RVTs */ }; /** @@ -556,6 +562,15 @@ void xsltParseTemplateContent(xsltStylesheetPtr style, xmlNodePtr templ); int xsltAllocateExtra (xsltStylesheetPtr style); int xsltAllocateExtraCtxt (xsltTransformContextPtr ctxt); +/* + * Extra functions for Result Value Trees + */ +xmlDocPtr xsltCreateRVT (xsltTransformContextPtr ctxt); +int xsltRegisterTmpRVT (xsltTransformContextPtr ctxt, + xmlDocPtr RVT); +int xsltRegisterPersistRVT (xsltTransformContextPtr ctxt, + xmlDocPtr RVT); +void xsltFreeRVTs (xsltTransformContextPtr ctxt); #ifdef __cplusplus } #endif diff --git a/tests/exslt/strings/Makefile.am b/tests/exslt/strings/Makefile.am index 5bdb16ec..78732c17 100644 --- a/tests/exslt/strings/Makefile.am +++ b/tests/exslt/strings/Makefile.am @@ -4,7 +4,8 @@ $(top_builddir)/xsltproc/xsltproc: @(cd ../../../xsltproc ; $(MAKE) xsltproc) EXTRA_DIST = \ - tokenize.1.xml tokenize.1.xsl tokenize.1.out + tokenize.1.xml tokenize.1.xsl tokenize.1.out \ + tokenize.2.xml tokenize.2.xsl tokenize.2.out all: diff --git a/tests/exslt/strings/tokenize.2.out b/tests/exslt/strings/tokenize.2.out new file mode 100644 index 00000000..32bf7e12 --- /dev/null +++ b/tests/exslt/strings/tokenize.2.out @@ -0,0 +1,2 @@ + +Thisisstrangebehavior diff --git a/tests/exslt/strings/tokenize.2.xml b/tests/exslt/strings/tokenize.2.xml new file mode 100644 index 00000000..69d62f2c --- /dev/null +++ b/tests/exslt/strings/tokenize.2.xml @@ -0,0 +1 @@ + diff --git a/tests/exslt/strings/tokenize.2.xsl b/tests/exslt/strings/tokenize.2.xsl new file mode 100644 index 00000000..c60a6fe1 --- /dev/null +++ b/tests/exslt/strings/tokenize.2.xsl @@ -0,0 +1,13 @@ + + + + + + + + + +