[libxslt] Make xsl:decimal-format work with namespaces



commit 38d4a907541379e7c3381324776fcb9f0c4324ee
Author: Nick Wellnhofer <wellnhofer aevum de>
Date:   Tue Feb 7 15:47:27 2017 +0100

    Make xsl:decimal-format work with namespaces
    
    Fixes bug #778170:
    
    https://bugzilla.gnome.org/show_bug.cgi?id=778170

 doc/symbols.xml           |    1 +
 libxslt/functions.c       |   23 +++++++++++++--
 libxslt/xslt.c            |   66 ++++++++++++++++++++++++++++++++++++++++-----
 libxslt/xsltInternals.h   |    5 +++
 tests/docs/bug-202.xml    |    1 +
 tests/docs/bug-203.xml    |    1 +
 tests/docs/bug-204.xml    |    1 +
 tests/docs/bug-205.xml    |    1 +
 tests/general/bug-202.err |    2 +
 tests/general/bug-202.xsl |    5 +++
 tests/general/bug-203.err |    1 +
 tests/general/bug-203.xsl |    5 +++
 tests/general/bug-204.err |    2 +
 tests/general/bug-204.xsl |    6 ++++
 tests/general/bug-205.out |    2 +
 tests/general/bug-205.xsl |   10 +++++++
 16 files changed, 122 insertions(+), 10 deletions(-)
---
diff --git a/doc/symbols.xml b/doc/symbols.xml
index 1499909..49d9b0a 100644
--- a/doc/symbols.xml
+++ b/doc/symbols.xml
@@ -316,5 +316,6 @@
   </release>
   <release version="1.1.30">
     <symbol file="xsltInternals">xsltFlagRVTs</symbol>
+    <symbol file="xsltInternals">xsltDecimalFormatGetByQName</symbol>
   </release>
 </symbols>
diff --git a/libxslt/functions.c b/libxslt/functions.c
index ec22203..5cc9da5 100644
--- a/libxslt/functions.c
+++ b/libxslt/functions.c
@@ -603,12 +603,15 @@ xsltFormatNumberFunction(xmlXPathParserContextPtr ctxt, int nargs)
     xmlXPathObjectPtr formatObj = NULL;
     xmlXPathObjectPtr decimalObj = NULL;
     xsltStylesheetPtr sheet;
-    xsltDecimalFormatPtr formatValues;
+    xsltDecimalFormatPtr formatValues = NULL;
     xmlChar *result;
+    const xmlChar *ncname;
+    const xmlChar *prefix = NULL;
+    const xmlChar *nsUri = NULL;
     xsltTransformContextPtr tctxt;
 
     tctxt = xsltXPathGetTransformContext(ctxt);
-    if (tctxt == NULL)
+    if ((tctxt == NULL) || (tctxt->inst == NULL))
        return;
     sheet = tctxt->style;
     if (sheet == NULL)
@@ -619,7 +622,21 @@ xsltFormatNumberFunction(xmlXPathParserContextPtr ctxt, int nargs)
     case 3:
        CAST_TO_STRING;
        decimalObj = valuePop(ctxt);
