xpathparser.java
来自「RESIN 3.2 最新源码」· Java 代码 · 共 1,355 行 · 第 1/3 页
JAVA
1,355 行
/* * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved * * This file is part of Resin(R) Open Source * * Each copy or derived work must preserve the copyright notice and this * notice unmodified. * * Resin Open Source is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Resin Open Source is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty * of NON-INFRINGEMENT. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with Resin Open Source; if not, write to the * Free SoftwareFoundation, Inc. * 59 Temple Place, Suite 330 * Boston, MA 02111-1307 USA * * @author Scott Ferguson */package com.caucho.xpath;import com.caucho.log.Log;import com.caucho.server.util.CauchoSystem;import com.caucho.util.CharBuffer;import com.caucho.util.IntMap;import com.caucho.util.L10N;import com.caucho.xml.XmlChar;import com.caucho.xpath.expr.*;import com.caucho.xpath.functions.BaseURI;import com.caucho.xpath.functions.ResolveURI;import com.caucho.xpath.functions.Trace;import com.caucho.xpath.pattern.*;import org.w3c.dom.Node;import java.lang.reflect.Constructor;import java.lang.reflect.Method;import java.lang.reflect.Modifier;import java.util.ArrayList;import java.util.HashMap;import java.util.logging.Logger;/** * Parses an XPath expression. */class XPathParser { private static final Logger log = Log.open(XPathParser.class); private static final L10N L = new L10N(XPathParser.class); private final static int ANCESTOR_AXIS = 0; private final static int ANCESTOR_OR_SELF_AXIS = ANCESTOR_AXIS + 1; private final static int ATTRIBUTE_AXIS = ANCESTOR_OR_SELF_AXIS + 1; private final static int CHILD_AXIS = ATTRIBUTE_AXIS + 1; private final static int DESCENDANT_AXIS = CHILD_AXIS + 1; private final static int DESCENDANT_OR_SELF_AXIS = DESCENDANT_AXIS + 1; private final static int FOLLOWING_AXIS = DESCENDANT_OR_SELF_AXIS + 1; private final static int FOLLOWING_SIBLING_AXIS = FOLLOWING_AXIS + 1; private final static int NAMESPACE_AXIS = FOLLOWING_SIBLING_AXIS + 1; private final static int PARENT_AXIS = NAMESPACE_AXIS + 1; private final static int PRECEDING_AXIS = PARENT_AXIS + 1; private final static int PRECEDING_SIBLING_AXIS = PRECEDING_AXIS + 1; private final static int SELF_AXIS = PRECEDING_SIBLING_AXIS + 1; private final static int TEXT = Expr.LAST_FUN + 1; private final static int COMMENT = TEXT + 1; private final static int ER = COMMENT + 1; private final static int PI = ER + 1; private final static int NODE = PI + 1; private final static int CURRENT = NODE + 1; private final static int NODE_TEXT = CURRENT + 1; private final static int CONTEXT = NODE_TEXT + 1; private static IntMap exprFunctions; private static IntMap axisMap; private static HashMap<String,Constructor> _exprFunctions; private CharBuffer tag = new CharBuffer(); private String _string; private int index; private int peek; private NamespaceContext _namespace; XPathParser(String string, NamespaceContext namespace) { _string = string; _namespace = namespace; } /** * Parse a select pattern, i.e. a path rooted in a context. */ AbstractPattern parseSelect() throws XPathParseException { AbstractPattern top = new FromContext(); AbstractPattern pattern = parseUnion(parseTop(top), top); if (index < _string.length()) throw error(L.l("unexpected character at `{0}'", badChar(read()))); return pattern; } /** * Parse a match pattern, i.e. a path with no root. */ AbstractPattern parseMatch() throws XPathParseException { AbstractPattern root = new FromAny(); AbstractPattern pattern = parseUnion(parseTop(root), root); if (index < _string.length()) throw error(L.l("unexpected character at `{0}'", badChar(read()))); return pattern; } /** * Parse an expression. */ Expr parseExpr() throws XPathParseException { Expr expr = parseExpr(null, null); if (index < _string.length()) throw error(L.l("unexpected character at `{0}'", badChar(read()))); return expr; } private AbstractPattern parseStep(AbstractPattern root) throws XPathParseException { return parseUnion(parseTop(root), root); } private AbstractPattern parseUnion(AbstractPattern left, AbstractPattern root) throws XPathParseException { int ch = skipWhitespace(read()); while (ch >= 0) { if (ch == '|') { AbstractPattern tail = parseUnion(parseTop(root), root); left = new UnionPattern(left, tail); } else break; for (ch = read(); XmlChar.isWhitespace(ch); ch = read()) { } } unread(); return left; } /** * Parses the top expression. * * <pre> * top ::= (expr) * ::= term * </pre> */ private AbstractPattern parseTop(AbstractPattern pattern) throws XPathParseException { int ch = skipWhitespace(read()); unread(); if (ch == '(') { Expr expr = parseTerm(pattern, pattern); // If the expression is really a pattern and the iterator is // ascending, then just unwrap it. if (expr instanceof NodeSetExpr) { AbstractPattern nodeSet = ((NodeSetExpr) expr).getPattern(); if (nodeSet.isAscending()) return nodeSet; } return new FromExpr(null, expr); } else return parseTerm(pattern, pattern).toNodeList(); } private AbstractPattern parseBasisTop(AbstractPattern pattern) throws XPathParseException { int ch; ch = skipWhitespace(read()); if (ch == '/') { ch = read(); if (ch == '/') { pattern = new FromRoot(); pattern = new FromDescendants(pattern, false); pattern = parseBasis(pattern); pattern = parseFilter(pattern); pattern = parsePath(pattern); return pattern; } pattern = new FromRoot(); ch = skipWhitespace(ch); if (ch == -1) return pattern; } unread(); if (pattern == null) pattern = new FromContext(); pattern = parseBasis(pattern); pattern = parseFilter(pattern); return parsePath(pattern); } /** * path ::= top ('/' filter)* */ private AbstractPattern parsePath(AbstractPattern pattern) throws XPathParseException { int ch = skipWhitespace(read()); while (ch == '/') { ch = read(); if (ch == '/') { pattern = new FromDescendants(pattern, false); pattern = parseBasis(pattern); pattern = parseFilter(pattern); } else { unread(); pattern = parseBasis(pattern); pattern = parseFilter(pattern); } ch = skipWhitespace(read()); } unread(); return pattern; } /** * filter ::= atom('[' expr ']')* */ private AbstractPattern parseFilter(AbstractPattern pattern) throws XPathParseException { int ch = skipWhitespace(read()); while (ch == '[') { AbstractPattern context = new FromContext(); Expr expr = parseExpr(context, pattern); pattern = new FilterPattern(pattern, expr); ch = skipWhitespace(read()); if (ch != ']') throw error(L.l("expected `{0}' at {1}", "]", badChar(ch))); ch = skipWhitespace(read()); } unread(); return pattern; } /** * basis ::= name::node-test * | node-test * | @node-test * | . * | .. * ; */ private AbstractPattern parseBasis(AbstractPattern pattern) throws XPathParseException { boolean fromChildren = true; int ch = skipWhitespace(read()); int nodeType = Node.ELEMENT_NODE; String namespace = null; tag.clear(); if (ch == '@') { if (pattern instanceof FromDescendants) pattern = NodeTypePattern.create(pattern, NodeTypePattern.NODE); pattern = new FromAttributes(pattern); nodeType = Node.ATTRIBUTE_NODE; fromChildren = false; ch = read(); } else if (ch == '.') { ch = read(); if (ch == '.') return NodeTypePattern.create(new FromParent(pattern), NodeTypePattern.NODE); else { unread(); if (pattern != null) return pattern; else return NodeTypePattern.create(new FromSelf(pattern), NodeTypePattern.ANY); } } else if (ch == '(') { // XXX: not strictly correct for counting Expr expr = parseExpr(null, null); if ((ch = read()) != ')') throw error(L.l("expected `{0}' at {1}", ")", badChar(ch))); return new FromExpr(pattern, expr); } if (ch == '*') { tag.append('*'); } else if (XmlChar.isNameStart(ch)) { for (; XmlChar.isNameChar(ch); ch = read()) tag.append((char) ch); if (ch == '*' && tag.endsWith(":")) tag.append('*'); else unread(); } else unread(); String name = tag.toString(); if (name.equals("")) throw error(L.l("expected name at {0}", badChar(ch))); return parseAxis(pattern, name, fromChildren, nodeType); } private AbstractPattern parseAxis(AbstractPattern pattern, String name, boolean fromChildren, int nodeType) throws XPathParseException { String axis = ""; int axisIndex = name.indexOf("::"); if (axisIndex >= 0 && nodeType != Node.ATTRIBUTE_NODE) { axis = name.substring(0, axisIndex); name = name.substring(axisIndex + 2); } if (pattern instanceof FromDescendants) return parseNodeTest(pattern, name, false, Node.ELEMENT_NODE); switch (axisMap.get(axis)) { case ANCESTOR_AXIS: return parseNodeTest(new FromAncestors(pattern, false), name, false, Node.ELEMENT_NODE); case ANCESTOR_OR_SELF_AXIS: return parseNodeTest(new FromAncestors(pattern, true), name, false, Node.ELEMENT_NODE); case ATTRIBUTE_AXIS: return parseNodeTest(new FromAttributes(pattern), name, false, Node.ATTRIBUTE_NODE); case CHILD_AXIS: return parseNodeTest(new FromChildren(pattern), name, false, Node.ELEMENT_NODE); case DESCENDANT_AXIS: return parseNodeTest(new FromDescendants(pattern, false), name, false, Node.ELEMENT_NODE); case DESCENDANT_OR_SELF_AXIS: return parseNodeTest(new FromDescendants(pattern, true), name, false, Node.ELEMENT_NODE); case FOLLOWING_AXIS: return parseNodeTest(new FromNext(pattern), name, false, Node.ELEMENT_NODE); case FOLLOWING_SIBLING_AXIS: return parseNodeTest(new FromNextSibling(pattern), name, false, Node.ELEMENT_NODE); case NAMESPACE_AXIS: return parseNodeTest(new FromNamespace(pattern), name, false, Node.ATTRIBUTE_NODE); case PARENT_AXIS: return parseNodeTest(new FromParent(pattern), name, false, Node.ELEMENT_NODE); case PRECEDING_AXIS: return parseNodeTest(new FromPrevious(pattern), name, false, Node.ELEMENT_NODE); case PRECEDING_SIBLING_AXIS: return parseNodeTest(new FromPreviousSibling(pattern), name, false, Node.ELEMENT_NODE); case SELF_AXIS: return parseNodeTest(new FromSelf(pattern), name, false, Node.ELEMENT_NODE); default: return parseNodeTest(pattern, name, fromChildren, nodeType); } } /** * node-test ::= qname * | *:name * | * * | name '(' args ')' * ; */ private AbstractPattern parseNodeTest(AbstractPattern pattern, String name, boolean fromChildren, int nodeType) throws XPathParseException {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?