0001: /*
0002: * The Apache Software License, Version 1.1
0003: *
0004: *
0005: * Copyright (c) 2000,2001 The Apache Software Foundation.
0006: * All rights reserved.
0007: *
0008: * Redistribution and use in source and binary forms, with or without
0009: * modification, are permitted provided that the following conditions
0010: * are met:
0011: *
0012: * 1. Redistributions of source code must retain the above copyright
0013: * notice, this list of conditions and the following disclaimer.
0014: *
0015: * 2. Redistributions in binary form must reproduce the above copyright
0016: * notice, this list of conditions and the following disclaimer in
0017: * the documentation and/or other materials provided with the
0018: * distribution.
0019: *
0020: * 3. The end-user documentation included with the redistribution,
0021: * if any, must include the following acknowledgment:
0022: * "This product includes software developed by the
0023: * Apache Software Foundation (http://www.apache.org/)."
0024: * Alternately, this acknowledgment may appear in the software itself,
0025: * if and wherever such third-party acknowledgments normally appear.
0026: *
0027: * 4. The names "Xerces" and "Apache Software Foundation" must
0028: * not be used to endorse or promote products derived from this
0029: * software without prior written permission. For written
0030: * permission, please contact apache@apache.org.
0031: *
0032: * 5. Products derived from this software may not be called "Apache",
0033: * nor may "Apache" appear in their name, without prior written
0034: * permission of the Apache Software Foundation.
0035: *
0036: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
0037: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0038: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
0039: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
0040: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
0041: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0042: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
0043: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
0044: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
0045: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
0046: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
0047: * SUCH DAMAGE.
0048: * ====================================================================
0049: *
0050: * This software consists of voluntary contributions made by many
0051: * individuals on behalf of the Apache Software Foundation and was
0052: * originally based on software copyright (c) 1999, International
0053: * Business Machines, Inc., http://www.apache.org. For more
0054: * information on the Apache Software Foundation, please see
0055: * <http://www.apache.org/>.
0056: */
0057:
0058: package org.apache.xerces.validators.schema.identity;
0059:
0060: import org.apache.xerces.utils.NamespacesScope;
0061: import org.apache.xerces.utils.QName;
0062: import org.apache.xerces.utils.StringPool;
0063: import org.apache.xerces.utils.XMLCharacterProperties;
0064:
0065: /**
0066: * Bare minimum XPath parser.
0067: *
0068: * @author Andy Clark, IBM
0069: * @version $Id: XPath.java,v 1.10 2001/06/08 14:23:49 sandygao Exp $
0070: */
0071: public class XPath {
0072:
0073: //
0074: // Constants
0075: //
0076:
0077: private static final boolean DEBUG_ALL = false;
0078:
0079: private static final boolean DEBUG_XPATH_PARSE = DEBUG_ALL || false;
0080:
0081: private static final boolean DEBUG_ANY = DEBUG_XPATH_PARSE;
0082:
0083: //
0084: // Data
0085: //
0086:
0087: /** Expression. */
0088: protected String fExpression;
0089:
0090: // Xerces 1.x framework
0091:
0092: /** String pool. */
0093: protected StringPool fStringPool;
0094:
0095: //
0096: // Constructors
0097: //
0098:
0099: /** Constructs an XPath object from the specified expression. */
0100: public XPath(String xpath, StringPool stringPool,
0101: NamespacesScope context) throws XPathException {
0102: XMLCharacterProperties.initCharFlags();
0103: fExpression = xpath;
0104: fStringPool = stringPool;
0105: parseExpression(context);
0106: } // <init>(String,StringPool,NamespacesScope)
0107:
0108: //
0109: // Public methods
0110: //
0111:
0112: /** Returns a representation of the first location path for this XPath. */
0113: public LocationPath getLocationPath() {
0114: return (LocationPath) fLocationPaths[0].clone();
0115: } // getLocationPath(LocationPath)
0116:
0117: //
0118: // Object methods
0119: //
0120:
0121: /** Returns a string representation of this object. */
0122: public String toString() {
0123: StringBuffer buf = new StringBuffer();
0124: for (int i = 0; i < fLocationPaths.length; i++) {
0125: if (i > 0) {
0126: buf.append("|");
0127: }
0128: buf.append(fLocationPaths[i].toString());
0129: }
0130: return buf.toString();
0131: } // toString():String
0132:
0133: //
0134: // Private methods
0135: //
0136:
0137: /**
0138: * This method is implemented by using the XPathExprScanner and
0139: * examining the list of tokens that it returns.
0140: */
0141: private void parseExpression(final NamespacesScope context)
0142: throws XPathException {
0143:
0144: // tokens
0145: final XPath.Tokens xtokens = new XPath.Tokens(fStringPool);
0146:
0147: // scanner
0148: XPath.Scanner scanner = new XPath.Scanner(fStringPool) {
0149: protected void addToken(XPath.Tokens tokens, int token)
0150: throws XPathException {
0151: if (token == XPath.Tokens.EXPRTOKEN_ATSIGN
0152: || token == XPath.Tokens.EXPRTOKEN_AXISNAME_ATTRIBUTE
0153: || token == XPath.Tokens.EXPRTOKEN_AXISNAME_CHILD
0154: ||
0155: //token == XPath.Tokens.EXPRTOKEN_AXISNAME_SELF ||
0156: token == XPath.Tokens.EXPRTOKEN_DOUBLE_COLON
0157: ||
0158: //token == XPath.Tokens.EXPRTOKEN_NAMETEST_ANY ||
0159: token == XPath.Tokens.EXPRTOKEN_NAMETEST_QNAME
0160: ||
0161: //token == XPath.Tokens.EXPRTOKEN_NODETYPE_NODE ||
0162: token == XPath.Tokens.EXPRTOKEN_OPERATOR_SLASH
0163: || token == XPath.Tokens.EXPRTOKEN_PERIOD
0164: ||
0165: //added to conform to PR Spec
0166: token == XPath.Tokens.EXPRTOKEN_NAMETEST_ANY
0167: || token == XPath.Tokens.EXPRTOKEN_NAMETEST_NAMESPACE
0168: || token == XPath.Tokens.EXPRTOKEN_OPERATOR_DOUBLE_SLASH
0169: || token == XPath.Tokens.EXPRTOKEN_OPERATOR_UNION
0170: //
0171: ) {
0172: super .addToken(tokens, token);
0173: return;
0174: }
0175: StringBuffer str = new StringBuffer();
0176: str.append("token not supported: ");
0177: String tokenName = tokens.getTokenName(token);
0178: if (tokenName != null) {
0179: str.append('"');
0180: str.append(tokenName);
0181: str.append('"');
0182: } else {
0183: str.append('(');
0184: str.append(token);
0185: str.append(')');
0186: }
0187: String message = str.toString();
0188: throw new XPathException(message);
0189: }
0190: };
0191:
0192: int length = fExpression.length();
0193: /***/
0194: boolean success = scanner.scanExpr(fStringPool, xtokens,
0195: fExpression, 0, length);
0196: //fTokens.dumpTokens();
0197: java.util.Vector stepsVector = new java.util.Vector();
0198: java.util.Vector locationPathsVector = new java.util.Vector();
0199: int tokenCount = xtokens.getTokenCount();
0200: boolean firstTokenOfLocationPath = true;
0201:
0202: for (int i = 0; i < tokenCount; i++) {
0203: int token = xtokens.getToken(i);
0204: boolean isNamespace = false;
0205:
0206: switch (token) {
0207: case XPath.Tokens.EXPRTOKEN_OPERATOR_UNION: {
0208: if (i == 0) {
0209: throw new XPathException(
0210: "not allowed to have '|' at the beginning of an xpath value");
0211: }
0212:
0213: int size = stepsVector.size();
0214: if (size == 0) {
0215: throw new XPathException("not allowed to have '||'");
0216: }
0217: Step[] steps = new Step[size];
0218: stepsVector.copyInto(steps);
0219: // add location path
0220: locationPathsVector.addElement(new LocationPath(steps));
0221: //reset stepsVector
0222: stepsVector.removeAllElements();
0223: firstTokenOfLocationPath = true;
0224: break;
0225: }
0226:
0227: case XPath.Tokens.EXPRTOKEN_AXISNAME_ATTRIBUTE: {
0228: // consume "::" token and drop through
0229: i++;
0230: }
0231: case XPath.Tokens.EXPRTOKEN_ATSIGN: {
0232: // consume QName token
0233: if (i == tokenCount - 1) {
0234: throw new XPathException("missing attribute name");
0235: }
0236: token = xtokens.getToken(++i);
0237:
0238: if (token != XPath.Tokens.EXPRTOKEN_NAMETEST_QNAME
0239: && token != XPath.Tokens.EXPRTOKEN_NAMETEST_ANY
0240: && token != XPath.Tokens.EXPRTOKEN_NAMETEST_NAMESPACE) {
0241: throw new XPathException(
0242: "expected \""
0243: + xtokens
0244: .getTokenName(XPath.Tokens.EXPRTOKEN_NAMETEST_QNAME)
0245: + "\" or \""
0246: + xtokens
0247: .getTokenName(XPath.Tokens.EXPRTOKEN_NAMETEST_ANY)
0248: + "\" or \""
0249: + xtokens
0250: .getTokenName(XPath.Tokens.EXPRTOKEN_NAMETEST_NAMESPACE)
0251: + "\", found "
0252: + xtokens.getTokenName(token));
0253: }
0254: boolean isNamespaceAtt = false;
0255: switch (token) {
0256: case XPath.Tokens.EXPRTOKEN_NAMETEST_ANY: {
0257: Axis axis = new Axis(Axis.ATTRIBUTE);
0258: NodeTest nodeTest = new NodeTest(NodeTest.WILDCARD);
0259: Step step = new Step(axis, nodeTest);
0260: stepsVector.addElement(step);
0261: break;
0262: }
0263: case XPath.Tokens.EXPRTOKEN_NAMETEST_NAMESPACE: {
0264: isNamespaceAtt = true;
0265: }
0266: case XPath.Tokens.EXPRTOKEN_NAMETEST_QNAME: {
0267:
0268: token = xtokens.getToken(++i);
0269: int prefix = xtokens.getTokenString(token);
0270: int uri = StringPool.EMPTY_STRING;
0271: if (context != null && prefix != -1) {
0272: uri = context.getNamespaceForPrefix(prefix);
0273: }
0274: if (prefix != -1 && context != null
0275: && uri == StringPool.EMPTY_STRING) {
0276: throw new XPathException("prefix "
0277: + fStringPool.toString(prefix)
0278: + " not bound to namespace URI");
0279: }
0280:
0281: if (isNamespaceAtt) {
0282: // build step
0283: Axis axis = new Axis(Axis.ATTRIBUTE);
0284: NodeTest nodeTest = new NodeTest(fStringPool,
0285: prefix, uri);
0286: Step step = new Step(axis, nodeTest);
0287: stepsVector.addElement(step);
0288: break;
0289: }
0290:
0291: token = xtokens.getToken(++i);
0292: int localpart = xtokens.getTokenString(token);
0293: int rawname = prefix != -1 ? fStringPool
0294: .addSymbol(fStringPool.toString(prefix)
0295: + ':'
0296: + fStringPool.toString(localpart))
0297: : localpart;
0298:
0299: // build step
0300: Axis axis = new Axis(Axis.ATTRIBUTE);
0301: NodeTest nodeTest = new NodeTest(fStringPool,
0302: new QName(prefix, localpart, rawname, uri));
0303: Step step = new Step(axis, nodeTest);
0304: stepsVector.addElement(step);
0305: break;
0306: }
0307: }
0308: firstTokenOfLocationPath = false;
0309: break;
0310: }
0311: /***
0312: case XPath.Tokens.EXPRTOKEN_AXISNAME_SELF: {
0313: break;
0314: }
0315: /***/
0316: case XPath.Tokens.EXPRTOKEN_DOUBLE_COLON: {
0317: // should never have a bare double colon
0318: throw new XPathException(
0319: "Not allowed to have double colon here");
0320: }
0321: /***
0322: case XPath.Tokens.EXPRTOKEN_NAMETEST_ANY: {
0323: break;
0324: }
0325: /***/
0326: case XPath.Tokens.EXPRTOKEN_AXISNAME_CHILD: {
0327:
0328: // consume "::" token and drop through
0329: i++;
0330: if (i == tokenCount - 1) {
0331: throw new XPathException(
0332: "expected step following '"
0333: + xtokens
0334: .getTokenName(XPath.Tokens.EXPRTOKEN_AXISNAME_CHILD)
0335: + "::'");
0336: }
0337: firstTokenOfLocationPath = false;
0338: break;
0339: }
0340: case XPath.Tokens.EXPRTOKEN_NAMETEST_ANY: {
0341: Axis axis = new Axis(Axis.CHILD);
0342: NodeTest nodeTest = new NodeTest(NodeTest.WILDCARD);
0343: Step step = new Step(axis, nodeTest);
0344: stepsVector.addElement(step);
0345: firstTokenOfLocationPath = false;
0346: break;
0347: }
0348:
0349: case XPath.Tokens.EXPRTOKEN_NAMETEST_NAMESPACE: {
0350: isNamespace = true;
0351: }
0352: case XPath.Tokens.EXPRTOKEN_NAMETEST_QNAME: {
0353: // consume QName token
0354: token = xtokens.getToken(++i);
0355: int prefix = xtokens.getTokenString(token);
0356: int uri = StringPool.EMPTY_STRING;
0357: if (context != null && prefix != -1) {
0358: uri = context.getNamespaceForPrefix(prefix);
0359: }
0360: if (prefix != -1 && context != null
0361: && uri == StringPool.EMPTY_STRING) {
0362: throw new XPathException("prefix "
0363: + fStringPool.toString(prefix)
0364: + " not bound to namespace URI");
0365: }
0366:
0367: if (isNamespace) {
0368: // build step
0369: Axis axis = new Axis(Axis.CHILD);
0370: NodeTest nodeTest = new NodeTest(fStringPool,
0371: prefix, uri);
0372: Step step = new Step(axis, nodeTest);
0373: stepsVector.addElement(step);
0374: break;
0375: }
0376:
0377: token = xtokens.getToken(++i);
0378: int localpart = xtokens.getTokenString(token);
0379: int rawname = prefix != -1 ? fStringPool
0380: .addSymbol(fStringPool.toString(prefix) + ':'
0381: + fStringPool.toString(localpart))
0382: : localpart;
0383:
0384: // build step
0385: Axis axis = new Axis(Axis.CHILD);
0386: NodeTest nodeTest = new NodeTest(fStringPool,
0387: new QName(prefix, localpart, rawname, uri));
0388: Step step = new Step(axis, nodeTest);
0389: stepsVector.addElement(step);
0390: firstTokenOfLocationPath = false;
0391: break;
0392: }
0393: /***
0394: case XPath.Tokens.EXPRTOKEN_NODETYPE_NODE: {
0395: break;
0396: }
0397: /***/
0398:
0399: case XPath.Tokens.EXPRTOKEN_PERIOD: {
0400: // build step
0401: Axis axis = new Axis(Axis.SELF);
0402: NodeTest nodeTest = new NodeTest(NodeTest.NODE);
0403: Step step = new Step(axis, nodeTest);
0404: stepsVector.addElement(step);
0405:
0406: if (firstTokenOfLocationPath && i + 1 < tokenCount) {
0407: token = xtokens.getToken(i + 1);
0408: if (token == XPath.Tokens.EXPRTOKEN_OPERATOR_DOUBLE_SLASH) {
0409: i++;
0410: if (i == tokenCount - 1) {
0411: throw new XPathException(
0412: "expected step following '//'");
0413: }
0414: if (i + 1 < tokenCount) {
0415: token = xtokens.getToken(i + 1);
0416: if (token == XPath.Tokens.EXPRTOKEN_OPERATOR_SLASH)
0417: throw new XPathException(
0418: "'/' not allowed after '//'");
0419: }
0420: // build step
0421: axis = new Axis(Axis.DESCENDANT);
0422: nodeTest = new NodeTest(NodeTest.NODE);
0423: step = new Step(axis, nodeTest);
0424: stepsVector.addElement(step);
0425: }
0426: }
0427: firstTokenOfLocationPath = false;
0428: break;
0429: }
0430:
0431: case XPath.Tokens.EXPRTOKEN_OPERATOR_DOUBLE_SLASH: {
0432: throw new XPathException(
0433: "'//' only allowed after '.' at the beginning of an xpath");
0434: }
0435: case XPath.Tokens.EXPRTOKEN_OPERATOR_SLASH: {
0436: if (i == 0) {
0437: throw new XPathException(
0438: "not allowed to have '/' at the beginning of an xpath value");
0439: }
0440: // keep on truckin'
0441: if (firstTokenOfLocationPath) {
0442: throw new XPathException(
0443: "not allowed to select the root");
0444: }
0445: if (i == tokenCount - 1) {
0446: throw new XPathException(
0447: "expected step following '/'");
0448: }
0449: firstTokenOfLocationPath = false;
0450: break;
0451: }
0452: default:
0453: firstTokenOfLocationPath = false;
0454: }
0455: }
0456:
0457: int size = stepsVector.size();
0458: if (size == 0) {
0459: if (locationPathsVector.size() == 0)
0460: throw new XPathException("empty xpath expression");
0461: else
0462: throw new XPathException("xpath cannot end with '|'");
0463: }
0464: Step[] steps = new Step[size];
0465: stepsVector.copyInto(steps);
0466: locationPathsVector.addElement(new LocationPath(steps));
0467:
0468: // save location path
0469: fLocationPaths = new LocationPath[locationPathsVector.size()];
0470: locationPathsVector.copyInto(fLocationPaths);
0471:
0472: if (DEBUG_XPATH_PARSE) {
0473: System.out.println(">>> " + fLocationPaths);
0474: }
0475:
0476: } // parseExpression(SymbolTable,NamespaceContext)
0477:
0478: //
0479: // Classes
0480: //
0481:
0482: // location path information
0483:
0484: /**
0485: * A location path representation for an XPath expression.
0486: *
0487: * @author Andy Clark, IBM
0488: */
0489: public static class LocationPath implements Cloneable {
0490:
0491: //
0492: // Data
0493: //
0494:
0495: /** List of steps. */
0496: public Step[] steps;
0497:
0498: //
0499: // Constructors
0500: //
0501:
0502: /** Creates a location path from a series of steps. */
0503: public LocationPath(Step[] steps) {
0504: this .steps = steps;
0505: } // <init>(Step[])
0506:
0507: /** Copy constructor. */
0508: protected LocationPath(LocationPath path) {
0509: steps = new Step[path.steps.length];
0510: for (int i = 0; i < steps.length; i++) {
0511: steps[i] = (Step) path.steps[i].clone();
0512: }
0513: } // <init>(LocationPath)
0514:
0515: //
0516: // Object methods
0517: //
0518:
0519: /** Returns a string representation of this object. */
0520: public String toString() {
0521: StringBuffer str = new StringBuffer();
0522: for (int i = 0; i < steps.length; i++) {
0523: if (i > 0
0524: && (steps[i - 1].axis.type != Axis.DESCENDANT && steps[i].axis.type != Axis.DESCENDANT)) {
0525: str.append('/');
0526: }
0527: str.append(steps[i].toString());
0528: }
0529: // DEBUG: This code is just for debugging and should *not*
0530: // be left in because it will mess up hashcodes of
0531: // serialized versions of this object. -Ac
0532: if (false) {
0533: str.append('[');
0534: String s = super .toString();
0535: str.append(s.substring(s.indexOf('@')));
0536: str.append(']');
0537: }
0538: return str.toString();
0539: } // toString():String
0540:
0541: /** Returns a clone of this object. */
0542: public Object clone() {
0543: return new LocationPath(this );
0544: } // clone():Object
0545:
0546: } // class locationPath
0547:
0548: /**
0549: * A location path step comprised of an axis and node test.
0550: *
0551: * @author Andy Clark, IBM
0552: */
0553: public static class Step implements Cloneable {
0554:
0555: //
0556: // Data
0557: //
0558:
0559: /** Axis. */
0560: public Axis axis;
0561:
0562: /** Node test. */
0563: public NodeTest nodeTest;
0564:
0565: //
0566: // Constructors
0567: //
0568:
0569: /** Constructs a step from an axis and node test. */
0570: public Step(Axis axis, NodeTest nodeTest) {
0571: this .axis = axis;
0572: this .nodeTest = nodeTest;
0573: } // <init>(Axis,NodeTest)
0574:
0575: /** Copy constructor. */
0576: protected Step(Step step) {
0577: axis = (Axis) step.axis.clone();
0578: nodeTest = (NodeTest) step.nodeTest.clone();
0579: } // <init>(Step)
0580:
0581: //
0582: // Object methods
0583: //
0584:
0585: /** Returns a string representation of this object. */
0586: public String toString() {
0587: /***
0588: return axis.toString() + "::" + nodeTest.toString();
0589: /***/
0590: if (axis.type == Axis.SELF) {
0591: return ".";
0592: }
0593: if (axis.type == Axis.ATTRIBUTE) {
0594: return "@" + nodeTest.toString();
0595: }
0596: if (axis.type == Axis.CHILD) {
0597: return nodeTest.toString();
0598: }
0599: if (axis.type == Axis.DESCENDANT) {
0600: return "//";
0601: }
0602: return "??? (" + axis.type + ')';
0603: /***/
0604: } // toString():String
0605:
0606: /** Returns a clone of this object. */
0607: public Object clone() {
0608: return new Step(this );
0609: } // clone():Object
0610:
0611: } // class Step
0612:
0613: /**
0614: * Axis.
0615: *
0616: * @author Andy Clark, IBM
0617: */
0618: public static class Axis implements Cloneable {
0619:
0620: //
0621: // Constants
0622: //
0623:
0624: /** Type: child. */
0625: public static final short CHILD = 1;
0626:
0627: /** Type: attribute. */
0628: public static final short ATTRIBUTE = 2;
0629:
0630: /** Type: self. */
0631: public static final short SELF = 3;
0632:
0633: /** Type: descendant. */
0634: public static final short DESCENDANT = 4;
0635: //
0636: // Data
0637: //
0638:
0639: /** Axis type. */
0640: public short type;
0641:
0642: //
0643: // Constructors
0644: //
0645:
0646: /** Constructs an axis with the specified type. */
0647: public Axis(short type) {
0648: this .type = type;
0649: } // <init>(short)
0650:
0651: /** Copy constructor. */
0652: protected Axis(Axis axis) {
0653: type = axis.type;
0654: } // <init>(Axis)
0655:
0656: //
0657: // Object methods
0658: //
0659:
0660: /** Returns a string representation of this object. */
0661: public String toString() {
0662: switch (type) {
0663: case CHILD:
0664: return "child";
0665: case ATTRIBUTE:
0666: return "attribute";
0667: case SELF:
0668: return "self";
0669: case DESCENDANT:
0670: return "descendant";
0671: }
0672: return "???";
0673: } // toString():String
0674:
0675: /** Returns a clone of this object. */
0676: public Object clone() {
0677: return new Axis(this );
0678: } // clone():Object
0679:
0680: } // class Axis
0681:
0682: /**
0683: * Node test.
0684: *
0685: * @author Andy Clark, IBM
0686: */
0687: public static class NodeTest implements Cloneable {
0688:
0689: //
0690: // Constants
0691: //
0692:
0693: /** Type: qualified name. */
0694: public static final short QNAME = 1;
0695:
0696: /** Type: wildcard. */
0697: public static final short WILDCARD = 2;
0698:
0699: /** Type: node. */
0700: public static final short NODE = 3;
0701:
0702: /** Type: namespace */
0703: public static final short NAMESPACE = 4;
0704:
0705: //
0706: // Data
0707: //
0708:
0709: /** String pool. */
0710: protected StringPool fStringPool;
0711:
0712: /** Node test type. */
0713: public short type;
0714:
0715: /** Node qualified name. */
0716: public final QName name = new QName();
0717:
0718: //
0719: // Constructors
0720: //
0721:
0722: /** Constructs a node test of type WILDCARD or NODE. */
0723: public NodeTest(short type) {
0724: this .type = type;
0725: } // <init>(int)
0726:
0727: /** Constructs a node test of type QName. */
0728: public NodeTest(StringPool stringPool, QName name) {
0729: fStringPool = stringPool;
0730: this .type = QNAME;
0731: this .name.setValues(name);
0732: } // <init>(QName)
0733:
0734: /** Constructs a node test of type Namespace. */
0735: public NodeTest(StringPool stringPool, int prefix, int uri) {
0736: fStringPool = stringPool;
0737: this .type = NAMESPACE;
0738: this .name.setValues(prefix, -1, -1, uri);
0739: }
0740:
0741: /** Copy constructor. */
0742: public NodeTest(NodeTest nodeTest) {
0743: fStringPool = nodeTest.fStringPool;
0744: type = nodeTest.type;
0745: name.setValues(nodeTest.name);
0746: } // <init>(NodeTest)
0747:
0748: //
0749: // Object methods
0750: //
0751:
0752: /** Returns a string representation of this object. */
0753: public String toString() {
0754:
0755: switch (type) {
0756: case QNAME: {
0757: if (name.prefix != -1) {
0758: if (name.uri == StringPool.EMPTY_STRING) {
0759: return fStringPool.toString(name.prefix) + ':'
0760: + fStringPool.toString(name.localpart);
0761: }
0762: return "{" + fStringPool.toString(name.uri) + '}'
0763: + fStringPool.toString(name.prefix) + ':'
0764: + fStringPool.toString(name.localpart);
0765: }
0766: return fStringPool.toString(name.localpart);
0767: }
0768: case NAMESPACE: {
0769: if (name.prefix != -1) {
0770: if (name.uri == StringPool.EMPTY_STRING) {
0771: return fStringPool.toString(name.prefix) + ":*";
0772: }
0773: return "{" + fStringPool.toString(name.uri) + '}'
0774: + fStringPool.toString(name.prefix) + ":*";
0775: }
0776: return "???:*";
0777: }
0778: case WILDCARD: {
0779: return "*";
0780: }
0781: case NODE: {
0782: return "node()";
0783: }
0784: }
0785: return "???";
0786:
0787: } // toString():String
0788:
0789: /** Returns a clone of this object. */
0790: public Object clone() {
0791: return new NodeTest(this );
0792: } // clone():Object
0793:
0794: } // class NodeTest
0795:
0796: // xpath implementation
0797:
0798: // NOTE: The XPath implementation classes are kept internal because
0799: // this implementation is just a temporary hack until a better
0800: // and/or more appropriate implementation can be written.
0801: // keeping the code in separate source files would "muddy" the
0802: // CVS directory when it's not needed. -Ac
0803:
0804: /**
0805: * @author Glenn Marcy, IBM
0806: * @author Andy Clark, IBM
0807: *
0808: * @version $Id: XPath.java,v 1.10 2001/06/08 14:23:49 sandygao Exp $
0809: */
0810: private static final class Tokens {
0811:
0812: static final boolean DUMP_TOKENS = false;
0813:
0814: /**
0815: * [28] ExprToken ::= '(' | ')' | '[' | ']' | '.' | '..' | '@' | ',' | '::'
0816: * | NameTest | NodeType | Operator | FunctionName
0817: * | AxisName | Literal | Number | VariableReference
0818: */
0819: public static final int EXPRTOKEN_OPEN_PAREN = 0,
0820: EXPRTOKEN_CLOSE_PAREN = 1,
0821: EXPRTOKEN_OPEN_BRACKET = 2,
0822: EXPRTOKEN_CLOSE_BRACKET = 3,
0823: EXPRTOKEN_PERIOD = 4,
0824: EXPRTOKEN_DOUBLE_PERIOD = 5,
0825: EXPRTOKEN_ATSIGN = 6,
0826: EXPRTOKEN_COMMA = 7,
0827: EXPRTOKEN_DOUBLE_COLON = 8,
0828: //
0829: // [37] NameTest ::= '*' | NCName ':' '*' | QName
0830: //
0831: // followed by symbol handle of NCName or QName
0832: //
0833: EXPRTOKEN_NAMETEST_ANY = 9,
0834: EXPRTOKEN_NAMETEST_NAMESPACE = 10,
0835: EXPRTOKEN_NAMETEST_QNAME = 11,
0836: //
0837: // [38] NodeType ::= 'comment' | 'text' | 'processing-instruction' | 'node'
0838: //
0839: EXPRTOKEN_NODETYPE_COMMENT = 12,
0840: EXPRTOKEN_NODETYPE_TEXT = 13,
0841: EXPRTOKEN_NODETYPE_PI = 14,
0842: EXPRTOKEN_NODETYPE_NODE = 15,
0843: //
0844: // [32] Operator ::= OperatorName
0845: // | MultiplyOperator
0846: // | '/' | '//' | '|' | '+' | '-' | '=' | '!=' | '<' | '<=' | '>' | '>='
0847: // [33] OperatorName ::= 'and' | 'or' | 'mod' | 'div'
0848: // [34] MultiplyOperator ::= '*'
0849: //
0850: EXPRTOKEN_OPERATOR_AND = 16,
0851: EXPRTOKEN_OPERATOR_OR = 17,
0852: EXPRTOKEN_OPERATOR_MOD = 18,
0853: EXPRTOKEN_OPERATOR_DIV = 19,
0854: EXPRTOKEN_OPERATOR_MULT = 20,
0855: EXPRTOKEN_OPERATOR_SLASH = 21,
0856: EXPRTOKEN_OPERATOR_DOUBLE_SLASH = 22,
0857: EXPRTOKEN_OPERATOR_UNION = 23,
0858: EXPRTOKEN_OPERATOR_PLUS = 24,
0859: EXPRTOKEN_OPERATOR_MINUS = 25,
0860: EXPRTOKEN_OPERATOR_EQUAL = 26,
0861: EXPRTOKEN_OPERATOR_NOT_EQUAL = 27,
0862: EXPRTOKEN_OPERATOR_LESS = 28,
0863: EXPRTOKEN_OPERATOR_LESS_EQUAL = 29,
0864: EXPRTOKEN_OPERATOR_GREATER = 30,
0865: EXPRTOKEN_OPERATOR_GREATER_EQUAL = 31,
0866:
0867: //EXPRTOKEN_FIRST_OPERATOR = EXPRTOKEN_OPERATOR_AND,
0868: //EXPRTOKEN_LAST_OPERATOR = EXPRTOKEN_OPERATOR_GREATER_EQUAL,
0869:
0870: //
0871: // [35] FunctionName ::= QName - NodeType
0872: //
0873: // followed by symbol handle
0874: //
0875: EXPRTOKEN_FUNCTION_NAME = 32,
0876: //
0877: // [6] AxisName ::= 'ancestor' | 'ancestor-or-self'
0878: // | 'attribute'
0879: // | 'child'
0880: // | 'descendant' | 'descendant-or-self'
0881: // | 'following' | 'following-sibling'
0882: // | 'namespace'
0883: // | 'parent'
0884: // | 'preceding' | 'preceding-sibling'
0885: // | 'self'
0886: //
0887: EXPRTOKEN_AXISNAME_ANCESTOR = 33,
0888: EXPRTOKEN_AXISNAME_ANCESTOR_OR_SELF = 34,
0889: EXPRTOKEN_AXISNAME_ATTRIBUTE = 35,
0890: EXPRTOKEN_AXISNAME_CHILD = 36,
0891: EXPRTOKEN_AXISNAME_DESCENDANT = 37,
0892: EXPRTOKEN_AXISNAME_DESCENDANT_OR_SELF = 38,
0893: EXPRTOKEN_AXISNAME_FOLLOWING = 39,
0894: EXPRTOKEN_AXISNAME_FOLLOWING_SIBLING = 40,
0895: EXPRTOKEN_AXISNAME_NAMESPACE = 41,
0896: EXPRTOKEN_AXISNAME_PARENT = 42,
0897: EXPRTOKEN_AXISNAME_PRECEDING = 43,
0898: EXPRTOKEN_AXISNAME_PRECEDING_SIBLING = 44,
0899: EXPRTOKEN_AXISNAME_SELF = 45,
0900: //
0901: // [29] Literal ::= '"' [^"]* '"' | "'" [^']* "'"
0902: //
0903: // followed by symbol handle for literal
0904: //
0905: EXPRTOKEN_LITERAL = 46,
0906: //
0907: // [30] Number ::= Digits ('.' Digits?)? | '.' Digits
0908: // [31] Digits ::= [0-9]+
0909: //
0910: // followed by number handle
0911: //
0912: EXPRTOKEN_NUMBER = 47,
0913: //
0914: // [36] VariableReference ::= '$' QName
0915: //
0916: // followed by symbol handle for QName
0917: //
0918: EXPRTOKEN_VARIABLE_REFERENCE = 48;
0919:
0920: public static final String[] fgTokenNames = {
0921: "EXPRTOKEN_OPEN_PAREN", "EXPRTOKEN_CLOSE_PAREN",
0922: "EXPRTOKEN_OPEN_BRACKET", "EXPRTOKEN_CLOSE_BRACKET",
0923: "EXPRTOKEN_PERIOD", "EXPRTOKEN_DOUBLE_PERIOD",
0924: "EXPRTOKEN_ATSIGN", "EXPRTOKEN_COMMA",
0925: "EXPRTOKEN_DOUBLE_COLON", "EXPRTOKEN_NAMETEST_ANY",
0926: "EXPRTOKEN_NAMETEST_NAMESPACE",
0927: "EXPRTOKEN_NAMETEST_QNAME",
0928: "EXPRTOKEN_NODETYPE_COMMENT",
0929: "EXPRTOKEN_NODETYPE_TEXT", "EXPRTOKEN_NODETYPE_PI",
0930: "EXPRTOKEN_NODETYPE_NODE", "EXPRTOKEN_OPERATOR_AND",
0931: "EXPRTOKEN_OPERATOR_OR", "EXPRTOKEN_OPERATOR_MOD",
0932: "EXPRTOKEN_OPERATOR_DIV", "EXPRTOKEN_OPERATOR_MULT",
0933: "EXPRTOKEN_OPERATOR_SLASH",
0934: "EXPRTOKEN_OPERATOR_DOUBLE_SLASH",
0935: "EXPRTOKEN_OPERATOR_UNION", "EXPRTOKEN_OPERATOR_PLUS",
0936: "EXPRTOKEN_OPERATOR_MINUS", "EXPRTOKEN_OPERATOR_EQUAL",
0937: "EXPRTOKEN_OPERATOR_NOT_EQUAL",
0938: "EXPRTOKEN_OPERATOR_LESS",
0939: "EXPRTOKEN_OPERATOR_LESS_EQUAL",
0940: "EXPRTOKEN_OPERATOR_GREATER",
0941: "EXPRTOKEN_OPERATOR_GREATER_EQUAL",
0942: "EXPRTOKEN_FUNCTION_NAME",
0943: "EXPRTOKEN_AXISNAME_ANCESTOR",
0944: "EXPRTOKEN_AXISNAME_ANCESTOR_OR_SELF",
0945: "EXPRTOKEN_AXISNAME_ATTRIBUTE",
0946: "EXPRTOKEN_AXISNAME_CHILD",
0947: "EXPRTOKEN_AXISNAME_DESCENDANT",
0948: "EXPRTOKEN_AXISNAME_DESCENDANT_OR_SELF",
0949: "EXPRTOKEN_AXISNAME_FOLLOWING",
0950: "EXPRTOKEN_AXISNAME_FOLLOWING_SIBLING",
0951: "EXPRTOKEN_AXISNAME_NAMESPACE",
0952: "EXPRTOKEN_AXISNAME_PARENT",
0953: "EXPRTOKEN_AXISNAME_PRECEDING",
0954: "EXPRTOKEN_AXISNAME_PRECEDING_SIBLING",
0955: "EXPRTOKEN_AXISNAME_SELF", "EXPRTOKEN_LITERAL",
0956: "EXPRTOKEN_NUMBER", "EXPRTOKEN_VARIABLE_REFERENCE" };
0957:
0958: /**
0959: *
0960: */
0961: private static final int INITIAL_TOKEN_COUNT = 1 << 8;
0962: private int[] fTokens = new int[INITIAL_TOKEN_COUNT];
0963: private int fTokenCount = 0; // for writing
0964:
0965: private StringPool fStringPool;
0966:
0967: // REVISIT: Code something better here. -Ac
0968: //private java.util.Hashtable fSymbolMapping = new java.util.Hashtable();
0969:
0970: // REVISIT: Code something better here. -Ac
0971: //private java.util.Hashtable fTokenNames = new java.util.Hashtable();
0972:
0973: //
0974: // Constructors
0975: //
0976:
0977: /***
0978: public XPath.Tokens(SymbolTable symbolTable) {
0979: fSymbolTable = symbolTable;
0980: }
0981: /***/
0982: public Tokens(StringPool stringPool) {
0983: fStringPool = stringPool;
0984: /***
0985: final String[] symbols = {
0986: "ancestor", "ancestor-or-self", "attribute",
0987: "child", "descendant", "descendant-or-self",
0988: "following", "following-sibling", "namespace",
0989: "parent", "preceding", "preceding-sibling",
0990: "self",
0991: };
0992: for (int i = 0; i < symbols.length; i++) {
0993: fSymbolMapping.put(fSymbolTable.addSymbol(symbols[i]), new Integer(i));
0994: }
0995: /*
0996: fTokenNames.put(new Integer(EXPRTOKEN_OPEN_PAREN), "EXPRTOKEN_OPEN_PAREN");
0997: fTokenNames.put(new Integer(EXPRTOKEN_CLOSE_PAREN), "EXPRTOKEN_CLOSE_PAREN");
0998: fTokenNames.put(new Integer(EXPRTOKEN_OPEN_BRACKET), "EXPRTOKEN_OPEN_BRACKET");
0999: fTokenNames.put(new Integer(EXPRTOKEN_CLOSE_BRACKET), "EXPRTOKEN_CLOSE_BRACKET");
1000: fTokenNames.put(new Integer(EXPRTOKEN_PERIOD), "EXPRTOKEN_PERIOD");
1001: fTokenNames.put(new Integer(EXPRTOKEN_DOUBLE_PERIOD), "EXPRTOKEN_DOUBLE_PERIOD");
1002: fTokenNames.put(new Integer(EXPRTOKEN_ATSIGN), "EXPRTOKEN_ATSIGN");
1003: fTokenNames.put(new Integer(EXPRTOKEN_COMMA), "EXPRTOKEN_COMMA");
1004: fTokenNames.put(new Integer(EXPRTOKEN_DOUBLE_COLON), "EXPRTOKEN_DOUBLE_COLON");
1005: fTokenNames.put(new Integer(EXPRTOKEN_NAMETEST_ANY), "EXPRTOKEN_NAMETEST_ANY");
1006: fTokenNames.put(new Integer(EXPRTOKEN_NAMETEST_NAMESPACE), "EXPRTOKEN_NAMETEST_NAMESPACE");
1007: fTokenNames.put(new Integer(EXPRTOKEN_NAMETEST_QNAME), "EXPRTOKEN_NAMETEST_QNAME");
1008: fTokenNames.put(new Integer(EXPRTOKEN_NODETYPE_COMMENT), "EXPRTOKEN_NODETYPE_COMMENT");
1009: fTokenNames.put(new Integer(EXPRTOKEN_NODETYPE_TEXT), "EXPRTOKEN_NODETYPE_TEXT");
1010: fTokenNames.put(new Integer(EXPRTOKEN_NODETYPE_PI), "EXPRTOKEN_NODETYPE_PI");
1011: fTokenNames.put(new Integer(EXPRTOKEN_NODETYPE_NODE), "EXPRTOKEN_NODETYPE_NODE");
1012: fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_AND), "EXPRTOKEN_OPERATOR_AND");
1013: fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_OR), "EXPRTOKEN_OPERATOR_OR");
1014: fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_MOD), "EXPRTOKEN_OPERATOR_MOD");
1015: fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_DIV), "EXPRTOKEN_OPERATOR_DIV");
1016: fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_MULT), "EXPRTOKEN_OPERATOR_MULT");
1017: fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_SLASH), "EXPRTOKEN_OPERATOR_SLASH");
1018: fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_DOUBLE_SLASH), "EXPRTOKEN_OPERATOR_DOUBLE_SLASH");
1019: fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_UNION), "EXPRTOKEN_OPERATOR_UNION");
1020: fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_PLUS), "EXPRTOKEN_OPERATOR_PLUS");
1021: fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_MINUS), "EXPRTOKEN_OPERATOR_MINUS");
1022: fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_EQUAL), "EXPRTOKEN_OPERATOR_EQUAL");
1023: fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_NOT_EQUAL), "EXPRTOKEN_OPERATOR_NOT_EQUAL");
1024: fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_LESS), "EXPRTOKEN_OPERATOR_LESS");
1025: fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_LESS_EQUAL), "EXPRTOKEN_OPERATOR_LESS_EQUAL");
1026: fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_GREATER), "EXPRTOKEN_OPERATOR_GREATER");
1027: fTokenNames.put(new Integer(EXPRTOKEN_OPERATOR_GREATER_EQUAL), "EXPRTOKEN_OPERATOR_GREATER_EQUAL");
1028: fTokenNames.put(new Integer(EXPRTOKEN_FUNCTION_NAME), "EXPRTOKEN_FUNCTION_NAME");
1029: fTokenNames.put(new Integer(EXPRTOKEN_AXISNAME_ANCESTOR), "EXPRTOKEN_AXISNAME_ANCESTOR");
1030: fTokenNames.put(new Integer(EXPRTOKEN_AXISNAME_ANCESTOR_OR_SELF), "EXPRTOKEN_AXISNAME_ANCESTOR_OR_SELF");
1031: fTokenNames.put(new Integer(EXPRTOKEN_AXISNAME_ATTRIBUTE), "EXPRTOKEN_AXISNAME_ATTRIBUTE");
1032: fTokenNames.put(new Integer(EXPRTOKEN_AXISNAME_CHILD), "EXPRTOKEN_AXISNAME_CHILD");
1033: fTokenNames.put(new Integer(EXPRTOKEN_AXISNAME_DESCENDANT), "EXPRTOKEN_AXISNAME_DESCENDANT");
1034: fTokenNames.put(new Integer(EXPRTOKEN_AXISNAME_DESCENDANT_OR_SELF), "EXPRTOKEN_AXISNAME_DESCENDANT_OR_SELF");
1035: fTokenNames.put(new Integer(EXPRTOKEN_AXISNAME_FOLLOWING), "EXPRTOKEN_AXISNAME_FOLLOWING");
1036: fTokenNames.put(new Integer(EXPRTOKEN_AXISNAME_FOLLOWING_SIBLING), "EXPRTOKEN_AXISNAME_FOLLOWING_SIBLING");
1037: fTokenNames.put(new Integer(EXPRTOKEN_AXISNAME_NAMESPACE), "EXPRTOKEN_AXISNAME_NAMESPACE");
1038: fTokenNames.put(new Integer(EXPRTOKEN_AXISNAME_PARENT), "EXPRTOKEN_AXISNAME_PARENT");
1039: fTokenNames.put(new Integer(EXPRTOKEN_AXISNAME_PRECEDING), "EXPRTOKEN_AXISNAME_PRECEDING");
1040: fTokenNames.put(new Integer(EXPRTOKEN_AXISNAME_PRECEDING_SIBLING), "EXPRTOKEN_AXISNAME_PRECEDING_SIBLING");
1041: fTokenNames.put(new Integer(EXPRTOKEN_AXISNAME_SELF), "EXPRTOKEN_AXISNAME_SELF");
1042: fTokenNames.put(new Integer(EXPRTOKEN_LITERAL), "EXPRTOKEN_LITERAL");
1043: fTokenNames.put(new Integer(EXPRTOKEN_NUMBER), "EXPRTOKEN_NUMBER");
1044: fTokenNames.put(new Integer(EXPRTOKEN_VARIABLE_REFERENCE), "EXPRTOKEN_VARIABLE_REFERENCE");
1045: */
1046: }
1047:
1048: /***/
1049:
1050: //
1051: // Public methods
1052: //
1053: /***
1054: public int addSymbol(byte[] data, int offset, int length, EncodingMap encoding) {
1055: //return fSymbolTable.addSymbol(data, offset, length, encoding);
1056: return fSymbolTable.addSymbol(new String(data, offset, length));
1057: }
1058: /***/
1059:
1060: public String getTokenName(int token) {
1061: if (token < 0 || token >= fgTokenNames.length)
1062: return null;
1063: return fgTokenNames[token];
1064: }
1065:
1066: public int getTokenString(int token) {
1067: return token;
1068: }
1069:
1070: public void addToken(int token) {
1071: try {
1072: fTokens[fTokenCount] = token;
1073: } catch (ArrayIndexOutOfBoundsException ex) {
1074: int[] oldList = fTokens;
1075: fTokens = new int[fTokenCount << 1];
1076: System.arraycopy(oldList, 0, fTokens, 0, fTokenCount);
1077: fTokens[fTokenCount] = token;
1078: }
1079: fTokenCount++;
1080: }
1081:
1082: public int getTokenCount() {
1083: return fTokenCount;
1084: }
1085:
1086: public int getToken(int tokenIndex) {
1087: return fTokens[tokenIndex];
1088: }
1089:
1090: public void dumpTokens() {
1091: //if (DUMP_TOKENS) {
1092: for (int i = 0; i < fTokenCount; i++) {
1093: switch (fTokens[i]) {
1094: case EXPRTOKEN_OPEN_PAREN:
1095: System.out.print("<OPEN_PAREN/>");
1096: break;
1097: case EXPRTOKEN_CLOSE_PAREN:
1098: System.out.print("<CLOSE_PAREN/>");
1099: break;
1100: case EXPRTOKEN_OPEN_BRACKET:
1101: System.out.print("<OPEN_BRACKET/>");
1102: break;
1103: case EXPRTOKEN_CLOSE_BRACKET:
1104: System.out.print("<CLOSE_BRACKET/>");
1105: break;
1106: case EXPRTOKEN_PERIOD:
1107: System.out.print("<PERIOD/>");
1108: break;
1109: case EXPRTOKEN_DOUBLE_PERIOD:
1110: System.out.print("<DOUBLE_PERIOD/>");
1111: break;
1112: case EXPRTOKEN_ATSIGN:
1113: System.out.print("<ATSIGN/>");
1114: break;
1115: case EXPRTOKEN_COMMA:
1116: System.out.print("<COMMA/>");
1117: break;
1118: case EXPRTOKEN_DOUBLE_COLON:
1119: System.out.print("<DOUBLE_COLON/>");
1120: break;
1121: case EXPRTOKEN_NAMETEST_ANY:
1122: System.out.print("<NAMETEST_ANY/>");
1123: break;
1124: case EXPRTOKEN_NAMETEST_NAMESPACE:
1125: System.out.print("<NAMETEST_NAMESPACE");
1126: /***
1127: System.out.print(" prefix=\"" + fSymbolTable.toString(fTokens[++i]) + "\"");
1128: /***/
1129: System.out.print(" prefix=\""
1130: + getTokenString(fTokens[++i]) + "\"");
1131: /***/
1132: System.out.print("/>");
1133: break;
1134: case EXPRTOKEN_NAMETEST_QNAME:
1135: System.out.print("<NAMETEST_QNAME");
1136: if (fTokens[++i] != -1)
1137: /***
1138: System.out.print(" prefix=\"" + fSymbolTable.toString(fTokens[i]) + "\"");
1139: /***/
1140: System.out.print(" prefix=\""
1141: + getTokenString(fTokens[i]) + "\"");
1142: /***/
1143: /***
1144: System.out.print(" localpart=\"" + fSymbolTable.toString(fTokens[++i]) + "\"");
1145: /***/
1146: System.out.print(" localpart=\""
1147: + getTokenString(fTokens[++i]) + "\"");
1148: /***/
1149: System.out.print("/>");
1150: break;
1151: case EXPRTOKEN_NODETYPE_COMMENT:
1152: System.out.print("<NODETYPE_COMMENT/>");
1153: break;
1154: case EXPRTOKEN_NODETYPE_TEXT:
1155: System.out.print("<NODETYPE_TEXT/>");
1156: break;
1157: case EXPRTOKEN_NODETYPE_PI:
1158: System.out.print("<NODETYPE_PI/>");
1159: break;
1160: case EXPRTOKEN_NODETYPE_NODE:
1161: System.out.print("<NODETYPE_NODE/>");
1162: break;
1163: case EXPRTOKEN_OPERATOR_AND:
1164: System.out.print("<OPERATOR_AND/>");
1165: break;
1166: case EXPRTOKEN_OPERATOR_OR:
1167: System.out.print("<OPERATOR_OR/>");
1168: break;
1169: case EXPRTOKEN_OPERATOR_MOD:
1170: System.out.print("<OPERATOR_MOD/>");
1171: break;
1172: case EXPRTOKEN_OPERATOR_DIV:
1173: System.out.print("<OPERATOR_DIV/>");
1174: break;
1175: case EXPRTOKEN_OPERATOR_MULT:
1176: System.out.print("<OPERATOR_MULT/>");
1177: break;
1178: case EXPRTOKEN_OPERATOR_SLASH:
1179: System.out.print("<OPERATOR_SLASH/>");
1180: if (i + 1 < fTokenCount) {
1181: System.out.println();
1182: System.out.print(" ");
1183: }
1184: break;
1185: case EXPRTOKEN_OPERATOR_DOUBLE_SLASH:
1186: System.out.print("<OPERATOR_DOUBLE_SLASH/>");
1187: break;
1188: case EXPRTOKEN_OPERATOR_UNION:
1189: System.out.print("<OPERATOR_UNION/>");
1190: break;
1191: case EXPRTOKEN_OPERATOR_PLUS:
1192: System.out.print("<OPERATOR_PLUS/>");
1193: break;
1194: case EXPRTOKEN_OPERATOR_MINUS:
1195: System.out.print("<OPERATOR_MINUS/>");
1196: break;
1197: case EXPRTOKEN_OPERATOR_EQUAL:
1198: System.out.print("<OPERATOR_EQUAL/>");
1199: break;
1200: case EXPRTOKEN_OPERATOR_NOT_EQUAL:
1201: System.out.print("<OPERATOR_NOT_EQUAL/>");
1202: break;
1203: case EXPRTOKEN_OPERATOR_LESS:
1204: System.out.print("<OPERATOR_LESS/>");
1205: break;
1206: case EXPRTOKEN_OPERATOR_LESS_EQUAL:
1207: System.out.print("<OPERATOR_LESS_EQUAL/>");
1208: break;
1209: case EXPRTOKEN_OPERATOR_GREATER:
1210: System.out.print("<OPERATOR_GREATER/>");
1211: break;
1212: case EXPRTOKEN_OPERATOR_GREATER_EQUAL:
1213: System.out.print("<OPERATOR_GREATER_EQUAL/>");
1214: break;
1215: case EXPRTOKEN_FUNCTION_NAME:
1216: System.out.print("<FUNCTION_NAME");
1217: if (fTokens[++i] != -1)
1218: /***
1219: System.out.print(" prefix=\"" + fSymbolTable.toString(fTokens[i]) + "\"");
1220: /***/
1221: System.out.print(" prefix=\""
1222: + getTokenString(fTokens[i]) + "\"");
1223: /***/
1224: /***
1225: System.out.print(" localpart=\"" + fSymbolTable.toString(fTokens[++i]) + "\"");
1226: /***/
1227: System.out.print(" localpart=\""
1228: + getTokenString(fTokens[++i]) + "\"");
1229: /***/
1230: System.out.print("/>");
1231: break;
1232: case EXPRTOKEN_AXISNAME_ANCESTOR:
1233: System.out.print("<AXISNAME_ANCESTOR/>");
1234: break;
1235: case EXPRTOKEN_AXISNAME_ANCESTOR_OR_SELF:
1236: System.out.print("<AXISNAME_ANCESTOR_OR_SELF/>");
1237: break;
1238: case EXPRTOKEN_AXISNAME_ATTRIBUTE:
1239: System.out.print("<AXISNAME_ATTRIBUTE/>");
1240: break;
1241: case EXPRTOKEN_AXISNAME_CHILD:
1242: System.out.print("<AXISNAME_CHILD/>");
1243: break;
1244: case EXPRTOKEN_AXISNAME_DESCENDANT:
1245: System.out.print("<AXISNAME_DESCENDANT/>");
1246: break;
1247: case EXPRTOKEN_AXISNAME_DESCENDANT_OR_SELF:
1248: System.out.print("<AXISNAME_DESCENDANT_OR_SELF/>");
1249: break;
1250: case EXPRTOKEN_AXISNAME_FOLLOWING:
1251: System.out.print("<AXISNAME_FOLLOWING/>");
1252: break;
1253: case EXPRTOKEN_AXISNAME_FOLLOWING_SIBLING:
1254: System.out.print("<AXISNAME_FOLLOWING_SIBLING/>");
1255: break;
1256: case EXPRTOKEN_AXISNAME_NAMESPACE:
1257: System.out.print("<AXISNAME_NAMESPACE/>");
1258: break;
1259: case EXPRTOKEN_AXISNAME_PARENT:
1260: System.out.print("<AXISNAME_PARENT/>");
1261: break;
1262: case EXPRTOKEN_AXISNAME_PRECEDING:
1263: System.out.print("<AXISNAME_PRECEDING/>");
1264: break;
1265: case EXPRTOKEN_AXISNAME_PRECEDING_SIBLING:
1266: System.out.print("<AXISNAME_PRECEDING_SIBLING/>");
1267: break;
1268: case EXPRTOKEN_AXISNAME_SELF:
1269: System.out.print("<AXISNAME_SELF/>");
1270: break;
1271: case EXPRTOKEN_LITERAL:
1272: System.out.print("<LITERAL");
1273: /***
1274: System.out.print(" value=\"" + fSymbolTable.toString(fTokens[++i]) + "\"");
1275: /***/
1276: System.out.print(" value=\""
1277: + getTokenString(fTokens[++i]) + "\"");
1278: /***/
1279: System.out.print("/>");
1280: break;
1281: case EXPRTOKEN_NUMBER:
1282: System.out.print("<NUMBER");
1283: System.out.print(" whole=\""
1284: + getTokenString(fTokens[++i]) + "\"");
1285: System.out.print(" part=\""
1286: + getTokenString(fTokens[++i]) + "\"");
1287: System.out.print("/>");
1288: break;
1289: case EXPRTOKEN_VARIABLE_REFERENCE:
1290: System.out.print("<VARIABLE_REFERENCE");
1291: if (fTokens[++i] != -1)
1292: /***
1293: System.out.print(" prefix=\"" + fSymbolTable.toString(fTokens[i]) + "\"");
1294: /***/
1295: System.out.print(" prefix=\""
1296: + getTokenString(fTokens[i]) + "\"");
1297: /***/
1298: /***
1299: System.out.print(" localpart=\"" + fSymbolTable.toString(fTokens[++i]) + "\"");
1300: /***/
1301: System.out.print(" localpart=\""
1302: + getTokenString(fTokens[++i]) + "\"");
1303: /***/
1304: System.out.print("/>");
1305: break;
1306: default:
1307: System.out.println("<???/>");
1308: }
1309: }
1310: System.out.println();
1311: //}
1312: }
1313:
1314: } // class Tokens
1315:
1316: /**
1317: * @author Glenn Marcy, IBM
1318: * @author Andy Clark, IBM
1319: *
1320: * @version $Id: XPath.java,v 1.10 2001/06/08 14:23:49 sandygao Exp $
1321: */
1322: private static class Scanner {
1323:
1324: /**
1325: * 7-bit ASCII subset
1326: *
1327: * 0 1 2 3 4 5 6 7 8 9 A B C D E F
1328: * 0, 0, 0, 0, 0, 0, 0, 0, 0, HT, LF, 0, 0, CR, 0, 0, // 0
1329: * 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1
1330: * SP, !, ", #, $, %, &, ', (, ), *, +, ,, -, ., /, // 2
1331: * 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, :, ;, <, =, >, ?, // 3
1332: * @, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, // 4
1333: * P, Q, R, S, T, U, V, W, X, Y, Z, [, \, ], ^, _, // 5
1334: * `, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, // 6
1335: * p, q, r, s, t, u, v, w, x, y, z, {, |, }, ~, DEL // 7
1336: */
1337: private static final byte CHARTYPE_INVALID = 0, // invalid XML character
1338: CHARTYPE_OTHER = 1, // not special - one of "#%&;?\^`{}~" or DEL
1339: CHARTYPE_WHITESPACE = 2, // one of "\t\n\r " (0x09, 0x0A, 0x0D, 0x20)
1340: CHARTYPE_EXCLAMATION = 3, // '!' (0x21)
1341: CHARTYPE_QUOTE = 4, // '\"' or '\'' (0x22 and 0x27)
1342: CHARTYPE_DOLLAR = 5, // '$' (0x24)
1343: CHARTYPE_OPEN_PAREN = 6, // '(' (0x28)
1344: CHARTYPE_CLOSE_PAREN = 7, // ')' (0x29)
1345: CHARTYPE_STAR = 8, // '*' (0x2A)
1346: CHARTYPE_PLUS = 9, // '+' (0x2B)
1347: CHARTYPE_COMMA = 10, // ',' (0x2C)
1348: CHARTYPE_MINUS = 11, // '-' (0x2D)
1349: CHARTYPE_PERIOD = 12, // '.' (0x2E)
1350: CHARTYPE_SLASH = 13, // '/' (0x2F)
1351: CHARTYPE_DIGIT = 14, // '0'-'9' (0x30 to 0x39)
1352: CHARTYPE_COLON = 15, // ':' (0x3A)
1353: CHARTYPE_LESS = 16, // '<' (0x3C)
1354: CHARTYPE_EQUAL = 17, // '=' (0x3D)
1355: CHARTYPE_GREATER = 18, // '>' (0x3E)
1356: CHARTYPE_ATSIGN = 19, // '@' (0x40)
1357: CHARTYPE_LETTER = 20, // 'A'-'Z' or 'a'-'z' (0x41 to 0x5A and 0x61 to 0x7A)
1358: CHARTYPE_OPEN_BRACKET = 21, // '[' (0x5B)
1359: CHARTYPE_CLOSE_BRACKET = 22, // ']' (0x5D)
1360: CHARTYPE_UNDERSCORE = 23, // '_' (0x5F)
1361: CHARTYPE_UNION = 24, // '|' (0x7C)
1362: CHARTYPE_NONASCII = 25; // Non-ASCII Unicode codepoint (>= 0x80)
1363:
1364: private static byte[] fASCIICharMap = { 0, 0, 0, 0, 0, 0, 0, 0,
1365: 0, 2, 2, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1366: 0, 0, 0, 0, 0, 0, 2, 3, 4, 1, 5, 1, 1, 4, 6, 7, 8, 9,
1367: 10, 11, 12, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
1368: 15, 1, 16, 17, 18, 1, 19, 20, 20, 20, 20, 20, 20, 20,
1369: 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
1370: 20, 20, 20, 20, 20, 21, 1, 22, 1, 23, 1, 20, 20, 20,
1371: 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
1372: 20, 20, 20, 20, 20, 20, 20, 20, 20, 1, 24, 1, 1, 1 };
1373:
1374: /**
1375: * Symbol literals
1376: */
1377: /***
1378: private static int fgAndSymbol = -1; // 'and'
1379: private static int fgOrSymbol = -1; // 'or'
1380: private static int fgModSymbol = -1; // 'mod'
1381: private static int fgDivSymbol = -1; // 'div'
1382:
1383: private static int fgCommentSymbol = -1; // 'comment'
1384: private static int fgTextSymbol = -1; // 'text'
1385: private static int fgPISymbol = -1; // 'processing-instruction'
1386: private static int fgNodeSymbol = -1; // 'node'
1387:
1388: private static int fgAncestorSymbol = -1; // 'ancestor'
1389: private static int fgAncestorOrSelfSymbol = -1; // 'ancestor-or-self'
1390: private static int fgAttributeSymbol = -1; // 'attribute'
1391: private static int fgChildSymbol = -1; // 'child'
1392: private static int fgDescendantSymbol = -1; // 'descendant'
1393: private static int fgDescendantOrSelfSymbol = -1; // 'descendant-or-self'
1394: private static int fgFollowingSymbol = -1; // 'following'
1395: private static int fgFollowingSiblingSymbol = -1; // 'following-sibling'
1396: private static int fgNamespaceSymbol = -1; // 'namespace'
1397: private static int fgParentSymbol = -1; // 'parent'
1398: private static int fgPrecedingSymbol = -1; // 'preceding'
1399: private static int fgPrecedingSiblingSymbol = -1; // 'preceding-sibling'
1400: private static int fgSelfSymbol = -1; // 'self'
1401:
1402: private static SymbolTable fgSymbolTable = new SymbolTable();
1403:
1404: static {
1405: fgAndSymbol = fgSymbolTable.addSymbol("and");
1406: fgOrSymbol = fgSymbolTable.addSymbol("or");
1407: fgModSymbol = fgSymbolTable.addSymbol("mod");
1408: fgDivSymbol = fgSymbolTable.addSymbol("div");
1409: fgCommentSymbol = fgSymbolTable.addSymbol("comment");
1410: fgTextSymbol = fgSymbolTable.addSymbol("text");
1411: fgPISymbol = fgSymbolTable.addSymbol("processing-instruction");
1412: fgNodeSymbol = fgSymbolTable.addSymbol("node");
1413: fgAncestorSymbol = fgSymbolTable.addSymbol("ancestor");
1414: fgAncestorOrSelfSymbol = fgSymbolTable.addSymbol("ancestor-or-self");
1415: fgAttributeSymbol = fgSymbolTable.addSymbol("attribute");
1416: fgChildSymbol = fgSymbolTable.addSymbol("child");
1417: fgDescendantSymbol = fgSymbolTable.addSymbol("descendant");
1418: fgDescendantOrSelfSymbol = fgSymbolTable.addSymbol("descendant-or-self");
1419: fgFollowingSymbol = fgSymbolTable.addSymbol("following");
1420: fgFollowingSiblingSymbol = fgSymbolTable.addSymbol("following-sibling");
1421: fgNamespaceSymbol = fgSymbolTable.addSymbol("namespace");
1422: fgParentSymbol = fgSymbolTable.addSymbol("parent");
1423: fgPrecedingSymbol = fgSymbolTable.addSymbol("preceding");
1424: fgPrecedingSiblingSymbol = fgSymbolTable.addSymbol("preceding-sibling");
1425: fgSelfSymbol = fgSymbolTable.addSymbol("self");
1426: }
1427: /***/
1428:
1429: //
1430: // Data
1431: //
1432: /** String pool. */
1433: private StringPool fStringPool;
1434:
1435: // symbols
1436:
1437: private int fAndSymbol;
1438: private int fOrSymbol;
1439: private int fModSymbol;
1440: private int fDivSymbol;
1441:
1442: private int fCommentSymbol;
1443: private int fTextSymbol;
1444: private int fPISymbol;
1445: private int fNodeSymbol;
1446:
1447: private int fAncestorSymbol;
1448: private int fAncestorOrSelfSymbol;
1449: private int fAttributeSymbol;
1450: private int fChildSymbol;
1451: private int fDescendantSymbol;
1452: private int fDescendantOrSelfSymbol;
1453: private int fFollowingSymbol;
1454: private int fFollowingSiblingSymbol;
1455: private int fNamespaceSymbol;
1456: private int fParentSymbol;
1457: private int fPrecedingSymbol;
1458: private int fPrecedingSiblingSymbol;
1459: private int fSelfSymbol;
1460:
1461: //
1462: // Constructors
1463: //
1464:
1465: /** Constructs an XPath expression scanner. */
1466: public Scanner(StringPool stringPool) {
1467:
1468: // save pool and tokens
1469: fStringPool = stringPool;
1470:
1471: // create symbols
1472: fAndSymbol = fStringPool.addSymbol("and");
1473: fOrSymbol = fStringPool.addSymbol("or");
1474: fModSymbol = fStringPool.addSymbol("mod");
1475: fDivSymbol = fStringPool.addSymbol("div");
1476: fCommentSymbol = fStringPool.addSymbol("comment");
1477: fTextSymbol = fStringPool.addSymbol("text");
1478: fPISymbol = fStringPool.addSymbol("processing-instruction");
1479: fNodeSymbol = fStringPool.addSymbol("node");
1480: fAncestorSymbol = fStringPool.addSymbol("ancestor");
1481: fAncestorOrSelfSymbol = fStringPool
1482: .addSymbol("ancestor-or-self");
1483: fAttributeSymbol = fStringPool.addSymbol("attribute");
1484: fChildSymbol = fStringPool.addSymbol("child");
1485: fDescendantSymbol = fStringPool.addSymbol("descendant");
1486: fDescendantOrSelfSymbol = fStringPool
1487: .addSymbol("descendant-or-self");
1488: fFollowingSymbol = fStringPool.addSymbol("following");
1489: fFollowingSiblingSymbol = fStringPool
1490: .addSymbol("following-sibling");
1491: fNamespaceSymbol = fStringPool.addSymbol("namespace");
1492: fParentSymbol = fStringPool.addSymbol("parent");
1493: fPrecedingSymbol = fStringPool.addSymbol("preceding");
1494: fPrecedingSiblingSymbol = fStringPool
1495: .addSymbol("preceding-sibling");
1496: fSelfSymbol = fStringPool.addSymbol("self");
1497:
1498: } // <init>(StringPool)
1499:
1500: /**
1501: *
1502: */
1503: public boolean scanExpr(StringPool stringPool,
1504: XPath.Tokens tokens, String data, int currentOffset,
1505: int endOffset) throws XPathException {
1506:
1507: int nameOffset;
1508: int nameHandle, prefixHandle;
1509: boolean starIsMultiplyOperator = false;
1510: int ch;
1511:
1512: /***
1513: if (XPath.Tokens.DUMP_TOKENS) {
1514: System.out.println(" <test>");
1515: System.out.println(" <expression>");
1516: System.out.println(" " + encoding.createString(data, currentOffset, endOffset - currentOffset));
1517: System.out.println(" </expression>");
1518: }
1519: /***/
1520: while (true) {
1521: if (currentOffset == endOffset) {
1522: break;
1523: }
1524: /***
1525: ch = (data[currentOffset] & 0xFF);
1526: /***/
1527: ch = data.charAt(currentOffset);
1528: /***/
1529: //
1530: // [39] ExprWhitespace ::= S
1531: //
1532: while (ch == ' ' || ch == 0x0A || ch == 0x09
1533: || ch == 0x0D) {
1534: if (++currentOffset == endOffset) {
1535: break;
1536: }
1537: /***
1538: ch = (data[currentOffset] & 0xFF);
1539: /***/
1540: ch = data.charAt(currentOffset);
1541: /***/
1542: }
1543: if (currentOffset == endOffset) {
1544: break;
1545: }
1546: //
1547: // [28] ExprToken ::= '(' | ')' | '[' | ']' | '.' | '..' | '@' | ',' | '::'
1548: // | NameTest | NodeType | Operator | FunctionName
1549: // | AxisName | Literal | Number | VariableReference
1550: //
1551: byte chartype = (ch >= 0x80) ? CHARTYPE_NONASCII
1552: : fASCIICharMap[ch];
1553: switch (chartype) {
1554: case CHARTYPE_OPEN_PAREN: // '('
1555: addToken(tokens, XPath.Tokens.EXPRTOKEN_OPEN_PAREN);
1556: starIsMultiplyOperator = false;
1557: if (++currentOffset == endOffset) {
1558: break;
1559: }
1560: break;
1561: case CHARTYPE_CLOSE_PAREN: // ')'
1562: addToken(tokens, XPath.Tokens.EXPRTOKEN_CLOSE_PAREN);
1563: starIsMultiplyOperator = true;
1564: if (++currentOffset == endOffset) {
1565: break;
1566: }
1567: break;
1568: case CHARTYPE_OPEN_BRACKET: // '['
1569: addToken(tokens,
1570: XPath.Tokens.EXPRTOKEN_OPEN_BRACKET);
1571: starIsMultiplyOperator = false;
1572: if (++currentOffset == endOffset) {
1573: break;
1574: }
1575: break;
1576: case CHARTYPE_CLOSE_BRACKET: // ']'
1577: addToken(tokens,
1578: XPath.Tokens.EXPRTOKEN_CLOSE_BRACKET);
1579: starIsMultiplyOperator = true;
1580: if (++currentOffset == endOffset) {
1581: break;
1582: }
1583: break;
1584: //
1585: // [30] Number ::= Digits ('.' Digits?)? | '.' Digits
1586: // ^^^^^^^^^^
1587: //
1588: case CHARTYPE_PERIOD: // '.', '..' or '.' Digits
1589: if (currentOffset + 1 == endOffset) {
1590: addToken(tokens, XPath.Tokens.EXPRTOKEN_PERIOD);
1591: starIsMultiplyOperator = true;
1592: currentOffset++;
1593: break;
1594: }
1595: /***
1596: ch = (data[currentOffset + 1] & 0xFF);
1597: /***/
1598: ch = data.charAt(currentOffset + 1);
1599: /***/
1600: if (ch == '.') { // '..'
1601: addToken(tokens,
1602: XPath.Tokens.EXPRTOKEN_DOUBLE_PERIOD);
1603: starIsMultiplyOperator = true;
1604: currentOffset += 2;
1605: } else if (ch >= '0' && ch <= '9') {
1606: addToken(tokens, XPath.Tokens.EXPRTOKEN_NUMBER);
1607: starIsMultiplyOperator = true;
1608: currentOffset = scanNumber(tokens, data,
1609: endOffset, currentOffset/*, encoding*/);
1610: } else if (ch == '/') {
1611: addToken(tokens, XPath.Tokens.EXPRTOKEN_PERIOD);
1612: starIsMultiplyOperator = true;
1613: currentOffset++;
1614: } else { // '.'
1615: throw new XPathException(
1616: "Invalid character following '.'");
1617: }
1618: if (currentOffset == endOffset) {
1619: break;
1620: }
1621: break;
1622: case CHARTYPE_ATSIGN: // '@'
1623: addToken(tokens, XPath.Tokens.EXPRTOKEN_ATSIGN);
1624: starIsMultiplyOperator = false;
1625: if (++currentOffset == endOffset) {
1626: break;
1627: }
1628: break;
1629: case CHARTYPE_COMMA: // ','
1630: addToken(tokens, XPath.Tokens.EXPRTOKEN_COMMA);
1631: starIsMultiplyOperator = false;
1632: if (++currentOffset == endOffset) {
1633: break;
1634: }
1635: break;
1636: case CHARTYPE_COLON: // '::'
1637: if (++currentOffset == endOffset) {
1638: // System.out.println("abort 1a");
1639: return false; // REVISIT
1640: }
1641: /***
1642: ch = (data[currentOffset] & 0xFF);
1643: /***/
1644: ch = data.charAt(currentOffset);
1645: /***/
1646: if (ch != ':') {
1647: // System.out.println("abort 1b");
1648: return false; // REVISIT
1649: }
1650: addToken(tokens,
1651: XPath.Tokens.EXPRTOKEN_DOUBLE_COLON);
1652: starIsMultiplyOperator = false;
1653: if (++currentOffset == endOffset) {
1654: break;
1655: }
1656: break;
1657: case CHARTYPE_SLASH: // '/' and '//'
1658: if (++currentOffset == endOffset) {
1659: addToken(tokens,
1660: XPath.Tokens.EXPRTOKEN_OPERATOR_SLASH);
1661: starIsMultiplyOperator = false;
1662: break;
1663: }
1664: /***
1665: ch = (data[currentOffset] & 0xFF);
1666: /***/
1667: ch = data.charAt(currentOffset);
1668: /***/
1669: if (ch == '/') { // '//'
1670: addToken(
1671: tokens,
1672: XPath.Tokens.EXPRTOKEN_OPERATOR_DOUBLE_SLASH);
1673: starIsMultiplyOperator = false;
1674: if (++currentOffset == endOffset) {
1675: break;
1676: }
1677: } else {
1678: addToken(tokens,
1679: XPath.Tokens.EXPRTOKEN_OPERATOR_SLASH);
1680: starIsMultiplyOperator = false;
1681: }
1682: break;
1683: case CHARTYPE_UNION: // '|'
1684: addToken(tokens,
1685: XPath.Tokens.EXPRTOKEN_OPERATOR_UNION);
1686: starIsMultiplyOperator = false;
1687: if (++currentOffset == endOffset) {
1688: break;
1689: }
1690: break;
1691: case CHARTYPE_PLUS: // '+'
1692: addToken(tokens,
1693: XPath.Tokens.EXPRTOKEN_OPERATOR_PLUS);
1694: starIsMultiplyOperator = false;
1695: if (++currentOffset == endOffset) {
1696: break;
1697: }
1698: break;
1699: case CHARTYPE_MINUS: // '-'
1700: addToken(tokens,
1701: XPath.Tokens.EXPRTOKEN_OPERATOR_MINUS);
1702: starIsMultiplyOperator = false;
1703: if (++currentOffset == endOffset) {
1704: break;
1705: }
1706: break;
1707: case CHARTYPE_EQUAL: // '='
1708: addToken(tokens,
1709: XPath.Tokens.EXPRTOKEN_OPERATOR_EQUAL);
1710: starIsMultiplyOperator = false;
1711: if (++currentOffset == endOffset) {
1712: break;
1713: }
1714: break;
1715: case CHARTYPE_EXCLAMATION: // '!='
1716: if (++currentOffset == endOffset) {
1717: // System.out.println("abort 2a");
1718: return false; // REVISIT
1719: }
1720: /***
1721: ch = (data[currentOffset] & 0xFF);
1722: /***/
1723: ch = data.charAt(currentOffset);
1724: /***/
1725: if (ch != '=') {
1726: // System.out.println("abort 2b");
1727: return false; // REVISIT
1728: }
1729: addToken(tokens,
1730: XPath.Tokens.EXPRTOKEN_OPERATOR_NOT_EQUAL);
1731: starIsMultiplyOperator = false;
1732: if (++currentOffset == endOffset) {
1733: break;
1734: }
1735: break;
1736: case CHARTYPE_LESS: // '<' and '<='
1737: if (++currentOffset == endOffset) {
1738: addToken(tokens,
1739: XPath.Tokens.EXPRTOKEN_OPERATOR_LESS);
1740: starIsMultiplyOperator = false;
1741: break;
1742: }
1743: /***
1744: ch = (data[currentOffset] & 0xFF);
1745: /***/
1746: ch = data.charAt(currentOffset);
1747: /***/
1748: if (ch == '=') { // '<='
1749: addToken(
1750: tokens,
1751: XPath.Tokens.EXPRTOKEN_OPERATOR_LESS_EQUAL);
1752: starIsMultiplyOperator = false;
1753: if (++currentOffset == endOffset) {
1754: break;
1755: }
1756: } else {
1757: addToken(tokens,
1758: XPath.Tokens.EXPRTOKEN_OPERATOR_LESS);
1759: starIsMultiplyOperator = false;
1760: }
1761: break;
1762: case CHARTYPE_GREATER: // '>' and '>='
1763: if (++currentOffset == endOffset) {
1764: addToken(tokens,
1765: XPath.Tokens.EXPRTOKEN_OPERATOR_GREATER);
1766: starIsMultiplyOperator = false;
1767: break;
1768: }
1769: /***
1770: ch = (data[currentOffset] & 0xFF);
1771: /***/
1772: ch = data.charAt(currentOffset);
1773: /***/
1774: if (ch == '=') { // '>='
1775: addToken(
1776: tokens,
1777: XPath.Tokens.EXPRTOKEN_OPERATOR_GREATER_EQUAL);
1778: starIsMultiplyOperator = false;
1779: if (++currentOffset == endOffset) {
1780: break;
1781: }
1782: } else {
1783: addToken(tokens,
1784: XPath.Tokens.EXPRTOKEN_OPERATOR_GREATER);
1785: starIsMultiplyOperator = false;
1786: }
1787: break;
1788: //
1789: // [29] Literal ::= '"' [^"]* '"' | "'" [^']* "'"
1790: //
1791: case CHARTYPE_QUOTE: // '\"' or '\''
1792: int qchar = ch;
1793: if (++currentOffset == endOffset) {
1794: // System.out.println("abort 2c");
1795: return false; // REVISIT
1796: }
1797: /***
1798: ch = (data[currentOffset] & 0xFF);
1799: /***/
1800: ch = data.charAt(currentOffset);
1801: /***/
1802: int litOffset = currentOffset;
1803: while (ch != qchar) {
1804: if (++currentOffset == endOffset) {
1805: // System.out.println("abort 2d");
1806: return false; // REVISIT
1807: }
1808: /***
1809: ch = (data[currentOffset] & 0xFF);
1810: /***/
1811: ch = data.charAt(currentOffset);
1812: /***/
1813: }
1814: int litLength = currentOffset - litOffset;
1815: addToken(tokens, XPath.Tokens.EXPRTOKEN_LITERAL);
1816: starIsMultiplyOperator = true;
1817: /***
1818: addToken(tokens, tokens.addSymbol(data, litOffset, litLength, encoding));
1819: /***/
1820: tokens.addToken(stringPool
1821: .addSymbol(data.substring(litOffset,
1822: litOffset + litLength)));
1823: /***/
1824: if (++currentOffset == endOffset) {
1825: break;
1826: }
1827: break;
1828: //
1829: // [30] Number ::= Digits ('.' Digits?)? | '.' Digits
1830: // [31] Digits ::= [0-9]+
1831: //
1832: case CHARTYPE_DIGIT:
1833: addToken(tokens, XPath.Tokens.EXPRTOKEN_NUMBER);
1834: starIsMultiplyOperator = true;
1835: currentOffset = scanNumber(tokens, data, endOffset,
1836: currentOffset/*, encoding*/);
1837: break;
1838: //
1839: // [36] VariableReference ::= '$' QName
1840: //
1841: case CHARTYPE_DOLLAR:
1842: if (++currentOffset == endOffset) {
1843: // System.out.println("abort 3a");
1844: return false; // REVISIT
1845: }
1846: nameOffset = currentOffset;
1847: currentOffset = scanNCName(data, endOffset,
1848: currentOffset);
1849: if (currentOffset == nameOffset) {
1850: // System.out.println("abort 3b");
1851: return false; // REVISIT
1852: }
1853: if (currentOffset < endOffset) {
1854: ch = data.charAt(currentOffset);
1855: } else {
1856: ch = -1;
1857: }
1858: /***
1859: nameHandle = tokens.addSymbol(data, nameOffset, currentOffset - nameOffset, encoding);
1860: /***/
1861: nameHandle = stringPool.addSymbol(data.substring(
1862: nameOffset, currentOffset));
1863: /***/
1864: if (ch != ':') {
1865: prefixHandle = -1;
1866: } else {
1867: prefixHandle = nameHandle;
1868: if (++currentOffset == endOffset) {
1869: // System.out.println("abort 4a");
1870: return false; // REVISIT
1871: }
1872: nameOffset = currentOffset;
1873: currentOffset = scanNCName(data, endOffset,
1874: currentOffset);
1875: if (currentOffset == nameOffset) {
1876: // System.out.println("abort 4b");
1877: return false; // REVISIT
1878: }
1879: if (currentOffset < endOffset) {
1880: ch = data.charAt(currentOffset);
1881: } else {
1882: ch = -1;
1883: }
1884: /***
1885: nameHandle = tokens.addSymbol(data, nameOffset, currentOffset - nameOffset, encoding);
1886: /***/
1887: nameHandle = stringPool.addSymbol(data
1888: .substring(nameOffset, currentOffset));
1889: /***/
1890: }
1891: addToken(tokens,
1892: XPath.Tokens.EXPRTOKEN_VARIABLE_REFERENCE);
1893: starIsMultiplyOperator = true;
1894: tokens.addToken(prefixHandle);
1895: tokens.addToken(nameHandle);
1896: break;
1897: //
1898: // [37] NameTest ::= '*' | NCName ':' '*' | QName
1899: // [34] MultiplyOperator ::= '*'
1900: //
1901: case CHARTYPE_STAR: // '*'
1902: //
1903: // 3.7 Lexical Structure
1904: //
1905: // If there is a preceding token and the preceding token is not one of @, ::, (, [, , or
1906: // an Operator, then a * must be recognized as a MultiplyOperator.
1907: //
1908: // Otherwise, the token must not be recognized as a MultiplyOperator.
1909: //
1910: if (starIsMultiplyOperator) {
1911: addToken(tokens,
1912: XPath.Tokens.EXPRTOKEN_OPERATOR_MULT);
1913: starIsMultiplyOperator = false;
1914: } else {
1915: addToken(tokens,
1916: XPath.Tokens.EXPRTOKEN_NAMETEST_ANY);
1917: starIsMultiplyOperator = true;
1918: }
1919: if (++currentOffset == endOffset) {
1920: break;
1921: }
1922: break;
1923: //
1924: // NCName, QName and non-terminals
1925: //
1926: case CHARTYPE_NONASCII: // possibly a valid non-ascii 'Letter' (BaseChar | Ideographic)
1927: case CHARTYPE_LETTER:
1928: case CHARTYPE_UNDERSCORE:
1929: //
1930: // 3.7 Lexical Structure
1931: //
1932: // If there is a preceding token and the preceding token is not one of @, ::, (, [, , or
1933: // an Operator, then an NCName must be recognized as an OperatorName.
1934: //
1935: // If the character following an NCName (possibly after intervening ExprWhitespace) is (,
1936: // then the token must be recognized as a NodeType or a FunctionName.
1937: //
1938: // If the two characters following an NCName (possibly after intervening ExprWhitespace)
1939: // are ::, then the token must be recognized as an AxisName.
1940: //
1941: // Otherwise, the token must not be recognized as an OperatorName, a NodeType, a
1942: // FunctionName, or an AxisName.
1943: //
1944: // [33] OperatorName ::= 'and' | 'or' | 'mod' | 'div'
1945: // [38] NodeType ::= 'comment' | 'text' | 'processing-instruction' | 'node'
1946: // [35] FunctionName ::= QName - NodeType
1947: // [6] AxisName ::= (see above)
1948: //
1949: // [37] NameTest ::= '*' | NCName ':' '*' | QName
1950: // [5] NCName ::= (Letter | '_') (NCNameChar)*
1951: // [?] NCNameChar ::= Letter | Digit | '.' | '-' | '_' (ascii subset of 'NCNameChar')
1952: // [?] QName ::= (NCName ':')? NCName
1953: // [?] Letter ::= [A-Za-z] (ascii subset of 'Letter')
1954: // [?] Digit ::= [0-9] (ascii subset of 'Digit')
1955: //
1956: nameOffset = currentOffset;
1957: currentOffset = scanNCName(data, endOffset,
1958: currentOffset);
1959: if (currentOffset == nameOffset) {
1960: // System.out.println("abort 4c");
1961: return false; // REVISIT
1962: }
1963: if (currentOffset < endOffset) {
1964: ch = data.charAt(currentOffset);
1965: } else {
1966: ch = -1;
1967: }
1968: /***
1969: nameHandle = tokens.addSymbol(data, nameOffset, currentOffset - nameOffset, encoding);
1970: /***/
1971: nameHandle = stringPool.addSymbol(data.substring(
1972: nameOffset, currentOffset));
1973: /***/
1974: boolean isNameTestNCName = false;
1975: boolean isAxisName = false;
1976: prefixHandle = -1;
1977: if (ch == ':') {
1978: if (++currentOffset == endOffset) {
1979: // System.out.println("abort 5");
1980: return false; // REVISIT
1981: }
1982: /***
1983: ch = (data[currentOffset] & 0xFF);
1984: /***/
1985: ch = data.charAt(currentOffset);
1986: /***/
1987: if (ch == '*') {
1988: if (++currentOffset < endOffset) {
1989: /***
1990: ch = (data[currentOffset] & 0xFF);
1991: /***/
1992: ch = data.charAt(currentOffset);
1993: /***/
1994: }
1995: isNameTestNCName = true;
1996: } else if (ch == ':') {
1997: if (++currentOffset < endOffset) {
1998: /***
1999: ch = (data[currentOffset] & 0xFF);
2000: /***/
2001: ch = data.charAt(currentOffset);
2002: /***/
2003: }
2004: isAxisName = true;
2005: } else {
2006: prefixHandle = nameHandle;
2007: nameOffset = currentOffset;
2008: currentOffset = scanNCName(data, endOffset,
2009: currentOffset);
2010: if (currentOffset == nameOffset) {
2011: // System.out.println("abort 5b");
2012: return false; // REVISIT
2013: }
2014: if (currentOffset < endOffset) {
2015: ch = data.charAt(currentOffset);
2016: } else {
2017: ch = -1;
2018: }
2019: /***
2020: nameHandle = tokens.addSymbol(data, nameOffset, currentOffset - nameOffset, encoding);
2021: /***/
2022: nameHandle = stringPool.addSymbol(data
2023: .substring(nameOffset,
2024: currentOffset));
2025: /***/
2026: }
2027: }
2028: //
2029: // [39] ExprWhitespace ::= S
2030: //
2031: while (ch == ' ' || ch == 0x0A || ch == 0x09
2032: || ch == 0x0D) {
2033: if (++currentOffset == endOffset) {
2034: break;
2035: }
2036: /***
2037: ch = (data[currentOffset] & 0xFF);
2038: /***/
2039: ch = data.charAt(currentOffset);
2040: /***/
2041: }
2042: //
2043: // If there is a preceding token and the preceding token is not one of @, ::, (, [, , or
2044: // an Operator, then an NCName must be recognized as an OperatorName.
2045: //
2046: if (starIsMultiplyOperator) {
2047: if (nameHandle == fAndSymbol) {
2048: addToken(tokens,
2049: XPath.Tokens.EXPRTOKEN_OPERATOR_AND);
2050: starIsMultiplyOperator = false;
2051: } else if (nameHandle == fOrSymbol) {
2052: addToken(tokens,
2053: XPath.Tokens.EXPRTOKEN_OPERATOR_OR);
2054: starIsMultiplyOperator = false;
2055: } else if (nameHandle == fModSymbol) {
2056: addToken(tokens,
2057: XPath.Tokens.EXPRTOKEN_OPERATOR_MOD);
2058: starIsMultiplyOperator = false;
2059: } else if (nameHandle == fDivSymbol) {
2060: addToken(tokens,
2061: XPath.Tokens.EXPRTOKEN_OPERATOR_DIV);
2062: starIsMultiplyOperator = false;
2063: } else {
2064: // System.out.println("abort 6");
2065: return false; // REVISIT
2066: }
2067: if (isNameTestNCName) {
2068: // System.out.println("abort 7");
2069: return false; // REVISIT - NCName:* where an OperatorName is required
2070: } else if (isAxisName) {
2071: // System.out.println("abort 8");
2072: return false; // REVISIT - AxisName:: where an OperatorName is required
2073: }
2074: break;
2075: }
2076: //
2077: // If the character following an NCName (possibly after intervening ExprWhitespace) is (,
2078: // then the token must be recognized as a NodeType or a FunctionName.
2079: //
2080: if (ch == '(' && !isNameTestNCName && !isAxisName) {
2081: if (nameHandle == fCommentSymbol) {
2082: addToken(
2083: tokens,
2084: XPath.Tokens.EXPRTOKEN_NODETYPE_COMMENT);
2085: } else if (nameHandle == fTextSymbol) {
2086: addToken(
2087: tokens,
2088: XPath.Tokens.EXPRTOKEN_NODETYPE_TEXT);
2089: } else if (nameHandle == fPISymbol) {
2090: addToken(tokens,
2091: XPath.Tokens.EXPRTOKEN_NODETYPE_PI);
2092: } else if (nameHandle == fNodeSymbol) {
2093: addToken(
2094: tokens,
2095: XPath.Tokens.EXPRTOKEN_NODETYPE_NODE);
2096: } else {
2097: addToken(
2098: tokens,
2099: XPath.Tokens.EXPRTOKEN_FUNCTION_NAME);
2100: tokens.addToken(prefixHandle);
2101: tokens.addToken(nameHandle);
2102: }
2103: addToken(tokens,
2104: XPath.Tokens.EXPRTOKEN_OPEN_PAREN);
2105: starIsMultiplyOperator = false;
2106: if (++currentOffset == endOffset) {
2107: break;
2108: }
2109: break;
2110: }
2111: //
2112: // If the two characters following an NCName (possibly after intervening ExprWhitespace)
2113: // are ::, then the token must be recognized as an AxisName.
2114: //
2115: if (isAxisName
2116: || (ch == ':'
2117: && currentOffset + 1 < endOffset &&
2118: /***
2119: (data[currentOffset + 1] & 0xFF) == ':')) {
2120: /***/
2121: data.charAt(currentOffset + 1) == ':')) {
2122: /***/
2123: if (nameHandle == fAncestorSymbol) {
2124: addToken(
2125: tokens,
2126: XPath.Tokens.EXPRTOKEN_AXISNAME_ANCESTOR);
2127: } else if (nameHandle == fAncestorOrSelfSymbol) {
2128: addToken(
2129: tokens,
2130: XPath.Tokens.EXPRTOKEN_AXISNAME_ANCESTOR_OR_SELF);
2131: } else if (nameHandle == fAttributeSymbol) {
2132: addToken(
2133: tokens,
2134: XPath.Tokens.EXPRTOKEN_AXISNAME_ATTRIBUTE);
2135: } else if (nameHandle == fChildSymbol) {
2136: addToken(
2137: tokens,
2138: XPath.Tokens.EXPRTOKEN_AXISNAME_CHILD);
2139: } else if (nameHandle == fDescendantSymbol) {
2140: addToken(
2141: tokens,
2142: XPath.Tokens.EXPRTOKEN_AXISNAME_DESCENDANT);
2143: } else if (nameHandle == fDescendantOrSelfSymbol) {
2144: addToken(
2145: tokens,
2146: XPath.Tokens.EXPRTOKEN_AXISNAME_DESCENDANT_OR_SELF);
2147: } else if (nameHandle == fFollowingSymbol) {
2148: addToken(
2149: tokens,
2150: XPath.Tokens.EXPRTOKEN_AXISNAME_FOLLOWING);
2151: } else if (nameHandle == fFollowingSiblingSymbol) {
2152: addToken(
2153: tokens,
2154: XPath.Tokens.EXPRTOKEN_AXISNAME_FOLLOWING_SIBLING);
2155: } else if (nameHandle == fNamespaceSymbol) {
2156: addToken(
2157: tokens,
2158: XPath.Tokens.EXPRTOKEN_AXISNAME_NAMESPACE);
2159: } else if (nameHandle == fParentSymbol) {
2160: addToken(
2161: tokens,
2162: XPath.Tokens.EXPRTOKEN_AXISNAME_PARENT);
2163: } else if (nameHandle == fPrecedingSymbol) {
2164: addToken(
2165: tokens,
2166: XPath.Tokens.EXPRTOKEN_AXISNAME_PRECEDING);
2167: } else if (nameHandle == fPrecedingSiblingSymbol) {
2168: addToken(
2169: tokens,
2170: XPath.Tokens.EXPRTOKEN_AXISNAME_PRECEDING_SIBLING);
2171: } else if (nameHandle == fSelfSymbol) {
2172: addToken(
2173: tokens,
2174: XPath.Tokens.EXPRTOKEN_AXISNAME_SELF);
2175: } else {
2176: // System.out.println("abort 9");
2177: return false; // REVISIT
2178: }
2179: if (isNameTestNCName) {
2180: // System.out.println("abort 10");
2181: return false; // REVISIT - "NCName:* ::" where "AxisName ::" is required
2182: }
2183: addToken(tokens,
2184: XPath.Tokens.EXPRTOKEN_DOUBLE_COLON);
2185: starIsMultiplyOperator = false;
2186: if (!isAxisName) {
2187: currentOffset++;
2188: if (++currentOffset == endOffset) {
2189: break;
2190: }
2191: }
2192: break;
2193: }
2194: //
2195: // Otherwise, the token must not be recognized as an OperatorName, a NodeType, a
2196: // FunctionName, or an AxisName.
2197: //
2198: if (isNameTestNCName) {
2199: addToken(
2200: tokens,
2201: XPath.Tokens.EXPRTOKEN_NAMETEST_NAMESPACE);
2202: starIsMultiplyOperator = true;
2203: tokens.addToken(nameHandle);
2204: } else {
2205: addToken(tokens,
2206: XPath.Tokens.EXPRTOKEN_NAMETEST_QNAME);
2207: starIsMultiplyOperator = true;
2208: tokens.addToken(prefixHandle);
2209: tokens.addToken(nameHandle);
2210: }
2211: break;
2212: }
2213: }
2214: if (XPath.Tokens.DUMP_TOKENS) {
2215: tokens.dumpTokens();
2216: }
2217: return true;
2218: }
2219:
2220: //
2221: // [5] NCName ::= (Letter | '_') (NCNameChar)*
2222: // [6] NCNameChar ::= Letter | Digit | '.' | '-' | '_' | CombiningChar | Extender
2223: //
2224: int scanNCName(String data, int endOffset, int currentOffset) {
2225: int ch = data.charAt(currentOffset);
2226: if (ch >= 0x80) {
2227: if ((XMLCharacterProperties.fgCharFlags[ch] & XMLCharacterProperties.E_InitialNameCharFlag) == 0) {
2228: return currentOffset;
2229: }
2230: } else {
2231: byte chartype = fASCIICharMap[ch];
2232: if (chartype != CHARTYPE_LETTER
2233: && chartype != CHARTYPE_UNDERSCORE) {
2234: return currentOffset;
2235: }
2236: }
2237: while (++currentOffset < endOffset) {
2238: ch = data.charAt(currentOffset);
2239: if (ch >= 0x80) {
2240: if ((XMLCharacterProperties.fgCharFlags[ch] & XMLCharacterProperties.E_NameCharFlag) == 0) {
2241: break;
2242: }
2243: } else {
2244: byte chartype = fASCIICharMap[ch];
2245: if (chartype != CHARTYPE_LETTER
2246: && chartype != CHARTYPE_DIGIT
2247: && chartype != CHARTYPE_PERIOD
2248: && chartype != CHARTYPE_MINUS
2249: && chartype != CHARTYPE_UNDERSCORE) {
2250: break;
2251: }
2252: }
2253: }
2254: return currentOffset;
2255: }
2256:
2257: /*
2258: void allocateProducer(byte[] data, int offset, int length, EncodingSupport encoding) {
2259: XPathStringProducer sp = fStringProducers[fStringProducerCount];
2260: if (sp != null) {
2261: sp = sp.setState(data, offset, length, encoding);
2262: } else {
2263: sp = new XPathStringProducer(data, offset, length, encoding);
2264: }
2265: fStringProducers[fStringProducerCount++] = sp;
2266: }
2267: void finalizeProducer(byte[] data) {
2268: fStringProducerCount--;
2269: }
2270: class XPathStringProducer {
2271: byte[] fData = null;
2272: int fOffset = -1;
2273: int fLength = -1;
2274: String fEncoding = null;
2275: XPathStringProducer(byte[] data, int offset, int length, EncodingSupport encoding) {
2276: init(data, offset, length, encoding);
2277: }
2278: XPathStringProducer setState(byte[] bytes, int offset, int length, EncodingSupport encoding) {
2279: init(bytes, offset, length, encoding);
2280: return this;
2281: }
2282: void init(byte[] data, int offset, int length, EncodingSupport encoding) {
2283: fData = data;
2284: fOffset = offset;
2285: fLength = length;
2286: fEncoding = encoding;
2287: }
2288: String getEncoding() {
2289: return fEncoding;
2290: }
2291: void finalizeProducer() {
2292: // do nothing
2293: }
2294: int addSymbol(int offset, int length) {
2295: return fSymbolTable.addSymbol(fData, offset, length, fEncoding);
2296: }
2297: }
2298: private XPathStringProducer[] fStringProducers = new XPathStringProducer[8];
2299: private int fStringProducerCount = 0;
2300: private XPathStringProducer getStringProducer(byte[] data) {
2301: XPathStringProducer sp = null;
2302: for (int i = 0; i < fStringProducerCount; i++) {
2303: if (fStringProducers[i].fData == data) {
2304: return fStringProducers[i];
2305: }
2306: }
2307: throw new RuntimeException("No StringProducer");
2308: }
2309: */
2310: //
2311: // [30] Number ::= Digits ('.' Digits?)? | '.' Digits
2312: // [31] Digits ::= [0-9]+
2313: //
2314: private int scanNumber(XPath.Tokens tokens,
2315: String/*byte[]*/data, int endOffset, int currentOffset/*, EncodingSupport encoding*/) {
2316: /***
2317: int ch = (data[currentOffset] & 0xFF);
2318: /***/
2319: int ch = data.charAt(currentOffset);
2320: /***/
2321: int whole = 0;
2322: int part = 0;
2323: while (ch >= '0' && ch <= '9') {
2324: whole = (whole * 10) + (ch - '0');
2325: if (++currentOffset == endOffset) {
2326: break;
2327: }
2328: /***
2329: ch = (data[currentOffset] & 0xFF);
2330: /***/
2331: ch = data.charAt(currentOffset);
2332: /***/
2333: }
2334: if (ch == '.') {
2335: if (++currentOffset < endOffset) {
2336: int start = currentOffset;
2337: /***
2338: ch = (data[currentOffset] & 0xFF);
2339: /***/
2340: ch = data.charAt(currentOffset);
2341: /***/
2342: while (ch >= '0' && ch <= '9') {
2343: part = (part * 10) + (ch - '0');
2344: if (++currentOffset == endOffset) {
2345: break;
2346: }
2347: /***
2348: ch = (data[currentOffset] & 0xFF);
2349: /***/
2350: ch = data.charAt(currentOffset);
2351: /***/
2352: }
2353: if (part != 0) {
2354: /***
2355: part = tokens.addSymbol(data, start, currentOffset - start, encoding);
2356: /***/
2357: throw new RuntimeException("find a solution!");
2358: //part = fStringPool.addSymbol(data.substring(start, currentOffset));
2359: /***/
2360: }
2361: }
2362: }
2363: tokens.addToken(whole);
2364: tokens.addToken(part);
2365: return currentOffset;
2366: }
2367:
2368: /***
2369: public static SymbolTable getGlobalTokens() {
2370: return fgSymbolTable;
2371: }
2372:
2373: public static void main(String argv[]) {
2374: try {
2375: SymbolTable symbols = new SymbolTable(XPathExprScanner.getGlobalTokens());
2376: XPath.Tokens tokens = new XPath.Tokens(symbols);
2377: byte[] bytes = new byte[1 << 8]; // 256
2378: int i = 0;
2379: if (XPath.Tokens.DUMP_TOKENS) {
2380: System.out.println("<output>");
2381: System.out.println();
2382: }
2383: while (i < argv.length) {
2384: String uri = argv[i++];
2385: // System.out.println("uri: "+uri);
2386: FileInputStream is = new FileInputStream(uri);
2387: int lineOffset = 0;
2388: int offset = 0;
2389: while (true) {
2390: int avail = bytes.length - offset;
2391: if (avail == 0) {
2392: avail = bytes.length;
2393: byte[] newBytes = new byte[avail << 1];
2394: System.arraycopy(bytes, 0, newBytes, 0, avail);
2395: bytes = newBytes;
2396: }
2397: int result = is.read(bytes, offset, avail);
2398: if (result == -1) {
2399: bytes[offset] = 0;
2400: break;
2401: }
2402: result += offset;
2403: for (int j = offset; j < result; j++) {
2404: int ch = bytes[j];
2405: if (ch == 0x0A || ch == 0x0D) {
2406: if (lineOffset < offset) {
2407: XPathExprScanner.scanExpr(tokens, bytes, lineOffset, offset, UTF8EncodingSupport.getInstance());
2408: }
2409: while (ch == 0x0A || ch == 0x0D) {
2410: if (++j == result) {
2411: j = result;
2412: break;
2413: }
2414: ch = bytes[j];
2415: }
2416: lineOffset = offset;
2417: if (j == result) {
2418: break;
2419: }
2420: }
2421: bytes[offset++] = (byte)ch;
2422: }
2423: }
2424: is.close();
2425: }
2426: if (XPath.Tokens.DUMP_TOKENS) {
2427: System.out.println("</output>");
2428: }
2429: }
2430: catch (Exception e) {
2431: e.printStackTrace();
2432: }
2433: }
2434: /***/
2435:
2436: //
2437: // Protected methods
2438: //
2439: /**
2440: * This method adds the specified token to the token list. By
2441: * default, this method allows all tokens. However, subclasses
2442: * of the XPathExprScanner can override this method in order
2443: * to disallow certain tokens from being used in the scanned
2444: * XPath expression. This is a convenient way of allowing only
2445: * a subset of XPath.
2446: */
2447: protected void addToken(XPath.Tokens tokens, int token)
2448: throws XPathException {
2449: tokens.addToken(token);
2450: } // addToken(int)
2451:
2452: } // class Scanner
2453:
2454: /**
2455: * @author Glenn Marcy, IBM
2456: * @author Andy Clark, IBM
2457: *
2458: * @version $Id: XPath.java,v 1.10 2001/06/08 14:23:49 sandygao Exp $
2459: */
2460: /***
2461: public static class XPathExprParser {
2462:
2463: //
2464: // Constants
2465: //
2466:
2467: private static final boolean DUMP_PARSE_TREE = false;
2468:
2469: private static final boolean DEBUG_PUSH_PARSEOPS = false;
2470:
2471: /** Parse Tree operations * /
2472: public static final int
2473: PARSEOP_OR = -5000,
2474: PARSEOP_AND = -5001,
2475: PARSEOP_EQUAL = -5002,
2476: PARSEOP_NOT_EQUAL = -5003,
2477: PARSEOP_PLUS = -5004,
2478: PARSEOP_MINUS = -5005,
2479: PARSEOP_MULT = -5006,
2480: PARSEOP_DIV = -5007,
2481: PARSEOP_MOD = -5008,
2482: PARSEOP_LESS = -5009,
2483: PARSEOP_GREATER = -5010,
2484: PARSEOP_LESS_EQUAL = -5011,
2485: PARSEOP_GREATER_EQUAL = -5012,
2486: PARSEOP_NEGATE = -5013,
2487: PARSEOP_UNION = -5014,
2488: PARSEOP_SELECT_ROOT = -5015,
2489: PARSEOP_STEPS = -5016,
2490: PARSEOP_STEP = -5017,
2491: PARSEOP_AXIS_ANCESTOR = -5018,
2492: PARSEOP_AXIS_ANCESTOR_OR_SELF = -5019,
2493: PARSEOP_AXIS_ATTRIBUTE = -5020,
2494: PARSEOP_AXIS_CHILD = -5021,
2495: PARSEOP_AXIS_DESCENDANT = -5022,
2496: PARSEOP_AXIS_DESCENDANT_OR_SELF = -5023,
2497: PARSEOP_AXIS_FOLLOWING = -5024,
2498: PARSEOP_AXIS_FOLLOWING_SIBLING = -5025,
2499: PARSEOP_AXIS_NAMESPACE = -5026,
2500: PARSEOP_AXIS_PARENT = -5027,
2501: PARSEOP_AXIS_PRECEDING = -5028,
2502: PARSEOP_AXIS_PRECEDING_SIBLING = -5029,
2503: PARSEOP_AXIS_SELF = -5030,
2504: PARSEOP_NODETEST_ANY = -5031,
2505: PARSEOP_NODETEST_NAMESPACE = -5032,
2506: PARSEOP_NODETEST_QNAME = -5033,
2507: PARSEOP_NODETEST_COMMENT = -5034,
2508: PARSEOP_NODETEST_TEXT = -5035,
2509: PARSEOP_NODETEST_PI = -5036,
2510: PARSEOP_NODETEST_PI_TARGET = -5037,
2511: PARSEOP_NODETEST_NODE = -5038,
2512: PARSEOP_FILTER = -5039,
2513: PARSEOP_PREDICATES = -5040,
2514: PARSEOP_PREDICATE = -5041,
2515: PARSEOP_VARIABLE_REFERENCE = -5042,
2516: PARSEOP_GROUPING = -5043,
2517: PARSEOP_LITERAL = -5044,
2518: PARSEOP_NUMBER = -5045,
2519: PARSEOP_FUNCTION = -5046,
2520: PARSEOP_FUNCTION_NAME = -5047,
2521: PARSEOP_FUNCTION_ARGUMENTS = -5048;
2522:
2523: //
2524: // Data
2525: //
2526:
2527: private int fTokenCount = 0; // for reading
2528: private int fCurrentToken = 0; // for reading
2529:
2530: private static final int INITIAL_PARSEOP_COUNT = 1 << 8;
2531: private int[] fParseTree = new int[INITIAL_PARSEOP_COUNT];
2532: private int fParseOpCount = 0; // for writing
2533: private int fCurrentParseOp = 0; // for reading
2534:
2535: /** Symbol table. * /
2536: private SymbolTable fSymbolTable;
2537:
2538: /** Tokens. * /
2539: private XPath.Tokens fTokens;
2540:
2541: /** Scanner. * /
2542: private XPathExprScanner fScanner;
2543:
2544: //
2545: // Constructors
2546: //
2547:
2548: public XPathExprParser() {
2549: this(new SymbolTable());
2550: }
2551:
2552: public XPathExprParser(SymbolTable symbolTable) {
2553: this(symbolTable, new XPathExprScanner(symbolTable));
2554: }
2555:
2556: public XPathExprParser(SymbolTable symbolTable, XPathExprScanner scanner) {
2557:
2558: fSymbolTable = symbolTable;
2559: fScanner = scanner;
2560:
2561: } // <init>(SymbolTable,XPathExprScanner)
2562:
2563: //
2564: // Public methods
2565: //
2566:
2567: // init
2568:
2569: public void reset() {
2570: fParseOpCount = 0;
2571: fCurrentParseOp = 0;
2572: }
2573:
2574: // parsing
2575:
2576: public int parseExpr(String data) throws XPathException {
2577: return parseExpr(data, 0, data.length());
2578: }
2579:
2580: public int parseExpr(String data, int currentOffset, int endOffset)
2581: throws XPathException {
2582: return parseExprOrPattern(data, currentOffset, endOffset, false);
2583: }
2584:
2585: public int parsePattern(String data, int currentOffset, int endOffset)
2586: throws XPathException {
2587: return parseExprOrPattern(data, currentOffset, endOffset, true);
2588: }
2589:
2590: public int parseExprOrPattern(String data, int currentOffset,
2591: int endOffset, boolean isPattern)
2592: throws XPathException {
2593: fTokenCount = 0;
2594:
2595: if (DUMP_PARSE_TREE) {
2596: System.out.println(" <test>");
2597: System.out.println(" <expression>");
2598: System.out.println(" " + data.substring(currentOffset, endOffset));
2599: System.out.println(" </expression>");
2600: }
2601: fTokens = new XPath.Tokens(fSymbolTable);
2602: fScanner.scanExpr(fTokens, data, currentOffset, endOffset);
2603: //
2604: // Build parse tree
2605: //
2606: fTokenCount = fTokens.getTokenCount();
2607: fCurrentToken = 0;
2608: if (!parseExpr()) {
2609: // System.out.println("abort 12");
2610: return -1; // REVISIT
2611: }
2612: if (fCurrentToken < fTokenCount) {
2613: // System.out.println("abort 13");
2614: return -1; // REVISIT
2615: }
2616: if (DUMP_PARSE_TREE) {
2617: dumpParseTree(fCurrentParseOp, 4);
2618: }
2619: if (DUMP_PARSE_TREE) {
2620: System.out.println(" </test>");
2621: System.out.println();
2622: }
2623: return fCurrentParseOp;
2624: }
2625:
2626: // parse tree ops
2627:
2628: public int getCurrentParseOp() {
2629: return fCurrentParseOp;
2630: }
2631:
2632: public int getParseTreeOp(int handle) {
2633: return fParseTree[handle];
2634: }
2635:
2636: public int getParseTreeSubHandle(int handle, int subHandleIndex) {
2637: return fParseTree[handle - 1 - subHandleIndex];
2638: }
2639:
2640: public String getParseTreeSymbol(int handle, int subHandleIndex) {
2641: int symHandle = fParseTree[handle - 1 - subHandleIndex];
2642: return fTokens.getTokenString(symHandle);
2643: }
2644:
2645: public int getParseTreeIntValue(int handle, int subHandleIndex) {
2646: return fParseTree[handle - 1 - subHandleIndex];
2647: }
2648:
2649: // debugging
2650:
2651: public void dumpParseTree(int rootParseOp, int indent) {
2652: indentPrint(indent);
2653: System.out.println("<parse-tree>");
2654: dumpParseTreeNode(rootParseOp, indent + 2);
2655: indentPrint(indent);
2656: System.out.println("</parse-tree>");
2657: }
2658:
2659: public String getParseOpName(int parseOp) {
2660: switch (parseOp) {
2661: case PARSEOP_OR: return "PARSEOP_OR";
2662: case PARSEOP_AND: return "PARSEOP_AND";
2663: case PARSEOP_EQUAL: return "PARSEOP_EQUAL";
2664: case PARSEOP_NOT_EQUAL: return "PARSEOP_NOT_EQUAL";
2665: case PARSEOP_PLUS: return "PARSEOP_PLUS";
2666: case PARSEOP_MINUS: return "PARSEOP_MINUS";
2667: case PARSEOP_MULT: return "PARSEOP_MULT";
2668: case PARSEOP_DIV: return "PARSEOP_DIV";
2669: case PARSEOP_MOD: return "PARSEOP_MOD";
2670: case PARSEOP_LESS: return "PARSEOP_LESS";
2671: case PARSEOP_GREATER: return "PARSEOP_GREATER";
2672: case PARSEOP_LESS_EQUAL: return "PARSEOP_LESS_EQUAL";
2673: case PARSEOP_GREATER_EQUAL: return "PARSEOP_GREATER_EQUAL";
2674: case PARSEOP_NEGATE: return "PARSEOP_NEGATE";
2675: case PARSEOP_UNION: return "PARSEOP_UNION";
2676: case PARSEOP_SELECT_ROOT: return "PARSEOP_SELECT_ROOT";
2677: case PARSEOP_STEPS: return "PARSEOP_STEPS";
2678: case PARSEOP_STEP: return "PARSEOP_STEP";
2679: case PARSEOP_AXIS_ANCESTOR: return "PARSEOP_AXIS_ANCESTOR";
2680: case PARSEOP_AXIS_ANCESTOR_OR_SELF: return "PARSEOP_AXIS_ANCESTOR_OR_SELF";
2681: case PARSEOP_AXIS_ATTRIBUTE: return "PARSEOP_AXIS_ATTRIBUTE";
2682: case PARSEOP_AXIS_CHILD: return "PARSEOP_AXIS_CHILD";
2683: case PARSEOP_AXIS_DESCENDANT: return "PARSEOP_AXIS_DESCENDANT";
2684: case PARSEOP_AXIS_DESCENDANT_OR_SELF: return "PARSEOP_AXIS_DESCENDANT_OR_SELF";
2685: case PARSEOP_AXIS_FOLLOWING: return "PARSEOP_AXIS_FOLLOWING";
2686: case PARSEOP_AXIS_FOLLOWING_SIBLING: return "PARSEOP_AXIS_FOLLOWING_SIBLING";
2687: case PARSEOP_AXIS_NAMESPACE: return "PARSEOP_AXIS_NAMESPACE";
2688: case PARSEOP_AXIS_PARENT: return "PARSEOP_AXIS_PARENT";
2689: case PARSEOP_AXIS_PRECEDING: return "PARSEOP_AXIS_PRECEDING";
2690: case PARSEOP_AXIS_PRECEDING_SIBLING: return "PARSEOP_AXIS_PRECEDING_SIBLING";
2691: case PARSEOP_AXIS_SELF: return "PARSEOP_AXIS_SELF";
2692: case PARSEOP_NODETEST_ANY: return "PARSEOP_NODETEST_ANY";
2693: case PARSEOP_NODETEST_NAMESPACE: return "PARSEOP_NODETEST_NAMESPACE";
2694: case PARSEOP_NODETEST_QNAME: return "PARSEOP_NODETEST_QNAME";
2695: case PARSEOP_NODETEST_COMMENT: return "PARSEOP_NODETEST_COMMENT";
2696: case PARSEOP_NODETEST_TEXT: return "PARSEOP_NODETEST_TEXT";
2697: case PARSEOP_NODETEST_PI: return "PARSEOP_NODETEST_PI";
2698: case PARSEOP_NODETEST_PI_TARGET: return "PARSEOP_NODETEST_PI_TARGET";
2699: case PARSEOP_NODETEST_NODE: return "PARSEOP_NODETEST_NODE";
2700: case PARSEOP_FILTER: return "PARSEOP_FILTER";
2701: case PARSEOP_PREDICATES: return "PARSEOP_PREDICATES";
2702: case PARSEOP_PREDICATE: return "PARSEOP_PREDICATE";
2703: case PARSEOP_VARIABLE_REFERENCE: return "PARSEOP_VARIABLE_REFERENCE";
2704: case PARSEOP_GROUPING: return "PARSEOP_GROUPING";
2705: case PARSEOP_LITERAL: return "PARSEOP_LITERAL";
2706: case PARSEOP_NUMBER: return "PARSEOP_NUMBER";
2707: case PARSEOP_FUNCTION: return "PARSEOP_FUNCTION";
2708: case PARSEOP_FUNCTION_NAME: return "PARSEOP_FUNCTION_NAME";
2709: case PARSEOP_FUNCTION_ARGUMENTS: return "PARSEOP_FUNCTION_ARGUMENTS";
2710: }
2711: return "??? ("+parseOp+')';
2712: }
2713:
2714: //
2715: // Protected methods
2716: //
2717:
2718: protected void checkParseOp(int parseOp) throws XPathException {
2719: // do nothing; all parse ops allowed in the class
2720: }
2721:
2722: //
2723: // Private methods
2724: //
2725:
2726: private void pushParseOp(int parseOp) throws XPathException {
2727: if (DEBUG_PUSH_PARSEOPS) {
2728: System.out.println("pushParseOp: "+getParseOpName(parseOp));
2729: }
2730: checkParseOp(parseOp);
2731: try {
2732: fParseTree[fParseOpCount] = parseOp;
2733: } catch (ArrayIndexOutOfBoundsException ex) {
2734: int[] oldList = fParseTree;
2735: fParseTree = new int[fParseOpCount << 1];
2736: System.arraycopy(oldList, 0, fParseTree, 0, fParseOpCount);
2737: fParseTree[fParseOpCount] = parseOp;
2738: }
2739: fCurrentParseOp = fParseOpCount++;
2740: }
2741:
2742: private void pushParseOp2(int parseOp, int arg) throws XPathException {
2743: if (DEBUG_PUSH_PARSEOPS) {
2744: System.out.println("pushParseOp2: "+getParseOpName(parseOp)+", "+arg);
2745: }
2746: checkParseOp(parseOp);
2747: try {
2748: fParseTree[fParseOpCount + 1] = parseOp;
2749: } catch (ArrayIndexOutOfBoundsException ex) {
2750: int[] oldList = fParseTree;
2751: fParseTree = new int[fParseOpCount << 1];
2752: System.arraycopy(oldList, 0, fParseTree, 0, fParseOpCount);
2753: fParseTree[fParseOpCount + 1] = parseOp;
2754: }
2755: fParseTree[fParseOpCount++] = arg;
2756: fCurrentParseOp = fParseOpCount++;
2757: }
2758:
2759: private void pushParseOp3(int parseOp, int arg1, int arg2)
2760: throws XPathException {
2761: if (DEBUG_PUSH_PARSEOPS) {
2762: System.out.println("pushParseOp3: "+getParseOpName(parseOp)+", "+arg1+", "+arg2);
2763: }
2764: checkParseOp(parseOp);
2765: try {
2766: fParseTree[fParseOpCount + 2] = parseOp;
2767: } catch (ArrayIndexOutOfBoundsException ex) {
2768: int[] oldList = fParseTree;
2769: fParseTree = new int[fParseOpCount << 1];
2770: System.arraycopy(oldList, 0, fParseTree, 0, fParseOpCount);
2771: fParseTree[fParseOpCount + 2] = parseOp;
2772: }
2773: fParseTree[fParseOpCount++] = arg2;
2774: fParseTree[fParseOpCount++] = arg1;
2775: fCurrentParseOp = fParseOpCount++;
2776: }
2777:
2778: private void indentPrint(int indent) {
2779: for (int i = 0; i < indent; i++) {
2780: System.out.print(" ");
2781: }
2782: }
2783:
2784: private void dumpParseTreeNode(int parseOp, int indent) {
2785: switch (fParseTree[parseOp]) {
2786: case PARSEOP_OR:
2787: indentPrint(indent);
2788: System.out.println("<or>");
2789: dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2790: dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
2791: indentPrint(indent);
2792: System.out.println("</or>");
2793: break;
2794: case PARSEOP_AND:
2795: indentPrint(indent);
2796: System.out.println("<and>");
2797: dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2798: dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
2799: indentPrint(indent);
2800: System.out.println("</and>");
2801: break;
2802: case PARSEOP_EQUAL:
2803: indentPrint(indent);
2804: System.out.println("<equal>");
2805: dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2806: dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
2807: indentPrint(indent);
2808: System.out.println("</equal>");
2809: break;
2810: case PARSEOP_NOT_EQUAL:
2811: indentPrint(indent);
2812: System.out.println("<not-equal>");
2813: dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2814: dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
2815: indentPrint(indent);
2816: System.out.println("</not-equal>");
2817: break;
2818: case PARSEOP_PLUS:
2819: indentPrint(indent);
2820: System.out.println("<plus>");
2821: dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2822: dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
2823: indentPrint(indent);
2824: System.out.println("</plus>");
2825: break;
2826: case PARSEOP_MINUS:
2827: indentPrint(indent);
2828: System.out.println("<minus>");
2829: dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2830: dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
2831: indentPrint(indent);
2832: System.out.println("</minus>");
2833: break;
2834: case PARSEOP_MULT:
2835: indentPrint(indent);
2836: System.out.println("<mult>");
2837: dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2838: dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
2839: indentPrint(indent);
2840: System.out.println("</mult>");
2841: break;
2842: case PARSEOP_DIV:
2843: indentPrint(indent);
2844: System.out.println("<div>");
2845: dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2846: dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
2847: indentPrint(indent);
2848: System.out.println("</div>");
2849: break;
2850: case PARSEOP_MOD:
2851: indentPrint(indent);
2852: System.out.println("<mod>");
2853: dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2854: dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
2855: indentPrint(indent);
2856: System.out.println("</mod>");
2857: break;
2858: case PARSEOP_LESS:
2859: indentPrint(indent);
2860: System.out.println("<less>");
2861: dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2862: dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
2863: indentPrint(indent);
2864: System.out.println("</less>");
2865: break;
2866: case PARSEOP_GREATER:
2867: indentPrint(indent);
2868: System.out.println("<greater>");
2869: dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2870: dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
2871: indentPrint(indent);
2872: System.out.println("</greater>");
2873: break;
2874: case PARSEOP_LESS_EQUAL:
2875: indentPrint(indent);
2876: System.out.println("<less-equal>");
2877: dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2878: dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
2879: indentPrint(indent);
2880: System.out.println("</less-equal>");
2881: break;
2882: case PARSEOP_GREATER_EQUAL:
2883: indentPrint(indent);
2884: System.out.println("<greater-equal>");
2885: dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2886: dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
2887: indentPrint(indent);
2888: System.out.println("</greater-equal>");
2889: break;
2890: case PARSEOP_NEGATE:
2891: indentPrint(indent);
2892: System.out.println("<negate>");
2893: dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2894: indentPrint(indent);
2895: System.out.println("</negate>");
2896: break;
2897: case PARSEOP_UNION:
2898: indentPrint(indent);
2899: System.out.println("<union>");
2900: dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2901: dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
2902: indentPrint(indent);
2903: System.out.println("</union>");
2904: break;
2905: case PARSEOP_SELECT_ROOT:
2906: indentPrint(indent);
2907: if (fParseTree[parseOp - 1] == -1) {
2908: System.out.println("<select-root/>");
2909: } else {
2910: System.out.println("<select-root>");
2911: dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2912: indentPrint(indent);
2913: System.out.println("</select-root>");
2914: }
2915: break;
2916: case PARSEOP_STEPS:
2917: indentPrint(indent);
2918: System.out.println("<relative-location-path>");
2919: dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2920: dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
2921: indentPrint(indent);
2922: System.out.println("</relative-location-path>");
2923: break;
2924: case PARSEOP_STEP:
2925: indentPrint(indent);
2926: System.out.println("<step>");
2927: dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
2928: dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
2929: indentPrint(indent);
2930: System.out.println("</step>");
2931: break;
2932: case PARSEOP_AXIS_ANCESTOR:
2933: indentPrint(indent);
2934: System.out.println("<axis name=\"ancestor\"/>");
2935: break;
2936: case PARSEOP_AXIS_ANCESTOR_OR_SELF:
2937: indentPrint(indent);
2938: System.out.println("<axis name=\"ancestor-or-self\"/>");
2939: break;
2940: case PARSEOP_AXIS_ATTRIBUTE:
2941: indentPrint(indent);
2942: System.out.println("<axis name=\"attribute\"/>");
2943: break;
2944: case PARSEOP_AXIS_CHILD:
2945: indentPrint(indent);
2946: System.out.println("<axis name=\"child\"/>");
2947: break;
2948: case PARSEOP_AXIS_DESCENDANT:
2949: indentPrint(indent);
2950: System.out.println("<axis name=\"descendant\"/>");
2951: break;
2952: case PARSEOP_AXIS_DESCENDANT_OR_SELF:
2953: indentPrint(indent);
2954: System.out.println("<axis name=\"descendant-or-self\"/>");
2955: break;
2956: case PARSEOP_AXIS_FOLLOWING:
2957: indentPrint(indent);
2958: System.out.println("<axis name=\"following\"/>");
2959: break;
2960: case PARSEOP_AXIS_FOLLOWING_SIBLING:
2961: indentPrint(indent);
2962: System.out.println("<axis name=\"following-sibling\"/>");
2963: break;
2964: case PARSEOP_AXIS_NAMESPACE:
2965: indentPrint(indent);
2966: System.out.println("<axis name=\"namespace\"/>");
2967: break;
2968: case PARSEOP_AXIS_PARENT:
2969: indentPrint(indent);
2970: System.out.println("<axis name=\"parent\"/>");
2971: break;
2972: case PARSEOP_AXIS_PRECEDING:
2973: indentPrint(indent);
2974: System.out.println("<axis name=\"preceding\"/>");
2975: break;
2976: case PARSEOP_AXIS_PRECEDING_SIBLING:
2977: indentPrint(indent);
2978: System.out.println("<axis name=\"preceding-sibling\"/>");
2979: break;
2980: case PARSEOP_AXIS_SELF:
2981: indentPrint(indent);
2982: System.out.println("<axis name=\"self\"/>");
2983: break;
2984: case PARSEOP_NODETEST_ANY:
2985: indentPrint(indent);
2986: System.out.println("<nodetest type=\"any\"/>");
2987: break;
2988: case PARSEOP_NODETEST_NAMESPACE:
2989: indentPrint(indent);
2990: System.out.print("<nodetest type=\"namespace\"");
2991: System.out.print(" prefix=\"" + fParseTree[parseOp - 1] + "\"");
2992: System.out.println("/>");
2993: break;
2994: case PARSEOP_NODETEST_QNAME:
2995: indentPrint(indent);
2996: System.out.print("<nodetest type=\"qname\"");
2997: if (fParseTree[parseOp - 1] != -1) {
2998: System.out.print(" prefix=\"" + fParseTree[parseOp - 1] + "\"");
2999: }
3000: System.out.print(" localpart=\"" + fParseTree[parseOp - 2] + "\"");
3001: System.out.println("/>");
3002: break;
3003: case PARSEOP_NODETEST_COMMENT:
3004: indentPrint(indent);
3005: System.out.println("<nodetest type=\"comment\"/>");
3006: break;
3007: case PARSEOP_NODETEST_TEXT:
3008: indentPrint(indent);
3009: System.out.println("<nodetest type=\"text\"/>");
3010: break;
3011: case PARSEOP_NODETEST_PI:
3012: indentPrint(indent);
3013: System.out.println("<nodetest type=\"processing-instruction\"/>");
3014: break;
3015: case PARSEOP_NODETEST_PI_TARGET:
3016: indentPrint(indent);
3017: System.out.print("<nodetest type=\"processing-instruction\" target=\"");
3018: System.out.print(fParseTree[parseOp - 1]);
3019: System.out.println("\"/>");
3020: break;
3021: case PARSEOP_NODETEST_NODE:
3022: indentPrint(indent);
3023: System.out.println("<nodetest type=\"node\"/>");
3024: break;
3025: case PARSEOP_FILTER:
3026: indentPrint(indent);
3027: System.out.println("<step-with-predicate>");
3028: dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
3029: dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
3030: indentPrint(indent);
3031: System.out.println("</step-with-predicate>");
3032: break;
3033: case PARSEOP_PREDICATES:
3034: indentPrint(indent);
3035: System.out.println("<predicates>");
3036: dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
3037: dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
3038: indentPrint(indent);
3039: System.out.println("</predicates>");
3040: break;
3041: case PARSEOP_PREDICATE:
3042: indentPrint(indent);
3043: System.out.println("<predicate>");
3044: dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
3045: indentPrint(indent);
3046: System.out.println("</predicate>");
3047: break;
3048: case PARSEOP_VARIABLE_REFERENCE:
3049: indentPrint(indent);
3050: System.out.print("<variable-reference");
3051: if (fParseTree[parseOp - 1] != -1) {
3052: System.out.print(" prefix=\"" + fParseTree[parseOp - 1] + "\"");
3053: }
3054: System.out.print(" localpart=\"" + fParseTree[parseOp - 2] + "\"");
3055: System.out.println("/>");
3056: break;
3057: case PARSEOP_GROUPING:
3058: indentPrint(indent);
3059: System.out.println("<grouping>");
3060: dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
3061: indentPrint(indent);
3062: System.out.println("</grouping>");
3063: break;
3064: case PARSEOP_LITERAL:
3065: indentPrint(indent);
3066: System.out.print("<literal");
3067: System.out.print(" value=\"" + fParseTree[parseOp - 1] + "\"");
3068: System.out.println("/>");
3069: break;
3070: case PARSEOP_NUMBER:
3071: indentPrint(indent);
3072: System.out.print("<number");
3073: System.out.print(" whole=\"" + fParseTree[parseOp - 1] + "\"");
3074: System.out.print(" part=\"" + fParseTree[parseOp - 2] + "\"");
3075: System.out.println("/>");
3076: break;
3077: case PARSEOP_FUNCTION:
3078: indentPrint(indent);
3079: System.out.println("<function-call>");
3080: dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
3081: if (fParseTree[parseOp - 2] != -1) {
3082: dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
3083: }
3084: indentPrint(indent);
3085: System.out.println("</function-call>");
3086: break;
3087: case PARSEOP_FUNCTION_NAME:
3088: indentPrint(indent);
3089: System.out.print("<function-name");
3090: if (fParseTree[parseOp - 1] != -1) {
3091: System.out.print(" prefix=\"" + fParseTree[parseOp - 1] + "\"");
3092: }
3093: System.out.print(" localpart=\"" + fParseTree[parseOp - 2] + "\"");
3094: System.out.println("/>");
3095: break;
3096: case PARSEOP_FUNCTION_ARGUMENTS:
3097: indentPrint(indent);
3098: System.out.println("<function-args>");
3099: dumpParseTreeNode(fParseTree[parseOp - 1], indent + 2);
3100: dumpParseTreeNode(fParseTree[parseOp - 2], indent + 2);
3101: indentPrint(indent);
3102: System.out.println("</function-args>");
3103: break;
3104: default:
3105: throw new RuntimeException("dumpParseTreeNode("+parseOp+")");
3106: }
3107: }
3108:
3109: //
3110: // Package methods
3111: //
3112:
3113: /**
3114: * [14] Expr ::= OrExpr
3115: * /
3116: boolean parseExpr() throws XPathException {
3117: return parseOrExpr();
3118: }
3119:
3120: /**
3121: * [21] OrExpr ::= AndExpr | OrExpr 'or' AndExpr
3122: *
3123: * also: OrExpr ::= (AndExpr 'or')* AndExpr
3124: * /
3125: boolean parseOrExpr() throws XPathException {
3126: if (!parseAndExpr()) {
3127: return false;
3128: }
3129: while (fCurrentToken < fTokenCount) {
3130: if (fTokens.getToken(fCurrentToken) != XPath.Tokens.EXPRTOKEN_OPERATOR_OR) {
3131: break;
3132: }
3133: int saveToken = fCurrentToken;
3134: int saveParseOp = fCurrentParseOp;
3135: int left = fCurrentParseOp;
3136: if (++fCurrentToken == fTokenCount) {
3137: fCurrentToken = saveToken;
3138: fCurrentParseOp = saveParseOp;
3139: return true;
3140: }
3141: if (!parseAndExpr()) {
3142: fCurrentToken = saveToken;
3143: fCurrentParseOp = saveParseOp;
3144: return true;
3145: }
3146: int right = fCurrentParseOp;
3147: pushParseOp3(PARSEOP_OR, left, right);
3148: }
3149: return true;
3150: }
3151:
3152: /**
3153: * [22] AndExpr ::= EqualityExpr | AndExpr 'and' EqualityExpr
3154: * /
3155: boolean parseAndExpr() throws XPathException {
3156: if (!parseEqualityExpr()) {
3157: return false;
3158: }
3159: while (fCurrentToken < fTokenCount) {
3160: if (fTokens.getToken(fCurrentToken) != XPath.Tokens.EXPRTOKEN_OPERATOR_AND) {
3161: break;
3162: }
3163: int saveToken = fCurrentToken;
3164: int saveParseOp = fCurrentParseOp;
3165: int left = fCurrentParseOp;
3166: if (++fCurrentToken == fTokenCount) {
3167: fCurrentToken = saveToken;
3168: fCurrentParseOp = saveParseOp;
3169: return true;
3170: }
3171: if (!parseEqualityExpr()) {
3172: fCurrentToken = saveToken;
3173: fCurrentParseOp = saveParseOp;
3174: return true;
3175: }
3176: int right = fCurrentParseOp;
3177: pushParseOp3(PARSEOP_AND, left, right);
3178: }
3179: return true;
3180: }
3181:
3182: /**
3183: * [23] EqualityExpr ::= RelationalExpr
3184: * | EqualityExpr '=' RelationalExpr
3185: * | EqualityExpr '!=' RelationalExpr
3186: * /
3187: boolean parseEqualityExpr() throws XPathException {
3188: if (!parseRelationalExpr()) {
3189: return false;
3190: }
3191: while (fCurrentToken < fTokenCount) {
3192: int parseOp;
3193: if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_OPERATOR_EQUAL) {
3194: parseOp = PARSEOP_EQUAL;
3195: } else if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_OPERATOR_NOT_EQUAL) {
3196: parseOp = PARSEOP_NOT_EQUAL;
3197: } else {
3198: break;
3199: }
3200: int saveToken = fCurrentToken;
3201: int saveParseOp = fCurrentParseOp;
3202: int left = fCurrentParseOp;
3203: if (++fCurrentToken == fTokenCount) {
3204: fCurrentToken = saveToken;
3205: fCurrentParseOp = saveParseOp;
3206: return true;
3207: }
3208: if (!parseRelationalExpr()) {
3209: fCurrentToken = saveToken;
3210: fCurrentParseOp = saveParseOp;
3211: return true;
3212: }
3213: int right = fCurrentParseOp;
3214: pushParseOp3(parseOp, left, right);
3215: }
3216: return true;
3217: }
3218:
3219: /**
3220: * [24] RelationalExpr ::= AdditiveExpr
3221: * | RelationalExpr '<' AdditiveExpr
3222: * | RelationalExpr '>' AdditiveExpr
3223: * | RelationalExpr '<=' AdditiveExpr
3224: * | RelationalExpr '>=' AdditiveExpr
3225: * /
3226: boolean parseRelationalExpr() throws XPathException {
3227: if (!parseAdditiveExpr()) {
3228: return false;
3229: }
3230: while (fCurrentToken < fTokenCount) {
3231: int parseOp;
3232: if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_OPERATOR_LESS) {
3233: parseOp = PARSEOP_LESS;
3234: } else if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_OPERATOR_GREATER) {
3235: parseOp = PARSEOP_GREATER;
3236: } else if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_OPERATOR_LESS_EQUAL) {
3237: parseOp = PARSEOP_LESS_EQUAL;
3238: } else if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_OPERATOR_GREATER_EQUAL) {
3239: parseOp = PARSEOP_GREATER_EQUAL;
3240: } else {
3241: break;
3242: }
3243: int saveToken = fCurrentToken;
3244: int saveParseOp = fCurrentParseOp;
3245: int left = fCurrentParseOp;
3246: if (++fCurrentToken == fTokenCount) {
3247: fCurrentToken = saveToken;
3248: fCurrentParseOp = saveParseOp;
3249: return true;
3250: }
3251: if (!parseAdditiveExpr()) {
3252: fCurrentToken = saveToken;
3253: fCurrentParseOp = saveParseOp;
3254: return true;
3255: }
3256: int right = fCurrentParseOp;
3257: pushParseOp3(parseOp, left, right);
3258: }
3259: return true;
3260: }
3261:
3262: /**
3263: * [25] AdditiveExpr ::= MultiplicativeExpr
3264: * | AdditiveExpr '+' MultiplicativeExpr
3265: * | AdditiveExpr '-' MultiplicativeExpr
3266: * /
3267: boolean parseAdditiveExpr() throws XPathException {
3268: if (!parseMultiplicativeExpr()) {
3269: return false;
3270: }
3271: while (fCurrentToken < fTokenCount) {
3272: int parseOp;
3273: if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_OPERATOR_PLUS) {
3274: parseOp = PARSEOP_PLUS;
3275: } else if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_OPERATOR_MINUS) {
3276: parseOp = PARSEOP_MINUS;
3277: } else {
3278: break;
3279: }
3280: int saveToken = fCurrentToken;
3281: int saveParseOp = fCurrentParseOp;
3282: int left = fCurrentParseOp;
3283: if (++fCurrentToken == fTokenCount) {
3284: fCurrentToken = saveToken;
3285: fCurrentParseOp = saveParseOp;
3286: return true;
3287: }
3288: if (!parseMultiplicativeExpr()) {
3289: fCurrentToken = saveToken;
3290: fCurrentParseOp = saveParseOp;
3291: return true;
3292: }
3293: int right = fCurrentParseOp;
3294: pushParseOp3(parseOp, left, right);
3295: }
3296: return true;
3297: }
3298:
3299: /**
3300: * [26] MultiplicativeExpr ::= UnaryExpr
3301: * | MultiplicativeExpr MultiplyOperator UnaryExpr
3302: * | MultiplicativeExpr 'div' UnaryExpr
3303: * | MultiplicativeExpr 'mod' UnaryExpr
3304: * [34] MultiplyOperator ::= '*'
3305: * /
3306: boolean parseMultiplicativeExpr() throws XPathException {
3307: if (!parseUnaryExpr()) {
3308: return false;
3309: }
3310: while (fCurrentToken < fTokenCount) {
3311: int parseOp;
3312: if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_OPERATOR_MULT) {
3313: parseOp = PARSEOP_MULT;
3314: } else if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_OPERATOR_DIV) {
3315: parseOp = PARSEOP_DIV;
3316: } else if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_OPERATOR_MOD) {
3317: parseOp = PARSEOP_MOD;
3318: } else {
3319: break;
3320: }
3321: int saveToken = fCurrentToken;
3322: int saveParseOp = fCurrentParseOp;
3323: int left = fCurrentParseOp;
3324: if (++fCurrentToken == fTokenCount) {
3325: fCurrentToken = saveToken;
3326: fCurrentParseOp = saveParseOp;
3327: return true;
3328: }
3329: if (!parseUnaryExpr()) {
3330: fCurrentToken = saveToken;
3331: fCurrentParseOp = saveParseOp;
3332: return true;
3333: }
3334: int right = fCurrentParseOp;
3335: pushParseOp3(parseOp, left, right);
3336: }
3337: return true;
3338: }
3339:
3340: /**
3341: * [27] UnaryExpr ::= UnionExpr | '-' UnaryExpr
3342: *
3343: * Note: "--UnionExpr" == "-(-UnionExpr)"
3344: * /
3345: boolean parseUnaryExpr() throws XPathException {
3346: if (parseUnionExpr()) {
3347: return true;
3348: }
3349: int saveToken = fCurrentToken;
3350: boolean negate = false;
3351: while (fCurrentToken < fTokenCount) {
3352: if (fTokens.getToken(fCurrentToken) != XPath.Tokens.EXPRTOKEN_OPERATOR_MINUS) {
3353: break;
3354: }
3355: fCurrentToken++;
3356: negate = !negate;
3357: }
3358: if (fCurrentToken == fTokenCount) {
3359: fCurrentToken = saveToken;
3360: return false;
3361: }
3362: if (!parseUnionExpr()) {
3363: fCurrentToken = saveToken;
3364: return false;
3365: }
3366: if (negate) {
3367: pushParseOp2(PARSEOP_NEGATE, fCurrentParseOp);
3368: }
3369: return true;
3370: }
3371:
3372: /**
3373: * [18] UnionExpr ::= PathExpr | UnionExpr '|' PathExpr
3374: * /
3375: boolean parseUnionExpr() throws XPathException {
3376: if (!parsePathExpr()) {
3377: return false;
3378: }
3379: while (fCurrentToken < fTokenCount) {
3380: if (fTokens.getToken(fCurrentToken) != XPath.Tokens.EXPRTOKEN_OPERATOR_UNION) {
3381: break;
3382: }
3383: int saveToken = fCurrentToken;
3384: int saveParseOp = fCurrentParseOp;
3385: int left = fCurrentParseOp;
3386: if (++fCurrentToken == fTokenCount) {
3387: fCurrentToken = saveToken;
3388: fCurrentParseOp = saveParseOp;
3389: return true;
3390: }
3391: if (!parsePathExpr()) {
3392: fCurrentToken = saveToken;
3393: fCurrentParseOp = saveParseOp;
3394: return true;
3395: }
3396: int right = fCurrentParseOp;
3397: pushParseOp3(PARSEOP_UNION, left, right);
3398: }
3399: return true;
3400: }
3401:
3402: /**
3403: * [19] PathExpr ::= RelativeLocationPath
3404: * | '/' RelativeLocationPath?
3405: * | '//' RelativeLocationPath
3406: * | PrimaryExpr Predicate*
3407: * | PrimaryExpr Predicate* '/' RelativeLocationPath
3408: * | PrimaryExpr Predicate* '//' RelativeLocationPath
3409: * /
3410: boolean parsePathExpr() throws XPathException {
3411: if (parseRelativeLocationPath()) {
3412: return true;
3413: } else {
3414: if (fCurrentToken == fTokenCount) {
3415: return false;
3416: }
3417: if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_OPERATOR_SLASH) {
3418: if (++fCurrentToken < fTokenCount && parseRelativeLocationPath()) {
3419: pushParseOp2(PARSEOP_SELECT_ROOT, fCurrentParseOp);
3420: } else {
3421: pushParseOp2(PARSEOP_SELECT_ROOT, -1);
3422: }
3423: return true;
3424: } else if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_OPERATOR_DOUBLE_SLASH) {
3425: if (++fCurrentToken == fTokenCount) {
3426: return false; // REVISIT - backup index
3427: }
3428: if (!parseRelativeLocationPath()) {
3429: return false;
3430: }
3431: int left = fCurrentParseOp;
3432: pushParseOp(PARSEOP_AXIS_DESCENDANT_OR_SELF);
3433: int left2 = fCurrentParseOp;
3434: pushParseOp(PARSEOP_NODETEST_NODE);
3435: pushParseOp3(PARSEOP_STEP, left2, fCurrentParseOp);
3436: pushParseOp3(PARSEOP_STEPS, fCurrentParseOp, left);
3437: pushParseOp2(PARSEOP_SELECT_ROOT, fCurrentParseOp);
3438: return true;
3439: }
3440: }
3441: if (!parsePrimaryExpr()) {
3442: return false;
3443: }
3444: int left = fCurrentParseOp;
3445: if (parsePredicates()) {
3446: pushParseOp3(PARSEOP_FILTER, left, fCurrentParseOp);
3447: }
3448: if (fCurrentToken == fTokenCount) {
3449: return true;
3450: }
3451: left = fCurrentParseOp;
3452: if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_OPERATOR_SLASH) {
3453: if (++fCurrentToken == fTokenCount) {
3454: return false; // REVISIT
3455: }
3456: if (!parseRelativeLocationPath()) {
3457: return false; // REVISIT
3458: }
3459: pushParseOp3(PARSEOP_STEPS, left, fCurrentParseOp);
3460: } else if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_OPERATOR_DOUBLE_SLASH) {
3461: if (++fCurrentToken == fTokenCount) {
3462: return false;
3463: }
3464: if (!parseRelativeLocationPath()) {
3465: return false;
3466: }
3467: int left2 = fCurrentParseOp;
3468: pushParseOp(PARSEOP_AXIS_DESCENDANT_OR_SELF);
3469: int left3 = fCurrentParseOp;
3470: pushParseOp(PARSEOP_NODETEST_NODE);
3471: pushParseOp3(PARSEOP_STEP, left3, fCurrentParseOp);
3472: pushParseOp3(PARSEOP_STEPS, fCurrentParseOp, left2);
3473: pushParseOp3(PARSEOP_STEPS, left, fCurrentParseOp);
3474: }
3475: return true;
3476: }
3477:
3478: /**
3479: * [3] RelativeLocationPath ::= Step
3480: * | RelativeLocationPath '/' Step
3481: * | RelativeLocationPath '//' Step
3482: * /
3483: boolean parseRelativeLocationPath() throws XPathException {
3484: if (!parseStep()) {
3485: return false;
3486: }
3487: while (fCurrentToken < fTokenCount) {
3488: boolean descendantOrSelf;
3489: if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_OPERATOR_SLASH) {
3490: descendantOrSelf = false;
3491: } else if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_OPERATOR_DOUBLE_SLASH) {
3492: descendantOrSelf = true;
3493: } else {
3494: break;
3495: }
3496: int saveToken = fCurrentToken;
3497: int saveParseOp = fCurrentParseOp;
3498: int left = fCurrentParseOp;
3499: if (++fCurrentToken == fTokenCount) {
3500: fCurrentToken = saveToken;
3501: fCurrentParseOp = saveParseOp;
3502: return true;
3503: }
3504: if (!parseStep()) {
3505: fCurrentToken = saveToken;
3506: fCurrentParseOp = saveParseOp;
3507: return true;
3508: }
3509: if (descendantOrSelf) {
3510: int left2 = fCurrentParseOp;
3511: pushParseOp(PARSEOP_AXIS_DESCENDANT_OR_SELF);
3512: int left3 = fCurrentParseOp;
3513: pushParseOp(PARSEOP_NODETEST_NODE);
3514: pushParseOp3(PARSEOP_STEP, left3, fCurrentParseOp);
3515: pushParseOp3(PARSEOP_STEPS, left, fCurrentParseOp);
3516: pushParseOp3(PARSEOP_STEPS, fCurrentParseOp, left2);
3517: } else {
3518: pushParseOp3(PARSEOP_STEPS, left, fCurrentParseOp);
3519: }
3520: }
3521: return true;
3522: }
3523:
3524: /**
3525: * [4] Step ::= (AxisName '::' | '@'?) NodeTest Predicate* | '.' | '..'
3526: * [6] AxisName ::= 'ancestor' | 'ancestor-or-self'
3527: * | 'attribute'
3528: * | 'child'
3529: * | 'descendant' | 'descendant-or-self'
3530: * | 'following' | 'following-sibling'
3531: * | 'namespace'
3532: * | 'parent'
3533: * | 'preceding' | 'preceding-sibling'
3534: * | 'self'
3535: * /
3536: boolean parseStep() throws XPathException {
3537: int parseOp;
3538: int left;
3539: boolean checkDoubleColon = true;
3540: int saveToken = fCurrentToken;
3541: int saveParseOp = fCurrentParseOp;
3542: if (fCurrentToken == fTokenCount) {
3543: return false;
3544: }
3545: switch (fTokens.getToken(fCurrentToken)) {
3546: case XPath.Tokens.EXPRTOKEN_PERIOD:
3547: fCurrentToken++;
3548: pushParseOp(PARSEOP_AXIS_SELF);
3549: left = fCurrentParseOp;
3550: pushParseOp(PARSEOP_NODETEST_NODE);
3551: pushParseOp3(PARSEOP_STEP, left, fCurrentParseOp);
3552: return true;
3553: case XPath.Tokens.EXPRTOKEN_DOUBLE_PERIOD:
3554: fCurrentToken++;
3555: pushParseOp(PARSEOP_AXIS_PARENT);
3556: left = fCurrentParseOp;
3557: pushParseOp(PARSEOP_NODETEST_NODE);
3558: pushParseOp3(PARSEOP_STEP, left, fCurrentParseOp);
3559: return true;
3560: case XPath.Tokens.EXPRTOKEN_AXISNAME_ANCESTOR:
3561: fCurrentToken++;
3562: parseOp = PARSEOP_AXIS_ANCESTOR;
3563: break;
3564: case XPath.Tokens.EXPRTOKEN_AXISNAME_ANCESTOR_OR_SELF:
3565: fCurrentToken++;
3566: parseOp = PARSEOP_AXIS_ANCESTOR_OR_SELF;
3567: break;
3568: case XPath.Tokens.EXPRTOKEN_ATSIGN:
3569: checkDoubleColon = false;
3570: // fall through
3571: case XPath.Tokens.EXPRTOKEN_AXISNAME_ATTRIBUTE:
3572: fCurrentToken++;
3573: parseOp = PARSEOP_AXIS_ATTRIBUTE;
3574: break;
3575: case XPath.Tokens.EXPRTOKEN_AXISNAME_DESCENDANT:
3576: fCurrentToken++;
3577: parseOp = PARSEOP_AXIS_DESCENDANT;
3578: break;
3579: case XPath.Tokens.EXPRTOKEN_AXISNAME_DESCENDANT_OR_SELF:
3580: fCurrentToken++;
3581: parseOp = PARSEOP_AXIS_DESCENDANT_OR_SELF;
3582: break;
3583: case XPath.Tokens.EXPRTOKEN_AXISNAME_FOLLOWING:
3584: fCurrentToken++;
3585: parseOp = PARSEOP_AXIS_FOLLOWING;
3586: break;
3587: case XPath.Tokens.EXPRTOKEN_AXISNAME_FOLLOWING_SIBLING:
3588: fCurrentToken++;
3589: parseOp = PARSEOP_AXIS_FOLLOWING_SIBLING;
3590: break;
3591: case XPath.Tokens.EXPRTOKEN_AXISNAME_NAMESPACE:
3592: fCurrentToken++;
3593: parseOp = PARSEOP_AXIS_NAMESPACE;
3594: break;
3595: case XPath.Tokens.EXPRTOKEN_AXISNAME_PARENT:
3596: fCurrentToken++;
3597: parseOp = PARSEOP_AXIS_PARENT;
3598: break;
3599: case XPath.Tokens.EXPRTOKEN_AXISNAME_PRECEDING:
3600: fCurrentToken++;
3601: parseOp = PARSEOP_AXIS_PRECEDING;
3602: break;
3603: case XPath.Tokens.EXPRTOKEN_AXISNAME_PRECEDING_SIBLING:
3604: fCurrentToken++;
3605: parseOp = PARSEOP_AXIS_PRECEDING_SIBLING;
3606: break;
3607: case XPath.Tokens.EXPRTOKEN_AXISNAME_SELF:
3608: fCurrentToken++;
3609: parseOp = PARSEOP_AXIS_SELF;
3610: break;
3611: case XPath.Tokens.EXPRTOKEN_AXISNAME_CHILD:
3612: fCurrentToken++;
3613: parseOp = PARSEOP_AXIS_CHILD;
3614: break;
3615: default:
3616: checkDoubleColon = false;
3617: parseOp = PARSEOP_AXIS_CHILD;
3618: break;
3619: }
3620: pushParseOp(parseOp);
3621: left = fCurrentParseOp;
3622: if (checkDoubleColon) {
3623: if (fCurrentToken == fTokenCount) {
3624: fCurrentToken = saveToken;
3625: fCurrentParseOp = saveParseOp;
3626: return false;
3627: }
3628: if (fTokens.getToken(fCurrentToken) != XPath.Tokens.EXPRTOKEN_DOUBLE_COLON) {
3629: fCurrentToken = saveToken;
3630: fCurrentParseOp = saveParseOp;
3631: return false;
3632: }
3633: fCurrentToken++;
3634: }
3635: if (fCurrentToken == fTokenCount) {
3636: fCurrentToken = saveToken;
3637: fCurrentParseOp = saveParseOp;
3638: return false;
3639: }
3640: if (!parseNodeTest()) {
3641: fCurrentToken = saveToken;
3642: fCurrentParseOp = saveParseOp;
3643: return false;
3644: }
3645: pushParseOp3(PARSEOP_STEP, left, fCurrentParseOp);
3646: left = fCurrentParseOp;
3647: if (parsePredicates()) {
3648: pushParseOp3(PARSEOP_FILTER, left, fCurrentParseOp);
3649: }
3650: return true;
3651: }
3652:
3653: /**
3654: * [7] NodeTest ::= '*'
3655: * | NCName ':' '*'
3656: * | QName
3657: * | 'comment' '(' ')'
3658: * | 'text' '(' ')'
3659: * | 'processing-instruction' '(' Literal? ')'
3660: * | 'node' '(' ')'
3661: * [29] Literal ::= '"' [^"]* '"' | "'" [^']* "'"
3662: * /
3663: boolean parseNodeTest() throws XPathException {
3664: int parseOp;
3665: int prefix;
3666: int name;
3667: if (fCurrentToken == fTokenCount) {
3668: return false;
3669: }
3670: switch (fTokens.getToken(fCurrentToken)) {
3671: case XPath.Tokens.EXPRTOKEN_NAMETEST_ANY:
3672: fCurrentToken++;
3673: pushParseOp(PARSEOP_NODETEST_ANY);
3674: return true;
3675: case XPath.Tokens.EXPRTOKEN_NAMETEST_NAMESPACE:
3676: prefix = fTokens.getToken(++fCurrentToken);
3677: fCurrentToken++;
3678: pushParseOp2(PARSEOP_NODETEST_NAMESPACE, prefix);
3679: return true;
3680: case XPath.Tokens.EXPRTOKEN_NAMETEST_QNAME:
3681: prefix = fTokens.getToken(++fCurrentToken);
3682: name = fTokens.getToken(++fCurrentToken);
3683: fCurrentToken++;
3684: pushParseOp3(PARSEOP_NODETEST_QNAME, prefix, name);
3685: return true;
3686: case XPath.Tokens.EXPRTOKEN_NODETYPE_COMMENT:
3687: parseOp = PARSEOP_NODETEST_COMMENT;
3688: break;
3689: case XPath.Tokens.EXPRTOKEN_NODETYPE_TEXT:
3690: parseOp = PARSEOP_NODETEST_TEXT;
3691: break;
3692: case XPath.Tokens.EXPRTOKEN_NODETYPE_PI:
3693: parseOp = PARSEOP_NODETEST_PI;
3694: break;
3695: case XPath.Tokens.EXPRTOKEN_NODETYPE_NODE:
3696: parseOp = PARSEOP_NODETEST_NODE;
3697: break;
3698: default:
3699: return false;
3700: }
3701: int saveToken = fCurrentToken;
3702: int saveParseOp = fCurrentParseOp;
3703: int left = fCurrentParseOp;
3704: if (++fCurrentToken == fTokenCount) {
3705: fCurrentToken = saveToken;
3706: fCurrentParseOp = saveParseOp;
3707: return false;
3708: }
3709: if (fTokens.getToken(fCurrentToken) != XPath.Tokens.EXPRTOKEN_OPEN_PAREN) {
3710: fCurrentToken = saveToken;
3711: fCurrentParseOp = saveParseOp;
3712: return false;
3713: }
3714: if (++fCurrentToken == fTokenCount) {
3715: fCurrentToken = saveToken;
3716: fCurrentParseOp = saveParseOp;
3717: return false;
3718: }
3719: if (parseOp == PARSEOP_NODETEST_PI && fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_LITERAL) {
3720: int target = fTokens.getToken(++fCurrentToken);
3721: if (++fCurrentToken == fTokenCount) {
3722: fCurrentToken = saveToken;
3723: fCurrentParseOp = saveParseOp;
3724: return false;
3725: }
3726: if (fTokens.getToken(fCurrentToken) != XPath.Tokens.EXPRTOKEN_CLOSE_PAREN) {
3727: fCurrentToken = saveToken;
3728: fCurrentParseOp = saveParseOp;
3729: return false;
3730: }
3731: fCurrentToken++;
3732: pushParseOp2(PARSEOP_NODETEST_PI_TARGET, target);
3733: } else {
3734: if (fTokens.getToken(fCurrentToken) != XPath.Tokens.EXPRTOKEN_CLOSE_PAREN) {
3735: fCurrentToken = saveToken;
3736: fCurrentParseOp = saveParseOp;
3737: return false;
3738: }
3739: fCurrentToken++;
3740: pushParseOp(parseOp);
3741: }
3742: return true;
3743: }
3744:
3745: /**
3746: * [8] Predicate ::= '[' PredicateExpr ']'
3747: * [9] PredicateExpr ::= Expr
3748: * [4] Step ::= AxisSpecifier NodeTest Predicate* | AbbreviatedStep
3749: * [20] FilterExpr ::= PrimaryExpr Predicate*
3750: * /
3751: boolean parsePredicates() throws XPathException {
3752: int left = -1;
3753: boolean found = false;
3754: while (true) {
3755: if (fCurrentToken == fTokenCount || fTokens.getToken(fCurrentToken) != XPath.Tokens.EXPRTOKEN_OPEN_BRACKET) {
3756: return found;
3757: }
3758: int saveToken = fCurrentToken;
3759: int saveParseOp = fCurrentParseOp;
3760: if (++fCurrentToken == fTokenCount || !parseExpr() ||
3761: fCurrentToken == fTokenCount || fTokens.getToken(fCurrentToken) != XPath.Tokens.EXPRTOKEN_CLOSE_BRACKET) {
3762: fCurrentToken = saveToken;
3763: fCurrentParseOp = saveParseOp;
3764: return found;
3765: }
3766: fCurrentToken++;
3767: found = true;
3768: pushParseOp2(PARSEOP_PREDICATE, fCurrentParseOp);
3769: if (left != -1) {
3770: pushParseOp3(PARSEOP_PREDICATES, left, fCurrentParseOp);
3771: }
3772: left = fCurrentParseOp;
3773: }
3774: }
3775:
3776: /**
3777: * [15] PrimaryExpr ::= '$' QName
3778: * | '(' Expr ')'
3779: * | '"' [^"]* '"' | "'" [^']* "'"
3780: * | ([0-9]+) ('.' ([0-9]+)?)? | '.' Digits
3781: * | (QName - NodeType) '(' ( Expr ( ',' Expr )* )? ')'
3782: * /
3783: boolean parsePrimaryExpr() throws XPathException {
3784: int prefix;
3785: int handle;
3786: int saveToken;
3787: int saveParseOp;
3788: if (fCurrentToken == fTokenCount) {
3789: return false;
3790: }
3791: switch (fTokens.getToken(fCurrentToken)) {
3792: case XPath.Tokens.EXPRTOKEN_VARIABLE_REFERENCE:
3793: prefix = fTokens.getToken(++fCurrentToken);
3794: handle = fTokens.getToken(++fCurrentToken); // localpart
3795: fCurrentToken++;
3796: pushParseOp3(PARSEOP_VARIABLE_REFERENCE, prefix, handle);
3797: break;
3798: case XPath.Tokens.EXPRTOKEN_OPEN_PAREN:
3799: saveToken = fCurrentToken;
3800: saveParseOp = fCurrentParseOp;
3801: if (++fCurrentToken == fTokenCount) {
3802: fCurrentToken = saveToken;
3803: fCurrentParseOp = saveParseOp;
3804: return false;
3805: }
3806: if (!parseExpr()) {
3807: fCurrentToken = saveToken;
3808: fCurrentParseOp = saveParseOp;
3809: return false;
3810: }
3811: if (fCurrentToken == fTokenCount) {
3812: fCurrentToken = saveToken;
3813: fCurrentParseOp = saveParseOp;
3814: return false;
3815: }
3816: if (fTokens.getToken(fCurrentToken) != XPath.Tokens.EXPRTOKEN_CLOSE_PAREN) {
3817: fCurrentToken = saveToken;
3818: fCurrentParseOp = saveParseOp;
3819: return false;
3820: }
3821: fCurrentToken++;
3822: pushParseOp2(PARSEOP_GROUPING, fCurrentParseOp);
3823: break;
3824: case XPath.Tokens.EXPRTOKEN_LITERAL:
3825: handle = fTokens.getToken(++fCurrentToken);
3826: fCurrentToken++;
3827: pushParseOp2(PARSEOP_LITERAL, handle);
3828: break;
3829: case XPath.Tokens.EXPRTOKEN_NUMBER:
3830: int whole = fTokens.getToken(++fCurrentToken);
3831: int part = fTokens.getToken(++fCurrentToken);
3832: fCurrentToken++;
3833: pushParseOp3(PARSEOP_NUMBER, whole, part);
3834: break;
3835: case XPath.Tokens.EXPRTOKEN_FUNCTION_NAME:
3836: saveToken = fCurrentToken;
3837: saveParseOp = fCurrentParseOp;
3838: prefix = fTokens.getToken(++fCurrentToken);
3839: handle = fTokens.getToken(++fCurrentToken); // localpart
3840: fCurrentToken++;
3841: pushParseOp3(PARSEOP_FUNCTION_NAME, prefix, handle);
3842: if (fTokens.getToken(fCurrentToken) != XPath.Tokens.EXPRTOKEN_OPEN_PAREN) {
3843: fCurrentToken = saveToken;
3844: fCurrentParseOp = saveParseOp;
3845: return false;
3846: }
3847: fCurrentToken++;
3848: int funcName = fCurrentParseOp;
3849: int nextArg = -1;
3850: if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_CLOSE_PAREN) {
3851: fCurrentToken++;
3852: } else {
3853: while (true) {
3854: if (!parseExpr()) {
3855: fCurrentToken = saveToken;
3856: fCurrentParseOp = saveParseOp;
3857: return false;
3858: }
3859: if (nextArg != -1) {
3860: pushParseOp3(PARSEOP_FUNCTION_ARGUMENTS, nextArg, fCurrentParseOp);
3861: }
3862: nextArg = fCurrentParseOp;
3863: if (fTokens.getToken(fCurrentToken) == XPath.Tokens.EXPRTOKEN_CLOSE_PAREN) {
3864: fCurrentToken++;
3865: break;
3866: }
3867: if (fTokens.getToken(fCurrentToken) != XPath.Tokens.EXPRTOKEN_COMMA) {
3868: fCurrentToken = saveToken;
3869: fCurrentParseOp = saveParseOp;
3870: return false;
3871: }
3872: fCurrentToken++;
3873: }
3874: }
3875: pushParseOp3(PARSEOP_FUNCTION, funcName, nextArg);
3876: break;
3877: default:
3878: return false;
3879: }
3880: return true;
3881: }
3882:
3883: //
3884: // MAIN
3885: //
3886:
3887: public static void main(String argv[]) {
3888: for (int i = 0; i < argv.length; i++) {
3889: String expression = argv[i];
3890: System.out.println("# XPath expression: "+expression);
3891: XPathExprParser parser = new XPathExprParser();
3892: try {
3893: parser.parseExpr(expression);
3894: }
3895: catch (Exception e) {
3896: e.printStackTrace();
3897: }
3898: }
3899: }
3900:
3901: } // class XPathExprParser
3902: /***/
3903:
3904: //
3905: // MAIN
3906: //
3907: /** Main program entry. */
3908: public static void main(String[] argv) throws Exception {
3909:
3910: for (int i = 0; i < argv.length; i++) {
3911: final String expression = argv[i];
3912: System.out.println("# XPath expression: \"" + expression
3913: + '"');
3914: try {
3915: StringPool stringPool = new StringPool();
3916: XPath xpath = new XPath(expression, stringPool, null);
3917: System.out.println("expanded xpath: \""
3918: + xpath.toString() + '"');
3919: } catch (XPathException e) {
3920: System.out.println("error: " + e.getMessage());
3921: }
3922: }
3923:
3924: } // main(String[])
3925:
3926: /** Location paths. */
3927: protected LocationPath[] fLocationPaths; //
3928:
3929: // Public methods
3930: //
3931:
3932: /** Returns a representation of all location paths for this XPath.
3933: XPath = locationPath ( '|' locationPath)*
3934: */
3935: public LocationPath[] getLocationPaths() {
3936: LocationPath[] ret = new LocationPath[fLocationPaths.length];
3937: for (int i = 0; i < fLocationPaths.length; i++) {
3938: ret[i] = (LocationPath) fLocationPaths[i].clone();
3939: }
3940: return ret;
3941: } // getLocationPath(LocationPath)
3942: } // class XPath
|