source: trunk/Distribution/XSL/slides/keynote/xsltsl/cmp.xsl

Last change on this file was 2, checked in by jkacer, 18 years ago

Added all DocBook Framework stuff:

  • DocBook DTD
  • Transformation software FOP 0.20.5 and Saxon 6
  • XSL styles
  • Rexx scripts

Also added some WarpIN-related stuff for creation of WarpIN installation packages.
This state corresponds to version 1.0.0 from November 2005, just slightly modified to carry versioning information (Rexx scripts).

File size: 11.3 KB
Line 
1<?xml version="1.0"?>
2
3<xsl:stylesheet
4 version="1.0"
5 extension-element-prefixes="doc"
6 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
7 xmlns:doc="http://xsltsl.org/xsl/documentation/1.0"
8 xmlns:str="http://xsltsl.org/string"
9 xmlns:cmp="http://xsltsl.org/cmp"
10 exclude-result-prefixes="cmp str doc"
11>
12
13 <doc:reference xmlns="">
14 <referenceinfo>
15 <releaseinfo role="meta">
16 $Id: cmp.xsl,v 1.1 2004/11/10 06:51:55 balls Exp $
17 </releaseinfo>
18 <author>
19 <surname>Hummel</surname>
20 <firstname>Mark</firstname>
21 </author>
22 <copyright>
23 <year>2003</year>
24 <holder>Mark Hummel</holder>
25 </copyright>
26 </referenceinfo>
27
28 <title>XML Compare</title>
29
30 <partintro>
31 <section>
32 <title>Introduction</title>
33
34 <para>This module provides a template for comparing two xml documents. </para>
35
36 </section>
37 </partintro>
38
39 </doc:reference>
40
41
42 <doc:template name="cmp:diff">
43 <refpurpose>Find differences</refpurpose>
44
45 <refdescription>
46 <para>Compare two xml documents and display differences. Two xml documents are defined to be the same if: They have the matching elements and attributes, and that the data in the elements also match. The comparison is order sensitive. </para>
47
48 <para>The element names from the documents at the current depth are compared, followed by their values, then any attribute names and values are compared. The process is applied then to the subtrees of the documents.</para>
49
50 <para>Notes: If there are leaf nodes in one nodeset which don't exist in the other, the value of those 'extra' elements won't appear as a difference.
51 </para>
52 </refdescription>
53
54 <refparameter>
55 <variablelist>
56 <varlistentry>
57 <term>ns1</term>
58 <term>ns2</term>
59 <listitem>
60 <para>The two nodesets which are to be compared. </para>
61 </listitem>
62 </varlistentry>
63 </variablelist>
64 </refparameter>
65
66 <refreturn>
67 <para>Returns the difference between the documents. </para>
68
69 <para>The format of the output is an xml document. A node is added to the result tree for every difference. The node contains the type of difference (e.g element name difference, attribute value difference, etc), the value in the first nodeset and the value in the second nodeset, and the parent node. The indentation level is the depth at which the difference was found relative to the first document. </para>
70
71 </refreturn>
72 </doc:template>
73
74 <!-- pass in a nodeset and compare. Is order sensitive. Output attribute, element and textual differences. -->
75
76 <xsl:template name="cmp:diff">
77 <xsl:param name="ns1"/>
78 <xsl:param name="ns2"/>
79
80 <!-- attribute compare -->
81 <!-- Optimisation attempt
82
83 Can probaby change this into one loop ie -
84 <xsl:for-each
85 i = position
86 if node1[i] = node2[i]...
87
88 -->
89
90 <!-- Need to check if there are two sets of attributes -->
91 <xsl:choose>
92 <xsl:when test='count($ns1/attribute::*) = count($ns2/attribute::*)'>
93 <xsl:for-each select="$ns1/attribute::*">
94 <xsl:variable name="name1" select="name()"/>
95 <xsl:variable name="value1" select="."/>
96 <xsl:variable name="i" select="position()"/>
97
98 <xsl:for-each select="$ns2/attribute::*">
99
100 <xsl:variable name="j" select="position()"/>
101 <xsl:variable name="name2" select="name()"/>
102 <xsl:variable name="value2" select="."/>
103
104 <xsl:if test="$i = $j">
105 <xsl:if test="$name1 != $name2">
106 <attributeNameDifference>
107 <parentElement><xsl:value-of select="name(..)"/></parentElement>
108 <before><xsl:value-of select="$name1"/></before>
109 <after><xsl:value-of select="$name2"/></after>
110 </attributeNameDifference>
111 </xsl:if>
112
113 <xsl:if test="$name1 = $name2 and $value1 != $value2">
114 <attributeValueDifference>
115 <parentElement><xsl:value-of select="name(..)"/></parentElement>
116 <before><xsl:value-of select="$value1"/></before>
117 <after><xsl:value-of select="$value2"/></after>
118 </attributeValueDifference>
119 </xsl:if>
120
121 </xsl:if>
122 </xsl:for-each>
123 </xsl:for-each>
124 </xsl:when>
125 <xsl:otherwise>
126 <attributeNameDifference>
127 <parentElement>
128 <xsl:value-of select="name(..)"/>
129 </parentElement>
130 <before><xsl:value-of select='$ns1/attribute::*'/></before>
131 <after><xsl:value-of select='$ns2/attribute::*'/></after>
132 </attributeNameDifference>
133 </xsl:otherwise>
134 </xsl:choose>
135
136
137 <!-- Find element differences by comparing the element names from the same position in both documents. Iterate over all the nodes in the nodeset with the largest number of elements, so the extra elements will appear as differences. -->
138
139 <xsl:choose>
140 <!-- Define loop direction based on which tree has more nodes
141 FIXME: Replacing this with one for-each and a test for the case
142 of the second tree having more nodes would be more elegant
143
144 Solution: Add variable for direction and assign the 'larger' nodeset to that
145 variable. Then do one for-each.
146
147 FIXME: The solution is a bit too iterative. Make it more functional
148
149 -->
150 <xsl:when test="count($ns1) &gt; count($ns2)">
151 <xsl:for-each select="$ns1">
152 <xsl:variable name="i" select="position()"/>
153
154 <xsl:message>node[<xsl:value-of select='$i'/>]:
155 <xsl:value-of select='$ns1[$i]'/>
156 </xsl:message>
157
158 <!-- Element name compare -->
159 <xsl:if test="name($ns1[$i]) != name($ns2[$i])">
160 <elementNameDifference>
161 <parentElement><xsl:value-of select="name(..)"/></parentElement>
162 <before><xsl:value-of select="name($ns1[$i])"/></before>
163 <after><xsl:value-of select="name($ns2[$i])"/></after>
164 </elementNameDifference>
165 </xsl:if>
166
167 <!-- Element Value compare -->
168
169 <xsl:if test="count($ns1/*) = 0">
170 <xsl:if test="$ns1[$i] != $ns2[$i]">
171 <elementValueDifference>
172 <parentElement><xsl:value-of select="name(..)"/></parentElement>
173 <before><xsl:value-of select="$ns1[$i]"/></before>
174 <after><xsl:value-of select="$ns2[$i]"/></after>
175 </elementValueDifference>
176 </xsl:if>
177 </xsl:if>
178
179 </xsl:for-each>
180 </xsl:when>
181 <xsl:otherwise>
182 <xsl:for-each select="$ns2">
183 <xsl:variable name="i" select="position()"/>
184
185 <!-- Element Name compare -->
186
187 <xsl:if test="name($ns1[$i]) != name($ns2[$i])">
188 <elementNameDifference>
189 <parentElement><xsl:value-of select="name(..)"/></parentElement>
190 <before><xsl:value-of select="name($ns1[$i])"/></before>
191 <after><xsl:value-of select="name($ns2[$i])"/></after>
192 </elementNameDifference>
193
194 </xsl:if>
195
196 <!-- value compare -->
197
198 <xsl:if test="count($ns2/*) = 0">
199 <xsl:if test="$ns2[$i] != $ns1[$i]">
200 <elementValueDifference>
201 <parentElement><xsl:value-of select="name(..)"/></parentElement>
202 <after><xsl:value-of select="$ns2[$i]"/></after>
203 <before><xsl:value-of select="$ns1[$i]"/></before>
204 </elementValueDifference>
205 </xsl:if>
206 </xsl:if>
207
208 </xsl:for-each>
209 </xsl:otherwise>
210 </xsl:choose>
211
212 <!-- stop processing when leaf node is reached. -->
213
214 <xsl:if test="count($ns1/*) &gt; 0 and count($ns2/*) &gt; 0">
215 <xsl:call-template name="cmp:diff">
216 <xsl:with-param name="ns1" select="$ns1/*"/>
217 <xsl:with-param name="ns2" select="$ns2/*"/>
218 </xsl:call-template>
219 </xsl:if>
220
221 </xsl:template>
222
223 <!-- Return false if the two nodesets are not identical
224 -->
225
226 <doc:template name="cmp:cmp">
227 <refpurpose>Compare</refpurpose>
228
229 <refdescription>
230 <para>Recursively compare two xml nodesets, stop when a difference is found and return false. Otherwise return true if the document is identical. </para>
231
232 <para>The element names from the documents at the current depth are compared, followed by their values, then any attribute names and values are compared. The process is applied then to the subtrees of the documents.</para>
233
234 <para>Notes: If there are leaf nodes in one nodeset which don't exist in the other, the value of those 'extra' elements won't appear as a difference.
235 </para>
236 </refdescription>
237
238 <refparameter>
239 <variablelist>
240 <varlistentry>
241 <term>ns1</term>
242 <term>ns2</term>
243 <listitem>
244 <para>The two nodesets which are to be compared. </para>
245 </listitem>
246 </varlistentry>
247 </variablelist>
248 </refparameter>
249
250 <refreturn>
251 <para>False when the nodesets are not identical, empty otherwise. </para>
252
253 </refreturn>
254 </doc:template>
255
256 <xsl:template name="cmp:cmp">
257 <xsl:param name="ns1"/>
258 <xsl:param name="ns2"/>
259 <xsl:param name="depth"/>
260
261 <xsl:choose>
262 <xsl:when test='count($ns1) != count($ns2)'>
263 <xsl:value-of select='"countDiff"'/>
264 </xsl:when>
265 <xsl:when test='count($ns1/attribute::*) != count($ns2/attribute::*)'>
266 <xsl:value-of select='"countDiff"'/>
267 </xsl:when>
268 <xsl:when test='$ns1 and $ns2'>
269
270 <xsl:variable name='result'>
271 <xsl:call-template name='cmp:cmp'>
272 <xsl:with-param name='ns1' select='$ns1/*'/>
273 <xsl:with-param name='ns2' select='$ns2/*'/>
274 <xsl:with-param name='depth' select='$depth+1'/>
275 </xsl:call-template>
276 </xsl:variable>
277
278 <xsl:choose>
279 <xsl:when test='$result = "countDiff"'>
280 <xsl:value-of select='$result'/>
281 </xsl:when>
282 <xsl:when test='$result = "textDiff"'>
283 <xsl:value-of select='$result'/>
284 </xsl:when>
285 <xsl:when test='$result = ""'>
286
287 <xsl:variable name='keyText1' select='name($ns1)'/>
288 <xsl:variable name='keyText2' select='name($ns2)'/>
289
290 <xsl:choose>
291 <!-- Check if the text of the nodesets are the same and the attributes-->
292 <xsl:when test='$ns1 = $ns2 and $keyText1 = $keyText2'>
293
294 <!-- Check the attribute names are the same -->
295 <!-- Number of attributes being different is caught higher up -->
296 <xsl:if test='count($ns1/attribute::*)'>
297 <xsl:for-each select='$ns1/attribute::*'>
298 <xsl:variable name='i' select='position()'/>
299 <xsl:variable name='name1' select='name(.)'/>
300 <xsl:variable name='value1' select='.'/>
301
302 <xsl:for-each select='$ns2/attribute::*'>
303 <xsl:variable name='j' select='position()'/>
304 <xsl:variable name='name2' select='name(.)'/>
305 <xsl:variable name='value2' select='.'/>
306
307 <xsl:if test='$i = $j and ($name1 != $name2 or
308 $value1 != $value2)'>
309 <xsl:value-of select='"textDiff"'/>
310 </xsl:if>
311
312 </xsl:for-each>
313 </xsl:for-each>
314 </xsl:if>
315 <!--
316 <xsl:variable name='diffResult'>
317 <xsl:call-template name='cmp:diff'>
318 <xsl:with-param name='ns1' select='$ns1'/>
319 <xsl:with-param name='ns2' select='$ns2'/>
320 </xsl:call-template>
321 </xsl:variable>
322
323 <xsl:if test='not($diffResult = "")'>
324 <xsl:value-of select='"textDiff"'/>
325 </xsl:if>
326 -->
327
328 </xsl:when>
329 <xsl:otherwise>
330 <xsl:value-of select='"textDiff"'/>
331 </xsl:otherwise>
332 </xsl:choose>
333 </xsl:when>
334 </xsl:choose>
335
336 </xsl:when>
337 <xsl:when test='$ns1 and not($ns2)'>
338 <xsl:value-of select='"structDiff"'/>
339 </xsl:when>
340 <xsl:when test='$ns2 and not($ns1)'>
341 <xsl:value-of select='"structDiff"'/>
342 </xsl:when>
343 </xsl:choose>
344
345 </xsl:template>
346
347</xsl:stylesheet>
348
Note: See TracBrowser for help on using the repository browser.