mirror of
https://gitlab.gnome.org/GNOME/libxslt
synced 2025-11-08 11:02:18 +03:00
now seems in place !!! * xsltproc.c: removed bug * tests/REC2/html.xml: added newline after doctype * libxslt/variables.[ch] libxslt/xsltInternals.h: added param support, result tree fragment support (requires just commited extensions to libxml2 XPath !!!) * transform.c: added call-template, with-param support * libxslt/pattern.[ch]: xsltFindTemplate() needed for call-template * TODO: updated, added a DONE section and started migrating stuff :-) Daniel
875 lines
20 KiB
C
875 lines
20 KiB
C
/*
|
|
* variables.c: Implementation of the variable storage and lookup
|
|
*
|
|
* Reference:
|
|
* http://www.w3.org/TR/1999/REC-xslt-19991116
|
|
*
|
|
* See Copyright for the status of this software.
|
|
*
|
|
* Daniel.Veillard@imag.fr
|
|
*/
|
|
|
|
#include "xsltconfig.h"
|
|
|
|
#include <string.h>
|
|
|
|
#include <libxml/xmlmemory.h>
|
|
#include <libxml/tree.h>
|
|
#include <libxml/valid.h>
|
|
#include <libxml/hash.h>
|
|
#include <libxml/xmlerror.h>
|
|
#include <libxml/xpath.h>
|
|
#include <libxml/xpathInternals.h>
|
|
#include <libxml/parserInternals.h>
|
|
#include "xslt.h"
|
|
#include "xsltInternals.h"
|
|
#include "xsltutils.h"
|
|
#include "variables.h"
|
|
#include "transform.h"
|
|
|
|
#define DEBUG_VARIABLE
|
|
|
|
/*
|
|
* Types are private:
|
|
*/
|
|
|
|
typedef struct _xsltStack xsltStack;
|
|
typedef xsltStack *xsltStackPtr;
|
|
struct _xsltStack {
|
|
int cur;
|
|
int max;
|
|
xsltStackElemPtr elems[50];
|
|
};
|
|
|
|
|
|
/************************************************************************
|
|
* *
|
|
* Module interfaces *
|
|
* *
|
|
************************************************************************/
|
|
|
|
/**
|
|
* xsltNewParserContext:
|
|
*
|
|
* Create a new XSLT ParserContext
|
|
*
|
|
* Returns the newly allocated xsltParserStackElem or NULL in case of error
|
|
*/
|
|
xsltStackElemPtr
|
|
xsltNewStackElem(void) {
|
|
xsltStackElemPtr cur;
|
|
|
|
cur = (xsltStackElemPtr) xmlMalloc(sizeof(xsltStackElem));
|
|
if (cur == NULL) {
|
|
xsltGenericError(xsltGenericErrorContext,
|
|
"xsltNewStackElem : malloc failed\n");
|
|
return(NULL);
|
|
}
|
|
memset(cur, 0, sizeof(xsltStackElem));
|
|
cur->computed = 0;
|
|
return(cur);
|
|
}
|
|
|
|
/**
|
|
* xsltFreeStackElem:
|
|
* @elem: an XSLT stack element
|
|
*
|
|
* Free up the memory allocated by @elem
|
|
*/
|
|
void
|
|
xsltFreeStackElem(xsltStackElemPtr elem) {
|
|
if (elem == NULL)
|
|
return;
|
|
if (elem->name != NULL)
|
|
xmlFree(elem->name);
|
|
if (elem->nameURI != NULL)
|
|
xmlFree(elem->nameURI);
|
|
if (elem->select != NULL)
|
|
xmlFree(elem->select);
|
|
if (elem->value != NULL)
|
|
xmlXPathFreeObject(elem->value);
|
|
|
|
memset(elem, -1, sizeof(xsltStackElem));
|
|
xmlFree(elem);
|
|
}
|
|
|
|
/**
|
|
* xsltFreeStackElemList:
|
|
* @elem: an XSLT stack element
|
|
*
|
|
* Free up the memory allocated by @elem
|
|
*/
|
|
void
|
|
xsltFreeStackElemList(xsltStackElemPtr elem) {
|
|
xsltStackElemPtr next;
|
|
|
|
while(elem != NULL) {
|
|
next = elem->next;
|
|
xsltFreeStackElem(elem);
|
|
elem = next;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* xsltAddStackElem:
|
|
* @ctxt: xn XSLT transformation context
|
|
* @elem: a stack element
|
|
*
|
|
* add a new element at this level of the stack.
|
|
*
|
|
* Returns 0 in case of success, -1 in case of failure.
|
|
*/
|
|
int
|
|
xsltAddStackElem(xsltTransformContextPtr ctxt, xsltStackElemPtr elem) {
|
|
xsltStackPtr stack;
|
|
xsltStackElemPtr cur;
|
|
|
|
if ((ctxt == NULL) || (elem == NULL))
|
|
return(-1);
|
|
|
|
stack = ctxt->variablesHash;
|
|
if (stack == NULL) {
|
|
/* TODO make stack size dynamic !!! */
|
|
stack = xmlMalloc(sizeof (xsltStack));
|
|
if (stack == NULL) {
|
|
xsltGenericError(xsltGenericErrorContext,
|
|
"xsltPushStack : malloc failed\n");
|
|
return(-1);
|
|
}
|
|
memset(stack, 0, sizeof(xsltStack));
|
|
ctxt->variablesHash = stack;
|
|
stack->cur = 0;
|
|
stack->max = 50;
|
|
}
|
|
/* TODO: check that there is no conflict with existing values
|
|
* at that level */
|
|
cur = stack->elems[stack->cur];
|
|
while (cur != NULL) {
|
|
if (xmlStrEqual(elem->name, cur->name)) {
|
|
if (((elem->nameURI == NULL) && (cur->nameURI == NULL)) ||
|
|
((elem->nameURI != NULL) && (cur->nameURI != NULL) &&
|
|
(xmlStrEqual(elem->nameURI, cur->nameURI)))) {
|
|
xsltGenericError(xsltGenericErrorContext,
|
|
"redefinition of param or variable %s\n", elem->name);
|
|
xsltFreeStackElem(elem);
|
|
}
|
|
}
|
|
cur = cur->next;
|
|
}
|
|
|
|
elem->next = stack->elems[stack->cur];
|
|
stack->elems[stack->cur] = elem;
|
|
return(0);
|
|
}
|
|
|
|
/**
|
|
* xsltPushStack:
|
|
* @ctxt: xn XSLT transformation context
|
|
*
|
|
* Push a new level on the ctxtsheet interprestation stack
|
|
*/
|
|
void
|
|
xsltPushStack(xsltTransformContextPtr ctxt) {
|
|
xsltStackPtr stack;
|
|
|
|
if (ctxt == NULL)
|
|
return;
|
|
|
|
stack = ctxt->variablesHash;
|
|
if (stack == NULL) {
|
|
/* TODO make stack size dynamic !!! */
|
|
stack = xmlMalloc(sizeof (xsltStack));
|
|
if (stack == NULL) {
|
|
xsltGenericError(xsltGenericErrorContext,
|
|
"xsltPushStack : malloc failed\n");
|
|
return;
|
|
}
|
|
memset(stack, 0, sizeof(xsltStack));
|
|
ctxt->variablesHash = stack;
|
|
stack->cur = 0;
|
|
stack->max = 50;
|
|
}
|
|
if (stack->cur >= stack->max + 1) {
|
|
TODO /* make stack size dynamic !!! */
|
|
xsltGenericError(xsltGenericErrorContext,
|
|
"xsltPushStack : overflow\n");
|
|
return;
|
|
}
|
|
stack->cur++;
|
|
stack->elems[stack->cur] = NULL;
|
|
}
|
|
|
|
/**
|
|
* xsltPopStack:
|
|
* @ctxt: an XSLT transformation context
|
|
*
|
|
* Pop a level on the ctxtsheet interprestation stack
|
|
*/
|
|
void
|
|
xsltPopStack(xsltTransformContextPtr ctxt) {
|
|
xsltStackPtr stack;
|
|
|
|
if (ctxt == NULL)
|
|
return;
|
|
|
|
stack = ctxt->variablesHash;
|
|
if (stack == NULL)
|
|
return;
|
|
|
|
xsltFreeStackElemList(stack->elems[stack->cur]);
|
|
stack->elems[stack->cur] = NULL;
|
|
stack->cur--;
|
|
}
|
|
|
|
/**
|
|
* xsltStackLookup:
|
|
* @ctxt: an XSLT transformation context
|
|
* @name: the local part of the name
|
|
* @nameURI: the URI part of the name
|
|
*
|
|
* Locate an element in the stack based on its name.
|
|
*/
|
|
xsltStackElemPtr
|
|
xsltStackLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
|
|
const xmlChar *nameURI) {
|
|
xsltStackElemPtr ret = NULL;
|
|
xsltStackPtr stack;
|
|
int i;
|
|
xsltStackElemPtr cur;
|
|
|
|
if ((ctxt == NULL) || (name == NULL))
|
|
return(NULL);
|
|
|
|
stack = ctxt->variablesHash;
|
|
if (stack == NULL)
|
|
return(NULL);
|
|
|
|
for (i = stack->cur;i >= 0;i--) {
|
|
cur = stack->elems[i];
|
|
while (cur != NULL) {
|
|
if (xmlStrEqual(cur->name, name)) {
|
|
/* TODO: double check param binding */
|
|
if (nameURI == NULL) {
|
|
if (cur->nameURI == NULL) {
|
|
if (cur->type == XSLT_ELEM_PARAM)
|
|
ret = cur;
|
|
else
|
|
return(cur);
|
|
}
|
|
} else {
|
|
if ((cur->nameURI != NULL) &&
|
|
(xmlStrEqual(cur->nameURI, nameURI))) {
|
|
if (cur->type == XSLT_ELEM_PARAM)
|
|
ret = cur;
|
|
else
|
|
return(cur);
|
|
}
|
|
}
|
|
|
|
}
|
|
cur = cur->next;
|
|
}
|
|
}
|
|
return(ret);
|
|
}
|
|
|
|
/************************************************************************
|
|
* *
|
|
* Module interfaces *
|
|
* *
|
|
************************************************************************/
|
|
|
|
/**
|
|
* xsltEvalVariable:
|
|
* @ctxt: the XSLT transformation context
|
|
* @elem: the variable or parameter.
|
|
*
|
|
* Evaluate a variable value.
|
|
*
|
|
* Returns 0 in case of success, -1 in case of error
|
|
*/
|
|
int
|
|
xsltEvalVariables(xsltTransformContextPtr ctxt, xsltStackElemPtr elem) {
|
|
xmlXPathParserContextPtr xpathParserCtxt;
|
|
|
|
if ((ctxt == NULL) || (elem == NULL))
|
|
return(-1);
|
|
|
|
if (ctxt->xpathCtxt == NULL) {
|
|
xmlXPathInit();
|
|
ctxt->xpathCtxt = xmlXPathNewContext(ctxt->doc);
|
|
if (ctxt->xpathCtxt == NULL)
|
|
return(-1);
|
|
XSLT_REGISTER_VARIABLE_LOOKUP(ctxt);
|
|
}
|
|
|
|
#ifdef DEBUG_VARIABLE
|
|
xsltGenericDebug(xsltGenericDebugContext,
|
|
"Evaluating variable %s\n", elem->name);
|
|
#endif
|
|
if (elem->select != NULL) {
|
|
xmlXPathObjectPtr result, tmp;
|
|
|
|
xpathParserCtxt = xmlXPathNewParserContext(elem->select,
|
|
ctxt->xpathCtxt);
|
|
if (xpathParserCtxt == NULL)
|
|
return(-1);
|
|
ctxt->xpathCtxt->node = (xmlNodePtr) ctxt->node;
|
|
xmlXPathEvalExpr(xpathParserCtxt);
|
|
result = valuePop(xpathParserCtxt);
|
|
do {
|
|
tmp = valuePop(xpathParserCtxt);
|
|
if (tmp != NULL) {
|
|
xmlXPathFreeObject(tmp);
|
|
}
|
|
} while (tmp != NULL);
|
|
|
|
if (result == NULL) {
|
|
xsltGenericError(xsltGenericErrorContext,
|
|
"Evaluating global variable %s failed\n");
|
|
}
|
|
if (xpathParserCtxt != NULL)
|
|
xmlXPathFreeParserContext(xpathParserCtxt);
|
|
if (result != NULL) {
|
|
if (elem->value != NULL)
|
|
xmlXPathFreeObject(elem->value);
|
|
elem->value = result;
|
|
elem->computed = 1;
|
|
}
|
|
} else {
|
|
if (elem->tree == NULL) {
|
|
elem->value = xmlXPathNewCString("");
|
|
elem->computed = 1;
|
|
} 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(-1);
|
|
oldInsert = ctxt->insert;
|
|
oldNode = ctxt->node;
|
|
ctxt->insert = container;
|
|
|
|
xsltApplyOneTemplate(ctxt, ctxt->node, elem->tree);
|
|
|
|
ctxt->insert = oldInsert;
|
|
ctxt->node = oldNode;
|
|
elem->value = xmlXPathNewValueTree(container);
|
|
elem->computed = 1;
|
|
}
|
|
}
|
|
return(0);
|
|
}
|
|
/**
|
|
* xsltEvalGlobalVariables:
|
|
* @ctxt: the XSLT transformation context
|
|
*
|
|
* Evaluate the global variables of a stylesheet. This need to be
|
|
* done on parsed stylesheets before starting to apply transformations
|
|
*
|
|
* Returns 0 in case of success, -1 in case of error
|
|
*/
|
|
int
|
|
xsltEvalGlobalVariables(xsltTransformContextPtr ctxt) {
|
|
xsltStackElemPtr elem;
|
|
xsltStylesheetPtr style;
|
|
|
|
if (ctxt == NULL)
|
|
return(-1);
|
|
|
|
if (ctxt->xpathCtxt == NULL) {
|
|
xmlXPathInit();
|
|
ctxt->xpathCtxt = xmlXPathNewContext(ctxt->doc);
|
|
if (ctxt->xpathCtxt == NULL)
|
|
return(-1);
|
|
XSLT_REGISTER_VARIABLE_LOOKUP(ctxt);
|
|
}
|
|
|
|
#ifdef DEBUG_VARIABLE
|
|
xsltGenericDebug(xsltGenericDebugContext,
|
|
"Evaluating global variables\n");
|
|
#endif
|
|
ctxt->node = (xmlNodePtr) ctxt->doc;
|
|
style = ctxt->style;
|
|
/* TODO: handle the stylesheet cascade */
|
|
if (style != NULL) {
|
|
elem = style->variables;
|
|
|
|
while (elem != NULL) {
|
|
xsltEvalVariables(ctxt, elem);
|
|
elem = elem->next;
|
|
}
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
/**
|
|
* xsltRegisterGlobalVariable:
|
|
* @style: the XSLT transformation context
|
|
* @name: the variable name
|
|
* @ns_uri: the variable namespace URI
|
|
* @select: the expression which need to be evaluated to generate a value
|
|
* @tree: the subtree if select is NULL
|
|
* @param: this is a parameter actually
|
|
*
|
|
* Register a new variable value. If @value is NULL it unregisters
|
|
* the variable
|
|
*
|
|
* Returns 0 in case of success, -1 in case of error
|
|
*/
|
|
int
|
|
xsltRegisterGlobalVariable(xsltStylesheetPtr style, const xmlChar *name,
|
|
const xmlChar *ns_uri, const xmlChar *select,
|
|
xmlNodePtr tree, int param) {
|
|
xsltStackElemPtr elem;
|
|
if (style == NULL)
|
|
return(-1);
|
|
if (name == NULL)
|
|
return(-1);
|
|
|
|
#ifdef DEBUG_VARIABLE
|
|
if (param)
|
|
xsltGenericDebug(xsltGenericDebugContext,
|
|
"Defineing global param %s\n", name);
|
|
else
|
|
xsltGenericDebug(xsltGenericDebugContext,
|
|
"Defineing global variable %s\n", name);
|
|
#endif
|
|
elem = xsltNewStackElem();
|
|
if (elem == NULL)
|
|
return(-1);
|
|
if (param)
|
|
elem->type = XSLT_ELEM_PARAM;
|
|
else
|
|
elem->type = XSLT_ELEM_VARIABLE;
|
|
elem->name = xmlStrdup(name);
|
|
elem->select = xmlStrdup(select);
|
|
if (ns_uri)
|
|
elem->nameURI = xmlStrdup(ns_uri);
|
|
elem->tree = tree;
|
|
elem->next = style->variables;
|
|
style->variables = elem;
|
|
return(0);
|
|
}
|
|
|
|
/**
|
|
* xsltRegisterVariable:
|
|
* @ctxt: the XSLT transformation context
|
|
* @name: the variable name
|
|
* @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
|
|
* @param: this is a parameter actually
|
|
*
|
|
* Register a new variable value. If @value is NULL it unregisters
|
|
* the variable
|
|
*
|
|
* Returns 0 in case of success, -1 in case of error
|
|
*/
|
|
int
|
|
xsltRegisterVariable(xsltTransformContextPtr ctxt, const xmlChar *name,
|
|
const xmlChar *ns_uri, const xmlChar *select,
|
|
xmlNodePtr tree, int param) {
|
|
xsltStackElemPtr elem;
|
|
if (ctxt == NULL)
|
|
return(-1);
|
|
if (name == NULL)
|
|
return(-1);
|
|
|
|
#ifdef DEBUG_VARIABLE
|
|
xsltGenericDebug(xsltGenericDebugContext,
|
|
"Defineing variable %s\n", name);
|
|
#endif
|
|
elem = xsltNewStackElem();
|
|
if (elem == NULL)
|
|
return(-1);
|
|
if (param)
|
|
elem->type = XSLT_ELEM_PARAM;
|
|
else
|
|
elem->type = XSLT_ELEM_VARIABLE;
|
|
elem->name = xmlStrdup(name);
|
|
elem->select = xmlStrdup(select);
|
|
if (ns_uri)
|
|
elem->nameURI = xmlStrdup(ns_uri);
|
|
elem->tree = tree;
|
|
xsltAddStackElem(ctxt, elem);
|
|
xsltEvalVariables(ctxt, elem);
|
|
return(0);
|
|
}
|
|
|
|
/**
|
|
* xsltVariableLookup:
|
|
* @ctxt: the XSLT transformation context
|
|
* @name: the variable name
|
|
* @ns_uri: the variable namespace URI
|
|
*
|
|
* Search in the Variable array of the context for the given
|
|
* variable value.
|
|
*
|
|
* Returns the value or NULL if not found
|
|
*/
|
|
xmlXPathObjectPtr
|
|
xsltVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
|
|
const xmlChar *ns_uri) {
|
|
xsltStackElemPtr elem;
|
|
|
|
if (ctxt == NULL)
|
|
return(NULL);
|
|
|
|
elem = xsltStackLookup(ctxt, name, ns_uri);
|
|
if (elem == NULL) {
|
|
TODO /* searching on other ctxtsheets ? */
|
|
return(NULL);
|
|
}
|
|
if (!elem->computed) {
|
|
#ifdef DEBUG_VARIABLE
|
|
xsltGenericDebug(xsltGenericDebugContext,
|
|
"uncomputed variable %s\n", name);
|
|
#endif
|
|
xsltEvalVariables(ctxt, elem);
|
|
}
|
|
if (elem->value != NULL)
|
|
return(xmlXPathObjectCopy(elem->value));
|
|
#ifdef DEBUG_VARIABLE
|
|
xsltGenericDebug(xsltGenericDebugContext,
|
|
"variable not found %s\n", name);
|
|
#endif
|
|
return(NULL);
|
|
}
|
|
|
|
|
|
/**
|
|
* xsltFreeVariableHashes:
|
|
* @ctxt: an XSLT transformation context
|
|
*
|
|
* Free up the memory used by xsltAddVariable/xsltGetVariable mechanism
|
|
*/
|
|
void
|
|
xsltFreeVariableHashes(xsltTransformContextPtr ctxt) {
|
|
xsltStackPtr stack;
|
|
int i;
|
|
|
|
if (ctxt == NULL)
|
|
return;
|
|
|
|
stack = ctxt->variablesHash;
|
|
if (stack == NULL)
|
|
return;
|
|
|
|
for (i = 0; i <= stack->cur;i++) {
|
|
xsltFreeStackElemList(stack->elems[i]);
|
|
}
|
|
xmlFree(stack);
|
|
}
|
|
|
|
/**
|
|
* xsltParseStylesheetParam:
|
|
* @ctxt: the XSLT transformation context
|
|
* @cur: the "param" element
|
|
*
|
|
* parse an XSLT transformation param declaration and record
|
|
* its value.
|
|
*/
|
|
|
|
void
|
|
xsltParseStylesheetParam(xsltTransformContextPtr ctxt, xmlNodePtr cur) {
|
|
xmlChar *name, *ncname, *prefix;
|
|
xmlChar *select;
|
|
xmlNodePtr tree = NULL;
|
|
|
|
if ((cur == NULL) || (ctxt == NULL))
|
|
return;
|
|
|
|
name = xmlGetNsProp(cur, (const xmlChar *)"name", XSLT_NAMESPACE);
|
|
if (name == NULL) {
|
|
xsltGenericError(xsltGenericErrorContext,
|
|
"xsl:param : missing name attribute\n");
|
|
return;
|
|
}
|
|
|
|
#ifdef DEBUG_VARIABLE
|
|
xsltGenericDebug(xsltGenericDebugContext,
|
|
"Parsing param %s\n", name);
|
|
#endif
|
|
|
|
select = xmlGetNsProp(cur, (const xmlChar *)"select", XSLT_NAMESPACE);
|
|
if (select == NULL) {
|
|
tree = cur->children;
|
|
} else {
|
|
if (cur->children != NULL)
|
|
xsltGenericError(xsltGenericErrorContext,
|
|
"xsl:param : content shuld be empty since select is present \n");
|
|
}
|
|
|
|
ncname = xmlSplitQName2(name, &prefix);
|
|
|
|
if (ncname != NULL) {
|
|
if (prefix != NULL) {
|
|
xmlNsPtr ns;
|
|
|
|
ns = xmlSearchNs(cur->doc, cur, prefix);
|
|
if (ns == NULL) {
|
|
xsltGenericError(xsltGenericErrorContext,
|
|
"xsl:param : no namespace bound to prefix %s\n", prefix);
|
|
} else {
|
|
xsltRegisterVariable(ctxt, ncname, ns->href, select, tree, 1);
|
|
}
|
|
xmlFree(prefix);
|
|
} else {
|
|
xsltRegisterVariable(ctxt, ncname, NULL, select, tree, 1);
|
|
}
|
|
xmlFree(ncname);
|
|
} else {
|
|
xsltRegisterVariable(ctxt, name, NULL, select, tree, 1);
|
|
}
|
|
|
|
xmlFree(name);
|
|
if (select != NULL)
|
|
xmlFree(select);
|
|
|
|
}
|
|
|
|
/**
|
|
* xsltParseGlobalVariable:
|
|
* @style: the XSLT stylesheet
|
|
* @cur: the "variable" element
|
|
*
|
|
* parse an XSLT transformation variable declaration and record
|
|
* its value.
|
|
*/
|
|
|
|
void
|
|
xsltParseGlobalVariable(xsltStylesheetPtr style, xmlNodePtr cur) {
|
|
xmlChar *name, *ncname, *prefix;
|
|
xmlChar *select;
|
|
xmlNodePtr tree = NULL;
|
|
|
|
if ((cur == NULL) || (style == NULL))
|
|
return;
|
|
|
|
name = xmlGetNsProp(cur, (const xmlChar *)"name", XSLT_NAMESPACE);
|
|
if (name == NULL) {
|
|
xsltGenericError(xsltGenericErrorContext,
|
|
"xsl:variable : missing name attribute\n");
|
|
return;
|
|
}
|
|
|
|
#ifdef DEBUG_VARIABLE
|
|
xsltGenericDebug(xsltGenericDebugContext,
|
|
"Parsing global variable %s\n", name);
|
|
#endif
|
|
|
|
select = xmlGetNsProp(cur, (const xmlChar *)"select", XSLT_NAMESPACE);
|
|
if (select == NULL) {
|
|
tree = cur->children;
|
|
} else {
|
|
if (cur->children != NULL)
|
|
xsltGenericError(xsltGenericErrorContext,
|
|
"xsl:variable : content shuld be empty since select is present \n");
|
|
}
|
|
|
|
ncname = xmlSplitQName2(name, &prefix);
|
|
|
|
if (ncname != NULL) {
|
|
if (prefix != NULL) {
|
|
xmlNsPtr ns;
|
|
|
|
ns = xmlSearchNs(cur->doc, cur, prefix);
|
|
if (ns == NULL) {
|
|
xsltGenericError(xsltGenericErrorContext,
|
|
"xsl:variable : no namespace bound to prefix %s\n", prefix);
|
|
} else {
|
|
xsltRegisterGlobalVariable(style, ncname, ns->href, select, tree, 0);
|
|
}
|
|
xmlFree(prefix);
|
|
} else {
|
|
xsltRegisterGlobalVariable(style, ncname, NULL, select, tree, 0);
|
|
}
|
|
xmlFree(ncname);
|
|
} else {
|
|
xsltRegisterGlobalVariable(style, name, NULL, select, tree, 0);
|
|
}
|
|
|
|
xmlFree(name);
|
|
if (select != NULL)
|
|
xmlFree(select);
|
|
|
|
}
|
|
|
|
/**
|
|
* xsltParseGlobalParam:
|
|
* @style: the XSLT stylesheet
|
|
* @cur: the "param" element
|
|
*
|
|
* parse an XSLT transformation param declaration and record
|
|
* its value.
|
|
*/
|
|
|
|
void
|
|
xsltParseGlobalParam(xsltStylesheetPtr style, xmlNodePtr cur) {
|
|
xmlChar *name, *ncname, *prefix;
|
|
xmlChar *select;
|
|
xmlNodePtr tree = NULL;
|
|
|
|
if ((cur == NULL) || (style == NULL))
|
|
return;
|
|
|
|
name = xmlGetNsProp(cur, (const xmlChar *)"name", XSLT_NAMESPACE);
|
|
if (name == NULL) {
|
|
xsltGenericError(xsltGenericErrorContext,
|
|
"xsl:param : missing name attribute\n");
|
|
return;
|
|
}
|
|
|
|
#ifdef DEBUG_VARIABLE
|
|
xsltGenericDebug(xsltGenericDebugContext,
|
|
"Parsing global param %s\n", name);
|
|
#endif
|
|
|
|
select = xmlGetNsProp(cur, (const xmlChar *)"select", XSLT_NAMESPACE);
|
|
if (select == NULL) {
|
|
tree = cur->children;
|
|
} else {
|
|
if (cur->children != NULL)
|
|
xsltGenericError(xsltGenericErrorContext,
|
|
"xsl:param : content shuld be empty since select is present \n");
|
|
}
|
|
|
|
ncname = xmlSplitQName2(name, &prefix);
|
|
|
|
if (ncname != NULL) {
|
|
if (prefix != NULL) {
|
|
xmlNsPtr ns;
|
|
|
|
ns = xmlSearchNs(cur->doc, cur, prefix);
|
|
if (ns == NULL) {
|
|
xsltGenericError(xsltGenericErrorContext,
|
|
"xsl:param : no namespace bound to prefix %s\n", prefix);
|
|
} else {
|
|
xsltRegisterGlobalVariable(style, ncname, ns->href, select, tree, 1);
|
|
}
|
|
xmlFree(prefix);
|
|
} else {
|
|
xsltRegisterGlobalVariable(style, ncname, NULL, select, tree, 1);
|
|
}
|
|
xmlFree(ncname);
|
|
} else {
|
|
xsltRegisterGlobalVariable(style, name, NULL, select, tree, 1);
|
|
}
|
|
|
|
xmlFree(name);
|
|
if (select != NULL)
|
|
xmlFree(select);
|
|
}
|
|
|
|
/**
|
|
* xsltParseStylesheetVariable:
|
|
* @ctxt: the XSLT transformation context
|
|
* @cur: the "variable" element
|
|
*
|
|
* parse an XSLT transformation variable declaration and record
|
|
* its value.
|
|
*/
|
|
|
|
void
|
|
xsltParseStylesheetVariable(xsltTransformContextPtr ctxt, xmlNodePtr cur) {
|
|
xmlChar *name, *ncname, *prefix;
|
|
xmlChar *select;
|
|
xmlNodePtr tree = NULL;
|
|
|
|
if ((cur == NULL) || (ctxt == NULL))
|
|
return;
|
|
|
|
name = xmlGetNsProp(cur, (const xmlChar *)"name", XSLT_NAMESPACE);
|
|
if (name == NULL) {
|
|
xsltGenericError(xsltGenericErrorContext,
|
|
"xsl:variable : missing name attribute\n");
|
|
return;
|
|
}
|
|
|
|
#ifdef DEBUG_VARIABLE
|
|
xsltGenericDebug(xsltGenericDebugContext,
|
|
"Parsing variable %s\n", name);
|
|
#endif
|
|
|
|
select = xmlGetNsProp(cur, (const xmlChar *)"select", XSLT_NAMESPACE);
|
|
if (select == NULL) {
|
|
tree = cur->children;
|
|
} else {
|
|
if (cur->children != NULL)
|
|
xsltGenericError(xsltGenericErrorContext,
|
|
"xsl:variable : content shuld be empty since select is present \n");
|
|
}
|
|
|
|
ncname = xmlSplitQName2(name, &prefix);
|
|
|
|
if (ncname != NULL) {
|
|
if (prefix != NULL) {
|
|
xmlNsPtr ns;
|
|
|
|
ns = xmlSearchNs(cur->doc, cur, prefix);
|
|
if (ns == NULL) {
|
|
xsltGenericError(xsltGenericErrorContext,
|
|
"xsl:variable : no namespace bound to prefix %s\n", prefix);
|
|
} else {
|
|
xsltRegisterVariable(ctxt, ncname, ns->href, select, tree, 0);
|
|
}
|
|
xmlFree(prefix);
|
|
} else {
|
|
xsltRegisterVariable(ctxt, ncname, NULL, select, tree, 0);
|
|
}
|
|
xmlFree(ncname);
|
|
} else {
|
|
xsltRegisterVariable(ctxt, name, NULL, select, tree, 0);
|
|
}
|
|
|
|
xmlFree(name);
|
|
if (select != NULL)
|
|
xmlFree(select);
|
|
|
|
}
|
|
|
|
/**
|
|
* xsltVariableLookup:
|
|
* @ctxt: a void * but the the XSLT transformation context actually
|
|
* @name: the variable name
|
|
* @ns_uri: the variable namespace URI
|
|
*
|
|
* This is the entry point when a varibale is needed by the XPath
|
|
* interpretor.
|
|
*
|
|
* Returns the value or NULL if not found
|
|
*/
|
|
xmlXPathObjectPtr
|
|
xsltXPathVariableLookup(void *ctxt, const xmlChar *name,
|
|
const xmlChar *ns_uri) {
|
|
xsltTransformContextPtr context;
|
|
xmlXPathObjectPtr ret;
|
|
|
|
if ((ctxt == NULL) || (name == NULL))
|
|
return(NULL);
|
|
|
|
#ifdef DEBUG_VARIABLE
|
|
xsltGenericDebug(xsltGenericDebugContext,
|
|
"Lookup variable %s\n", name);
|
|
#endif
|
|
context = (xsltTransformContextPtr) ctxt;
|
|
ret = xsltVariableLookup(context, name, ns_uri);
|
|
if (ret == NULL) {
|
|
xsltGenericError(xsltGenericErrorContext,
|
|
"unregistered variable %s\n", name);
|
|
}
|
|
#ifdef DEBUG_VARIABLE
|
|
if (ret != NULL)
|
|
xsltGenericDebug(xsltGenericDebugContext,
|
|
"found variable %s\n", name);
|
|
#endif
|
|
return(ret);
|
|
}
|
|
|