title: dynamically concatenating xml files with ant and xslt
body: <h1>Question</h1>
  
  <p>We have a large number of xml configuration files that we want merged into one master version at build time. Smaller config files are easier to maintain and one large file loads faster so I imagined this to be a popular build transformation process that I would find lots of good examples of on the net. </p>
  
  <p>I was able to find some good solutions to one part of the problem <a href="https://stackoverflow.com/questions/217591/concatenating-xml-files-with-xslt">here at StackOverflow</a> but they all rely upon knowing the names of the xml files that need merging up front. This seems like an unnecessary overhead to me. It should be possible to write a build script which can dynamically calculate which input xml files are needed.</p>
  
  <p>Unfortunately, the only way I could find to achieve this was a bit of a hack. It works like this,</p>
  
  <ol>
  <li>Use a random ant task I stole of the internet to write a directory listing into an xml file.</li>
  <li>Feed the xml file into an xslt transformation that can then load the other directory listing referenced xml files and concatenate them.</li>
  <li>Delete the temporary xml file containing the directory listing.</li>
  </ol>
  
  <p>Here's the ant script</p>
  
  <pre><code>&lt;taskdef name="xml-dir-list"
    classname="net.matthaynes.xml.dirlist.AntFileListing"
    classpath="antlib/xml-dir-listing.0.1.jar;
      antlib/jakarta-regexp-1.5.jar;antlib/log4j-1.2.14.jar"/&gt;
  
  &lt;macrodef name="build-plugin-xml" description="todo"&gt;
      &lt;attribute name="pluginName"/&gt;
  
      &lt;xml-dir-list depth="0" verbose="false" 
        srcDir="${src.dir}/@{pluginName}/forms/" includesRegEx="\.xml$" 
        destFile="${src.dir}/@{pluginName}/forms/fileList.xml"/&gt;
  
      &lt;xslt in="${src.dir}/forms/fileList.xml"
        out="${src.dir}/@{pluginName}/@{pluginName}_extn.yuix
        style="${src.dir}/@{pluginName}/forms/extn.yuix.xsl" /&gt;
  
      &lt;delete file="${src.dir}/@{pluginName}/forms/fileList.xml"/&gt;
  &lt;/macrodef&gt;
  </code></pre>
  
  <p>And here's the stylesheet,</p>
  
  <pre><code>&lt;xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
      &lt;xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/&gt;
  
      &lt;xsl:template match="/"&gt;
          &lt;Forms applicationId="YFSSYS00011"&gt;
              &lt;GlobalExtensions&gt;
                  &lt;Tasks/&gt;
              &lt;/GlobalExtensions&gt; 
              &lt;xsl:apply-templates select="directory/file"/&gt;
          &lt;/Forms&gt;
      &lt;/xsl:template&gt;
  
      &lt;xsl:template match="file"&gt;
          &lt;xsl:copy-of select="document(@name)/Forms/Form"/&gt;
      &lt;/xsl:template&gt;
  &lt;/xsl:stylesheet&gt;
  </code></pre>
  
  <p>Has anyone found a simpler way to achieve this dynamic discovery of what files to merge in XSLT? It's not surprising that XSLT cannot read directories directly, but I was hoping to find a simpler way to pass in a list of file names than through another xml file.</p>
  
  <h1>Implemented Solution</h1>
  
  <p><a href="https://stackoverflow.com/questions/501133/dynamically-concatenating-xml-files-with-ant-and-xslt/501534#501534">Dimitre's solution</a> worked great once I'd made a few extra tweaks to the ant script,</p>
  
  <pre><code>&lt;taskdef name="saxon-xslt" classname="net.sf.saxon.ant.AntTransform"
    classpath="antlib/saxon9.jar;antlib/saxon9-ant.jar"/&gt;
  </code></pre>
  
  <p>[...]</p>
  
  <pre><code>&lt;macrodef name="build-plugin-xml" description="todo"&gt;
      &lt;attribute name="pluginName"/&gt;
  
      &lt;saxon-xslt 
        in="build.xml"
        out="${compca.src.dir}/temp/@{pluginName}/@{pluginName}_extn.yuix"
        style="antscripts/extn.yuix.xsl"&gt;
      &lt;param name="formsDir" 
        expression="${compca.src.dir}/@{pluginName}/forms/"/&gt;
      &lt;/saxon-xslt&gt;
  &lt;/macrodef&gt;
  </code></pre>
  
  <p>and the xsl stylesheet (which I moved)</p>
  
  <pre><code>   &lt;xsl:stylesheet version="1.0" 
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
        &lt;xsl:param name="formsDir" /&gt;
          &lt;xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/&gt;
  
          &lt;xsl:template match="/"&gt;
              &lt;Forms applicationId="YFSSYS00011"&gt;
                  &lt;GlobalExtensions&gt;
                      &lt;Tasks/&gt;
                  &lt;/GlobalExtensions&gt;
                  &lt;xsl:apply-templates select=
                    "collection(
                    concat('file:///',
                    $formsDir,
                    '?select=*.yuix;recurse=yes;on-error=ignore'
                    )
                    )/*
                  "/&gt;
              &lt;/Forms&gt;
  
          &lt;/xsl:template&gt;
  
          &lt;xsl:template match="file"&gt;
              &lt;xsl:copy-of select="/Forms/Form"/&gt;
          &lt;/xsl:template&gt;
      &lt;/xsl:stylesheet&gt;
  </code></pre>
  
  <p>Those tweaks were just around getting Saxon9 to load and setting the directory with a parameter.</p>