Comparing nodes that have attributes that match

Here should go questions about transforming XML with XSLT and FOP.
chris999

Comparing nodes that have attributes that match

Post by chris999 »

Hello folks,

I'm trying to use XSLT to compare two xml documents and display just the changes found. I've prepared some example documents below: ContactsBefore.xml and ContactsAfter.xml. Now my first assumption is I probably needed to get both documents merged into a single xml document for the XSLT template to work on. I've also provided that merged document below called ContactsChanges.xml.

The very last code snippet below is my XSLT attempt with some obvious errors. This XSLT is attempting to test if the surname has changed and output a row of change data if it has.

My obvious question is in the test predicate and value-of, I'm trying to access the nodes with the same attribute values for id using

Code: Select all

/changes/after/contacts/contact[@id = @id]/lastname
This doesn't work and I can't see in any XSLT documentation I have read how the syntax of these predicate expressions can refer to anything other than the contect node. Anybody got any ideas?

In summary, there are two aspects to my question:

1) How would you go about comparing two documents in XSLT?

2) Even if I'm totally barking up the wrong tree here, I am hoping to learn something fundamental about XSLT that I clearly haven't grasped yet. Is there a way to say things like: "Give me the value of another node (somewhere else in the tree) which has the same value for a certain attribute as the contect node has."?

Your help would be much appreciated.

Please ignore the previous post. It was a test.



ContactsBefore.xml

Code: Select all


<?xml version="1.0" encoding="ISO-8859-1"?>
<contacts>
<contact id="1">
<firstname>Bob</firstname>
<lastname>Jones</lastname>
<address1>71 Southgate Street</address1>
<address2></address2>
<address3></address3>
<town>Gloucester</town>
<postcode>GL1 1SH</postcode>
</contact>
<contact id="2">
<firstname>Bill</firstname>
<lastname>Smith</lastname>
<address1>19 Gosditch Street</address1>
<address2></address2>
<address3></address3>
<town>Cirencester</town>
<postcode>GL7 2AG</postcode>
</contact>
<contact id="3">
<firstname>Amanda</firstname>
<lastname>Smith</lastname>
<address1>8 Bennington Street</address1>
<address2></address2>
<address3></address3>
<town>Cheltenham</town>
<postcode>GL60 4ED</postcode>
</contact>
</contacts>
ContactsAfter.xml

Code: Select all


<?xml version="1.0" encoding="ISO-8859-1"?>
<contacts>
<contact id="1">
<firstname>Bob</firstname>
<lastname>Jones</lastname>
<address1>8 Bennington Street</address1>
<address2></address2>
<address3></address3>
<town>Cheltenham</town>
<postcode>GL60 4ED</postcode>
</contact>
<contact id="2">
<firstname>Bill</firstname>
<lastname>Smith</lastname>
<address1>19 Gosditch Street</address1>
<address2></address2>
<address3></address3>
<town>Cirencester</town>
<postcode>GL7 2AG</postcode>
</contact>
<contact id="3">
<firstname>Amanda</firstname>
<lastname>Smith-Jones</lastname>
<address1>8 Bennington Street</address1>
<address2></address2>
<address3></address3>
<town>Cheltenham</town>
<postcode>GL60 4ED</postcode>
</contact>
</contacts>
ContactsChanges.xml

Code: Select all


<?xml version="1.0" encoding="ISO-8859-1"?>
<changes>
<before>
<contacts>
<contact id="1">
<firstname>Bob</firstname>
<lastname>Jones</lastname>
<address1>71 Southgate Street</address1>
<address2></address2>
<address3></address3>
<town>Gloucester</town>
<postcode>GL1 1SH</postcode>
</contact>
<contact id="2">
<firstname>Bill</firstname>
<lastname>Smith</lastname>
<address1>19 Gosditch Street</address1>
<address2></address2>
<address3></address3>
<town>Cirencester</town>
<postcode>GL7 2AG</postcode>
</contact>
<contact id="3">
<firstname>Amanda</firstname>
<lastname>Smith</lastname>
<address1>8 Bennington Street</address1>
<address2></address2>
<address3></address3>
<town>Cheltenham</town>
<postcode>GL60 4ED</postcode>
</contact>
</contacts>
</before>
<after>
<contacts>
<contact id="1">
<firstname>Bob</firstname>
<lastname>Jones</lastname>
<address1>8 Bennington Street</address1>
<address2></address2>
<address3></address3>
<town>Cheltenham</town>
<postcode>GL60 4ED</postcode>
</contact>
<contact id="2">
<firstname>Bill</firstname>
<lastname>Smith</lastname>
<address1>19 Gosditch Street</address1>
<address2></address2>
<address3></address3>
<town>Cirencester</town>
<postcode>GL7 2AG</postcode>
</contact>
<contact id="3">
<firstname>Amanda</firstname>
<lastname>Smith-Jones</lastname>
<address1>8 Bennington Street</address1>
<address2></address2>
<address3></address3>
<town>Cheltenham</town>
<postcode>GL60 4ED</postcode>
</contact>
</contacts>
</after>
</changes>

CompareContacts.xsl

Code: Select all


<?xml version='1.0'?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

<xsl:template match="/">

<table>
<tr>
<td>Change</td>
<td>Field</td>
<td>Before</td>
<td>After</td>
</tr>

<xsl:for-each select="changes/before/contacts/contact">

<xsl:if test = "lastname != /changes/after/contacts/contact[@id = @id]/lastname">
<tr>
<td><xsl:value-of select="@id"/></td>
<td>Last Name</td>
<td><xsl:value-of select="lastname"/></td>
<td><xsl:value-of select="/changes/after/contacts/contact[@id = @id]/lastname"/></td>
</tr>
</xsl:if>

</xsl:for-each>

</table>

</xsl:template>
</xsl:stylesheet>
george
Site Admin
Posts: 2095
Joined: Thu Jan 09, 2003 2:58 pm

Post by george »

Hi Chris,

You should use current() to refer to the current code. Replace

contact[@id = @id]

with

contact[@id = current()/@id]

Best Regards,
George
chris999
Posts: 1
Joined: Wed Dec 01, 2004 2:41 pm

RE: Comparing nodes that have attributes that match

Post by chris999 »

Thanks George

current() worked great for me. I'm steaming ahead now. Much appreciated.

You do learn something new every day. I thought that current() was simply accessing the context node and was redundant. How wrong was I?
Cheers,


Chris
Post Reply