Furious hacking session, making serious progresses, the hardest stuff
authorDaniel Veillard <veillard@src.gnome.org>
Mon, 22 Jan 2001 10:52:35 +0000 (10:52 +0000)
committerDaniel Veillard <veillard@src.gnome.org>
Mon, 22 Jan 2001 10:52:35 +0000 (10:52 +0000)
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

12 files changed:
ChangeLog
TODO
libxslt/pattern.c
libxslt/pattern.h
libxslt/transform.c
libxslt/transform.h
libxslt/variables.c
libxslt/variables.h
libxslt/xslt.c
libxslt/xsltInternals.h
libxslt/xsltproc.c
tests/REC2/html.xml

index 6a0fb5c..8f4f9d5 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -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>
 
        * Makefile.am tests/Makefile.am tests/REC1/Makefile.am
diff --git a/TODO b/TODO
index ec37cfd..57e8f36 100644 (file)
--- 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
 
index 6ccf845..a96c19e 100644 (file)
@@ -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);
+}
+
index 0a7d143..96d32ae 100644 (file)
@@ -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
index 19ed865..797bfd1 100644 (file)
@@ -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")) {
index 1f8f9f2..de953fb 100644 (file)
@@ -21,7 +21,9 @@ extern "C" {
  */
 xmlDocPtr      xsltApplyStylesheet     (xsltStylesheetPtr style,
                                         xmlDocPtr doc);
-
+void           xsltApplyOneTemplate    (xsltTransformContextPtr ctxt,
+                                        xmlNodePtr node,
+                                        xmlNodePtr list);
 #ifdef __cplusplus
 }
 #endif
index 08bf778..b256310 100644 (file)
 #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 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);
index a063362..e4cea41 100644 (file)
@@ -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);
index b6f2e7c..25b1b33 100644 (file)
@@ -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
index f4bcbc4..179ba2c 100644 (file)
 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
 }
index a3314a1..63f2332 100644 (file)
@@ -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 */
index 0ba4c8e..ad34859 100644 (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>
 <body><table border="1">
 <tr>