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