Date operations on xsl 1.0
Asked Answered
B

2

2

I need to get 3 days before and after a given date defined in a variable, and store each one of them in a new individual variable in xsl 1.0. i can't use any extensions or third party tools.

Looking trough the answers in the forums, i found this: Expanding datetime ranges in XSLT 1.0 for a similar problem, but i dont fully understand if and how it would aply to my code.

Mi date variable is in standard dateTime format, like this:

<xsl:variable name="Date" select="2014-05-13T00:00:00"/>

And i would need to output an html similar to this:

<table>
  <tr>
    <td>
   2014-05-10
    <td>
  </tr>
  <!---some rows with pricing information -->
</table>
<table>
  <tr>
    <td>
   2014-05-11
    <td>
  </tr>
  <!---some rows with pricing information -->
</table>
<table>
  <tr>
    <td>
   2014-05-12
    <td>
  </tr>
  <!---some rows with pricing information -->
</table>
<!-- etc -->

In the rows with pricing information I will have to use each individual date to perform other operations, so each day must be stored in a variable for further use.

Is there a way to accomplish this, using just xslt 1.0?

Thanks in advance.

Billhead answered 9/5, 2014 at 14:8 Comment(7)
What XSLT processor do you use? The optimal answer depends on that. (In other words, you could use the answer in the other thread and bend it to your needs, but it would be a lot easier if you had access to XSLT extensions of some sort, so you should explore that first.)Literatim
The problem with extensions is that my .xsl will be implemented in a server wich i don't have access to, so I have to use everything 'as is'or it won't work there, even if it works for me.Billhead
But the server uses Saxon 6.5.5 in a Java host?Literatim
Saxon 6.5.5 does not support the EXSLT date:add() function, so you will have to do the calculation yourself. A relatively simple method (simpler than the one you linked to or the one used in the XSLT template available from the link above, IMHO) is to calculate a serial date number such as JDN, add/subtract the appropriate number of days, and convert the result back to date.Mainis
Tomalak: Yes, the server uses exactly the same processor as I do. michael.hor: I don't understand what do you mean by "calculate a serial date number such as JDN"; would you mind posting how would it be that procedure? Thanks both for your time.Billhead
You can modify the addOneToDate template from the code you linked. It calculates the day, month and year after adding one day. Add a param to pass the days you want to add/remove, and adapt the expressions using the parameter as a variable to calculate the correct day, year and month.Koren
I hadn't seen @Mainis 's suggestion. Calculating a serial date is definitely better.Koren
M
15

Adding/subtracting number of days to/from date in pure XSLT 1.0:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:param name="givenDate" select="'2014-05-13T00:00:00'"/>
<xsl:param name="daysDiff" select="-3"/>

<xsl:variable name="JDN">
    <xsl:call-template name="JDN">
        <xsl:with-param name="date" select="$givenDate" />
    </xsl:call-template>
</xsl:variable>

<xsl:variable name="newDate">
    <xsl:call-template name="GD">
        <xsl:with-param name="JDN" select="$JDN + $daysDiff" />
    </xsl:call-template>
</xsl:variable>


<xsl:template match="/">
    <output>
        <GivenDate><xsl:value-of select="$givenDate"/></GivenDate>
        <NewDate><xsl:value-of select="$newDate"/></NewDate>
    </output>
</xsl:template> 


<xsl:template name="JDN">
    <xsl:param name="date"/>
    <xsl:param name="year" select="substring($date, 1, 4)"/>
    <xsl:param name="month" select="substring($date, 6, 2)"/>
    <xsl:param name="day" select="substring($date, 9, 2)"/>
    <xsl:param name="a" select="floor((14 - $month) div 12)"/>
    <xsl:param name="y" select="$year + 4800 - $a"/>
    <xsl:param name="m" select="$month + 12*$a - 3"/>
    <xsl:value-of select="$day + floor((153*$m + 2) div 5) + 365*$y + floor($y div 4) - floor($y div 100) + floor($y div 400) - 32045" />
</xsl:template> 

