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.Compiler;
020    import org.apache.commons.jxpath.ri.EvalContext;
021    import org.apache.commons.jxpath.ri.QName;
022    import org.apache.commons.jxpath.ri.compiler.NodeNameTest;
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     * EvalContext that walks the "attribute::" axis.
030     *
031     * @author Dmitri Plotnikov
032     * @version $Revision: 652845 $ $Date: 2008-05-02 12:46:46 -0500 (Fri, 02 May 2008) $
033     */
034    public class AttributeContext extends EvalContext {
035        private static final QName WILDCARD = new QName(null, "*");
036    
037        private NodeTest nodeTest;
038        private boolean setStarted = false;
039        private NodeIterator iterator;
040        private NodePointer currentNodePointer;
041    
042        /**
043         * Create a new AttributeContext.
044         * @param parentContext represents the previous step on the path
045         * @param nodeTest is the name of the attribute we are looking for
046         */
047        public AttributeContext(EvalContext parentContext, NodeTest nodeTest) {
048            super(parentContext);
049            this.nodeTest = nodeTest;
050        }
051    
052        public NodePointer getCurrentNodePointer() {
053            return currentNodePointer;
054        }
055    
056        public void reset() {
057            setStarted = false;
058            iterator = null;
059            super.reset();
060        }
061    
062        public boolean setPosition(int position) {
063            if (position < getCurrentPosition()) {
064                reset();
065            }
066    
067            while (getCurrentPosition() < position) {
068                if (!nextNode()) {
069                    return false;
070                }
071            }
072            return true;
073        }
074    
075        public boolean nextNode() {
076            super.setPosition(getCurrentPosition() + 1);
077            if (!setStarted) {
078                setStarted = true;
079                QName name;
080                if (nodeTest instanceof NodeNameTest) {
081                    name = ((NodeNameTest) nodeTest).getNodeName();
082                }
083                else {
084                    if (nodeTest instanceof NodeTypeTest
085                            && ((NodeTypeTest) nodeTest).getNodeType() == Compiler.NODE_TYPE_NODE) {
086                        name = WILDCARD;
087                    }
088                    else {
089                        iterator = null;
090                        return false;
091                    }
092                }
093                iterator = parentContext.getCurrentNodePointer().attributeIterator(
094                        name);
095            }
096            if (iterator == null) {
097                return false;
098            }
099            if (!iterator.setPosition(iterator.getPosition() + 1)) {
100                return false;
101            }
102            currentNodePointer = iterator.getNodePointer();
103            return true;
104        }
105    }