    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}