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

Furious hacking session, making serious progresses, the hardest stuff

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
This commit is contained in:
Daniel Veillard
2001-01-22 10:52:35 +00:00
parent 935ed1d25f
commit b94fc73a64
12 changed files with 676 additions and 94 deletions

View File

@@ -1,3 +1,14 @@
Mon Jan 22 11:46:44 CET 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
* 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 :-)
Sun Jan 21 12:03:16 CET 2001 Daniel Veillard <Daniel.Veillard@imag.fr> Sun Jan 21 12:03:16 CET 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
* Makefile.am tests/Makefile.am tests/REC1/Makefile.am * Makefile.am tests/Makefile.am tests/REC1/Makefile.am

35
TODO
View File

@@ -1,3 +1,8 @@
********
* *
* TODO *
* *
********
Design: Design:
- should transforms for a given stylesheet be thread clean, - should transforms for a given stylesheet be thread clean,
or can a stylesheet be enriched with document specific or can a stylesheet be enriched with document specific
@@ -18,15 +23,6 @@ Pattern scanner:
-> handle unions -> handle unions
-> compute priority -> compute priority
Separate util module:
-> macros, config, verbosity ?
Support for disable-output-escaping="yes":
-> looks problematic, libxml has no support for anything like this,
and unless adding a new node type :-( or tweaking text node and
output routines this is gonna be messy ... must be handled at libxml
level.
Error handling: Error handling:
-> check the version stuff, design a separate module for error interfacing -> check the version stuff, design a separate module for error interfacing
and default handling, parsing vs. runtime, fatal / compat / warning, and default handling, parsing vs. runtime, fatal / compat / warning,
@@ -35,6 +31,8 @@ Error handling:
Support Attribute value templates: Support Attribute value templates:
-> starts to be urgent. Design it in flexible ways but try to optimize -> starts to be urgent. Design it in flexible ways but try to optimize
to handle most of it at the stylesheet parse time ... to handle most of it at the stylesheet parse time ...
=> Done for the most part need to check all attributes in XSLT constructs
using them and use the dedicated readin function.
Sorting: Sorting:
-> add support for imbricated sorts -> add support for imbricated sorts
@@ -45,4 +43,23 @@ Validity:
-> should we add validation by default ? Make this an option -> should we add validation by default ? Make this an option
-> redirrect validity errors -> redirrect validity errors
Contextual error reporting:
-> provide a couple of functions providing context analysis, not urgent
********
* *
* DONE *
* *
********
Separate util module:
-> macros, config, verbosity ?
=> xsltutils.[ch]
Support for disable-output-escaping="yes":
-> looks problematic, libxml has no support for anything like this,
and unless adding a new node type :-( or tweaking text node and
output routines this is gonna be messy ... must be handled at libxml
level.
=> Done with a trick, text node name is different, requires > 2.2.11

View File

@@ -974,12 +974,33 @@ int
xsltAddTemplate(xsltStylesheetPtr style, xsltTemplatePtr cur) { xsltAddTemplate(xsltStylesheetPtr style, xsltTemplatePtr cur) {
xsltCompMatchPtr pat, list; xsltCompMatchPtr pat, list;
const xmlChar *name; const xmlChar *name;
xmlChar *p, *pattern, tmp;
if ((style == NULL) || (cur == NULL))
return(-1);
p = cur->match;
if (p == NULL)
return(-1);
next_pattern:
if (*p == 0)
return(0);
/* /*
* get a compiled form of the pattern * get a compiled form of the pattern
*/ */
/* TODO : handle | in patterns as multple pat !!! */ pattern = p;
pat = xsltCompilePattern(cur->match); while ((*p != 0) && (*p != '|')) {
/* TODO: handle string escaping "a | b" in patterns ... */
p++;
}
tmp = *p;
*p = 0;
pat = xsltCompilePattern(pattern);
*p = tmp;
if (tmp != 0)
p++;
if (pat == NULL) if (pat == NULL)
return(-1); return(-1);
pat->template = cur; pat->template = cur;
@@ -1080,6 +1101,8 @@ xsltAddTemplate(xsltStylesheetPtr style, xsltTemplatePtr cur) {
} }
} }
} }
if (*p != 0)
goto next_pattern;
return(0); return(0);
} }
@@ -1174,3 +1197,36 @@ xsltFreeTemplateHashes(xsltStylesheetPtr style) {
(xmlHashDeallocator) xsltFreeCompMatchList); (xmlHashDeallocator) xsltFreeCompMatchList);
} }
/**
* xsltFindTemplate:
* @style: an XSLT stylesheet
* @name: the template name
* @nameURI: the template name URI
*
* Finds the named template.
*
* Returns the xsltTemplatePtr or NULL if not found
*/
xsltTemplatePtr
xsltFindTemplate(xsltStylesheetPtr style, const xmlChar *name,
const xmlChar *nameURI) {
xsltTemplatePtr cur;
if ((style == NULL) || (name == NULL))
return(NULL);
/* TODO: apply stylesheet import order */
cur = style->templates;
while (cur != NULL) {
if (xmlStrEqual(name, cur->name)) {
if (((nameURI == NULL) && (cur->nameURI == NULL)) ||
((nameURI != NULL) && (cur->nameURI != NULL) &&
(xmlStrEqual(nameURI, cur->nameURI)))) {
return(cur);
}
}
cur = cur->next;
}
return(NULL);
}

