Skip to main content

By clicking Submit, you agree to the developerWorks terms of use.

The first time you sign into developerWorks, a profile is created for you. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

All information submitted is secure.

  • Close [x]

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerworks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

By clicking Submit, you agree to the developerWorks terms of use.

All information submitted is secure.

  • Close [x]

Enhance Ant with XSL transformations

Real-world examples of Ant's power and flexibility

Jim Creasman (creasman@us.ibm.com), Advisory Programmer, IBM 
Jim Creasman is the team leader of a software build group at IBM in Research Triangle Park, NC (USA). He received a B.S. degree in Mathematics from Mars Hill College, and an M.S. degree in Applied Mathematics from North Carolina State University. He enjoys woodworking, outdoor activities, and keeping up with his three sons. He is currently working on a screenplay which he hopes to sell to a big Hollywood studio and retire. It is a semi-autobiographical story about a guy who is given an impossible job, befriends a hapless Ant, and finally goes native with the locals. He plans to call it "Dances with Ants" and hopes to cast Kevin Costner in the lead role. You can contact Jim at creasman@us.ibm.com.

Summary:  Ant is a powerful tool for scripting build processes. When combined with XSLT, Ant's power and flexibility increase dramatically. Here, Jim explains and illustrates this concept using real world examples from his previous experience.

Date:  09 Sep 2003
Level:  Introductory

Activity:  14858 views
Comments:  

I have led a build team for the past several years, and during this time I have seen a fair number of changes in how software goes from concept to code to customer. In particular, the tools and techniques used to manage the build activity of large software development projects have seen a lot of change.

In the mid-1990s, most of the source code was C or C++. make was the tool of choice for scripting and managing code compilation. Sprinkle in a dash of batch files or shell scripts to add automation and you had a build process.

Times change. Enter Java technology, XML, XSLT, extreme programming with continuous build, and a host of other new technologies and ideas. By the late '90s the playing field was looking a lot different. Perhaps the single biggest addition to the set of build tools was Ant.

Ant is a Java-based build tool from the Jakarta project at the Apache Software Foundation. It has become a de facto standard for building Java projects. Ant scripts derive their structure, along with much of their ease of use, from XML. Also, because Ant scripts are XML, they can be parsed, modified, generated, or otherwise transformed programatically using eXtensible Stylesheet Language Transformations (XSLT). You can even invoke the stylesheet processor from an Ant task (See the Ant style task description in Resources).

It takes two to tango!

Consider the team of Ant and XSLT. The remainder of this article focuses on three examples, each illustrating some problem I have encountered in my work. In each case, I demonstrate a solution based on combining a base Ant script with one or more XSL stylesheets. XSLT adds flexibility to what would otherwise be a static script. Watch the Ants dance as you experience:

  • Easier maintenance of scripts
  • Complex scripts built up from XML metadata
  • Scripts that provide their own browser

The value lies in the method. You may not find any of these specific examples applicable, but I am confident you will find ways to use this simple technique to liven up your build process.


Learning by example

Before getting started, I want to make sure you understand the bigger picture. Each of these solutions requires making an XSL transformation happen. Figure 1 describes the general way in which XSLT works. In the context of this article the source document is usually an Ant script, but sometimes it is another XML data file. The transformation process applies the rules found in the stylesheet to the source, producing the result document.


Figure 1. Overview of XSLT process
Overview of XSLT process

Example 1: Building with style

I mentioned working on a build team for a number of years. My group contracts with various development organizations to provide their build support. We have simultaneously supported as many as 17 different products, providing builds for up to 50 releases on an active basis.

Build script outline (Ant targets)

This outline represents the general set of steps each of our build processes follow. A default action is implemented for each step, which most processes then use by default.

  1. init
  2. start
    1. setup
      1. step.setup_scm
      2. step.setup_base
      3. step.setup_delta
      4. step.setup_build
      5. step.setup_nls
      6. step.setup_verify
    2. build
      1. step.build_release
      2. step.build_verify
    3. distribute
      1. step.distribute_connect
      2. step.distribute_copy
      3. step.distribute_nls
      4. step.distribute_verify
    4. complete
      1. step.complete_scm
      2. step.complete_stats
      3. step.complete_distribute
      4. step.complete_verify

