One more day of hacking:
authorDaniel Veillard <veillard@src.gnome.org>
Mon, 29 Jan 2001 17:44:52 +0000 (17:44 +0000)
committerDaniel Veillard <veillard@src.gnome.org>
Mon, 29 Jan 2001 17:44:52 +0000 (17:44 +0000)
- FEATURES: updated
- tests/numbers/Makefile.am tests/numbers/format-number.*
  tests/Makefile.am configure.in: added number formattting
  test from Bjorn
- libxslt/attributes.[ch]: separated attribute support, started
  add support for attribute-sets
- libxslt/functions.[ch]: update for number and formatting
  from Bjorn
- libxslt/transform.c libxslt/xslt.c libxslt/xsltInternals.h:
  cleanups updates, etc ...
Daniel

16 files changed:
ChangeLog
FEATURES
configure.in
libxslt/Makefile.am
libxslt/attributes.c [new file with mode: 0644]
libxslt/attributes.h [new file with mode: 0644]
libxslt/functions.c
libxslt/functions.h
libxslt/transform.c
libxslt/xslt.c
libxslt/xsltInternals.h
tests/Makefile.am
tests/numbers/Makefile.am [new file with mode: 0644]
tests/numbers/format-number.out [new file with mode: 0644]
tests/numbers/format-number.xml [new file with mode: 0644]
tests/numbers/format-number.xsl [new file with mode: 0644]

index 0e6a8ea..0019f41 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+Mon Jan 29 18:40:23 CET 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
+
+       * FEATURES: updated
+       * tests/numbers/Makefile.am tests/numbers/format-number.*
+         tests/Makefile.am configure.in: added number formattting
+         test from Bjorn
+       * libxslt/attributes.[ch]: separated attribute support, started
+         add support for attribute-sets
+       * libxslt/functions.[ch]: update for number and formatting
+         from Bjorn
+       * libxslt/transform.c libxslt/xslt.c libxslt/xsltInternals.h:
+         cleanups updates, etc ...
+
 Mon Jan 29 00:53:25 CET 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
 
        * FEATURES: updated
index 387d37c..2c65e23 100644 (file)
--- a/FEATURES
+++ b/FEATURES
@@ -109,7 +109,7 @@ YES                 name = { ncname }
 
 YES                xsl:comment
 
-NO                 xsl:copy
+YES                xsl:copy
 NO                     use-attribute-sets = qnames
 
 YES                xsl:value-of
index bc4dfb7..08cd778 100644 (file)
@@ -146,6 +146,7 @@ libxslt/xsltconfig.h
 tests/Makefile
 tests/REC1/Makefile
 tests/REC2/Makefile
+tests/numbers/Makefile
 doc/Makefile
 xslt-config
 libxslt.spec
index f582bf1..a29ec9e 100644 (file)
@@ -13,6 +13,7 @@ xsltinc_HEADERS =                     \
        variables.h                     \
        functions.h                     \
        namespaces.h                    \
+       attributes.h                    \
        transform.h                     \
        xsltInternals.h
 
@@ -24,6 +25,7 @@ libxslt_la_SOURCES =                  \
        variables.c                     \
        functions.c                     \
        namespaces.c                    \
+       attributes.c                    \
        transform.c
 
 
