0001: /*
0002: * Copyright 1999-2004 The Apache Software Foundation.
0003: *
0004: * Licensed under the Apache License, Version 2.0 (the "License");
0005: * you may not use this file except in compliance with the License.
0006: * You may obtain a copy of the License at
0007: *
0008: * http://www.apache.org/licenses/LICENSE-2.0
0009: *
0010: * Unless required by applicable law or agreed to in writing, software
0011: * distributed under the License is distributed on an "AS IS" BASIS,
0012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013: * See the License for the specific language governing permissions and
0014: * limitations under the License.
0015: */
0016: /*
0017: * $Id: Compiler.java,v 1.41 2005/05/17 21:25:46 jycli Exp $
0018: */
0019: package org.apache.xpath.compiler;
0020:
0021: import javax.xml.transform.ErrorListener;
0022: import javax.xml.transform.SourceLocator;
0023: import javax.xml.transform.TransformerException;
0024:
0025: import org.apache.xalan.res.XSLMessages;
0026: import org.apache.xml.dtm.Axis;
0027: import org.apache.xml.dtm.DTMFilter;
0028: import org.apache.xml.dtm.DTMIterator;
0029: import org.apache.xml.utils.PrefixResolver;
0030: import org.apache.xml.utils.QName;
0031: import org.apache.xml.utils.SAXSourceLocator;
0032: import org.apache.xpath.Expression;
0033: import org.apache.xpath.axes.UnionPathIterator;
0034: import org.apache.xpath.axes.WalkerFactory;
0035: import org.apache.xpath.functions.FuncExtFunction;
0036: import org.apache.xpath.functions.FuncExtFunctionAvailable;
0037: import org.apache.xpath.functions.Function;
0038: import org.apache.xpath.functions.WrongNumberArgsException;
0039: import org.apache.xpath.objects.XNumber;
0040: import org.apache.xpath.objects.XString;
0041: import org.apache.xpath.operations.And;
0042: import org.apache.xpath.operations.Div;
0043: import org.apache.xpath.operations.Equals;
0044: import org.apache.xpath.operations.Gt;
0045: import org.apache.xpath.operations.Gte;
0046: import org.apache.xpath.operations.Lt;
0047: import org.apache.xpath.operations.Lte;
0048: import org.apache.xpath.operations.Minus;
0049: import org.apache.xpath.operations.Mod;
0050: import org.apache.xpath.operations.Mult;
0051: import org.apache.xpath.operations.Neg;
0052: import org.apache.xpath.operations.NotEquals;
0053: import org.apache.xpath.operations.Operation;
0054: import org.apache.xpath.operations.Or;
0055: import org.apache.xpath.operations.Plus;
0056: import org.apache.xpath.operations.UnaryOperation;
0057: import org.apache.xpath.operations.Variable;
0058: import org.apache.xpath.patterns.FunctionPattern;
0059: import org.apache.xpath.patterns.NodeTest;
0060: import org.apache.xpath.patterns.StepPattern;
0061: import org.apache.xpath.patterns.UnionPattern;
0062: import org.apache.xpath.res.XPATHErrorResources;
0063:
0064: /**
0065: * An instance of this class compiles an XPath string expression into
0066: * a Expression object. This class compiles the string into a sequence
0067: * of operation codes (op map) and then builds from that into an Expression
0068: * tree.
0069: * @xsl.usage advanced
0070: */
0071: public class Compiler extends OpMap {
0072:
0073: /**
0074: * Construct a Compiler object with a specific ErrorListener and
0075: * SourceLocator where the expression is located.
0076: *
0077: * @param errorHandler Error listener where messages will be sent, or null
0078: * if messages should be sent to System err.
0079: * @param locator The location object where the expression lives, which
0080: * may be null, but which, if not null, must be valid over
0081: * the long haul, in other words, it will not be cloned.
0082: * @param fTable The FunctionTable object where the xpath build-in
0083: * functions are stored.
0084: */
0085: public Compiler(ErrorListener errorHandler, SourceLocator locator,
0086: FunctionTable fTable) {
0087: m_errorHandler = errorHandler;
0088: m_locator = locator;
0089: m_functionTable = fTable;
0090: }
0091:
0092: /**
0093: * Construct a Compiler instance that has a null error listener and a
0094: * null source locator.
0095: */
0096: public Compiler() {
0097: m_errorHandler = null;
0098: m_locator = null;
0099: }
0100:
0101: /**
0102: * Execute the XPath object from a given opcode position.
0103: * @param opPos The current position in the xpath.m_opMap array.
0104: * @return The result of the XPath.
0105: *
0106: * @throws TransformerException if there is a syntax or other error.
0107: * @xsl.usage advanced
0108: */
0109: public Expression compile(int opPos) throws TransformerException {
0110:
0111: int op = getOp(opPos);
0112:
0113: Expression expr = null;
0114: // System.out.println(getPatternString()+"op: "+op);
0115: switch (op) {
0116: case OpCodes.OP_XPATH:
0117: expr = compile(opPos + 2);
0118: break;
0119: case OpCodes.OP_OR:
0120: expr = or(opPos);
0121: break;
0122: case OpCodes.OP_AND:
0123: expr = and(opPos);
0124: break;
0125: case OpCodes.OP_NOTEQUALS:
0126: expr = notequals(opPos);
0127: break;
0128: case OpCodes.OP_EQUALS:
0129: expr = equals(opPos);
0130: break;
0131: case OpCodes.OP_LTE:
0132: expr = lte(opPos);
0133: break;
0134: case OpCodes.OP_LT:
0135: expr = lt(opPos);
0136: break;
0137: case OpCodes.OP_GTE:
0138: expr = gte(opPos);
0139: break;
0140: case OpCodes.OP_GT:
0141: expr = gt(opPos);
0142: break;
0143: case OpCodes.OP_PLUS:
0144: expr = plus(opPos);
0145: break;
0146: case OpCodes.OP_MINUS:
0147: expr = minus(opPos);
0148: break;
0149: case OpCodes.OP_MULT:
0150: expr = mult(opPos);
0151: break;
0152: case OpCodes.OP_DIV:
0153: expr = div(opPos);
0154: break;
0155: case OpCodes.OP_MOD:
0156: expr = mod(opPos);
0157: break;
0158: // case OpCodes.OP_QUO :
0159: // expr = quo(opPos); break;
0160: case OpCodes.OP_NEG:
0161: expr = neg(opPos);
0162: break;
0163: case OpCodes.OP_STRING:
0164: expr = string(opPos);
0165: break;
0166: case OpCodes.OP_BOOL:
0167: expr = bool(opPos);
0168: break;
0169: case OpCodes.OP_NUMBER:
0170: expr = number(opPos);
0171: break;
0172: case OpCodes.OP_UNION:
0173: expr = union(opPos);
0174: break;
0175: case OpCodes.OP_LITERAL:
0176: expr = literal(opPos);
0177: break;
0178: case OpCodes.OP_VARIABLE:
0179: expr = variable(opPos);
0180: break;
0181: case OpCodes.OP_GROUP:
0182: expr = group(opPos);
0183: break;
0184: case OpCodes.OP_NUMBERLIT:
0185: expr = numberlit(opPos);
0186: break;
0187: case OpCodes.OP_ARGUMENT:
0188: expr = arg(opPos);
0189: break;
0190: case OpCodes.OP_EXTFUNCTION:
0191: expr = compileExtension(opPos);
0192: break;
0193: case OpCodes.OP_FUNCTION:
0194: expr = compileFunction(opPos);
0195: break;
0196: case OpCodes.OP_LOCATIONPATH:
0197: expr = locationPath(opPos);
0198: break;
0199: case OpCodes.OP_PREDICATE:
0200: expr = null;
0201: break; // should never hit this here.
0202: case OpCodes.OP_MATCHPATTERN:
0203: expr = matchPattern(opPos + 2);
0204: break;
0205: case OpCodes.OP_LOCATIONPATHPATTERN:
0206: expr = locationPathPattern(opPos);
0207: break;
0208: case OpCodes.OP_QUO:
0209: error(XPATHErrorResources.ER_UNKNOWN_OPCODE,
0210: new Object[] { "quo" }); //"ERROR! Unknown op code: "+m_opMap[opPos]);
0211: break;
0212: default:
0213: error(XPATHErrorResources.ER_UNKNOWN_OPCODE,
0214: new Object[] { Integer.toString(getOp(opPos)) }); //"ERROR! Unknown op code: "+m_opMap[opPos]);
0215: }
0216: // if(null != expr)
0217: // expr.setSourceLocator(m_locator);
0218:
0219: return expr;
0220: }
0221:
0222: /**
0223: * Bottle-neck compilation of an operation with left and right operands.
0224: *
0225: * @param operation non-null reference to parent operation.
0226: * @param opPos The op map position of the parent operation.
0227: *
0228: * @return reference to {@link org.apache.xpath.operations.Operation} instance.
0229: *
0230: * @throws TransformerException if there is a syntax or other error.
0231: */
0232: private Expression compileOperation(Operation operation, int opPos)
0233: throws TransformerException {
0234:
0235: int leftPos = getFirstChildPos(opPos);
0236: int rightPos = getNextOpPos(leftPos);
0237:
0238: operation.setLeftRight(compile(leftPos), compile(rightPos));
0239:
0240: return operation;
0241: }
0242:
0243: /**
0244: * Bottle-neck compilation of a unary operation.
0245: *
0246: * @param unary The parent unary operation.
0247: * @param opPos The position in the op map of the parent operation.
0248: *
0249: * @return The unary argument.
0250: *
0251: * @throws TransformerException if syntax or other error occurs.
0252: */
0253: private Expression compileUnary(UnaryOperation unary, int opPos)
0254: throws TransformerException {
0255:
0256: int rightPos = getFirstChildPos(opPos);
0257:
0258: unary.setRight(compile(rightPos));
0259:
0260: return unary;
0261: }
0262:
0263: /**
0264: * Compile an 'or' operation.
0265: *
0266: * @param opPos The current position in the m_opMap array.
0267: *
0268: * @return reference to {@link org.apache.xpath.operations.Or} instance.
0269: *
0270: * @throws TransformerException if a error occurs creating the Expression.
0271: */
0272: protected Expression or(int opPos) throws TransformerException {
0273: return compileOperation(new Or(), opPos);
0274: }
0275:
0276: /**
0277: * Compile an 'and' operation.
0278: *
0279: * @param opPos The current position in the m_opMap array.
0280: *
0281: * @return reference to {@link org.apache.xpath.operations.And} instance.
0282: *
0283: * @throws TransformerException if a error occurs creating the Expression.
0284: */
0285: protected Expression and(int opPos) throws TransformerException {
0286: return compileOperation(new And(), opPos);
0287: }
0288:
0289: /**
0290: * Compile a '!=' operation.
0291: *
0292: * @param opPos The current position in the m_opMap array.
0293: *
0294: * @return reference to {@link org.apache.xpath.operations.NotEquals} instance.
0295: *
0296: * @throws TransformerException if a error occurs creating the Expression.
0297: */
0298: protected Expression notequals(int opPos)
0299: throws TransformerException {
0300: return compileOperation(new NotEquals(), opPos);
0301: }
0302:
0303: /**
0304: * Compile a '=' operation.
0305: *
0306: * @param opPos The current position in the m_opMap array.
0307: *
0308: * @return reference to {@link org.apache.xpath.operations.Equals} instance.
0309: *
0310: * @throws TransformerException if a error occurs creating the Expression.
0311: */
0312: protected Expression equals(int opPos) throws TransformerException {
0313: return compileOperation(new Equals(), opPos);
0314: }
0315:
0316: /**
0317: * Compile a '<=' operation.
0318: *
0319: * @param opPos The current position in the m_opMap array.
0320: *
0321: * @return reference to {@link org.apache.xpath.operations.Lte} instance.
0322: *
0323: * @throws TransformerException if a error occurs creating the Expression.
0324: */
0325: protected Expression lte(int opPos) throws TransformerException {
0326: return compileOperation(new Lte(), opPos);
0327: }
0328:
0329: /**
0330: * Compile a '<' operation.
0331: *
0332: * @param opPos The current position in the m_opMap array.
0333: *
0334: * @return reference to {@link org.apache.xpath.operations.Lt} instance.
0335: *
0336: * @throws TransformerException if a error occurs creating the Expression.
0337: */
0338: protected Expression lt(int opPos) throws TransformerException {
0339: return compileOperation(new Lt(), opPos);
0340: }
0341:
0342: /**
0343: * Compile a '>=' operation.
0344: *
0345: * @param opPos The current position in the m_opMap array.
0346: *
0347: * @return reference to {@link org.apache.xpath.operations.Gte} instance.
0348: *
0349: * @throws TransformerException if a error occurs creating the Expression.
0350: */
0351: protected Expression gte(int opPos) throws TransformerException {
0352: return compileOperation(new Gte(), opPos);
0353: }
0354:
0355: /**
0356: * Compile a '>' operation.
0357: *
0358: * @param opPos The current position in the m_opMap array.
0359: *
0360: * @return reference to {@link org.apache.xpath.operations.Gt} instance.
0361: *
0362: * @throws TransformerException if a error occurs creating the Expression.
0363: */
0364: protected Expression gt(int opPos) throws TransformerException {
0365: return compileOperation(new Gt(), opPos);
0366: }
0367:
0368: /**
0369: * Compile a '+' operation.
0370: *
0371: * @param opPos The current position in the m_opMap array.
0372: *
0373: * @return reference to {@link org.apache.xpath.operations.Plus} instance.
0374: *
0375: * @throws TransformerException if a error occurs creating the Expression.
0376: */
0377: protected Expression plus(int opPos) throws TransformerException {
0378: return compileOperation(new Plus(), opPos);
0379: }
0380:
0381: /**
0382: * Compile a '-' operation.
0383: *
0384: * @param opPos The current position in the m_opMap array.
0385: *
0386: * @return reference to {@link org.apache.xpath.operations.Minus} instance.
0387: *
0388: * @throws TransformerException if a error occurs creating the Expression.
0389: */
0390: protected Expression minus(int opPos) throws TransformerException {
0391: return compileOperation(new Minus(), opPos);
0392: }
0393:
0394: /**
0395: * Compile a '*' operation.
0396: *
0397: * @param opPos The current position in the m_opMap array.
0398: *
0399: * @return reference to {@link org.apache.xpath.operations.Mult} instance.
0400: *
0401: * @throws TransformerException if a error occurs creating the Expression.
0402: */
0403: protected Expression mult(int opPos) throws TransformerException {
0404: return compileOperation(new Mult(), opPos);
0405: }
0406:
0407: /**
0408: * Compile a 'div' operation.
0409: *
0410: * @param opPos The current position in the m_opMap array.
0411: *
0412: * @return reference to {@link org.apache.xpath.operations.Div} instance.
0413: *
0414: * @throws TransformerException if a error occurs creating the Expression.
0415: */
0416: protected Expression div(int opPos) throws TransformerException {
0417: return compileOperation(new Div(), opPos);
0418: }
0419:
0420: /**
0421: * Compile a 'mod' operation.
0422: *
0423: * @param opPos The current position in the m_opMap array.
0424: *
0425: * @return reference to {@link org.apache.xpath.operations.Mod} instance.
0426: *
0427: * @throws TransformerException if a error occurs creating the Expression.
0428: */
0429: protected Expression mod(int opPos) throws TransformerException {
0430: return compileOperation(new Mod(), opPos);
0431: }
0432:
0433: /*
0434: * Compile a 'quo' operation.
0435: *
0436: * @param opPos The current position in the m_opMap array.
0437: *
0438: * @return reference to {@link org.apache.xpath.operations.Quo} instance.
0439: *
0440: * @throws TransformerException if a error occurs creating the Expression.
0441: */
0442: // protected Expression quo(int opPos) throws TransformerException
0443: // {
0444: // return compileOperation(new Quo(), opPos);
0445: // }
0446: /**
0447: * Compile a unary '-' operation.
0448: *
0449: * @param opPos The current position in the m_opMap array.
0450: *
0451: * @return reference to {@link org.apache.xpath.operations.Neg} instance.
0452: *
0453: * @throws TransformerException if a error occurs creating the Expression.
0454: */
0455: protected Expression neg(int opPos) throws TransformerException {
0456: return compileUnary(new Neg(), opPos);
0457: }
0458:
0459: /**
0460: * Compile a 'string(...)' operation.
0461: *
0462: * @param opPos The current position in the m_opMap array.
0463: *
0464: * @return reference to {@link org.apache.xpath.operations.String} instance.
0465: *
0466: * @throws TransformerException if a error occurs creating the Expression.
0467: */
0468: protected Expression string(int opPos) throws TransformerException {
0469: return compileUnary(new org.apache.xpath.operations.String(),
0470: opPos);
0471: }
0472:
0473: /**
0474: * Compile a 'boolean(...)' operation.
0475: *
0476: * @param opPos The current position in the m_opMap array.
0477: *
0478: * @return reference to {@link org.apache.xpath.operations.Bool} instance.
0479: *
0480: * @throws TransformerException if a error occurs creating the Expression.
0481: */
0482: protected Expression bool(int opPos) throws TransformerException {
0483: return compileUnary(new org.apache.xpath.operations.Bool(),
0484: opPos);
0485: }
0486:
0487: /**
0488: * Compile a 'number(...)' operation.
0489: *
0490: * @param opPos The current position in the m_opMap array.
0491: *
0492: * @return reference to {@link org.apache.xpath.operations.Number} instance.
0493: *
0494: * @throws TransformerException if a error occurs creating the Expression.
0495: */
0496: protected Expression number(int opPos) throws TransformerException {
0497: return compileUnary(new org.apache.xpath.operations.Number(),
0498: opPos);
0499: }
0500:
0501: /**
0502: * Compile a literal string value.
0503: *
0504: * @param opPos The current position in the m_opMap array.
0505: *
0506: * @return reference to {@link org.apache.xpath.objects.XString} instance.
0507: *
0508: * @throws TransformerException if a error occurs creating the Expression.
0509: */
0510: protected Expression literal(int opPos) {
0511:
0512: opPos = getFirstChildPos(opPos);
0513:
0514: return (XString) getTokenQueue().elementAt(getOp(opPos));
0515: }
0516:
0517: /**
0518: * Compile a literal number value.
0519: *
0520: * @param opPos The current position in the m_opMap array.
0521: *
0522: * @return reference to {@link org.apache.xpath.objects.XNumber} instance.
0523: *
0524: * @throws TransformerException if a error occurs creating the Expression.
0525: */
0526: protected Expression numberlit(int opPos) {
0527:
0528: opPos = getFirstChildPos(opPos);
0529:
0530: return (XNumber) getTokenQueue().elementAt(getOp(opPos));
0531: }
0532:
0533: /**
0534: * Compile a variable reference.
0535: *
0536: * @param opPos The current position in the m_opMap array.
0537: *
0538: * @return reference to {@link org.apache.xpath.operations.Variable} instance.
0539: *
0540: * @throws TransformerException if a error occurs creating the Expression.
0541: */
0542: protected Expression variable(int opPos)
0543: throws TransformerException {
0544:
0545: Variable var = new Variable();
0546:
0547: opPos = getFirstChildPos(opPos);
0548:
0549: int nsPos = getOp(opPos);
0550: java.lang.String namespace = (OpCodes.EMPTY == nsPos) ? null
0551: : (java.lang.String) getTokenQueue().elementAt(nsPos);
0552: java.lang.String localname = (java.lang.String) getTokenQueue()
0553: .elementAt(getOp(opPos + 1));
0554: QName qname = new QName(namespace, localname);
0555:
0556: var.setQName(qname);
0557:
0558: return var;
0559: }
0560:
0561: /**
0562: * Compile an expression group.
0563: *
0564: * @param opPos The current position in the m_opMap array.
0565: *
0566: * @return reference to the contained expression.
0567: *
0568: * @throws TransformerException if a error occurs creating the Expression.
0569: */
0570: protected Expression group(int opPos) throws TransformerException {
0571:
0572: // no-op
0573: return compile(opPos + 2);
0574: }
0575:
0576: /**
0577: * Compile a function argument.
0578: *
0579: * @param opPos The current position in the m_opMap array.
0580: *
0581: * @return reference to the argument expression.
0582: *
0583: * @throws TransformerException if a error occurs creating the Expression.
0584: */
0585: protected Expression arg(int opPos) throws TransformerException {
0586:
0587: // no-op
0588: return compile(opPos + 2);
0589: }
0590:
0591: /**
0592: * Compile a location path union. The UnionPathIterator itself may create
0593: * {@link org.apache.xpath.axes.LocPathIterator} children.
0594: *
0595: * @param opPos The current position in the m_opMap array.
0596: *
0597: * @return reference to {@link org.apache.xpath.axes.LocPathIterator} instance.
0598: *
0599: * @throws TransformerException if a error occurs creating the Expression.
0600: */
0601: protected Expression union(int opPos) throws TransformerException {
0602: locPathDepth++;
0603: try {
0604: return UnionPathIterator.createUnionIterator(this , opPos);
0605: } finally {
0606: locPathDepth--;
0607: }
0608: }
0609:
0610: private int locPathDepth = -1;
0611:
0612: /**
0613: * Get the level of the location path or union being constructed.
0614: * @return 0 if it is a top-level path.
0615: */
0616: public int getLocationPathDepth() {
0617: return locPathDepth;
0618: }
0619:
0620: /**
0621: * Get the function table
0622: */
0623: FunctionTable getFunctionTable() {
0624: return m_functionTable;
0625: }
0626:
0627: /**
0628: * Compile a location path. The LocPathIterator itself may create
0629: * {@link org.apache.xpath.axes.AxesWalker} children.
0630: *
0631: * @param opPos The current position in the m_opMap array.
0632: *
0633: * @return reference to {@link org.apache.xpath.axes.LocPathIterator} instance.
0634: *
0635: * @throws TransformerException if a error occurs creating the Expression.
0636: */
0637: public Expression locationPath(int opPos)
0638: throws TransformerException {
0639: locPathDepth++;
0640: try {
0641: DTMIterator iter = WalkerFactory.newDTMIterator(this ,
0642: opPos, (locPathDepth == 0));
0643: return (Expression) iter; // cast OK, I guess.
0644: } finally {
0645: locPathDepth--;
0646: }
0647: }
0648:
0649: /**
0650: * Compile a location step predicate expression.
0651: *
0652: * @param opPos The current position in the m_opMap array.
0653: *
0654: * @return the contained predicate expression.
0655: *
0656: * @throws TransformerException if a error occurs creating the Expression.
0657: */
0658: public Expression predicate(int opPos) throws TransformerException {
0659: return compile(opPos + 2);
0660: }
0661:
0662: /**
0663: * Compile an entire match pattern expression.
0664: *
0665: * @param opPos The current position in the m_opMap array.
0666: *
0667: * @return reference to {@link org.apache.xpath.patterns.UnionPattern} instance.
0668: *
0669: * @throws TransformerException if a error occurs creating the Expression.
0670: */
0671: protected Expression matchPattern(int opPos)
0672: throws TransformerException {
0673: locPathDepth++;
0674: try {
0675: // First, count...
0676: int nextOpPos = opPos;
0677: int i;
0678:
0679: for (i = 0; getOp(nextOpPos) == OpCodes.OP_LOCATIONPATHPATTERN; i++) {
0680: nextOpPos = getNextOpPos(nextOpPos);
0681: }
0682:
0683: if (i == 1)
0684: return compile(opPos);
0685:
0686: UnionPattern up = new UnionPattern();
0687: StepPattern[] patterns = new StepPattern[i];
0688:
0689: for (i = 0; getOp(opPos) == OpCodes.OP_LOCATIONPATHPATTERN; i++) {
0690: nextOpPos = getNextOpPos(opPos);
0691: patterns[i] = (StepPattern) compile(opPos);
0692: opPos = nextOpPos;
0693: }
0694:
0695: up.setPatterns(patterns);
0696:
0697: return up;
0698: } finally {
0699: locPathDepth--;
0700: }
0701: }
0702:
0703: /**
0704: * Compile a location match pattern unit expression.
0705: *
0706: * @param opPos The current position in the m_opMap array.
0707: *
0708: * @return reference to {@link org.apache.xpath.patterns.StepPattern} instance.
0709: *
0710: * @throws TransformerException if a error occurs creating the Expression.
0711: */
0712: public Expression locationPathPattern(int opPos)
0713: throws TransformerException {
0714:
0715: opPos = getFirstChildPos(opPos);
0716:
0717: return stepPattern(opPos, 0, null);
0718: }
0719:
0720: /**
0721: * Get a {@link org.w3c.dom.traversal.NodeFilter} bit set that tells what
0722: * to show for a given node test.
0723: *
0724: * @param opPos the op map position for the location step.
0725: *
0726: * @return {@link org.w3c.dom.traversal.NodeFilter} bit set that tells what
0727: * to show for a given node test.
0728: */
0729: public int getWhatToShow(int opPos) {
0730:
0731: int axesType = getOp(opPos);
0732: int testType = getOp(opPos + 3);
0733:
0734: // System.out.println("testType: "+testType);
0735: switch (testType) {
0736: case OpCodes.NODETYPE_COMMENT:
0737: return DTMFilter.SHOW_COMMENT;
0738: case OpCodes.NODETYPE_TEXT:
0739: // return DTMFilter.SHOW_TEXT | DTMFilter.SHOW_COMMENT;
0740: return DTMFilter.SHOW_TEXT | DTMFilter.SHOW_CDATA_SECTION;
0741: case OpCodes.NODETYPE_PI:
0742: return DTMFilter.SHOW_PROCESSING_INSTRUCTION;
0743: case OpCodes.NODETYPE_NODE:
0744: // return DTMFilter.SHOW_ALL;
0745: switch (axesType) {
0746: case OpCodes.FROM_NAMESPACE:
0747: return DTMFilter.SHOW_NAMESPACE;
0748: case OpCodes.FROM_ATTRIBUTES:
0749: case OpCodes.MATCH_ATTRIBUTE:
0750: return DTMFilter.SHOW_ATTRIBUTE;
0751: case OpCodes.FROM_SELF:
0752: case OpCodes.FROM_ANCESTORS_OR_SELF:
0753: case OpCodes.FROM_DESCENDANTS_OR_SELF:
0754: return DTMFilter.SHOW_ALL;
0755: default:
0756: if (getOp(0) == OpCodes.OP_MATCHPATTERN)
0757: return ~DTMFilter.SHOW_ATTRIBUTE
0758: & ~DTMFilter.SHOW_DOCUMENT
0759: & ~DTMFilter.SHOW_DOCUMENT_FRAGMENT;
0760: else
0761: return ~DTMFilter.SHOW_ATTRIBUTE;
0762: }
0763: case OpCodes.NODETYPE_ROOT:
0764: return DTMFilter.SHOW_DOCUMENT
0765: | DTMFilter.SHOW_DOCUMENT_FRAGMENT;
0766: case OpCodes.NODETYPE_FUNCTEST:
0767: return NodeTest.SHOW_BYFUNCTION;
0768: case OpCodes.NODENAME:
0769: switch (axesType) {
0770: case OpCodes.FROM_NAMESPACE:
0771: return DTMFilter.SHOW_NAMESPACE;
0772: case OpCodes.FROM_ATTRIBUTES:
0773: case OpCodes.MATCH_ATTRIBUTE:
0774: return DTMFilter.SHOW_ATTRIBUTE;
0775:
0776: // break;
0777: case OpCodes.MATCH_ANY_ANCESTOR:
0778: case OpCodes.MATCH_IMMEDIATE_ANCESTOR:
0779: return DTMFilter.SHOW_ELEMENT;
0780:
0781: // break;
0782: default:
0783: return DTMFilter.SHOW_ELEMENT;
0784: }
0785: default:
0786: // System.err.println("We should never reach here.");
0787: return DTMFilter.SHOW_ALL;
0788: }
0789: }
0790:
0791: private static final boolean DEBUG = false;
0792:
0793: /**
0794: * Compile a step pattern unit expression, used for both location paths
0795: * and match patterns.
0796: *
0797: * @param opPos The current position in the m_opMap array.
0798: * @param stepCount The number of steps to expect.
0799: * @param ancestorPattern The owning StepPattern, which may be null.
0800: *
0801: * @return reference to {@link org.apache.xpath.patterns.StepPattern} instance.
0802: *
0803: * @throws TransformerException if a error occurs creating the Expression.
0804: */
0805: protected StepPattern stepPattern(int opPos, int stepCount,
0806: StepPattern ancestorPattern) throws TransformerException {
0807:
0808: int startOpPos = opPos;
0809: int stepType = getOp(opPos);
0810:
0811: if (OpCodes.ENDOP == stepType) {
0812: return null;
0813: }
0814:
0815: boolean addMagicSelf = true;
0816:
0817: int endStep = getNextOpPos(opPos);
0818:
0819: // int nextStepType = getOpMap()[endStep];
0820: StepPattern pattern;
0821:
0822: // boolean isSimple = ((OpCodes.ENDOP == nextStepType) && (stepCount == 0));
0823: int argLen;
0824:
0825: switch (stepType) {
0826: case OpCodes.OP_FUNCTION:
0827: if (DEBUG)
0828: System.out.println("MATCH_FUNCTION: "
0829: + m_currentPattern);
0830: addMagicSelf = false;
0831: argLen = getOp(opPos + OpMap.MAPINDEX_LENGTH);
0832: pattern = new FunctionPattern(compileFunction(opPos),
0833: Axis.PARENT, Axis.CHILD);
0834: break;
0835: case OpCodes.FROM_ROOT:
0836: if (DEBUG)
0837: System.out.println("FROM_ROOT, " + m_currentPattern);
0838: addMagicSelf = false;
0839: argLen = getArgLengthOfStep(opPos);
0840: opPos = getFirstChildPosOfStep(opPos);
0841: pattern = new StepPattern(DTMFilter.SHOW_DOCUMENT
0842: | DTMFilter.SHOW_DOCUMENT_FRAGMENT, Axis.PARENT,
0843: Axis.CHILD);
0844: break;
0845: case OpCodes.MATCH_ATTRIBUTE:
0846: if (DEBUG)
0847: System.out.println("MATCH_ATTRIBUTE: "
0848: + getStepLocalName(startOpPos) + ", "
0849: + m_currentPattern);
0850: argLen = getArgLengthOfStep(opPos);
0851: opPos = getFirstChildPosOfStep(opPos);
0852: pattern = new StepPattern(DTMFilter.SHOW_ATTRIBUTE,
0853: getStepNS(startOpPos),
0854: getStepLocalName(startOpPos), Axis.PARENT,
0855: Axis.ATTRIBUTE);
0856: break;
0857: case OpCodes.MATCH_ANY_ANCESTOR:
0858: if (DEBUG)
0859: System.out.println("MATCH_ANY_ANCESTOR: "
0860: + getStepLocalName(startOpPos) + ", "
0861: + m_currentPattern);
0862: argLen = getArgLengthOfStep(opPos);
0863: opPos = getFirstChildPosOfStep(opPos);
0864: int what = getWhatToShow(startOpPos);
0865: // bit-o-hackery, but this code is due for the morgue anyway...
0866: if (0x00000500 == what)
0867: addMagicSelf = false;
0868: pattern = new StepPattern(getWhatToShow(startOpPos),
0869: getStepNS(startOpPos),
0870: getStepLocalName(startOpPos), Axis.ANCESTOR,
0871: Axis.CHILD);
0872: break;
0873: case OpCodes.MATCH_IMMEDIATE_ANCESTOR:
0874: if (DEBUG)
0875: System.out.println("MATCH_IMMEDIATE_ANCESTOR: "
0876: + getStepLocalName(startOpPos) + ", "
0877: + m_currentPattern);
0878: argLen = getArgLengthOfStep(opPos);
0879: opPos = getFirstChildPosOfStep(opPos);
0880: pattern = new StepPattern(getWhatToShow(startOpPos),
0881: getStepNS(startOpPos),
0882: getStepLocalName(startOpPos), Axis.PARENT,
0883: Axis.CHILD);
0884: break;
0885: default:
0886: error(XPATHErrorResources.ER_UNKNOWN_MATCH_OPERATION, null); //"unknown match operation!");
0887:
0888: return null;
0889: }
0890:
0891: pattern.setPredicates(getCompiledPredicates(opPos + argLen));
0892: if (null == ancestorPattern) {
0893: // This is the magic and invisible "." at the head of every
0894: // match pattern, and corresponds to the current node in the context
0895: // list, from where predicates are counted.
0896: // So, in order to calculate "foo[3]", it has to count from the
0897: // current node in the context list, so, from that current node,
0898: // the full pattern is really "self::node()/child::foo[3]". If you
0899: // translate this to a select pattern from the node being tested,
0900: // which is really how we're treating match patterns, it works out to
0901: // self::foo/parent::node[child::foo[3]]", or close enough.
0902: /* if(addMagicSelf && pattern.getPredicateCount() > 0)
0903: {
0904: StepPattern selfPattern = new StepPattern(DTMFilter.SHOW_ALL,
0905: Axis.PARENT, Axis.CHILD);
0906: // We need to keep the new nodetest from affecting the score...
0907: XNumber score = pattern.getStaticScore();
0908: pattern.setRelativePathPattern(selfPattern);
0909: pattern.setStaticScore(score);
0910: selfPattern.setStaticScore(score);
0911: }*/
0912: } else {
0913: // System.out.println("Setting "+ancestorPattern+" as relative to "+pattern);
0914: pattern.setRelativePathPattern(ancestorPattern);
0915: }
0916:
0917: StepPattern relativePathPattern = stepPattern(endStep,
0918: stepCount + 1, pattern);
0919:
0920: return (null != relativePathPattern) ? relativePathPattern
0921: : pattern;
0922: }
0923:
0924: /**
0925: * Compile a zero or more predicates for a given match pattern.
0926: *
0927: * @param opPos The position of the first predicate the m_opMap array.
0928: *
0929: * @return reference to array of {@link org.apache.xpath.Expression} instances.
0930: *
0931: * @throws TransformerException if a error occurs creating the Expression.
0932: */
0933: public Expression[] getCompiledPredicates(int opPos)
0934: throws TransformerException {
0935:
0936: int count = countPredicates(opPos);
0937:
0938: if (count > 0) {
0939: Expression[] predicates = new Expression[count];
0940:
0941: compilePredicates(opPos, predicates);
0942:
0943: return predicates;
0944: }
0945:
0946: return null;
0947: }
0948:
0949: /**
0950: * Count the number of predicates in the step.
0951: *
0952: * @param opPos The position of the first predicate the m_opMap array.
0953: *
0954: * @return The number of predicates for this step.
0955: *
0956: * @throws TransformerException if a error occurs creating the Expression.
0957: */
0958: public int countPredicates(int opPos) throws TransformerException {
0959:
0960: int count = 0;
0961:
0962: while (OpCodes.OP_PREDICATE == getOp(opPos)) {
0963: count++;
0964:
0965: opPos = getNextOpPos(opPos);
0966: }
0967:
0968: return count;
0969: }
0970:
0971: /**
0972: * Compiles predicates in the step.
0973: *
0974: * @param opPos The position of the first predicate the m_opMap array.
0975: * @param predicates An empty pre-determined array of
0976: * {@link org.apache.xpath.Expression}s, that will be filled in.
0977: *
0978: * @throws TransformerException
0979: */
0980: private void compilePredicates(int opPos, Expression[] predicates)
0981: throws TransformerException {
0982:
0983: for (int i = 0; OpCodes.OP_PREDICATE == getOp(opPos); i++) {
0984: predicates[i] = predicate(opPos);
0985: opPos = getNextOpPos(opPos);
0986: }
0987: }
0988:
0989: /**
0990: * Compile a built-in XPath function.
0991: *
0992: * @param opPos The current position in the m_opMap array.
0993: *
0994: * @return reference to {@link org.apache.xpath.functions.Function} instance.
0995: *
0996: * @throws TransformerException if a error occurs creating the Expression.
0997: */
0998: Expression compileFunction(int opPos) throws TransformerException {
0999:
1000: int endFunc = opPos + getOp(opPos + 1) - 1;
1001:
1002: opPos = getFirstChildPos(opPos);
1003:
1004: int funcID = getOp(opPos);
1005:
1006: opPos++;
1007:
1008: if (-1 != funcID) {
1009: Function func = m_functionTable.getFunction(funcID);
1010:
1011: /**
1012: * It is a trick for function-available. Since the function table is an
1013: * instance field, insert this table at compilation time for later usage
1014: */
1015:
1016: if (func instanceof FuncExtFunctionAvailable)
1017: ((FuncExtFunctionAvailable) func)
1018: .setFunctionTable(m_functionTable);
1019:
1020: func.postCompileStep(this );
1021:
1022: try {
1023: int i = 0;
1024:
1025: for (int p = opPos; p < endFunc; p = getNextOpPos(p), i++) {
1026:
1027: // System.out.println("argPos: "+ p);
1028: // System.out.println("argCode: "+ m_opMap[p]);
1029: func.setArg(compile(p), i);
1030: }
1031:
1032: func.checkNumberArgs(i);
1033: } catch (WrongNumberArgsException wnae) {
1034: java.lang.String name = m_functionTable
1035: .getFunctionName(funcID);
1036:
1037: m_errorHandler
1038: .fatalError(new TransformerException(
1039: XSLMessages
1040: .createXPATHMessage(
1041: XPATHErrorResources.ER_ONLY_ALLOWS,
1042: new Object[] {
1043: name,
1044: wnae
1045: .getMessage() }),
1046: m_locator));
1047: //"name + " only allows " + wnae.getMessage() + " arguments", m_locator));
1048: }
1049:
1050: return func;
1051: } else {
1052: error(XPATHErrorResources.ER_FUNCTION_TOKEN_NOT_FOUND, null); //"function token not found.");
1053:
1054: return null;
1055: }
1056: }
1057:
1058: // The current id for extension functions.
1059: private static long s_nextMethodId = 0;
1060:
1061: /**
1062: * Get the next available method id
1063: */
1064: synchronized private long getNextMethodId() {
1065: if (s_nextMethodId == Long.MAX_VALUE)
1066: s_nextMethodId = 0;
1067:
1068: return s_nextMethodId++;
1069: }
1070:
1071: /**
1072: * Compile an extension function.
1073: *
1074: * @param opPos The current position in the m_opMap array.
1075: *
1076: * @return reference to {@link org.apache.xpath.functions.FuncExtFunction} instance.
1077: *
1078: * @throws TransformerException if a error occurs creating the Expression.
1079: */
1080: private Expression compileExtension(int opPos)
1081: throws TransformerException {
1082:
1083: int endExtFunc = opPos + getOp(opPos + 1) - 1;
1084:
1085: opPos = getFirstChildPos(opPos);
1086:
1087: java.lang.String ns = (java.lang.String) getTokenQueue()
1088: .elementAt(getOp(opPos));
1089:
1090: opPos++;
1091:
1092: java.lang.String funcName = (java.lang.String) getTokenQueue()
1093: .elementAt(getOp(opPos));
1094:
1095: opPos++;
1096:
1097: // We create a method key to uniquely identify this function so that we
1098: // can cache the object needed to invoke it. This way, we only pay the
1099: // reflection overhead on the first call.
1100:
1101: Function extension = new FuncExtFunction(ns, funcName, String
1102: .valueOf(getNextMethodId()));
1103:
1104: try {
1105: int i = 0;
1106:
1107: while (opPos < endExtFunc) {
1108: int nextOpPos = getNextOpPos(opPos);
1109:
1110: extension.setArg(this .compile(opPos), i);
1111:
1112: opPos = nextOpPos;
1113:
1114: i++;
1115: }
1116: } catch (WrongNumberArgsException wnae) {
1117: ; // should never happen
1118: }
1119:
1120: return extension;
1121: }
1122:
1123: /**
1124: * Warn the user of an problem.
1125: *
1126: * @param msg An error msgkey that corresponds to one of the constants found
1127: * in {@link org.apache.xpath.res.XPATHErrorResources}, which is
1128: * a key for a format string.
1129: * @param args An array of arguments represented in the format string, which
1130: * may be null.
1131: *
1132: * @throws TransformerException if the current ErrorListoner determines to
1133: * throw an exception.
1134: */
1135: public void warn(String msg, Object[] args)
1136: throws TransformerException {
1137:
1138: java.lang.String fmsg = XSLMessages.createXPATHWarning(msg,
1139: args);
1140:
1141: if (null != m_errorHandler) {
1142: m_errorHandler.warning(new TransformerException(fmsg,
1143: m_locator));
1144: } else {
1145: System.out.println(fmsg + "; file "
1146: + m_locator.getSystemId() + "; line "
1147: + m_locator.getLineNumber() + "; column "
1148: + m_locator.getColumnNumber());
1149: }
1150: }
1151:
1152: /**
1153: * Tell the user of an assertion error, and probably throw an
1154: * exception.
1155: *
1156: * @param b If false, a runtime exception will be thrown.
1157: * @param msg The assertion message, which should be informative.
1158: *
1159: * @throws RuntimeException if the b argument is false.
1160: */
1161: public void assertion(boolean b, java.lang.String msg) {
1162:
1163: if (!b) {
1164: java.lang.String fMsg = XSLMessages
1165: .createXPATHMessage(
1166: XPATHErrorResources.ER_INCORRECT_PROGRAMMER_ASSERTION,
1167: new Object[] { msg });
1168:
1169: throw new RuntimeException(fMsg);
1170: }
1171: }
1172:
1173: /**
1174: * Tell the user of an error, and probably throw an
1175: * exception.
1176: *
1177: * @param msg An error msgkey that corresponds to one of the constants found
1178: * in {@link org.apache.xpath.res.XPATHErrorResources}, which is
1179: * a key for a format string.
1180: * @param args An array of arguments represented in the format string, which
1181: * may be null.
1182: *
1183: * @throws TransformerException if the current ErrorListoner determines to
1184: * throw an exception.
1185: */
1186: public void error(String msg, Object[] args)
1187: throws TransformerException {
1188:
1189: java.lang.String fmsg = XSLMessages.createXPATHMessage(msg,
1190: args);
1191:
1192: if (null != m_errorHandler) {
1193: m_errorHandler.fatalError(new TransformerException(fmsg,
1194: m_locator));
1195: } else {
1196:
1197: // System.out.println(te.getMessage()
1198: // +"; file "+te.getSystemId()
1199: // +"; line "+te.getLineNumber()
1200: // +"; column "+te.getColumnNumber());
1201: throw new TransformerException(fmsg,
1202: (SAXSourceLocator) m_locator);
1203: }
1204: }
1205:
1206: /**
1207: * The current prefixResolver for the execution context.
1208: */
1209: private PrefixResolver m_currentPrefixResolver = null;
1210:
1211: /**
1212: * Get the current namespace context for the xpath.
1213: *
1214: * @return The current prefix resolver, *may* be null, though hopefully not.
1215: */
1216: public PrefixResolver getNamespaceContext() {
1217: return m_currentPrefixResolver;
1218: }
1219:
1220: /**
1221: * Set the current namespace context for the xpath.
1222: *
1223: * @param pr The resolver for prefixes in the XPath expression.
1224: */
1225: public void setNamespaceContext(PrefixResolver pr) {
1226: m_currentPrefixResolver = pr;
1227: }
1228:
1229: /** The error listener where errors will be sent. If this is null, errors
1230: * and warnings will be sent to System.err. May be null. */
1231: ErrorListener m_errorHandler;
1232:
1233: /** The source locator for the expression being compiled. May be null. */
1234: SourceLocator m_locator;
1235:
1236: /**
1237: * The FunctionTable for all xpath build-in functions
1238: */
1239: private FunctionTable m_functionTable;
1240: }
|