One of our challenges is managing this much activity and diversity. Often the development groups have little in common and no interaction with one another. Standardization is the key. At an abstract level, our build process for each release is the same:

  1. Define what you plan to build.
  2. Extract the source code to the build machine.
  3. Run the compilation and packaging sub-processes.
  4. Publish the build output.
  5. Notify everyone the build is ready.

Our approach has been to develop common scripts which, if not identical to one another, do at least follow this outline. As with so many plans, the devil is in the details. Over time, these scripts have a tendency to wander off in different directions if they aren't closely shepherded. Each one becomes more unique. Common maintenance requires a great deal of effort, time, and coordination.

The solution
Recently, we decided to re-engineer our scripts, consolidating on the use of Ant as the primary scripting tool. We agreed upon a default build process. The generalized tasks listed in the preceding process were refined into smaller steps, each representing a unit of work likely to be common across multiple build processes. Each step of this refined process was implemented as one or more Ant targets, each with a default behavior that was applicable to most cases. The sidebar "Build script outline" shows the actual sequence of steps represented by their Ant target names.

The outline is applicable to each build process, but the default behavior may not be right for a particular step. This is where XSLT adds the required flexibility. Without the ability to transform the default script, we would still have to maintain many copies of nearly identical scripts. Instead, each build process implements a local script containing only the steps that are unique to that process. A front-end process (also an Ant script) runs the stylesheet to transform the input documents into the Ant build file. Any steps not overridden in the local script are defined by the default set.

Think of the process as an equation:
local targets + default targets + style sheet = build script

The local targets are contained in the primary XML file input to the transformation. It reads the default targets from a secondary input document and merges the results, giving preference to the local script during the merge process.

The Ant <style> task that runs this transformation is shown in Listing 1.


Listing 1. Ant style task
                
<style in="${local_targets}"
       out="${build_script}"
       style="${style_sheet}"
       force="yes">
  <param name="defaults" expression="${default_targets}"/>
</style>

The default "targets" document is not a true Ant script. It does not contain a <project> tag and uses <default> tags to group the Ant targets for each default. This allows a group of targets to define a single step (see Listing 2).


Listing 2. Build defaults XML sample
                
                <defaults>
  <default name="init">
  <!--
    =========================================================================
       Target:  init

      Purpose:  Common initialization target.
    =========================================================================
  -->
  <target name="init">

    <!-- This is where my default initialization tasks would be found ... -->
    
  </target>
  </default>

  <!-- Additional defaults go here ... -->

</defaults>
            

Common enhancements are applied to the default targets or as modifications to the stylesheet. Since all processes reference a single instance of these, changes are applied automatically to all scripts at execution. Maintenance remains a concern if the local script has overridden the enhancement of a common step. However, by carefully managing the design, we have defined the steps such that those likely to be overridden do not contain any actions for their default behavior.

Example 2: Using XSL to view Ant scripts

One of the problems I have encountered frequently is attempting to understand and modify a script someone else has written. Build scripts are often kludged together for that build by people who would rather be writing source code than developing a process. Such scripts are notorious for poor or misleading documentation.

While good documentation has no substitute, you can offset its absence by having the ability to navigate the process in an abstract fashion. You can succeed if you have a point of reference and a mental framework to guide your investigation. With good browsers, you can see a conceptual view and move around freely without loosing your context. You can see both the forest and the trees.

A large Ant script can be daunting the first time you see it. Even if you are familiar with the script, determining where to make a modification can be time consuming. All XML documents, including Ant scripts, have a high degree of structure. With XSLT you can make use of this feature to transform your Ant script into an HTML document that is easier to read and comprehend. You can use XSL to filter out much of the noise and reveal only the critical elements.

If you are using a browser that has support for XSL stylesheets (such as Microsoft Internet Explorer, version 6), you can even make this a permanent part of your Ant script. No mess, no fuss -- just browse the Ant script directly and watch the results! Ant will just ignore the extra processing instruction when executing, so you have no need to generate a separate HTML file first.

Seeing is believing
The first step is to develop a stylesheet that handles the transformation to HTML. This can be as simple or as elaborate as you want to make it. For better or worse, here is my stylesheet. It satisfies my basic requirements when viewing an Ant script:

  • Provide a table of contents to help users quickly find a section in the script
  • Group and alphabetize all properties and targets used
  • Provide navigational links between targets and their dependencies
  • Show the tasks that make up a given target

