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