Reputation: 279
I am completely new to XSLT so please bear with me.
I have two xml files that I am attempting to concatenate together using XSLT. I would like to combine the files such that any values specified in the second file override the first. E.g.
firstFile.xml
<person>
<person-name>Sandy</person-name>
<person-age>21</person-age>
</person>
<person>
<person-name>Bob</person-name>
<person-age>15</person-age>
</person>
override.xml
<person>
<person-name>Bob</person-name>
<person-age>21</person-age>
</person>
Result:
<person>
<person-name>Sandy</person-name>
<person-age>21</person-age>
</person>
<person>
<person-name>Bob</person-name>
<person-age>21</person-age>
</person>
My template for concatenating the 2 files is as follows:
<xsl:template match="/">
<!-- MainFile -->
<xsl:copy-of select="/*"/>
<!-- Overrides-->
<xsl:copy-of select="document($overrideFile)/*"/>
</xsl:template>
I was attempting to setup a for-each loop such that before copying each person in firstFile.xml check if there is a corresponding node in override.xml, but was unsuccessful.
Any tips would be greatly appreciated
Upvotes: 2
Views: 900
Reputation: 243449
This transformation:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="pDoc2Url" select="'file:///c:/temp/delete/override.xml'"/>
<xsl:variable name="vDoc2" select="document($pDoc2Url)"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*">
<t>
<xsl:apply-templates
select="person[not(person-name = $vDoc2/*/person/person-name)]"/>
<xsl:apply-templates select="$vDoc2/*/person"/>
</t>
</xsl:template>
</xsl:stylesheet>
when applied on the first of the provided XML documents (wrapped into a single top element -- to be made a well-formed XML document):
<t>
<person>
<person-name>Sandy</person-name>
<person-age>21</person-age>
</person>
<person>
<person-name>Bob</person-name>
<person-age>15</person-age>
</person>
</t>
and being passed as parameter the filename where the second document (again wrapped into a top element) resides -- here is the corrected second document:
c:/temp/delete/override.xml:
<t>
<person>
<person-name>Bob</person-name>
<person-age>21</person-age>
</person>
</t>
produces the wanted, correct result:
<t>
<person>
<person-name>Sandy</person-name>
<person-age>21</person-age>
</person>
<person>
<person-name>Bob</person-name>
<person-age>21</person-age>
</person>
</t>
II. A shorter, but less flexible solution -- no identity rule and no xsl:apply-templates
:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="pDoc2Url" select="'file:///c:/temp/delete/override.xml'"/>
<xsl:variable name="vDoc2" select="document($pDoc2Url)"/>
<xsl:template match="/*">
<t>
<xsl:copy-of
select="person[not(person-name = $vDoc2/*/person/person-name)]"/>
<xsl:copy-of select="$vDoc2/*/person"/>
</t>
</xsl:template>
</xsl:stylesheet>
Upvotes: 3