View File

@@ -20,6 +20,9 @@ int xsltAddTemplate (xsltStylesheetPtr style,
xsltTemplatePtr xsltGetTemplate (xsltStylesheetPtr style, xsltTemplatePtr xsltGetTemplate (xsltStylesheetPtr style,
xmlNodePtr node); xmlNodePtr node);
void xsltFreeTemplateHashes (xsltStylesheetPtr style); void xsltFreeTemplateHashes (xsltStylesheetPtr style);
xsltTemplatePtr xsltFindTemplate (xsltStylesheetPtr style,
const xmlChar *name,
const xmlChar *nameURI);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -295,7 +295,7 @@ xsltAttribute(xsltTransformContextPtr ctxt, xmlNodePtr node,
if (value == NULL) { if (value == NULL) {
if (ns) { if (ns) {
#if LIBXML_VERSION > 20211 #if LIBXML_VERSION > 20211
attr = xmlSetNsProp(ctxt->insert, ncname, ns->href, attr = xmlSetNsProp(ctxt->insert, ns, ncname,
(const xmlChar *)""); (const xmlChar *)"");
#else #else
xsltGenericError(xsltGenericErrorContext, xsltGenericError(xsltGenericErrorContext,
@@ -585,6 +585,89 @@ xsltDefaultProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node) {
} }
} }
/**
* xsltCallTemplate:
* @ctxt: a XSLT process context
* @node: the node in the source tree.
* @inst: the xslt call-template node
*
* Process the xslt call-template node on the source node
*/
void
xsltCallTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node,
xmlNodePtr inst) {
xmlChar *prop = NULL;
xmlChar *ncname = NULL;
xmlChar *prefix = NULL;
xmlNsPtr ns = NULL;
xsltTemplatePtr template;
xmlNodePtr cur;
int has_param = 0;
if (ctxt->insert == NULL)
return;
prop = xmlGetNsProp(inst, (const xmlChar *)"name", XSLT_NAMESPACE);
if (prop == NULL) {
xsltGenericError(xsltGenericErrorContext,
"xslt:call-template : name is missing\n");
goto error;
}
ncname = xmlSplitQName2(prop, &prefix);
if (ncname == NULL) {
ncname = prop;
prop = NULL;
prefix = NULL;
}
if ((prefix != NULL) && (ns == NULL)) {
ns = xmlSearchNs(ctxt->insert->doc, ctxt->insert, prefix);
if (ns == NULL) {
xsltGenericError(xsltGenericErrorContext,
"no namespace bound to prefix %s\n", prefix);
}
}
if (ns != NULL)
template = xsltFindTemplate(ctxt->style, ncname, ns->href);
else
template = xsltFindTemplate(ctxt->style, ncname, NULL);
if (template == NULL) {
xsltGenericError(xsltGenericDebugContext,
"xslt:call-template: template %s not found\n", cur->name);
goto error;
}
cur = inst->children;
while (cur != NULL) {
if (IS_XSLT_ELEM(cur)) {
if (IS_XSLT_NAME(cur, "with-param")) {
if (has_param == 0) {
xsltPushStack(ctxt);
has_param = 1;
}
xsltParseStylesheetParam(ctxt, cur);
} else {
xsltGenericError(xsltGenericDebugContext,
"xslt:call-template: misplaced xslt:%s\n", cur->name);
}
} else {
xsltGenericError(xsltGenericDebugContext,
"xslt:call-template: misplaced %s element\n", cur->name);
}
cur = cur->next;
}
xsltApplyOneTemplate(ctxt, node, template->content);
error:
if (has_param == 1)
xsltPopStack(ctxt);
if (prop != NULL)
xmlFree(prop);
if (ncname != NULL)
xmlFree(ncname);
if (prefix != NULL)
xmlFree(prefix);
}
/** /**
* xsltApplyTemplates: * xsltApplyTemplates:
* @ctxt: a XSLT process context * @ctxt: a XSLT process context
@@ -803,8 +886,21 @@ xsltApplyOneTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node,
} else if (IS_XSLT_NAME(cur, "variable")) { } else if (IS_XSLT_NAME(cur, "variable")) {
if (has_variables == 0) { if (has_variables == 0) {
xsltPushStack(ctxt); xsltPushStack(ctxt);
has_variables = 1;
} }
xsltParseStylesheetVariable(ctxt, cur); xsltParseStylesheetVariable(ctxt, cur);
} else if (IS_XSLT_NAME(cur, "param")) {
if (has_variables == 0) {
xsltPushStack(ctxt);
has_variables = 1;
}
xsltParseStylesheetParam(ctxt, cur);
} else if (IS_XSLT_NAME(cur, "call-template")) {
if (has_variables == 0) {
xsltPushStack(ctxt);
has_variables = 1;
}
xsltCallTemplate(ctxt, node, cur);
} else { } else {
#ifdef DEBUG_PROCESS #ifdef DEBUG_PROCESS
xsltGenericError(xsltGenericDebugContext, xsltGenericError(xsltGenericDebugContext,
@@ -1120,6 +1216,7 @@ xsltApplyStylesheet(xsltStylesheetPtr style, xmlDocPtr doc) {
return(NULL); return(NULL);
ctxt->doc = doc; ctxt->doc = doc;
ctxt->style = style; ctxt->style = style;
xsltEvalGlobalVariables(ctxt);
if ((style->method != NULL) && if ((style->method != NULL) &&
(!xmlStrEqual(style->method, (const xmlChar *) "xml"))) { (!xmlStrEqual(style->method, (const xmlChar *) "xml"))) {
if (xmlStrEqual(style->method, (const xmlChar *) "html")) { if (xmlStrEqual(style->method, (const xmlChar *) "html")) {

View File

@@ -21,7 +21,9 @@ extern "C" {
*/ */
xmlDocPtr xsltApplyStylesheet (xsltStylesheetPtr style, xmlDocPtr xsltApplyStylesheet (xsltStylesheetPtr style,
xmlDocPtr doc); xmlDocPtr doc);
void xsltApplyOneTemplate (xsltTransformContextPtr ctxt,
xmlNodePtr node,
xmlNodePtr list);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -18,12 +18,14 @@
#include <libxml/valid.h> #include <libxml/valid.h>
#include <libxml/hash.h> #include <libxml/hash.h>
#include <libxml/xmlerror.h> #include <libxml/xmlerror.h>
#include <libxml/xpath.h>
#include <libxml/xpathInternals.h> #include <libxml/xpathInternals.h>
#include <libxml/parserInternals.h> #include <libxml/parserInternals.h>
#include "xslt.h" #include "xslt.h"
#include "xsltInternals.h" #include "xsltInternals.h"
#include "xsltutils.h" #include "xsltutils.h"
#include "variables.h" #include "variables.h"
#include "transform.h"
#define DEBUG_VARIABLE #define DEBUG_VARIABLE
@@ -31,24 +33,6 @@
* Types are private: * Types are private:
*/ */
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 struct _xsltStack xsltStack;
typedef xsltStack *xsltStackPtr; typedef xsltStack *xsltStackPtr;
struct _xsltStack { struct _xsltStack {
@@ -138,6 +122,7 @@ xsltFreeStackElemList(xsltStackElemPtr elem) {
int int
xsltAddStackElem(xsltTransformContextPtr ctxt, xsltStackElemPtr elem) { xsltAddStackElem(xsltTransformContextPtr ctxt, xsltStackElemPtr elem) {
xsltStackPtr stack; xsltStackPtr stack;
xsltStackElemPtr cur;
if ((ctxt == NULL) || (elem == NULL)) if ((ctxt == NULL) || (elem == NULL))
return(-1); return(-1);
@@ -158,6 +143,20 @@ xsltAddStackElem(xsltTransformContextPtr ctxt, xsltStackElemPtr elem) {
} }
/* TODO: check that there is no conflict with existing values /* TODO: check that there is no conflict with existing values
* at that level */ * 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]; elem->next = stack->elems[stack->cur];
stack->elems[stack->cur] = elem; stack->elems[stack->cur] = elem;
return(0); return(0);
@@ -233,6 +232,7 @@ xsltPopStack(xsltTransformContextPtr ctxt) {
xsltStackElemPtr xsltStackElemPtr
xsltStackLookup(xsltTransformContextPtr ctxt, const xmlChar *name, xsltStackLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
const xmlChar *nameURI) { const xmlChar *nameURI) {
xsltStackElemPtr ret = NULL;
xsltStackPtr stack; xsltStackPtr stack;
int i; int i;
xsltStackElemPtr cur; xsltStackElemPtr cur;
@@ -248,20 +248,29 @@ xsltStackLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
cur = stack->elems[i]; cur = stack->elems[i];
while (cur != NULL) { while (cur != NULL) {
if (xmlStrEqual(cur->name, name)) { if (xmlStrEqual(cur->name, name)) {
/* TODO: double check param binding */
if (nameURI == NULL) { if (nameURI == NULL) {
if (cur->nameURI == NULL) if (cur->nameURI == NULL) {
return(cur); if (cur->type == XSLT_ELEM_PARAM)
ret = cur;
else
return(cur);
}
} else { } else {
if ((cur->nameURI != NULL) && if ((cur->nameURI != NULL) &&
(xmlStrEqual(cur->nameURI, nameURI))) (xmlStrEqual(cur->nameURI, nameURI))) {
return(cur); if (cur->type == XSLT_ELEM_PARAM)
ret = cur;
else
return(cur);
}
} }
} }
cur = cur->next; cur = cur->next;
} }
} }
return(NULL); return(ret);
} }
/************************************************************************ /************************************************************************
@@ -270,13 +279,192 @@ xsltStackLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
* * * *
************************************************************************/ ************************************************************************/
/**
* 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: * xsltRegisterVariable:
* @ctxt: the XSLT transformation context * @ctxt: the XSLT transformation context
* @name: the variable name * @name: the variable name
* @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
* @value: the variable value if select is NULL * @tree: the tree if select is NULL
* @param: this is a parameter actually
* *
* Register a new variable value. If @value is NULL it unregisters * Register a new variable value. If @value is NULL it unregisters
* the variable * the variable
@@ -286,7 +474,7 @@ xsltStackLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
int int
xsltRegisterVariable(xsltTransformContextPtr ctxt, const xmlChar *name, xsltRegisterVariable(xsltTransformContextPtr ctxt, const xmlChar *name,
const xmlChar *ns_uri, const xmlChar *select, const xmlChar *ns_uri, const xmlChar *select,
xmlXPathObjectPtr value) { xmlNodePtr tree, int param) {
xsltStackElemPtr elem; xsltStackElemPtr elem;
if (ctxt == NULL) if (ctxt == NULL)
return(-1); return(-1);
@@ -300,46 +488,17 @@ xsltRegisterVariable(xsltTransformContextPtr ctxt, const xmlChar *name,
elem = xsltNewStackElem(); elem = xsltNewStackElem();
if (elem == NULL) if (elem == NULL)
return(-1); return(-1);
if (param)
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->value = value; elem->tree = tree;
xsltAddStackElem(ctxt, elem); xsltAddStackElem(ctxt, elem);
if (elem->select != NULL) { xsltEvalVariables(ctxt, elem);
xmlXPathObjectPtr result, tmp;
xmlXPathParserContextPtr xpathParserCtxt;
xpathParserCtxt = xmlXPathNewParserContext(elem->select,
ctxt->xpathCtxt);
if (xpathParserCtxt == NULL)
goto error;
ctxt->xpathCtxt->node = ctxt->node;
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); return(0);
} }
@@ -372,7 +531,7 @@ xsltVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
xsltGenericDebug(xsltGenericDebugContext, xsltGenericDebug(xsltGenericDebugContext,
"uncomputed variable %s\n", name); "uncomputed variable %s\n", name);
#endif #endif
TODO /* Variable value computation needed */ xsltEvalVariables(ctxt, elem);
} }
if (elem->value != NULL) if (elem->value != NULL)
return(xmlXPathObjectCopy(elem->value)); return(xmlXPathObjectCopy(elem->value));
@@ -408,12 +567,212 @@ xsltFreeVariableHashes(xsltTransformContextPtr ctxt) {
xmlFree(stack); 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: * xsltParseStylesheetVariable:
* @ctxt: the XSLT transformation context * @ctxt: the XSLT transformation context
* @template: the "variable" name * @cur: the "variable" element
* *
* parse an XSLT transformation context variable name and record * parse an XSLT transformation variable declaration and record
* its value. * its value.
*/ */
@@ -421,7 +780,7 @@ void
xsltParseStylesheetVariable(xsltTransformContextPtr ctxt, xmlNodePtr cur) { xsltParseStylesheetVariable(xsltTransformContextPtr ctxt, xmlNodePtr cur) {
xmlChar *name, *ncname, *prefix; xmlChar *name, *ncname, *prefix;
xmlChar *select; xmlChar *select;
xmlXPathObjectPtr value = NULL; xmlNodePtr tree = NULL;
if ((cur == NULL) || (ctxt == NULL)) if ((cur == NULL) || (ctxt == NULL))
return; return;
@@ -440,10 +799,7 @@ xsltParseStylesheetVariable(xsltTransformContextPtr ctxt, xmlNodePtr cur) {
select = xmlGetNsProp(cur, (const xmlChar *)"select", XSLT_NAMESPACE); select = xmlGetNsProp(cur, (const xmlChar *)"select", XSLT_NAMESPACE);
if (select == NULL) { if (select == NULL) {
if (cur->children == NULL) tree = cur->children;
value = xmlXPathNewCString("");
else
value = xmlXPathNewNodeSet(cur->children);
} else { } else {
if (cur->children != NULL) if (cur->children != NULL)
xsltGenericError(xsltGenericErrorContext, xsltGenericError(xsltGenericErrorContext,
@@ -461,15 +817,15 @@ xsltParseStylesheetVariable(xsltTransformContextPtr ctxt, xmlNodePtr cur) {
xsltGenericError(xsltGenericErrorContext, xsltGenericError(xsltGenericErrorContext,
"xsl:variable : no namespace bound to prefix %s\n", prefix); "xsl:variable : no namespace bound to prefix %s\n", prefix);
} else { } else {
xsltRegisterVariable(ctxt, ncname, ns->href, select, value); xsltRegisterVariable(ctxt, ncname, ns->href, select, tree, 0);
} }
xmlFree(prefix); xmlFree(prefix);
} else { } else {
xsltRegisterVariable(ctxt, ncname, NULL, select, value); xsltRegisterVariable(ctxt, ncname, NULL, select, tree, 0);
} }
xmlFree(ncname); xmlFree(ncname);
} else { } else {
xsltRegisterVariable(ctxt, name, NULL, select, value); xsltRegisterVariable(ctxt, name, NULL, select, tree, 0);
} }
xmlFree(name); xmlFree(name);

View File

@@ -25,10 +25,17 @@ extern "C" {
* Interfaces for the variable module. * Interfaces for the variable module.
*/ */
int xsltEvalGlobalVariables (xsltTransformContextPtr ctxt);
void xsltPushStack (xsltTransformContextPtr ctxt); void xsltPushStack (xsltTransformContextPtr ctxt);
void xsltPopStack (xsltTransformContextPtr ctxt); void xsltPopStack (xsltTransformContextPtr ctxt);
void xsltParseGlobalVariable (xsltStylesheetPtr style,
xmlNodePtr cur);
void xsltParseGlobalParam (xsltStylesheetPtr style,
xmlNodePtr cur);
void xsltParseStylesheetVariable (xsltTransformContextPtr ctxt, void xsltParseStylesheetVariable (xsltTransformContextPtr ctxt,
xmlNodePtr cur); xmlNodePtr cur);
void xsltParseStylesheetParam (xsltTransformContextPtr ctxt,
xmlNodePtr cur);
void xsltFreeVariableHashes (xsltTransformContextPtr ctxt); void xsltFreeVariableHashes (xsltTransformContextPtr ctxt);
xmlXPathObjectPtr xsltVariableLookup (xsltTransformContextPtr ctxt, xmlXPathObjectPtr xsltVariableLookup (xsltTransformContextPtr ctxt,
const xmlChar *name, const xmlChar *name,
@@ -37,7 +44,8 @@ int xsltRegisterVariable (xsltTransformContextPtr ctxt,
const xmlChar *name, const xmlChar *name,
const xmlChar *ns_uri, const xmlChar *ns_uri,
const xmlChar *select, const xmlChar *select,
xmlXPathObjectPtr value); xmlNodePtr tree,
int param);
xmlXPathObjectPtr xsltXPathVariableLookup (void *ctxt, xmlXPathObjectPtr xsltXPathVariableLookup (void *ctxt,
const xmlChar *name, const xmlChar *name,
const xmlChar *ns_uri); const xmlChar *ns_uri);

View File

@@ -165,6 +165,8 @@ xsltFreeStylesheet(xsltStylesheetPtr sheet) {
xsltFreeTemplateList(sheet->templates); xsltFreeTemplateList(sheet->templates);
if (sheet->doc != NULL) if (sheet->doc != NULL)
xmlFreeDoc(sheet->doc); xmlFreeDoc(sheet->doc);
if (sheet->variables != NULL)
xsltFreeStackElemList(sheet->variables);
if (sheet->stripSpaces != NULL) if (sheet->stripSpaces != NULL)
xmlHashFree(sheet->stripSpaces, NULL); xmlHashFree(sheet->stripSpaces, NULL);
@@ -563,12 +565,11 @@ skip_children:
/* /*
* Find and handle the params * Find and handle the params
*/
cur = template->children; cur = template->children;
while (cur != NULL) { while (cur != NULL) {
/* / *
* Remove Blank nodes found at this level. * Remove Blank nodes found at this level.
*/ * /
if (IS_BLANK_NODE(cur)) { if (IS_BLANK_NODE(cur)) {
xmlNodePtr blank = cur; xmlNodePtr blank = cur;
@@ -578,11 +579,12 @@ skip_children:
continue; continue;
} }
if ((IS_XSLT_ELEM(cur)) && (IS_XSLT_NAME(cur, "param"))) { if ((IS_XSLT_ELEM(cur)) && (IS_XSLT_NAME(cur, "param"))) {
TODO /* Handle param */ xsltParseGlobalParam(style, cur);
} else } else
break; break;
cur = cur->next; cur = cur->next;
} }
*/
/* /*
* Browse the remaining of the template * Browse the remaining of the template

View File

@@ -19,12 +19,33 @@
extern "C" { extern "C" {
#endif #endif
/* /*
* The in-memory structure corresponding to an XSLT Stylesheet * The in-memory structure corresponding to an XSLT Variable
* NOTE: most of the content is simply linked from the doc tree * or Param
* structure, no specific allocation is made.
*/ */
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 */
xmlXPathObjectPtr value; /* The value if computed */
};
/*
* The in-memory structure corresponding to an XSLT Template
*/
#define XSLT_PAT_NO_PRIORITY -12345789 #define XSLT_PAT_NO_PRIORITY -12345789
typedef struct _xsltTemplate xsltTemplate; typedef struct _xsltTemplate xsltTemplate;
@@ -42,6 +63,8 @@ struct _xsltTemplate {
/* /*
* 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
* structure, no specific allocation is made.
*/ */
typedef struct _xsltStylesheet xsltStylesheet; typedef struct _xsltStylesheet xsltStylesheet;
typedef xsltStylesheet *xsltStylesheetPtr; typedef xsltStylesheet *xsltStylesheetPtr;
@@ -59,6 +82,11 @@ struct _xsltStylesheet {
xmlHashTablePtr stripSpaces;/* the hash table of the strip-space xmlHashTablePtr stripSpaces;/* the hash table of the strip-space
preserve space and cdata-section elements */ preserve space and cdata-section elements */
/*
* Global variable or parameters
*/
xsltStackElemPtr variables; /* linked list of param and variables */
/* /*
* Template descriptions * Template descriptions
*/ */
@@ -114,6 +142,7 @@ struct _xsltTransformContext {
xsltStylesheetPtr xsltParseStylesheetFile (const xmlChar* filename); xsltStylesheetPtr xsltParseStylesheetFile (const xmlChar* filename);
void xsltFreeStylesheet (xsltStylesheetPtr sheet); void xsltFreeStylesheet (xsltStylesheetPtr sheet);
int xsltIsBlank (xmlChar *str); int xsltIsBlank (xmlChar *str);
void xsltFreeStackElemList (xsltStackElemPtr elem);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@@ -22,7 +22,7 @@ static int repeat = 0;
int int
main(int argc, char **argv) { main(int argc, char **argv) {
int i; int i;
xsltStylesheetPtr cur; xsltStylesheetPtr cur = NULL;
xmlDocPtr doc, res; xmlDocPtr doc, res;
/* --repeat : repeat 100 times, for timing or profiling */ /* --repeat : repeat 100 times, for timing or profiling */

View File

@@ -1,4 +1,5 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"><html lang="en"> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html lang="en">
<head><title>Sales Results By Division</title></head> <head><title>Sales Results By Division</title></head>
<body><table border="1"> <body><table border="1">
<tr> <tr>