How to execute XSLT 2.0 with ant?

16,878

Solution 1

The problem is that while Saxon is added to the classpath, the default JAXP mechanism to determine which TransformerFactory is used and it will use the default that is Xalan. You either need to:

  • Set javax.xml.transform.TransformerFactory system variable to net.sf.saxon.TransformerFactoryImpl,
  • Add saxon9.jar to the CLASSPATH system variable, or
  • Use <factory name="net.sf.saxon.TransformerFactoryImpl"/> inside the xslt element

Solution 2

If you are having this problem, check that you are not using Ant 1.8.1, because there is a bug in Ant 1.8.1 that prevents this from working. (Though this is not the problem in the original post, because that was before Ant 1.8.1 was released).

Your options are:

  1. Use a version of Ant that does not have the bug (e.g. Ant 1.7.1).
  2. Explicitly specify saxon9.jar in the CLASSPATH to Ant before it starts, by either:
    • Setting the system CLASSPATH environment variable, or
    • Use the -lib command line option to ant
  3. Define your own task using SAXON Ant (as described by another answer on this thread).
  4. Workaround by adding processor="org.apache.tools.ant.taskdefs.optional.TraXLiaison" as an attribute of the xslt task element.

I would suggestion using option 1, followed by option 4.

Option 2 will work, but it places the responsibility on the person running ant to set up their environment and run ant properly. I assume you don't want that, which is why you are trying to get the classpath attribute on the xslt task to work.

Option 3 has limitations, because SAXON Ant requires downloading and installing its JAR file. Also SAXON Ant does not work with SAXON 9.2 or later (and SAXON Ant has not been updated since it was created in June 2008).

In theory, specifying a factory subelement makes the XSLT processor that you want to use explicit -- to prevent the class loader from finding a different XSLT processor earlier in its search, and using it instead of your XSLT processor which is further down in the CLASSPATH. In practice (at least in ant 1.7.0, 1.7.1 and 1.8.0) if the factory subelement is specified the xslt task ignores the classpath attribute -- which means you have to resort to explicitly specifying the CLASSPATH (option 2). So it doesn't help solve the original problem. However, this seems to have been fixed in the Ant source code, so could work in releases after 1.8.1.

Solution 3

This tutorial seems to give step by step instructions on how to do what you are asking:

http://www.abbeyworkshop.com/howto/xslt/ant-saxon/index.html

From that it appears you are doing the correct thing. Are you sure you need the double back slashes?

Update: The xslt Ant documentation mentions the 'factory' property which may help you get closer:

http://ant.apache.org/manual/Tasks/style.html

Solution 4

EDIT: Dr. Michael Kay has pointed out that the AntTransform is no longer supported, nor recommended.

Create a taskdef from the Saxon AntTransform class:

  <taskdef name="saxon-xslt" classname="net.sf.saxon.ant.AntTransform" classpath="${basedir}/lib/saxon/saxon9.jar;${basedir}/lib/saxon/saxon9-ant.jar"/>

   <saxon-xslt
     in="${source.xml}"
     out="${out.dir}/${output.xml}"
     style="${basedir}/${stylesheet.xsl}"
     force="true">
   </saxon-xslt>


I have begun using the standard <xslt> task with the saxon jar specified in a <classpath>, but had been running into performance issues. It seemed to "hang" for a bit when the task was called. I have found that adding processor="trax" and specifying <factory name="net.sf.saxon.TransformerFactoryImpl"/> helps it run much faster.

 <xslt in="${source.xml}"
       out="${out.dir}/${output.xml}"
       style="${basedir}/${stylesheet.xsl}"
       processor="trax">
       <factory name="net.sf.saxon.TransformerFactoryImpl"/>
       <classpath refid="saxon-classpath" />
 </xslt>  

Solution 5

Rather than waiting for this to be fixed in 1.8.2 and then waiting for everyone to eventually upgrade to 1.8.2, you can roll your own XSLT macro (for situations where you explicitly want to use Saxon, rather than a user selected XSLT engine)

<macrodef name="xslt" uri="com.mycompany.mydepartment">
    <attribute name="in" />
    <attribute name="out" />
    <attribute name="style" />
    <attribute name="classpath" default="${saxon.jar.path}" />
    <attribute name="taskname" default="mydep:xslt" />
    <element name="params" optional="true" implicit="true" />
    <sequential>
        <java classname="net.sf.saxon.Transform"
              classpath="@{classpath}"
              taskname="@{taskname}">
            <classpath path="${saxon.jar.path}" />
            <arg value="-s:@{in}" />
            <arg value="-xsl:@{style}" />
            <arg value="-o:@{out}" />
            <params />
        </java>
    </sequential>
</macrodef>

you can then invoke it like (assuming xmlns:mydep="com.mycompany.mydepartment" is set on the project element)

<mydep:xslt in="${myinput}"
             out="${myoutput}"
             style="${myxslt}">
    <arg value="param1=value1" />
    <arg value="param2=value2" />
    <arg value="+param3=somefile.xml" />
</mydep:xslt>

You can find the docs for passing parameters to Saxon at http://www.saxonica.com/documentation/using-xsl/commandline.xml

Share:
16,878
Mike
Author by

Mike

Updated on June 12, 2022

Comments

  • Mike
    Mike about 2 years

    I'm trying to run an XSLT transformation from an ant file.

    I'm using a XSLT 2.0 stylesheet with a saxon 9 parser (supporting XSLT 2.0).

    The problem is that it seems that ant is always calling an XSLT 1.0 parser.

    Here's my ant file :

    <xslt style="stylesheet.xslt"
       basedir="core/"    
       extension=".xml"
       destdir="core/"
       classpath="D:\\DevTools\\saxon\\bin\\saxon9.jar">
    </xslt>
    

    If I call it directly (without ant), it's working.

    Any idea ?

  • Kai Sternad
    Kai Sternad over 13 years
    here is the link to the ant 1.8.1 xslt task bug: issues.apache.org/bugzilla/show_bug.cgi?id=49271
  • Michael Kay
    Michael Kay over 13 years
    Note that the AntTransform task is no longer recommended. It proved to be buggy, and there was no feasible strategy for testing it properly since Apache do not release a comprehensive test suite for Ant.
  • Mads Hansen
    Mads Hansen over 13 years
    Noted. I have begun using the standard <xslt> task with the saxon jar specified in a <classpath>, but had been running into performance issues. It seemed to "hang" for a bit when the task was called. Recently, I've found that adding processor="trax" and specifying <factory name="net.sf.saxon.TransformerFactoryImpl"/> helps it run much faster.