1
2
3
4
5
6
7
8
9
10 package org.dom4j.util;
11
12 import java.util.Comparator;
13
14 import org.dom4j.Attribute;
15 import org.dom4j.Branch;
16 import org.dom4j.CDATA;
17 import org.dom4j.CharacterData;
18 import org.dom4j.Comment;
19 import org.dom4j.Document;
20 import org.dom4j.DocumentType;
21 import org.dom4j.Element;
22 import org.dom4j.Entity;
23 import org.dom4j.Namespace;
24 import org.dom4j.Node;
25 import org.dom4j.ProcessingInstruction;
26 import org.dom4j.QName;
27 import org.dom4j.Text;
28
29 /*** <p><code>NodeComparator</code> is a {@link Comparator} of Node instances
30 * which is capable of comparing Nodes for equality based on their values.</p>
31 *
32 * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
33 * @version $Revision: 1.8 $
34 */
35 public class NodeComparator implements Comparator {
36
37 /***
38 * Compares its two arguments for order. Returns a negative integer,
39 * zero, or a positive integer as the first argument is less than, equal
40 * to, or greater than the second.<p>
41 *
42 * The implementor must ensure that <tt>sgn(compare(x, y)) ==
43 * -sgn(compare(y, x))</tt> for all <tt>x</tt> and <tt>y</tt>. (This
44 * implies that <tt>compare(x, y)</tt> must throw an exception if and only
45 * if <tt>compare(y, x)</tt> throws an exception.)<p>
46 *
47 * The implementor must also ensure that the relation is transitive:
48 * <tt>((compare(x, y)>0) && (compare(y, z)>0))</tt> implies
49 * <tt>compare(x, z)>0</tt>.<p>
50 *
51 * Finally, the implementer must ensure that <tt>compare(x, y)==0</tt>
52 * implies that <tt>sgn(compare(x, z))==sgn(compare(y, z))</tt> for all
53 * <tt>z</tt>.<p>
54 *
55 * It is generally the case, but <i>not</i> strictly required that
56 * <tt>(compare(x, y)==0) == (x.equals(y))</tt>. Generally speaking,
57 * any comparator that violates this condition should clearly indicate
58 * this fact. The recommended language is "Note: this comparator
59 * imposes orderings that are inconsistent with equals."
60 *
61 * @param o1 the first object to be compared.
62 * @param o2 the second object to be compared.
63 * @return a negative integer, zero, or a positive integer as the
64 * first argument is less than, equal to, or greater than the
65 * second.
66 * @throws ClassCastException if the arguments' types prevent them from
67 * being compared by this Comparator.
68 */
69 public int compare(Object o1, Object o2) {
70 if ( o1 == o2 ) {
71 return 0;
72 }
73 else if ( o1 == null ) {
74
75 return -1;
76 }
77 else if ( o2 == null ) {
78 return 1;
79 }
80 if ( o1 instanceof Node ) {
81 if ( o2 instanceof Node ) {
82 return compare( (Node) o1, (Node) o2 );
83 }
84 else {
85
86 return 1;
87 }
88 }
89 else {
90 if ( o2 instanceof Node ) {
91
92 return -1;
93 }
94 else {
95 if ( o1 instanceof Comparable ) {
96 Comparable c1 = (Comparable) o1;
97 return c1.compareTo( o2 );
98 }
99 else {
100 int answer = o1.getClass().getName().compareTo(
101 o2.getClass().getName()
102 );
103 if ( answer == 0 ) {
104 answer = o1.hashCode() - o2.hashCode();
105 }
106 return answer;
107 }
108 }
109 }
110 }
111
112 public int compare( Node n1, Node n2 ) {
113 int nodeType1 = n1.getNodeType();
114 int nodeType2 = n2.getNodeType();
115 int answer = nodeType1 - nodeType2;
116 if ( answer != 0 ) {
117 return answer;
118 }
119 else {
120 switch (nodeType1) {
121 case Node.ELEMENT_NODE:
122 return compare((Element) n1, (Element) n2);
123 case Node.DOCUMENT_NODE:
124 return compare((Document) n1, (Document) n2);
125 case Node.ATTRIBUTE_NODE:
126 return compare((Attribute) n1, (Attribute) n2);
127 case Node.TEXT_NODE:
128 return compare((Text) n1, (Text) n2);
129 case Node.CDATA_SECTION_NODE:
130 return compare((CDATA) n1, (CDATA) n2);
131 case Node.ENTITY_REFERENCE_NODE:
132 return compare((Entity) n1, (Entity) n2);
133 case Node.PROCESSING_INSTRUCTION_NODE:
134 return compare((ProcessingInstruction) n1, (ProcessingInstruction) n2);
135 case Node.COMMENT_NODE:
136 return compare((Comment) n1, (Comment) n2);
137 case Node.DOCUMENT_TYPE_NODE:
138 return compare((DocumentType) n1, (DocumentType) n2);
139 case Node.NAMESPACE_NODE:
140 return compare((Namespace) n1, (Namespace) n2);
141 default:
142 throw new RuntimeException(
143 "Invalid node types. node1: " + n1 + " and node2: " + n2
144 );
145 }
146 }
147 }
148
149 public int compare( Document n1, Document n2 ) {
150 int answer = compare( n1.getDocType(), n2.getDocType() );
151 if ( answer == 0 ) {
152 answer = compareContent( n1, n2 );
153 }
154 return answer;
155 }
156
157 public int compare( Element n1, Element n2 ) {
158 int answer = compare( n1.getQName(), n2.getQName() );
159 if ( answer == 0 ) {
160
161 int c1 = n1.attributeCount();
162 int c2 = n2.attributeCount();
163 answer = c1 - c2;
164 if ( answer == 0 ) {
165 for ( int i = 0; i < c1; i++ ) {
166 Attribute a1 = n1.attribute(i);
167 Attribute a2 = n2.attribute(a1.getQName());
168 answer = compare( a1, a2 );
169 if ( answer != 0 ) {
170 return answer;
171 }
172 }
173 answer = compareContent( n1, n2 );
174 }
175 }
176 return answer;
177 }
178
179 public int compare( Attribute n1, Attribute n2 ) {
180 int answer = compare( n1.getQName(), n2.getQName() );
181 if ( answer == 0 ) {
182 answer = compare( n1.getValue(), n2.getValue() );
183 }
184 return answer;
185 }
186
187 public int compare( QName n1, QName n2 ) {
188 int answer = compare( n1.getNamespaceURI(), n2.getNamespaceURI() );
189 if ( answer == 0 ) {
190 answer = compare( n1.getQualifiedName(), n2.getQualifiedName() );
191 }
192 return answer;
193 }
194
195 public int compare( Namespace n1, Namespace n2 ) {
196 int answer = compare( n1.getURI(), n2.getURI() );
197 if ( answer == 0 ) {
198 answer = compare( n1.getPrefix(), n2.getPrefix() );
199 }
200 return answer;
201 }
202
203 public int compare( CharacterData t1, CharacterData t2 ) {
204 return compare( t1.getText(), t2.getText() );
205 }
206
207 public int compare( DocumentType o1, DocumentType o2 ) {
208 if ( o1 == o2 ) {
209 return 0;
210 }
211 else if ( o1 == null ) {
212
213 return -1;
214 }
215 else if ( o2 == null ) {
216 return 1;
217 }
218 int answer = compare( o1.getPublicID(), o2.getPublicID() );
219 if ( answer == 0 ) {
220 answer = compare( o1.getSystemID(), o2.getSystemID() );
221 if ( answer == 0 ) {
222 answer = compare( o1.getName(), o2.getName() );
223 }
224 }
225 return answer;
226 }
227
228 public int compare( Entity n1, Entity n2 ) {
229 int answer = compare( n1.getName(), n2.getName() );
230 if ( answer == 0 ) {
231 answer = compare( n1.getText(), n2.getText() );
232 }
233 return answer;
234 }
235
236 public int compare( ProcessingInstruction n1, ProcessingInstruction n2 ) {
237 int answer = compare( n1.getTarget(), n2.getTarget() );
238 if ( answer == 0 ) {
239 answer = compare( n1.getText(), n2.getText() );
240 }
241 return answer;
242 }
243
244 public int compareContent( Branch b1, Branch b2 ) {
245 int c1 = b1.nodeCount();
246 int c2 = b2.nodeCount();
247 int answer = c1 - c2;
248 if ( answer == 0 ) {
249 for ( int i = 0; i < c1; i++ ) {
250 Node n1 = b1.node(i);
251 Node n2 = b2.node(i);
252 answer = compare( n1, n2 );
253 if ( answer != 0 ) {
254 break;
255 }
256 }
257 }
258 return answer;
259 }
260
261 public int compare( String o1, String o2 ) {
262 if ( o1 == o2 ) {
263 return 0;
264 }
265 else if ( o1 == null ) {
266
267 return -1;
268 }
269 else if ( o2 == null ) {
270 return 1;
271 }
272 return o1.compareTo( o2 );
273 }
274 }
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322