View Javadoc

1   /*
2    * $Header$
3    * $Revision$
4    * $Date$
5    *
6    * ====================================================================
7    *
8    * Copyright 2005 Elliotte Rusty Harold.
9    * All rights reserved.
10   *
11   * Redistribution and use in source and binary forms, with or without
12   * modification, are permitted provided that the following conditions are
13   * met:
14   * 
15   *   * Redistributions of source code must retain the above copyright
16   *     notice, this list of conditions and the following disclaimer.
17   * 
18   *   * Redistributions in binary form must reproduce the above copyright
19   *     notice, this list of conditions and the following disclaimer in the
20   *     documentation and/or other materials provided with the distribution.
21   * 
22   *   * Neither the name of the Jaxen Project nor the names of its
23   *     contributors may be used to endorse or promote products derived 
24   *     from this software without specific prior written permission.
25   * 
26   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
27   * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28   * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
29   * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
30   * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31   * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32   * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33   * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34   * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35   * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37   *
38   * ====================================================================
39   * This software consists of voluntary contributions made by many 
40   * individuals on behalf of the Jaxen Project and was originally 
41   * created by bob mcwhirter <bob@werken.com> and 
42   * James Strachan <jstrachan@apache.org>.  For more information on the 
43   * Jaxen Project, please see <http://www.jaxen.org/>.
44   * 
45   * $Id$
46   */
47  package org.jaxen.expr;
48  
49  import java.util.Comparator;
50  import java.util.Iterator;
51  
52  import org.jaxen.Navigator;
53  import org.jaxen.UnsupportedAxisException;
54  
55  
56  class NodeComparator implements Comparator {
57      
58      private Navigator navigator;
59  
60  
61      NodeComparator(Navigator navigator) {
62          this.navigator = navigator;
63      }
64      
65      public int compare(Object o1, Object o2) {
66          
67          if (navigator == null) return 0;
68          
69          if (isNonChild(o1) && isNonChild(o2)) {
70              
71              try {
72                  Object p1 = navigator.getParentNode(o1);
73                  Object p2 = navigator.getParentNode(o2);
74              
75                  if (p1 == p2) {
76                      if (navigator.isNamespace(o1) && navigator.isAttribute(o2)) {
77                          return -1;
78                      }
79                      else if (navigator.isNamespace(o2) && navigator.isAttribute(o1)) {
80                          return 1;
81                      }
82                  }
83  
84                  return compare(p1, p2);
85              }
86              catch (UnsupportedAxisException ex) {
87                  return 0;
88              }
89              
90          }
91  
92          try {
93              int depth1 = getDepth(o1);
94              int depth2 = getDepth(o2);
95              
96              Object a1 = o1;
97              Object a2 = o2;
98                          
99              while (depth1 > depth2) {
100                 a1 = navigator.getParentNode(a1);
101                 depth1--;
102             }
103             if (a1 == o2) return 1;
104             
105             while (depth2 > depth1) {
106                 a2 = navigator.getParentNode(a2);
107                 depth2--;
108             }
109             if (a2 == o1) return -1;
110             
111             // a1 and a2 are now at same depth; and are not the same
112             while (true) {
113                 Object p1 = navigator.getParentNode(a1);
114                 Object p2 = navigator.getParentNode(a2);
115                 if (p1 == p2) {
116                     return compareSiblings(a1, a2);
117                 }
118                 a1 = p1;
119                 a2 = p2;
120             }
121             
122         }
123         catch (UnsupportedAxisException ex) {
124             return 0; // ???? should I throw an exception instead?
125         }
126     }
127     
128 
129     private boolean isNonChild(Object o) {
130         return navigator.isAttribute(o) || navigator.isNamespace(o);
131     }
132 
133     private int compareSiblings(Object sib1, Object sib2) 
134       throws UnsupportedAxisException {
135 
136         Iterator following = navigator.getFollowingSiblingAxisIterator(sib1);
137         while (following.hasNext()) {
138             Object next = following.next();
139             if (next.equals(sib2)) return -1;
140         }
141         return 1;
142         
143     }
144 
145     private int getDepth(Object o) throws UnsupportedAxisException {
146 
147         int depth = 0;
148         Object parent = o;
149         
150         while ((parent = navigator.getParentNode(parent)) != null) {
151             depth++;
152         }
153         return depth;
154         
155     }
156     
157 }