8

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?

giannis christofakis
  • 8,201
  • 4
  • 54
  • 65
Zyga
  • 2,367
  • 3
  • 22
  • 32

4 Answers4

7

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.

Djordje Nedovic
  • 559
  • 8
  • 20
Michael Kay
  • 156,231
  • 11
  • 92
  • 164
3

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>
Matthias M
  • 12,906
  • 17
  • 87
  • 116
Dimitre Novatchev
  • 240,661
  • 26
  • 293
  • 431
  • +1 and a note to the OP: You can also add `extension-element-prefixes="date"` to `xsl:stylesheet` so you don't get the `xmlns:date="java:java.util.Date"` in the output. – Daniel Haley Oct 06 '12 at 20:11
  • 1
    While extension-element-prefixes will have that effect, it's the wrong tool for the job: the correct attribute to use is exclude-result-prefixes. – Michael Kay Oct 07 '12 at 08:43
2

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()"/>
Augusto
  • 28,839
  • 5
  • 58
  • 88
  • Its not working with Saxon (says Undeclared namespace prefix {test}). I will install Xalan and try it there though. Saxon preferred as it supports xslt2. Thanks – Zyga Oct 06 '12 at 17:40
  • I tried to do that with Xalan, but it says 'Namespace prefix 'test' is undeclared.' – Grief Mar 01 '18 at 16:07
0

Its too late I am posting but for some one else it may be helpful.

You can easily achieve this with the help of xalan processor:

Step 1: include the Xalan dependency or suitable jar involved

<!-- https://mvnrepository.com/artifact/xalan/xalan -->
 <dependency>
<groupId>xalan</groupId>
<artifactId>xalan</artifactId>
<version>2.7.1</version>
</dependency>

Step 2. Choose this processor while integrating with java

TransformerFactory factory = TransformerFactory.newInstance("org.apache.xalan.processor.TransformerFactoryImpl",null);

Step 3. In your xsl enter the info in the stylesheet

xmlns:uuid="xalan://PackageName.className"

Please note that this class should be having the Static method that you will be using in the xslt

Step 4 : use it in your xslt

<xsl:value-of select="uuid:methodName(string(xpath))" />

It can be string or number..depending upon your method argument

Source: http://www.cafeconleche.org/books/xmljava/chapters/ch17s03.html

hiccup
  • 42
  • 8