Using non-core EXSLT date functions with Xalan Java
Asked Answered
D

2

0

I have had EXSLT's core date functions working well in some XSL templates I've been using for years. I'd like to start using a new one: seconds. This function is not one of the "core" functions and therefore implementations can claim compliance with EXSLT without actually implementing it.

I'm using Cocoon 2.1.11 with Xalan 2.7.1 which, it appears, has chosen not to implement date:seconds.

Fortunately, the kind folks at EXSLT provide downloads to help you plug-in individual functions but I can't seem to figure out how to actually achieve the plug-in.

I can use the core functions easily using this template for instance:

<?xml version="1.0" ?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:date="http://exslt.org/dates-and-times" >
  <xsl:template match="/">
    <xsl:value-of select="date:date-time()" />
  </xsl:template>
</xsl:stylesheet>

When attempting to use the date.seconds function, I have tried the following:

  1. Simply adding <xsl:import href="date.seconds.xsl" /> to my template, and using date:seconds(). This gets me the error message "For extension function, could not find method org.apache.xalan.lib.ExsltDatetime.seconds"
  2. Removing the xmlns:date as shown above. This gets me the error "Prefix must resolve to a namespace: date"
  3. Placing the contents of date.seconds.xsl within the template I'm trying to write, then calling date:seconds() with no argument (it's defined to use the current time by default). I get this error message: "Instance method call to method seconds requires an Object instance as first argument". This is looking promising, now.
  4. Adding an argument to date:seconds. I get the error message: "For extension function, could not find method java.lang.String.seconds([ExpressionContext,] )"

Any suggestions for how to use this non-core EXSLT function?

Here is my current template, still telling me that it's trying to call java.lang.String.seconds():

<?xml version="1.0" ?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:func="http://exslt.org/functions"
    xmlns:date="http://exslt.org/dates and times">
  <xsl:import href="date.seconds.xsl" />
  <func:script language="exslt:javascript" implements-prefix="date" src="date.js"/>
  <func:script language="exslt:msxsl" implements-prefix="date" src="date.msxsl.xsl"/>

  <xsl:template match="/">
    <xsl:value-of select="date:seconds('2014-02-27')" />
  </xsl:template>
</xsl:stylesheet>
Dupe answered 27/2, 2014 at 21:58 Comment(0)
D
2

For those who want to roll their own (for seconds() specifically), it can be done rather simply using this code:

package tools;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.text.ParseException;

public class Dates
{
  /**
   * Converts a date in xs:dateTime format into seconds-since-the-epoch
   * 
   * @param date The date to be converted,
   *             in <code>s:dateTime</code> format (yyyy-MM-dd'T'hh:mm:ss).
   *
   * @return Number of seconds since <code>1970-01-01 00:00:00</code>,
   *         or 0 if the date is blank or null.
   * @throws ParseException
   */
  public static long seconds(String date)
      throws ParseException
  {
      if(null == date || 0 == date.trim().length()) return 0;

      SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss");
      Date d = df.parse(date);

      return d.getTime() / 1000;
  }
}

This can be used through Apache Xalan like this:

<?xml ...
  xmlns:java="http://xml.apache.org/xalan/java"
  ...

<xsl:variable name="some-date" select="...some xs:dateTime data ..." />
<xsl:value-of select="java:tools.Dates.seconds($some-date)" />

I'll probably look at the Xalan source in order to make this more flexible, but for now it seems to be doing what I'd like it to do.

Dupe answered 3/3, 2014 at 21:12 Comment(0)
M
1

First, have a look at: http://www.exslt.org/howto.html#other-implementations However, AFAIK Xalan does not support the func:script extension element (at least it says it doesn't, which is not always the same). OTOH, Xalan has its own extension mechanism - see: http://xml.apache.org/xalan-j/extensions.html

If it were me, I would simply use a named template instead.

Mendelevium answered 27/2, 2014 at 22:24 Comment(3)
As a hack, I ended up using Xalan's Java-language binding and writing my own simple function to do this. Oddly enough, the named-template that ESXLT provides simply defines the functions using the <func:script> stuff, so its equally ineffective for me.Dupe
Why don't you write this up as an answer and post it here? It might be useful to someone wishing to follow in your footsteps. Not sure why you're calling it a hack, if it follows Xalan's recipe.Mendelevium
Hack = having to write my own Java code, when there should be a perfectly-usable fallback implementation out there. I'm not trying to re-invent the wheel. I'll post my solution just for the fun of it, but I still want to know how to use EXSLT's fallbacks.Dupe

© 2022 - 2024 — McMap. All rights reserved.