1
0
mirror of https://gitlab.gnome.org/GNOME/libxslt synced 2025-11-08 11:02:18 +03:00

Working on variables implementation:

- libxslt/transform.c libxslt/variables.[ch] libxslt/xslt.c
  libxslt/xsltInternals.h libxslt/xsltutils.h: changed a few
  structure to add an execution stack with variables. Tree
  valued variables still missing.
- TODO: updated
Daniel
This commit is contained in:
Daniel Veillard
2001-01-20 17:02:16 +00:00
parent 327c8bdab6
commit 6b5e9df67f
8 changed files with 504 additions and 63 deletions

View File

@@ -1,3 +1,11 @@
Sat Jan 20 17:59:20 CET 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
* libxslt/transform.c libxslt/variables.[ch] libxslt/xslt.c
libxslt/xsltInternals.h libxslt/xsltutils.h: changed a few
structure to add an execution stack with variables. Tree
valued variables still missing.
* TODO: updated
Fri Jan 19 13:16:57 CET 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
* libxslt/xslt.c: check version on stylesheets

1
TODO
View File

@@ -2,6 +2,7 @@ Design:
- should transforms for a given stylesheet be thread clean,
or can a stylesheet be enriched with document specific
informations and cleaned up later ?
=> currently stylesheet manipulation is not reentrant.
- seems that saving back XSLT stylesheet from a compiled form might
be a bit ugly ...

View File

