xpathparser.java
来自「java jdk 1.4的源码」· Java 代码 · 共 2,396 行 · 第 1/5 页
JAVA
2,396 行
/* * The Apache Software License, Version 1.1 * * * Copyright (c) 1999 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Xalan" and "Apache Software Foundation" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache", * nor may "Apache" appear in their name, without prior written * permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation and was * originally based on software copyright (c) 1999, Lotus * Development Corporation., http://www.lotus.com. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. */package org.apache.xpath.compiler;import java.util.Vector;import java.util.Hashtable;import org.apache.xml.utils.PrefixResolver;import org.apache.xpath.XPathProcessorException;import org.apache.xpath.res.XPATHErrorResources;import org.apache.xpath.compiler.Compiler;import org.apache.xpath.objects.XString;import org.apache.xpath.objects.XNumber;import org.apache.xalan.res.XSLMessages;import javax.xml.transform.TransformerException;import org.xml.sax.Locator;import org.xml.sax.helpers.LocatorImpl;import javax.xml.transform.TransformerConfigurationException;import javax.xml.transform.TransformerException;import javax.xml.transform.ErrorListener;/** * <meta name="usage" content="general"/> * Tokenizes and parses XPath expressions. This should really be named * XPathParserImpl, and may be renamed in the future. */public class XPathParser{ // %REVIEW% Is there a better way of doing this? // Upside is minimum object churn. Downside is that we don't have a useful // backtrace in the exception itself -- but we don't expect to need one. static public final String CONTINUE_AFTER_FATAL_ERROR="CONTINUE_AFTER_FATAL_ERROR"; /** * The XPath to be processed. */ private OpMap m_ops; /** * The next token in the pattern. */ transient String m_token; /** * The first char in m_token, the theory being that this * is an optimization because we won't have to do charAt(0) as * often. */ transient char m_tokenChar = 0; /** * The position in the token queue is tracked by m_queueMark. */ int m_queueMark = 0; /** * Results from checking FilterExpr syntax */ protected final static int FILTER_MATCH_FAILED = 0; protected final static int FILTER_MATCH_PRIMARY = 1; protected final static int FILTER_MATCH_PREDICATES = 2; /** * The parser constructor. */ public XPathParser(ErrorListener errorListener, javax.xml.transform.SourceLocator sourceLocator) { m_errorListener = errorListener; m_sourceLocator = sourceLocator; } /** * The prefix resolver to map prefixes to namespaces in the OpMap. */ PrefixResolver m_namespaceContext; /** * Given an string, init an XPath object for selections, * in order that a parse doesn't * have to be done each time the expression is evaluated. * * @param compiler The compiler object. * @param expression A string conforming to the XPath grammar. * @param namespaceContext An object that is able to resolve prefixes in * the XPath to namespaces. * * @throws javax.xml.transform.TransformerException */ public void initXPath( Compiler compiler, String expression, PrefixResolver namespaceContext) throws javax.xml.transform.TransformerException { m_ops = compiler; m_namespaceContext = namespaceContext; Lexer lexer = new Lexer(compiler, namespaceContext, this); lexer.tokenize(expression); m_ops.setOp(0,OpCodes.OP_XPATH); m_ops.setOp(OpMap.MAPINDEX_LENGTH,2); // Patch for Christine's gripe. She wants her errorHandler to return from // a fatal error and continue trying to parse, rather than throwing an exception. // Without the patch, that put us into an endless loop. // // %REVIEW% Is there a better way of doing this? // %REVIEW% Are there any other cases which need the safety net? // (and if so do we care right now, or should we rewrite the XPath // grammar engine and can fix it at that time?) try { nextToken(); Expr(); if (null != m_token) { String extraTokens = ""; while (null != m_token) { extraTokens += "'" + m_token + "'"; nextToken(); if (null != m_token) extraTokens += ", "; } error(XPATHErrorResources.ER_EXTRA_ILLEGAL_TOKENS, new Object[]{ extraTokens }); //"Extra illegal tokens: "+extraTokens); } } catch (org.apache.xpath.XPathProcessorException e) { if(CONTINUE_AFTER_FATAL_ERROR.equals(e.getMessage())) { // What I _want_ to do is null out this XPath. // I doubt this has the desired effect, but I'm not sure what else to do. // %REVIEW%!!! initXPath(compiler, "/..", namespaceContext); } else throw e; } compiler.shrink(); } /** * Given an string, init an XPath object for pattern matches, * in order that a parse doesn't * have to be done each time the expression is evaluated. * @param compiler The XPath object to be initialized. * @param expression A String representing the XPath. * @param namespaceContext An object that is able to resolve prefixes in * the XPath to namespaces. * * @throws javax.xml.transform.TransformerException */ public void initMatchPattern( Compiler compiler, String expression, PrefixResolver namespaceContext) throws javax.xml.transform.TransformerException { m_ops = compiler; m_namespaceContext = namespaceContext; Lexer lexer = new Lexer(compiler, namespaceContext, this); lexer.tokenize(expression); m_ops.setOp(0, OpCodes.OP_MATCHPATTERN); m_ops.setOp(OpMap.MAPINDEX_LENGTH, 2); nextToken(); Pattern(); if (null != m_token) { String extraTokens = ""; while (null != m_token) { extraTokens += "'" + m_token + "'"; nextToken(); if (null != m_token) extraTokens += ", "; } error(XPATHErrorResources.ER_EXTRA_ILLEGAL_TOKENS, new Object[]{ extraTokens }); //"Extra illegal tokens: "+extraTokens); } // Terminate for safety. m_ops.setOp(m_ops.getOp(OpMap.MAPINDEX_LENGTH), OpCodes.ENDOP); m_ops.setOp(OpMap.MAPINDEX_LENGTH, m_ops.getOp(OpMap.MAPINDEX_LENGTH)+1); m_ops.shrink(); } /** The error listener where syntax errors are to be sent. */ private ErrorListener m_errorListener; /** The source location of the XPath. */ javax.xml.transform.SourceLocator m_sourceLocator; /** * Allow an application to register an error event handler, where syntax * errors will be sent. If the error listener is not set, syntax errors * will be sent to System.err. * * @param handler Reference to error listener where syntax errors will be * sent. */ public void setErrorHandler(ErrorListener handler) { m_errorListener = handler; } /** * Return the current error listener. * * @return The error listener, which should not normally be null, but may be. */ public ErrorListener getErrorListener() { return m_errorListener; } /** * Check whether m_token matches the target string. * * @param s A string reference or null. * * @return If m_token is null, returns false (or true if s is also null), or * return true if the current token matches the string, else false. */ final boolean tokenIs(String s) { return (m_token != null) ? (m_token.equals(s)) : (s == null); } /** * Check whether m_tokenChar==c. * * @param c A character to be tested. * * @return If m_token is null, returns false, or return true if c matches * the current token. */ final boolean tokenIs(char c) { return (m_token != null) ? (m_tokenChar == c) : false; } /** * Look ahead of the current token in order to * make a branching decision. * * @param c the character to be tested for. * @param n number of tokens to look ahead. Must be * greater than 1. * * @return true if the next token matches the character argument. */ final boolean lookahead(char c, int n) { int pos = (m_queueMark + n); boolean b; if ((pos <= m_ops.getTokenQueueSize()) && (pos > 0) && (m_ops.getTokenQueueSize() != 0)) { String tok = ((String) m_ops.m_tokenQueue.elementAt(pos - 1)); b = (tok.length() == 1) ? (tok.charAt(0) == c) : false; } else { b = false; } return b; } /** * Look behind the first character of the current token in order to * make a branching decision. * * @param c the character to compare it to. * @param n number of tokens to look behind. Must be * greater than 1. Note that the look behind terminates * at either the beginning of the string or on a '|' * character. Because of this, this method should only * be used for pattern matching. * * @return true if the token behind the current token matches the character * argument. */ private final boolean lookbehind(char c, int n) { boolean isToken; int lookBehindPos = m_queueMark - (n + 1); if (lookBehindPos >= 0) { String lookbehind = (String) m_ops.m_tokenQueue.elementAt(lookBehindPos); if (lookbehind.length() == 1) { char c0 = (lookbehind == null) ? '|' : lookbehind.charAt(0); isToken = (c0 == '|') ? false : (c0 == c); } else { isToken = false; } } else { isToken = false; } return isToken; } /** * look behind the current token in order to * see if there is a useable token. * * @param n number of tokens to look behind. Must be * greater than 1. Note that the look behind terminates * at either the beginning of the string or on a '|' * character. Because of this, this method should only * be used for pattern matching. * * @return true if look behind has a token, false otherwise. */ private final boolean lookbehindHasToken(int n) { boolean hasToken; if ((m_queueMark - n) > 0) { String lookbehind = (String) m_ops.m_tokenQueue.elementAt(m_queueMark - (n - 1)); char c0 = (lookbehind == null) ? '|' : lookbehind.charAt(0); hasToken = (c0 == '|') ? false : true; } else { hasToken = false; } return hasToken; } /** * Look ahead of the current token in order to * make a branching decision. * * @param s the string to compare it to. * @param n number of tokens to lookahead. Must be * greater than 1. * * @return true if the token behind the current token matches the string * argument. */ private final boolean lookahead(String s, int n) { boolean isToken; if ((m_queueMark + n) <= m_ops.getTokenQueueSize()) { String lookahead = (String) m_ops.m_tokenQueue.elementAt(m_queueMark + (n - 1)); isToken = (lookahead != null) ? lookahead.equals(s) : (s == null); } else { isToken = (null == s); } return isToken; } /** * Retrieve the next token from the command and * store it in m_token string. */ private final void nextToken() { if (m_queueMark < m_ops.getTokenQueueSize()) { m_token = (String) m_ops.m_tokenQueue.elementAt(m_queueMark++); m_tokenChar = m_token.charAt(0); } else { m_token = null; m_tokenChar = 0; } } /** * Retrieve a token relative to the current token. * * @param i Position relative to current token. * * @return The string at the given index, or null if the index is out * of range.
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?