Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Call Java instance methods in XSLT

Tags:

java

xslt

saxon

I am using Saxon (I could use Xalan if necessary) XSLT processor to do some transformation. I want to pass the instance of below object to the XSLT template as parameter.

public class Test {
   private String value;

   public Test(String v) {
       value = v;
   }
   //getters, setters etc.
}

So I create this object, ie.

Test test = new Test("test");
transformer.setParameter("test", test);

In XSLT file I declare the param as:

<xsl:param name="test" required="yes" as="jt:com.whatever.package.Test" xmlns:jt="http://saxon.sf.net/java-type"/>

Now my question is how can I call any instance method (ie. getValue() ) on this object within XSLT? Is it even possible? I know i can call static methods of different Java classes but thats not exactly what Im looking for.

Also, is it possible to populate Java objects within XSLT, ie. call setter methods for instance of an object and then use this object with new values in Java code after the transformation is completed?

like image 979
Zyga Avatar asked Oct 06 '12 16:10

Zyga


3 Answers

You should be able to call instance methods of an "external object" passed in as a parameter in the way you describe. If $object is such an object and com.package.MyClass is its class, and you want to call the method getColor() on this object, then

(a) you need to declare a namespace, such as xmlns:MyClass="java:com.package.MyClass"

(b) you call the method as MyClass:getColor($object)

This mechanism for calling out to Java is referred to in Saxon as "reflexive extension functions". It's not supported in the Saxon Home Edition. You will need either the Saxon Professional Edition or the old open-source Saxon-B product. There's another mechanism in Saxon-HE called "integrated extension functions", but it requires a bit more coding on the Java side to declare the types of the arguments and result.

You need to be aware that with reflexive extension functions, Saxon is making best guesses as to how to map Java types to XPath types, and it doesn't always do the mapping in the way you would want, especially when using collection types.

Try to avoid using methods with side-effects, such as setter methods. There's no absolutely reliable way of ensuring in Saxon that such calls are executed in any particular order, and sometimes the Saxon optimizer will find a way of organizing the query that avoids making the call at all. If you must make such calls, treat them as if the call were returning a result (such as an empty sequence) and use the call in such a way that if it did return a result, the result would appear in your stylesheet output.

like image 198
Michael Kay Avatar answered Nov 16 '22 10:11

Michael Kay


This is thoroughly explained here:

http://www.saxonica.com/html/documentation/extensibility/functions/

A short example:

<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:date="java:java.util.Date" exclude-result-prefixes="date">

<xsl:template match="/">
  <html>
    <xsl:if test="function-available('date:to-string') and
                          function-available('date:new')">
      <p><xsl:value-of select="date:to-string(date:new())"/></p>
    </xsl:if>
  </html>
</xsl:template>

</xsl:stylesheet>

when applied on any XML document (not used) produces the wanted, correct result:

<html>
   <p>Sat Oct 06 11:41:30 PDT 2012</p>
</html>
like image 3
Dimitre Novatchev Avatar answered Nov 16 '22 11:11

Dimitre Novatchev


I've done this long time ago using Xalan. First, you need to add the following to your xslt (I don't think you need all the other attributes you put)

<xsl:param name="test" />

and then, to call the method, you can do

<xsl:value-of select="test:getValue()"/>
like image 2
Augusto Avatar answered Nov 16 '22 12:11

Augusto