Step in improving performances:
authorDaniel Veillard <veillard@src.gnome.org>
Tue, 6 Mar 2001 18:06:04 +0000 (18:06 +0000)
committerDaniel Veillard <veillard@src.gnome.org>
Tue, 6 Mar 2001 18:06:04 +0000 (18:06 +0000)
- libxslt/preproc.[ch] Makefile.am templates.[ch] transform.[ch]
  xsltInternals.h: started working on optimizing stylesheet
  element parsing. Just builds the extra informations so far.
- xsltutils.h: added a missing XPath decl
Daniel

12 files changed:
ChangeLog
libxslt/Makefile.am
libxslt/attributes.c
libxslt/numbersInternals.h
libxslt/preproc.c [new file with mode: 0644]
libxslt/preproc.h [new file with mode: 0644]
libxslt/templates.c
libxslt/templates.h
libxslt/transform.c
libxslt/transform.h
libxslt/xsltInternals.h
libxslt/xsltutils.h

index d12b5bb..79e10e0 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+Tue Mar  6 19:03:21 CET 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
+
+       * libxslt/preproc.[ch] Makefile.am templates.[ch] transform.[ch]
+         xsltInternals.h: started working on optimizing stylesheet
+         element parsing. Just builds the extra informations so far.
+       * xsltutils.h: added a missing XPath decl
+
 Tue Mar  6 09:52:13 CET 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
 
        * libxslt/variables.c: William M. Brack found a serious bug
index 43f2539..750c8de 100644 (file)
@@ -20,6 +20,7 @@ xsltinc_HEADERS =                     \
        imports.h                       \
        attributes.h                    \
        documents.h                     \
+       preproc.h                       \
        transform.h                     \
        xsltInternals.h
 
@@ -38,6 +39,7 @@ libxslt_la_SOURCES =                  \
        imports.c                       \
        attributes.c                    \
        documents.c                     \
+       preproc.c                       \
        transform.c
 
 