<xsl:template name="GD">
    <xsl:param name="JDN"/>
    <xsl:param name="f" select="$JDN + 1401 + floor((floor((4 * $JDN + 274277) div 146097) * 3) div 4) - 38"/>
    <xsl:param name="e" select="4*$f + 3"/>
    <xsl:param name="g" select="floor(($e mod 1461) div 4)"/>
    <xsl:param name="h" select="5*$g + 2"/>
    <xsl:param name="D" select="floor(($h mod 153) div 5 ) + 1"/>
    <xsl:param name="M" select="(floor($h div 153) + 2) mod 12 + 1"/>
    <xsl:param name="Y" select="floor($e div 1461) - 4716 + floor((14 - $M) div 12)"/>
    <xsl:param name="MM" select="substring(100 + $M, 2)"/>
    <xsl:param name="DD" select="substring(100 + $D, 2)"/>
    <xsl:value-of select="concat($Y, '-', $MM, '-', $DD)" />
</xsl:template>     

</xsl:stylesheet>

Result:

<?xml version="1.0" encoding="UTF-8"?>
<output>
   <GivenDate>2014-05-13T00:00:00</GivenDate>
   <NewDate>2014-05-10</NewDate>
</output>

--
Note that the givenDate's parameter value is a string and as such must be wrapped in single quotes.

Mainis answered 9/5, 2014 at 16:8 Comment(0)
L
1

SAXON 6.5.5 supports the EXSLT extensions, but the date:add-duration() from dates and times module — which would solve your problem elegantly — is not implemented.

However, you can directly use Java objects from within XSLT with Saxon:

You can also use a short-cut technique of binding external Java classes, by making the class name part of the namespace URI.

With the short-cut technique, the URI for the namespace identifies the class where the external function will be found. The namespace URI must either be "java:" followed by the fully-qualified class name (for example xmlns:date="java:java.util.Date") ...

Quoting from this post, the method for adding days to dates in Java is

String dt = "2008-01-01";  // Start date
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Calendar c = Calendar.getInstance();
c.setTime(sdf.parse(dt));
c.add(Calendar.DATE, 1);  // number of days to add
dt = sdf.format(c.getTime());  // dt is now the new date

the XSLT version could look something like this (untested):

<xsl:stylesheet
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:simple-date-format:="java:java.text.SimpleDateFormat"
  xmlns:calendar="java:java.util.Calendar"
>

  <xsl:template name="date-add-days">
    <xsl:param name="input" />
    <xsl:param name="days" />

    <xsl:if test="
      function-available('simple-date-format:new') 
      and function-available('calendar:get-instance')
    ">
      <xsl:variable name="sdf"  select="simple-date-format:new('yyyy-MM-dd')" />
      <xsl:variable name="cal"  select="calendar:get-instance()" />

      <xsl:variable name="time" select="simple-date-format:parse($sdf, $input)" />
      <xsl:variable name="tmp1" select="calendar:set-time($cal, $time)" />
      <xsl:variable name="tmp2" select="calendar:add($cal, calendar:DATE(), number($days))" />
      <xsl:variable name="res" select="calendar:get-time($cal)" />

      <xsl:value-of select="simple-date-format:format($sdf, $res)" />
    </xsl:if>
  </xsl:template>

</xsl:stylesheet>

With regard to interacting with Java classes and objects from XPath:

I'm not sure of the method name format. The Saxon 6.5.5 documentation seems to imply dashed format (toString() becomes to-string()), so I've been using this here. Maybe calendar:set-time() must actually called calendar:setTime(), try it out & fix my answer.

Literatim answered 9/5, 2014 at 15:19 Comment(3)
I dont seem to have a problem with calendar:set-time, but on variable "tmp2" i got the following error: Description: Error in expression calendar:add($cal, $cal:DATE(), number($days)): expected "<name>", found "<function>"Billhead
Try calendar:DATE(), that should have been an access to the the static field.Literatim
Doesn't show any errors, but doesn't output a result either. Anyway, the lead programmer just told me to NOT use java procedures on this code, because of compatibility problems when parsing on the final website.Billhead

© 2022 - 2024 — McMap. All rights reserved.