@@ -29,6 +29,7 @@
#include "xsltutils.h"
#include "pattern.h"
#include "transform.h"
#include "variables.h"
#define DEBUG_PROCESS
@@ -39,31 +40,6 @@
#define IS_BLANK_NODE(n) \
(((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))
/*
* Types are private:
*/
typedef enum xsltOutputType {
XSLT_OUTPUT_XML = 0,
XSLT_OUTPUT_HTML,
XSLT_OUTPUT_TEXT
} xsltOutputType;
typedef struct _xsltTransformContext xsltTransformContext;
typedef xsltTransformContext *xsltTransformContextPtr;
struct _xsltTransformContext {
xsltStylesheetPtr style; /* the stylesheet used */
xsltOutputType type; /* the type of output */
xmlDocPtr doc; /* the current doc */
xmlNodePtr node; /* the current node */
xmlNodeSetPtr nodeList; /* the current node list */
xmlDocPtr output; /* the resulting document */
xmlNodePtr insert; /* the insertion node */
xmlXPathContextPtr xpathCtxt; /* the XPath context */
};
/************************************************************************
* *
@@ -104,6 +80,7 @@ xsltFreeTransformContext(xsltTransformContextPtr ctxt) {
return;
if (ctxt->xpathCtxt != NULL)
xmlXPathFreeContext(ctxt->xpathCtxt);
xsltFreeVariableHashes(ctxt);
memset(ctxt, -1, sizeof(xsltTransformContext));
xmlFree(ctxt);
}
@@ -330,7 +307,7 @@ xsltAttribute(xsltTransformContextPtr ctxt, xmlNodePtr node,
/* TODO: attribute value template */
if (ns) {
#if LIBXML_VERSION > 20211
attr = xmlSetNsProp(ctxt->insert, ncname, ns->href, value);
attr = xmlSetNsProp(ctxt->insert, ns, ncname, value);
#else
xsltGenericError(xsltGenericErrorContext,
"xsl:attribute: recompile against newer libxml version\n");
@@ -403,6 +380,7 @@ xsltValueOf(xsltTransformContextPtr ctxt, xmlNodePtr node,
ctxt->xpathCtxt = xmlXPathNewContext(ctxt->doc);
if (ctxt->xpathCtxt == NULL)
goto error;
XSLT_REGISTER_VARIABLE_LOOKUP(ctxt);
}
xpathParserCtxt =
xmlXPathNewParserContext(prop, ctxt->xpathCtxt);
@@ -643,6 +621,7 @@ xsltApplyTemplates(xsltTransformContextPtr ctxt, xmlNodePtr node,
ctxt->xpathCtxt = xmlXPathNewContext(ctxt->doc);
if (ctxt->xpathCtxt == NULL)
goto error;
XSLT_REGISTER_VARIABLE_LOOKUP(ctxt);
}
xpathParserCtxt =
xmlXPathNewParserContext(prop, ctxt->xpathCtxt);
@@ -775,6 +754,7 @@ xsltApplyOneTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node,
xmlNodePtr list) {
xmlNodePtr cur, insert, copy;
xmlNodePtr oldInsert;
int has_variables = 0;
oldInsert = insert = ctxt->insert;
/*
@@ -818,6 +798,11 @@ xsltApplyOneTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node,
ctxt->insert = insert;
xsltAttribute(ctxt, node, cur);
ctxt->insert = oldInsert;
} else if (IS_XSLT_NAME(cur, "variable")) {
if (has_variables == 0) {
xsltPushStack(ctxt);
}
xsltParseStylesheetVariable(ctxt, cur);
} else {
#ifdef DEBUG_PROCESS
xsltGenericError(xsltGenericDebugContext,
@@ -889,6 +874,9 @@ skip_children:
}
} while (cur != NULL);
}
if (has_variables != 0) {
xsltPopStack(ctxt);
}
}
/**
@@ -926,6 +914,7 @@ xsltIf(xsltTransformContextPtr ctxt, xmlNodePtr node,
ctxt->xpathCtxt = xmlXPathNewContext(ctxt->doc);
if (ctxt->xpathCtxt == NULL)
goto error;
XSLT_REGISTER_VARIABLE_LOOKUP(ctxt);
}
xpathParserCtxt = xmlXPathNewParserContext(prop, ctxt->xpathCtxt);
if (xpathParserCtxt == NULL)
@@ -1008,6 +997,7 @@ xsltForEach(xsltTransformContextPtr ctxt, xmlNodePtr node,
ctxt->xpathCtxt = xmlXPathNewContext(ctxt->doc);
if (ctxt->xpathCtxt == NULL)
goto error;
XSLT_REGISTER_VARIABLE_LOOKUP(ctxt);
}
xpathParserCtxt = xmlXPathNewParserContext(prop, ctxt->xpathCtxt);
if (xpathParserCtxt == NULL)

View File

@@ -32,6 +32,238 @@
*/
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 elem; /* 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 */
xmlXPathObjectPtr value; /* The value if computed */
xmlChar *select; /* the eval string */
};
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;
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 */
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) {
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)) {
if (nameURI == NULL) {
if (cur->nameURI == NULL)
return(cur);
} else {
if ((cur->nameURI != NULL) &&
(xmlStrEqual(cur->nameURI, nameURI)))
return(cur);
}
}
cur = cur->next;
}
}
return(NULL);
}
/************************************************************************
* *
* Module interfaces *
@@ -40,10 +272,11 @@
/**
* xsltRegisterVariable:
* @style: the XSLT stylesheet
* @ctxt: the XSLT transformation context
* @name: the variable name
* @ns_uri: the variable namespace URI
* @value: the variable value or NULL
* @select: the expression which need to be evaluated to generate a value
* @value: the variable value if select is NULL
*
* Register a new variable value. If @value is NULL it unregisters
* the variable
@@ -51,26 +284,63 @@
* Returns 0 in case of success, -1 in case of error
*/
int
xsltRegisterVariable(xsltStylesheetPtr style, const xmlChar *name,
const xmlChar *ns_uri, xmlXPathObjectPtr value) {
if (style == NULL)
xsltRegisterVariable(xsltTransformContextPtr ctxt, const xmlChar *name,
const xmlChar *ns_uri, const xmlChar *select,
xmlXPathObjectPtr value) {
xsltStackElemPtr elem;
if (ctxt == NULL)
return(-1);
if (name == NULL)
return(-1);
if (style->variablesHash == NULL)
style->variablesHash = xmlHashCreate(0);
if (style->variablesHash == NULL)
elem = xsltNewStackElem();
if (elem == NULL)
return(-1);
return(xmlHashUpdateEntry2((xmlHashTablePtr) style->variablesHash,
name, ns_uri,
(void *) value,
(xmlHashDeallocator) xmlXPathFreeObject));
elem->name = xmlStrdup(name);
elem->select = xmlStrdup(select);
if (ns_uri)
elem->nameURI = xmlStrdup(ns_uri);
elem->value = value;
xsltAddStackElem(ctxt, elem);
if (elem->select != NULL) {
xmlXPathObjectPtr result, tmp;
xmlXPathParserContextPtr xpathParserCtxt;
xpathParserCtxt = xmlXPathNewParserContext(elem->select,
ctxt->xpathCtxt);
if (xpathParserCtxt == NULL)
goto error;
xmlXPathEvalExpr(xpathParserCtxt);
result = valuePop(xpathParserCtxt);
do {
tmp = valuePop(xpathParserCtxt);
if (tmp != NULL) {
xmlXPathFreeObject(tmp);
}
} while (tmp != NULL);
if (result == NULL) {
#ifdef DEBUG_PROCESS
xsltGenericDebug(xsltGenericDebugContext,
"Evaluating variable %s failed\n");
#endif
}
if (xpathParserCtxt != NULL)
xmlXPathFreeParserContext(xpathParserCtxt);
if (result != NULL) {
if (elem->value != NULL)
xmlXPathFreeObject(elem->value);
elem->value = result;
elem->computed = 1;
}
}
error:
return(0);
}
/**
* xsltVariableLookup:
* @style: the XSLT stylesheet
* @ctxt: the XSLT transformation context
* @name: the variable name
* @ns_uri: the variable namespace URI
*
@@ -80,32 +350,162 @@ xsltRegisterVariable(xsltStylesheetPtr style, const xmlChar *name,
* Returns the value or NULL if not found
*/
xmlXPathObjectPtr
xsltVariableLookup(xsltStylesheetPtr style, const xmlChar *name,
xsltVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
const xmlChar *ns_uri) {
if (style == NULL)
xsltStackElemPtr elem;
if (ctxt == NULL)
return(NULL);
if (style->variablesHash == NULL)
elem = xsltStackLookup(ctxt, name, ns_uri);
if (elem == NULL) {
TODO /* searching on other ctxtsheets ? */
return(NULL);
if (name == NULL)
return(NULL);
return((xmlXPathObjectPtr)
xmlHashLookup2((xmlHashTablePtr) style->variablesHash,
name, ns_uri));
}
if (!elem->computed) {
#ifdef DEBUG_VARIABLE
xsltGenericDebug(xsltGenericDebugContext,
"uncomputed variable %s\n", name);
#endif
TODO /* Variable value computation needed */
}
error:
if (elem->value != NULL)
return(xmlXPathObjectCopy(elem->value));
return(NULL);
}
/**
* xsltFreeVariableHashes:
* @style: an XSLT stylesheet
* @ctxt: an XSLT transformation context
*
* Free up the memory used by xsltAddVariable/xsltGetVariable mechanism
*/
void
xsltFreeVariableHashes(xsltStylesheetPtr style) {
if (style->variablesHash != NULL)
xmlHashFree((xmlHashTablePtr) style->variablesHash,
(xmlHashDeallocator) xmlXPathFreeObject);
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);
}
/**
* xsltParseStylesheetVariable:
* @ctxt: the XSLT transformation context
* @template: the "variable" name
*
* parse an XSLT transformation context variable name and record
* its value.
*/
void
xsltParseStylesheetVariable(xsltTransformContextPtr ctxt, xmlNodePtr cur) {
xmlChar *name, *ncname, *prefix;
xmlChar *select;
xmlXPathObjectPtr value = 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
if (ret != NULL)
xsltGenericDebug(xsltGenericDebugContext,
"Parsing variable %s\n", name);
#endif
select = xmlGetNsProp(cur, (const xmlChar *)"select", XSLT_NAMESPACE);
if (select == NULL) {
if (cur->children == NULL)
value = xmlXPathNewCString("");
else
value = xmlXPathNewNodeSet(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, value);
}
xmlFree(prefix);
} else {
xsltRegisterVariable(ctxt, ncname, NULL, select, value);
}
xmlFree(ncname);
} else {
xsltRegisterVariable(ctxt, name, NULL, select, value);
}
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);
}

