Reputation: 85
i have two xml files as given below file1.xml and file2.xml
file1.xml:
<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet type="text/xsl" href="test.xsl"?>
<serviceProviders>
<code>Test</code>
<skin>
<code>default</code>
<label>Default</label>
<sortOrder>99</sortOrder>
</skin>
<serviceProviderProperties>
<propertyGroup>
<code>tabConfiguration</code>
<label>Tab Configuration</label>
<sortOrder>99</sortOrder>
</propertyGroup>
<name>clinicalTabContainer</name>
<value>clinical</value>
<sortOrder>1</sortOrder>
</serviceProviderProperties>
</serviceProviders>
file2.xml:
<?xml version="1.0" encoding="ISO-8859-1"?>
<serviceProviders>
<code>Test</code>
<idPrefix>KNWC</idPrefix>
<skin>
<code>default</code>
<label>Default</label>
<!--<sortOrder>99</sortOrder>-->
</skin>
<serviceProviderProperties>
<propertyGroup>
<code>tabConfiguration</code>
<label>Tab Configuration</label>
<sortOrder>99</sortOrder>
</propertyGroup>
<name>clinicalTabContainer</name>
<value>clinical</value>
<sortOrder>1</sortOrder>
</serviceProviderProperties>
<serviceProviderProperties>
<name>autoSubmitServiceDescription</name>
<value>Primary Mental Health</value>
<sortOrder>99</sortOrder>
</serviceProviderProperties>
</serviceProviders>
I want to compare these two xml and using test.xsl print the difference. I have got this XSL file also. But i am not getting desired result... where I went wrong can you explain and fix it?
test.xsl
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exslt="http://exslt.org/common" version="1.0">
<!-- Replace // with / everywhere if we're only interested
in immediate children of /RootElement. -->
<xsl:variable name="docA" select="/" />
<xsl:variable name="docB" select="document('file3.xml')"/>
<!-- This produces a whole nother copy of both docs!
So, is the performance cost worth it?? -->
<xsl:variable name="sortedNodesA">
<!-- produce a sorted, flattened RTF of A's nodes -->
<xsl:for-each select="$docA/RootElement//*">
<xsl:sort select="name()" />
<xsl:copy-of select="." />
</xsl:for-each>
</xsl:variable>
<xsl:variable name="sortedNodesB">
<!-- produce a sorted, flattened RTF of B's nodes -->
<xsl:for-each select="$docB/RootElement//*">
<xsl:sort select="name()" />
<xsl:copy-of select="." />
</xsl:for-each>
</xsl:variable>
<xsl:template name="recurse">
<xsl:param name="nodesA" />
<xsl:param name="nodesB" />
<xsl:if test="$nodesA | $nodesB">
<xsl:variable name="nameA" select="name($nodesA[1])" />
<xsl:variable name="nameB" select="name($nodesB[1])" />
<xsl:variable name="compar">
<xsl:call-template name="compare-names">
<xsl:with-param name="a" select="$nodesA[1]" />
<xsl:with-param name="b" select="$nodesB[1]" />
</xsl:call-template>
</xsl:variable>
<xsl:template match="/">
<xsl:call-template name="recurse">
<xsl:with-param name="nodesA"
select="exslt:node-set($sortedNodesA)/*" />
<xsl:with-param name="nodesB"
select="exslt:node-set($sortedNodesB)/*" />
</xsl:call-template>
</xsl:template>
<xsl:choose>
<xsl:when test="0 > $compar"> <!-- $nodesA[1] is alph. first -->
<p><xsl:value-of select="$nameA" /> is only in Old XML.</p>
<xsl:call-template name="recurse">
<xsl:with-param name="nodesA" select="$nodesA[position()>1]" />
<xsl:with-param name="nodesB" select="$nodesB" />
</xsl:call-template>
</xsl:when>
<xsl:when test="$compar > 0"> <!-- $nodesB[1] is alph. first -->
<p><xsl:value-of select="$nameB" /> is only in New XML.</p>
<xsl:call-template name="recurse">
<xsl:with-param name="nodesA" select="$nodesA" />
<xsl:with-param name="nodesB" select="$nodesB[position()>1]" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<p><xsl:value-of select="$nameB" /> is in both documents.
<!-- Do I need string(text(...))? -->
<xsl:if
test="string($nodesA[1]/text()) != string($nodesB[1]/text())">
But their contents differ:
'<xsl:value-of select="$nodesA[1]/text()" />' !=
'<xsl:value-of select="$nodesB[1]/text()" />'.
</xsl:if><br></br>
</p>
<xsl:call-template name="recurse">
<xsl:with-param name="nodesA" select="$nodesA[position()>1]" />
<xsl:with-param name="nodesB" select="$nodesB[position()>1]" />
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
thanks in advance...
Upvotes: 2
Views: 1354
Reputation: 162
If the XML be input as a single file for example ;
<root>
<old>
file 1 xml
</old>
<new>
file 2 xml
</new>
</root>
You may be able to use something liek the below, Allthough i am running tests on this currently and struggling! but you may have a better background in XSLT than myself and be able to figure it out
<xsl:key name="old" match="root/old/serviceProviders/*" use="." />
<xsl:key name="new" match="root/new/serviceProviders/*" use="." />
<xsl:template match="*">
<xsl:copy>
<xsl:copy-of select="@*" />
<xsl:apply-templates />
</xsl:copy>
</xsl:template>
<xsl:template match="root/new/serviceProviders/*[key('old', .)]">
</xsl:template>
<xsl:template match="root/old/serviceProviders/*[key('new', .)]">
</xsl:template>
Hopefully you can see what i am trying to do here, i have used this before, only i was checking certain field names and could add this restriction as well as outputting to new field names (not needing the existing structure
Using your XML in the above suggested format, this outputs the following, this isn't perfect, but it is getting close.....
<old>
<serviceProviders>
<skin>
<code>default</code>
<label>Default</label>
<sortOrder>99</sortOrder>
</skin>
</serviceProviders>
</old>
<new>
<serviceProviders>
<idPrefix>KNWC</idPrefix>
<skin>
<code>default</code>
<label>Default</label>
</skin>
<serviceProviderProperties>
<name>autoSubmitServiceDescription</name>
<value>Primary Mental Health</value>
<sortOrder>99</sortOrder>
</serviceProviderProperties>
</serviceProviders>
</new>
Still along way to go as i am struggling to pick up the Parent nodes of some elements etc. but hopefully this will help and someone can turn my nonesense into some useful code for you!
Upvotes: 1