Those skilled in HTML or JavaScript will no doubt have more creative ways to format and display the data. (Please send me your results.) The basic concept is still the same.

Once you have the stylesheet, park it somewhere that's accessible to the browser. This could be on an HTTP server or a shared drive for convenience. The final step is to add an instruction to the Ant script. This tells the browser to use your stylesheet when displaying the document. Otherwise, you will just see a more colorful version of the raw XML. Blink and you might miss this step. Are you ready? Add the line highlighted in Listing 3 to the top of your Ant script, substituting the location of your stylesheet for the value of the href attribute.


Listing 3. Stylesheet processing instruction
                
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" 
    href="./examples/example2/ant2html.xsl"?>
<project name="Example2" default="main" basedir=".">

  <!--  The rest of the Ant script goes here.  --  >

</project> 

That is all there is to it. If the browser you are currently using is enabled to handle XSL stylesheets, you can compare the results by clicking on the following links:

As with the previous example, since the stylesheet is separate from the data (that is the Ant script), any enhancements you make to the stylesheet require no additional changes to the script. They are instantly available to all users as soon as the changes are deployed.

If you were able to view the formatted Ant script, you might be wondering why I did not use frames to make the navigation easier. Generating multiple frames from within a single stylesheet is not as easy as it might appear, and requires the use of a script language (such as JavaScript). It can, however, be done. I include a second instance of the same Ant script, this time formatted with a stylesheet which generates frames. It requires Microsoft Internet Explorer as the browser since it makes use of JavaScript, MSXML, and ActiveX controls. Chapter 14 in Jeni Tennison's book (see Resources) was particularly useful in making this example work.

Example 3: Using XSL to extend Ant

As with any instruction set, the Ant syntax is unable to express certain concepts. While Ant handles dependencies, references, and hierarchical processing very nicely, it lacks any support for basic looping. The native set of tags offers no way to repetitively execute a set of tasks.

The problem
Consider a simple problem. The release you are building ships with support for eight languages: German, English, French, Italian, Japanese, Korean, Portuguese, and Spanish. The language-specific properties files are returned in their native code page, requiring that the Ant native2ascii task (see Resources) be run against each language-specific properties file. Sounds like a great setup for a loop, right?

Consider three solutions to this problem.

Solution 1: The brute force approach
The brute force approach is to just code the tasks repeatedly the number of times they they are required. This gets the job done and is fine for a small number of iterations. For larger loops with many iterations, maintenance becomes a factor. Each block of repeated code increases the chances of introducing an error into the logic. In this example, any change (such as adding a new properties file) is magnified by a factor of eight. Listing 4 shows this solution. Note the sections in bold type that highlight the slight difference in each set of lines.


Listing 4. The brute force approach
                
<target name="convert_native_encodings">
  <native2ascii encoding="Cp850" src="${basedir}/src" dest="${basedir}/export">
    <include name="**/*_de.properties/>
  </native2ascii>

  <native2ascii encoding="Cp850" src="${basedir}/src" dest="${basedir}/export">
    <include name="**/*_en.properties/>
  </native2ascii>

  <native2ascii encoding="Cp850" src="${basedir}/src" dest="${basedir}/export">
    <include name="**/*_es.properties/>
  </native2ascii>
  <native2ascii encoding="Cp850" src="${basedir}/src" dest="${basedir}/export">
    <include name="**/*_fr.properties/>
  </native2ascii>

  <native2ascii encoding="Cp850" src="${basedir}/src" dest="${basedir}/export">
    <include name="**/*_it.properties/>
  </native2ascii>

  <native2ascii encoding="SJIS" src="${basedir}/src" dest="${basedir}/export">
    <include name="**/*_ja.properties/>
  </native2ascii>

  <native2ascii encoding="KSC5601" src="${basedir}/src" 
        dest="${basedir}/export">
    <include name="**/*_ko.properties/>
  </native2ascii>

  <native2ascii encoding="Cp850" src="${basedir}/src" 
        dest="${basedir}/export">
    <include name="**/*_pt_BR.properties/>
  </native2ascii>
</target> 

Solution 2: The <for> tag
A better solution is to give Ant a <for> tag. A properly designed extension enhances the language. Listing 5 shows how this solution might look. However, it is not without drawbacks. First, it requires a deeper understanding of how Ant works in order to implement the new tag. Second, and of greater concern, is again maintenance. The classes that support the new tag must be available to Ant at runtime. This requires a separate .jar file, or a repackaging of Ant. Every system that runs the script needs access to the new tag.


