[xsl] Merging multiple documents and combining their nodes

Subject: [xsl] Merging multiple documents and combining their nodes
From: "Mark Peters" <flickrmeister@xxxxxxxxx>
Date: Wed, 13 Jun 2007 09:08:33 -0400
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