    001    /*
    002     * Licensed to the Apache Software Foundation (ASF) under one or more
    003     * contributor license agreements.  See the NOTICE file distributed with
    004     * this work for additional information regarding copyright ownership.
    005     * The ASF licenses this file to You under the Apache License, Version 2.0
    006     * (the "License"); you may not use this file except in compliance with
    007     * the License.  You may obtain a copy of the License at
    008     *
    009     *     http://www.apache.org/licenses/LICENSE-2.0
    010     *
    011     * Unless required by applicable law or agreed to in writing, software
    012     * distributed under the License is distributed on an "AS IS" BASIS,
    013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014     * See the License for the specific language governing permissions and
    015     * limitations under the License.
    016     */
    017    package org.apache.commons.jxpath.ri.axes;
    018
    019    import org.apache.commons.jxpath.ri.EvalContext;
    020    import org.apache.commons.jxpath.ri.compiler.NodeTest;
    021    import org.apache.commons.jxpath.ri.model.NodePointer;
    022
    023    /**
    024     * EvalContext that walks the "ancestor::" and "ancestor-or-self::" axes.
    025     *
    026     * @author Dmitri Plotnikov
    027     * @version $Revision: 652845 $ $Date: 2008-05-02 12:46:46 -0500 (Fri, 02 May 2008) $
    028     */
    029    public class AncestorContext extends EvalContext {
    030        private NodeTest nodeTest;
    031        private boolean setStarted = false;
    032        private NodePointer currentNodePointer;
    033        private boolean includeSelf;
    034
    035        /**
    036         * Create a new AncestorContext.
    037         * @param parentContext represents the previous step on the path
    038         * @param  includeSelf differentiates between "ancestor::" and
    039         *                     "ancestor-or-self::" axes
    040         * @param nodeTest is the name of the element(s) we are looking for
    041         */
    042        public AncestorContext(
    043            EvalContext parentContext,
    044            boolean includeSelf,
    045            NodeTest nodeTest) {
    046            super(parentContext);
    047            this.includeSelf = includeSelf;
    048            this.nodeTest = nodeTest;
    049        }
    050
    051        public NodePointer getCurrentNodePointer() {
    052            return currentNodePointer;
    053        }
    054
    055        public int getDocumentOrder() {
    056            return -1;
    057        }
    058
    059        public void reset() {
    060            super.reset();
    061            setStarted = false;
    062        }
    063
    064        public boolean setPosition(int position) {
    065            if (position < getCurrentPosition()) {
    066                reset();
    067            }
    068
    069            while (getCurrentPosition() < position) {
    070                if (!nextNode()) {
    071                    return false;
    072                }
    073            }
    074            return true;
    075        }
    076
    077        public boolean nextNode() {
    078            if (!setStarted) {
    079                setStarted = true;
    080                currentNodePointer = parentContext.getCurrentNodePointer();
    081                if (includeSelf && currentNodePointer.testNode(nodeTest)) {
    082                    position++;
    083                    return true;
    084                }
    085            }
    086
    087            while (true) {
    088                currentNodePointer = currentNodePointer.getImmediateParentPointer();
    089
    090                if (currentNodePointer == null) {
    091                    return false;
    092                }
    093
    094                if (currentNodePointer.testNode(nodeTest)) {
    095                    position++;
    096                    return true;
    097                }
    098            }
    099        }
    100    }