Listing 5. A more elegant solution
                
<!-- Iterate over each language code -->
<target name="convert_native_encodings">
 <loadproperties srcFile="encodings.properties"/>
 <for token="%lang%" 
	      iterate-over="de, en, es, fr, it, ja, ko, pt_BR">
   <native2ascii encoding="${encoding.%lang%}" src="${basedir}/src" 
         dest="${basedir}/export">
     <include name="**/*_%lang%.properties"/>
   </native2ascii>
 </for>
</target> 

The encodings.properties file is used to create a mapping of the language code to the encoding mnemonic:


Listing 6. Encoding mappings
                
# File:  encodings.properties
encoding.de=Cp850
encoding.en=Cp850
encoding.es=Cp850
encoding.fr=Cp850
encoding.it=Cp850
encoding.ja=SJIS
encoding.ko=KSC5601
encoding.pt_BR=Cp850 

Solution 3: Using XSLT
The final solution extends the Ant language, as in the second approach, without creating a maintenance problem. Instead of coding the for loop extension as a new Java class within Ant, I use XSLT to accomplish the same goal. The result is a script that runs in vanilla Ant. The stylesheet simply expands the <for> tag into a sequence of tasks, similar to the first approach.

The stylesheet for this transformation is straightforward. The default template outputs the XML exactly as it is written -- no changes required. Only when a <for> tag is encountered is anything different output. You can view the complete stylesheet for this transformation.

It is worth noting that the original input is not a valid Ant script; the output from the stylesheet is. When distributing the build output, only the final script is published. This is a perfectly legal Ant script that can be run by the larger development community without requiring access to the stylesheet.


Conclusion: Everything old is new again

I hope you find this information useful, either directly or as a spark for ideas of your own. In many ways, I am simply restating an old idea. The use of templates to preprocess source code prior to compilation has been around since the earliest days of assembler programming. It remains a powerful technique even today.

More applications of this technique are yet to be explored and developed. I'll leave you with a couple of final suggestions -- just to keep those Ants dancing. Enjoy!

  • Consider a stylesheet that takes other XML data files and produces Ant scripts. For example, much of the Java code that's written gets packaged and deployed using a plug-in architecture. This requires a plugin.xml file as part of the package. Assembling a plug-in uses basic Ant tasks (<javac>, <jar>, and more). Why not use XSLT to transform the plugin.xml description into an Ant script that builds the plug-in?

  • Suppose you want real-time status as the build process is running -- perhaps to update a Web page in real time. One way to implement this is to code a logger for Ant that performs the update at the beginning or end of each target. Once again, this requires an in-depth understanding of Ant and some Java skills. A simpler solution uses XSLT to insert a probe task at the beginning or end of each target. The probes act as trace points and use existing Ant tasks to capture status by writing data to a file.


Download

NameSizeDownload method
x-antxslsource.zip HTTP

Information about download methods


Resources

About the author

Jim Creasman is the team leader of a software build group at IBM in Research Triangle Park, NC (USA). He received a B.S. degree in Mathematics from Mars Hill College, and an M.S. degree in Applied Mathematics from North Carolina State University. He enjoys woodworking, outdoor activities, and keeping up with his three sons. He is currently working on a screenplay which he hopes to sell to a big Hollywood studio and retire. It is a semi-autobiographical story about a guy who is given an impossible job, befriends a hapless Ant, and finally goes native with the locals. He plans to call it "Dances with Ants" and hopes to cast Kevin Costner in the lead role. You can contact Jim at creasman@us.ibm.com.

Report abuse help

Report abuse

Thank you. This entry has been flagged for moderator attention.


Report abuse help

Report abuse

Report abuse submission failed. Please try again later.


developerWorks: Sign in


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

Choose your display name

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


Rate this article

Comments

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=XML
ArticleID=12315
ArticleTitle=Enhance Ant with XSL transformations
publish-date=09092003
author1-email=creasman@us.ibm.com
author1-email-cc=

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

For articles in technology zones (such as Java technology, Linux, Open source, XML), Popular tags shows the top tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), Popular tags shows the top tags for just that product zone.

For articles in technology zones (such as Java technology, Linux, Open source, XML), My tags shows your tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), My tags shows your tags for just that product zone.

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Special offers