diff --git a/libxslt/attributes.c b/libxslt/attributes.c
new file mode 100644 (file)
index 0000000..3bafd1c
--- /dev/null
@@ -0,0 +1,439 @@
+/*
+ * attributes.c: Implementation of the XSLT attributes handling
+ *
+ * Reference:
+ *   http://www.w3.org/TR/1999/REC-xslt-19991116
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@imag.fr
+ */
+
+#include "xsltconfig.h"
+
+#include <string.h>
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_MATH_H
+#include <math.h>
+#endif
+#ifdef HAVE_FLOAT_H
+#include <float.h>
+#endif
+#ifdef HAVE_IEEEFP_H
+#include <ieeefp.h>
+#endif
+#ifdef HAVE_NAN_H
+#include <nan.h>
+#endif
+#ifdef HAVE_CTYPE_H
+#include <ctype.h>
+#endif
+
+#include <libxml/xmlmemory.h>
+#include <libxml/tree.h>
+#include <libxml/hash.h>
+#include <libxml/xmlerror.h>
+#include <libxml/uri.h>
+#include "xslt.h"
+#include "xsltInternals.h"
+#include "xsltutils.h"
+#include "attributes.h"
+#include "namespaces.h"
+#include "templates.h"
+
+/*
+ * Useful macros
+ */
+
+#define IS_BLANK(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) || \
+                     ((c) == 0x0D))
+
+#define IS_BLANK_NODE(n)                                               \
+    (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))
+
+
+/*
+ * The in-memory structure corresponding to an XSLT Attribute in
+ * an attribute set
+ */
+
+typedef struct _xsltAttrElem xsltAttrElem;
+typedef xsltAttrElem *xsltAttrElemPtr;
+struct _xsltAttrElem {
+    struct _xsltAttrElem *next;/* chained list */
+    xmlNodePtr attr;   /* the xsl:attribute definition */
+};
+
+/************************************************************************
+ *                                                                     *
+ *                     XSLT Attribute handling                         *
+ *                                                                     *
+ ************************************************************************/
+
+/**
+ * xsltNewAttrElem:
+ * @attr:  the new xsl:attribute node
+ *
+ * Create a new XSLT AttrElem
+ *
+ * Returns the newly allocated xsltAttrElemPtr or NULL in case of error
+ */
+xsltAttrElemPtr
+xsltNewAttrElem(xmlNodePtr attr) {
+    xsltAttrElemPtr cur;
+
+    cur = (xsltAttrElemPtr) xmlMalloc(sizeof(xsltAttrElem));
+    if (cur == NULL) {
+        xsltGenericError(xsltGenericErrorContext,
+               "xsltNewAttrElem : malloc failed\n");
+       return(NULL);
+    }
+    memset(cur, 0, sizeof(xsltAttrElem));
+    cur->attr = attr;
+    return(cur);
+}
+
+/**
+ * xsltFreeAttrElem:
+ * @attr:  an XSLT AttrElem
+ *
+ * Free up the memory allocated by @attr
+ */
+void
+xsltFreeAttrElem(xsltAttrElemPtr attr) {
+    memset(attr, -1, sizeof(xsltAttrElem));
+    xmlFree(attr);
+}
+
+/**
+ * xsltFreeAttrElemList:
+ * @list:  an XSLT AttrElem list
+ *
+ * Free up the memory allocated by @list
+ */
+void
+xsltFreeAttrElemList(xsltAttrElemPtr list) {
+    xsltAttrElemPtr next;
+    
+    while (list != NULL) {
+       next = list->next;
+       xsltFreeAttrElem(list);
+       list = next;
+    }
+}
+
+/**
+ * xsltAddAttrElemList:
+ * @list:  an XSLT AttrElem list
+ * @attr:  the new xsl:attribute node
+ *
+ * Add the new attribute to the list.
+ *
+ * Returns the new list pointer
+ */
+xsltAttrElemPtr
+xsltAddAttrElemList(xsltAttrElemPtr list, xmlNodePtr attr) {
+    xsltAttrElemPtr next;
+
+    if (attr == NULL)
+       return(list);
+    while (list != NULL) {
+       next = list->next;
+       if (list->attr == attr)
+           return(list);
+       if (next == NULL) {
+           list->next = xsltNewAttrElem(attr);
+           return(list);
+       }
+       list = next;
+    }
+    return(xsltNewAttrElem(attr));
+}
+/************************************************************************
+ *                                                                     *
+ *                     Module interfaces                               *
+ *                                                                     *
+ ************************************************************************/
+
+/**
+ * xsltParseStylesheetAttributeSet:
+ * @style:  the XSLT stylesheet
+ * @template:  the "preserve-space" element
+ *
+ * parse an XSLT stylesheet preserve-space element and record
+ * elements needing preserving
+ */
+
+void
+xsltParseStylesheetAttributeSet(xsltStylesheetPtr style, xmlNodePtr cur) {
+    xmlChar *prop = NULL;
+    xmlChar *ncname = NULL;
+    xmlChar *prefix = NULL;
+    xmlChar *attributes;
+    xmlChar *attribute, *end;
+    xmlNodePtr list, delete;
+    xsltAttrElemPtr values;
+
+    if ((cur == NULL) || (style == NULL))
+       return;
+
+    prop = xmlGetNsProp(cur, (const xmlChar *)"name", XSLT_NAMESPACE);
+    if (prop == NULL) {
+       xsltGenericError(xsltGenericErrorContext,
+            "xslt:attribute-set : name is missing\n");
+       goto error;
+    }
+
+    ncname = xmlSplitQName2(prop, &prefix);
+    if (ncname == NULL) {
+       ncname = prop;
+       prop = NULL;
+       prefix = NULL;
+    }
+
+    if (style->attributeSets == NULL)
+       style->attributeSets = xmlHashCreate(10);
+    if (style->attributeSets == NULL)
+       goto error;
+
+    values = xmlHashLookup2(style->attributeSets, ncname, prefix);
+
+    /*
+     * check the children list
+     */
+    list = cur->children;
+    delete = NULL;
+    while (list != NULL) {
+       if (IS_XSLT_ELEM(cur)) {
+           if (!IS_XSLT_NAME(cur, "attribute")) {
+               xsltGenericError(xsltGenericErrorContext,
+                   "xslt:attribute-set : unexpected child xsl:%s\n",
+                                cur->name);
+               delete = cur;
+           } else {
+#ifdef DEBUG_PARSING
+               xsltGenericDebug(xsltGenericDebugContext,
+                   "add attribute to list %s\n", ncname);
+#endif
+                values = xsltAddAttrElemList(values, cur);
+           }
+       } else {
+           xsltGenericError(xsltGenericErrorContext,
+               "xslt:attribute-set : unexpected child %s\n", cur->name);
+           delete = cur;
+       }
+       list = list->next;
+    }
+
+    /*
+     * Check a possible use-attribute-sets definition
+     */
+    /* TODO check recursion */
+
+    attributes = xmlGetNsProp(cur, (const xmlChar *)"use-attribute-sets",
+                             XSLT_NAMESPACE);
+    if (attributes == NULL) {
+       goto done;
+    }
+
+    attribute = attributes;
+    while (*attribute != 0) {
+       while (IS_BLANK(*attribute)) attribute++;
+       if (*attribute == 0)
+           break;
+        end = attribute;
+       while ((*end != 0) && (!IS_BLANK(*end))) end++;
+       attribute = xmlStrndup(attribute, end - attribute);
+       if (attribute) {
+#ifdef DEBUG_PARSING
+           xsltGenericDebug(xsltGenericDebugContext,
+               "xslt:attribute-set : %s adds use %s\n", ncname);
+#endif
+           TODO /* add use-attribute-sets support to atribute-set */
+       }
+       attribute = end;
+    }
+    xmlFree(attributes);
+
+done:
+    /*
+     * Update the value
+     */
+    xmlHashUpdateEntry2(style->attributeSets, ncname, prefix, values, NULL);
+#ifdef DEBUG_PARSING
+    xsltGenericDebug(xsltGenericDebugContext,
+       "updated attribute list %s\n", ncname);
+#endif
+
+error:
+    if (prop != NULL)
+        xmlFree(prop);
+    if (ncname != NULL)
+        xmlFree(ncname);
+    if (prefix != NULL)
+        xmlFree(prefix);
+}
+
+/**
+ * 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 (xmlStrEqual(ncname, (const xmlChar *) "xmlns")) {
+       xsltGenericError(xsltGenericErrorContext,
+            "xslt:attribute : xmlns forbidden\n");
+       goto error;
+    }
+    prop = xsltEvalAttrValueTemplate(ctxt, inst, (const xmlChar *)"namespace");
+    if (prop != NULL) {
+       TODO /* xsl:attribute namespace */
+       xmlFree(prop);
+       return;
+    } 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.
+ * @inst:  the xslt attribute node
+ * @attributes:  the set list.
+ *
+ * Apply the xsl:use-attribute-sets
+ */
+
+void
+xsltApplyAttributeSet(xsltTransformContextPtr ctxt, xmlNodePtr node,
+                     xmlNodePtr inst, xmlChar *attributes) {
+    xmlChar *ncname = NULL;
+    xmlChar *prefix = NULL;
+    xmlChar *attribute, *end;
+    xsltAttrElemPtr values;
+
+    if (attributes == NULL) {
+       return;
+    }
+
+    attribute = attributes;
+    while (*attribute != 0) {
+       while (IS_BLANK(*attribute)) attribute++;
+       if (*attribute == 0)
+           break;
+        end = attribute;
+       while ((*end != 0) && (!IS_BLANK(*end))) end++;
+       attribute = xmlStrndup(attribute, end - attribute);
+       if (attribute) {
+#ifdef DEBUG_PARSING
+           xsltGenericDebug(xsltGenericDebugContext,
+               "apply attribute set %s\n", attribute);
+#endif
+           ncname = xmlSplitQName2(attribute, &prefix);
+           if (ncname == NULL) {
+               ncname = attribute;
+               attribute = NULL;
+               prefix = NULL;
+           }
+
+           /* TODO: apply cascade */
+           values = xmlHashLookup2(ctxt->style->attributeSets, ncname, prefix);
+           while (values != NULL) {
+               xsltAttribute(ctxt, node, values->attr);
+               values = values->next;
+           }
+           if (attribute != NULL)
+               xmlFree(attribute);
+           if (ncname != NULL)
+               xmlFree(ncname);
+           if (prefix != NULL)
+               xmlFree(prefix);
+       }
+       attribute = end;
+    }
+}
+
+/**
+ * xsltFreeAttributeSetsHashes:
+ * @style: an XSLT stylesheet
+ *
+ * Free up the memory used by attribute sets
+ */
+void
+xsltFreeAttributeSetsHashes(xsltStylesheetPtr style) {
+    if (style->attributeSets != NULL)
+       xmlHashFree((xmlHashTablePtr) style->attributeSets,
+                   (xmlHashDeallocator) xsltFreeAttrElemList);
+    style->attributeSets = NULL;
+}
diff --git a/libxslt/attributes.h b/libxslt/attributes.h
new file mode 100644 (file)
index 0000000..6159aaa
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * attributes.h: interface for the XSLT attribute handling
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@imag.fr
+ */
+
+#ifndef __XML_XSLT_ATTRIBUTES_H__
+#define __XML_XSLT_ATTRIBUTES_H__
+
+#include <libxml/tree.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void   xsltParseStylesheetAttributeSet (xsltStylesheetPtr style,
+                                        xmlNodePtr cur);
+void   xsltAttribute                   (xsltTransformContextPtr ctxt,
+                                        xmlNodePtr node,
+                                        xmlNodePtr inst);
+void   xsltFreeAttributeSetsHashes     (xsltStylesheetPtr style);
+void   xsltApplyAttributeSet           (xsltTransformContextPtr ctxt,
+                                        xmlNodePtr node,
+                                        xmlNodePtr inst,
+                                        xmlChar *attributes);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __XML_XSLT_ATTRIBUTES_H__ */
+
index d79d5ac..9512684 100644 (file)
@@ -7,7 +7,7 @@
  * See Copyright for the status of this software.
  *
  * Daniel.Veillard@imag.fr
