mirror of
https://gitlab.gnome.org/GNOME/libxslt
synced 2025-08-07 10:42:55 +03:00
cleaning up Result Value Tree handling fixed a pair of implementations.
* 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 Daniel
This commit is contained in:
@@ -1,3 +1,12 @@
|
||||
Wed Apr 30 22:44:49 CEST 2003 Daniel Veillard <daniel@veillard.com>
|
||||
|
||||
* 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 <daniel@veillard.com>
|
||||
|
||||
* libxslt/transform.c: fixing bug #111755 when a template is
|
||||
|
@@ -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
|
||||
|
@@ -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)
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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:
|
||||
|
||||
|
2
tests/exslt/strings/tokenize.2.out
Normal file
2
tests/exslt/strings/tokenize.2.out
Normal file
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0"?>
|
||||
<tok>This</tok><tok>is</tok><tok>strange</tok><tok>behavior</tok>
|
1
tests/exslt/strings/tokenize.2.xml
Normal file
1
tests/exslt/strings/tokenize.2.xml
Normal file
@@ -0,0 +1 @@
|
||||
<doc/>
|
13
tests/exslt/strings/tokenize.2.xsl
Normal file
13
tests/exslt/strings/tokenize.2.xsl
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0"?>
|
||||
<xsl:stylesheet version="1.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:str="http://exslt.org/strings"
|
||||
extension-element-prefixes="str">
|
||||
|
||||
<xsl:template match="/">
|
||||
<xsl:for-each select="str:tokenize('This is strange behavior', ' ')" >
|
||||
<tok><xsl:value-of select="."/></tok>
|
||||
</xsl:for-each>
|
||||
</xsl:template>
|
||||
|
||||
</xsl:stylesheet>
|
Reference in New Issue
Block a user