Ant Patterns – Continued

This is a follow up post of the previous one about the build tool Apache Ant and usage patterns called Ant Patterns.

Converting a Path to a Property

You can use Ant to gather a list of files from a fileset and convert this using pathconvert to a property with each file on a separate line. The property ${line.separator} is a JVM and OS dependent system property which is automatically available for every ant script.

<fileset id="my.files" dir="." includes="**/*.php">
      <!-- any condition, etc. ... -->
</fileset>
<!-- joins all files together into one string -->
<pathconvert pathsep="${line.separator}" property="my.files.flattend" refid="my.files"/>

The resulting property can then by piped to a program which receives the list on its standard input (STDIN) adhereing to the Unix principles. An example is shown below which uses a ruby script.

<fileset id="my.files" dir="." includes="**/*.php">
      <!-- any condition, etc. ... -->
</fileset>
<!-- joins all files together into one string -->
<pathconvert pathsep="${line.separator}" property="my.files.flattend" refid="my.files"/>
<!-- pipes the list of all files seperated by new lines to a script -->
<exec executable="ruby.exe" inputstring="${my.files.flattend}">
      <arg value="${my.script.name}"/>
</exec>

Note: Usage of the Ant Pattern Executing Platform Independent from the previous post in conjunction with this pattern is strongly recommended.

Ant as a Template System

Ant can use its property resolution mechanism for evaluating templates. This is useful if you need to generate files using templates. The templates can be read from any file while the properties can be stated within the ant file directly, read from a property file, xml file or requested from the user. An example is given below with leverages the copy task with its filterchain which can provide additional operations for the files to be copied, in this case the expansion of the properties. The filterchain basically implements the Unix pipes the Ant way.

<!-- make sure properties are set using the property, propertyfile, xmlproperty or input task -->
<property name="name" value="World" />

<!-- apply template by copying -->
<copy file="${template}" tofile="${target}"> 
  <filterchain> 
    <!-- fill the blanks with values -->
    <expandproperties/> 
  </filterchain> 
</copy>

Given the contents of the template.tt are Hello ${name}, the contents of the ${target} file will be Hello World.

This approach gives only simple property expansion as loops, conditions or any other mechanism normally used in templates does not work. However, this may suffice for some use cases.

Formatting XML Files Resulting from XSLT Transformations

Ant can use xslt stylesheets in the xslt task to transform a XML file to another XML file or simple text. In many cases, the result is another XML file which should look formatted well. However, Ant uses by default Apache Xalan as its XSL engine which contains a bug ignoring the indent attribute of the ouput tag. The listing below shows such the stub of a stylesheet which results in unindented XML code.

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes" encoding="UTF-8"/>
    <!-- templates and stuff -->
</xsl:stylesheet>

This can be solved by adding the special indent-amount attribute to the output element with the namespace http://xml.apache.org/xslt and set it, for example, to 4 spaces.

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xalan="http://xml.apache.org/xslt">
    <xsl:output method="xml" indent="yes" encoding="UTF-8" xalan:indent-amount="4"/>
    <!-- templates and stuff -->
</xsl:stylesheet>

More information about this can be found here.

Additional Links

Advertisements

Line Separators

Line separators are a funny problem in itself. Each operating system uses different kind of escape sequences to determine a new line.

  • Windows: \r\n
  • Unix/Linux/Mac OS X: \n
  • pre-OSX Mac: \r

Orignially, the write head of typewriters could only do few tasks. I listed the most important ones below:

  • Write symbol and move the cursor one column to the right.
  • \r | carriage return | CR | Move cursor to the first column of the line.
  • \n | line feed         | LF | Move cursor to the next row/line at the same column.
  • \b | backspace     | BS | Move cursor one column back.
  • \t | horizontal tab  | HT | Move cursor to the next tab-stop.
In order to get the cursor to the beginning of the new line, you needed to use a carriage return followed by a line feed. This behaviour resulted in the \r\n escape sequence of windows. Others simplified it by selecting either \n or \r.

In Java, which is plattform independent, you get the plattform dependent escape sequence by obtaining the system property named line.separator.

String lineSeparator = System.getProperty("line.separator");

Other plattform specific system properties as the path.separator (backslash or slash) can be found at this guide.