View Javadoc

1   /*
2    * Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved.
3    *
4    * This software is open source.
5    * See the bottom of this file for the licence.
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)&gt;0) &amp;&amp; (compare(y, z)&gt;0))</tt> implies
53       * <tt>compare(x, z)&gt;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              // null is less
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                  // Node implementations are greater
93                  return 1;
94              }
95          } else {
96              if (o2 instanceof Node) {
97                  // Node implementations are greater
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             // lets compare attributes
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             // null is less
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             // null is less
300             return -1;
301         } else if (o2 == null) {
302             return 1;
303         }
304 
305         return o1.compareTo(o2);
306     }
307 }
308 
309 /*
310  * Redistribution and use of this software and associated documentation
311  * ("Software"), with or without modification, are permitted provided that the
312  * following conditions are met:
313  * 
314  * 1. Redistributions of source code must retain copyright statements and
315  * notices. Redistributions must also contain a copy of this document.
316  * 
317  * 2. Redistributions in binary form must reproduce the above copyright notice,
318  * this list of conditions and the following disclaimer in the documentation
319  * and/or other materials provided with the distribution.
320  * 
321  * 3. The name "DOM4J" must not be used to endorse or promote products derived
322  * from this Software without prior written permission of MetaStuff, Ltd. For
323  * written permission, please contact dom4j-info@metastuff.com.
324  * 
325  * 4. Products derived from this Software may not be called "DOM4J" nor may
326  * "DOM4J" appear in their names without prior written permission of MetaStuff,
327  * Ltd. DOM4J is a registered trademark of MetaStuff, Ltd.
328  * 
329  * 5. Due credit should be given to the DOM4J Project - http://www.dom4j.org
330  * 
331  * THIS SOFTWARE IS PROVIDED BY METASTUFF, LTD. AND CONTRIBUTORS ``AS IS'' AND
332  * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
333  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
334  * ARE DISCLAIMED. IN NO EVENT SHALL METASTUFF, LTD. OR ITS CONTRIBUTORS BE
335  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
336  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
337  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
338  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
339  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
340  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
341  * POSSIBILITY OF SUCH DAMAGE.
342  * 
343  * Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved.
344  */