View File

@@ -10,20 +10,37 @@
#define __XML_XSLT_VARIABLES_H__
#include <libxml/xpath.h>
#include <libxml/xpathInternals.h>
#include "xsltInternals.h"
#ifdef __cplusplus
extern "C" {
#endif
void xsltFreeVariableHashes (xsltStylesheetPtr style);
xmlXPathObjectPtr xsltVariableLookup (xsltStylesheetPtr style,
#define XSLT_REGISTER_VARIABLE_LOOKUP(ctxt) \
xmlXPathRegisterVariableLookup((ctxt)->xpathCtxt, \
xsltXPathVariableLookup, (void *)(ctxt))
/*
* Interfaces for the variable module.
*/
void xsltPushStack (xsltTransformContextPtr ctxt);
void xsltPopStack (xsltTransformContextPtr ctxt);
void xsltParseStylesheetVariable (xsltTransformContextPtr ctxt,
xmlNodePtr cur);
void xsltFreeVariableHashes (xsltTransformContextPtr ctxt);
xmlXPathObjectPtr xsltVariableLookup (xsltTransformContextPtr ctxt,
const xmlChar *name,
const xmlChar *ns_uri);
int xsltRegisterVariable (xsltStylesheetPtr style,
int xsltRegisterVariable (xsltTransformContextPtr ctxt,
const xmlChar *name,
const xmlChar *ns_uri,
const xmlChar *select,
xmlXPathObjectPtr value);
xmlXPathObjectPtr xsltXPathVariableLookup (void *ctxt,
const xmlChar *name,
const xmlChar *ns_uri);
#ifdef __cplusplus
}
#endif

View File

@@ -162,7 +162,6 @@ xsltFreeStylesheet(xsltStylesheetPtr sheet) {
return;
xsltFreeTemplateHashes(sheet);
xsltFreeVariableHashes(sheet);
xsltFreeTemplateList(sheet->templates);
if (sheet->doc != NULL)
xmlFreeDoc(sheet->doc);

View File

@@ -12,6 +12,7 @@
#include <libxml/tree.h>
#include <libxml/hash.h>
#include <libxml/xpath.h>
#include <libxslt/xslt.h>
#ifdef __cplusplus
@@ -64,12 +65,6 @@ struct _xsltStylesheet {
xsltTemplatePtr templates; /* the ordered list of templates */
void *templatesHash; /* hash table or wherever compiled templates
informations are stored */
/*
* Variable descriptions
*/
void *variablesHash; /* hash table or wherever variables
informations are stored */
/*
* Output related stuff.
*/
@@ -86,6 +81,33 @@ struct _xsltStylesheet {
};
/*
* The in-memory structure corresponding to an XSLT Transformation
*/
typedef enum xsltOutputType {
XSLT_OUTPUT_XML = 0,
XSLT_OUTPUT_HTML,
XSLT_OUTPUT_TEXT
} xsltOutputType;
typedef struct _xsltTransformContext xsltTransformContext;
typedef xsltTransformContext *xsltTransformContextPtr;
struct _xsltTransformContext {
xsltStylesheetPtr style; /* the stylesheet used */
xsltOutputType type; /* the type of output */
xmlDocPtr doc; /* the current doc */
xmlNodePtr node; /* the current node */
xmlNodeSetPtr nodeList; /* the current node list */
xmlDocPtr output; /* the resulting document */
xmlNodePtr insert; /* the insertion node */
xmlXPathContextPtr xpathCtxt; /* the XPath context */
void *variablesHash; /* hash table or wherever variables
informations are stored */
};
/*
* Functions associated to the internal types
*/

View File

@@ -24,6 +24,10 @@ xmlChar *xmlSplitQName2(const xmlChar *name, xmlChar **prefix);
void xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs);
xmlAttrPtr xmlSetNsProp (xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
const xmlChar *value);
/*********
void xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
xmlXPathVariableLookupFunc f, void *data)
*********/
/*
* Useful macros