I want to compare two xmls and then merge them. For example:
myFile1.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<catalog>
<data>
<title>Title1</title>
<description>Description1</description>
<myid>1</myid>
</data>
<data>
<title>Title2</title>
<description>Description2</description>
<myid>2</myid>
</data>
</catalog>
myFile2.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<catalog>
<data>
<title>Title1</title>
<description>Description1</description>
<author>Author1</author>
<date>12/34/5678</date>
<myid>1</myid>
</data>
<data>
<author>Author2</author>
<date>87/65/4321</date>
<myid>2</myid>
</data>
</catalog>
Desired Output:
<?xml version="1.0" encoding="ISO-8859-1"?>
<catalog>
<data>
<title>Title1</title>
<description>Description1</description>
<myid>1</myid>
<author>Author1</author>
<date>12/34/5678</date>
</data>
<data>
<title>Title2</title>
<description>Description2</description>
<myid>2</myid>
<author>Author2</author>
<date>87/65/4321</date>
</data>
</catalog>
I have a code but, it doesnot perform as per the required output.
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="ISO-8859-1" indent="yes"/>
<xsl:variable name="compare" select="'myFile1.xml'"/>
<xsl:variable name="with" select="'myFile2.xml'"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
<xsl:variable name="info1" select="document($compare)/catalog/data[myid=current()/myid]/."/>
<xsl:variable name="info2" select="document($with)/catalog/data[myid=current()/myid]/."/>
<xsl:for-each select="$info1/*">
<xsl:variable name="check1" select="name(current())"/>
<!--xsl:text>Current node1 : </xsl:text><xsl:value-of select="$check1"/-->
<xsl:for-each select="$info2/*">
<xsl:variable name="check2" select="name(current())"/>
<!--xsl:text>Current node2 : </xsl:text><xsl:value-of select="$check2"/-->
<xsl:if test="$check1!=$check2">
<xsl:copy-of select="."/>
</xsl:if>
</xsl:for-each>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:transform>
Please Help!
This solution is totally free of loops or keys. I've loaded only one document using document()
, while I use the other one as source. Briefly, an element missing in the source document, it is taken on the loaded one. More elements you have less usable is this solution. See bottom for a more general one.
XSLT 1.0 tested on Saxon-HE 9.2.1.1J
<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:variable name="catalog2" select="document('source_test2.xml')/catalog"/>
<xsl:template match="catalog">
<catalog>
<xsl:apply-templates select="data"/>
</catalog>
</xsl:template>
<xsl:template match="data">
<xsl:variable name="data2" select="$catalog2/data[myid=current()/myid]/."/>
<data>
<xsl:choose>
<xsl:when test="title">
<xsl:copy-of select="title"/>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="$data2/title"/>
</xsl:otherwise>
</xsl:choose>
<xsl:choose>
<xsl:when test="description">
<xsl:copy-of select="description"/>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="$data2/description"/>
</xsl:otherwise>
</xsl:choose>
<xsl:copy-of select="myid"/>
<xsl:choose>
<xsl:when test="author">
<xsl:copy-of select="author"/>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="$data2/author"/>
</xsl:otherwise>
</xsl:choose>
<xsl:choose>
<xsl:when test="date">
<xsl:copy-of select="date"/>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="$data2/date"/>
</xsl:otherwise>
</xsl:choose>
</data>
</xsl:template>
</xsl:stylesheet>
Here follows a more general solution. The approach is the same. For each data
, an element present in myFile2
and missing in myFile1
is added to the result tree, and vice-versa.
XSLT 1.0 tested on Saxon-B 9.0.0.4J
<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:variable name="catalog2" select="document('myFile2.xml')/catalog"/>
<xsl:template match="catalog">
<catalog>
<xsl:apply-templates select="data"/>
</catalog>
</xsl:template>
<xsl:template match="data">
<xsl:variable name="data1" select="."/>
<xsl:variable name="data2" select="$catalog2/data[myid=current()/myid]/."/>
<data>
<xsl:copy-of select="$data1/*"/>
<xsl:for-each select="$data2/*">
<xsl:variable name="element2" select="name(.)"/>
<xsl:if test="count($data1/*[name()=$element2])=0">
<xsl:copy-of select="."/>
</xsl:if>
</xsl:for-each>
</data>
</xsl:template>
</xsl:stylesheet>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With