1
0
mirror of https://gitlab.gnome.org/GNOME/libxslt synced 2025-11-09 22:20:55 +03:00

- libxslt/extra.c libxslt/transform.c libxslt/variables.[ch]

libxslt/xsltInternals.h: optimizations, cleanup of global
  variables handling
Daniel
This commit is contained in:
Daniel Veillard
2001-05-16 21:02:29 +00:00
parent 232b43a471
commit 36fd932592
6 changed files with 385 additions and 120 deletions

View File

@@ -1,3 +1,9 @@
Wed May 16 23:00:53 CEST 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
* libxslt/extra.c libxslt/transform.c libxslt/variables.[ch]
libxslt/xsltInternals.h: optimizations, cleanup of global
variables handling
Wed May 16 12:29:17 CEST 2001 Daniel Veillard <Daniel.Veillard@imag.fr> Wed May 16 12:29:17 CEST 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
* libxslt/extensions.c libxslt/preproc.c libxslt/transform.c * libxslt/extensions.c libxslt/preproc.c libxslt/transform.c

View File

@@ -72,12 +72,12 @@ xsltDebug(xsltTransformContextPtr ctxt, xmlNodePtr node ATTRIBUTE_UNUSED,
fprintf(stdout, "#%d\n", i); fprintf(stdout, "#%d\n", i);
cur = ctxt->varsTab[j]; cur = ctxt->varsTab[j];
while (cur != NULL) { while (cur != NULL) {
if (cur->type == XSLT_ELEM_VARIABLE) if (cur->comp == NULL) {
fprintf(stdout, "var ");
else if (cur->type == XSLT_ELEM_PARAM)
fprintf(stdout, "param ");
else {
fprintf(stdout, "corrupted !!!\n"); fprintf(stdout, "corrupted !!!\n");
} else if (cur->comp->type == XSLT_FUNC_PARAM) {
fprintf(stdout, "param ");
} else if (cur->comp->type == XSLT_FUNC_VARIABLE) {
fprintf(stdout, "var ");
} }
if (cur->name != NULL) if (cur->name != NULL)
fprintf(stdout, "%s ", cur->name); fprintf(stdout, "%s ", cur->name);

View File

@@ -214,6 +214,7 @@ xsltFreeTransformContext(xsltTransformContextPtr ctxt) {
xmlFree(ctxt->varsTab); xmlFree(ctxt->varsTab);
xsltFreeDocuments(ctxt); xsltFreeDocuments(ctxt);
xsltFreeCtxtExts(ctxt); xsltFreeCtxtExts(ctxt);
xsltFreeGlobalVariables(ctxt);
memset(ctxt, -1, sizeof(xsltTransformContext)); memset(ctxt, -1, sizeof(xsltTransformContext));
xmlFree(ctxt); xmlFree(ctxt);
} }
@@ -2544,6 +2545,8 @@ xsltApplyStylesheet(xsltStylesheetPtr style, xmlDocPtr doc,
const xmlChar *doctypePublic; const xmlChar *doctypePublic;
const xmlChar *doctypeSystem; const xmlChar *doctypeSystem;
const xmlChar *version; const xmlChar *version;
xsltStackElemPtr variables;
xsltStackElemPtr vptr;
if ((style == NULL) || (doc == NULL)) if ((style == NULL) || (doc == NULL))
@@ -2602,12 +2605,14 @@ xsltApplyStylesheet(xsltStylesheetPtr style, xmlDocPtr doc,
res->charset = XML_CHAR_ENCODING_UTF8; res->charset = XML_CHAR_ENCODING_UTF8;
if (style->encoding != NULL) if (style->encoding != NULL)
res->encoding = xmlStrdup(style->encoding); res->encoding = xmlStrdup(style->encoding);
variables = style->variables;
/* /*
* Start. * Start.
*/ */
ctxt->output = res; ctxt->output = res;
ctxt->insert = (xmlNodePtr) res; ctxt->insert = (xmlNodePtr) res;
ctxt->globalVars = xmlHashCreate(20);
if (params != NULL) if (params != NULL)
xsltEvalUserParams(ctxt, params); xsltEvalUserParams(ctxt, params);
xsltEvalGlobalVariables(ctxt); xsltEvalGlobalVariables(ctxt);
@@ -2617,6 +2622,27 @@ xsltApplyStylesheet(xsltStylesheetPtr style, xmlDocPtr doc,
xsltFreeStackElemList(varsPop(ctxt)); xsltFreeStackElemList(varsPop(ctxt));
xsltCleanupTemplates(style); xsltCleanupTemplates(style);
/* Now cleanup our variables so stylesheet can be re-used */
if (style->variables != variables) {
vptr = style->variables;
while (vptr->next!=variables)
vptr = vptr->next;
vptr->next = NULL;
xsltFreeStackElemList(style->variables);
style->variables = variables;
}
vptr = style->variables;
while(vptr!=NULL) {
if (vptr->computed) {
if (vptr->value != NULL) {
xmlXPathFreeObject(vptr->value);
vptr->value = NULL;
vptr->computed = 0;
}
}
vptr = vptr->next;
}
root = xmlDocGetRootElement(res); root = xmlDocGetRootElement(res);
if (root != NULL) { if (root != NULL) {

View File

@@ -63,6 +63,35 @@ xsltNewStackElem(void) {
cur->select = NULL; cur->select = NULL;
cur->tree = NULL; cur->tree = NULL;
cur->value = NULL; cur->value = NULL;
cur->comp = NULL;
return(cur);
}
/**
* xsltCopyStackElem:
* @elem: an XSLT stack element
*
* Makes a copy of the stack element
*
* Returns the copy of NULL
*/
static xsltStackElemPtr
xsltCopyStackElem(xsltStackElemPtr elem) {
xsltStackElemPtr cur;
cur = (xsltStackElemPtr) xmlMalloc(sizeof(xsltStackElem));
if (cur == NULL) {
xsltGenericError(xsltGenericErrorContext,
"xsltNewStackElem : malloc failed\n");
return(NULL);
}
cur->name = xmlStrdup(elem->name);
cur->nameURI = xmlStrdup(elem->nameURI);
cur->select = xmlStrdup(elem->select);
cur->tree = elem->tree;
cur->comp = elem->comp;
cur->computed = 0;
cur->value = NULL;
return(cur); return(cur);
} }
@@ -211,7 +240,7 @@ xsltStackLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
*/ */
i = ctxt->varsNr - 1; i = ctxt->varsNr - 1;
for (;i >= 0;i--) { for (;i > 0;i--) {
cur = ctxt->varsTab[i]; cur = ctxt->varsTab[i];
while (cur != NULL) { while (cur != NULL) {
if (xmlStrEqual(cur->name, name)) { if (xmlStrEqual(cur->name, name)) {
@@ -246,14 +275,15 @@ xsltStackLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
* *
* Evaluate a variable value. * Evaluate a variable value.
* *
* Returns 0 in case of success, -1 in case of error * Returns the XPath Object value or NULL in case of error
*/ */
static int static xmlXPathObjectPtr
xsltEvalVariable(xsltTransformContextPtr ctxt, xsltStackElemPtr elem, xsltEvalVariable(xsltTransformContextPtr ctxt, xsltStackElemPtr elem,
xsltStylePreCompPtr precomp) { xsltStylePreCompPtr precomp) {
xmlXPathObjectPtr result = NULL;
int oldProximityPosition, oldContextSize; int oldProximityPosition, oldContextSize;
if ((ctxt == NULL) || (elem == NULL)) if ((ctxt == NULL) || (elem == NULL))
return(-1); return(NULL);
#ifdef WITH_XSLT_DEBUG_VARIABLE #ifdef WITH_XSLT_DEBUG_VARIABLE
xsltGenericDebug(xsltGenericDebugContext, xsltGenericDebug(xsltGenericDebugContext,
@@ -261,7 +291,6 @@ xsltEvalVariable(xsltTransformContextPtr ctxt, xsltStackElemPtr elem,
#endif #endif
if (elem->select != NULL) { if (elem->select != NULL) {
xmlXPathCompExprPtr comp = NULL; xmlXPathCompExprPtr comp = NULL;
xmlXPathObjectPtr result;
if ((precomp != NULL) && (precomp->comp != NULL)) { if ((precomp != NULL) && (precomp->comp != NULL)) {
comp = precomp->comp; comp = precomp->comp;
@@ -269,7 +298,7 @@ xsltEvalVariable(xsltTransformContextPtr ctxt, xsltStackElemPtr elem,
comp = xmlXPathCompile(elem->select); comp = xmlXPathCompile(elem->select);
} }
if (comp == NULL) if (comp == NULL)
return(-1); return(NULL);
oldProximityPosition = ctxt->xpathCtxt->proximityPosition; oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
oldContextSize = ctxt->xpathCtxt->contextSize; oldContextSize = ctxt->xpathCtxt->contextSize;
ctxt->xpathCtxt->node = (xmlNodePtr) ctxt->node; ctxt->xpathCtxt->node = (xmlNodePtr) ctxt->node;
@@ -284,23 +313,19 @@ xsltEvalVariable(xsltTransformContextPtr ctxt, xsltStackElemPtr elem,
if (result == NULL) { if (result == NULL) {
xsltGenericError(xsltGenericErrorContext, xsltGenericError(xsltGenericErrorContext,
"Evaluating variable %s failed\n", elem->name); "Evaluating variable %s failed\n", elem->name);
} else {
#ifdef WITH_XSLT_DEBUG_VARIABLE #ifdef WITH_XSLT_DEBUG_VARIABLE
#ifdef LIBXML_DEBUG_ENABLED #ifdef LIBXML_DEBUG_ENABLED
} else {
if ((xsltGenericDebugContext == stdout) || if ((xsltGenericDebugContext == stdout) ||
(xsltGenericDebugContext == stderr)) (xsltGenericDebugContext == stderr))
xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext, xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
result, 0); result, 0);
#endif #endif
#endif #endif
if (elem->value != NULL)
xmlXPathFreeObject(elem->value);
elem->value = result;
} }
elem->computed = 1;
} else { } else {
if (elem->tree == NULL) { if (elem->tree == NULL) {
elem->value = xmlXPathNewCString(""); result = xmlXPathNewCString("");
} else { } else {
/* /*
* This is a result tree fragment. * This is a result tree fragment.
@@ -311,7 +336,7 @@ xsltEvalVariable(xsltTransformContextPtr ctxt, xsltStackElemPtr elem,
container = xmlNewDocNode(ctxt->output, NULL, container = xmlNewDocNode(ctxt->output, NULL,
(const xmlChar *) "fake", NULL); (const xmlChar *) "fake", NULL);
if (container == NULL) if (container == NULL)
return(-1); return(NULL);
oldInsert = ctxt->insert; oldInsert = ctxt->insert;
oldNode = ctxt->node; oldNode = ctxt->node;
@@ -320,24 +345,125 @@ xsltEvalVariable(xsltTransformContextPtr ctxt, xsltStackElemPtr elem,
ctxt->insert = oldInsert; ctxt->insert = oldInsert;
ctxt->node = oldNode; ctxt->node = oldNode;
if (elem->value != NULL) result = xmlXPathNewValueTree(container);
xmlXPathFreeObject(elem->value); if (result == NULL) {
elem->value = xmlXPathNewValueTree(container); result = xmlXPathNewCString("");
if (elem->value == NULL) {
elem->value = xmlXPathNewCString("");
} }
#ifdef WITH_XSLT_DEBUG_VARIABLE #ifdef WITH_XSLT_DEBUG_VARIABLE
#ifdef LIBXML_DEBUG_ENABLED #ifdef LIBXML_DEBUG_ENABLED
if ((xsltGenericDebugContext == stdout) || if ((xsltGenericDebugContext == stdout) ||
(xsltGenericDebugContext == stderr)) (xsltGenericDebugContext == stderr))
xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext, xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
elem->value, 0); result, 0);
#endif #endif
#endif #endif
} }
}
return(result);
}
/**
* xsltEvalGlobalVariable:
* @ctxt: the XSLT transformation context
* @elem: the variable or parameter.
*
* Evaluate a global variable value.
*
* Returns the XPath Object value or NULL in case of error
*/
static xmlXPathObjectPtr
xsltEvalGlobalVariable(xsltStackElemPtr elem, xsltTransformContextPtr ctxt) {
xmlXPathObjectPtr result = NULL;
xsltStylePreCompPtr precomp;
int oldProximityPosition, oldContextSize;
if ((ctxt == NULL) || (elem == NULL))
return(NULL);
if (elem->computed)
return(elem->value);
#ifdef WITH_XSLT_DEBUG_VARIABLE
xsltGenericDebug(xsltGenericDebugContext,
"Evaluating global variable %s\n", elem->name);
#endif
precomp = elem->comp;
if (elem->select != NULL) {
xmlXPathCompExprPtr comp = NULL;
if ((precomp != NULL) && (precomp->comp != NULL)) {
comp = precomp->comp;
} else {
comp = xmlXPathCompile(elem->select);
}
if (comp == NULL)
return(NULL);
oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
oldContextSize = ctxt->xpathCtxt->contextSize;
ctxt->xpathCtxt->node = (xmlNodePtr) ctxt->node;
/* TODO: do we need to propagate the namespaces here ? */
ctxt->xpathCtxt->namespaces = NULL;
ctxt->xpathCtxt->nsNr = 0;
result = xmlXPathCompiledEval(comp, ctxt->xpathCtxt);
ctxt->xpathCtxt->contextSize = oldContextSize;
ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
if ((precomp == NULL) || (precomp->comp == NULL))
xmlXPathFreeCompExpr(comp);
if (result == NULL) {
xsltGenericError(xsltGenericErrorContext,
"Evaluating global variable %s failed\n", elem->name);
#ifdef WITH_XSLT_DEBUG_VARIABLE
#ifdef LIBXML_DEBUG_ENABLED
} else {
if ((xsltGenericDebugContext == stdout) ||
(xsltGenericDebugContext == stderr))
xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
result, 0);
#endif
#endif
}
} else {
if (elem->tree == NULL) {
result = xmlXPathNewCString("");
} else {
/*
* This is a result tree fragment.
*/
xmlNodePtr container;
xmlNodePtr oldInsert, oldNode;
container = xmlNewDocNode(ctxt->output, NULL,
(const xmlChar *) "fake", NULL);
if (container == NULL)
return(NULL);
oldInsert = ctxt->insert;
oldNode = ctxt->node;
ctxt->insert = container;
xsltApplyOneTemplate(ctxt, ctxt->node, elem->tree, 0);
ctxt->insert = oldInsert;
ctxt->node = oldNode;
result = xmlXPathNewValueTree(container);
if (result == NULL) {
result = xmlXPathNewCString("");
}
#ifdef WITH_XSLT_DEBUG_VARIABLE
#ifdef LIBXML_DEBUG_ENABLED
if ((xsltGenericDebugContext == stdout) ||
(xsltGenericDebugContext == stderr))
xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
result, 0);
#endif
#endif
}
}
if (result != NULL) {
elem->value = result;
elem->computed = 1; elem->computed = 1;
} }
return(0); return(result);
} }
/** /**
@@ -359,23 +485,62 @@ xsltEvalGlobalVariables(xsltTransformContextPtr ctxt) {
#ifdef WITH_XSLT_DEBUG_VARIABLE #ifdef WITH_XSLT_DEBUG_VARIABLE
xsltGenericDebug(xsltGenericDebugContext, xsltGenericDebug(xsltGenericDebugContext,
"Evaluating global variables\n"); "Registering global variables\n");
#endif #endif
ctxt->node = (xmlNodePtr) ctxt->document->doc; ctxt->node = (xmlNodePtr) ctxt->document->doc;
ctxt->xpathCtxt->contextSize = 1; ctxt->xpathCtxt->contextSize = 1;
ctxt->xpathCtxt->proximityPosition = 1; ctxt->xpathCtxt->proximityPosition = 1;
/*
* Walk the list from the stylesheets and populate the hash table
*/
style = ctxt->style; style = ctxt->style;
while (style != NULL) { while (style != NULL) {
elem = style->variables; elem = style->variables;
#ifdef WITH_XSLT_DEBUG_VARIABLE
if ((style->doc != NULL) && (style->doc->URL != NULL)) {
xsltGenericDebug(xsltGenericDebugContext,
"Registering global variables from %s\n",
style->doc->URL);
}
#endif
while (elem != NULL) { while (elem != NULL) {
if (elem->computed == 0) xsltStackElemPtr def;
xsltEvalVariable(ctxt, elem, NULL);
/*
* Global variables are stored in the variables pool.
*/
def = (xsltStackElemPtr)
xmlHashLookup2(ctxt->globalVars,
elem->name, elem->nameURI);
if (def == NULL) {
int res;
def = xsltCopyStackElem(elem);
res = xmlHashAddEntry2(ctxt->globalVars,
elem->name, elem->nameURI, def);
} else if ((elem->comp != NULL) &&
(elem->comp->type == XSLT_FUNC_VARIABLE)) {
xsltGenericError(xsltGenericErrorContext,
"Global variable %s already defined\n", elem->name);
}
elem = elem->next; elem = elem->next;
} }
style = xsltNextImport(style); style = xsltNextImport(style);
} }
/*
* This part does the actual evaluation
*/
ctxt->node = (xmlNodePtr) ctxt->document->doc;
ctxt->xpathCtxt->contextSize = 1;
ctxt->xpathCtxt->proximityPosition = 1;
xmlHashScan(ctxt->globalVars,
(xmlHashScanner) xsltEvalGlobalVariable, ctxt);
return(0); return(0);
} }
@@ -386,7 +551,7 @@ xsltEvalGlobalVariables(xsltTransformContextPtr ctxt) {
* @ns_uri: the variable namespace URI * @ns_uri: the variable namespace URI
* @select: the expression which need to be evaluated to generate a value * @select: the expression which need to be evaluated to generate a value
* @tree: the subtree if select is NULL * @tree: the subtree if select is NULL
* @param: this is a parameter actually * @comp: the precompiled value
* @value: the string value if available * @value: the string value if available
* *
* Register a new variable value. If @value is NULL it unregisters * Register a new variable value. If @value is NULL it unregisters
@@ -397,15 +562,18 @@ xsltEvalGlobalVariables(xsltTransformContextPtr ctxt) {
static int static int
xsltRegisterGlobalVariable(xsltStylesheetPtr style, const xmlChar *name, xsltRegisterGlobalVariable(xsltStylesheetPtr style, const xmlChar *name,
const xmlChar *ns_uri, const xmlChar *select, const xmlChar *ns_uri, const xmlChar *select,
xmlNodePtr tree, int param, const xmlChar *value) { xmlNodePtr tree, xsltStylePreCompPtr comp,
xsltStackElemPtr elem; const xmlChar *value) {
xsltStackElemPtr elem, tmp;
if (style == NULL) if (style == NULL)
return(-1); return(-1);
if (name == NULL) if (name == NULL)
return(-1); return(-1);
if (comp == NULL)
return(-1);
#ifdef WITH_XSLT_DEBUG_VARIABLE #ifdef WITH_XSLT_DEBUG_VARIABLE
if (param) if (comp->type == XSLT_FUNC_PARAM)
xsltGenericDebug(xsltGenericDebugContext, xsltGenericDebug(xsltGenericDebugContext,
"Defining global param %s\n", name); "Defining global param %s\n", name);
else else
@@ -415,17 +583,22 @@ xsltRegisterGlobalVariable(xsltStylesheetPtr style, const xmlChar *name,
elem = xsltNewStackElem(); elem = xsltNewStackElem();
if (elem == NULL) if (elem == NULL)
return(-1); return(-1);
if (param) elem->comp = comp;
elem->type = XSLT_ELEM_PARAM;
else
elem->type = XSLT_ELEM_VARIABLE;
elem->name = xmlStrdup(name); elem->name = xmlStrdup(name);
elem->select = xmlStrdup(select); elem->select = xmlStrdup(select);
if (ns_uri) if (ns_uri)
elem->nameURI = xmlStrdup(ns_uri); elem->nameURI = xmlStrdup(ns_uri);
elem->tree = tree; elem->tree = tree;
elem->next = style->variables; tmp = style->variables;
if (tmp == NULL) {
elem->next = NULL;
style->variables = elem; style->variables = elem;
} else {
while (tmp->next != NULL)
tmp = tmp->next;
elem->next = NULL;
tmp->next = elem;
}
if (value != NULL) { if (value != NULL) {
elem->computed = 1; elem->computed = 1;
elem->value = xmlXPathNewString(value); elem->value = xmlXPathNewString(value);
@@ -450,6 +623,10 @@ xsltEvalUserParams(xsltTransformContextPtr ctxt, const char **params) {
const xmlChar *name; const xmlChar *name;
const xmlChar *value; const xmlChar *value;
xmlChar *ncname, *prefix; xmlChar *ncname, *prefix;
const xmlChar *href;
xmlXPathCompExprPtr comp;
xmlXPathObjectPtr result;
int oldProximityPosition, oldContextSize;
if (ctxt == NULL) if (ctxt == NULL)
return(-1); return(-1);
@@ -467,7 +644,11 @@ xsltEvalUserParams(xsltTransformContextPtr ctxt, const char **params) {
xsltGenericDebug(xsltGenericDebugContext, xsltGenericDebug(xsltGenericDebugContext,
"Evaluating user parameter %s=%s\n", name, value); "Evaluating user parameter %s=%s\n", name, value);
#endif #endif
/*
* Name lookup
*/
ncname = xmlSplitQName2(name, &prefix); ncname = xmlSplitQName2(name, &prefix);
href = NULL;
if (ncname != NULL) { if (ncname != NULL) {
if (prefix != NULL) { if (prefix != NULL) {
xmlNsPtr ns; xmlNsPtr ns;
@@ -477,20 +658,78 @@ xsltEvalUserParams(xsltTransformContextPtr ctxt, const char **params) {
if (ns == NULL) { if (ns == NULL) {
xsltGenericError(xsltGenericErrorContext, xsltGenericError(xsltGenericErrorContext,
"user param : no namespace bound to prefix %s\n", prefix); "user param : no namespace bound to prefix %s\n", prefix);
href = NULL;
} else { } else {
xsltRegisterGlobalVariable(style, ncname, ns->href, NULL, href = ns->href;
NULL, 1, value);
} }
xmlFree(prefix); xmlFree(prefix);
} else { } else {
xsltRegisterGlobalVariable(style, ncname, NULL, NULL, NULL, href = NULL;
1, value);
} }
xmlFree(ncname); xmlFree(ncname);
} else { } else {
xsltRegisterGlobalVariable(style, name, NULL, NULL, NULL, 1, value); href = NULL;
ncname = xmlStrdup(name);
} }
/*
* Do the evaluation
*/
result = NULL;
comp = xmlXPathCompile(value);
if (comp != NULL) {
oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
oldContextSize = ctxt->xpathCtxt->contextSize;
ctxt->xpathCtxt->node = (xmlNodePtr) ctxt->node;
/* TODO: do we need to propagate the namespaces here ? */
ctxt->xpathCtxt->namespaces = NULL;
ctxt->xpathCtxt->nsNr = 0;
result = xmlXPathCompiledEval(comp, ctxt->xpathCtxt);
ctxt->xpathCtxt->contextSize = oldContextSize;
ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
xmlXPathFreeCompExpr(comp);
}
if (result == NULL) {
xsltGenericError(xsltGenericErrorContext,
"Evaluating user parameter %s failed\n", name);
} else {
xsltStackElemPtr elem;
int res;
#ifdef WITH_XSLT_DEBUG_VARIABLE
#ifdef LIBXML_DEBUG_ENABLED
if ((xsltGenericDebugContext == stdout) ||
(xsltGenericDebugContext == stderr))
xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
result, 0);
#endif
#endif
elem = xsltNewStackElem();
if (elem != NULL) {
elem->name = xmlStrdup(ncname);
if (value != NULL)
elem->select = xmlStrdup(value);
else
elem->select = NULL;
if (href)
elem->nameURI = xmlStrdup(href);
elem->tree = NULL;
elem->computed = 1;
elem->value = result;
}
/*
* Global parameters are stored in the XPath context
* variables pool.
*/
res = xmlHashAddEntry2(ctxt->globalVars,
ncname, href, elem);
if (res != 0) {
xsltFreeStackElem(elem);
xsltGenericError(xsltGenericErrorContext,
"Global parameter %s already defined\n", ncname);
}
}
xmlFree(ncname);
} }
return(0); return(0);
@@ -499,11 +738,8 @@ xsltEvalUserParams(xsltTransformContextPtr ctxt, const char **params) {
/** /**
* xsltBuildVariable: * xsltBuildVariable:
* @ctxt: the XSLT transformation context * @ctxt: the XSLT transformation context
* @name: the variable name * @comp: the precompiled form
* @ns_uri: the variable namespace URI
* @select: the expression which need to be evaluated to generate a value
* @tree: the tree if select is NULL * @tree: the tree if select is NULL
* @param: this is a parameter actually
* *
* Computes a new variable value. * Computes a new variable value.
* *
@@ -511,7 +747,7 @@ xsltEvalUserParams(xsltTransformContextPtr ctxt, const char **params) {
*/ */
static xsltStackElemPtr static xsltStackElemPtr
xsltBuildVariable(xsltTransformContextPtr ctxt, xsltStylePreCompPtr comp, xsltBuildVariable(xsltTransformContextPtr ctxt, xsltStylePreCompPtr comp,
xmlNodePtr tree, int param) { xmlNodePtr tree) {
xsltStackElemPtr elem; xsltStackElemPtr elem;
#ifdef WITH_XSLT_DEBUG_VARIABLE #ifdef WITH_XSLT_DEBUG_VARIABLE
@@ -525,10 +761,7 @@ xsltBuildVariable(xsltTransformContextPtr ctxt, xsltStylePreCompPtr comp,
elem = xsltNewStackElem(); elem = xsltNewStackElem();
if (elem == NULL) if (elem == NULL)
return(NULL); return(NULL);
if (param) elem->comp = comp;
elem->type = XSLT_ELEM_PARAM;
else
elem->type = XSLT_ELEM_VARIABLE;
elem->name = xmlStrdup(comp->name); elem->name = xmlStrdup(comp->name);
if (comp->select != NULL) if (comp->select != NULL)
elem->select = xmlStrdup(comp->select); elem->select = xmlStrdup(comp->select);
@@ -537,7 +770,11 @@ xsltBuildVariable(xsltTransformContextPtr ctxt, xsltStylePreCompPtr comp,
if (comp->ns) if (comp->ns)
elem->nameURI = xmlStrdup(comp->ns); elem->nameURI = xmlStrdup(comp->ns);
elem->tree = tree; elem->tree = tree;
xsltEvalVariable(ctxt, elem, comp); if (elem->computed == 0) {
elem->value = xsltEvalVariable(ctxt, elem, comp);
if (elem->value != NULL)
elem->computed = 1;
}
return(elem); return(elem);
} }
@@ -571,7 +808,7 @@ xsltRegisterVariable(xsltTransformContextPtr ctxt, xsltStylePreCompPtr comp,
#endif #endif
return(0); return(0);
} }
elem = xsltBuildVariable(ctxt, comp, tree, param); elem = xsltBuildVariable(ctxt, comp, tree);
xsltAddStackElem(ctxt, elem); xsltAddStackElem(ctxt, elem);
return(0); return(0);
} }
@@ -590,48 +827,28 @@ xsltRegisterVariable(xsltTransformContextPtr ctxt, xsltStylePreCompPtr comp,
static xmlXPathObjectPtr static xmlXPathObjectPtr
xsltGlobalVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name, xsltGlobalVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
const xmlChar *ns_uri) { const xmlChar *ns_uri) {
xsltStylesheetPtr style; xsltStackElemPtr elem;
xsltStackElemPtr elem = NULL; xmlXPathObjectPtr ret = NULL;
style = ctxt->style; /*
while (style != NULL) { * Lookup the global variables in XPath global variable hash table
elem = style->variables; */
if ((ctxt->xpathCtxt == NULL) || (ctxt->globalVars == NULL))
while (elem != NULL) {
if (xmlStrEqual(elem->name, name)) {
if (ns_uri == NULL) {
if (elem->nameURI == NULL)
break;
} else {
if ((elem->nameURI != NULL) &&
(xmlStrEqual(elem->nameURI, ns_uri)))
break;
}
}
elem = elem->next;
}
if (elem != NULL) break;
style = xsltNextImport(style);
}
if (elem == NULL)
return(NULL); return(NULL);
elem = (xsltStackElemPtr)
if (!elem->computed) { xmlHashLookup2(ctxt->globalVars, name, ns_uri);
#ifdef WITH_XSLT_DEBUG_VARIABLE if (elem == NULL) {
xsltGenericDebug(xsltGenericDebugContext,
"uncomputed global variable %s\n", name);
#endif
xsltEvalVariable(ctxt, elem, NULL);
}
if (elem->value != NULL)
return(xmlXPathObjectCopy(elem->value));
#ifdef WITH_XSLT_DEBUG_VARIABLE #ifdef WITH_XSLT_DEBUG_VARIABLE
xsltGenericDebug(xsltGenericDebugContext, xsltGenericDebug(xsltGenericDebugContext,
"global variable not found %s\n", name); "global variable not found %s\n", name);
#endif #endif
return(NULL); return(NULL);
}
if (elem->computed == 0)
ret = xsltEvalGlobalVariable(elem, ctxt);
else
ret = elem->value;
return(xmlXPathObjectCopy(ret));
} }
/** /**
@@ -657,12 +874,13 @@ xsltVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
if (elem == NULL) { if (elem == NULL) {
return(xsltGlobalVariableLookup(ctxt, name, ns_uri)); return(xsltGlobalVariableLookup(ctxt, name, ns_uri));
} }
if (!elem->computed) { if (elem->computed == 0) {
#ifdef WITH_XSLT_DEBUG_VARIABLE #ifdef WITH_XSLT_DEBUG_VARIABLE
xsltGenericDebug(xsltGenericDebugContext, xsltGenericDebug(xsltGenericDebugContext,
"uncomputed variable %s\n", name); "uncomputed variable %s\n", name);
#endif #endif
xsltEvalVariable(ctxt, elem, NULL); elem->value = xsltEvalVariable(ctxt, elem, NULL);
elem->computed = 1;
} }
if (elem->value != NULL) if (elem->value != NULL)
return(xmlXPathObjectCopy(elem->value)); return(xmlXPathObjectCopy(elem->value));
@@ -720,7 +938,7 @@ xsltParseStylesheetCallerParam(xsltTransformContextPtr ctxt, xmlNodePtr cur) {
tree = cur; tree = cur;
} }
elem = xsltBuildVariable(ctxt, comp, tree, 1); elem = xsltBuildVariable(ctxt, comp, tree);
return(elem); return(elem);
} }
@@ -761,7 +979,7 @@ xsltParseGlobalVariable(xsltStylesheetPtr style, xmlNodePtr cur) {
#endif #endif
xsltRegisterGlobalVariable(style, comp->name, comp->ns, comp->select, xsltRegisterGlobalVariable(style, comp->name, comp->ns, comp->select,
cur->children, 0, NULL); cur->children, comp, NULL);
} }
/** /**
@@ -800,7 +1018,7 @@ xsltParseGlobalParam(xsltStylesheetPtr style, xmlNodePtr cur) {
#endif #endif
xsltRegisterGlobalVariable(style, comp->name, comp->ns, comp->select, xsltRegisterGlobalVariable(style, comp->name, comp->ns, comp->select,
cur->children, 1, NULL); cur->children, comp, NULL);
} }
/** /**
@@ -877,6 +1095,19 @@ xsltParseStylesheetParam(xsltTransformContextPtr ctxt, xmlNodePtr cur) {
xsltRegisterVariable(ctxt, comp, cur->children, 1); xsltRegisterVariable(ctxt, comp, cur->children, 1);
} }
/**
* xsltFreeGlobalVariables:
* @ctxt: the XSLT transformation context
*
* Free up the data associated to the global variables
* its value.
*/
void
xsltFreeGlobalVariables(xsltTransformContextPtr ctxt) {
xmlHashFree(ctxt->globalVars, (xmlHashDeallocator) xsltFreeStackElem);
}
/** /**
* xsltVariableLookup: * xsltVariableLookup:
* @ctxt: a void * but the the XSLT transformation context actually * @ctxt: a void * but the the XSLT transformation context actually
@@ -915,3 +1146,4 @@ xsltXPathVariableLookup(void *ctxt, const xmlChar *name,
return(ret); return(ret);
} }

View File

@@ -51,6 +51,7 @@ xsltStackElemPtr xsltParseStylesheetCallerParam (xsltTransformContextPtr ctxt,
int xsltAddStackElemList (xsltTransformContextPtr ctxt, int xsltAddStackElemList (xsltTransformContextPtr ctxt,
xsltStackElemPtr elems); xsltStackElemPtr elems);
void xsltFreeVariableHashes (xsltTransformContextPtr ctxt); void xsltFreeVariableHashes (xsltTransformContextPtr ctxt);
void xsltFreeGlobalVariables (xsltTransformContextPtr ctxt);
xmlXPathObjectPtr xsltVariableLookup (xsltTransformContextPtr ctxt, xmlXPathObjectPtr xsltVariableLookup (xsltTransformContextPtr ctxt,
const xmlChar *name, const xmlChar *name,
const xmlChar *ns_uri); const xmlChar *ns_uri);

View File

@@ -25,29 +25,6 @@ extern "C" {
*/ */
#define XSLT_MAX_SORT 5 #define XSLT_MAX_SORT 5
/*
* The in-memory structure corresponding to an XSLT Variable
* or Param
*/
typedef enum {
XSLT_ELEM_VARIABLE=1,
XSLT_ELEM_PARAM
} xsltElem;
typedef struct _xsltStackElem xsltStackElem;
typedef xsltStackElem *xsltStackElemPtr;
struct _xsltStackElem {
struct _xsltStackElem *next;/* chained list */
xsltElem type; /* type of the element */
int computed; /* was the evaluation done */
xmlChar *name; /* the local part of the name QName */
xmlChar *nameURI; /* the URI part of the name QName */
xmlChar *select; /* the eval string */
xmlNodePtr tree; /* the tree if no eval string or the location */
xmlXPathObjectPtr value; /* The value if computed */
};
/* /*
* The in-memory structure corresponding to an XSLT Template * The in-memory structure corresponding to an XSLT Template
*/ */
@@ -188,6 +165,24 @@ struct _xsltStylePreComp {
int nsNr; /* the number of namespaces in scope */ int nsNr; /* the number of namespaces in scope */
}; };
/*
* The in-memory structure corresponding to an XSLT Variable
* or Param
*/
typedef struct _xsltStackElem xsltStackElem;
typedef xsltStackElem *xsltStackElemPtr;
struct _xsltStackElem {
struct _xsltStackElem *next;/* chained list */
xsltStylePreCompPtr comp; /* the compiled form */
int computed; /* was the evaluation done */
xmlChar *name; /* the local part of the name QName */
xmlChar *nameURI; /* the URI part of the name QName */
xmlChar *select; /* the eval string */
xmlNodePtr tree; /* the tree if no eval string or the location */
xmlXPathObjectPtr value; /* The value if computed */
};
/* /*
* The in-memory structure corresponding to an XSLT Stylesheet * The in-memory structure corresponding to an XSLT Stylesheet
* NOTE: most of the content is simply linked from the doc tree * NOTE: most of the content is simply linked from the doc tree
@@ -329,6 +324,11 @@ struct _xsltTransformContext {
xmlXPathContextPtr xpathCtxt; /* the XPath context */ xmlXPathContextPtr xpathCtxt; /* the XPath context */
xsltTransformState state; /* the current state */ xsltTransformState state; /* the current state */
/*
* Global variables
*/
xmlHashTablePtr globalVars; /* the global variables and params */
}; };
#define CHECK_STOPPED if (ctxt->state == XSLT_STATE_STOPPED) return; #define CHECK_STOPPED if (ctxt->state == XSLT_STATE_STOPPED) return;