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