1

Using only Ant and XSLT, I'd like to create an XML file that is a list of XML files in a specific directory.

Ant's concat task doesn't do the job as I end up with a list that's not XML -- ie. it doesn't have a single root element.

I have an XSLT file that I apply, using the XSLT Ant task, that uses the collection() function. This produces exactly the result I want, but it tries to do so for each file in the target directory -- I want just one list. My XSLT is operating on every file in the target directory (collection) -- how can I limit the number of tims the XSLT is applied?

Here's what I have so far:

XML files are in the target directory c:\tmp

This is the XSL file that I apply to the files in the target directory (using the Ant XSLT task);

 <xsl:template match="/">
    <xsl:call-template name="generatelist" />
</xsl:template>

<xsl:template name="generatelist">
    <xsl:result-document href="list.xml">
        <xsl:element name="list">
            <xsl:element name="dir">
                <xsl:for-each
                    select="collection('file:///C:/tmp?select=*.xml')">
                    <xsl:element name="file">
                        <xsl:attribute name="name">
                            <xsl:value-of select="tokenize(document-uri(.), '/')[last()]" />
                        </xsl:attribute>
                    </xsl:element>
                </xsl:for-each>
            </xsl:element>
        </xsl:element>
    </xsl:result-document>
</xsl:template>

And this is the resulting XML list:

<list>
    <dir>
        <file name="filename_1.xml"/>
        <file name="filename_2.xml"/>
         . . .
        <file name="filename_n.xml"/>
    </dir>
</list>

Thanks.

Drew

Adding the Ant XSLT task that I'm using:

<xslt basedir="${staging_2}"
      destdir="${staging_3}" extension=".xml" includes="**/*.xml"
      style="create_list.xsl">     
</xslt>
3
  • So there seems to be nothing wrong with the XSLT, the problem is in the Ant code that calls it. Can you post the relevant snippet of your build.xml? Commented Sep 25, 2013 at 13:38
  • Thanks for your quick response, Ian -- I've added the XSLT task. Commented Sep 25, 2013 at 14:46
  • How the heck do you get this to work when the XML files are in a relative path (e.g. in ${BUILDDIR}/files instead of C:\Tmp)? I tried something like collection(iri-to-uri('./files/?select=*.xml'), but that's not it. Commented Oct 6, 2016 at 17:56

2 Answers 2

3

XSLT really isn't the appropriate tool for your needs. XSLT is best for transforming XML into new XML. In this case, however, the source isn't XML; it's a filesystem directory.

Given this, it's fine to just generate the XML directly. The following Ant script uses the third-party Ant-Contrib library's <for> task:

<project name="ant-echo-xml" default="run" basedir=".">
    <taskdef resource="net/sf/antcontrib/antlib.xml" />

    <target name="run">
        <property name="dest-xml.file" value="list.xml"/>

        <echo file="${dest-xml.file}"
><![CDATA[<list>
    <dir>
]]></echo>

        <for param="src-xml.absolute-path">
            <fileset dir="my-dir" includes="*.xml"/>
            <sequential>
                <local name="src-xml.basename"/>
                <basename property="src-xml.basename" file="@{src-xml.absolute-path}"/>

                <echo file="${dest-xml.file}" append="yes"
>        <![CDATA[<file name="${src-xml.basename}"/>
]]></echo>
            </sequential>
        </for>

        <echo file="${dest-xml.file}" append="yes"
><![CDATA[    </dir>
</list>
]]></echo>
    </target>
</project>

Outputs:

<list>
    <dir>
        <file name="filename_1.xml"/>
        <file name="filename_2.xml"/>
    </dir>
</list>
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for your answer, Chad, and for the Ant code that does the job. I'm more comfortable with XSLT, but I'm keeping a copy of your code for future use. -- Drew
Note that if you are using Ant pre-1.8, you'll need to change the <local> to <var> (which is provided by ant-contrib).
1

Since the XSLT itself takes care of enumerating the file names you just need to run it once, i.e. give it just one file to use as input and one file to use as output. The stylesheet doesn't use anything from the input document so any input file will do as long as it's XML, you could use the stylesheet itself as its own input.

<xslt style="create_list.xsl" in="create_list.xsl" out="list.xsl" />

and remove the <xsl:result-document> from the stylesheet so it just outputs to the default result document (the one specified by out="..." in build.xml).

1 Comment

That's perfect -- thanks very much Ian. I'd thought about using a 'dummy' file of some sort, but I couldn't work out how to get it into the 'basedir', and I don't know beforehand the names of the files in 'basedir'. Using the .xsl file as the dummy input is an excellent idea. Thanks again.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.