View Javadoc

1   /*
2    * Copyright 1999-2004 The Apache Software Foundation
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.apache.commons.jxpath.ri.axes;
17  
18  import java.util.Stack;
19  
20  import org.apache.commons.jxpath.ri.EvalContext;
21  import org.apache.commons.jxpath.ri.compiler.NodeTest;
22  import org.apache.commons.jxpath.ri.model.NodeIterator;
23  import org.apache.commons.jxpath.ri.model.NodePointer;
24  import org.apache.commons.jxpath.ri.model.beans.PropertyIterator;
25  
26  /***
27   * EvalContext that walks the "preceding::" and "following::" axes.
28   *
29   * @author Dmitri Plotnikov
30   * @version $Revision: 1.15 $ $Date: 2004/03/25 03:49:50 $
31   */
32  public class PrecedingOrFollowingContext extends EvalContext {
33      private NodeTest nodeTest;
34      private boolean setStarted = false;
35      private boolean started = false;
36      private Stack stack;
37      private Stack nameStack;
38      private NodePointer currentNodePointer;
39      private NodePointer currentRootLocation;
40      private boolean reverse;
41  
42      public PrecedingOrFollowingContext(
43          EvalContext parentContext,
44          NodeTest nodeTest,
45          boolean reverse) 
46      {
47          super(parentContext);
48          this.nodeTest = nodeTest;
49          this.reverse = reverse;
50      }
51  
52      public NodePointer getCurrentNodePointer() {
53          return currentNodePointer;
54      }
55  
56      public int getDocumentOrder() {
57          return reverse ? -1 : 1;
58      }
59  
60      public void reset() {
61          super.reset();
62          stack = new Stack();
63          setStarted = false;
64      }
65  
66      public boolean setPosition(int position) {
67          if (position < this.position) {
68              reset();
69          }
70  
71          while (this.position < position) {
72              if (!nextNode()) {
73                  return false;
74              }
75          }
76          return true;
77      }
78  
79      public boolean nextNode() {
80          if (!setStarted) {
81              setStarted = true;
82              currentRootLocation = parentContext.getCurrentNodePointer();
83              NodePointer parent = currentRootLocation.getParent();
84              if (parent != null) {
85                  // TBD: check type
86                  stack.push(
87                      parent.childIterator(null, reverse, currentRootLocation));
88              }
89          }
90  
91          while (true) {
92              if (stack.isEmpty()) {
93                  currentRootLocation = currentRootLocation.getParent();
94  
95                  if (currentRootLocation == null
96                      || currentRootLocation.isRoot()) {
97                      break;
98                  }
99  
100                 NodePointer parent = currentRootLocation.getParent();
101                 if (parent != null) {
102                     stack.push(
103                         parent.childIterator(
104                             null,
105                             reverse,
106                             currentRootLocation));
107                 }
108             }
109 
110             while (!stack.isEmpty()) {
111                 if (!reverse) {
112                     NodeIterator it = (NodeIterator) stack.peek();
113                     if (it.setPosition(it.getPosition() + 1)) {
114                         currentNodePointer = it.getNodePointer();
115                         if (!currentNodePointer.isLeaf()) {
116                             stack.push(
117                                 currentNodePointer.childIterator(
118                                     null,
119                                     reverse,
120                                     null));
121                         }
122                         if (currentNodePointer.testNode(nodeTest)) {
123                             super.setPosition(getCurrentPosition() + 1);
124                             return true;
125                         }
126                     }
127                     else {
128                         // We get here only if the name test failed 
129                         // and the iterator ended
130                         stack.pop();
131                     }
132                 }
133                 else {
134                     NodeIterator it = (NodeIterator) stack.peek();
135                     if (it.setPosition(it.getPosition() + 1)) {
136                         currentNodePointer = it.getNodePointer();
137                         if (!currentNodePointer.isLeaf()) {
138                             stack.push(
139                                 currentNodePointer.childIterator(
140                                     null,
141                                     reverse,
142                                     null));
143                         }
144                         else if (currentNodePointer.testNode(nodeTest)) {
145                             super.setPosition(getCurrentPosition() + 1);
146                             return true;
147                         }
148                     }
149                     else {
150                         stack.pop();
151                         if (!stack.isEmpty()) {
152                             it = (PropertyIterator) stack.peek();
153                             currentNodePointer = it.getNodePointer();
154                             if (currentNodePointer.testNode(nodeTest)) {
155                                 super.setPosition(getCurrentPosition() + 1);
156                                 return true;
157                             }
158                         }
159                     }
160                 }
161             }
162         }
163         return false;
164     }
165 }