- * Bjorn Reese <breese@mail1.stofanet.dk> for number formatting
+ * Bjorn Reese <breese@users.sourceforge.net> for number formatting
  */
 
 #include "xsltconfig.h"
 
 #define DIGIT_LIST "0123456789"
 #define SYMBOL_QUOTE             ((xmlChar)'\'')
-#define SYMBOL_PATTERN_SEPARATOR ((xmlChar)';')
-#define SYMBOL_ZERO_DIGIT        ((xmlChar)'#')
-#define SYMBOL_DIGIT             ((xmlChar)'0')
-#define SYMBOL_DECIMAL_POINT     ((xmlChar)'.')
-#define SYMBOL_GROUPING          ((xmlChar)',')
-#define SYMBOL_MINUS             ((xmlChar)'-')
-#define SYMBOL_PERCENT           ((xmlChar)'%')
-#define SYMBOL_PERMILLE          ((xmlChar)'?')
 #define ID_STRING "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
 
-static struct _xsltDecimalFormat globalDecimalFormat;
 
 /************************************************************************
  *                                                                     *
@@ -291,27 +282,26 @@ xsltUnparsedEntityURIFunction(xmlXPathParserContextPtr ctxt, int nargs){
  */
 /* TODO
  *
- *  The JDK description does not tell where percent and permille may
- *  and may not appear within the format string.
- *
- *  Error handling.
+ * The JDK description does not tell where they may and may not appear
+ * within the format string. Nor does it tell what happens to integer
+ * values that does not fit into the format string.
  *
  *  Inf and NaN not tested.
  */
 #define IS_SPECIAL(self,letter) \
-    ((letter == self->zeroDigit) || \
-     (letter == self->digit) || \
-     (letter == self->decimalPoint) || \
-     (letter == self->grouping) || \
-     (letter == self->minusSign) || \
-     (letter == self->percent) || \
-     (letter == self->permille)) \
+    (((letter) == (self)->zeroDigit[0]) || \
+     ((letter) == (self)->digit[0]) || \
+     ((letter) == (self)->decimalPoint[0]) || \
+     ((letter) == (self)->grouping[0]) || \
+     ((letter) == (self)->minusSign[0]) || \
+     ((letter) == (self)->percent[0]) || \
+     ((letter) == (self)->permille[0]))
 
 static xmlXPathError
