views:

215

answers:

2

I am working with an open source version of the Saxon XSLT processor "Saxon 9.0.0.2J from Saxonica" and am trying to make use of the java extensibility for the first time. I am running into an issue I suspect may be a limitation on the open source version, but wanted to check first whether there might be something I am just missing here.

From the snippet below, my result is that the final value of $c1 does not change as a result of the call to greg:setTime() - i.e. the $c1 variable within Saxon appears to be unhooked from the underlying Java object and there is no apparent way to access the object as updated by the setTime() call.

NOTE that all code in the snippet is tested and working otherwise - i.e. $c1 is properly instantiated by the getInstance() call, $startdate is of the proper format and $d1 is properly instantiated.

Thoughts?

<xsl:transform
       .....
       xmlns:sql="java:java.sql.Date"
       xmlns:greg="java:java.util.GregorianCalendar"
       .....
>
....
<xsl:element name="JobExpireDate">
      <xsl:variable name="c1" select="greg:getInstance()" />
      <xsl:variable name="d1" select="sql:valueOf($startdate)" />
      <xsl:variable name="void" select="greg:setTime($c1,$d1)" />
      <xsl:value-of select="$c1" />
</xsl:element>
A: 

Are you calling setTime on a GregorianCalendar with a java.sql.Date as argument? Shouldn't that fail? Or is there some hidden conversion taking place?

If it fails, maybe Saxon silently ignores the error?

I noticed that in some versions of Xalan, calls to void functions are ignored by the XSLT compiler. Saxon may behave similar.

Christian Semrau
Thanks Christian. I don't believe it should fail - java.sql.Date is a direct subclass of java.util.Date. Also, any call to set an individual field on the calendar object gives the same non-updated result for $c1, so I think we're dealing with the higher level issue of how object/variable instances are associated between Java and Saxon.
Chip Kaye
I never used java.sql.Date directly, so I never noticed that it is a subclass. :-) You are right then: The argument type is not the cause.
Christian Semrau
+1  A: 

I just tried with saxonb9-0-0-8j.

Calls to void functions are sometimes ignored, as demonstrated by the following.

The input file:

<root>
<date1>2009-01-02</date1>
<date2>2009-01-02</date2>
</root>

The transform:

 <xsl:transform
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
       xmlns:sql="java:java.sql.Date"
       xmlns:greg="java:java.util.GregorianCalendar"
 version="2.0">

<xsl:template match="*">
  <xsl:copy>
    <xsl:copy-of select="@*"/>
    <xsl:apply-templates/>
  </xsl:copy>
</xsl:template>

<xsl:template match="root/date1/text()">
      <xsl:variable name="c1" select="greg:getInstance()" />
      <xsl:variable name="d1" select="sql:valueOf(.)" />
      <xsl:variable name="void" select="greg:setTime($c1,$d1)" />
      <xsl:value-of select="greg:getTime($c1)" />
</xsl:template>

<xsl:template match="root/date2/text()">
      <xsl:variable name="c1" select="greg:getInstance()" />
      <xsl:variable name="d1" select="sql:valueOf(.)" />
      <xsl:value-of select="greg:setTime($c1,$d1)" />
      <xsl:value-of select="greg:getTime($c1)" />
</xsl:template>

</xsl:transform>

The result:

<?xml version="1.0" encoding="UTF-8"?>
<root>
<date1>2010-04-14T08:23:25.341Z</date1>
<date2>2009-01-01T23:00:00Z</date2>
</root>

So it seems that setTime() is not called for date1, but for date2.

Saxon has a nice explain feature that displayes the parsed transformation in a readable format:

...
<templateRule match="root/date2/text()" precedence="0" priority="0.5" line="21"
              module="file:/C:/devtools/saxonb9-0-0-8j/template.xsl">
  <let variable="c1" as="java:java.util.Calendar?">
    <be>
      <functionCall name="greg:getInstance"/>
    </be>
    <return>
      <sequence>
        <valueOf>
          <simpleContentConstructor>
            <functionCall name="greg:setTime">
              <variableReference name="c1"/>
              <functionCall name="sql:valueOf">
                <dot/>
              </functionCall>
            </functionCall>
            <literal value=" " type="xs:string"/>
          </simpleContentConstructor>
        </valueOf>
        <valueOf>
          <simpleContentConstructor>
            <functionCall name="greg:getTime">
              <variableReference name="c1"/>
            </functionCall>
            <literal value=" " type="xs:string"/>
          </simpleContentConstructor>
        </valueOf>
      </sequence>
    </return>
  </let>
</templateRule>
<templateRule match="root/date1/text()" precedence="0" priority="0.5" line="14"
              module="file:/C:/devtools/saxonb9-0-0-8j/template.xsl">
  <valueOf>
    <simpleContentConstructor>
      <functionCall name="greg:getTime">
        <functionCall name="greg:getInstance"/>
      </functionCall>
      <literal value=" " type="xs:string"/>
    </simpleContentConstructor>
  </valueOf>
</templateRule>
...

As you see, for date1, the call to setTime() is ignored, but is there for date2.

Christian Semrau
Oh man, Christian - you're going to love this. I was scratching my head for a while on this before realizing you found the solution via cut n' paste oversight. NOTE that your template for date2 calls setTime via <xsl:value-of> while the template for date1 calls via <xsl:variable>, as in my original snippet. Your altered date2 template results in the call succeeding. I moved that logic into my transform and all is working now. Thanks so much for your 2nd pair of eyes and your cut 'n paste "mistake"!
Chip Kaye
Sorry for not making the difference clear. :-) I played around with different ways to call the Java function, and the date2 variant worked. But I don't know why.
Christian Semrau