Apache Ant has a task called <xslt> (or its synonym <style>) that performs an XML transform on a file or group of files.

Here is an example XML transformation target:

 <target name="MyXSLT">
    <xslt in="MyInput.xml" 
       out="MyOutput.xml"
       style="MyTransform.xslt">
    </xslt>
 </target>

In the ant target there are three files you must specify:

  • in The name of the source XML input file
  • out The name of the XML output file
  • style The name of the XSLT file

To test this you can create a "dummy" input file:

 <?xml version="1.0" encoding="UTF-8"?>
 <root>
    <Input>Hi</Input>
 </root>

Hello World XSLT Transform

edit

To get started, here is a small "hello world" transform file. The transform looks for the root data element of the input file but does not actually process any of the input file data elements:

 <?xml version="1.0" encoding="UTF-8"?>
 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
     <xsl:template match="/">
         <MyMessage>Hello World!</MyMessage>
     </xsl:template>
 </xsl:stylesheet>

You can now execute this from a command line. The following is an example run from a Microsoft Windows command shell:

 C:\XMLClass\XSLT\Lab1>ant
 Buildfile: build.xml
 
 MyXSLT:
      [xslt] Processing C:\XMLClass\XSLT\Lab1\MyInput.xml to C:\XMLClass\XSLT\Lab
 1\MyOutput.xml
      [xslt] Loading stylesheet C:\XMLClass\XSLT\Lab1\MyTransform.xslt
 
 BUILD SUCCESSFUL
 Total time: 1 second

The output will appear in a file called MyOutput.xml

 <?xml version="1.0" encoding="UTF-8"?>
 <MyMessage>Hello World!</MyMessage>

Transforming Files containing external References

edit

Sometimes you may need to transform XML files containing external references, like URLs in DTDs or Schema definitions.

Quite often, parsing or validating against such external files can not be totally disabled. Saxon for example will want to read DTDs even if parsing them is disabled (parameter "-dtd:off" or equivalent).

In such cases it may also occur, that the development workstation is connected to a company intranet that is protected by a firewall from the internet, and needs some sort of proxy or socks configuration.

In these cases, the only solution to successfully execute the transformation is by adding this connection configuration to the ant script.

Example (taken from a bigger build.xml file):

    <target name="xdoclet-merge-top" depends="init, proxy-set" >
      <xslt style="${XDocletDescDir}/merge.xslt" 
        in="${XDocletDescDir}/merge1.xml" 
        out="${XDocletDescDir}/jboss-2.xml" force="true" >			
        <classpath location="${ZubehoerDir}/SaxonHE9-4-0-1J/saxon9he.jar" />	
      </xslt>
    </target>
    <target name="proxy-set">
      <setproxy proxyhost="proxy.mynet.de" proxyport="8080" proxyuser="" proxypassword=""/>
    </target>

Passing Parameters from Ant into an XSLT script

edit

You can also pass parameters from an ant build file into an XSLT. This is handy if you need to run the same transform with small variations. You can do this by simply adding the param tag the <xslt> target:

 <param name="MyParameter" expression="ANT AND XSLT ROCK"/>

The ant task now looks like the following:

 <?xml version="1.0" encoding="UTF-8"?>
 <project default="MyXSLT">
     <target name="MyXSLT">
        <xslt
           in="MyInput.xml"
           out="MyOutput.xml"
           style="MyTransform.xslt">
           <param name="MyParameter" expression="ANT AND XSLT ROCK"/>
         </xslt>
     </target>
 </project>

Here is a sample transform that takes a single input parameter:

 <?xml version="1.0" encoding="UTF-8"?>
 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:param name="MyParameter"/>
    <xsl:template match="/">
        <MyMessages>
            <MyMessage>Hello From XSLT</MyMessage>
            <MyMessage>From input: <xsl:value-of select="/root/Input"/>
            </MyMessage>
            <MyMessage>
                <xsl:value-of select="$MyParameter"/>
            </MyMessage>
        </MyMessages>
    </xsl:template>
 </xsl:stylesheet>

This will create the following output:

 <?xml version="1.0" encoding="UTF-8"?>
 <MyMessages>
     <MyMessage>Hello From XSLT</MyMessage>
     <MyMessage>From input: Hi</MyMessage>
     <MyMessage>ANT AND XSLT ROCK</MyMessage>
 </MyMessages>

Note that there are three different lines. One came from the transform file, one came from the input XML file and one was passed directly in from the ant file.

Other ways to use XSLT within Apache Ant

edit

Checking dependencies

edit

By default, the XSLT task will check the file time stamps to see if the output file is newer than the input file. If the outputs are newer the task should not have to re-run the transform. But sometimes a transform will import other transforms files and Ant does not check the timestamps of imported files. (Perhaps they will add that as an option in the future.) But all is not lost. We can achieve the same results by using the <dependset> tag. Here is an example:

 <dependset>
    <srcfilelist dir="${XSLTDir}"
       files="Content2HTML.xsl, HTMLHeader.xsl,PageHeader.xsl,LeftNav.xsl,PageFooter.xsl"/>
    <targetfileset
       dir="${BuildDir}"
       includes="*.htm"/>
 </dependset>

In the above example the source transform (Content2HTML.xsl) imported the other four page fragment transforms located in the XSLTDir (HTMLHeader.xsl, PageHeader.xsl, LeftNav.xsl and PageFooter.xsl). It created the files in the BuildDir directory. If any of the inputs files change, the outputs will be regenerated.

This is a handy way to build a little ant-based web content management system. You just put the HTML content in a directory and the transform can wrap the HTML headers, navigation bars and footers around your content. The HTML for each page can just be a <div> section that is copied into the output using the <xsl:copy-of> command.

References

edit