[xslt] [patch] implement exslt date:sum



This patch implements "date:sum" 
per http://www.exslt.org/date/functions/sum/index.html

Its largely based on code from AddDuration and math.c for 
extension functions using node sets.

Comments appreciated!

jr

example xsl:

<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:template match="editor">
    sum=<xsl:value-of select="date:sum(plaintext/date)"/>
  </xsl:template>

</xsl:stylesheet>

with xml file:

<?xml version="1.0" encoding="iso-8859-1"?>
<editor>
<plaintext>
<date>P0Y0M2DT0H4M5.0S</date>
<date>P0Y0M2DT0H2M6.0S</date>
</plaintext>
</editor>

produces: 

sum=P4DT6M11S

Index: libexslt/date.c
===================================================================
RCS file: /cvs/gnome/libxslt/libexslt/date.c,v
retrieving revision 1.25
diff -u -r1.25 date.c
--- libexslt/date.c	16 May 2004 22:09:35 -0000	1.25
+++ libexslt/date.c	4 Aug 2004 19:51:52 -0000
@@ -2672,6 +2672,99 @@
 }
 
 /**
+ * exsltDateSumFunction:
+ * @ns:      a node set of duration strings
+ *
+ * The date:sum function adds a set of durations together. 
+ * The string values of the nodes in the node set passed as an argument 
+ * are interpreted as durations and added together as if using the 
+ * date:add-duration function. (from exslt.org)
+ *
+ * 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 void
+exsltDateSumFunction (xmlXPathParserContextPtr ctxt, int nargs)
+{
+				xmlNodeSetPtr ns;
+				void *user = NULL;
+				xmlChar *tmp;
+				exsltDateValPtr x, total;
+				xmlChar			*ret;		
+				long carry;
+				int i;
+
+				if (nargs != 1) {
+								xmlXPathSetArityError(ctxt);
+								return;
+				}
+
+				/* We need to delay the freeing of value->user */
+				if ((ctxt->value != NULL) && ctxt->value->boolval != 0) {
+								user = ctxt->value->user;
+								ctxt->value->boolval = 0;
+								ctxt->value->user = NULL;
+				}
+
+				ns = xmlXPathPopNodeSet(ctxt);
+				if (xmlXPathCheckError(ctxt))
+								return;
+
+				if ((ns == NULL) || (ns->nodeNr == 0))
+								return;
+
+				total = exsltDateCreateDate(XS_DURATION);
+
+				for (i = 0; i < ns->nodeNr; i++) {
+
+								tmp = xmlXPathCastNodeToString(ns->nodeTab[i]);
+								if (tmp == NULL)
+												return;
+
+								x = exsltDateParseDuration(tmp);
+								if (x == NULL) {
+												xmlFree(tmp);
+												return;
+								}
+
+								/* months */
+								total->value.dur.mon += x->value.dur.mon;
+
+								/* seconds */
+								total->value.dur.sec += x->value.dur.sec;
+								carry = (long)FQUOTIENT(total->value.dur.sec, SECS_PER_DAY);
+								if (total->value.dur.sec != 0.0) {
+												total->value.dur.sec = MODULO(total->value.dur.sec, SECS_PER_DAY);
+								}
+
+								/* days */
+								total->value.dur.day += x->value.dur.day + carry;
+
+								exsltDateFreeDate(x);
+								xmlFree(tmp);
+				}
+
+				ret = exsltDateFormatDuration(&(total->value.dur));
+				exsltDateFreeDate(total);
+
+				xmlXPathFreeNodeSet(ns);
+				if (user != NULL)
+								xmlFreeNodeList((xmlNodePtr)user);
+
+				if (ret == NULL)
+								xmlXPathReturnEmptyString(ctxt);
+				else
+								xmlXPathReturnString(ctxt, ret);
+}
+
+/**
  * exsltDateSeconds:
  * @dateTime: a date/time string
  *
@@ -3496,78 +3589,81 @@
 void
 exsltDateRegister(void)
 {
+    xsltRegisterExtModuleFunction((const xmlChar *) "add",
+                            (const xmlChar *) EXSLT_DATE_NAMESPACE,
+                            exsltDateAddFunction);
+    xsltRegisterExtModuleFunction((const xmlChar *) "add-duration",
+                            (const xmlChar *) EXSLT_DATE_NAMESPACE,
+                            exsltDateAddDurationFunction);
+    xsltRegisterExtModuleFunction((const xmlChar *) "date",
+			  (const xmlChar *) EXSLT_DATE_NAMESPACE,
+			  exsltDateDateFunction);
 #ifdef WITH_TIME
     xsltRegisterExtModuleFunction((const xmlChar *) "date-time",
 			  (const xmlChar *) EXSLT_DATE_NAMESPACE,
 			  exsltDateDateTimeFunction);
 #endif
-    xsltRegisterExtModuleFunction((const xmlChar *) "date",
-			  (const xmlChar *) EXSLT_DATE_NAMESPACE,
-			  exsltDateDateFunction);
-    xsltRegisterExtModuleFunction((const xmlChar *) "time",
-			  (const xmlChar *) EXSLT_DATE_NAMESPACE,
-			  exsltDateTimeFunction);
-    xsltRegisterExtModuleFunction((const xmlChar *) "year",
-			  (const xmlChar *) EXSLT_DATE_NAMESPACE,
-			  exsltDateYearFunction);
-    xsltRegisterExtModuleFunction((const xmlChar *) "leap-year",
-			  (const xmlChar *) EXSLT_DATE_NAMESPACE,
-			  exsltDateLeapYearFunction);
-    xsltRegisterExtModuleFunction((const xmlChar *) "month-in-year",
-			  (const xmlChar *) EXSLT_DATE_NAMESPACE,
-			  exsltDateMonthInYearFunction);
-    xsltRegisterExtModuleFunction((const xmlChar *) "month-name",
-			  (const xmlChar *) EXSLT_DATE_NAMESPACE,
-			  exsltDateMonthNameFunction);
-    xsltRegisterExtModuleFunction((const xmlChar *) "month-abbreviation",
-			  (const xmlChar *) EXSLT_DATE_NAMESPACE,
-			  exsltDateMonthAbbreviationFunction);
-    xsltRegisterExtModuleFunction((const xmlChar *) "week-in-year",
-			  (const xmlChar *) EXSLT_DATE_NAMESPACE,
-			  exsltDateWeekInYearFunction);
-    xsltRegisterExtModuleFunction((const xmlChar *) "week-in-month",
-			  (const xmlChar *) EXSLT_DATE_NAMESPACE,
-			  exsltDateWeekInMonthFunction);
-    xsltRegisterExtModuleFunction((const xmlChar *) "day-in-year",
-			  (const xmlChar *) EXSLT_DATE_NAMESPACE,
-			  exsltDateDayInYearFunction);
+    xsltRegisterExtModuleFunction((const xmlChar *) "day-abbreviation",
+                            (const xmlChar *) EXSLT_DATE_NAMESPACE,
+                            exsltDateDayAbbreviationFunction);
     xsltRegisterExtModuleFunction((const xmlChar *) "day-in-month",
                             (const xmlChar *) EXSLT_DATE_NAMESPACE,
                             exsltDateDayInMonthFunction);
-    xsltRegisterExtModuleFunction((const xmlChar *) "day-of-week-in-month",
-                            (const xmlChar *) EXSLT_DATE_NAMESPACE,
-                            exsltDateDayOfWeekInMonthFunction);
     xsltRegisterExtModuleFunction((const xmlChar *) "day-in-week",
                             (const xmlChar *) EXSLT_DATE_NAMESPACE,
                             exsltDateDayInWeekFunction);
+    xsltRegisterExtModuleFunction((const xmlChar *) "day-in-year",
+			  (const xmlChar *) EXSLT_DATE_NAMESPACE,
+			  exsltDateDayInYearFunction);
     xsltRegisterExtModuleFunction((const xmlChar *) "day-name",
                             (const xmlChar *) EXSLT_DATE_NAMESPACE,
                             exsltDateDayNameFunction);
-    xsltRegisterExtModuleFunction((const xmlChar *) "day-abbreviation",
+    xsltRegisterExtModuleFunction((const xmlChar *) "day-of-week-in-month",
                             (const xmlChar *) EXSLT_DATE_NAMESPACE,
-                            exsltDateDayAbbreviationFunction);
+                            exsltDateDayOfWeekInMonthFunction);
+    xsltRegisterExtModuleFunction((const xmlChar *) "difference",
+                            (const xmlChar *) EXSLT_DATE_NAMESPACE,
+                            exsltDateDifferenceFunction);
+    xsltRegisterExtModuleFunction((const xmlChar *) "duration",
+                            (const xmlChar *) EXSLT_DATE_NAMESPACE,
+                            exsltDateDurationFunction);
     xsltRegisterExtModuleFunction((const xmlChar *) "hour-in-day",
                             (const xmlChar *) EXSLT_DATE_NAMESPACE,
                             exsltDateHourInDayFunction);
+    xsltRegisterExtModuleFunction((const xmlChar *) "leap-year",
+			  (const xmlChar *) EXSLT_DATE_NAMESPACE,
+			  exsltDateLeapYearFunction);
     xsltRegisterExtModuleFunction((const xmlChar *) "minute-in-hour",
                             (const xmlChar *) EXSLT_DATE_NAMESPACE,
                             exsltDateMinuteInHourFunction);
+    xsltRegisterExtModuleFunction((const xmlChar *) "month-abbreviation",
+			  (const xmlChar *) EXSLT_DATE_NAMESPACE,
+			  exsltDateMonthAbbreviationFunction);
+    xsltRegisterExtModuleFunction((const xmlChar *) "month-in-year",
+			  (const xmlChar *) EXSLT_DATE_NAMESPACE,
+			  exsltDateMonthInYearFunction);
+    xsltRegisterExtModuleFunction((const xmlChar *) "month-name",
+			  (const xmlChar *) EXSLT_DATE_NAMESPACE,
+			  exsltDateMonthNameFunction);
     xsltRegisterExtModuleFunction((const xmlChar *) "second-in-minute",
                             (const xmlChar *) EXSLT_DATE_NAMESPACE,
                             exsltDateSecondInMinuteFunction);
     xsltRegisterExtModuleFunction((const xmlChar *) "seconds",
                             (const xmlChar *) EXSLT_DATE_NAMESPACE,
                             exsltDateSecondsFunction);
-    xsltRegisterExtModuleFunction((const xmlChar *) "add",
+    xsltRegisterExtModuleFunction((const xmlChar *) "sum",
                             (const xmlChar *) EXSLT_DATE_NAMESPACE,
-                            exsltDateAddFunction);
-    xsltRegisterExtModuleFunction((const xmlChar *) "add-duration",
-                            (const xmlChar *) EXSLT_DATE_NAMESPACE,
-                            exsltDateAddDurationFunction);
-    xsltRegisterExtModuleFunction((const xmlChar *) "difference",
-                            (const xmlChar *) EXSLT_DATE_NAMESPACE,
-                            exsltDateDifferenceFunction);
-    xsltRegisterExtModuleFunction((const xmlChar *) "duration",
-                            (const xmlChar *) EXSLT_DATE_NAMESPACE,
-                            exsltDateDurationFunction);
+                            exsltDateSumFunction);
+    xsltRegisterExtModuleFunction((const xmlChar *) "time",
+			  (const xmlChar *) EXSLT_DATE_NAMESPACE,
+			  exsltDateTimeFunction);
+    xsltRegisterExtModuleFunction((const xmlChar *) "week-in-month",
+			  (const xmlChar *) EXSLT_DATE_NAMESPACE,
+			  exsltDateWeekInMonthFunction);
+    xsltRegisterExtModuleFunction((const xmlChar *) "week-in-year",
+			  (const xmlChar *) EXSLT_DATE_NAMESPACE,
+			  exsltDateWeekInYearFunction);
+    xsltRegisterExtModuleFunction((const xmlChar *) "year",
+			  (const xmlChar *) EXSLT_DATE_NAMESPACE,
+			  exsltDateYearFunction);
 }


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