Re: [xslt] Patch to implement date:sum(node-set)
- From: Derek Poon <dpoon ocf berkeley edu>
- To: The Gnome XSLT library mailing-list <xslt gnome org>
- Subject: Re: [xslt] Patch to implement date:sum(node-set)
- Date: Thu, 23 Sep 2004 02:04:28 +0200
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]