From b94fc73a6415c55bb34a3b2ae0783ed1c25ecded Mon Sep 17 00:00:00 2001 From: Daniel Veillard Date: Mon, 22 Jan 2001 10:52:35 +0000 Subject: [PATCH] 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 --- ChangeLog | 11 ++ TODO | 35 +++- libxslt/pattern.c | 60 +++++- libxslt/pattern.h | 3 + libxslt/transform.c | 99 +++++++++- libxslt/transform.h | 4 +- libxslt/variables.c | 488 +++++++++++++++++++++++++++++++++++++++++------- libxslt/variables.h | 10 +- libxslt/xslt.c | 10 +- libxslt/xsltInternals.h | 35 +++- libxslt/xsltproc.c | 2 +- tests/REC2/html.xml | 3 +- 12 files changed, 671 insertions(+), 89 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6a0fb5c..8f4f9d5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +Mon Jan 22 11:46:44 CET 2001 Daniel Veillard + + * 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 * Makefile.am tests/Makefile.am tests/REC1/Makefile.am diff --git a/TODO b/TODO index ec37cfd..57e8f36 100644 --- a/TODO +++ b/TODO @@ -1,3 +1,8 @@ + ******** + * * + * TODO * + * * + ******** Design: - should transforms for a given stylesheet be thread clean, or can a stylesheet be enriched with document specific @@ -18,15 +23,6 @@ Pattern scanner: -> handle unions -> 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: -> check the version stuff, design a separate module for error interfacing and default handling, parsing vs. runtime, fatal / compat / warning, @@ -35,6 +31,8 @@ Error handling: Support Attribute value templates: -> starts to be urgent. Design it in flexible ways but try to optimize 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: -> add support for imbricated sorts @@ -45,4 +43,23 @@ Validity: -> should we add validation by default ? Make this an option -> 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 diff --git a/libxslt/pattern.c b/libxslt/pattern.c index 6ccf845..a96c19e 100644 --- a/libxslt/pattern.c +++ b/libxslt/pattern.c @@ -974,12 +974,33 @@ int xsltAddTemplate(xsltStylesheetPtr style, xsltTemplatePtr cur) { xsltCompMatchPtr pat, list; 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 */ - /* TODO : handle | in patterns as multple pat !!! */ - pat = xsltCompilePattern(cur->match); + pattern = p; + 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) return(-1); pat->template = cur; @@ -1080,6 +1101,8 @@ xsltAddTemplate(xsltStylesheetPtr style, xsltTemplatePtr cur) { } } } + if (*p != 0) + goto next_pattern; return(0); } @@ -1174,3 +1197,36 @@ xsltFreeTemplateHashes(xsltStylesheetPtr style) { (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); +} + diff --git a/libxslt/pattern.h b/libxslt/pattern.h index 0a7d143..96d32ae 100644 --- a/libxslt/pattern.h +++ b/libxslt/pattern.h @@ -20,6 +20,9 @@ int xsltAddTemplate (xsltStylesheetPtr style, xsltTemplatePtr xsltGetTemplate (xsltStylesheetPtr style, xmlNodePtr node); void xsltFreeTemplateHashes (xsltStylesheetPtr style); +xsltTemplatePtr xsltFindTemplate (xsltStylesheetPtr style, + const xmlChar *name, + const xmlChar *nameURI); #ifdef __cplusplus } #endif diff --git a/libxslt/transform.c b/libxslt/transform.c index 19ed865..797bfd1 100644 --- a/libxslt/transform.c +++ b/libxslt/transform.c @@ -295,7 +295,7 @@ xsltAttribute(xsltTransformContextPtr ctxt, xmlNodePtr node, if (value == NULL) { if (ns) { #if LIBXML_VERSION > 20211 - attr = xmlSetNsProp(ctxt->insert, ncname, ns->href, + attr = xmlSetNsProp(ctxt->insert, ns, ncname, (const xmlChar *)""); #else xsltGenericError(xsltGenericErrorContext, @@ -586,6 +586,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: * @ctxt: a XSLT process context * @node: the node in the source tree. @@ -803,8 +886,21 @@ xsltApplyOneTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node, } else if (IS_XSLT_NAME(cur, "variable")) { if (has_variables == 0) { xsltPushStack(ctxt); + has_variables = 1; } 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 { #ifdef DEBUG_PROCESS xsltGenericError(xsltGenericDebugContext, @@ -1120,6 +1216,7 @@ xsltApplyStylesheet(xsltStylesheetPtr style, xmlDocPtr doc) { return(NULL); ctxt->doc = doc; ctxt->style = style; + xsltEvalGlobalVariables(ctxt); if ((style->method != NULL) && (!xmlStrEqual(style->method, (const xmlChar *) "xml"))) { if (xmlStrEqual(style->method, (const xmlChar *) "html")) { diff --git a/libxslt/transform.h b/libxslt/transform.h index 1f8f9f2..de953fb 100644 --- a/libxslt/transform.h +++ b/libxslt/transform.h @@ -21,7 +21,9 @@ extern "C" { */ xmlDocPtr xsltApplyStylesheet (xsltStylesheetPtr style, xmlDocPtr doc); - +void xsltApplyOneTemplate (xsltTransformContextPtr ctxt, + xmlNodePtr node, + xmlNodePtr list); #ifdef __cplusplus } #endif diff --git a/libxslt/variables.c b/libxslt/variables.c index 08bf778..b256310 100644 --- a/libxslt/variables.c +++ b/libxslt/variables.c @@ -18,12 +18,14 @@ #include #include #include +#include #include #include #include "xslt.h" #include "xsltInternals.h" #include "xsltutils.h" #include "variables.h" +#include "transform.h" #define DEBUG_VARIABLE @@ -31,24 +33,6 @@ * 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 xsltStack *xsltStackPtr; struct _xsltStack { @@ -138,6 +122,7 @@ xsltFreeStackElemList(xsltStackElemPtr elem) { int xsltAddStackElem(xsltTransformContextPtr ctxt, xsltStackElemPtr elem) { xsltStackPtr stack; + xsltStackElemPtr cur; if ((ctxt == NULL) || (elem == NULL)) return(-1); @@ -158,6 +143,20 @@ xsltAddStackElem(xsltTransformContextPtr ctxt, xsltStackElemPtr elem) { } /* 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); @@ -233,6 +232,7 @@ xsltPopStack(xsltTransformContextPtr ctxt) { xsltStackElemPtr xsltStackLookup(xsltTransformContextPtr ctxt, const xmlChar *name, const xmlChar *nameURI) { + xsltStackElemPtr ret = NULL; xsltStackPtr stack; int i; xsltStackElemPtr cur; @@ -248,20 +248,29 @@ xsltStackLookup(xsltTransformContextPtr ctxt, const xmlChar *name, cur = stack->elems[i]; while (cur != NULL) { if (xmlStrEqual(cur->name, name)) { + /* TODO: double check param binding */ if (nameURI == NULL) { - if (cur->nameURI == NULL) - return(cur); + if (cur->nameURI == NULL) { + if (cur->type == XSLT_ELEM_PARAM) + ret = cur; + else + return(cur); + } } else { if ((cur->nameURI != NULL) && - (xmlStrEqual(cur->nameURI, nameURI))) - return(cur); + (xmlStrEqual(cur->nameURI, nameURI))) { + if (cur->type == XSLT_ELEM_PARAM) + ret = cur; + else + return(cur); + } } } cur = cur->next; } } - return(NULL); + return(ret); } /************************************************************************ @@ -271,50 +280,41 @@ xsltStackLookup(xsltTransformContextPtr ctxt, const xmlChar *name, ************************************************************************/ /** - * xsltRegisterVariable: + * xsltEvalVariable: * @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 - * @value: the variable value if select is NULL + * @elem: the variable or parameter. * - * Register a new variable value. If @value is NULL it unregisters - * the variable + * Evaluate a variable value. * * 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, - xmlXPathObjectPtr value) { - xsltStackElemPtr elem; - if (ctxt == NULL) - return(-1); - if (name == NULL) +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, - "Defineing variable %s\n", name); + "Evaluating variable %s\n", elem->name); #endif - elem = xsltNewStackElem(); - if (elem == NULL) - return(-1); - 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; - ctxt->xpathCtxt->node = ctxt->node; + return(-1); + ctxt->xpathCtxt->node = (xmlNodePtr) ctxt->node; xmlXPathEvalExpr(xpathParserCtxt); result = valuePop(xpathParserCtxt); do { @@ -325,10 +325,8 @@ xsltRegisterVariable(xsltTransformContextPtr ctxt, const xmlChar *name, } while (tmp != NULL); if (result == NULL) { -#ifdef DEBUG_PROCESS - xsltGenericDebug(xsltGenericDebugContext, - "Evaluating variable %s failed\n"); -#endif + xsltGenericError(xsltGenericErrorContext, + "Evaluating global variable %s failed\n"); } if (xpathParserCtxt != NULL) xmlXPathFreeParserContext(xpathParserCtxt); @@ -338,8 +336,169 @@ xsltRegisterVariable(xsltTransformContextPtr ctxt, const xmlChar *name, 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; + } } -error: + 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); } @@ -372,7 +531,7 @@ xsltVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name, xsltGenericDebug(xsltGenericDebugContext, "uncomputed variable %s\n", name); #endif - TODO /* Variable value computation needed */ + xsltEvalVariables(ctxt, elem); } if (elem->value != NULL) return(xmlXPathObjectCopy(elem->value)); @@ -409,11 +568,211 @@ xsltFreeVariableHashes(xsltTransformContextPtr ctxt) { } /** + * 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 - * @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. */ @@ -421,7 +780,7 @@ void xsltParseStylesheetVariable(xsltTransformContextPtr ctxt, xmlNodePtr cur) { xmlChar *name, *ncname, *prefix; xmlChar *select; - xmlXPathObjectPtr value = NULL; + xmlNodePtr tree = NULL; if ((cur == NULL) || (ctxt == NULL)) return; @@ -440,10 +799,7 @@ xsltParseStylesheetVariable(xsltTransformContextPtr ctxt, xmlNodePtr cur) { select = xmlGetNsProp(cur, (const xmlChar *)"select", XSLT_NAMESPACE); if (select == NULL) { - if (cur->children == NULL) - value = xmlXPathNewCString(""); - else - value = xmlXPathNewNodeSet(cur->children); + tree = cur->children; } else { if (cur->children != NULL) xsltGenericError(xsltGenericErrorContext, @@ -461,15 +817,15 @@ xsltParseStylesheetVariable(xsltTransformContextPtr ctxt, xmlNodePtr cur) { xsltGenericError(xsltGenericErrorContext, "xsl:variable : no namespace bound to prefix %s\n", prefix); } else { - xsltRegisterVariable(ctxt, ncname, ns->href, select, value); + xsltRegisterVariable(ctxt, ncname, ns->href, select, tree, 0); } xmlFree(prefix); } else { - xsltRegisterVariable(ctxt, ncname, NULL, select, value); + xsltRegisterVariable(ctxt, ncname, NULL, select, tree, 0); } xmlFree(ncname); } else { - xsltRegisterVariable(ctxt, name, NULL, select, value); + xsltRegisterVariable(ctxt, name, NULL, select, tree, 0); } xmlFree(name); diff --git a/libxslt/variables.h b/libxslt/variables.h index a063362..e4cea41 100644 --- a/libxslt/variables.h +++ b/libxslt/variables.h @@ -25,10 +25,17 @@ extern "C" { * Interfaces for the variable module. */ +int xsltEvalGlobalVariables (xsltTransformContextPtr ctxt); void xsltPushStack (xsltTransformContextPtr ctxt); void xsltPopStack (xsltTransformContextPtr ctxt); +void xsltParseGlobalVariable (xsltStylesheetPtr style, + xmlNodePtr cur); +void xsltParseGlobalParam (xsltStylesheetPtr style, + xmlNodePtr cur); void xsltParseStylesheetVariable (xsltTransformContextPtr ctxt, xmlNodePtr cur); +void xsltParseStylesheetParam (xsltTransformContextPtr ctxt, + xmlNodePtr cur); void xsltFreeVariableHashes (xsltTransformContextPtr ctxt); xmlXPathObjectPtr xsltVariableLookup (xsltTransformContextPtr ctxt, const xmlChar *name, @@ -37,7 +44,8 @@ int xsltRegisterVariable (xsltTransformContextPtr ctxt, const xmlChar *name, const xmlChar *ns_uri, const xmlChar *select, - xmlXPathObjectPtr value); + xmlNodePtr tree, + int param); xmlXPathObjectPtr xsltXPathVariableLookup (void *ctxt, const xmlChar *name, const xmlChar *ns_uri); diff --git a/libxslt/xslt.c b/libxslt/xslt.c index b6f2e7c..25b1b33 100644 --- a/libxslt/xslt.c +++ b/libxslt/xslt.c @@ -165,6 +165,8 @@ xsltFreeStylesheet(xsltStylesheetPtr sheet) { xsltFreeTemplateList(sheet->templates); if (sheet->doc != NULL) xmlFreeDoc(sheet->doc); + if (sheet->variables != NULL) + xsltFreeStackElemList(sheet->variables); if (sheet->stripSpaces != NULL) xmlHashFree(sheet->stripSpaces, NULL); @@ -563,12 +565,11 @@ skip_children: /* * Find and handle the params - */ cur = template->children; while (cur != NULL) { - /* + / * * Remove Blank nodes found at this level. - */ + * / if (IS_BLANK_NODE(cur)) { xmlNodePtr blank = cur; @@ -578,11 +579,12 @@ skip_children: continue; } if ((IS_XSLT_ELEM(cur)) && (IS_XSLT_NAME(cur, "param"))) { - TODO /* Handle param */ + xsltParseGlobalParam(style, cur); } else break; cur = cur->next; } + */ /* * Browse the remaining of the template diff --git a/libxslt/xsltInternals.h b/libxslt/xsltInternals.h index f4bcbc4..179ba2c 100644 --- a/libxslt/xsltInternals.h +++ b/libxslt/xsltInternals.h @@ -19,12 +19,33 @@ extern "C" { #endif + /* - * 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. + * 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 */ + xmlXPathObjectPtr value; /* The value if computed */ +}; + +/* + * The in-memory structure corresponding to an XSLT Template + */ #define XSLT_PAT_NO_PRIORITY -12345789 typedef struct _xsltTemplate xsltTemplate; @@ -42,6 +63,8 @@ struct _xsltTemplate { /* * 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 xsltStylesheet *xsltStylesheetPtr; @@ -60,6 +83,11 @@ struct _xsltStylesheet { preserve space and cdata-section elements */ /* + * Global variable or parameters + */ + xsltStackElemPtr variables; /* linked list of param and variables */ + + /* * Template descriptions */ xsltTemplatePtr templates; /* the ordered list of templates */ @@ -114,6 +142,7 @@ struct _xsltTransformContext { xsltStylesheetPtr xsltParseStylesheetFile (const xmlChar* filename); void xsltFreeStylesheet (xsltStylesheetPtr sheet); int xsltIsBlank (xmlChar *str); +void xsltFreeStackElemList (xsltStackElemPtr elem); #ifdef __cplusplus } diff --git a/libxslt/xsltproc.c b/libxslt/xsltproc.c index a3314a1..63f2332 100644 --- a/libxslt/xsltproc.c +++ b/libxslt/xsltproc.c @@ -22,7 +22,7 @@ static int repeat = 0; int main(int argc, char **argv) { int i; - xsltStylesheetPtr cur; + xsltStylesheetPtr cur = NULL; xmlDocPtr doc, res; /* --repeat : repeat 100 times, for timing or profiling */ diff --git a/tests/REC2/html.xml b/tests/REC2/html.xml index 0ba4c8e..ad34859 100644 --- a/tests/REC2/html.xml +++ b/tests/REC2/html.xml @@ -1,4 +1,5 @@ - + + Sales Results By Division -- 2.7.4