—last Modified on 25 Aug 2004
This tutorial is a collection of information about using JavaScript and XSLT with Ant, and is focused towards intermediate to expert client-side web developers. It is presently a very rough draft.
Information in this tutorial was taken from several sources including the ant-user mailing list and the ant manual. Where possible the date and location of a source material has been noted to provide credit to members of the community and to aid in your search for more information. If there is any material in this tutorial which is not public or is copyrighted please contact the authors of this tutorial and this information will be removed.
All e-mail addresses in this document have been munged in an attempt to block spam spiders. Replace [at] with the @ symbol to un-munge the address.
Warning and Disclaimer: No guarantee exists that this tutorial is correct, up to date, or even harmless.
This tutorial is copyrighted and is provided as a resource for the open source community. In that spirit it is freely available to be copied, mirrored, modified, and taken for your own use provided that full credit is given to the authors and Ant community in all redistributions and derivative works.
The most up to date version of this document is located at http://www.sitepen.com/ant/javascript.html.
—Dylan Schiemann on 14 Feb 2002
What is Ant?
Apache Ant is a build based tool. It has a vast array of uses for programmers. Often overlooked is its usefulness for client-side web developers. It is especially useful for preprocessing tokens across many pages of a web site, rather than relying on SSI, php, asp, or jsp. It is also very useful for building a site with an xslt processor such as xalan. If you are not familiar with Ant, be sure to read the ant manual which has instructions for installing and using Ant.
Why JavaScript in Ant?
Ant does not have standard commands for programming techniques like recursion. Instead, it contains prebuilt tasks for using your language of choice. JavaScript is an easy to use, widely known scripting language, and is easily added to Ant through its optional tasks.
Adding JavaScript to Ant
Download the optional task jar from the ant web site, the bsf.jar, and rhino.jar from mozilla (rename js.jar to rhino.jar). Include these jars in your classpath. Note that some of the examples described here do not work effectively with older versions of Ant. There are also issues with mixing older and newer versions of BSF and Ant.
Adding XSLT to Ant
To include an xslt processor such as Xalan-J-2, you will also need to download and configure it. You will also need to add the location of your xalan jars to your ant classpath, or make a copy of the necessary jars.
Hello World Example
The obligatory hello world example simply echos Hello World to Ant’s generated results
<target name="setup">
<script language="javascript"> <![CDATA[
echo = helloWorld.createTask("echo");
main.addTask(echo);
echo.setMessage("Hello World!");
]]> </script>
</target>
<target name="main" depends="setup"/>
</project>
generates:
setup:
main:
Hello World!
BUILD SUCCESSFUL
To include JavaScript within Ant, you use a script tag much like you do in any xml document. To define the Script language, use the older language declaration rather than the newer type syntax, . You may also use a src attribute to include an external script.
—Ant Manual Script Task on 11 Feb 2002
General Objects
To do more interesting things with Ant, you have access to properties, targets, and references. For an explanation of properties, targets, and references, refer to the ant manual
project.getUserProperty(string propertyName);
project.getTarget(string targetId);
project.getReference(string refereceId);
project is a shortcut for getProject(), which returns the project object.
self returns the script task itself for logging and other task specific utilities.
If you have two things with the same name/id, only the last one in the document order is used. Illegal Java names cause it to be omitted.
—Erik Hatcher (jakarta-ant[at]ehatchersolutions.com) on 12 Feb 2002
XSLT Task
To use the standard XSLT task, with a single input and output file, and to pass a parameter to the stylesheet, you could do the following in your build file:
extension="html" style="webSite.xsl" processor="trax">
<param name="pageId" expression="com.sitepen.pages.home"/>
</style>
To process an entire directory of documents, you could do the following:
extension="html" style="style/webSite.xsl"/>
—Ant Manual Style Task on 11 Feb 2002
However, lost is the ability to pass a different parameter for each generated document. This is where I found JavaScript to be particularly useful, as shown in this example:
<project name="siteBuilder" default="deploy" basedir=".">
<target name="init">
<property name="runDir" value="." />
<property name="varsDir" value="vars" />
<property name="sourceDir" value="src" />
<property name="outputDir" value="www" />
<property name="tempDir" value="temp" />
<property name="tokenValues" value="tokenValues.properties" />
<property file="${varsDir}/${tokenValues}" />
</target>
<target name="clean" depends="init">
<delete includeEmptyDirs="true" >
<fileset dir="${outputDir}" />
</delete>
</target>
<target name="prepare" depends="clean">
<mkdir dir="${outputDir}" />
</target>
<target name="compile" depends="prepare">
<copy todir="${tempDir}">
<fileset dir="${sourceDir}">
<exclude name="**/*.html"/>
</fileset>
</copy>
<script language="javascript">
<![CDATA[
importClass(java.io.File)
xslt = siteBuilder.createTask("style");
runDirectory = siteBuilder.getProperty("runDir");
tempDirectory = siteBuilder.getProperty("tempDir");
inFile = new File(runDirectory + "/webProject.xml");
outFile = new File(tempDirectory+"/index.html");
xslt.setStyle("webSite.xsl");
xslt.setIn(inFile);
xslt.setOut(outFile);
xslt.setProcessor("trax");
idParameter = xslt.createParam();
idParameter.setName("pageId");
idParameter.setExpression("com.sitepen.pages.home");
xslt.execute();
]]>
</script>
</target>
<target name="deploy" depends="compile,init">
<copy todir="${outputDir}">
<fileset dir="${tempDir}">
<exclude name="**/*.xml"/>
</fileset>
</copy>
<delete includeEmptyDirs="true" >
<fileset dir="${tempDir}" />
</delete>
</target>
</project>
—Dylan Schiemann on 14 Feb 2002
Using JavaScript to recurse over a properties file
*** I am presently unable to get this to work as it seems that property files only work with tasks that uses tokens ***
Looping through tasks
Ant does not have a built-in looping mechanism, so many people use JavaScript to accomplish this. For example, to create a series of directories, you could do the following:
<![CDATA[
importClass(java.io.File); //Java class needed for file creation
var directoryNames = new Array();
directoryNames[0] = "directoryName0";
directoryNames[1] = "directoryName1";
directoryNames[2] = "directoryName2";
// … and so on
// in this example, the directory path is stored as part of the directory name.
for (i=0;i<directoryNames.length;i++)
{
// projectName is the name of your project
makeDirectory = projectName.createTask("mkdir");
directory = new File(directoryNames[i]);
makeDirectory.setDir(directory);
makeDirectory.execute();
}
]]>
</script>
—based on example by Diane Holt on 25 Sep 2001

