    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
    018package org.apache.commons.jxpath.ri.axes;
    019
    020import org.apache.commons.jxpath.ri.EvalContext;
    021import org.apache.commons.jxpath.ri.compiler.NodeTest;
    022import org.apache.commons.jxpath.ri.model.NodePointer;
    023
    024/**
    025 * EvalContext that walks the "ancestor::" and "ancestor-or-self::" axes.
    026 */
    027public class AncestorContext extends EvalContext {
    028
    029    private final NodeTest nodeTest;
    030    private boolean setStarted;
    031    private NodePointer currentNodePointer;
    032    private final boolean includeSelf;
    033
    034    /**
    035     * Constructs a new AncestorContext.
    036     *
    037     * @param parentContext represents the previous step on the path
    038     * @param includeSelf   differentiates between "ancestor::" and "ancestor-or-self::" axes
    039     * @param nodeTest      is the name of the element(s) we are looking for
    040     */
    041    public AncestorContext(final EvalContext parentContext, final boolean includeSelf, final NodeTest nodeTest) {
    042        super(parentContext);
    043        this.includeSelf = includeSelf;
    044        this.nodeTest = nodeTest;
    045    }
    046
    047    @Override
    048    public NodePointer getCurrentNodePointer() {
    049        return currentNodePointer;
    050    }
    051
    052    @Override
    053    public int getDocumentOrder() {
    054        return -1;
    055    }
    056
    057    @Override
    058    public boolean nextNode() {
    059        if (!setStarted) {
    060            setStarted = true;
    061            currentNodePointer = parentContext.getCurrentNodePointer();
    062            if (includeSelf && currentNodePointer.testNode(nodeTest)) {
    063                position++;
    064                return true;
    065            }
    066        }
    067        while (true) {
    068            currentNodePointer = currentNodePointer.getImmediateParentPointer();
    069            if (currentNodePointer == null) {
    070                return false;
    071            }
    072            if (currentNodePointer.testNode(nodeTest)) {
    073                position++;
    074                return true;
    075            }
    076        }
    077    }
    078
    079    @Override
    080    public void reset() {
    081        super.reset();
    082        setStarted = false;
    083    }
    084
    085    @Override
    086    public boolean setPosition(final int position) {
    087        if (position < getCurrentPosition()) {
    088            reset();
    089        }
    090        while (getCurrentPosition() < position) {
    091            if (!nextNode()) {
    092                return false;
    093            }
    094        }
    095        return true;
    096    }
    097}