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;
018    
019    import java.io.StringReader;
020    
021    import org.apache.commons.jxpath.JXPathInvalidSyntaxException;
022    import org.apache.commons.jxpath.ri.parser.ParseException;
023    import org.apache.commons.jxpath.ri.parser.TokenMgrError;
024    import org.apache.commons.jxpath.ri.parser.XPathParser;
025    
026    /**
027     * XPath parser
028     *
029     * @author Dmitri Plotnikov
030     * @version $Revision: 652845 $ $Date: 2008-05-02 12:46:46 -0500 (Fri, 02 May 2008) $
031     */
032    public class Parser {
033    
034        private static XPathParser parser = new XPathParser(new StringReader(""));
035    
036        /**
037         * Parses the XPath expression. Throws a JXPathException in case
038         * of a syntax error.
039         * @param expression to parse
040         * @param compiler the compiler
041         * @return parsed Object
042         */
043        public static Object parseExpression(
044            String expression,
045            Compiler compiler) {
046            synchronized (parser) {
047                parser.setCompiler(compiler);
048                Object expr = null;
049                try {
050                    parser.ReInit(new StringReader(expression));
051                    expr = parser.parseExpression();
052                }
053                catch (TokenMgrError e) {
054                    throw new JXPathInvalidSyntaxException(
055                        "Invalid XPath: '"
056                            + addEscapes(expression)
057                            + "'. Invalid symbol '"
058                            + addEscapes(String.valueOf(e.getCharacter()))
059                            + "' "
060                            + describePosition(expression, e.getPosition()));
061                }
062                catch (ParseException e) {
063                    throw new JXPathInvalidSyntaxException(
064                        "Invalid XPath: '"
065                            + addEscapes(expression)
066                            + "'. Syntax error "
067                            + describePosition(
068                                expression,
069                                e.currentToken.beginColumn));
070                }
071                return expr;
072            }
073        }
074    
075        /**
076         * Describe a parse position.
077         * @param expression to parse
078         * @param position parse position
079         * @return String
080         */
081        private static String describePosition(String expression, int position) {
082            if (position <= 0) {
083                return "at the beginning of the expression";
084            }
085            if (position >= expression.length()) {
086                return "- expression incomplete";
087            }
088            return "after: '"
089                + addEscapes(expression.substring(0, position)) + "'";
090        }
091    
092        /**
093         * Add escapes to the specified String.
094         * @param string incoming String
095         * @return String
096         */
097        private static String addEscapes(String string) {
098            // Piggy-back on the code generated by JavaCC
099            return TokenMgrError.addEscapes(string);
100        }
101    }