-       formatValues = xsltDecimalFormatGetByName(sheet, decimalObj->stringval);
+        ncname = xsltSplitQName(sheet->dict, decimalObj->stringval, &prefix);
+        if (prefix != NULL) {
+            xmlNsPtr ns = xmlSearchNs(tctxt->inst->doc, tctxt->inst, prefix);
+            if (ns == NULL) {
+                xsltTransformError(tctxt, NULL, NULL,
+                    "format-number : No namespace found for QName '%s:%s'\n",
+                    prefix, ncname);
+                sheet->errors++;
+                ncname = NULL;
+            }
+            nsUri = ns->href;
+        }
+        if (ncname != NULL) {
+           formatValues = xsltDecimalFormatGetByQName(sheet, nsUri, ncname);
+        }
        if (formatValues == NULL) {
            xsltTransformError(tctxt, NULL, NULL,
                    "format-number() : undeclared decimal format '%s'\n",
diff --git a/libxslt/xslt.c b/libxslt/xslt.c
index d41a98d..b367f9e 100644
--- a/libxslt/xslt.c
+++ b/libxslt/xslt.c
@@ -275,7 +275,7 @@ xsltIsBlank(xmlChar *str) {
  *                                                                     *
  ************************************************************************/
 static xsltDecimalFormatPtr
-xsltNewDecimalFormat(xmlChar *name)
+xsltNewDecimalFormat(const xmlChar *nsUri, xmlChar *name)
 {
     xsltDecimalFormatPtr self;
     /* UTF-8 for 0x2030 */
@@ -284,6 +284,7 @@ xsltNewDecimalFormat(xmlChar *name)
     self = xmlMalloc(sizeof(xsltDecimalFormat));
     if (self != NULL) {
        self->next = NULL;
+        self->nsUri = nsUri;
        self->name = name;
 
        /* Default values */
@@ -369,7 +370,39 @@ xsltDecimalFormatGetByName(xsltStylesheetPtr style, xmlChar *name)
        for (result = style->decimalFormat->next;
             result != NULL;
             result = result->next) {
-           if (xmlStrEqual(name, result->name))
+           if ((result->nsUri == NULL) && xmlStrEqual(name, result->name))
+               return result;
+       }
+       style = xsltNextImport(style);
+    }
+    return result;
+}
+
+/**
+ * xsltDecimalFormatGetByQName:
+ * @style: the XSLT stylesheet
+ * @nsUri: the namespace URI of the QName
+ * @name: the local part of the QName
+ *
+ * Find decimal-format by QName
+ *
+ * Returns the xsltDecimalFormatPtr
+ */
+xsltDecimalFormatPtr
+xsltDecimalFormatGetByQName(xsltStylesheetPtr style, const xmlChar *nsUri,
+                            const xmlChar *name)
+{
+    xsltDecimalFormatPtr result = NULL;
+
+    if (name == NULL)
+       return style->decimalFormat;
+
+    while (style != NULL) {
+       for (result = style->decimalFormat->next;
+            result != NULL;
+            result = result->next) {
+           if (xmlStrEqual(nsUri, result->nsUri) &&
+                xmlStrEqual(name, result->name))
                return result;
        }
        style = xsltNextImport(style);
@@ -747,7 +780,7 @@ xsltNewStylesheet(void) {
 
     ret->omitXmlDeclaration = -1;
     ret->standalone = -1;
-    ret->decimalFormat = xsltNewDecimalFormat(NULL);
+    ret->decimalFormat = xsltNewDecimalFormat(NULL, NULL);
     ret->indent = -1;
     ret->errors = 0;
     ret->warnings = 0;
@@ -1384,18 +1417,37 @@ xsltParseStylesheetDecimalFormat(xsltStylesheetPtr style, xmlNodePtr cur)
 
     prop = xmlGetNsProp(cur, BAD_CAST("name"), NULL);
     if (prop != NULL) {
-       format = xsltDecimalFormatGetByName(style, prop);
+        const xmlChar *nsUri;
+
+        if (xmlValidateQName(prop, 0) != 0) {
+            xsltTransformError(NULL, style, cur,
+                "xsl:decimal-format: Invalid QName '%s'.\n", prop);
+           style->warnings++;
+            xmlFree(prop);
+            return;
+        }
+        /*
+        * TODO: Don't use xsltGetQNameURI().
+        */
+        nsUri = xsltGetQNameURI(cur, &prop);
+        if (prop == NULL) {
+           style->warnings++;
+            return;
+        }
+       format = xsltDecimalFormatGetByQName(style, nsUri, prop);
        if (format != NULL) {
            xsltTransformError(NULL, style, cur,
         "xsltParseStylestyleDecimalFormat: %s already exists\n", prop);
-           if (style != NULL) style->warnings++;
+           style->warnings++;
+            xmlFree(prop);
            return;
        }
-       format = xsltNewDecimalFormat(prop);
+       format = xsltNewDecimalFormat(nsUri, prop);
        if (format == NULL) {
            xsltTransformError(NULL, style, cur,
      "xsltParseStylestyleDecimalFormat: failed creating new decimal-format\n");
-           if (style != NULL) style->errors++;
+           style->errors++;
+            xmlFree(prop);
            return;
        }
        /* Append new decimal-format structure */
diff --git a/libxslt/xsltInternals.h b/libxslt/xsltInternals.h
index 5ad1771..47125b3 100644
--- a/libxslt/xsltInternals.h
+++ b/libxslt/xsltInternals.h
@@ -324,6 +324,7 @@ struct _xsltDecimalFormat {
     xmlChar *percent;
     xmlChar *permille;
     xmlChar *zeroDigit;
+    const xmlChar *nsUri;
 };
 
 /**
@@ -1854,6 +1855,10 @@ XSLTPUBFUN void XSLTCALL
 XSLTPUBFUN xsltDecimalFormatPtr XSLTCALL
                        xsltDecimalFormatGetByName(xsltStylesheetPtr style,
                                                 xmlChar *name);
+XSLTPUBFUN xsltDecimalFormatPtr XSLTCALL
+                       xsltDecimalFormatGetByQName(xsltStylesheetPtr style,
+                                                const xmlChar *nsUri,
+                                                 const xmlChar *name);
 
 XSLTPUBFUN xsltStylesheetPtr XSLTCALL
                        xsltParseStylesheetProcess(xsltStylesheetPtr ret,
diff --git a/tests/docs/bug-202.xml b/tests/docs/bug-202.xml
new file mode 100644
index 0000000..69d62f2
--- /dev/null
+++ b/tests/docs/bug-202.xml
@@ -0,0 +1 @@
+<doc/>
diff --git a/tests/docs/bug-203.xml b/tests/docs/bug-203.xml
new file mode 100644
index 0000000..69d62f2
--- /dev/null
+++ b/tests/docs/bug-203.xml
@@ -0,0 +1 @@
+<doc/>
diff --git a/tests/docs/bug-204.xml b/tests/docs/bug-204.xml
new file mode 100644
index 0000000..69d62f2
--- /dev/null
+++ b/tests/docs/bug-204.xml
@@ -0,0 +1 @@
+<doc/>
diff --git a/tests/docs/bug-205.xml b/tests/docs/bug-205.xml
new file mode 100644
index 0000000..69d62f2
--- /dev/null
+++ b/tests/docs/bug-205.xml
@@ -0,0 +1 @@
+<doc/>
diff --git a/tests/general/bug-202.err b/tests/general/bug-202.err
new file mode 100644
index 0000000..f640148
--- /dev/null
+++ b/tests/general/bug-202.err
@@ -0,0 +1,2 @@
+compilation error: file ./bug-202.xsl line 3 element decimal-format
+xsl:decimal-format: Invalid QName 'testns:0format'.
diff --git a/tests/general/bug-202.out b/tests/general/bug-202.out
new file mode 100644
index 0000000..e69de29
diff --git a/tests/general/bug-202.xsl b/tests/general/bug-202.xsl
new file mode 100644
index 0000000..b8629f8
--- /dev/null
+++ b/tests/general/bug-202.xsl
@@ -0,0 +1,5 @@
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>
+
+<xsl:decimal-format xmlns:testns="urn:test:1" name="testns:0format" decimal-separator=","/>
+
+</xsl:stylesheet>
diff --git a/tests/general/bug-203.err b/tests/general/bug-203.err
new file mode 100644
index 0000000..0b18a5b
--- /dev/null
+++ b/tests/general/bug-203.err
@@ -0,0 +1 @@
+testns:format : no namespace bound to prefix testns
diff --git a/tests/general/bug-203.out b/tests/general/bug-203.out
new file mode 100644
index 0000000..e69de29
diff --git a/tests/general/bug-203.xsl b/tests/general/bug-203.xsl
new file mode 100644
index 0000000..f7f1f37
--- /dev/null
+++ b/tests/general/bug-203.xsl
@@ -0,0 +1,5 @@
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>
+
+<xsl:decimal-format name="testns:format" decimal-separator=","/>
+
+</xsl:stylesheet>
diff --git a/tests/general/bug-204.err b/tests/general/bug-204.err
new file mode 100644
index 0000000..dd9f40f
--- /dev/null
+++ b/tests/general/bug-204.err
@@ -0,0 +1,2 @@
+compilation error: file ./bug-204.xsl line 4 element decimal-format
+xsltParseStylestyleDecimalFormat: format already exists
diff --git a/tests/general/bug-204.out b/tests/general/bug-204.out
new file mode 100644
index 0000000..e69de29
diff --git a/tests/general/bug-204.xsl b/tests/general/bug-204.xsl
new file mode 100644
index 0000000..792af8a
--- /dev/null
+++ b/tests/general/bug-204.xsl
@@ -0,0 +1,6 @@
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>
+
+<xsl:decimal-format xmlns:testns="urn:test:1" name="testns:format" decimal-separator=","/>
+<xsl:decimal-format xmlns:newns="urn:test:1" name="newns:format" decimal-separator="."/>
+
+</xsl:stylesheet>
diff --git a/tests/general/bug-205.out b/tests/general/bug-205.out
new file mode 100644
index 0000000..cf63a11
--- /dev/null
+++ b/tests/general/bug-205.out
@@ -0,0 +1,2 @@
+<?xml version="1.0"?>
+123,00
diff --git a/tests/general/bug-205.xsl b/tests/general/bug-205.xsl
new file mode 100644
index 0000000..fa31965
--- /dev/null
+++ b/tests/general/bug-205.xsl
@@ -0,0 +1,10 @@
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>
+
+<xsl:decimal-format xmlns:testns="urn:test:1" name="testns:format" decimal-separator=","/>
+<xsl:decimal-format xmlns:testns="urn:test:2" name="testns:format" decimal-separator="."/>
+
+<xsl:template match="/" xmlns:newns="urn:test:1">
+    <xsl:value-of select="format-number(123, '0,00', 'newns:format')"/>
+</xsl:template>
+
+</xsl:stylesheet>


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]