xsl-list
[Top] [All Lists]

RE: [xsl] Merging multiple documents and combining their nodes

2007-06-13 06:27:18
Are you constrained to XSLT 1.0? If you can use 2.0, it's simple:

<xsl:variable name="docs" select="document(('file1.xml', 'file2.xml',
'file3.xml'))"/>
<xsl:variable name="comps" select="$docs/components/component"/>

<components>
 <xsl:for-each-group select="$comps" group-by="@name">
   <component name="{current-grouping-key()}"
              description="{(_at_)description}">\\\
     <xsl:copy-of select="current-group()/*"/>
   </component>
 </xsl:for-each-group>
</components>

Michael Kay
http://www.saxonica.com/ 

-----Original Message-----
From: Mark Peters [mailto:flickrmeister(_at_)gmail(_dot_)com] 
Sent: 13 June 2007 14:09
To: xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com
Subject: [xsl] Merging multiple documents and combining their nodes

Hi Everyone,

I'm starting with half a dozen files with identical top-level 
structures, but with different child nodes.

For example:

file1.xml

<components>
     <component name="a" description="1">
          <childA>Value</childA>
          <childB>Value</childB>
     </component>
</components>

file2.xml

<components>
     <component name="b" description="2">
          <childC>Value</childC>
          <childD>Value</childD>
     </component>
</components>


file3.xml

<components>
     <component name="a" description="1">
          <childE>Value</childE>
          <childF>Value</childF>
     </component>
</components>

I'm trying to merge all of these files into a single file and 
combine all of the child nodes for <component> elements with 
identical name attributes.


So far, I've been able to merge the documents:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>
      <xsl:output indent="yes"/>
      <xsl:param 
name="sources">file1.xml|file2.xml|file3.xml</xsl:param>
      <xsl:template match="/">
              <components>
                      <xsl:call-template name="loaddocuments"/>
              </components>
      </xsl:template>
      <xsl:template name="loaddocuments">
              <xsl:param name="string" select="concat($sources,'|')"/>
              <xsl:if test="substring-before($string,'|') != ''">
                      <xsl:apply-templates
select="document(substring-before($string,'|'))" mode="merge"/>
              </xsl:if>
              <xsl:if test="contains($string,'|')">
                      <xsl:call-template name="loaddocuments">
                              <xsl:with-param name="string" 
select="substring-after($string,'|')"/>
                      </xsl:call-template>
              </xsl:if>
      </xsl:template>
      <xsl:template match="/" mode="merge">
              <xsl:copy-of select="//component"/>
      </xsl:template>
</xsl:stylesheet>


But the output does not combine the <component> elements::

<components>
     <component name="a" description="1">
          ..
     </component>
     <component name="a" description="1">
          ..
     </component>
     <component name="b" description="1">
          ..
     </component>
</components>


So, then I tried following a few sets of instructions based 
on the information on the "Document" page of Dave Pawson's site
(http://www.dpawson.co.uk/xsl/sect2/N2602.html) and elsewhere.
Specifically, I tried creating a master file to list each of 
my XML files and then references this file in my stylesheet.

For example:

filenames_file.xml

<files>
      <file>file1.xml</file>
      <file>file2.xml</file>
      <file>file3.xml</file>
</files>


Stylesheet:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>
      <xsl:output indent="yes"/>
      <xsl:variable name="mergedset"
select="document('filenames_file.xml')/components/component"/>
      <xsl:template match="/">
              <components>
                      <xsl:apply-templates 
select="$mergedset" mode="process"/>
              </components>
      </xsl:template>
      <xsl:template match="/" mode="process">
              <xsl:apply-templates select="//component/@name">
                      <xsl:sort select="@name"/>
              </xsl:apply-templates>
      </xsl:template>
</xsl:stylesheet>


My output only contained an empty <components/> element.

I've tried applying various combinations of instructions on 
the "Document" page, and have referenced the W3.org page on 
the document() function (http://www.w3.org/TR/xslt#document), 
but have been unsuccessful in achieving the desired output.

I'd appreciate any suggestions.

Thanks,
Mark

-- 

Mark Peters
Senior Technical Writer
Saba Software

--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: 
<mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--



--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: <mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--