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.compiler;
019
020import org.apache.commons.jxpath.ri.Compiler;
021
022/**
023 * A step.
024 */
025public class Step {
026
027    /**
028     * Decode an axis code to its name.
029     *
030     * @param axis int code
031     * @return String name.
032     * @see Compiler
033     * @see "http://www.w3.org/TR/xpath#axes"
034     */
035    public static String axisToString(final int axis) {
036        switch (axis) {
037        case Compiler.AXIS_SELF:
038            return "self";
039        case Compiler.AXIS_CHILD:
040            return "child";
041        case Compiler.AXIS_PARENT:
042            return "parent";
043        case Compiler.AXIS_ANCESTOR:
044            return "ancestor";
045        case Compiler.AXIS_ATTRIBUTE:
046            return "attribute";
047        case Compiler.AXIS_NAMESPACE:
048            return "namespace";
049        case Compiler.AXIS_PRECEDING:
050            return "preceding";
051        case Compiler.AXIS_FOLLOWING:
052            return "following";
053        case Compiler.AXIS_DESCENDANT:
054            return "descendant";
055        case Compiler.AXIS_ANCESTOR_OR_SELF:
056            return "ancestor-or-self";
057        case Compiler.AXIS_FOLLOWING_SIBLING:
058            return "following-sibling";
059        case Compiler.AXIS_PRECEDING_SIBLING:
060            return "preceding-sibling";
061        case Compiler.AXIS_DESCENDANT_OR_SELF:
062            return "descendant-or-self";
063        default:
064            return "UNKNOWN";
065        }
066    }
067
068    private final int axis;
069    private final NodeTest nodeTest;
070    private final Expression[] predicates;
071
072    /**
073     * Constructs a new Step.
074     *
075     * @param axis       axis code
076     * @param nodeTest   step test
077     * @param predicates predicate expressions
078     */
079    protected Step(final int axis, final NodeTest nodeTest, final Expression[] predicates) {
080        this.axis = axis;
081        this.nodeTest = nodeTest;
082        this.predicates = predicates;
083    }
084
085    /**
086     * Gets the axis code.
087     *
088     * @return int
089     */
090    public int getAxis() {
091        return axis;
092    }
093
094    /**
095     * Gets the step test.
096     *
097     * @return NodeTest
098     */
099    public NodeTest getNodeTest() {
100        return nodeTest;
101    }
102
103    /**
104     * Gets the predicates.
105     *
106     * @return Expression[]
107     */
108    public Expression[] getPredicates() {
109        return predicates;
110    }
111
112    /**
113     * Tests whether this step contains any predicate that is context dependent.
114     *
115     * @return boolean
116     */
117    public boolean isContextDependent() {
118        if (predicates != null) {
119            for (final Expression predicate : predicates) {
120                if (predicate.isContextDependent()) {
121                    return true;
122                }
123            }
124        }
125        return false;
126    }
127
128    @Override
129    public String toString() {
130        final StringBuilder buffer = new StringBuilder();
131        final int axis = getAxis();
132        if (axis == Compiler.AXIS_CHILD) {
133            buffer.append(nodeTest);
134        } else if (axis == Compiler.AXIS_ATTRIBUTE) {
135            buffer.append('@');
136            buffer.append(nodeTest);
137        } else if (axis == Compiler.AXIS_SELF && nodeTest instanceof NodeTypeTest && ((NodeTypeTest) nodeTest).getNodeType() == Compiler.NODE_TYPE_NODE) {
138            buffer.append(".");
139        } else if (axis == Compiler.AXIS_PARENT && nodeTest instanceof NodeTypeTest && ((NodeTypeTest) nodeTest).getNodeType() == Compiler.NODE_TYPE_NODE) {
140            buffer.append("..");
141        } else if (axis == Compiler.AXIS_DESCENDANT_OR_SELF && nodeTest instanceof NodeTypeTest
142                && ((NodeTypeTest) nodeTest).getNodeType() == Compiler.NODE_TYPE_NODE && (predicates == null || predicates.length == 0)) {
143            buffer.append("");
144        } else {
145            buffer.append(axisToString(axis));
146            buffer.append("::");
147            buffer.append(nodeTest);
148        }
149        final Expression[] predicates = getPredicates();
150        if (predicates != null) {
151            for (final Expression predicate : predicates) {
152                buffer.append('[');
153                buffer.append(predicate);
154                buffer.append(']');
155            }
156        }
157        return buffer.toString();
158    }
159}