-PrivateDecimalFormat(xsltDecimalFormatPtr self,
-                    xmlChar *format,
-                    double number,
-                    xmlChar **result)
+xsltFormatNumberConversion(xsltDecimalFormatPtr self,
+                          xmlChar *format,
+                          double number,
+                          xmlChar **result)
 {
     xmlXPathError status = XPATH_EXPRESSION_OK;
     xmlChar *the_format;
@@ -328,6 +318,8 @@ PrivateDecimalFormat(xsltDecimalFormatPtr self,
     int decimal_point;
     double divisor;
     int digit;
+    int is_percent = FALSE;
+    int is_permille = FALSE;
 
     buffer = xmlBufferCreate();
     if (buffer == NULL) {
@@ -337,7 +329,7 @@ PrivateDecimalFormat(xsltDecimalFormatPtr self,
 
     /* Find positive or negative template */
     the_format = (xmlChar *)xmlStrchr(format,
-                                     self->patternSeparator);
+                                     self->patternSeparator[0]);
     if ((the_format != NULL) && (number < 0.0)) {
        /* Use negative template */
        the_format++;
@@ -385,7 +377,7 @@ PrivateDecimalFormat(xsltDecimalFormatPtr self,
        group = 0;
        for ( ; i < length; i++) {
            
-           if (the_format[i] == self->digit) {
+           if (the_format[i] == self->digit[0]) {
                if (decimal_point) {
                    if (fraction_zeroes > 0) {
                        status = XPATH_EXPR_ERROR;
@@ -397,7 +389,7 @@ PrivateDecimalFormat(xsltDecimalFormatPtr self,
                    group++;
                }
                
-           } else if (the_format[i] == self->zeroDigit) {
+           } else if (the_format[i] == self->zeroDigit[0]) {
                if (decimal_point)
                    fraction_zeroes++;
                else {
@@ -409,14 +401,14 @@ PrivateDecimalFormat(xsltDecimalFormatPtr self,
                    group++;
                }
                
-           } else if (the_format[i] == self->grouping) {
+           } else if (the_format[i] == self->grouping[0]) {
                if (decimal_point) {
                    status = XPATH_EXPR_ERROR;
                    goto DECIMAL_FORMAT_END;
                }
                group = 0;
                
-           } else if (the_format[i] == self->decimalPoint) {
+           } else if (the_format[i] == self->decimalPoint[0]) {
                if (decimal_point) {
                    status = XPATH_EXPR_ERROR;
                    goto DECIMAL_FORMAT_END;
@@ -426,13 +418,22 @@ PrivateDecimalFormat(xsltDecimalFormatPtr self,
            } else
                break;
        }
+       if (the_format[i] == self->percent[0]) {
+           is_percent = TRUE;
+       } else if (the_format[i] == self->permille[0]) {
+           is_permille = TRUE;
+       }
        
        /* Format the number */
 
        if (use_minus)
-           xmlBufferAdd(buffer, &(self->minusSign), 1);
+           xmlBufferAdd(buffer, self->minusSign, 1);
 
        number = fabs(number);
+       if (is_percent)
+           number /= 100.0;
+       else if (is_permille)
+           number /= 1000.0;
        number = floor(0.5 + number * pow(10.0, (double)(fraction_digits + fraction_zeroes)));
        
        /* Integer part */
@@ -449,7 +450,7 @@ PrivateDecimalFormat(xsltDecimalFormatPtr self,
        }
        
        if (decimal_point)
-           xmlBufferAdd(buffer, &(self->decimalPoint), 1);
+           xmlBufferAdd(buffer, self->decimalPoint, 1);
 
        /* Fraction part */
        for (j = fraction_digits + fraction_zeroes; j > 0; j--) {
@@ -463,6 +464,11 @@ PrivateDecimalFormat(xsltDecimalFormatPtr self,
        }
     }
 
+    if (is_percent)
+       xmlBufferAdd(buffer, self->percent, 1);
+    else if (is_permille)
+       xmlBufferAdd(buffer, self->permille, 1);
+    
     /* Suffix */
     for ( ; i < length; i++) {
        if (the_format[i] == SYMBOL_QUOTE)
@@ -483,13 +489,18 @@ xsltFormatNumberFunction(xmlXPathParserContextPtr ctxt, int nargs)
     xmlXPathObjectPtr numberObj = NULL;
     xmlXPathObjectPtr formatObj = NULL;
     xmlXPathObjectPtr decimalObj = NULL;
+    xsltStylesheetPtr sheet;
+    xsltDecimalFormatPtr formatValues;
     xmlChar *result;
+
+    sheet = ((xsltTransformContextPtr)ctxt->context->extra)->style;
+    formatValues = sheet->decimalFormat;
     
     switch (nargs) {
     case 3:
        CAST_TO_STRING;
        decimalObj = valuePop(ctxt);
-       globalDecimalFormat.decimalPoint = decimalObj->stringval[0]; /* hack */
+       formatValues = xsltDecimalFormatGetByName(sheet, decimalObj->stringval);
        /* Intentional fall-through */
     case 2:
        CAST_TO_STRING;
@@ -502,10 +513,10 @@ xsltFormatNumberFunction(xmlXPathParserContextPtr ctxt, int nargs)
        return;
     }
 
-    if (PrivateDecimalFormat(&globalDecimalFormat,
-                            formatObj->stringval,
-                            numberObj->floatval,
-                            &result) == XPATH_EXPRESSION_OK) {
+    if (xsltFormatNumberConversion(formatValues,
+                                  formatObj->stringval,
+                                  numberObj->floatval,
+                                  &result) == XPATH_EXPRESSION_OK) {
        valuePush(ctxt, xmlXPathNewString(result));
     }
     
@@ -722,17 +733,4 @@ xsltRegisterAllFunctions(xmlXPathContextPtr ctxt) {
                          xsltElementAvailableFunction);
     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"function-available",
                          xsltFunctionAvailableFunction);
-    
-    globalDecimalFormat.digit = SYMBOL_DIGIT;
-    globalDecimalFormat.patternSeparator = SYMBOL_PATTERN_SEPARATOR;
-    
-    globalDecimalFormat.decimalPoint = SYMBOL_DECIMAL_POINT;
-    globalDecimalFormat.grouping = SYMBOL_GROUPING;
-    globalDecimalFormat.percent = SYMBOL_PERCENT;
-    globalDecimalFormat.permille = SYMBOL_PERMILLE; /* #x2030 */
-    globalDecimalFormat.zeroDigit = SYMBOL_ZERO_DIGIT;
-    
-    globalDecimalFormat.minusSign = '-';
-    globalDecimalFormat.infinity = xmlStrdup(BAD_CAST("")); /* #x221E */
-    globalDecimalFormat.noNumber = xmlStrdup(BAD_CAST("")); /* #xFFFD */
 }
index b043451..e333f67 100644 (file)
@@ -4,7 +4,7 @@
  * See Copyright for the status of this software.
  *
  * Daniel.Veillard@imag.fr
- * Bjorn Reese <breese@mail1.stofanet.dk> for number formatting
+ * Bjorn Reese <breese@users.sourceforge.net> for number formatting
  */
 
 #ifndef __XML_XSLT_FUNCTIONS_H__
@@ -19,25 +19,6 @@ extern "C" {
 #endif
 
 /*
- * Data structure of decimal-format
- */
-typedef struct _xsltDecimalFormat {
-    /* Used for interpretation of pattern */
-    xmlChar digit;
-    xmlChar patternSeparator;
-    /* May appear in result */
-    xmlChar minusSign;
-    xmlChar *infinity;
-    xmlChar *noNumber;
-    /* Used for interpretation of pattern and may appear in result */
-    xmlChar decimalPoint;
-    xmlChar grouping;
-    xmlChar percent;
-    xmlChar permille;
-    xmlChar zeroDigit;
-} xsltDecimalFormat, *xsltDecimalFormatPtr;
-
-/*
  * Interfaces for the functions implementations
  */
 
index cc06f0c..4b761b5 100644 (file)
@@ -350,6 +350,35 @@ error:
 }
 
 /**
+ * xsltCopy:
+ * @ctxt:  a XSLT process context
+ * @node:  the node in the source tree.
+ * @inst:  the xslt copy node
+ *
+ * Process the xslt copy node on the source node
+ */
+void
+xsltCopy(xsltTransformContextPtr ctxt, xmlNodePtr node,
+                  xmlNodePtr inst) {
+    xmlChar *prop;
+    xmlNodePtr copy;
+
+    if ((node->type != XML_DOCUMENT_NODE) &&
+       (node->type != XML_HTML_DOCUMENT_NODE)) {
+       copy = xsltCopyNode(ctxt, node, ctxt->insert);
+       if (node->type == XML_ELEMENT_NODE) {
+           prop = xmlGetNsProp(inst, (const xmlChar *)"use-attribute-sets",
+                               XSLT_NAMESPACE);
+           if (prop != NULL) {
+               TODO /* xsl:copy use-attribute-sets */
+           }
+       }
+    }
+
+    xsltApplyOneTemplate(ctxt, ctxt->node, inst->children);
+}
+
+/**
  * xsltComment:
  * @ctxt:  a XSLT process context
  * @node:  the node in the source tree.
@@ -430,94 +459,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 (xmlStrEqual(ncname, (const xmlChar *) "xmlns")) {
-       xsltGenericError(xsltGenericErrorContext,
-            "xslt:attribute : xmlns forbidden\n");
-       goto error;
-    }
-    prop = xsltEvalAttrValueTemplate(ctxt, inst, (const xmlChar *)"namespace");
-    if (prop != NULL) {
-       TODO /* xsl:attribute namespace */
-       xmlFree(prop);
-       return;
-    } 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);
-}
-
-/**
  * xsltCopyOf:
  * @ctxt:  a XSLT process context
  * @node:  the node in the source tree.
@@ -1124,6 +1065,10 @@ xsltApplyOneTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node,
                ctxt->insert = insert;
                xsltValueOf(ctxt, node, cur);
                ctxt->insert = oldInsert;
+           } else if (IS_XSLT_NAME(cur, "copy")) {
+               ctxt->insert = insert;
+               xsltCopy(ctxt, node, cur);
+               ctxt->insert = oldInsert;
            } else if (IS_XSLT_NAME(cur, "copy-of")) {
                ctxt->insert = insert;
                xsltCopyOf(ctxt, node, cur);
@@ -1173,6 +1118,7 @@ xsltApplyOneTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node,
                }
                xsltCallTemplate(ctxt, node, cur);
            } else if (IS_XSLT_NAME(cur, "message")) {
+               xsltMessage(ctxt, node, cur);
            } else {
 #ifdef DEBUG_PROCESS
                xsltGenericError(xsltGenericDebugContext,
index 66a838b..c75ace4 100644 (file)
@@ -25,6 +25,7 @@
 #include "pattern.h"
 #include "variables.h"
 #include "namespaces.h"
+#include "attributes.h"
 #include "xsltutils.h"
 
 #define DEBUG_PARSING
@@ -68,6 +69,102 @@ xsltIsBlank(xmlChar *str) {
  *             Routines to handle XSLT data structures                 *
  *                                                                     *
  ************************************************************************/
+static xsltDecimalFormatPtr
+xsltNewDecimalFormat(xmlChar *name)
+{
+    xsltDecimalFormatPtr self;
+
+    self = xmlMalloc(sizeof(xsltDecimalFormat));
+    if (self != NULL) {
+       self->next = NULL;
+       self->name = (name == NULL) ? name : xmlStrdup(name);
+       
+       /* Default values */
+       self->digit = xmlStrdup(BAD_CAST("0"));
+       self->patternSeparator = xmlStrdup(BAD_CAST(";"));
+       self->decimalPoint = xmlStrdup(BAD_CAST("."));
+       self->grouping = xmlStrdup(BAD_CAST(","));
+       self->percent = xmlStrdup(BAD_CAST("%"));
+       self->permille = xmlStrdup(BAD_CAST("?"));
+       self->zeroDigit = xmlStrdup(BAD_CAST("#"));
+       self->minusSign = xmlStrdup(BAD_CAST("-"));
+       self->infinity = xmlStrdup(BAD_CAST("Infinity"));
+       self->noNumber = xmlStrdup(BAD_CAST("NaN"));
+    }
+    return self;
+}
+
+static void
+xsltFreeDecimalFormat(xsltDecimalFormatPtr self)
+{
+    if (self != NULL) {
+       if (self->digit)
+           xmlFree(self->digit);
+       if (self->patternSeparator)
+           xmlFree(self->patternSeparator);
+       if (self->decimalPoint)
+           xmlFree(self->decimalPoint);
+       if (self->grouping)
+           xmlFree(self->grouping);
+       if (self->percent)
+           xmlFree(self->percent);
+       if (self->permille)
+           xmlFree(self->permille);
+       if (self->zeroDigit)
+           xmlFree(self->zeroDigit);
+       if (self->minusSign)
+           xmlFree(self->minusSign);
+       if (self->infinity)
+           xmlFree(self->infinity);
+       if (self->noNumber)
+           xmlFree(self->noNumber);
+       if (self->name)
+           xmlFree(self->name);
+       xmlFree(self);
+    }
+}
+
+static void
+xsltFreeDecimalFormatList(xsltStylesheetPtr self)
+{
+    xsltDecimalFormatPtr iter;
+    xsltDecimalFormatPtr tmp;
+
+    if (self == NULL)
+       return;
+    
+    iter = self->decimalFormat;
+    while (iter != NULL) {
+       tmp = iter->next;
+       xsltFreeDecimalFormat(iter);
+       iter = tmp;
+    }
+}
+
+/**
+ * xsltDecimalFormatGetByName:
+ * @sheet: the XSLT stylesheet
+ * @name: the decimal-format name to find
+ *
+ * Find decimal-format by name
+ */
+xsltDecimalFormatPtr
+xsltDecimalFormatGetByName(xsltStylesheetPtr sheet, xmlChar *name)
+{
+    xsltDecimalFormatPtr result;
+
+    if (name == NULL)
+       return sheet->decimalFormat;
+    
+    for (result = sheet->decimalFormat->next;
+        result != NULL;
+        result = result->next) {
+       if (xmlStrEqual(name, result->name))
+           break; /* for */
+    }
+    return result;
+}
+
 
 /**
  * xsltNewTemplate:
@@ -147,6 +244,7 @@ xsltNewStylesheet(void) {
     memset(cur, 0, sizeof(xsltStylesheet));
     cur->omitXmlDeclaration = -1;
     cur->standalone = -1;
+    cur->decimalFormat = xsltNewDecimalFormat(NULL);
     cur->indent = -1;
     return(cur);
 }
@@ -163,7 +261,9 @@ xsltFreeStylesheet(xsltStylesheetPtr sheet) {
        return;
 
     xsltFreeTemplateHashes(sheet);
+    xsltFreeDecimalFormatList(sheet);
     xsltFreeTemplateList(sheet->templates);
+    xsltFreeAttributeSetsHashes(sheet);
     if (sheet->doc != NULL)
        xmlFreeDoc(sheet->doc);
     if (sheet->variables != NULL)
@@ -347,6 +447,108 @@ xsltParseStylesheetOutput(xsltStylesheetPtr style, xmlNodePtr cur) {
 }
 
 /**
+ * xsltParseStylesheetDecimalFormat:
+ * @style:  the XSLT stylesheet
+ * @cur:  the "decimal-format" element
+ *
+ * parse an XSLT stylesheet decimal-format element and
+ * and record the formatting characteristics
+ */
+void
+xsltParseStylesheetDecimalFormat(xsltStylesheetPtr sheet, xmlNodePtr cur)
+{
+    xmlChar *prop;
+    xsltDecimalFormatPtr format;
+    xsltDecimalFormatPtr iter;
+    
+    if ((cur == NULL) || (sheet == NULL))
+       return;
+
+    format = sheet->decimalFormat;
+    
+    prop = xmlGetNsProp(cur, BAD_CAST("name"), XSLT_NAMESPACE);
+    if (prop != NULL) {
+       format = xsltDecimalFormatGetByName(sheet, prop);
+       if (format != NULL) {
+           xsltGenericError(xsltGenericErrorContext,
+                            "xsltParseStylesheetDecimalFormat: %s already exists\n", prop);
+           return;
+       }
+       format = xsltNewDecimalFormat(prop);
+       if (format == NULL) {
+           xsltGenericError(xsltGenericErrorContext,
+                            "xsltParseStylesheetDecimalFormat: failed creating new decimal-format\n");
+           return;
+       }
+       /* Append new decimal-format structure */
+       for (iter = sheet->decimalFormat; iter->next; iter = iter->next)
+           ;
+       if (iter)
+           iter->next = format;
+    }
+
+    prop = xmlGetNsProp(cur, (const xmlChar *)"decimal-separator", XSLT_NAMESPACE);
+    if (prop != NULL) {
+       if (format->decimalPoint != NULL) xmlFree(format->decimalPoint);
+       format->decimalPoint  = prop;
+    }
+    
+    prop = xmlGetNsProp(cur, (const xmlChar *)"grouping-separator", XSLT_NAMESPACE);
+    if (prop != NULL) {
+       if (format->grouping != NULL) xmlFree(format->grouping);
+       format->grouping  = prop;
+    }
+
+    prop = xmlGetNsProp(cur, (const xmlChar *)"infinity", XSLT_NAMESPACE);
+    if (prop != NULL) {
+       if (format->infinity != NULL) xmlFree(format->infinity);
+       format->infinity  = prop;
+    }
+    
+    prop = xmlGetNsProp(cur, (const xmlChar *)"minus-sign", XSLT_NAMESPACE);
+    if (prop != NULL) {
+       if (format->minusSign != NULL) xmlFree(format->minusSign);
+       format->minusSign  = prop;
+    }
+    
+    prop = xmlGetNsProp(cur, (const xmlChar *)"NaN", XSLT_NAMESPACE);
+    if (prop != NULL) {
+       if (format->noNumber != NULL) xmlFree(format->noNumber);
+       format->noNumber  = prop;
+    }
+    
+    prop = xmlGetNsProp(cur, (const xmlChar *)"percent", XSLT_NAMESPACE);
+    if (prop != NULL) {
+       if (format->percent != NULL) xmlFree(format->percent);
+       format->percent  = prop;
+    }
+    
+    prop = xmlGetNsProp(cur, (const xmlChar *)"per-mille", XSLT_NAMESPACE);
+    if (prop != NULL) {
+       if (format->permille != NULL) xmlFree(format->permille);
+       format->permille  = prop;
+    }
+    
+    prop = xmlGetNsProp(cur, (const xmlChar *)"zero-digit", XSLT_NAMESPACE);
+    if (prop != NULL) {
+       if (format->zeroDigit != NULL) xmlFree(format->zeroDigit);
+       format->zeroDigit  = prop;
+    }
+    
+    prop = xmlGetNsProp(cur, (const xmlChar *)"digit", XSLT_NAMESPACE);
+    if (prop != NULL) {
+       if (format->digit != NULL) xmlFree(format->digit);
+       format->digit  = prop;
+    }
+    
+    prop = xmlGetNsProp(cur, (const xmlChar *)"pattern-separator", XSLT_NAMESPACE);
+    if (prop != NULL) {
+       if (format->patternSeparator != NULL) xmlFree(format->patternSeparator);
+       format->patternSeparator  = prop;
+    }
+}
+
+/**
  * xsltParseStylesheetPreserveSpace:
  * @style:  the XSLT stylesheet
  * @template:  the "preserve-space" element
@@ -447,6 +649,91 @@ xsltParseStylesheetStripSpace(xsltStylesheetPtr style, xmlNodePtr cur) {
 }
 
 /**
+ * xsltParseRemoveBlanks:
+ * @style:  the XSLT stylesheet
+ *
+ * Clean-up the stylesheet content from unwanted ignorable blank nodes
+ * and process xslt:text
+ */
+void
+xsltParseRemoveBlanks(xsltStylesheetPtr style) {
+    xmlNodePtr cur, delete;
+
+    /*
+     * This content comes from the stylesheet
+     * For stylesheets, the set of whitespace-preserving
+     * element names consists of just xsl:text.
+     */
+    cur = (xmlNodePtr) style->doc;
+    if (cur == NULL)
+       return;
+    cur = cur->children;
+    delete = NULL;
+    while (cur != NULL) {
+       if (delete != NULL) {
+#ifdef DEBUG_PARSING
+           xsltGenericDebug(xsltGenericDebugContext,
+            "xsltParseRemoveBlanks: removing ignorable blank node\n");
+#endif
+           xmlUnlinkNode(delete);
+           xmlFreeNode(delete);
+           delete = NULL;
+       }
+       if (IS_XSLT_ELEM(cur)) {
+           if (IS_XSLT_NAME(cur, "text")) {
+               goto skip_children;
+           }
+       } else if (cur->type == XML_TEXT_NODE) {
+           if (IS_BLANK_NODE(cur)) {
+               if (xmlNodeGetSpacePreserve(cur) != 1) {
+                   delete = cur;
+               }
+           }
+       } else if (cur->type != XML_ELEMENT_NODE) {
+           delete = cur;
+       }
+
+       /*
+        * Skip to next node
+        */
+       if (cur->children != NULL) {
+           if (cur->children->type != XML_ENTITY_DECL) {
+               cur = cur->children;
+               continue;
+           }
+       }
+skip_children:
+       if (cur->next != NULL) {
+           cur = cur->next;
+           continue;
+       }
+       
+       do {
+           cur = cur->parent;
+           if (cur == NULL)
+               break;
+           if (cur == (xmlNodePtr) style->doc) {
+               cur = NULL;
+               break;
+           }
+           if (cur->next != NULL) {
+               cur = cur->next;
+               break;
+           }
+       } while (cur != NULL);
+    }
+    if (delete != NULL) {
+#ifdef DEBUG_PARSING
+       xsltGenericDebug(xsltGenericDebugContext,
+        "xsltParseRemoveBlanks: removing ignorable blank node\n");
+#endif
+       xmlUnlinkNode(delete);
+       xmlFreeNode(delete);
+       delete = NULL;
+    }
+}
+
+/**
  * xsltParseTemplateContent:
  * @style:  the XSLT stylesheet
  * @ret:  the "template" structure
@@ -472,7 +759,7 @@ xsltParseTemplateContent(xsltStylesheetPtr style, xsltTemplatePtr ret,
        if (delete != NULL) {
 #ifdef DEBUG_PARSING
            xsltGenericDebug(xsltGenericDebugContext,
-            "xsltParseStylesheetTemplate: removing ignorable blank node\n");
+            "xsltParseStylesheetTemplate: removing text\n");
 #endif
            xmlUnlinkNode(delete);
            xmlFreeNode(delete);
@@ -510,14 +797,6 @@ xsltParseTemplateContent(xsltStylesheetPtr style, xsltTemplatePtr ret,
                delete = cur;
                goto skip_children;
            }
-       } else if (cur->type == XML_TEXT_NODE) {
-           if (IS_BLANK_NODE(cur)) {
-               if (xmlNodeGetSpacePreserve(cur) != 1) {
-                   delete = cur;
-               }
-           }
-       } else if (cur->type != XML_ELEMENT_NODE) {
-           delete = cur;
        }
 
        /*
@@ -552,7 +831,7 @@ skip_children:
     if (delete != NULL) {
 #ifdef DEBUG_PARSING
        xsltGenericDebug(xsltGenericDebugContext,
-        "xsltParseStylesheetTemplate: removing ignorable blank node\n");
+        "xsltParseStylesheetTemplate: removing text\n");
 #endif
        xmlUnlinkNode(delete);
        xmlFreeNode(delete);
@@ -564,17 +843,6 @@ skip_children:
      */
     cur = template->children;
     while (cur != NULL) {
-       /*
-        * Remove Blank nodes found at this level.
-        */
-       if (IS_BLANK_NODE(cur)) {
-           xmlNodePtr blank = cur;
-
-            cur = cur->next;
-           xmlUnlinkNode(blank);
-           xmlFreeNode(blank);
-           continue;
-       }
        if ((IS_XSLT_ELEM(cur)) && (!(IS_XSLT_NAME(cur, "param"))))
            break;
        cur = cur->next;
@@ -584,17 +852,6 @@ skip_children:
      * Browse the remaining of the template
      */
     while (cur != NULL) {
-       /*
-        * Remove Blank nodes found at this level.
-        */
-       if (IS_BLANK_NODE(cur)) {
-           xmlNodePtr blank = cur;
-
-            cur = cur->next;
-           xmlUnlinkNode(blank);
-           xmlFreeNode(blank);
-           continue;
-       }
        if ((IS_XSLT_ELEM(cur)) && (IS_XSLT_NAME(cur, "param"))) {
            xmlNodePtr param = cur;
 
@@ -745,10 +1002,6 @@ xsltParseStylesheetTop(xsltStylesheetPtr style, xmlNodePtr top) {
        cur = cur->next;
     }
     while (cur != NULL) {
-       if (IS_BLANK_NODE(cur)) {
-            cur = cur->next;
-           continue;
-       }
        if (!(IS_XSLT_ELEM(cur))) {
 #ifdef DEBUG_PARSING
            xsltGenericDebug(xsltGenericDebugContext,
@@ -772,9 +1025,9 @@ xsltParseStylesheetTop(xsltStylesheetPtr style, xmlNodePtr top) {
         } else if (IS_XSLT_NAME(cur, "key")) {
            TODO /* Handle key */
         } else if (IS_XSLT_NAME(cur, "decimal-format")) {
-           TODO /* Handle decimal-format */
+           xsltParseStylesheetDecimalFormat(style, cur);
         } else if (IS_XSLT_NAME(cur, "attribute-set")) {
-           TODO /* Handle attribute-set */
+           xsltParseStylesheetAttributeSet(style, cur);
         } else if (IS_XSLT_NAME(cur, "variable")) {
            xsltParseGlobalVariable(style, cur);
         } else if (IS_XSLT_NAME(cur, "param")) {
@@ -819,9 +1072,10 @@ xsltParseStylesheetDoc(xmlDocPtr doc) {
     ret = xsltNewStylesheet();
     if (ret == NULL)
        return(NULL);
-
+    
     /*
-     * First step, locate the xsl:stylesheet element and the
+     * First steps, remove blank nodes,
+     * locate the xsl:stylesheet element and the
      * namespace declaration.
      */
     cur = xmlDocGetRootElement(doc);
@@ -833,6 +1087,7 @@ xsltParseStylesheetDoc(xmlDocPtr doc) {
     }
 
     ret->doc = doc;
+    xsltParseRemoveBlanks(ret);
     if ((IS_XSLT_ELEM(cur)) && 
        ((IS_XSLT_NAME(cur, "stylesheet")) ||
         (IS_XSLT_NAME(cur, "transform")))) {
index b4f7c0b..ad959e2 100644 (file)
@@ -62,6 +62,27 @@ struct _xsltTemplate {
 };
 
 /*
+ * Data structure of decimal-format
+ */
+typedef struct _xsltDecimalFormat {
+    struct _xsltDecimalFormat *next; /* chained list */
+    xmlChar *name;
+    /* Used for interpretation of pattern */
+    xmlChar *digit;
+    xmlChar *patternSeparator;
+    /* May appear in result */
+    xmlChar *minusSign;
+    xmlChar *infinity;
+    xmlChar *noNumber; /* Not-a-number */
+    /* Used for interpretation of pattern and may appear in result */
+    xmlChar *decimalPoint;
+    xmlChar *grouping;
+    xmlChar *percent;
+    xmlChar *permille;
+    xmlChar *zeroDigit;
+} xsltDecimalFormat, *xsltDecimalFormatPtr;
+
+/*
  * 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.
@@ -107,6 +128,11 @@ struct _xsltStylesheet {
     xmlHashTablePtr nsAliases; /* the namespace alias hash tables */
 
     /*
+     * Attribute sets
+     */
+    xmlHashTablePtr attributeSets;/* the attribute sets hash tables */
+
+    /*
      * Output related stuff.
      */
     xmlChar *method;           /* the output method */
@@ -114,6 +140,9 @@ struct _xsltStylesheet {
     xmlChar *version;          /* version string */
     xmlChar *encoding;         /* encoding string */
     int omitXmlDeclaration;     /* omit-xml-declaration = "yes" | "no" */
+
+    /* Number formatting */
+    xsltDecimalFormatPtr decimalFormat;
     int standalone;             /* standalone = "yes" | "no" */
     xmlChar *doctypePublic;     /* doctype-public string */
     xmlChar *doctypeSystem;     /* doctype-system string */
@@ -163,6 +192,8 @@ struct _xsltTransformContext {
 
 /*
  * Functions associated to the internal types
+xsltDecimalFormatPtr   xsltDecimalFormatGetByName(xsltStylesheetPtr sheet,
+                                                  xmlChar *name);
  */
 xsltStylesheetPtr      xsltParseStylesheetFile (const xmlChar* filename);
 void                   xsltFreeStylesheet      (xsltStylesheetPtr sheet);
index 26fe50a..121818a 100644 (file)
@@ -1,5 +1,5 @@
 ## Process this file with automake to produce Makefile.in
 
-SUBDIRS=REC1 REC2
+SUBDIRS=REC1 REC2 numbers
 
 test tests: all
diff --git a/tests/numbers/Makefile.am b/tests/numbers/Makefile.am
new file mode 100644 (file)
index 0000000..03d230f
--- /dev/null
@@ -0,0 +1,16 @@
+## Process this file with automake to produce Makefile.in
+
+$(top_builddir)/libxslt/xsltproc:
+       @(cd ../../libxslt ; make xsltproc)
+
+EXTRA_DIST = doc.xsl doc.xml result.xml
+
+all: test
+
+test tests: $(top_builddir)/libxslt/xsltproc
+       @(rm -f .memdump ; touch .memdump)
+       @($(top_builddir)/libxslt/xsltproc format-number.xsl format-number.xml > format-number.res ; \
+       diff format-number.out format-number.res ; \
+       grep "MORY ALLO" .memdump  | grep -v "MEMORY ALLOCATED : 0";\
+       rm -f format-number.res)
+
diff --git a/tests/numbers/format-number.out b/tests/numbers/format-number.out
new file mode 100644 (file)
index 0000000..6395ae8
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<pi>
+  one prefix3.14suffix
+  two _-3.14_
+  three _-003.1415_
+  four _(3.1)_
+  five prefix3*14suffix</pi>
diff --git a/tests/numbers/format-number.xml b/tests/numbers/format-number.xml
new file mode 100644 (file)
index 0000000..0ca0212
--- /dev/null
@@ -0,0 +1,4 @@
+<functions>
+  <pi>3.1415</pi>
+  <negpi>-3.1415</negpi>
+</functions>
diff --git a/tests/numbers/format-number.xsl b/tests/numbers/format-number.xsl
new file mode 100644 (file)
index 0000000..4c34ce8
--- /dev/null
@@ -0,0 +1,25 @@
+<xsl:stylesheet version="1.0"
+             xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+
+<xsl:output
+ method="xml"
+ indent="yes"
+ encoding="iso-8859-1"
+/>
+
+<xsl:decimal-format
+ name = "special"
+ decimal-separator = "*"
+/>
+
+<xsl:template match="functions">
+ <pi>
+  one <xsl:value-of select="format-number(pi, 'prefix#,#,###.##suffix')"/>
+  two <xsl:value-of select="format-number(negpi, '_#,#,###.##_')"/>
+  three <xsl:value-of select="format-number(negpi, '_#,#,000.000##_')"/>
+  four <xsl:value-of select="format-number(negpi, '_#.#_;_(#.#)_')"/>
+  five <xsl:value-of select="format-number(pi, 'prefix#,#,###*##suffix','special')"/>
+ </pi>
+</xsl:template>
+
+</xsl:stylesheet>