Implement exslt-date:date-time (bug 603159) r=sicking
authorJulian Reschke <julian.reschke@gmx.de>
Tue, 26 Apr 2011 13:46:43 +0100 (2011-04-26)
changeset 69220 0abb7330c64ca7d61fa92e2e33a3117a5df452de
parent 69219 33992b8ef80ef8ce48db4149b687fb58c421960f
child 69222 65316725d03b17320542473d89362b5ccfd2f84b
child 69302 0de1cf797699bbb9e36e8955d309120eeed4194d
push id19887
push usersicking@mozilla.com
push dateMon, 09 May 2011 20:05:55 +0000 (2011-05-09)
treeherdermozilla-central@0abb7330c64c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssicking
bugs603159
milestone6.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Implement exslt-date:date-time (bug 603159) r=sicking
content/base/src/nsGkAtomList.h
content/xslt/src/xslt/txEXSLTFunctions.cpp
content/xslt/src/xslt/txStylesheetCompiler.cpp
content/xslt/tests/mochitest/Makefile.in
content/xslt/tests/mochitest/test_bug603159.html
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -258,16 +258,17 @@ GK_ATOM(count, "count")
 GK_ATOM(crop, "crop")
 GK_ATOM(curpos, "curpos")
 GK_ATOM(current, "current")
 GK_ATOM(currentloop, "currentloop")
 GK_ATOM(cycler, "cycler")
 GK_ATOM(data, "data")
 GK_ATOM(datalist, "datalist")
 GK_ATOM(dataType, "data-type")
+GK_ATOM(dateTime, "date-time")
 GK_ATOM(datasources, "datasources")
 GK_ATOM(datetime, "datetime")
 GK_ATOM(dblclick, "dblclick")
 GK_ATOM(dd, "dd")
 GK_ATOM(debug, "debug")
 GK_ATOM(decimalFormat, "decimal-format")
 GK_ATOM(decimalSeparator, "decimal-separator")
 GK_ATOM(deck, "deck")
--- a/content/xslt/src/xslt/txEXSLTFunctions.cpp
+++ b/content/xslt/src/xslt/txEXSLTFunctions.cpp
@@ -41,16 +41,17 @@
 #include "txAtoms.h"
 #include "txExecutionState.h"
 #include "txExpr.h"
 #include "txIXPathContext.h"
 #include "txNodeSet.h"
 #include "txOutputFormat.h"
 #include "txRtfHandler.h"
 #include "txXPathTreeWalker.h"
+#include "nsPrintfCString.h"
 
 #ifndef TX_EXE
 #include "nsComponentManagerUtils.h"
 #include "nsContentCID.h"
 #include "nsContentCreatorFunctions.h"
 #include "nsIContent.h"
 #include "nsIDOMDocumentFragment.h"
 #include "nsIDOMText.h"
@@ -220,16 +221,17 @@ struct txEXSLTFunctionDescriptor
     PRInt32 mNamespaceID;
     const char* mNamespaceURI;
 };
 
 static const char kEXSLTCommonNS[] = "http://exslt.org/common";
 static const char kEXSLTSetsNS[] = "http://exslt.org/sets";
 static const char kEXSLTStringsNS[] = "http://exslt.org/strings";
 static const char kEXSLTMathNS[] = "http://exslt.org/math";
+static const char kEXSLTDatesAndTimesNS[] = "http://exslt.org/dates-and-times";
 
 // The order of this table must be the same as the
 // txEXSLTFunctionCall::eType enum
 static txEXSLTFunctionDescriptor descriptTable[] =
 {
     { 1, 1, Expr::NODESET_RESULT, &txXSLTAtoms::nodeSet, 0, kEXSLTCommonNS }, // NODE_SET
     { 1, 1, Expr::STRING_RESULT,  &txXSLTAtoms::objectType, 0, kEXSLTCommonNS }, // OBJECT_TYPE
     { 2, 2, Expr::NODESET_RESULT, &txXSLTAtoms::difference, 0, kEXSLTSetsNS }, // DIFFERENCE
@@ -240,16 +242,17 @@ static txEXSLTFunctionDescriptor descrip
     { 2, 2, Expr::NODESET_RESULT, &txXSLTAtoms::trailing, 0, kEXSLTSetsNS }, // TRAILING
     { 1, 1, Expr::STRING_RESULT,  &txXSLTAtoms::concat, 0, kEXSLTStringsNS }, // CONCAT
     { 1, 2, Expr::STRING_RESULT,  &txXSLTAtoms::split, 0, kEXSLTStringsNS }, // SPLIT
     { 1, 2, Expr::STRING_RESULT,  &txXSLTAtoms::tokenize, 0, kEXSLTStringsNS }, // TOKENIZE
     { 1, 1, Expr::NUMBER_RESULT,  &txXSLTAtoms::max, 0, kEXSLTMathNS }, // MAX
     { 1, 1, Expr::NUMBER_RESULT,  &txXSLTAtoms::min, 0, kEXSLTMathNS }, // MIN
     { 1, 1, Expr::NODESET_RESULT, &txXSLTAtoms::highest, 0, kEXSLTMathNS }, // HIGHEST
     { 1, 1, Expr::NODESET_RESULT, &txXSLTAtoms::lowest, 0, kEXSLTMathNS }, // LOWEST
+    { 0, 0, Expr::STRING_RESULT,  &txXSLTAtoms::dateTime, 0, kEXSLTDatesAndTimesNS }, // DATE_TIME
 
 };
 
 class txEXSLTFunctionCall : public FunctionCall
 {
 public:
     // The order of this enum must be the same as the descriptTable
     // table above
@@ -264,17 +267,18 @@ public:
         LEADING,
         TRAILING,
         CONCAT,
         SPLIT,
         TOKENIZE,
         MAX,
         MIN,
         HIGHEST,
-        LOWEST
+        LOWEST,
+        DATE_TIME
     };
     
     txEXSLTFunctionCall(eType aType)
       : mType(aType)
     {
     }
 
     TX_DECL_FUNCTION
