title: Merge multiple XML files at group levels with XSLT
body: <p>First, let me say that I have enjoyed reading dozens of tips about merging multiple XML files. I've also enjoyed implementing a good number of them. But I still haven't achieved my goal.</p>
  
  <p>I don't want to simply merge XML files so that one is repeated after another in the resulting XML file. I have groups with repeating elements that need to each be merged:</p>
  
  <pre><code>&lt;SAN&gt;
    &lt;EQLHosts&gt;
      &lt;WindowsHosts&gt;
        &lt;WindowsHost&gt;
          more data and structures down here...
        &lt;/WindowsHost&gt;
      &lt;/WindowsHosts&gt;
      &lt;LinuxHosts&gt;
        &lt;LinuxHost&gt;
          ...and here...
        &lt;/LinuxHost&gt;
      &lt;/LinuxHosts&gt;
    &lt;/EQLHosts&gt;
  &lt;/SAN&gt;
  </code></pre>
  
  <p>Each of the individual XML files might have Windows and/or Linux hosts.  So if XML file 1 has data for Windows host <strong>A</strong>, <strong>B</strong> and <strong>C</strong>, and XML file 2 has data for Windows hosts <strong>D</strong>, <strong>E</strong> and <strong>F</strong>, the resulting XML should look like:</p>
  
  <pre><code>&lt;SAN&gt;
    &lt;EQLHosts&gt;
      &lt;WindowsHosts&gt;
        &lt;WindowsHost&gt;
          &lt;Name&gt;A&lt;/Name&gt;
        &lt;/WindowsHost&gt;
        &lt;WindowsHost&gt;
          &lt;Name&gt;B&lt;/Name&gt;
        &lt;/WindowsHost&gt;
        &lt;WindowsHost&gt;
          &lt;Name&gt;C&lt;/Name&gt;
        &lt;/WindowsHost&gt;
        &lt;WindowsHost&gt;
          &lt;Name&gt;D&lt;/Name&gt;
        &lt;/WindowsHost&gt;
        &lt;WindowsHost&gt;
          &lt;Name&gt;E&lt;/Name&gt;
        &lt;/WindowsHost&gt;
        &lt;WindowsHost&gt;
          &lt;Name&gt;F&lt;/Name&gt;
        &lt;/WindowsHost&gt;
      &lt;/WindowsHosts&gt;
      &lt;LinuxHosts&gt;
        &lt;LinuxHost/&gt;
      &lt;/LinuxHosts&gt;
    &lt;/EQLHosts&gt;
  &lt;/SAN&gt;
  </code></pre>
  
  <p>I have used this XSLT, among others, to get this to work:</p>
  
  <pre><code>&lt;?xml version="1.0"?&gt;
  &lt;xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
  
    &lt;xsl:output indent="yes"/&gt;
    &lt;xsl:strip-space elements="*"/&gt;
  
    &lt;xsl:variable name="file1" select="document('CorralData1.xml')"/&gt;
    &lt;xsl:variable name="file2" select="document('CorralData2.xml')"/&gt;
    &lt;xsl:variable name="file3" select="document('CorralData3.xml')"/&gt;
  
    &lt;xsl:template match="/"&gt;
      &lt;SAN&gt;
        &lt;xsl:copy-of select="/SAN/*"/&gt;
        &lt;xsl:copy-of select="$file1/SAN/*"/&gt;
        &lt;xsl:copy-of select="$file2/SAN/*"/&gt;
        &lt;xsl:copy-of select="$file3/SAN/*"/&gt;
      &lt;/SAN&gt;
    &lt;/xsl:template&gt;
  
  &lt;/xsl:stylesheet&gt;
  </code></pre>
  
  <p>This file produces a combined XSLT, with all data all the way down the tree included correctly, but with multiple instances of WindowsHosts.  Don't want that.</p>
  
  <p>Is there a way to tell XSLT how to do this with a minimum of syntax, or do I need to add each element and sub-element specifically in the XSLT file?</p>
  
  <hr>
  
  <p>I should have checked.  But I went ahead and used collection() and got a solution to work perfectly using the Saxon HE XSLT processor.</p>
  
  <p>But I'm running in an InfoPath environment, and there's only an XSLT 1.0 processor. Does anyone have a recommendation for replacing the collection() command in an XSLT 1.0 environment?  Can I go back to using document() in some way?</p>
  
  <hr>
  
  <p>So I now have this file...</p>
  
  <pre><code>&lt;?xml version="1.0" encoding="windows-1252"?&gt;
  
  &lt;files&gt;
      &lt;file name="CorralData1.xml"/&gt;
      &lt;file name="CorralData2.xml"/&gt;
  &lt;/files&gt;
  </code></pre>
  
  <p>...which I use with a stylesheet containing...</p>
  
  <pre><code>&lt;xsl:variable name="windowsHosts" select="/SAN/WindowsHosts/WindowsHost"/&gt;
  &lt;xsl:variable name="vmwareHosts" select="/SAN/VMwareHosts/VMwareHost"/&gt;
  &lt;xsl:variable name="linuxHosts" select="/SAN/LinuxHosts/LinuxHost"/&gt;
  
  &lt;xsl:template match="@*|node()"&gt;
      &lt;xsl:copy&gt;
          &lt;xsl:apply-templates select="@*|node()"/&gt;
      &lt;/xsl:copy&gt;
  &lt;/xsl:template&gt;
  
  &lt;xsl:template match="/"&gt;
      &lt;xsl:for-each select="/files/file"&gt;
          &lt;xsl:apply-templates select="document(@name)/SAN"/&gt;
      &lt;/xsl:for-each&gt;
      &lt;SAN&gt;
          &lt;EQLHosts&gt;
              &lt;WindowsHosts&gt;
                  &lt;xsl:for-each select="$windowsHosts"&gt;
                      &lt;xsl:copy-of select="."/&gt;
                  &lt;/xsl:for-each&gt;
              &lt;/WindowsHosts&gt;
              &lt;VMwareHosts&gt;
                  &lt;xsl:for-each select="$vmwareHosts"&gt;
                      &lt;xsl:copy-of select="."/&gt;
                  &lt;/xsl:for-each&gt;                 
              &lt;/VMwareHosts&gt;
              &lt;LinuxHosts&gt;
                  &lt;xsl:for-each select="$linuxHosts"&gt;
                      &lt;xsl:copy-of select="."/&gt;
                  &lt;/xsl:for-each&gt;                 
              &lt;/LinuxHosts&gt;
          &lt;/EQLHosts&gt;
      &lt;/SAN&gt;
  &lt;/xsl:template&gt;
  </code></pre>
  
  <p>...but this gets me multiple /SAN roots.  I'm close but something's still a little off.</p>