Ant: edit property values

One of the frustrations of using ant was the difficulty of deriving one property value performing some sort of editing operation on an existing property value. The mapper task does a lot of grunt work for file names, but not for property values as such.

A common requirement is to map a Java package name to a corresponding directory structure. I have a property containing the package name, and I want to create another property with the directories. Here’s one way to do that.

<property name="my.package" value="my.java.package"/>
<!-- ... Some time later ... -->
<loadresource property="my.package.dirs">
<string value="${my.package}"/>
<filterchain>
<replacestring from="." to="${file.separator}"/>
<striplinebreaks/>
      </filterchain>
</loadresource>

For more complex transformations, a replaceregexp filter can be used. The above example would then be:

<property name="my.package" value="my.java.package"/>
<!-- ... Some time later ... -->
<loadresource property="my.package.dirs">
<string value="${my.package}"/>
<filterchain>
<striplinebreaks/>
<replaceregex pattern="." replace="${file.separator}" flags="g"/>
</filterchain>
</loadresource>

Here’s a macrodef to perform string editing, included in an ant build file called editstring.xml with a test invocation. The base file, without the test, can be downloaded here.

<project name="editstring">
  <macrodef name="editstring"
    description="Edit a string using a regexp pattern and repacement, with optional flags, placing result in a property.">
    <attribute name="string"
      description="String being edited."/>
    <attribute name="dest"
      description="Name of the property receiving the edit result."/>
    <attribute name="pattern"
      description="Regexp pattern to be replaced."/>
    <attribute name="replace"
      description="Regexp replacement pattern."/>
    <attribute name="flags"
      description="Regexp replacement flags."
      default="-g"/>
    <sequential>
      <loadresource property="@{dest}">
        <string value="@{string}"/>
          <filterchain>
            <replaceregex pattern="@{pattern}"
             replace="@{replace}" flags="@{flags}"/>
            <striplinebreaks/>
          </filterchain>
      </loadresource>
    </sequential>
  </macrodef>

  <target name="junk">
    <property name="teststr" value="My test string."/>
    <editstring string="${teststr}" dest="result"
      pattern="^(S+s+)S+(s+.*)$" replace="1result2"/>
    <echo>${teststr} : ${result}</echo>
  </target>
</project>

Be aware of the striplinebreaks filter. I found when I used this method that I was getting a spurious newline on the end of my edited string, so I inserted striplinebreaks. However, if you are editing a multiline string, this will break your replacement. You will have to experiment in those circumstances. I suspect that this is an artifact of the line-at-a-time processing of replacement text. I think it appends a line break after replacement.

I first read about this solution in a post by Mark Melvin. Thanks to Mark.

Leave a Reply

Your email address will not be published. Required fields are marked *