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

Subject: RE: [xsl] Merging multiple documents and combining their nodes
From: "Michael Kay" <mike@xxxxxxxxxxxx>
Date: Wed, 13 Jun 2007 14:26:51 +0100
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="{@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@xxxxxxxxx] 
> Sent: 13 June 2007 14:09
> To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
> 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

Current Thread