[xsl] Merging multiple documents and combining the results

Subject: [xsl] Merging multiple documents and combining the results
From: "Mark Peters" <flickrmeister@xxxxxxxxx>
Date: Fri, 2 Nov 2007 09:11:25 -0400
Hi Everyone,

I have several files that I'm trying to merge into a single document.
In the examples below, I'm trying to combine the component nodes based
on the id attribute of the name sub-node.

File 1:

<?xml version="1.0" encoding="UTF-8"?>
<notification>
    <components>
        <component>
            <name id="cpobj1">Fish</name>
            <mode>Swims</name>
        </component>
        <component>
            <name id="cpobj35">Giraffe</name>
            <mode>Walks</name>
        </component>
    </components>
</notification>

File 2:

<?xml version="1.0" encoding="UTF-8"?>
<notification>
    <components>
        <component>
            <name id="cpobj1">Fish</name>
            <skin>Scales</skin>
        </component>
        <component>
            <name id="cpobj45">Ball</name>
            <shape>Round</shape>
        </component>
    </components>
</notification>

File 2:

<?xml version="1.0" encoding="UTF-8"?>
<notification>
    <components>
        <component>
            <name id="cpobj3">Bird</name>
            <mode>Flies</name>
        </component>
        <component>
            <name id="cpobj45">Ball</name>
            <mode>Rolls</name>
        </component>
    </components>
</notification>


My output would resemble the following:


<?xml version="1.0" encoding="UTF-8"?>
<notification>
    <components>
        <component>
            <name id="cpobj1">Fish</name>
            <mode>Swims</name>
            <skin>Scales</skin>
        </component>
        <component>
            <name id="cpobj35">Giraffe</name>
            <mode>Walks</name>
        </component>
        <component>
            <name id="cpobj45">Ball</name>
            <shape>Round</shape>
            <mode>Rolls</name>
        </component>
        <component>
            <name id="cpobj3">Bird</name>
            <mode>Flies</name>
        </component>
    </components>
</notification>


I used the following transformation:


<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
xmlns:exslt="http://exslt.org/common";>
       <xsl:output indent="yes"/>
       <xsl:template match="/">
               <xsl:variable name="temp">
                       <components>
                               <xsl:copy-of
select="document(/files/file)/notification/components/component"/>
                       </components>
               </xsl:variable>
               <notification>
                   <components>
                        <xsl:for-each
select="exslt:node-set($temp)/components/component[generate-id()=generate-id(key('c',name/@id))]">
                             <xsl:sort select="name/@id"/>
<xsl:copy>
<xsl:copy-of select="@*|key('c',name/@id)/*"/>
                               </xsl:copy>
                      </xsl:for-each>
                   </components>
               </notification>
       </xsl:template>
       <xsl:key name="c" match="component" use="name/@id"/>
</xsl:stylesheet>


The output doesn't combine the component nodes by /name/@id. Each
component is treated as a separate node, with no relationship with any
other node.

<?xml version="1.0" encoding="UTF-8"?>
<notification xmlns:exslt="http://exslt.org/common";>
    <components>
        <component>
            <name id="cpobj1">Fish</name>
            <mode>Swims</name>
        </component>
        <component>
            <name id="cpobj35">Giraffe</name>
            <mode>Walks</name>
        </component>
        <component>
            <name id="cpobj1">Fish</name>
            <skin>Scales</skin>
        </component>
        <component>
            <name id="cpobj45">Ball</name>
            <shape>Round</shape>
        </component>
        <component>
            <name id="cpobj3">Bird</name>
            <mode>Flies</name>
        </component>
        <component>
            <name id="cpobj45">Ball</name>
            <mode>Rolls</name>
        </component>
    </components>
</notification>

Does anyone know how I could combine the component nodes based on the
name/@id value?

Thanks,
Mark


-- 

Mark Peters
Senior Technical Writer
Saba Software

Current Thread