index 5be2ca8..ac52ef2 100644 (file)
@@ -369,95 +369,6 @@ error:
 }
 
 /**
- * xsltAttribute:
- * @ctxt:  a XSLT process context
- * @node:  the node in the source tree.
- * @inst:  the xslt attribute node
- *
- * Process the xslt attribute node on the source node
- */
-void
-xsltAttribute(xsltTransformContextPtr ctxt, xmlNodePtr node,
-                  xmlNodePtr inst) {
-    xmlChar *prop = NULL;
-    xmlChar *ncname = NULL;
-    xmlChar *prefix = NULL;
-    xmlChar *value = NULL;
-    xmlNsPtr ns = NULL;
-    xmlAttrPtr attr;
-
-
-    if (ctxt->insert == NULL)
-       return;
-    if (ctxt->insert->children != NULL) {
-       xsltGenericError(xsltGenericErrorContext,
-            "xslt:attribute : node has already children\n");
-       return;
-    }
-    prop = xsltEvalAttrValueTemplate(ctxt, inst, (const xmlChar *)"name");
-    if (prop == NULL) {
-       xsltGenericError(xsltGenericErrorContext,
-            "xslt:attribute : name is missing\n");
-       goto error;
-    }
-
-    ncname = xmlSplitQName2(prop, &prefix);
-    if (ncname == NULL) {
-       ncname = prop;
-       prop = NULL;
-       prefix = NULL;
-    }
-
-    if ((prefix != NULL) && (xmlStrEqual(prefix, (const xmlChar *)"xmlns"))) {
-#ifdef DEBUG_ATTRIBUTES
-       xsltGenericDebug(xsltGenericDebugContext,
-            "xslt:attribute : xmlns prefix forbidden\n");
-#endif
-       goto error;
-    }
-    prop = xsltEvalAttrValueTemplate(ctxt, inst, (const xmlChar *)"namespace");
-    if (prop != NULL) {
-       ns = xsltGetSpecialNamespace(ctxt, inst, prop, prefix, ctxt->insert);
-    } else {
-       if (prefix != NULL) {
-           ns = xmlSearchNs(inst->doc, inst, prefix);
-           if (ns == NULL) {
-               xsltGenericError(xsltGenericErrorContext,
-                   "no namespace bound to prefix %s\n", prefix);
-           } else {
-               ns = xsltGetNamespace(ctxt, inst, ns, ctxt->insert);
-           }
-       }
-    }
-    
-
-    value = xsltEvalTemplateString(ctxt, node, inst);
-    if (value == NULL) {
-       if (ns) {
-           attr = xmlSetNsProp(ctxt->insert, ns, ncname, 
-                               (const xmlChar *)"");
-       } else
-           attr = xmlSetProp(ctxt->insert, ncname, (const xmlChar *)"");
-    } else {
-       if (ns) {
-           attr = xmlSetNsProp(ctxt->insert, ns, ncname, value);
-       } else
-           attr = xmlSetProp(ctxt->insert, ncname, value);
-       
-    }
-
-error:
-    if (prop != NULL)
-        xmlFree(prop);
-    if (ncname != NULL)
-        xmlFree(ncname);
-    if (prefix != NULL)
-        xmlFree(prefix);
-    if (value != NULL)
-        xmlFree(value);
-}
-
-/**
  * xsltApplyAttributeSet:
  * @ctxt:  the XSLT stylesheet
  * @node:  the node in the source tree.
index a20dec1..02794f4 100644 (file)
@@ -11,7 +11,6 @@
 #define __XML_XSLT_NUMBERSINTERNALS_H__
 
 #include <libxml/tree.h>
-#include "xsltInternals.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -32,10 +31,6 @@ typedef struct _xsltNumberData {
     xmlNodePtr node;
 } xsltNumberData, *xsltNumberDataPtr;
 
-xmlXPathError xsltFormatNumberConversion(xsltDecimalFormatPtr, xmlChar *,
-                                        double, xmlChar **);
-void xsltNumberFormat(xsltTransformContextPtr, xsltNumberDataPtr, xmlNodePtr);
-
 #ifdef __cplusplus
 }
 #endif
diff --git a/libxslt/preproc.c b/libxslt/preproc.c
new file mode 100644 (file)
index 0000000..c63906f
--- /dev/null
@@ -0,0 +1,931 @@
+/*
+ * preproc.c: Preprocessing of style operations
+ *
+ * References:
+ *   http://www.w3.org/TR/1999/REC-xslt-19991116
+ *
+ *   Michael Kay "XSLT Programmer's Reference" pp 637-643
+ *   Writing Multiple Output Files
+ *
+ *   XSLT-1.1 Working Draft
+ *   http://www.w3.org/TR/xslt11#multiple-output
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@imag.fr
+ */
+
+#include "xsltconfig.h"
+
+#include <string.h>
+
+#include <libxml/xmlmemory.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/valid.h>
+#include <libxml/hash.h>
+#include <libxml/uri.h>
+#include <libxml/xmlerror.h>
+#include "xslt.h"
+#include "xsltutils.h"
+#include "xsltInternals.h"
+#include "transform.h"
+#include "templates.h"
+#include "variables.h"
+#include "numbersInternals.h"
+#include "preproc.h"
+#include "extra.h"
+#include "imports.h"
+
+#define DEBUG_PREPROC
+
+
+/************************************************************************
+ *                                                                     *
+ *                     handling of precomputed data                    *
+ *                                                                     *
+ ************************************************************************/
+
+/**
+ * xsltNewStylePreComp:
+ * @ctxt:  an XSLT processing context
+ * @type:  the construct type
+ *
+ * Create a new XSLT Style precomputed block
+ *
+ * Returns the newly allocated xsltStylePreCompPtr or NULL in case of error
+ */
+xsltStylePreCompPtr
+xsltNewStylePreComp(xsltTransformContextPtr ctxt, xsltStyleType type) {
+    xsltStylePreCompPtr cur;
+
+    cur = (xsltStylePreCompPtr) xmlMalloc(sizeof(xsltStylePreComp));
+    if (cur == NULL) {
+        xsltGenericError(xsltGenericErrorContext,
+               "xsltNewStylePreComp : malloc failed\n");
+       return(NULL);
+    }
+    memset(cur, 0, sizeof(xsltStylePreComp));
+
+    cur->type = type;
+    switch (cur->type) {
+        case XSLT_FUNC_COPY:
+            cur->func = xsltCopy;break;
+        case XSLT_FUNC_SORT:
+            cur->func = xsltSort;break;
+        case XSLT_FUNC_TEXT:
+            cur->func = xsltText;break;
+        case XSLT_FUNC_ELEMENT:
+            cur->func = xsltElement;break;
+        case XSLT_FUNC_ATTRIBUTE:
+            cur->func = xsltAttribute;break;
+        case XSLT_FUNC_COMMENT:
+            cur->func = xsltComment;break;
+        case XSLT_FUNC_PI:
+            cur->func = xsltProcessingInstruction;break;
+        case XSLT_FUNC_COPYOF:
+            cur->func = xsltCopyOf;break;
+        case XSLT_FUNC_VALUEOF:
+            cur->func = xsltValueOf;break;
+        case XSLT_FUNC_NUMBER:
+            cur->func = xsltNumber;break;
+        case XSLT_FUNC_APPLYIMPORTS:
+            cur->func = xsltApplyImports;break;
+        case XSLT_FUNC_CALLTEMPLATE:
+            cur->func = xsltCallTemplate;break;
+        case XSLT_FUNC_APPLYTEMPLATES:
+            cur->func = xsltApplyTemplates;break;
+        case XSLT_FUNC_CHOOSE:
+            cur->func = xsltChoose;break;
+        case XSLT_FUNC_IF:
+            cur->func = xsltIf;break;
+        case XSLT_FUNC_FOREACH:
+            cur->func = xsltForEach;break;
+        case XSLT_FUNC_DOCUMENT:
+            cur->func = xsltDocumentElem;break;
+    }
+    if (cur->func == NULL) {
+        xsltGenericError(xsltGenericErrorContext,
+               "xsltNewStylePreComp : no function for type %d\n", type);
+    }
+    cur->next = ctxt->preComps;
+    ctxt->preComps = cur;
+
+    return(cur);
+}
+
+/**
+ * xsltFreeStylePreComp:
+ * @comp:  an XSLT Style precomputed block
+ *
+ * Free up the memory allocated by @comp
+ */
+void
+xsltFreeStylePreComp(xsltStylePreCompPtr comp) {
+    if (comp == NULL)
+       return;
+    if (comp->stype != NULL)
+       xmlFree(comp->stype);
+    if (comp->order != NULL)
+       xmlFree(comp->order);
+    if (comp->use != NULL)
+       xmlFree(comp->use);
+    if (comp->name != NULL)
+       xmlFree(comp->name);
+    if (comp->ns != NULL)
+       xmlFree(comp->ns);
+    if (comp->mode != NULL)
+       xmlFree(comp->mode);
+    if (comp->modeURI != NULL)
+       xmlFree(comp->modeURI);
+    if (comp->test != NULL)
+       xmlFree(comp->test);
+    if (comp->select != NULL)
+       xmlFree(comp->select);
+
+    if (comp->filename != NULL)
+       xmlFree(comp->filename);
+
+    if (comp->numdata.level != NULL)
+       xmlFree(comp->numdata.level);
+    if (comp->numdata.count != NULL)
+       xmlFree(comp->numdata.count);
+    if (comp->numdata.from != NULL)
+       xmlFree(comp->numdata.from);
+    if (comp->numdata.value != NULL)
+       xmlFree(comp->numdata.value);
+    if (comp->numdata.format != NULL)
+       xmlFree(comp->numdata.format);
+
+    memset(comp, -1, sizeof(xsltStylePreComp));
+
+    xmlFree(comp);
+}
+
+
+/************************************************************************
+ *                                                                     *
+ *                 XSLT-1.1 extensions                                 *
+ *                                                                     *
+ ************************************************************************/
+
+/**
+ * xsltDocumentComp:
+ * @ctxt:  an XSLT processing context
+ * @inst:  the instruction in the stylesheet
+ *
+ * Pre process an XSLT-1.1 document element
+ */
+void
+xsltDocumentComp(xsltTransformContextPtr ctxt, xmlNodePtr inst) {
+    xsltStylePreCompPtr comp;
+    xmlChar *filename = NULL;
+    xmlChar *base = NULL;
+    xmlChar *URL = NULL;
+
+    comp = xsltNewStylePreComp(ctxt, XSLT_FUNC_DOCUMENT);
+    if (comp == NULL)
+       return;
+    inst->_private = comp;
+    comp->ver11 = 0;
+
+    if (xmlStrEqual(inst->name, (const xmlChar *) "output")) {
+#ifdef DEBUG_EXTRA
+       xsltGenericDebug(xsltGenericDebugContext,
+           "Found saxon:output extension\n");
+#endif
+       filename = xmlGetNsProp(inst, (const xmlChar *)"file",
+                       XSLT_SAXON_NAMESPACE);
+    } else if (xmlStrEqual(inst->name, (const xmlChar *) "write")) {
+#ifdef DEBUG_EXTRA
+       xsltGenericDebug(xsltGenericDebugContext,
+           "Found xalan:write extension\n");
+#endif
+       filename = xmlGetNsProp(inst, (const xmlChar *)"select",
+                       XSLT_XALAN_NAMESPACE);
+    } else if (xmlStrEqual(inst->name, (const xmlChar *) "document")) {
+       filename = xmlGetNsProp(inst, (const xmlChar *)"href",
+                       XSLT_XT_NAMESPACE);
+       if (filename == NULL) {
+#ifdef DEBUG_EXTRA
+           xsltGenericDebug(xsltGenericDebugContext,
+               "Found xslt11:document construct\n");
+#endif
+           filename = xmlGetNsProp(inst, (const xmlChar *)"href",
+                           XSLT_NAMESPACE);
+           comp->ver11 = 1;
+       } else {
+#ifdef DEBUG_EXTRA
+           xsltGenericDebug(xsltGenericDebugContext,
+               "Found xt:document extension\n");
+#endif
+           comp->ver11 = 0;
+       }
+    }
+    if (filename == NULL) {
+       xsltGenericError(xsltGenericErrorContext,
+           "xsltDocumentComp: could not find the href\n");
+       goto error;
+    }
+
+    /*
+     * Compute output URL
+     */
+    base = xmlNodeGetBase(inst->doc, inst);
+    URL = xmlBuildURI(base, filename);
+    if (URL == NULL) {
+       xsltGenericError(xsltGenericErrorContext,
+           "xsltDocumentElem: URL computation failed %s\n", filename);
+       comp->filename = xmlStrdup(filename);
+    } else {
+       comp->filename = URL;
+    }
+
+error:
+    if (base != NULL)
+       xmlFree(base);
+    if (filename != NULL)
+       xmlFree(filename);
+}
+
+/************************************************************************
+ *                                                                     *
+ *             Most of the XSLT-1.0 transformations                    *
+ *                                                                     *
+ ************************************************************************/
+
+/**
+ * xsltSortComp:
+ * @ctxt:  a XSLT process context
+ * @inst:  the xslt sort node
+ *
+ * Process the xslt sort node on the source node
+ */
+void
+xsltSortComp(xsltTransformContextPtr ctxt, xmlNodePtr inst) {
+    xsltStylePreCompPtr comp;
+
+
+    if ((ctxt == NULL) || (inst == NULL))
+       return;
+    comp = xsltNewStylePreComp(ctxt, XSLT_FUNC_SORT);
+    if (comp == NULL)
+       return;
+    inst->_private = comp;
+
+    comp->stype = xsltEvalStaticAttrValueTemplate(ctxt, inst,
+                        (const xmlChar *)"data-type", &comp->has_stype);
+    if (comp->stype != NULL) {
+       if (xmlStrEqual(comp->stype, (const xmlChar *) "text"))
+           comp->number = 0;
+       else if (xmlStrEqual(comp->stype, (const xmlChar *) "number"))
+           comp->number = 1;
+       else {
+           xsltGenericError(xsltGenericErrorContext,
+                "xsltSortComp: no support for data-type = %s\n", comp->stype);
+           comp->number = -1;
+       }
+    }
+    comp->order = xsltEvalStaticAttrValueTemplate(ctxt, inst,
+                             (const xmlChar *)"order", &comp->has_order);
+    if (comp->order != NULL) {
+       if (xmlStrEqual(comp->order, (const xmlChar *) "ascending"))
+           comp->descending = 0;
+       else if (xmlStrEqual(comp->order, (const xmlChar *) "descending"))
+           comp->descending = 1;
+       else {
+           xsltGenericError(xsltGenericErrorContext,
+                "xsltSortComp: invalid value %s for order\n", comp->order);
+           comp->descending = -1;
+       }
+    }
+    /* TODO: xsl:sort lang attribute */
+    /* TODO: xsl:sort case-order attribute */
+
+    comp->select = xmlGetNsProp(inst,(const xmlChar *)"select", XSLT_NAMESPACE);
+    if (comp->select == NULL) {
+       comp->select = xmlNodeGetContent(inst);
+       if (comp->select == NULL) {
+           xsltGenericError(xsltGenericErrorContext,
+                "xsltSortComp: select is not defined\n");
+       }
+    }
+}
+
+/**
+ * xsltCopyComp:
+ * @ctxt:  a XSLT process context
+ * @inst:  the xslt copy node
+ *
+ * Process the xslt copy node on the source node
+ */
+void
+xsltCopyComp(xsltTransformContextPtr ctxt, xmlNodePtr inst) {
+    xsltStylePreCompPtr comp;
+
+
+    if ((ctxt == NULL) || (inst == NULL))
+       return;
+    comp = xsltNewStylePreComp(ctxt, XSLT_FUNC_COPY);
+    if (comp == NULL)
+       return;
+    inst->_private = comp;
+
+
+    comp->use = xmlGetNsProp(inst, (const xmlChar *)"use-attribute-sets",
+                                   XSLT_NAMESPACE);
+    if (comp->use == NULL)
+       comp->has_use = 0;
+    else
+       comp->has_use = 1;
+}
+
+/**
+ * xsltTextComp:
+ * @ctxt:  a XSLT process context
+ * @inst:  the xslt text node
+ *
+ * Process the xslt text node on the source node
+ */
+void
+xsltTextComp(xsltTransformContextPtr ctxt, xmlNodePtr inst) {
+    xsltStylePreCompPtr comp;
+    xmlChar *prop;
+
+    if ((ctxt == NULL) || (inst == NULL))
+       return;
+    comp = xsltNewStylePreComp(ctxt, XSLT_FUNC_TEXT);
+    if (comp == NULL)
+       return;
+    inst->_private = comp;
+    comp->noescape = 0;
+
+    prop = xmlGetNsProp(inst,
+           (const xmlChar *)"disable-output-escaping",
+                       XSLT_NAMESPACE);
+    if (prop != NULL) {
+       if (xmlStrEqual(prop, (const xmlChar *)"yes")) {
+           comp->noescape = 1;
+       } else if (!xmlStrEqual(prop,
+                               (const xmlChar *)"no")){
+           xsltGenericError(xsltGenericErrorContext,
+"xslt:text: disable-output-escaping allow only yes or no\n");
+       }
+       xmlFree(prop);
+    }
+}
+
+/**
+ * xsltElementComp:
+ * @ctxt:  a XSLT process context
+ * @inst:  the xslt element node
+ *
+ * Process the xslt element node on the source node
+ */
+void
+xsltElementComp(xsltTransformContextPtr ctxt, xmlNodePtr inst) {
+    xsltStylePreCompPtr comp;
+
+    if ((ctxt == NULL) || (inst == NULL))
+       return;
+    comp = xsltNewStylePreComp(ctxt, XSLT_FUNC_ELEMENT);
+    if (comp == NULL)
+       return;
+    inst->_private = comp;
+
+    /*
+     * TODO: more computation can be done there, especially namespace lookup
+     */
+    comp->name = xsltEvalStaticAttrValueTemplate(ctxt, inst,
+                                (const xmlChar *)"name", &comp->has_name);
+    comp->ns = xsltEvalStaticAttrValueTemplate(ctxt, inst,
+                        (const xmlChar *)"namespace", &comp->has_ns);
+
+    comp->use = xsltEvalStaticAttrValueTemplate(ctxt, inst,
+                      (const xmlChar *)"use-attribute-sets", &comp->has_use);
+}
+
+/**
+ * xsltAttributeComp:
+ * @ctxt:  a XSLT process context
+ * @inst:  the xslt attribute node
+ *
+ * Process the xslt attribute node on the source node
+ */
+void
+xsltAttributeComp(xsltTransformContextPtr ctxt, xmlNodePtr inst) {
+    xsltStylePreCompPtr comp;
+
+    if ((ctxt == NULL) || (inst == NULL))
+       return;
+    comp = xsltNewStylePreComp(ctxt, XSLT_FUNC_ATTRIBUTE);
+    if (comp == NULL)
+       return;
+    inst->_private = comp;
+
+    /*
+     * TODO: more computation can be done there, especially namespace lookup
+     */
+    comp->name = xsltEvalStaticAttrValueTemplate(ctxt, inst,
+                                (const xmlChar *)"name", &comp->has_name);
+    comp->ns = xsltEvalStaticAttrValueTemplate(ctxt, inst,
+                        (const xmlChar *)"namespace", &comp->has_ns);
+
+}
+
+/**
+ * xsltCommentComp:
+ * @ctxt:  a XSLT process context
+ * @inst:  the xslt comment node
+ *
+ * Process the xslt comment node on the source node
+ */
+void
+xsltCommentComp(xsltTransformContextPtr ctxt, xmlNodePtr inst) {
+    xsltStylePreCompPtr comp;
+
+    if ((ctxt == NULL) || (inst == NULL))
+       return;
+    comp = xsltNewStylePreComp(ctxt, XSLT_FUNC_COMMENT);
+    if (comp == NULL)
+       return;
+    inst->_private = comp;
+}
+
+/**
+ * xsltProcessingInstructionComp:
+ * @ctxt:  a XSLT process context
+ * @inst:  the xslt processing-instruction node
+ *
+ * Process the xslt processing-instruction node on the source node
+ */
+void
+xsltProcessingInstructionComp(xsltTransformContextPtr ctxt, xmlNodePtr inst) {
+    xsltStylePreCompPtr comp;
+
+    if ((ctxt == NULL) || (inst == NULL))
+       return;
+    comp = xsltNewStylePreComp(ctxt, XSLT_FUNC_PI);
+    if (comp == NULL)
+       return;
+    inst->_private = comp;
+
+    comp->name = xsltEvalStaticAttrValueTemplate(ctxt, inst,
+                                (const xmlChar *)"name", &comp->has_name);
+}
+
+/**
+ * xsltCopyOfComp:
+ * @ctxt:  a XSLT process context
+ * @inst:  the xslt copy-of node
+ *
+ * Process the xslt copy-of node on the source node
+ */
+void
+xsltCopyOfComp(xsltTransformContextPtr ctxt, xmlNodePtr inst) {
+    xsltStylePreCompPtr comp;
+
+    if ((ctxt == NULL) || (inst == NULL))
+       return;
+    comp = xsltNewStylePreComp(ctxt, XSLT_FUNC_COPYOF);
+    if (comp == NULL)
+       return;
+    inst->_private = comp;
+
+    comp->select = xmlGetNsProp(inst, (const xmlChar *)"select",
+                               XSLT_NAMESPACE);
+    if (comp->select == NULL) {
+       xsltGenericError(xsltGenericErrorContext,
+            "xslt:copy-of : select is missing\n");
+    }
+}
+
+/**
+ * xsltValueOfComp:
+ * @ctxt:  a XSLT process context
+ * @inst:  the xslt value-of node
+ *
+ * Process the xslt value-of node on the source node
+ */
+void
+xsltValueOfComp(xsltTransformContextPtr ctxt, xmlNodePtr inst) {
+    xsltStylePreCompPtr comp;
+    xmlChar *prop;
+
+    if ((ctxt == NULL) || (inst == NULL))
+       return;
+    comp = xsltNewStylePreComp(ctxt, XSLT_FUNC_VALUEOF);
+    if (comp == NULL)
+       return;
+    inst->_private = comp;
+
+    prop = xmlGetNsProp(inst,
+           (const xmlChar *)"disable-output-escaping",
+                       XSLT_NAMESPACE);
+    if (prop != NULL) {
+       if (xmlStrEqual(prop, (const xmlChar *)"yes")) {
+           comp->noescape = 1;
+       } else if (!xmlStrEqual(prop,
+                               (const xmlChar *)"no")){
+           xsltGenericError(xsltGenericErrorContext,
+"value-of: disable-output-escaping allow only yes or no\n");
+       }
+       xmlFree(prop);
+    }
+    comp->select = xmlGetNsProp(inst, (const xmlChar *)"select",
+                               XSLT_NAMESPACE);
+    if (comp->select == NULL) {
+       xsltGenericError(xsltGenericErrorContext,
+            "xslt:value-of : select is missing\n");
+    }
+}
+
+/**
+ * xsltNumberComp:
+ * @ctxt:  a XSLT process context
+ * @cur:   the xslt number node
+ *
+ * Process the xslt number node on the source node
+ */
+void
+xsltNumberComp(xsltTransformContextPtr ctxt, xmlNodePtr cur) {
+    xsltStylePreCompPtr comp;
+    xmlChar *prop;
+
+    if ((ctxt == NULL) || (cur == NULL))
+       return;
+    comp = xsltNewStylePreComp(ctxt, XSLT_FUNC_NUMBER);
+    if (comp == NULL)
+       return;
+    cur->_private = comp;
+
+    if ((ctxt == NULL) || (cur == NULL))
+       return;
+
+    comp->numdata.doc = cur->doc;
+    comp->numdata.node = cur;
+    comp->numdata.value = xmlGetNsProp(cur, (const xmlChar *)"value",
+                                       XSLT_NAMESPACE);
+    
+    prop = xmlGetNsProp(cur, (const xmlChar *)"format", XSLT_NAMESPACE);
+    if (prop != NULL) {
+       comp->numdata.format = prop;
+    } else {
+       comp->numdata.format = xmlStrdup(BAD_CAST("1"));
+    }
+    
+    comp->numdata.count = xmlGetNsProp(cur, (const xmlChar *)"count",
+                                       XSLT_NAMESPACE);
+    comp->numdata.from = xmlGetNsProp(cur, (const xmlChar *)"from",
+                                       XSLT_NAMESPACE);
+    
+    prop = xmlGetNsProp(cur, (const xmlChar *)"level", XSLT_NAMESPACE);
+    if (prop != NULL) {
+       if (xmlStrEqual(prop, BAD_CAST("single")) ||
+           xmlStrEqual(prop, BAD_CAST("multiple")) ||
+           xmlStrEqual(prop, BAD_CAST("any"))) {
+           comp->numdata.level = prop;
+       } else {
+           xsltGenericError(xsltGenericErrorContext,
+                        "xsl:number : invalid value %s for level\n", prop);
+           xmlFree(prop);
+       }
+    }
+    
+    prop = xmlGetNsProp(cur, (const xmlChar *)"lang", XSLT_NAMESPACE);
+    if (prop != NULL) {
+       TODO; /* xsl:number lang attribute */
+       xmlFree(prop);
+    }
+    
+    prop = xmlGetNsProp(cur, (const xmlChar *)"letter-value", XSLT_NAMESPACE);
+    if (prop != NULL) {
+       if (xmlStrEqual(prop, BAD_CAST("alphabetic"))) {
+           TODO; /* xsl:number letter-value attribute alphabetic */
+       } else if (xmlStrEqual(prop, BAD_CAST("traditional"))) {
+           TODO; /* xsl:number letter-value attribute traditional */
+       } else {
+           xsltGenericError(xsltGenericErrorContext,
+                    "xsl:number : invalid value %s for letter-value\n", prop);
+       }
+       xmlFree(prop);
+    }
+    
+    prop = xmlGetNsProp(cur, (const xmlChar *)"grouping-separator", XSLT_NAMESPACE);
+    if (prop != NULL) {
+       comp->numdata.groupingCharacter = prop[0];
+       xmlFree(prop);
+    }
+    
+    prop = xmlGetNsProp(cur, (const xmlChar *)"grouping-size", XSLT_NAMESPACE);
+    if (prop != NULL) {
+       sscanf((char *)prop, "%d", &comp->numdata.digitsPerGroup);
+       xmlFree(prop);
+    } else {
+       comp->numdata.groupingCharacter = 0;
+    }
+
+    /* Set default values */
+    if (comp->numdata.value == NULL) {
+       if (comp->numdata.level == NULL) {
+           comp->numdata.level = xmlStrdup(BAD_CAST("single"));
+       }
+    }
+    
+}
+
+/**
+ * xsltApplyImportsComp:
+ * @ctxt:  a XSLT process context
+ * @inst:  the xslt apply-imports node
+ *
+ * Process the xslt apply-imports node on the source node
+ */
+void
+xsltApplyImportsComp(xsltTransformContextPtr ctxt, xmlNodePtr inst) {
+    xsltStylePreCompPtr comp;
+
+    if ((ctxt == NULL) || (inst == NULL))
+       return;
+    comp = xsltNewStylePreComp(ctxt, XSLT_FUNC_APPLYIMPORTS);
+    if (comp == NULL)
+       return;
+    inst->_private = comp;
+}
+
+/**
+ * xsltCallTemplateComp:
+ * @ctxt:  a XSLT process context
+ * @inst:  the xslt call-template node
+ *
+ * Process the xslt call-template node on the source node
+ */
+void
+xsltCallTemplateComp(xsltTransformContextPtr ctxt, xmlNodePtr inst) {
+    xsltStylePreCompPtr comp;
+    xmlChar *prop;
+    xmlChar *ncname = NULL;
+    xmlChar *prefix = NULL;
+    xmlNsPtr ns;
+
+    if ((ctxt == NULL) || (inst == NULL))
+       return;
+    comp = xsltNewStylePreComp(ctxt, XSLT_FUNC_CALLTEMPLATE);
+    if (comp == NULL)
+       return;
+    inst->_private = comp;
+
+    /*
+     * The full template resolution can be done statically
+     */
+    prop = xmlGetNsProp(inst, (const xmlChar *)"name", XSLT_NAMESPACE);
+    if (prop == NULL) {
+       xsltGenericError(xsltGenericErrorContext,
+            "xslt:call-template : name is missing\n");
+       goto error;
+    } else {
+
+       ncname = xmlSplitQName2(prop, &prefix);
+       if (ncname == NULL) {
+           ncname = prop;
+           prop = NULL;
+           prefix = NULL;
+       }
+       if (prefix != 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)
+           comp->templ = xsltFindTemplate(ctxt, ncname, ns->href);
+       else
+           comp->templ = xsltFindTemplate(ctxt, ncname, NULL);
+
+       if (comp->templ == NULL) {
+           xsltGenericError(xsltGenericErrorContext,
+                "xslt:call-template : template %s not found\n", ncname);
+       }
+    }
+
+    /* TODO: with-param could be optimized too */
+
+error:
+    if (prop != NULL)
+        xmlFree(prop);
+    if (ncname != NULL)
+        xmlFree(ncname);
+    if (prefix != NULL)
+        xmlFree(prefix);
+}
+
+/**
+ * xsltApplyTemplatesComp:
+ * @ctxt:  a XSLT process context
+ * @inst:  the apply-templates node
+ *
+ * Process the apply-templates node on the source node
+ */
+void
+xsltApplyTemplatesComp(xsltTransformContextPtr ctxt, xmlNodePtr inst) {
+    xsltStylePreCompPtr comp;
+    xmlChar *prop;
+
+    if ((ctxt == NULL) || (inst == NULL))
+       return;
+    comp = xsltNewStylePreComp(ctxt, XSLT_FUNC_APPLYTEMPLATES);
+    if (comp == NULL)
+       return;
+    inst->_private = comp;
+
+    /*
+     * Get mode if any
+     */
+    prop = xmlGetNsProp(inst, (const xmlChar *)"mode", XSLT_NAMESPACE);
+    if (prop != NULL) {
+       xmlChar *prefix = NULL;
+
+       comp->mode = xmlSplitQName2(prop, &prefix);
+       if (comp->mode != NULL) {
+           if (prefix != NULL) {
+               xmlNsPtr ns;
+
+               ns = xmlSearchNs(inst->doc, inst, prefix);
+               if (ns == NULL) {
+                   xsltGenericError(xsltGenericErrorContext,
+                       "no namespace bound to prefix %s\n", prefix);
+                   xmlFree(prefix);
+                   xmlFree(comp->mode);
+                   comp->mode = prop;
+                   comp->modeURI = NULL;
+               } else {
+                   comp->modeURI = xmlStrdup(ns->href);
+                   xmlFree(prefix);
+                   xmlFree(prop);
+               }
+           } else {
+               xmlFree(prop);
+               comp->modeURI = NULL;
+           }
+       } else {
+           comp->mode = prop;
+           comp->modeURI = NULL;
+       }
+    }
+    comp->select = xmlGetNsProp(inst, (const xmlChar *)"select",
+                               XSLT_NAMESPACE);
+
+    /* TODO: handle (or skip) the xsl:sort and xsl:with-param */
+}
+
+/**
+ * xsltChooseComp:
+ * @ctxt:  a XSLT process context
+ * @inst:  the xslt choose node
+ *
+ * Process the xslt choose node on the source node
+ */
+void
+xsltChooseComp(xsltTransformContextPtr ctxt, xmlNodePtr inst) {
+    xsltStylePreCompPtr comp;
+
+    if ((ctxt == NULL) || (inst == NULL))
+       return;
+    comp = xsltNewStylePreComp(ctxt, XSLT_FUNC_CHOOSE);
+    if (comp == NULL)
+       return;
+    inst->_private = comp;
+}
+
+/**
+ * xsltIfComp:
+ * @ctxt:  a XSLT process context
+ * @inst:  the xslt if node
+ *
+ * Process the xslt if node on the source node
+ */
+void
+xsltIfComp(xsltTransformContextPtr ctxt, xmlNodePtr inst) {
+    xsltStylePreCompPtr comp;
+
+    if ((ctxt == NULL) || (inst == NULL))
+       return;
+    comp = xsltNewStylePreComp(ctxt, XSLT_FUNC_IF);
+    if (comp == NULL)
+       return;
+    inst->_private = comp;
+
+    comp->test = xmlGetNsProp(inst, (const xmlChar *)"test", XSLT_NAMESPACE);
+    if (comp->test == NULL) {
+       xsltGenericError(xsltGenericErrorContext,
+            "xsltIf: test is not defined\n");
+       return;
+    }
+}
+
+/**
+ * xsltForEachComp:
+ * @ctxt:  a XSLT process context
+ * @inst:  the xslt for-each node
+ *
+ * Process the xslt for-each node on the source node
+ */
+void
+xsltForEachComp(xsltTransformContextPtr ctxt, xmlNodePtr inst) {
+    xsltStylePreCompPtr comp;
+
+    if ((ctxt == NULL) || (inst == NULL))
+       return;
+    comp = xsltNewStylePreComp(ctxt, XSLT_FUNC_FOREACH);
+    if (comp == NULL)
+       return;
+    inst->_private = comp;
+
+    comp->select = xmlGetNsProp(inst, (const xmlChar *)"select",
+                               XSLT_NAMESPACE);
+
+    /* TODO: handle and skip the xsl:sort */
+}
+
+
+/************************************************************************
+ *                                                                     *
+ *                 Generic interface                                   *
+ *                                                                     *
+ ************************************************************************/
+
+/**
+ * xsltFreeStylePreComps:
+ * @ctxt:  an XSLT transformation context
+ *
+ * Free up the memory allocated by all precomputed blocks
+ */
+void
+xsltFreeStylePreComps(xsltTransformContextPtr ctxt) {
+    xsltStylePreCompPtr cur, next;
+
+    if (ctxt == NULL)
+       return;
+    cur = ctxt->preComps;
+    while (cur != NULL) {
+       next = cur->next;
+       xsltFreeStylePreComp(cur);
+       cur = next;
+    }
+}
+
+/**
+ * xsltDocumentCompute:
+ * @ctxt:  an XSLT processing context
+ * @inst:  the instruction in the stylesheet
+ *
+ * Precompute an XSLT stylesheet element
+ */
+void
+xsltStylePreCompute(xsltTransformContextPtr ctxt, xmlNodePtr inst) {
+    if (IS_XSLT_ELEM(inst)) {
+       if (IS_XSLT_NAME(inst, "apply-templates")) {
+           xsltApplyTemplatesComp(ctxt, inst);
+       } else if (IS_XSLT_NAME(inst, "value-of")) {
+           xsltValueOfComp(ctxt, inst);
+       } else if (IS_XSLT_NAME(inst, "copy")) {
+           xsltCopyComp(ctxt, inst);
+       } else if (IS_XSLT_NAME(inst, "copy-of")) {
+           xsltCopyOfComp(ctxt, inst);
+       } else if (IS_XSLT_NAME(inst, "if")) {
+           xsltIfComp(ctxt, inst);
+       } else if (IS_XSLT_NAME(inst, "choose")) {
+           xsltChooseComp(ctxt, inst);
+       } else if (IS_XSLT_NAME(inst, "for-each")) {
+           xsltForEachComp(ctxt, inst);
+       } else if (IS_XSLT_NAME(inst, "apply-imports")) {
+           xsltApplyImportsComp(ctxt, inst);
+       } else if (IS_XSLT_NAME(inst, "attribute")) {
+           xsltAttributeComp(ctxt, inst);
+       } else if (IS_XSLT_NAME(inst, "element")) {
+           xsltElementComp(ctxt, inst);
+       } else if (IS_XSLT_NAME(inst, "text")) {
+           xsltTextComp(ctxt, inst);
+       } else if (IS_XSLT_NAME(inst, "comment")) {
+           xsltCommentComp(ctxt, inst);
+       } else if (IS_XSLT_NAME(inst, "number")) {
+           xsltNumberComp(ctxt, inst);
+       } else if (IS_XSLT_NAME(inst, "processing-instruction")) {
+           xsltProcessingInstructionComp(ctxt, inst);
+       } else if (IS_XSLT_NAME(inst, "call-template")) {
+           xsltCallTemplateComp(ctxt, inst);
+       } else if (IS_XSLT_NAME(inst, "variable")) {
+           /* TODO: is there any use optimizing variable too ? */
+           return;
+       } else if (IS_XSLT_NAME(inst, "message")) {
+           /* no optimization needed */
+           return;
+       } else if (IS_XSLT_NAME(inst, "document")) {
+           xsltDocumentComp(ctxt, inst);
+       } else {
+           xsltGenericError(xsltGenericDebugContext,
+                "xsltStylePreComp: unknown xslt:%s\n", inst->name);
+       }
+    }
+}
diff --git a/libxslt/preproc.h b/libxslt/preproc.h
new file mode 100644 (file)
index 0000000..f07412e
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * preproc.h: precomputing data interfaces
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@imag.fr
+ */
+
+#ifndef __XML_XSLT_PRECOMP_H__
+#define __XML_XSLT_PRECOMP_H__
+
+#include <libxml/tree.h>
+#include "xsltInternals.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Interfaces
+ */
+void           xsltStylePreCompute     (xsltTransformContextPtr ctxt,
+                                        xmlNodePtr inst);
+void           xsltFreeStylePreComps   (xsltTransformContextPtr ctxt);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __XML_XSLT_PRECOMP_H__ */
+
index 694357f..1f2dd53 100644 (file)
@@ -267,6 +267,43 @@ xsltEvalAttrValueTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node,
 }
 
 /**
+ * xsltEvalStaticAttrValueTemplate:
+ * @ctxt:  the XSLT transformation context
+ * @node:  the stylesheet node
+ * @name:  the attribute QName
+ * @found:  indicator whether the attribute is present
+ *
+ * Check if an attribute value template has a static value, i.e. the
+ * attribute value does not contain expressions contained in curly braces ({})
+ *
+ * Returns the static string value or NULL, must be deallocated by the
+ *    caller.
+ */
+xmlChar *
+xsltEvalStaticAttrValueTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node,
+                               const xmlChar *name, int *found) {
+    const xmlChar *ret;
+    xmlChar *expr;
+
+    if ((ctxt == NULL) || (node == NULL) || (name == NULL))
+       return(NULL);
+
+    expr = xmlGetNsProp(node, name, XSLT_NAMESPACE);
+    if (expr == NULL) {
+       *found = 0;
+       return(NULL);
+    }
+    *found = 1;
+
+    ret = xmlStrchr(expr, '{');
+    if (ret != NULL) {
+       xmlFree(expr);
+       return(NULL);
+    }
+    return(expr);
+}
+
+/**
  * xsltAttrTemplateProcess:
  * @ctxt:  the XSLT transformation context
  * @target:  the result node
index 0fdb763..be2f6c0 100644 (file)
@@ -25,6 +25,10 @@ xmlChar *    xsltEvalTemplateString          (xsltTransformContextPtr ctxt,
 xmlChar *      xsltEvalAttrValueTemplate       (xsltTransformContextPtr ctxt,
                                                 xmlNodePtr node,
                                                 const xmlChar *name);
+xmlChar *      xsltEvalStaticAttrValueTemplate (xsltTransformContextPtr ctxt,
+                                                xmlNodePtr node,
+                                                const xmlChar *name,
+                                                int *found);
 xmlChar *      xsltEvalXPathString             (xsltTransformContextPtr ctxt,
                                                 const xmlChar *expr);
 xmlNodePtr *   xsltTemplateProcess             (xsltTransformContextPtr ctxt,
index 196e722..38790dd 100644 (file)
@@ -47,6 +47,7 @@
 #include "documents.h"
 #include "extensions.h"
 #include "extra.h"
+#include "preproc.h"
 
 #define DEBUG_PROCESS
 
@@ -209,6 +210,7 @@ xsltFreeTransformContext(xsltTransformContextPtr ctxt) {
        xmlFree(ctxt->varsTab);
     xsltFreeDocuments(ctxt);
     xsltFreeCtxtExts(ctxt);
+    xsltFreeStylePreComps(ctxt);
     memset(ctxt, -1, sizeof(xsltTransformContext));
     xmlFree(ctxt);
 }
@@ -838,6 +840,96 @@ error:
 }
 
 /**
+ * xsltAttribute:
+ * @ctxt:  a XSLT process context
+ * @node:  the node in the source tree.
+ * @inst:  the xslt attribute node
+ *
+ * Process the xslt attribute node on the source node
+ */
+void
+xsltAttribute(xsltTransformContextPtr ctxt, xmlNodePtr node,
+                  xmlNodePtr inst) {
+    xmlChar *prop = NULL;
+    xmlChar *ncname = NULL;
+    xmlChar *prefix = NULL;
+    xmlChar *value = NULL;
+    xmlNsPtr ns = NULL;
+    xmlAttrPtr attr;
+
+
+    if (ctxt->insert == NULL)
+       return;
+    if (ctxt->insert->children != NULL) {
+       xsltGenericError(xsltGenericErrorContext,
+            "xslt:attribute : node has already children\n");
+       return;
+    }
+    prop = xsltEvalAttrValueTemplate(ctxt, inst, (const xmlChar *)"name");
+    if (prop == NULL) {
+       xsltGenericError(xsltGenericErrorContext,
+            "xslt:attribute : name is missing\n");
+       goto error;
+    }
+
+    ncname = xmlSplitQName2(prop, &prefix);
+    if (ncname == NULL) {
+       ncname = prop;
+       prop = NULL;
+       prefix = NULL;
+    }
+
+    if ((prefix != NULL) && (xmlStrEqual(prefix, (const xmlChar *)"xmlns"))) {
+#ifdef DEBUG_ATTRIBUTES
+       xsltGenericDebug(xsltGenericDebugContext,
+            "xslt:attribute : xmlns prefix forbidden\n");
+#endif
+       goto error;
+    }
+    prop = xsltEvalAttrValueTemplate(ctxt, inst, (const xmlChar *)"namespace");
+    if (prop != NULL) {
+       ns = xsltGetSpecialNamespace(ctxt, inst, prop, prefix, ctxt->insert);
+    } else {
+       if (prefix != NULL) {
+           ns = xmlSearchNs(inst->doc, inst, prefix);
+           if (ns == NULL) {
+               xsltGenericError(xsltGenericErrorContext,
+                   "no namespace bound to prefix %s\n", prefix);
+           } else {
+               ns = xsltGetNamespace(ctxt, inst, ns, ctxt->insert);
+           }
+       }
+    }
+    
+
+    value = xsltEvalTemplateString(ctxt, node, inst);
+    if (value == NULL) {
+       if (ns) {
+           attr = xmlSetNsProp(ctxt->insert, ns, ncname, 
+                               (const xmlChar *)"");
+       } else
+           attr = xmlSetProp(ctxt->insert, ncname, (const xmlChar *)"");
+    } else {
+       if (ns) {
+           attr = xmlSetNsProp(ctxt->insert, ns, ncname, value);
+       } else
+           attr = xmlSetProp(ctxt->insert, ncname, value);
+       
+    }
+
+error:
+    if (prop != NULL)
+        xmlFree(prop);
+    if (ncname != NULL)
+        xmlFree(ncname);
+    if (prefix != NULL)
+        xmlFree(prefix);
+    if (value != NULL)
+        xmlFree(value);
+}
+
+
+/**
  * xsltComment:
  * @ctxt:  a XSLT process context
  * @node:  the node in the source tree.
@@ -1951,8 +2043,37 @@ xsltApplyOneTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node,
            return;
        }
 
-       if (IS_XSLT_ELEM(cur)) {
-           if (IS_XSLT_NAME(cur, "apply-templates")) {
+       if (cur->_private != NULL) {
+           xsltStylePreCompPtr info = (xsltStylePreCompPtr) cur->_private;
+           if (info->func != NULL) {
+               ctxt->insert = insert;
+               info->func(ctxt, node, cur);
+               ctxt->insert = oldInsert;
+           } else {
+               xsltGenericError(xsltGenericDebugContext,
+                "xsltApplyOneTemplate: %s has _private without function\n",
+                                cur->name);
+           }
+           goto skip_children;
+       } else if (IS_XSLT_ELEM(cur)) {
+           xsltStylePreCompute(ctxt, cur);
+           if (cur->_private != NULL) {
+               xsltStylePreCompPtr info = (xsltStylePreCompPtr) cur->_private;
+               if (info->func != NULL) {
+                   ctxt->insert = insert;
+                   info->func(ctxt, node, cur);
+                   ctxt->insert = oldInsert;
+               } else {
+                   xsltGenericError(xsltGenericDebugContext,
+                    "xsltApplyOneTemplate: %s has _private without function\n",
+                                    cur->name);
+               }
+               goto skip_children;
+           }
+
+           if (IS_XSLT_NAME(cur, "variable")) {
+               xsltParseStylesheetVariable(ctxt, cur);
+           } else if (IS_XSLT_NAME(cur, "apply-templates")) {
                ctxt->insert = insert;
                xsltApplyTemplates(ctxt, node, cur);
                ctxt->insert = oldInsert;
@@ -2010,8 +2131,6 @@ xsltApplyOneTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node,
                ctxt->insert = insert;
                xsltProcessingInstruction(ctxt, node, cur);
                ctxt->insert = oldInsert;
-           } else if (IS_XSLT_NAME(cur, "variable")) {
-               xsltParseStylesheetVariable(ctxt, cur);
            } else if (IS_XSLT_NAME(cur, "param")) {
                xsltParseStylesheetParam(ctxt, cur);
            } else if (IS_XSLT_NAME(cur, "call-template")) {
index bfc9e05..0e0fa76 100644 (file)
@@ -28,6 +28,54 @@ void         xsltApplyOneTemplate    (xsltTransformContextPtr ctxt,
 void           xsltDocumentElem        (xsltTransformContextPtr ctxt,
                                         xmlNodePtr node,
                                         xmlNodePtr inst);
+void           xsltSort                (xsltTransformContextPtr ctxt,
+                                        xmlNodePtr node,
+                                        xmlNodePtr inst);
+void           xsltCopy                (xsltTransformContextPtr ctxt,
+                                        xmlNodePtr node,
+                                        xmlNodePtr inst);
+void           xsltText                (xsltTransformContextPtr ctxt,
+                                        xmlNodePtr node,
+                                        xmlNodePtr inst);
+void           xsltElement             (xsltTransformContextPtr ctxt,
+                                        xmlNodePtr node,
+                                        xmlNodePtr inst);
+void           xsltComment             (xsltTransformContextPtr ctxt,
+                                        xmlNodePtr node,
+                                        xmlNodePtr inst);
+void           xsltAttribute           (xsltTransformContextPtr ctxt,
+                                        xmlNodePtr node,
+                                        xmlNodePtr inst);
+void           xsltProcessingInstruction(xsltTransformContextPtr ctxt,
+                                        xmlNodePtr node,
+                                        xmlNodePtr inst);
+void           xsltCopyOf              (xsltTransformContextPtr ctxt,
+                                        xmlNodePtr node,
+                                        xmlNodePtr inst);
+void           xsltValueOf             (xsltTransformContextPtr ctxt,
+                                        xmlNodePtr node,
+                                        xmlNodePtr inst);
+void           xsltNumber              (xsltTransformContextPtr ctxt,
+                                        xmlNodePtr node,
+                                        xmlNodePtr cur);
+void           xsltApplyImports        (xsltTransformContextPtr ctxt,
+                                        xmlNodePtr node,
+                                        xmlNodePtr inst);
+void           xsltCallTemplate        (xsltTransformContextPtr ctxt,
+                                        xmlNodePtr node,
+                                        xmlNodePtr inst);
+void           xsltApplyTemplates      (xsltTransformContextPtr ctxt,
+                                        xmlNodePtr node,
+                                        xmlNodePtr inst);
+void           xsltChoose              (xsltTransformContextPtr ctxt,
+                                        xmlNodePtr node,
+                                        xmlNodePtr inst);
+void           xsltIf                  (xsltTransformContextPtr ctxt,
+                                        xmlNodePtr node,
+                                        xmlNodePtr inst);
+void           xsltForEach             (xsltTransformContextPtr ctxt,
+                                        xmlNodePtr node,
+                                        xmlNodePtr inst);
 #ifdef __cplusplus
 }
 #endif
index ae00895..fdd42be 100644 (file)
@@ -14,6 +14,7 @@
 #include <libxml/hash.h>
 #include <libxml/xpath.h>
 #include <libxslt/xslt.h>
+#include "numbersInternals.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -181,6 +182,80 @@ struct _xsltStylesheet {
 
 
 /*
+ * The in-memory structure corresponding to XSLT stylesheet constructs
+ * precomputed data.
+ */
+
+typedef struct _xsltTransformContext xsltTransformContext;
+typedef xsltTransformContext *xsltTransformContextPtr;
+
+typedef void (*xsltStyleFunc) (xsltTransformContextPtr ctxt,
+                              xmlNodePtr node, xmlNodePtr inst);
+
+typedef enum {
+    XSLT_FUNC_COPY=1,
+    XSLT_FUNC_SORT,
+    XSLT_FUNC_TEXT,
+    XSLT_FUNC_ELEMENT,
+    XSLT_FUNC_ATTRIBUTE,
+    XSLT_FUNC_COMMENT,
+    XSLT_FUNC_PI,
+    XSLT_FUNC_COPYOF,
+    XSLT_FUNC_VALUEOF,
+    XSLT_FUNC_NUMBER,
+    XSLT_FUNC_APPLYIMPORTS,
+    XSLT_FUNC_CALLTEMPLATE,
+    XSLT_FUNC_APPLYTEMPLATES,
+    XSLT_FUNC_CHOOSE,
+    XSLT_FUNC_IF,
+    XSLT_FUNC_FOREACH,
+    XSLT_FUNC_DOCUMENT
+} xsltStyleType;
+
+typedef struct _xsltStylePreComp xsltStylePreComp;
+typedef xsltStylePreComp *xsltStylePreCompPtr;
+struct _xsltStylePreComp {
+    struct _xsltStylePreComp *next;/* chained list */
+    xsltStyleType type;        /* type of the element */
+    xsltStyleFunc func; /* handling function */
+
+    /*
+     * Pre computed values
+     */
+
+    xmlChar *stype;             /* sort */
+    int      has_stype;                /* sort */
+    int      number;           /* sort */
+    xmlChar *order;             /* sort */
+    int      has_order;                /* sort */
+    int      descending;       /* sort */
+
+    xmlChar *use;              /* copy, element */
+    int      has_use;          /* copy, element */
+
+    int      noescape;         /* text */
+
+    xmlChar *name;             /* element, attribute, pi */
+    int      has_name;         /* element, attribute, pi */
+    xmlChar *ns;               /* element */
+    int      has_ns;           /* element */
+
+    xmlChar *mode;             /* apply-templates */
+    xmlChar *modeURI;          /* apply-templates */
+
+    xmlChar *test;             /* if */
+
+    xsltTemplatePtr templ;     /* call-template */
+
+    xmlChar *select;           /* sort, copy-of, value-of, apply-templates */
+
+    int      ver11;            /* document */
+    xmlChar *filename;         /* document URL */
+
+    xsltNumberData numdata;    /* number */
+};
+
+/*
  * The in-memory structure corresponding to an XSLT Transformation
  */
 typedef enum {
@@ -195,8 +270,6 @@ typedef enum {
     XSLT_STATE_STOPPED
 } xsltTransformState;
 
-typedef struct _xsltTransformContext xsltTransformContext;
-typedef xsltTransformContext *xsltTransformContextPtr;
 struct _xsltTransformContext {
     xsltStylesheetPtr style;           /* the stylesheet used */
     xsltOutputType type;               /* the type of output */
@@ -212,6 +285,11 @@ struct _xsltTransformContext {
     xsltStackElemPtr *varsTab;         /* the variable list stack */
 
     /*
+     * Precomputed blocks
+     */
+    xsltStylePreCompPtr preComps;      /* list of precomputed blocks */
+
+    /*
      * Extensions
      */
     xmlHashTablePtr   extFunctions;    /* the extension functions */
@@ -259,6 +337,14 @@ xsltStylesheetPtr  xsltParseStylesheetProcess(xsltStylesheetPtr ret,
 void                   xsltParseStylesheetOutput(xsltStylesheetPtr style,
                                                  xmlNodePtr cur);
 xsltStylesheetPtr      xsltParseStylesheetDoc  (xmlDocPtr doc);
+void                   xsltNumberFormat        (xsltTransformContextPtr ctxt,
+                                                xsltNumberDataPtr data,
+                                                xmlNodePtr node);
+xmlXPathError           xsltFormatNumberConversion(xsltDecimalFormatPtr self,
+                                                xmlChar *format,
+                                                double number,
+                                                xmlChar **result);
+
 #ifdef __cplusplus
 }
 #endif
index bd13734..44238e5 100644 (file)
@@ -20,13 +20,9 @@ extern "C" {
 /*
  * To cleanup
  */
+int xmlXPathIsNodeType(const xmlChar *name);
 xmlChar *xmlSplitQName2(const xmlChar *name, xmlChar **prefix);
 void xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs);
-xmlAttrPtr xmlSetNsProp        (xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
-                        const xmlChar *value);
-xmlNodePtr xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
-xmlNodePtr xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
-xmlNodePtr xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
 /*********
 void xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
                     xmlXPathVariableLookupFunc f, void *data)