Re: [xslt] Patch to implement date:sum(node-set)



On Wed, 2004-09-22 at 15:12, Daniel Veillard wrote:

>   Doesn't look bad, but can you provide a test (xsl + xml) to add
> to tests/exslt/date/ regression tests too ? It helps a lot,


Daniel,

As you requested, I wrote some unit tests for the new date:sum
function.  Indeed, I found some bugs in the corner cases, so please
discard my previous patch and use the one below instead.

In my opinion, the sum of an empty node-set ought to be a valid
zero-length duration.  But the spec says that it must return an empty
string; the implementation below adheres to the spec.

Derek


--- libxslt-1.1.5/libexslt/date.c.datesum	2004-03-05 11:58:29.000000000 +0100
+++ libxslt-1.1.5/libexslt/date.c	2004-09-23 00:34:42.675614152 +0200
@@ -2665,6 +2665,62 @@
 }
 
 /**
+ * exsltDateSum:
+ * @ns:        set of nodes to be summed as durations
+ *
+ * Implements the date:sum (node-set) function which returns
+ * the duration resulting from adding all of the durations in the node set.
+ * Each node is a string in the format defined for xs:duration
+ * in [3.2.6 duration] of [XML Schema Part 2: Datatypes]. If any
+ * argument is not in this format, the function returns an empty string
+ * (''). 
+ * The return value is a string in the format defined for xs:duration
+ * in [3.2.6 duration] of [XML Schema Part 2: Datatypes]. 
+ * The durations can usually be added by summing the numbers given for
+ * each of the components in the durations. However, if the durations
+ * are differently signed, then this sometimes results in durations
+ * that are impossible to express in this syntax (e.g. 'P1M' + '-P1D').
+ * In these cases, the function returns an empty string (''). 
+ *
+ * Returns duration string or NULL.
+ */
+static xmlChar *
+exsltDateSum (xmlNodeSetPtr ns) {
+    exsltDateValPtr cumul, oldcumul, xdur;
+    xmlChar *ret, *xstr;
+    int i;
+
+    if (xmlXPathNodeSetIsEmpty(ns))
+    	return NULL;
+
+    cumul = exsltDateCreateDate(XS_DURATION);
+    if (cumul == NULL)
+	return NULL;
+
+    for (i = 0; i < ns->nodeNr; i++) {
+	xstr = xmlXPathCastNodeToString(ns->nodeTab[i]);
+	xdur = exsltDateParseDuration(xstr);
+	if (xdur == NULL) {
+	    exsltDateFreeDate(cumul);
+	    return NULL;
+	}
+
+	oldcumul = cumul;
+	cumul = _exsltDateAddDuration(oldcumul, xdur);
+	exsltDateFreeDate(oldcumul);
+
+	/* Invalid duration encountered */
+	if (cumul == NULL) {
+	    return NULL;
+	}
+    }
+
+    ret = exsltDateFormatDuration(&(cumul->value.dur));
+    exsltDateFreeDate(cumul);
+    return ret;
+}
+
+/**
  * exsltDateSeconds:
  * @dateTime: a date/time string
  *
@@ -3410,6 +3466,38 @@
 }
 
 /**
+ * exsltDateSumFunction:
+ * @ctxt:  an XPath parser context
+ * @nargs:  the number of arguments
+ *
+ * Wraps exsltDateSum() for use by the XPath processor.
+ */
+static void
+exsltDateSumFunction (xmlXPathParserContextPtr ctxt, int nargs) {
+    xmlNodeSetPtr ns;
+    xmlChar *ret;
+
+    if (nargs != 1) {
+	xmlXPathSetArityError(ctxt);
+	return;
+    }
+
+    ns = xmlXPathPopNodeSet(ctxt);
+    if (xmlXPathCheckError(ctxt)) {
+	xmlXPathSetTypeError(ctxt);
+	return;
+    }
+
+    ret = exsltDateSum(ns);
+    xmlXPathFreeNodeSet(ns);
+
+    if (ret == NULL)
+	xmlXPathReturnEmptyString(ctxt);
+    else
+    	xmlXPathReturnString(ctxt, ret);
+}
+
+/**
  * exsltDateDifferenceFunction:
  * @ctxt:  an XPath parser context
  * @nargs:  the number of arguments
@@ -3557,6 +3645,9 @@
     xsltRegisterExtModuleFunction((const xmlChar *) "add-duration",
                             (const xmlChar *) EXSLT_DATE_NAMESPACE,
                             exsltDateAddDurationFunction);
+    xsltRegisterExtModuleFunction((const xmlChar *) "sum",
+                            (const xmlChar *) EXSLT_DATE_NAMESPACE,
+                            exsltDateSumFunction);
     xsltRegisterExtModuleFunction((const xmlChar *) "difference",
                             (const xmlChar *) EXSLT_DATE_NAMESPACE,
                             exsltDateDifferenceFunction);
--- libxslt-1.1.5/tests/exslt/date/Makefile.in.datesum	2004-03-23 13:41:42.000000000 +0100
+++ libxslt-1.1.5/tests/exslt/date/Makefile.in	2004-09-23 01:39:17.139606096 +0200
@@ -212,6 +212,8 @@
 	add.2.out	add.2.xml	add.2.xsl	\
 	add-duration.1.out add-duration.1.xml add-duration.1.xsl \
 	add-duration.2.out add-duration.2.xml add-duration.2.xsl \
+	sum.1.out	sum.1.xml	sum.1.xsl	\
+	sum.2.out	sum.2.xml	sum.2.xsl	\
 	difference.1.out difference.1.xml difference.1.xsl	\
 	difference.2.out difference.2.xml difference.2.xsl	\
 	duration.1.out	duration.1.xml	duration.1.xsl	\
--- libxslt-1.1.5/tests/exslt/date/Makefile.am.datesum	2004-03-22 15:17:21.000000000 +0100
+++ libxslt-1.1.5/tests/exslt/date/Makefile.am	2004-09-22 23:58:24.976674712 +0200
@@ -25,6 +25,8 @@
 	add.2.out	add.2.xml	add.2.xsl	\
 	add-duration.1.out add-duration.1.xml add-duration.1.xsl \
 	add-duration.2.out add-duration.2.xml add-duration.2.xsl \
+	sum.1.out	sum.1.xml	sum.1.xsl	\
+	sum.2.out	sum.2.xml	sum.2.xsl	\
 	difference.1.out difference.1.xml difference.1.xsl	\
 	difference.2.out difference.2.xml difference.2.xsl	\
 	duration.1.out	duration.1.xml	duration.1.xsl	\
--- libxslt-1.1.5/tests/exslt/date/sum.1.xml.datesum	2004-09-23 00:00:09.504784024 +0200
+++ libxslt-1.1.5/tests/exslt/date/sum.1.xml	2004-09-23 01:35:09.619234912 +0200
@@ -0,0 +1,63 @@
+<?xml version="1.0"?>
+<page>
+  <!-- valid date/times -->
+  <sum>
+    <date dur='PT1M'/>
+    <date dur='PT2M'/>
+  </sum>
+
+  <sum>
+    <date dur='P1DT2H'/>
+    <date dur='PT3M'/>
+    <date dur='PT4S'/>
+  </sum>
+
+  <sum>
+    <date dur='PT20M'/>
+    <date dur='PT20M'/>
+    <date dur='PT20M'/>
+  </sum>
+
+  <sum>
+    <date dur='PT01S'/>
+    <date dur='PT02S'/>
+    <date dur='PT04S'/>
+    <date dur='PT8S'/>
+    <date dur='PT16S'/>
+    <date dur='PT32S'/>
+  </sum>
+
+  <!-- Base case: sum of 1 node -->
+  <sum>
+    <date dur='P1M'/>
+  </sum>
+
+  <!-- Non-normalized input -->
+  <sum>
+    <date dur='PT70M'/>
+  </sum>
+
+  <sum>
+    <date dur='PT70M'/>
+    <date dur='P13M'/>
+  </sum>
+
+  <!-- Negative durations -->
+  <sum>
+    <date dur='PT70M'/>
+    <date dur='-PT30M'/>
+  </sum>
+
+  <sum>
+    <date dur='PT1H10M'/>
+    <date dur='-PT30M'/>
+    <date dur='-PT30S'/>
+  </sum>
+
+  <!-- Zero sum -->
+  <sum>
+    <date dur='PT1M'/>
+    <date dur='-PT1M'/>
+  </sum>
+
+</page>
--- libxslt-1.1.5/tests/exslt/date/sum.1.xsl.datesum	2004-09-23 00:04:18.694901368 +0200
+++ libxslt-1.1.5/tests/exslt/date/sum.1.xsl	2004-09-23 01:42:06.243898336 +0200
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0" 
+                xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
+                xmlns:date="http://exslt.org/dates-and-times";
+                extension-element-prefixes="date">
+
+<xsl:output method="text"/>
+<xsl:strip-space elements="*"/>
+
+<xsl:template match="sum">
+sum    : <xsl:apply-templates select="date"/>
+result : <xsl:value-of select="date:sum(date/@dur)"/>
+</xsl:template>
+
+<xsl:template match="date">
+  <xsl:if test="position() != 1"> + </xsl:if>
+  <xsl:value-of select="@dur"/>
+</xsl:template>
+
+</xsl:stylesheet>
--- libxslt-1.1.5/tests/exslt/date/sum.1.out.datesum	2004-09-23 01:41:08.437686216 +0200
+++ libxslt-1.1.5/tests/exslt/date/sum.1.out	2004-09-23 01:35:12.123854152 +0200
@@ -0,0 +1,21 @@
+
+sum    : PT1M + PT2M
+result : PT3M
+sum    : P1DT2H + PT3M + PT4S
+result : P1DT2H3M4S
+sum    : PT20M + PT20M + PT20M
+result : PT1H
+sum    : PT01S + PT02S + PT04S + PT8S + PT16S + PT32S
+result : PT1M3S
+sum    : P1M
+result : P1M
+sum    : PT70M
+result : PT1H10M
+sum    : PT70M + P13M
+result : P1Y1MT1H10M
+sum    : PT70M + -PT30M
+result : PT40M
+sum    : PT1H10M + -PT30M + -PT30S
+result : PT39M30S
+sum    : PT1M + -PT1M
+result : P0D
\ No newline at end of file
--- libxslt-1.1.5/tests/exslt/date/sum.2.xsl.datesum	2004-09-23 00:19:29.343461744 +0200
+++ libxslt-1.1.5/tests/exslt/date/sum.2.xsl	2004-09-23 01:42:09.548395976 +0200
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0" 
+                xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
+                xmlns:date="http://exslt.org/dates-and-times";
+                extension-element-prefixes="date">
+
+<xsl:output method="text"/>
+<xsl:strip-space elements="*"/>
+
+<xsl:template match="sum">
+sum    : <xsl:apply-templates select="date"/>
+result : <xsl:value-of select="date:sum(date/@dur)"/>
+</xsl:template>
+
+<xsl:template match="date">
+  <xsl:if test="position() != 1"> + </xsl:if>
+  <xsl:value-of select="@dur"/>
+</xsl:template>
+
+</xsl:stylesheet>
--- libxslt-1.1.5/tests/exslt/date/sum.2.xml.datesum	2004-09-23 00:37:24.024085456 +0200
+++ libxslt-1.1.5/tests/exslt/date/sum.2.xml	2004-09-23 01:28:15.144244688 +0200
@@ -0,0 +1,55 @@
+<?xml version="1.0"?>
+<page>
+  <!-- sum of empty node-set -->
+  <sum/>
+
+  <!-- According to http://exslt.org/date/functions/add-duration/
+       add-duration should fail when a sum involving negative durations
+       involve borrowing -->
+  <sum>
+    <date dur='P1M'/>
+    <date dur='-P1D'/>
+  </sum>
+
+  <sum>
+    <date dur='P1M'/>
+    <date dur='-P1D'/>
+    <date dur='P1D'/>
+  </sum>
+
+  <!-- ... but switching the order should make it work -->
+  <sum>
+    <date dur='P1M'/>
+    <date dur='P1D'/>
+    <date dur='-P1D'/>
+  </sum>
+
+  <!-- Empty durations -->
+  <sum>
+    <date dur=''/>
+  </sum>
+
+  <sum>
+    <date dur=''/>
+    <date dur='P45S'/>
+  </sum>
+
+  <!-- Invalid durations -->
+  <sum>
+    <date dur='2004-09-20'/>
+  </sum>
+
+  <sum>
+    <date dur='1H'/>
+  </sum>
+
+  <sum>
+    <date dur='2004-09-22'/>
+    <date dur='P1D'/>
+  </sum>
+
+  <sum>
+    <date dur='P2D'/>
+    <date dur='--P1D'/>
+  </sum>
+</page>



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