As more complex scripts are needed it is perhaps better to keep the scripts in separate files. Amending the “Hello World” example.
The javascript file becomes:
// helloworld.js HelloWorld example
echo = project.createTask(”echo”);
echo.setMessage(”Hello World!”);
echo.perform();
The task becomes:
If the “project” reference is used the script can be reused in
different Ant builds.
<target name=”test”>
<script language=”javascript”
src=”../javascript/helloworld.js”/>
</target>
Thanks to your helpful blog, I’ve been able to write an Ant Javascript to allow me to batch up calls over a large fileset into smaller chunks – eg I have 100 files and need to process them 20 at a time. This involves calling back out to an Ant target passing a reference to the batched filelist. Here is my proof-of-concept code:-
<![CDATA[
importClass(org.apache.tools.ant.taskdefs.Ant);
importClass(org.apache.tools.ant.types.FileList);
importClass(org.apache.tools.ant.types.FileSet);
var echo = project.createTask(”echo”);
echo.setMessage(”Hello, World!”);
echo.execute();
// Invoke a target using antcall, passing a property
var target = project.createTask(”antcall”);
var param = target.createParam();
param.setName(”test-prop”);
param.setValue(”Hello, Work”);
target.setTarget(”print-property”);
target.execute();
// Obtain a reference to a fileset in the enclosing project
var fileSet = project.getReference(”files-to-batch-up”);
echo.setMessage(”fileSet size = “+fileSet.size());
echo.execute();
var ds = fileSet.getDirectoryScanner(project);
var includes = ds.getIncludedFiles();
echo.setMessage(”selected file count = “+includes.length);
echo.execute();
// Prepare the call, we will pass a reference to FileList “batch-of-files” as “test-ref”.
var ref = new Ant.Reference();
ref.setProject(project);
ref.setRefId(”batch-of-files”);
ref.setToRefid(”test-ref”);
target.addReference(ref);
target.setTarget(”print-reference”);
var baseDir = fileSet.getDir();
var BATCHSIZE=20;
for (var i=0; i<includes.length; i+= BATCHSIZE) {
// Create a new fileset with reference name “batch-of-files”.
// We need a new one for each batch because we can only add, not remove, items.
var filesBatch = new FileList();
filesBatch.setDir(baseDir);
project.addReference(”batch-of-files”, filesBatch);
for (var j=0; j<BATCHSIZE && (i+j)
That didn’t come out very well :-(
I’ll email it to you direct.
<project name=”test” default=”runscript”>
<property name=”basedir” location=”…”/>
<fileset id=”files-to-batch-up” dir=”${basedir}/…” includes=”**/*Test.class”/>
<target name=”runscript”>
<script language=”javascript”>
<![CDATA[
importClass(org.apache.tools.ant.taskdefs.Ant);
importClass(org.apache.tools.ant.types.FileList);
importClass(org.apache.tools.ant.types.FileSet);
var echo = project.createTask(”echo”);
echo.setMessage(”Hello, World!”);
echo.execute();
// Invoke a target using antcall, passing a property
var target = project.createTask(”antcall”);
var param = target.createParam();
param.setName(”test-prop”);
param.setValue(”Hello, Work”);
target.setTarget(”print-property”);
target.execute();
// Obtain a reference to a fileset in the enclosing project
var fileSet = project.getReference(”files-to-batch-up”);
echo.setMessage(”fileSet size = “+fileSet.size());
echo.execute();
var ds = fileSet.getDirectoryScanner(project);
var includes = ds.getIncludedFiles();
echo.setMessage(”selected file count = “+includes.length);
echo.execute();
// Prepare the call, we will pass a reference to FileList “batch-of-files” as “test-ref”.
var ref = new Ant.Reference();
ref.setProject(project);
ref.setRefId(”batch-of-files”);
ref.setToRefid(”test-ref”);
target.addReference(ref);
target.setTarget(”print-reference”);
var baseDir = fileSet.getDir();
var BATCHSIZE=20;
for (var i=0; i<includes.length; i+= BATCHSIZE) {
// Create a new fileset with reference name “batch-of-files”.
// We need a new one for each batch because we can only add, not remove, items.
var filesBatch = new FileList();
filesBatch.setDir(baseDir);
project.addReference(”batch-of-files”, filesBatch);
for (var j=0; j<BATCHSIZE && (i+j)<includes.length; j++) {
var file = new FileList.FileName();
file.setName( includes[i+j] );
filesBatch.addConfiguredFile( file );
}
// Execute the job on this batch of files
target.execute();
}
]]>
</script>
</target>
<target name=”print-property”>
<echo message=”test-prop = ${test-prop}”/>
</target>
<target name=”print-reference”>
<echo message=”test-prop = ${test-prop}”/>
<pathconvert refid=”test-ref” property=”prop” pathsep=”${line.separator}”/>
<echo message=”${prop}”/>
</target>
</project>