@@ -682,16 +686,46 @@ txEXSLTFunctionCall::evaluate(txIEvalCon
                     NS_ENSURE_SUCCESS(rv, rv);
                 }
             }
 
             NS_ADDREF(*aResult = resultSet);
 
             return NS_OK;
         }
+        case DATE_TIME:
+        {
+            // http://exslt.org/date/functions/date-time/
+            // format: YYYY-MM-DDTTHH:MM:SS.sss+00:00
+            char formatstr[] = "%04hd-%02ld-%02ldT%02ld:%02ld:%02ld.%03ld%c%02ld:%02ld";
+            const size_t max = sizeof("YYYY-MM-DDTHH:MM:SS.sss+00:00");
+            
+            PRExplodedTime prtime;
+            PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &prtime);
+            
+            PRInt32 offset = (prtime.tm_params.tp_gmt_offset +
+              prtime.tm_params.tp_dst_offset) / 60;
+              
+            PRBool isneg = offset < 0;
+            if (isneg) offset = -offset;
+            
+            StringResult* strRes;
+            rv = aContext->recycler()->getStringResult(&strRes);
+            NS_ENSURE_SUCCESS(rv, rv);
+            
+            CopyASCIItoUTF16(nsPrintfCString(max, formatstr,
+              prtime.tm_year, prtime.tm_month + 1, prtime.tm_mday,
+              prtime.tm_hour, prtime.tm_min, prtime.tm_sec,
+              prtime.tm_usec / 10000,
+              isneg ? '-' : '+', offset / 60, offset % 60), strRes->mValue);
+              
+            *aResult = strRes;
+
+            return NS_OK;
+        }
     }
 
     aContext->receiveError(NS_LITERAL_STRING("Internal error"),
                            NS_ERROR_UNEXPECTED);
     return NS_ERROR_UNEXPECTED;
 }
 
 Expr::ResultType
--- a/content/xslt/src/xslt/txStylesheetCompiler.cpp
+++ b/content/xslt/src/xslt/txStylesheetCompiler.cpp
@@ -992,16 +992,18 @@ static txFunctionFactoryMapping kExtensi
     { "", kNameSpaceID_Unknown, TX_ConstructXSLTFunction },
     { "http://exslt.org/common", kNameSpaceID_Unknown,
       TX_ConstructEXSLTFunction },
     { "http://exslt.org/sets", kNameSpaceID_Unknown,
       TX_ConstructEXSLTFunction },
     { "http://exslt.org/strings", kNameSpaceID_Unknown,
       TX_ConstructEXSLTFunction },
     { "http://exslt.org/math", kNameSpaceID_Unknown,
+      TX_ConstructEXSLTFunction },
+    { "http://exslt.org/dates-and-times", kNameSpaceID_Unknown,
       TX_ConstructEXSLTFunction }
 };
 
 extern nsresult
 TX_ResolveFunctionCallXPCOM(const nsCString &aContractID, PRInt32 aNamespaceID,
                             nsIAtom *aName, nsISupports *aState,
                             FunctionCall **aFunction);
 
--- a/content/xslt/tests/mochitest/Makefile.in
+++ b/content/xslt/tests/mochitest/Makefile.in
@@ -49,13 +49,14 @@ include $(topsrcdir)/config/rules.mk
 		test_bug427060.html \
 		test_bug468208.html \
 		test_bug453441.html \
 		test_bug511487.html \
 		test_bug551412.html \
 		test_bug551654.html \
 		test_bug566629.html \
 		test_bug566629.xhtml \
+		test_bug603159.html \
 		test_exslt_regex.html \
 		$(NULL)
 
 libs:: $(_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/content/xslt/tests/mochitest/test_bug603159.html
@@ -0,0 +1,55 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=603159
+-->
+<head>
+  <title>Test for Bug 603159</title>
+  <script type="application/javascript" src="/MochiKit/packed.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=603159">Mozilla Bug 603159</a>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 603159 **/
+
+  var style =
+    '<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" ' +
+                    'xmlns:date="http://exslt.org/dates-and-times" '+
+                    'version="1.0">' +
+      '<xsl:output method="html"/>' +
+      '<xsl:template match="/">' +
+        '<xsl:value-of select="date:date-time()" /> ' +
+      '</xsl:template>' +
+    '</xsl:stylesheet>';
+  var styleDoc = new DOMParser().parseFromString (style, "text/xml");
+
+  var data = '<root/>';
+  var originalDoc = new DOMParser().parseFromString(data, "text/xml");
+
+  var processor = new XSLTProcessor();
+  processor.importStylesheet(styleDoc);
+
+  var fragment = processor.transformToFragment(originalDoc, document);
+  var content = document.getElementById("content");
+  content.appendChild(fragment);
+  
+  // use Gecko's Date.parse to parse, then compare the milliseconds since epoch
+  var xslt_ms = Date.parse(content.innerHTML);
+  var now_ms = new Date().getTime();
+  var accepted_diff = 30 * 60 * 1000; // 30 minutes
+  var diff = Math.abs(now_ms - xslt_ms);
+  
+  ok(diff < accepted_diff, "generated timestamp should be not more than "
+    + accepted_diff + " ms before 'now', but the difference was: " + diff);
+  
+  content.innerHTML = '';
+</script>
+</pre>
+</body>
+</html>