001: /*
002: * Copyright 1999-2004 The Apache Software Foundation
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.apache.commons.jxpath.ri.axes;
017:
018: import java.util.Stack;
019:
020: import org.apache.commons.jxpath.Pointer;
021: import org.apache.commons.jxpath.ri.Compiler;
022: import org.apache.commons.jxpath.ri.EvalContext;
023: import org.apache.commons.jxpath.ri.compiler.NodeTest;
024: import org.apache.commons.jxpath.ri.compiler.NodeTypeTest;
025: import org.apache.commons.jxpath.ri.model.NodeIterator;
026: import org.apache.commons.jxpath.ri.model.NodePointer;
027:
028: /**
029: * An EvalContext that walks the "descendant::" and "descendant-or-self::"
030: * axes.
031: *
032: * @author Dmitri Plotnikov
033: * @version $Revision: 1.16 $ $Date: 2004/02/29 14:17:38 $
034: */
035: public class DescendantContext extends EvalContext {
036: private NodeTest nodeTest;
037: private boolean setStarted = false;
038: private Stack stack;
039: private NodePointer currentNodePointer;
040: private boolean includeSelf;
041: private static final NodeTest ELEMENT_NODE_TEST = new NodeTypeTest(
042: Compiler.NODE_TYPE_NODE);
043:
044: public DescendantContext(EvalContext parentContext,
045: boolean includeSelf, NodeTest nodeTest) {
046: super (parentContext);
047: this .includeSelf = includeSelf;
048: this .nodeTest = nodeTest;
049: }
050:
051: public boolean isChildOrderingRequired() {
052: return true;
053: }
054:
055: public NodePointer getCurrentNodePointer() {
056: if (position == 0) {
057: if (!setPosition(1)) {
058: return null;
059: }
060: }
061: return currentNodePointer;
062: }
063:
064: public void reset() {
065: super .reset();
066: setStarted = false;
067: }
068:
069: public boolean setPosition(int position) {
070: if (position < this .position) {
071: reset();
072: }
073:
074: while (this .position < position) {
075: if (!nextNode()) {
076: return false;
077: }
078: }
079: return true;
080: }
081:
082: public boolean nextNode() {
083: if (!setStarted) {
084: setStarted = true;
085: stack = new Stack();
086: currentNodePointer = parentContext.getCurrentNodePointer();
087: if (currentNodePointer != null) {
088: if (!currentNodePointer.isLeaf()) {
089: stack.push(currentNodePointer.childIterator(
090: ELEMENT_NODE_TEST, false, null));
091: }
092: if (includeSelf) {
093: if (currentNodePointer.testNode(nodeTest)) {
094: position++;
095: return true;
096: }
097: }
098: }
099: }
100:
101: while (!stack.isEmpty()) {
102: NodeIterator it = (NodeIterator) stack.peek();
103: if (it.setPosition(it.getPosition() + 1)) {
104: currentNodePointer = it.getNodePointer();
105: if (!isRecursive()) {
106: if (!currentNodePointer.isLeaf()) {
107: stack.push(currentNodePointer.childIterator(
108: ELEMENT_NODE_TEST, false, null));
109: }
110: if (currentNodePointer.testNode(nodeTest)) {
111: position++;
112: return true;
113: }
114: }
115: } else {
116: // We get here only if the name test failed
117: // and the iterator ended
118: stack.pop();
119: }
120: }
121: return false;
122: }
123:
124: /**
125: * Checks if we are reentering a bean we have already seen and if so
126: * returns true to prevent infinite recursion.
127: */
128: private boolean isRecursive() {
129: Object node = currentNodePointer.getNode();
130: for (int i = stack.size() - 1; --i >= 0;) {
131: NodeIterator it = (NodeIterator) stack.get(i);
132: Pointer pointer = it.getNodePointer();
133: if (pointer != null && pointer.getNode() == node) {
134: return true;
135: }
136: }
137: return false;
138: }
139: }
|