Search code examples
xmlxsltmsxsl

xml merge two files using xsl?


I need to merge two similar xml files, but only records which match on common tags, e.g.<type> in the following example:

file1.xml is

<node>
    <type>a</type>
    <name>joe</name>
</node>
<node>
    <type>b</type>
    <name>sam</name>
</node>

file2.xml is

<node>
    <type>a</type>
    <name>jill</name>
</node>

so that I have an output of

<node>
    <type>a</type>
    <name>jill</name>
    <name>joe</name>
</node>
<node>
    <type>b</type>
    <name>sam</name>
</node>

What are the basics of doing this, in xsl? Many thanks.


Solution

  • This stylesheet:

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:key name="kElementByType" match="*[not(self::type)]" use="../type"/>
        <xsl:param name="pSource2" select="'file2.xml'"/>
        <xsl:variable name="vSource2" select="document($pSource2,/)"/>
        <xsl:template match="node()|@*" name="identity">
            <xsl:copy>
                <xsl:apply-templates select="node()|@*"/>
            </xsl:copy>
        </xsl:template>
        <xsl:template match="type">
            <xsl:variable name="vCurrent" select="."/>
            <xsl:call-template name="identity"/>
            <xsl:for-each select="$vSource2">
                <xsl:apply-templates select="key('kElementByType',$vCurrent)"/>
            </xsl:for-each>
        </xsl:template>
    </xsl:stylesheet>
    

    With this input (wellformed):

    <root>
        <node>
            <type>a</type>
            <name>joe</name>
        </node>
        <node>
            <type>b</type>
            <name>sam</name>
        </node>
    </root>
    

    Output:

    <root>
        <node>
            <type>a</type>
            <name>jill</name>
            <name>joe</name>
        </node>
        <node>
            <type>b</type>
            <name>sam</name>
        </node>
    </root>