View Javadoc

1   /*
2    * Copyright 2001-2004 (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    * $Id: NodeComparator.java,v 1.8 2004/06/25 08:03:41 maartenc Exp $
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)&gt;0) &amp;&amp; (compare(y, z)&gt;0))</tt> implies
49       * <tt>compare(x, z)&gt;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              // null is less
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                  // Node implementations are greater
86                  return 1;
87              }
88          }
89          else {
90              if ( o2 instanceof Node ) {
91                  // Node implementations are greater
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             // lets compare attributes
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             // null is less
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             // null is less
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  * Redistribution and use of this software and associated documentation
281  * ("Software"), with or without modification, are permitted provided
282  * that the following conditions are met:
283  *
284  * 1. Redistributions of source code must retain copyright
285  *    statements and notices.  Redistributions must also contain a
286  *    copy of this document.
287  *
288  * 2. Redistributions in binary form must reproduce the
289  *    above copyright notice, this list of conditions and the
290  *    following disclaimer in the documentation and/or other
291  *    materials provided with the distribution.
292  *
293  * 3. The name "DOM4J" must not be used to endorse or promote
294  *    products derived from this Software without prior written
295  *    permission of MetaStuff, Ltd.  For written permission,
296  *    please contact dom4j-info@metastuff.com.
297  *
298  * 4. Products derived from this Software may not be called "DOM4J"
299  *    nor may "DOM4J" appear in their names without prior written
300  *    permission of MetaStuff, Ltd. DOM4J is a registered
301  *    trademark of MetaStuff, Ltd.
302  *
303  * 5. Due credit should be given to the DOM4J Project - 
304  *    http://www.dom4j.org
305  *
306  * THIS SOFTWARE IS PROVIDED BY METASTUFF, LTD. AND CONTRIBUTORS
307  * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
308  * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
309  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
310  * METASTUFF, LTD. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
311  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
312  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
313  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
314  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
315  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
316  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
317  * OF THE POSSIBILITY OF SUCH DAMAGE.
318  *
319  * Copyright 2001-2004 (C) MetaStuff, Ltd. All Rights Reserved.
320  *
321  * $Id: NodeComparator.java,v 1.8 2004/06/25 08:03:41 maartenc Exp $
322  */