Package org.apache.xalan.xpath

Source Code of org.apache.xalan.xpath.XPath

/*
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 1999 The Apache Software Foundation.  All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in
*    the documentation and/or other materials provided with the
*    distribution.
*
* 3. The end-user documentation included with the redistribution,
*    if any, must include the following acknowledgment: 
*       "This product includes software developed by the
*        Apache Software Foundation (http://www.apache.org/)."
*    Alternately, this acknowledgment may appear in the software itself,
*    if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Xalan" and "Apache Software Foundation" must
*    not be used to endorse or promote products derived from this
*    software without prior written permission. For written
*    permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
*    nor may "Apache" appear in their name, without prior written
*    permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation and was
* originally based on software copyright (c) 1999, Lotus
* Development Corporation., http://www.lotus.com.  For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
package org.apache.xalan.xpath;
import org.w3c.dom.*;
import java.util.*;
import org.apache.xalan.xpath.xml.PrefixResolver;
import org.apache.xalan.xpath.xml.QName;
import java.io.*;
import org.apache.xalan.xpath.res.XPATHErrorResources;
import org.apache.xalan.xpath.xml.XSLMessages;
import org.apache.xalan.xpath.xml.ProblemListener;
/**
* <meta name="usage" content="general"/>
* The XPath class represents the semantic parse tree of the XPath pattern.
* It is the representation of the grammar which filters out
* the choice for replacement order of the production rules.
* In order to conserve memory and reduce object creation, the
* tree is represented as an array of integers:
*    [op code][length][...]
* where strings are represented within the array as
* indexes into the token tree.
*/
public class XPath implements Serializable
{   
  /**
   * <meta name="usage" content="internal"/>
   * A true boolean object so we don't have to keep creating them.
   */
  static XBoolean m_true = new XBooleanStatic(true);
 
  /**
   * <meta name="usage" content="internal"/>
   * A true boolean object so we don't have to keep creating them.
   */
  static XBoolean m_false = new XBooleanStatic(false);
 
  /**
   * The current pattern string, for diagnostics purposes
   */
  String m_currentPattern;
 
  /**
   * Get the pattern string.
   */
  public String getPatternString()
  {
    return m_currentPattern;
  }
 
  /**
   * The max size that the token queue can grow to.
   */
  static final int MAXTOKENQUEUESIZE = 500;

  /**
   *  TokenStack is the queue of used tokens. The current token is the token at the
   * end of the m_tokenQueue. The idea is that the queue can be marked and a sequence
   * of tokens can be reused.
   */
  Object[] m_tokenQueue = new Object[MAXTOKENQUEUESIZE];
 
  /**
   * <meta name="usage" content="advanced"/>
   * Get the XPath as a list of tokens.
   */
  public Object[] getTokenQueue()
  {
    return m_tokenQueue;
  }

  /**
   * The current size of the token queue.
   */
  int m_tokenQueueSize = 0;

  /**
   * <meta name="usage" content="advanced"/>
   * Get size of the token queue.
   */
  public int getTokenQueueSize()
  {
    return m_tokenQueueSize;
  }

  /**
   * An operations map is used instead of a proper parse tree.  It contains
   * operations codes and indexes into the m_tokenQueue.
   * I use an array instead of a full parse tree in order to cut down
   * on the number of objects created.
   */
  int m_opMap[] = null;
 
  /**
   * <meta name="usage" content="advanced"/>
   * Get the opcode list that describes the XPath operations.  It contains
   * operations codes and indexes into the m_tokenQueue.
   * I use an array instead of a full parse tree in order to cut down
   * on the number of objects created.
   */
  public int[] getOpMap()
  {
    return m_opMap;
  }
 
  // Position indexes
 
  /**
   * <meta name="usage" content="advanced"/>
   * The length is always the opcode position + 1.
   * Length is always expressed as the opcode+length bytes,
   * so it is always 2 or greater.
   */
  public static final int MAPINDEX_LENGTH = 1;
 
  /**
   * If this is true, extra programmer error checks will be made.
   */
  static final boolean m_debug = false;
 
  /**
   * This class can have a single listener that can be informed
   * of errors and warnings, and can normally control if an exception
   * is thrown or not (or the problem listeners can throw their
   * own RuntimeExceptions).
   */
  transient private org.apache.xalan.xpath.xml.ProblemListener m_problemListener = null;
 
  /**
   * If m_trace is set to true, trace strings will be written
   * out to System.out.
   */
  static final boolean m_trace = false;
  /**
   * Construct a XPath, passing in a problem listener.  The object must
   * be initialized by the XPathProcessorImpl.initXPath method.
   * @param problemListener An interface whereby the caller
   * can listen for errors and warnings.
   */
  public XPath(ProblemListener problemListener)
  {
    m_problemListener = problemListener;
  }

  /**
   * Construct an XPath object.  The object must be initialized by the
   * XPathProcessorImpl.initXPath method.
   */
  public XPath()
  {
    m_problemListener = new org.apache.xalan.xpath.xml.ProblemListenerDefault();
  }

  /**
   * Set the problem listener property.
   * This class can have a single listener that can be informed
   * of errors and warnings, and can normally control if an exception
   * is thrown or not (or the problem listeners can throw their
   * own RuntimeExceptions).
   * @param l A ProblemListener interface.
   */
  public void setProblemListener(ProblemListener l)
  {
    m_problemListener = l;
  }

  /**
   * Get the problem listener property.
   * This class can have a single listener that can be informed
   * of errors and warnings, and can normally control if an exception
   * is thrown or not (or the problem listeners can throw their
   * own RuntimeExceptions).
   * @return A ProblemListener interface.
   */
  public ProblemListener getProblemListener()
  {
    return m_problemListener;
  }
 
  /**
   * getXLocatorHandler.
   */
  private XLocator createXLocatorHandler(XPathSupport callbacks)
  {
    return callbacks.createXLocatorHandler();
  }

  /**
   * Read the object from an input stream.
   */
  private void readObject(ObjectInputStream stream)
    throws IOException
  {
    try
    {
      stream.defaultReadObject();
    }
    catch(ClassNotFoundException cnfe)
    {
      throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_XPATH_READOBJECT, new Object[]{cnfe.getMessage()})); //"In XPath.readObject: "+cnfe.getMessage());
    }
  }
 
  /**
   * Given an expression and a context, evaluate the XPath
   * and return the result.
   * @param execContext The execution context.
   * @param contextNode The node that "." expresses.
   * @param namespaceContext The context in which namespaces in the
   * XPath are supposed to be expanded.
   * @exception SAXException thrown if the active ProblemListener decides
   * the error condition is severe enough to halt processing.
   */
  public XObject execute(XPathSupport execContext, Node contextNode,
                        PrefixResolver namespaceContext)
    throws org.xml.sax.SAXException
  {
    return execute(execContext, contextNode, namespaceContext, null, null, false);
  }

  /**
   * <meta name="usage" content="experimental"/>
   * Given an expression and a context, evaluate the XPath
   * and call the callback as nodes are found.  Only some simple
   * types of expresions right now can call back, so if this
   * method returns null, then the callbacks have been called, otherwise
   * a valid XObject will be returned.
   * @param execContext The execution context.
   * @param contextNode The node that "." expresses.
   * @param namespaceContext The context in which namespaces in the
   * XPath are supposed to be expanded.
   * @exception SAXException thrown if the active ProblemListener decides
   * the error condition is severe enough to halt processing.
   * @param callback Interface that implements the processLocatedNode method.
   * @param callbackInfo Object that will be passed to the processLocatedNode method.
   * @param stopAtFirst True if the search should stop once the first node in document
   * order is found.
   * @return The result of the XPath or null if callbacks are used.
   * @exception SAXException thrown if
   * the error condition is severe enough to halt processing.
   */
  public XObject execute(XPathSupport execContext, Node contextNode,
                         PrefixResolver namespaceContext,
                         NodeCallback callback, Object callbackInfo, boolean stopAtFirst)
    throws org.xml.sax.SAXException
  {   
    PrefixResolver savedPrefixResolver = execContext.getNamespaceContext();
    execContext.setNamespaceContext(namespaceContext);
    execContext.setCurrentNode(contextNode);
    XObject xobj = null;
    try
    {
      if(null != callbackInfo)
        execContext.pushXPathContext(this, execContext, contextNode, namespaceContext);
      xobj = execute(execContext, contextNode, 0, callback, callbackInfo, stopAtFirst);
      if(null != callbackInfo)
        execContext.popXPathContext();
    }
    finally
    {
      execContext.setNamespaceContext(savedPrefixResolver);
      execContext.setCurrentNode(null); // I think this is probably fine
    }
    return xobj;
  }
 
  /**
   * Get the match score of the given node.
   * @param context The current source tree context node.
   * @returns score, one of MATCH_SCORE_NODETEST,
   * MATCH_SCORE_NONE, MATCH_SCORE_OTHER, MATCH_SCORE_QNAME.
   */
  public double getMatchScore(XPathSupport execContext, Node context)
    throws org.xml.sax.SAXException
  {
    double score = MATCH_SCORE_NONE;
    int opPos = 0;
    if(m_opMap[opPos] == OP_MATCHPATTERN)
    {
      opPos = getFirstChildPos(opPos);
     
      XLocator locator = execContext.getXLocatorFromNode(context);
     
      if(null == locator)
        locator = execContext.createXLocatorHandler();

      while(m_opMap[opPos] == OP_LOCATIONPATHPATTERN)
      {
        int nextOpPos = getNextOpPos(opPos);
       
        // opPos = getFirstChildPos(opPos);       
        score = locator.locationPathPattern(this, execContext, context, opPos);

        if(score != MATCH_SCORE_NONE)
          break;
        opPos = nextOpPos;
      }
     
    }
    else
    {
      error(context, XPATHErrorResources.ER_EXPECTED_MATCH_PATTERN); //"Expected match pattern in getMatchScore!");
    }
   
    return score;
  }

   
  /**
   * Get the position in the current context node list.
   */
  int getCountOfContextNodeList(XPath path, XPathSupport execContext, Node context)
    throws org.xml.sax.SAXException
  {
    //    assert(null != m_contextNodeList, "m_contextNodeList must be non-null");
   
    if(execContext.getThrowFoundIndex())
      throw new FoundIndex();
   
    NodeList cnl = execContext.getContextNodeList();
   
    if(null == cnl)
    {
      XObject xobject = execContext.reExecuteXPathContext(path, execContext, context);
      if((null != xobject) && (xobject.getType() == XObject.CLASS_NODESET))
        cnl = xobject.nodeset();
      else if(execContext.getContextNodePosition() > 0)
        throw new FoundIndex(); // Tell 'em to try again!
      else
        return 0; // I give up...
    }
    return cnl.getLength();
  }

  /**
   * Get the position in the current context node list.
   */
  int getPositionInContextNodeList(Node context, XPathSupport execContext)
  {
    // assert(null != m_contextNodeList, "m_contextNodeList must be non-null");
   
    if(execContext.getThrowFoundIndex())
      throw new FoundIndex();
   
    int pos = execContext.getContextNodePosition();
    if(pos >= 0)
      return pos;
   
    pos = -1;

    if(null != execContext.getContextNodeList())
    {
      int nNodes = execContext.getContextNodeList().getLength();
     
      for(int i = 0; i < nNodes; i++)
      {
        Node item = execContext.getContextNodeList().item(i);
        if((null != item) && item.equals( context ))
        {
          pos = i+1; // for 1-based XSL count.
          break;
        }
      }
    }
    return pos;
  }
 
  /**
   * Replace the large arrays
   * with a small array.
   */
  void shrink()
  {
    int map[] = m_opMap;
    int n = m_opMap[MAPINDEX_LENGTH];;
    m_opMap = new int[n+4];
    int i;
    for(i = 0; i < n; i++)
    {
      m_opMap[i] = map[i];
    }
    m_opMap[i] = 0;
    m_opMap[i+1] = 0;
    m_opMap[i+2] = 0;
       
    Object[] tokens = m_tokenQueue;
    n = m_tokenQueueSize;
    m_tokenQueue = new Object[n+4];
    for(i = 0; i < n; i++)
    {
      m_tokenQueue[i] = tokens[i];
    }
    m_tokenQueue[i] = null;
    m_tokenQueue[i+1] = null;
    m_tokenQueue[i+2] = null;
  }
 
  /**
   * Install a built-in function.
   * @param name The unqualified name of the function.
   * @param funcIndex The index of the function in the table.
   * @param func A Implementation of an XPath Function object.
   * @return the position of the function in the internal index.
   */
  public void installFunction (String name, int funcIndex, Function func)
  {           
    m_functions[funcIndex] = func;   
  }
 
  /**
   * Install a built-in function.
   * @param name The unqualified name of the function.
   * @param func A Implementation of an XPath Function object.
   * @return the position of the function in the internal index.
   */
  public static int installFunction(String name, Function func)
  {
    int funcIndex;
    Object funcIndexObj = XPathProcessorImpl.m_functions.get(name);
    if(null != funcIndexObj)
    {
      funcIndex = ((Integer)funcIndexObj).intValue();
    }
    else
    {
      funcIndex = m_funcNextFreeIndex;
      m_funcNextFreeIndex++;
      XPathProcessorImpl.m_functions.put(name, new Integer(funcIndex));
    }
    m_functions[funcIndex] = func;
    return funcIndex;
  }

  /**
   * Execute from the beginning of the xpath.
   * @param context The current source tree context node.
   * @param opPos The current position in the m_opMap array.
   * @returns The result of the expression.
   */
  protected XObject xpath(XPathSupport execContext, Node context, int opPos)
    throws org.xml.sax.SAXException
  {
    return execute(execContext, context, opPos+2);
  }

  /**
   * OR two expressions and return the boolean result.
   * @param context The current source tree context node.
   * @param opPos The current position in the m_opMap array.
   * @returns XBoolean set to true if the one of the two arguments are true.
   */
  protected XBoolean or(XPathSupport execContext, Node context, int opPos)
    throws org.xml.sax.SAXException
  {
    opPos = getFirstChildPos(opPos);
    int expr2Pos = getNextOpPos(opPos);
    XBoolean result;
    XObject expr1 = execute(execContext, context, opPos);
    if(!expr1.bool())
    {
      XObject expr2 = execute(execContext, context, expr2Pos);
      if(!expr2.bool())
      {
        result = new XBoolean(false);
      }
      else
      {
        result = new XBoolean(true);
      }
    }
    else
    {
      result = new XBoolean(true);
    }
    return result;
  }

  /**
   * OR two expressions and return the boolean result.
   * @param context The current source tree context node.
   * @param opPos The current position in the m_opMap array.
   * @returns XBoolean set to true if the two arguments are both true.
   */
  protected XBoolean and(XPathSupport execContext, Node context, int opPos)
    throws org.xml.sax.SAXException
  {
    opPos = getFirstChildPos(opPos);
    int expr2Pos = getNextOpPos(opPos);
    XObject expr1 = execute(execContext, context, opPos);
    if(expr1.bool())
    {
      XObject expr2 = execute(execContext, context, expr2Pos);
      return expr2.bool() ? m_true : m_false;
    }
    else
      return m_false;
  }

  /**
   * Tell if two expressions are functionally not equal.
   * @param context The current source tree context node.
   * @param opPos The current position in the m_opMap array.
   * @returns XBoolean set to true if the two arguments are not equal.
   */
  protected XBoolean notequals(XPathSupport execContext, Node context, int opPos)
    throws org.xml.sax.SAXException
  {
    opPos = getFirstChildPos(opPos);
    int expr2Pos = getNextOpPos(opPos);
   
    XObject expr1 = execute(execContext, context, opPos);
    XObject expr2 = execute(execContext, context, expr2Pos);
   
    return (expr1.notEquals(expr2)) ? m_true : m_false;
  }


  /**
   * Tell if two expressions are functionally equal.
   * @param context The current source tree context node.
   * @param opPos The current position in the m_opMap array.
   * @returns XBoolean set to true if the two arguments are equal.
   */
  protected XBoolean equals(XPathSupport execContext, Node context, int opPos)
    throws org.xml.sax.SAXException
  {
    opPos = getFirstChildPos(opPos);
    int expr2Pos = getNextOpPos(opPos);
   
    XObject expr1 = execute(execContext, context, opPos, null, null, true);
    XObject expr2 = execute(execContext, context, expr2Pos, null, null, true);
   
    return expr1.equals(expr2) ? m_true : m_false;
  }
   
  /**
   * Tell if one argument is less than or equal to the other argument.
   * @param context The current source tree context node.
   * @param opPos The current position in the m_opMap array.
   * @returns XBoolean set to true if arg 1 is less than or equal to arg 2.
   */
  protected XBoolean lte(XPathSupport execContext, Node context, int opPos)
    throws org.xml.sax.SAXException
  {
    opPos = getFirstChildPos(opPos);
    int expr2Pos = getNextOpPos(opPos);
   
    XObject expr1 = execute(execContext, context, opPos);
    XObject expr2 = execute(execContext, context, expr2Pos);
   
    return expr1.lessThanOrEqual(expr2) ? m_true : m_false;
  }

  /**
   * Tell if one argument is less than the other argument.
   * @param context The current source tree context node.
   * @param opPos The current position in the m_opMap array.
   * @returns XBoolean set to true if arg 1 is less than arg 2.
   */
  protected XBoolean lt(XPathSupport execContext, Node context, int opPos)
    throws org.xml.sax.SAXException
  {
    opPos = getFirstChildPos(opPos);
    int expr2Pos = getNextOpPos(opPos);
   
    XObject expr1 = execute(execContext, context, opPos);
    XObject expr2 = execute(execContext, context, expr2Pos);
   
    return expr1.lessThan(expr2) ? m_true : m_false;
  }

  /**
   * Tell if one argument is greater than or equal to the other argument.
   * @param context The current source tree context node.
   * @param opPos The current position in the m_opMap array.
   * @returns XBoolean set to true if arg 1 is greater than or equal to arg 2.
   */
  protected XBoolean gte(XPathSupport execContext, Node context, int opPos)
    throws org.xml.sax.SAXException
  {
    opPos = getFirstChildPos(opPos);
    int expr2Pos = getNextOpPos(opPos);
   
    XObject expr1 = execute(execContext, context, opPos);
    XObject expr2 = execute(execContext, context, expr2Pos);
   
    return expr1.greaterThanOrEqual(expr2) ? m_true : m_false;
  }


  /**
   * Tell if one argument is greater than the other argument.
   * @param context The current source tree context node.
   * @param opPos The current position in the m_opMap array.
   * @returns XBoolean set to true if arg 1 is greater than arg 2.
   */
  protected XBoolean gt(XPathSupport execContext, Node context, int opPos)
    throws org.xml.sax.SAXException
  {
    opPos = getFirstChildPos(opPos);
    int expr2Pos = getNextOpPos(opPos);
   
    XObject expr1 = execute(execContext, context, opPos);
    XObject expr2 = execute(execContext, context, expr2Pos);
   
    return expr1.greaterThan(expr2) ? m_true : m_false;
  }

  /**
   * Give the sum of two arguments.
   * @param context The current source tree context node.
   * @param opPos The current position in the m_opMap array.
   * @returns sum of arg1 and arg2.
   */
  protected XNumber plus(XPathSupport execContext, Node context, int opPos)
    throws org.xml.sax.SAXException
  {
    opPos = getFirstChildPos(opPos);
    int expr2Pos = getNextOpPos(opPos);
   
    XObject expr1 = execute(execContext, context, opPos);
    XObject expr2 = execute(execContext, context, expr2Pos);
   
    return new XNumber(expr1.num() +  expr2.num());
  }

  /**
   * Give the difference of two arguments.
   * @param context The current source tree context node.
   * @param opPos The current position in the m_opMap array.
   * @returns difference of arg1 and arg2.
   */
  protected XNumber minus(XPathSupport execContext, Node context, int opPos)
    throws org.xml.sax.SAXException
  {
    opPos = getFirstChildPos(opPos);
    int expr2Pos = getNextOpPos(opPos);
   
    XObject expr1 = execute(execContext, context, opPos);
    XObject expr2 = execute(execContext, context, expr2Pos);
   
    return new XNumber(expr1.num() -  expr2.num());
  }

  /**
   * Multiply two arguments.
   * @param context The current source tree context node.
   * @param opPos The current position in the m_opMap array.
   * @returns arg1 * arg2.
   */
  protected XNumber mult(XPathSupport execContext, Node context, int opPos)
    throws org.xml.sax.SAXException
  {
    opPos = getFirstChildPos(opPos);
    int expr2Pos = getNextOpPos(opPos);
   
    XObject expr1 = execute(execContext, context, opPos);
    XObject expr2 = execute(execContext, context, expr2Pos);
   
    return new XNumber(expr1.num() *  expr2.num());
  }

  /**
   * Divide a number.
   * @param context The current source tree context node.
   * @param opPos The current position in the m_opMap array.
   * @returns arg1 / arg2.
   */
  protected XNumber div(XPathSupport execContext, Node context, int opPos)
    throws org.xml.sax.SAXException
  {
    opPos = getFirstChildPos(opPos);
    int expr2Pos = getNextOpPos(opPos);
   
    XObject expr1 = execute(execContext, context, opPos);
    XObject expr2 = execute(execContext, context, expr2Pos);
   
    return new XNumber(expr1.num() / expr2.num());
  }

  /**
   * Return the remainder from a truncating division.
   * @param context The current source tree context node.
   * @param opPos The current position in the m_opMap array.
   * @returns arg1 mod arg2.
   */
  protected XNumber mod(XPathSupport execContext, Node context, int opPos)
    throws org.xml.sax.SAXException
  {
    opPos = getFirstChildPos(opPos);
    int expr2Pos = getNextOpPos(opPos);
   
    XObject expr1 = execute(execContext, context, opPos);
    XObject expr2 = execute(execContext, context, expr2Pos);
   
    return new XNumber(expr1.num() %  expr2.num());
  }

  /**
   * Return the remainder from a truncating division.
   * (Quo is no longer supported by xpath).
   * @param context The current source tree context node.
   * @param opPos The current position in the m_opMap array.
   * @returns arg1 mod arg2.
   */
  protected XNumber quo(XPathSupport execContext, Node context, int opPos)
    throws org.xml.sax.SAXException
  {
    // Actually, this is no longer supported by xpath...
    warn(XPATHErrorResources.WG_QUO_NO_LONGER_DEFINED); //"Old syntax: quo(...) is no longer defined in XPath.");
   
    opPos = getFirstChildPos(opPos);
    int expr2Pos = getNextOpPos(opPos);
   
    XObject expr1 = execute(execContext, context, opPos);
    XObject expr2 = execute(execContext, context, expr2Pos);
   
    return new XNumber((int)(expr1.num() /  expr2.num()));
  }

  /**
   * Return the negation of a number.
   * @param context The current source tree context node.
   * @param opPos The current position in the m_opMap array.
   * @returns -arg.
   */
  protected XNumber neg(XPathSupport execContext, Node context, int opPos)
    throws org.xml.sax.SAXException
  {
    XObject expr1 = execute(execContext, context, opPos+2);
   
    return new XNumber(-expr1.num());
  }

  /**
   * Cast an expression to a string.
   * @param context The current source tree context node.
   * @param opPos The current position in the m_opMap array.
   * @returns arg cast to a string.
   */
  protected XString string(XPathSupport execContext, Node context, int opPos)
    throws org.xml.sax.SAXException
  {
    XObject expr1 = execute(execContext, context, opPos+2);
   
    return new XString(expr1.str());
  }

  /**
   * Cast an expression to a boolean.
   * @param context The current source tree context node.
   * @param opPos The current position in the m_opMap array.
   * @returns arg cast to a boolean.
   */
  protected XBoolean bool(XPathSupport execContext, Node context, int opPos)
    throws org.xml.sax.SAXException
  {
    XObject expr1 = execute(execContext, context, opPos+2);
   
    return expr1.bool() ? m_true : m_false;
  }
  /**
   * Cast an expression to a number.
   * @param context The current source tree context node.
   * @param opPos The current position in the m_opMap array.
   * @returns arg cast to a number.
   */
  protected XNumber number(XPathSupport execContext, Node context, int opPos)
    throws org.xml.sax.SAXException
  {
    XObject expr1 = execute(execContext, context, opPos+2);
   
    return new XNumber(expr1.num());
  }
 
  /**
   * Computes the union of its operands which must be node-sets.
   * @param context The current source tree context node.
   * @param opPos The current position in the m_opMap array.
   * @param callback Interface that implements the processLocatedNode method.
   * @param callbackInfo Object that will be passed to the processLocatedNode method.
   * @returns the union of node-set operands.
   */
  protected XNodeSet union(XPathSupport execContext,
                           Node context, int opPos,
                           NodeCallback callback, Object callbackInfo)
    throws org.xml.sax.SAXException
  {
    XLocator xlocator = execContext.getXLocatorFromNode(context);
   
    if(null == xlocator)
        xlocator = execContext.createXLocatorHandler();
     
    XNodeSet results = xlocator.union(this, execContext,
                                      context, opPos, callback, callbackInfo);
   
    return results;
  }

  /**
   * Get a literal value.
   * @param context The current source tree context node.
   * @param opPos The current position in the m_opMap array.
   * @returns an XString object.
   */
  protected XString literal(XPathSupport execContext, Node context, int opPos)
  {
    opPos = getFirstChildPos(opPos);
   
    // TODO: It's too expensive to create an object every time...
    return (XString)m_tokenQueue[m_opMap[opPos]];
  }
 
  /**
   * Get a literal value.
   * @param context The current source tree context node.
   * @param opPos The current position in the m_opMap array.
   * @returns an XObject object.
   */
  protected XObject variable(XPathSupport execContext, Node context, int opPos)
    throws org.xml.sax.SAXException
  {
    opPos = getFirstChildPos(opPos);
    String varName = (String)m_tokenQueue[m_opMap[opPos]];
    // System.out.println("variable name: "+varName);
    // TODO: I don't this will be parsed right in the first place...
    QName qname = new QName(varName, execContext.getNamespaceContext());
    XObject result;
    try
    {
      result = execContext.getVariable(qname);
    }
    catch(Exception e)
    {
      error(XPATHErrorResources.ER_COULDNOT_GET_VAR_NAMED, new Object[] {varName}); //"Could not get variable named "+varName);
      result = null;
    }

    if(null == result)
    {
      error(context, XPATHErrorResources.ER_ILLEGAL_VARIABLE_REFERENCE, new Object[] {varName}); //"VariableReference given for variable out "+
                    //"of context or without definition!  Name = " + varName);
    }

    return result;
  }


  /**
   * Execute an expression as a group.
   * @param context The current source tree context node.
   * @param opPos The current position in the m_opMap array.
   * @returns arg.
   */
  protected XObject group(XPathSupport execContext, Node context, int opPos)
    throws org.xml.sax.SAXException
  {   
    return execute(execContext, context, opPos+2);
  }


  /**
   * Get a literal value.
   * @param context The current source tree context node.
   * @param opPos The current position in the m_opMap array.
   * @returns an XString object.
   */
  protected XNumber numberlit(XPathSupport execContext, Node context, int opPos)
  {
    opPos = getFirstChildPos(opPos);
   
    return (XNumber)m_tokenQueue[m_opMap[opPos]];
  }
 
  /**
   * Execute a function argument.
   * @param context The current source tree context node.
   * @param opPos The current position in the m_opMap array.
   * @returns the result of the argument expression.
   */
  protected XObject arg(XPathSupport execContext, Node context, int opPos)
    throws org.xml.sax.SAXException
  {   
    return execute(execContext, context, opPos+2);
  }

  /**
   * <meta name="usage" content="advanced"/>
   * Execute a location path.
   * @param context The current source tree context node.
   * @param opPos The current position in the m_opMap array.
   * @param callback Interface that implements the processLocatedNode method.
   * @param callbackInfo Object that will be passed to the processLocatedNode method.
   * @returns a node-set.
   */
  public XNodeSet locationPath(XPathSupport execContext,
                               Node context, int opPos,
                               NodeCallback callback, Object callbackInfo,
                               boolean stopAtFirst)
    throws org.xml.sax.SAXException
  {   
    XLocator xlocator = execContext.getXLocatorFromNode(context);
   
    if(null == xlocator)
        xlocator = execContext.createXLocatorHandler();
     
    XNodeSet results = xlocator.locationPath(this, execContext,
                                             context, opPos, callback, callbackInfo,
                                             stopAtFirst);
   
    return results;
  }

  /**
   * <meta name="usage" content="advanced"/>
   * Evaluate a predicate.
   * @param context The current source tree context node.
   * @param opPos The current position in the m_opMap array.
   * @returns either a boolean or a number.
   */
  public XObject predicate(XPathSupport execContext, Node context, int opPos)
    throws org.xml.sax.SAXException
  {
    XObject expr1 = execute(execContext, context, opPos+2, null, null, true);
    int objType = expr1.getType();
    if((XObject.CLASS_NUMBER != objType) && (XObject.CLASS_BOOLEAN != objType))
    {
      expr1 = expr1.bool() ? m_true : m_false;
    }
   
    return expr1;
  }
 
  /**
   * Execute a step in a location path.  This must be implemented
   * by a derived class of XPath (or don't call at all
   * from the derived implementation of locationPath()).
   * @param context The current source tree context node.
   * @param opPos The current position in the m_opMap array.
   * @returns a node-set.
   */
  protected MutableNodeList step(XPathSupport execContext, Node context, int opPos)
    throws org.xml.sax.SAXException
  {   
    warn(context,XPATHErrorResources.WG_NEED_DERIVED_OBJECT_TO_IMPLEMENT_NODETEST); //"XPath needs a derived object to implement step!");
    return null;
  }

  /**
   * Handle an extension function.
   */
  protected XObject extfunction(XPathSupport execContext, Node context, int opPos,
                                String namespace, String extensionName,
                                Vector argVec, Object methodKey)
    throws org.xml.sax.SAXException
  {
    XObject result;
    Object val = execContext.extFunction(namespace, extensionName,
                                         argVec, methodKey);
    if(null != val)
    {
      if(val instanceof XObject)
      {
        result = (XObject)val;
      }
      else if(val instanceof XLocator)
      {
        XLocator locator = (XLocator)val;
        opPos = getNextOpPos(opPos+1);
        result = locator.connectToNodes(this, execContext, context, opPos, argVec)
        // System.out.println("nodeset len: "+result.nodeset().getLength());
      }
      else if(val instanceof String)
      {
        result = new XString((String)val);
      }
      else if(val instanceof Boolean)
      {
        result = ((Boolean)val).booleanValue() ? m_true : m_false;
      }
      else if(val instanceof Double)
      {
        result = new XNumber(((Double)val).doubleValue());
      }
      else if(val instanceof DocumentFragment)
      {
        result = new XRTreeFrag((DocumentFragment)val);
      }
      else if(val instanceof Node)
      {
        // First, see if we need to follow-up with a location path.
        opPos = getNextOpPos(opPos);
        XNodeSet mnl = null;
        if((opPos < m_opMap[MAPINDEX_LENGTH]) &&
           (OP_LOCATIONPATH == (m_opMap[opPos] & XPath.LOCATIONPATHEX_MASK)))
        {
          mnl = locationPath(execContext, (Node)val, opPos, null, null, false);
        }
        result = (null == mnl) ? new XNodeSet((Node)val)
                                 : mnl;
      }
      else if(val instanceof NodeList)
      {
        // First, see if we need to follow-up with a location path.
        opPos = getNextOpPos(opPos);
        XNodeSet mnl = null;
        if((opPos < m_opMap[MAPINDEX_LENGTH]) &&
           (OP_LOCATIONPATH == (m_opMap[opPos] & XPath.LOCATIONPATHEX_MASK)))
        {
          NodeList nl = (NodeList)val;
          int nNodes = nl.getLength();
          for(int i = 0; i < nNodes; i++)
          {
            XNodeSet xnl = locationPath(execContext, nl.item(i), opPos, null, null, false);
            if(null == xnl)
              mnl = xnl;
            else
              mnl.mutableNodeset().addNodes(xnl.nodeset());
          }
        }
        result = (null == mnl) ? new XNodeSet((NodeList)val)
                                 : mnl;
      }
      else
      {
        result = new XObject(val);
      }
    }
    else
    {
      result = new XNull();
    }
    return result;
  }


  /**
   * Computes the union of its operands which must be node-sets.
   * @param context The current source tree context node.
   * @param opPos The current position in the m_opMap array.
   * @returns the match score in the form of an XObject.
   */
  protected XObject matchPattern(XPathSupport execContext, Node context, int opPos)
    throws org.xml.sax.SAXException
  {
    XObject score = null;

    while(m_opMap[opPos] == OP_LOCATIONPATHPATTERN)
    {
      int nextOpPos = getNextOpPos(opPos);
      score = execute(execContext, context, opPos);
      if(score.num() != MATCH_SCORE_NONE)
        break;
      opPos = nextOpPos;
    }
    if(null == score)
    {
      score = new XNumber(MATCH_SCORE_NONE);
    }
   
    return score;
  }

  /**
   * Execute a location path.
   * @param context The current source tree context node.
   * @param opPos The current position in the m_opMap array.
   * @returns score in an XNumber, one of MATCH_SCORE_NODETEST,
   * MATCH_SCORE_NONE, MATCH_SCORE_OTHER, MATCH_SCORE_QNAME.
   */
  protected XNumber locationPathPattern(XPathSupport execContext, Node context, int opPos)
    throws org.xml.sax.SAXException
  {   
    // opPos = getFirstChildPos(opPos);
    XLocator locator = execContext.getXLocatorFromNode(context);
   
    if(null == locator)
        locator = execContext.createXLocatorHandler();
     
    double results = locator.locationPathPattern(this, execContext, context, opPos);
   
    return new XNumber(results);
  }

  /**
   * <meta name="usage" content="advanced"/>
   * This method is for building indexes of match patterns for fast lookup.
   * This allows a caller to get the name or type of a node, and quickly
   * find the likely candidates that may match.
   */
  public Vector getTargetElementStrings()
  {
    Vector targetStrings = new Vector();

    int opPos = 2;

    while(m_opMap[opPos] == OP_LOCATIONPATHPATTERN)
    {
      int nextOpPos = getNextOpPos(opPos);
      opPos = getFirstChildPos(opPos);
     
      while( m_opMap[opPos] != ENDOP )
      {
        int nextStepPos = getNextOpPos(opPos);
        int nextOp = m_opMap[nextStepPos];
        if((nextOp == OP_PREDICATE) || (nextOp == ENDOP))
        {
          int stepType = m_opMap[opPos];
          opPos += 3;
          switch(stepType)
          {
          case OP_FUNCTION:
            targetStrings.addElement(PSEUDONAME_ANY);
            break;
          case FROM_ROOT:
            targetStrings.addElement(PSEUDONAME_ROOT);
            break;
          case MATCH_ATTRIBUTE:
          case MATCH_ANY_ANCESTOR:
          case MATCH_IMMEDIATE_ANCESTOR:
            int tok = m_opMap[opPos];
            opPos++;
            switch(tok)
            {
            case NODETYPE_COMMENT:
              targetStrings.addElement(PSEUDONAME_COMMENT);
              break;
            case NODETYPE_TEXT:
              targetStrings.addElement(PSEUDONAME_TEXT);
              break;
            case NODETYPE_NODE:
              targetStrings.addElement(PSEUDONAME_ANY);
              break;
            case NODETYPE_ROOT:
              targetStrings.addElement(PSEUDONAME_ROOT);
              break;
            case NODETYPE_ANYELEMENT:
              targetStrings.addElement(PSEUDONAME_ANY);
              break;
            case NODETYPE_PI:
              targetStrings.addElement(PSEUDONAME_ANY);
              break;
            case NODENAME:
              // Skip the namespace
              int tokenIndex = m_opMap[opPos+1];
              if(tokenIndex >= 0)
              {
                String targetName = (String)m_tokenQueue[tokenIndex];
                if(targetName.equals("*"))
                {
                  targetStrings.addElement(PSEUDONAME_ANY);
                }
                else
                {
                  targetStrings.addElement(targetName);
                }
              }
              else
              {
                targetStrings.addElement(PSEUDONAME_ANY);
              }
              break;
            default:
              targetStrings.addElement(PSEUDONAME_ANY);
              break;
            }
            break;
          }
        }
        opPos = nextStepPos;
      }
     
      opPos = nextOpPos;
    }
    return targetStrings;
  }
   
  /**
   * Execute an extension function from an op code.
   */
  private XObject executeExtension(XPathSupport execContext, Node context, int opPos)
    throws org.xml.sax.SAXException
  {
    int endExtFunc = opPos+m_opMap[opPos+1]-1;
    opPos = getFirstChildPos(opPos);
    String ns = (String)m_tokenQueue[m_opMap[opPos]];
    opPos++;
    String funcName = (String)m_tokenQueue[m_opMap[opPos]];
    opPos++;
    Vector args = new Vector();
    while(opPos < endExtFunc)
    {
      int nextOpPos = getNextOpPos(opPos);
      args.addElement( execute(execContext, context, opPos) );
      opPos = nextOpPos;
    }
    return extfunction(execContext, context, opPos, ns, funcName, args,
                       // Create a method key, for faster lookup.
      String.valueOf(m_opMap[opPos])+String.valueOf(((Object)this).hashCode()));
  }

  /**
   * Execute a function from an op code.
   */
  XObject executeFunction(XPathSupport execContext, Node context, int opPos)
    throws org.xml.sax.SAXException
  {
    int endFunc = opPos+m_opMap[opPos+1]-1;
    opPos = getFirstChildPos(opPos);
    int funcID = m_opMap[opPos];
    opPos++;
    if(-1 != funcID)
    {
      return m_functions[funcID].execute(this, execContext, context, opPos, funcID, endFunc);
    }
    else
    {
      warn(XPATHErrorResources.WG_FUNCTION_TOKEN_NOT_FOUND); //"function token not found.");
      return null;
    }
  }
 
  /**
   * <meta name="usage" content="advanced"/>
   * Execute the XPath object from a given opcode position.
   * @param execContext The execution context.
   * @param context The current source tree context node.
   * @param opPos The current position in the xpath.m_opMap array.
   * @param callback Interface that implements the processLocatedNode method.
   * @param callbackInfo Object that will be passed to the processLocatedNode method.
   * @return The result of the XPath.
   */
  public XObject execute(XPathSupport execContext,
                         Node context, int opPos)
    throws org.xml.sax.SAXException
  {
    int op = m_opMap[opPos];
    switch(op)
    {
    case OP_XPATH: return execute(execContext, context, opPos+2);
    case OP_OR: return or(execContext, context, opPos);
    case OP_AND: return and(execContext, context, opPos);
    case OP_NOTEQUALS: return notequals(execContext, context, opPos);
    case OP_EQUALS: return equals(execContext, context, opPos);
    case OP_LTE: return lte(execContext, context, opPos);
    case OP_LT: return lt(execContext, context, opPos);
    case OP_GTE: return gte(execContext, context, opPos);
    case OP_GT: return gt(execContext, context, opPos);
    case OP_PLUS: return plus(execContext, context, opPos);
    case OP_MINUS: return minus(execContext, context, opPos);
    case OP_MULT: return mult(execContext, context, opPos);
    case OP_DIV: return div(execContext, context, opPos);
    case OP_MOD: return mod(execContext, context, opPos);
    case OP_QUO: return quo(execContext, context, opPos);
    case OP_NEG: return neg(execContext, context, opPos);
    case OP_STRING: return string(execContext, context, opPos);
    case OP_BOOL: return bool(execContext, context, opPos);
    case OP_NUMBER: return number(execContext, context, opPos);
    case OP_UNION: return union(execContext, context, opPos, null, null);
    case OP_LITERAL: return literal(execContext, context, opPos);
    case OP_VARIABLE: return variable(execContext, context, opPos);
    case OP_GROUP: return group(execContext, context, opPos);
    case OP_NUMBERLIT: return numberlit(execContext, context, opPos);
    case OP_ARGUMENT: return arg(execContext, context, opPos);
    case OP_EXTFUNCTION: return executeExtension(execContext, context, opPos);
    case OP_FUNCTION: return executeFunction(execContext, context, opPos);
    case OP_LOCATIONPATH: return locationPath(execContext, context, opPos, null, null, false);
    case OP_PREDICATE: return null; // should never hit this here.
    case OP_MATCHPATTERN: return matchPattern(execContext, context, opPos+2);
    case OP_LOCATIONPATHPATTERN: return locationPathPattern(execContext, context, opPos);
    default: if(op == OP_LOCATIONPATH_EX) return locationPath(execContext, context, opPos, null, null, false);
             else error(context, XPATHErrorResources.ER_UNKNOWN_OPCODE, new Object[] {Integer.toString(m_opMap[opPos])}); //"ERROR! Unknown op code: "+m_opMap[opPos]);
    }
    return null;
  }

  /**
   * <meta name="usage" content="advanced"/>
   * Execute the XPath object from a given opcode position, calling back
   * to a NodeCallback interface as the nodes are found.  This will return
   * null if the path is simple enough for callbacks to be used, otherwise
   * it will return an XObject.
   * @param execContext The execution context.
   * @param context The current source tree context node.
   * @param opPos The current position in the xpath.m_opMap array.
   * @param callback Interface that implements the processLocatedNode method.
   * @param callbackInfo Object that will be passed to the processLocatedNode method.
   * @return The result of the XPath or null if callbacks are used.
   */
  public XObject execute(XPathSupport execContext, Node context, int opPos,
                         NodeCallback callback, Object callbackInfo, boolean stopAtFirst)
    throws org.xml.sax.SAXException
  {
    int op = m_opMap[opPos];
    switch(op)
    {
    case OP_XPATH: return execute(execContext, context, opPos+2, callback, callbackInfo, stopAtFirst);
    case OP_OR: return or(execContext, context, opPos);
    case OP_AND: return and(execContext, context, opPos);
    case OP_NOTEQUALS: return notequals(execContext, context, opPos);
    case OP_EQUALS: return equals(execContext, context, opPos);
    case OP_LTE: return lte(execContext, context, opPos);
    case OP_LT: return lt(execContext, context, opPos);
    case OP_GTE: return gte(execContext, context, opPos);
    case OP_GT: return gt(execContext, context, opPos);
    case OP_PLUS: return plus(execContext, context, opPos);
    case OP_MINUS: return minus(execContext, context, opPos);
    case OP_MULT: return mult(execContext, context, opPos);
    case OP_DIV: return div(execContext, context, opPos);
    case OP_MOD: return mod(execContext, context, opPos);
    case OP_QUO: return quo(execContext, context, opPos);
    case OP_NEG: return neg(execContext, context, opPos);
    case OP_STRING: return string(execContext, context, opPos);
    case OP_BOOL: return bool(execContext, context, opPos);
    case OP_NUMBER: return number(execContext, context, opPos);
    case OP_UNION: return union(execContext, context, opPos, callback, callbackInfo);
    case OP_LITERAL: return literal(execContext, context, opPos);
    case OP_VARIABLE: return variable(execContext, context, opPos);
    case OP_GROUP: return group(execContext, context, opPos);
    case OP_NUMBERLIT: return numberlit(execContext, context, opPos);
    case OP_ARGUMENT: return arg(execContext, context, opPos);
    case OP_EXTFUNCTION: return executeExtension(execContext, context, opPos);
    case OP_FUNCTION: return executeFunction(execContext, context, opPos);
    case OP_LOCATIONPATH: return locationPath(execContext, context, opPos, callback, callbackInfo, stopAtFirst);
    case OP_PREDICATE: return null; // should never hit this here.
    case OP_MATCHPATTERN: return matchPattern(execContext, context, opPos+2);
    case OP_LOCATIONPATHPATTERN: return locationPathPattern(execContext, context, opPos);
    default: if(op == OP_LOCATIONPATH_EX) return locationPath(execContext, context, opPos, callback, callbackInfo, stopAtFirst);
             else error(context, XPATHErrorResources.ER_UNKNOWN_OPCODE, new Object[] {Integer.toString(m_opMap[opPos])}); //"ERROR! Unknown op code: "+m_opMap[opPos]);
    }
   
    return null;
  }
 
  /**
   * <meta name="usage" content="advanced"/>
   * Given an operation position, return the current op.
   * @return position of next operation in m_opMap.
   */
  public int getOp(int opPos)
  {
    return m_opMap[opPos];
  }

  /**
   * <meta name="usage" content="advanced"/>
   * Given an operation position, return the end position, i.e. the
   * beginning of the next operation.
   * @return position of next operation in m_opMap.
   */
  public int getNextOpPos(int opPos)
  {
    return opPos+m_opMap[opPos+1];
  }
 
  /**
   * <meta name="usage" content="advanced"/>
   * Given an operation position, return the end position, i.e. the
   * beginning of the next operation.
   * @return position of next operation in m_opMap.
   */
  public static int getNextOpPos(int[] opMap, int opPos)
  {
    return opPos+opMap[opPos+1];
  }
 
  /**
   * <meta name="usage" content="advanced"/>
   * Go to the first child of a given operation.
   */
  public static int getFirstChildPos(int opPos)
  {
    return opPos+2;
  }

  /**
   * <meta name="usage" content="advanced"/>
   * Go to the first child of a given operation.
   */
  public int getArgLengthOfStep(int opPos)
  {
    return m_opMap[opPos+MAPINDEX_LENGTH+1]-3;
  }

  /**
   * <meta name="usage" content="advanced"/>
   * Go to the first child of a given operation.
   */
  public static int getFirstChildPosOfStep(int opPos)
  {
    return opPos+3;
  }

  /**
   * Simple trace function.
   */
  private final void trace(String s)
  {
    System.out.println(s);
  }

  /**
   * Warn the user of an problem.
   */
  void warn(int msg)
    throws org.xml.sax.SAXException
  {
    warn(null, msg, null);
  }
 
  /**
   * Warn the user of an problem.
   */
  void warn(int msg, Object[]args)
    throws org.xml.sax.SAXException
  {
    warn(null, msg, args);
  }

  /**
   * Warn the user of an problem.
   */
  void warn(Node sourceNode, int msg)
    throws org.xml.sax.SAXException
  {
    warn(sourceNode, msg, null);
  }    

  /**
   * Warn the user of an problem.
   */
  void warn(Node sourceNode, int msg, Object[] args)
    throws org.xml.sax.SAXException
  {
    String fmsg = XSLMessages.createXPATHWarning(msg, args);
    boolean shouldThrow = this.m_problemListener.problem(ProblemListener.XPATHPROCESSOR,
                                              ProblemListener.WARNING,
                                              (Object)null, // should be the namespace context
                                              sourceNode, fmsg, null, 0, 0);
    if(shouldThrow)
    {
      throw new XPathException(fmsg);
    }
  }

  /**
   * Tell the user of an assertion error, and probably throw an
   * exception.
   */
  private void assert(boolean b, String msg)
    throws org.xml.sax.SAXException
  {
    if(!b)
      error(null, XPATHErrorResources.ER_INCORRECT_PROGRAMMER_ASSERTION, new Object[] {msg}); //"Programmer assertion is incorrect! - "+msg);
  }

  /**
   * Tell the user of an error, and probably throw an
   * exception.
   */
  void error(int msg)
    throws org.xml.sax.SAXException
  {
    error(null, msg, null);
  }

  /**
   * Tell the user of an error, and probably throw an
   * exception.
   */
  void error(int msg, Object[]args )
    throws org.xml.sax.SAXException
  {
    error(null, msg, args);
  }
 
  /**
   * Tell the user of an error, and probably throw an
   * exception.
   */
  void error(Node sourceNode, int msg)
    throws org.xml.sax.SAXException
  {
    error(sourceNode, msg, null);
  }    

  /**
   * Tell the user of an error, and probably throw an
   * exception.
   */
  void error(Node sourceNode, int msg, Object[] args)
    throws org.xml.sax.SAXException
  {
    String fMsg = XSLMessages.createXPATHMessage(msg, args);
    String emsg = ((null != m_currentPattern)
                   ? ("pattern = '"+m_currentPattern+"'\n") : "") +
                  fMsg;

    boolean shouldThrow = this.m_problemListener.problem(ProblemListener.XPATHPROCESSOR,
                                                         ProblemListener.ERROR,
                                                         null, // Should be the namespace context
                                                         sourceNode, emsg, null, 0, 0);
    if(shouldThrow)
    {
      throw new XPathException(emsg);
    }
  }
   
  /**
   * <meta name="usage" content="advanced"/>
   * The match score if no match is made.
   */
  public static final double MATCH_SCORE_NONE = Double.NEGATIVE_INFINITY;

  /**
   * <meta name="usage" content="advanced"/>
   * The match score if the pattern has the form
   * of a QName optionally preceded by an @ character.
   */
  public static final double MATCH_SCORE_QNAME = 0.0;
 
  /**
   * <meta name="usage" content="advanced"/>
   * The match score if the pattern pattern has the form NCName:*.
   */
  public static final double MATCH_SCORE_NSWILD = -0.25;

  /**
   * <meta name="usage" content="advanced"/>
   * The match score if the pattern consists of just a NodeTest.
   */
  public static final double MATCH_SCORE_NODETEST = -0.5;

  /**
   * <meta name="usage" content="advanced"/>
   * The match score if the pattern consists of something
   * other than just a NodeTest or just a qname.
   */
  public static final double MATCH_SCORE_OTHER = 0.5;

  // List of operations codes.
  //
  // Code for the descriptions of the operations codes:
  // [UPPER CASE] indicates a literal value,
  // [lower case] is a description of a value,
  //      ([length] always indicates the length of the operation,
  //       including the operations code and the length integer.)
  // {UPPER CASE} indicates the given production,
  // {description} is the description of a new production,
  //      (For instance, {boolean expression} means some expression
  //       that should be resolved to a boolean.)
  //  * means that it occurs zero or more times,
  //  + means that it occurs one or more times,
  //  ? means that it is optional.
  //
  // returns: indicates what the production should return.

  /**
   * <meta name="usage" content="advanced"/>
   * [ENDOP]
   * Some operators may like to have a terminator.
   */
  public static final int ENDOP = -1;
 
  /**
   * [EMPTY]
   * Empty slot to indicate NULL.
   */
  public static final int EMPTY = -2;

  /**
   * <meta name="usage" content="advanced"/>
   * [ELEMWILDCARD]
   * Means ELEMWILDCARD ("*"), used instead
   * of string index in some places.
   */
  public static final int ELEMWILDCARD = -3;

  /**
   * <meta name="usage" content="advanced"/>
   * [OP_XPATH]
   * [length]
   *  {expression}
   *
   * returns:
   *  XNodeSet
   *  XNumber
   *  XString
   *  XBoolean
   *  XRTree
   *  XObject
   */
  public static final int OP_XPATH = 1;
 
  /**
   * <meta name="usage" content="advanced"/>
   * [OP_OR]
   * [length]
   *  {boolean expression}
   *  {boolean expression}
   *
   * returns:
   *  XBoolean
   */
  public static final int OP_OR = 2;
 
  /**
   * <meta name="usage" content="advanced"/>
   * [OP_AND]
   * [length]
   *  {boolean expression}
   *  {boolean expression}
   *
   * returns:
   *  XBoolean
   */
  public static final int OP_AND = 3;
 
  /**
   * <meta name="usage" content="advanced"/>
   * [OP_NOTEQUALS]
   * [length]
   *  {expression}
   *  {expression}
   *
   * returns:
   *  XBoolean
   */
  public static final int OP_NOTEQUALS = 4;

  /**
   * <meta name="usage" content="advanced"/>
   * [OP_EQUALS]
   * [length]
   *  {expression}
   *  {expression}
   *
   * returns:
   *  XBoolean
   */
  public static final int OP_EQUALS = 5;

  /**
   * <meta name="usage" content="advanced"/>
   * [OP_LTE] (less-than-or-equals)
   * [length]
   *  {number expression}
   *  {number expression}
   *
   * returns:
   *  XBoolean
   */
  public static final int OP_LTE = 6;

  /**
   * <meta name="usage" content="advanced"/>
   * [OP_LT] (less-than)
   * [length]
   *  {number expression}
   *  {number expression}
   *
   * returns:
   *  XBoolean
   */
  public static final int OP_LT = 7;

  /**
   * <meta name="usage" content="advanced"/>
   * [OP_GTE] (greater-than-or-equals)
   * [length]
   *  {number expression}
   *  {number expression}
   *
   * returns:
   *  XBoolean
   */
  public static final int OP_GTE = 8;

  /**
   * <meta name="usage" content="advanced"/>
   * [OP_GT] (greater-than)
   * [length]
   *  {number expression}
   *  {number expression}
   *
   * returns:
   *  XBoolean
   */
  public static final int OP_GT = 9;

  /**
   * <meta name="usage" content="advanced"/>
   * [OP_PLUS]
   * [length]
   *  {number expression}
   *  {number expression}
   *
   * returns:
   *  XNumber
   */
  public static final int OP_PLUS = 10;

  /**
   * <meta name="usage" content="advanced"/>
   * [OP_MINUS]
   * [length]
   *  {number expression}
   *  {number expression}
   *
   * returns:
   *  XNumber
   */
  public static final int OP_MINUS = 11;

  /**
   * <meta name="usage" content="advanced"/>
   * [OP_MULT]
   * [length]
   *  {number expression}
   *  {number expression}
   *
   * returns:
   *  XNumber
   */
  public static final int OP_MULT = 12;

  /**
   * <meta name="usage" content="advanced"/>
   * [OP_DIV]
   * [length]
   *  {number expression}
   *  {number expression}
   *
   * returns:
   *  XNumber
   */
  public static final int OP_DIV = 13;

  /**
   * <meta name="usage" content="advanced"/>
   * [OP_MOD]
   * [length]
   *  {number expression}
   *  {number expression}
   *
   * returns:
   *  XNumber
   */
  public static final int OP_MOD = 14;

  /**
   * <meta name="usage" content="advanced"/>
   * [OP_QUO]
   * [length]
   *  {number expression}
   *  {number expression}
   *
   * returns:
   *  XNumber
   */
  public static final int OP_QUO = 15;


  /**
   * <meta name="usage" content="advanced"/>
   * [OP_NEG]
   * [length]
   *  {number expression}
   *
   * returns:
   *  XNumber
   */
  public static final int OP_NEG = 16;
 
  /**
   * <meta name="usage" content="advanced"/>
   * [OP_STRING] (cast operation)
   * [length]
   *  {expression}
   *
   * returns:
   *  XString
   */
  public static final int OP_STRING = 17;
 
  /**
   * <meta name="usage" content="advanced"/>
   * [OP_BOOL] (cast operation)
   * [length]
   *  {expression}
   *
   * returns:
   *  XBoolean
   */
  public static final int OP_BOOL = 18;


  /**
   * <meta name="usage" content="advanced"/>
   * [OP_NUMBER] (cast operation)
   * [length]
   *  {expression}
   *
   * returns:
   *  XBoolean
   */
  public static final int OP_NUMBER = 19;

  /**
   * <meta name="usage" content="advanced"/>
   * [OP_UNION]
   * [length]
   *  {PathExpr}+
   *
   * returns:
   *  XNodeSet
   */
  public static final int OP_UNION = 20;
 
  /**
   * <meta name="usage" content="advanced"/>
   * [OP_LITERAL]
   * [3]
   * [index to token]
   *
   * returns:
   *  XString
   */
  public static final int OP_LITERAL = 21;
 
  /**
   * <meta name="usage" content="advanced"/>
   * [OP_VARIABLE]
   * [3]
   * [index to token]
   *
   * returns:
   *  XString
   */
  public static final int OP_VARIABLE = 22;
   
  /**
   * <meta name="usage" content="advanced"/>
   * [OP_GROUP]
   * [length]
   *  {expression}
   *
   * returns:
   *  XNodeSet
   *  XNumber
   *  XString
   *  XBoolean
   *  XRTree
   *  XObject
   */
  public static final int OP_GROUP = 23;

  /**
   * <meta name="usage" content="advanced"/>
   * [OP_NUMBERLIT] (Number literal.)
   * [3]
   * [index to token]
   *
   * returns:
   *  XString
   */
  public static final int OP_NUMBERLIT = 24;

  /**
   * <meta name="usage" content="advanced"/>
   * [OP_ARGUMENT] (Function argument.)
   * [length]
   *  {expression}
   *
   * returns:
   *  XNodeSet
   *  XNumber
   *  XString
   *  XBoolean
   *  XRTree
   *  XObject
   */
  public static final int OP_ARGUMENT = 25;
 
  /**
   * <meta name="usage" content="advanced"/>
   * [OP_EXTFUNCTION] (Extension function.)
   * [length]
   * [index to namespace token]
   * [index to function name token]
   *  {OP_ARGUMENT}*
   *
   * returns:
   *  XNodeSet
   *  XNumber
   *  XString
   *  XBoolean
   *  XRTree
   *  XObject
   */
  public static final int OP_EXTFUNCTION = 26;
 
 
  /**
   * <meta name="usage" content="advanced"/>
   * [OP_FUNCTION]
   * [length]
   * [FUNC_name]
   *  {OP_ARGUMENT}*
   * [ENDOP]
   *
   * returns:
   *  XNodeSet
   *  XNumber
   *  XString
   *  XBoolean
   *  XRTree
   *  XObject
   */
  public static final int OP_FUNCTION = 27;
 
  /**
   * <meta name="usage" content="advanced"/>
   * [OP_LOCATIONPATH]
   * [length]
   *   {FROM_stepType}
   * | {function}{predicate}*
   * [ENDOP]
   *
   * (Note that element and attribute namespaces and
   * names can be wildcarded '*'.)
   *
   * returns:
   *  XNodeSet
   */
  public static final int OP_LOCATIONPATH = 28;
  public static final int LOCATIONPATHEX_MASK = 0x0000FFFF;
  public static final int LOCATIONPATHEX_ISSIMPLE = 0x00010000;
  public static final int OP_LOCATIONPATH_EX = (28 | 0x00010000);
   

  /**
   * <meta name="usage" content="advanced"/>
   * [OP_PREDICATE]
   * [length]
   *  {expression}
   * [ENDOP] (For safety)
   *
   * returns:
   *  XBoolean or XNumber
   */
  public static final int OP_PREDICATE = 29;
 
  /**
   * <meta name="usage" content="advanced"/>
   * [OP_UNION]
   * [length]
   *  {PathExpr}+
   *
   * returns:
   *  XNodeSet
   */
  public static final int OP_MATCHPATTERN = 30;
 
 
  /**
   * <meta name="usage" content="advanced"/>
   * [OP_UNION]
   * [length]
   *  {PathExpr}+
   *
   * returns:
   *  XNodeSet
   */
  public static final int OP_LOCATIONPATHPATTERN = 31;

 
  /**
   * <meta name="usage" content="advanced"/>
   * [NODETYPE_COMMENT]
   * No size or arguments.
   * Note: must not overlap function OP number!
   *
   * returns:
   *  XBoolean
   */
  public static final int NODETYPE_COMMENT = 1030;
   
  /**
   * <meta name="usage" content="advanced"/>
   * [NODETYPE_TEXT]
   * No size or arguments.
   * Note: must not overlap function OP number!
   *
   * returns:
   *  XBoolean
   */
  public static final int NODETYPE_TEXT = 1031;
   
  /**
   * <meta name="usage" content="advanced"/>
   * [NODETYPE_PI]
   * [index to token]
   * Note: must not overlap function OP number!
   *
   * returns:
   *  XBoolean
   */
  public static final int NODETYPE_PI = 1032;
   
  /**
   * <meta name="usage" content="advanced"/>
   * [NODETYPE_NODE]
   * No size or arguments.
   * Note: must not overlap function OP number!
   *
   * returns:
   *  XBoolean
   */
  public static final int NODETYPE_NODE = 1033;
   
  /**
   * <meta name="usage" content="advanced"/>
   * [NODENAME]
   * [index to ns token or EMPTY]
   * [index to name token]
   *
   * returns:
   *  XBoolean
   */
  public static final int NODENAME = 34;
   
  /**
   * <meta name="usage" content="advanced"/>
   * [NODETYPE_ROOT]
   * No size or arguments.
   *
   * returns:
   *  XBoolean
   */
  public static final int NODETYPE_ROOT = 35;
   
  /**
   * <meta name="usage" content="advanced"/>
   * [NODETYPE_ANY]
   * No size or arguments.
   *
   * returns:
   *  XBoolean
   */
  public static final int NODETYPE_ANYELEMENT = 36;
 
  /**
   * <meta name="usage" content="advanced"/>
   * [FROM_stepType]
   * [length, including predicates]
   * [length of just the step, without the predicates]
   * {node test}
   * {predicates}?
   *
   * returns:
   *  XBoolean
   */
  public static final int FROM_ANCESTORS = 37;
  public static final int FROM_ANCESTORS_OR_SELF = 38;
  public static final int FROM_ATTRIBUTES = 39;
  public static final int FROM_CHILDREN = 40;
  public static final int FROM_DESCENDANTS = 41;
  public static final int FROM_DESCENDANTS_OR_SELF = 42;
  public static final int FROM_FOLLOWING = 43;
  public static final int FROM_FOLLOWING_SIBLINGS = 44;
  public static final int FROM_PARENT = 45;
  public static final int FROM_PRECEDING = 46;
  public static final int FROM_PRECEDING_SIBLINGS = 47;
  public static final int FROM_SELF = 48;
  public static final int FROM_NAMESPACE = 49
  public static final int FROM_ROOT = 55
  // public static final int FROM_ATTRIBUTE = 50;
  // public static final int FROM_DOC = 51;
  // public static final int FROM_DOCREF = 52;
  // public static final int FROM_ID = 53;
  // public static final int FROM_IDREF = 54;
 
  public static final int FUNC_CURRENT = 0;
  public static final int FUNC_LAST = 1;
  public static final int FUNC_POSITION = 2;
  public static final int FUNC_COUNT = 3;
  public static final int FUNC_ID = 4;
  public static final int FUNC_KEY = 5;
  // public static final int FUNC_DOC = 6;
  public static final int FUNC_LOCAL_PART = 7;
  public static final int FUNC_NAMESPACE = 8;
  public static final int FUNC_QNAME = 9;
  public static final int FUNC_GENERATE_ID = 10;
  public static final int FUNC_NOT = 11;
  public static final int FUNC_TRUE = 12;
  public static final int FUNC_FALSE = 13;
  public static final int FUNC_BOOLEAN = 14;
  public static final int FUNC_NUMBER = 15;
  public static final int FUNC_FLOOR = 16;
  public static final int FUNC_CEILING = 17;
  public static final int FUNC_ROUND = 18;
  public static final int FUNC_SUM = 19;
  public static final int FUNC_STRING = 20;
  public static final int FUNC_STARTS_WITH = 21;
  public static final int FUNC_CONTAINS = 22;
  public static final int FUNC_SUBSTRING_BEFORE = 23;
  public static final int FUNC_SUBSTRING_AFTER = 24;
  public static final int FUNC_NORMALIZE_SPACE = 25;
  public static final int FUNC_TRANSLATE = 26;
  public static final int FUNC_CONCAT = 27;
// public static final int FUNC_FORMAT_NUMBER = 28;
  public static final int FUNC_SUBSTRING = 29;
  public static final int FUNC_STRING_LENGTH = 30;
  public static final int FUNC_SYSTEM_PROPERTY = 31;
  public static final int FUNC_LANG = 32;
  public static final int FUNC_EXT_FUNCTION_AVAILABLE = 33;
  public static final int FUNC_EXT_ELEM_AVAILABLE = 34;
   
  // Proprietary
  public static final int FUNC_DOCLOCATION = 35;

  public static final int FUNC_UNPARSED_ENTITY_URI = 36;

  /**
   * Number of built in functions.  Be sure to update this as
   * built-in functions are added.
   */
  private static final int NUM_BUILT_IN_FUNCS = 37;

  /**
   * Number of built-in functions that may be added.
   */
  private static final int NUM_ALLOWABLE_ADDINS = 30;

  /**
   * The function table.
   */
  static private Function m_functions[];
 
  /**
   * The index to the next free function index.
   */
  static private int m_funcNextFreeIndex = NUM_BUILT_IN_FUNCS;
 
  static
  {
    m_functions = new Function[NUM_BUILT_IN_FUNCS+NUM_ALLOWABLE_ADDINS];
    m_functions[FUNC_CURRENT] = new FuncLoader("FuncCurrent", FUNC_CURRENT);
    m_functions[FUNC_LAST] = new FuncLoader("FuncLast", FUNC_LAST);
    m_functions[FUNC_POSITION] = new FuncLoader("FuncPosition", FUNC_POSITION);
    m_functions[FUNC_COUNT] = new FuncLoader("FuncCount", FUNC_COUNT);
    m_functions[FUNC_ID] = new FuncLoader("FuncId", FUNC_ID);
    m_functions[FUNC_KEY] = new FuncLoader("FuncKey", FUNC_KEY);
    // m_functions[FUNC_DOC] = new FuncDoc();
    m_functions[FUNC_LOCAL_PART] = new FuncLoader("FuncLocalPart", FUNC_LOCAL_PART);
    m_functions[FUNC_NAMESPACE] = new FuncLoader("FuncNamespace", FUNC_NAMESPACE);
    m_functions[FUNC_QNAME] = new FuncLoader("FuncQname", FUNC_QNAME);
    m_functions[FUNC_GENERATE_ID] = new FuncLoader("FuncGenerateId", FUNC_GENERATE_ID);
    m_functions[FUNC_NOT] = new FuncLoader("FuncNot", FUNC_NOT);
    m_functions[FUNC_TRUE] = new FuncLoader("FuncTrue", FUNC_TRUE);
    m_functions[FUNC_FALSE] = new FuncLoader("FuncFalse", FUNC_FALSE);
    m_functions[FUNC_BOOLEAN] = new FuncLoader("FuncBoolean", FUNC_BOOLEAN);
    m_functions[FUNC_LANG] = new FuncLoader("FuncLang", FUNC_LANG);
    m_functions[FUNC_NUMBER] = new FuncLoader("FuncNumber", FUNC_NUMBER);
    m_functions[FUNC_FLOOR] = new FuncLoader("FuncFloor", FUNC_FLOOR);
    m_functions[FUNC_CEILING] = new FuncLoader("FuncCeiling", FUNC_CEILING);
    m_functions[FUNC_ROUND] = new FuncLoader("FuncRound", FUNC_ROUND);
    m_functions[FUNC_SUM] = new FuncLoader("FuncSum", FUNC_SUM);
    m_functions[FUNC_STRING] = new FuncLoader("FuncString", FUNC_STRING);
    m_functions[FUNC_STARTS_WITH] = new FuncLoader("FuncStartsWith", FUNC_STARTS_WITH);
    m_functions[FUNC_CONTAINS] = new FuncLoader("FuncContains", FUNC_CONTAINS);
    m_functions[FUNC_SUBSTRING_BEFORE] = new FuncLoader("FuncSubstringBefore", FUNC_SUBSTRING_BEFORE);
    m_functions[FUNC_SUBSTRING_AFTER] = new FuncLoader("FuncSubstringAfter", FUNC_SUBSTRING_AFTER);
    m_functions[FUNC_NORMALIZE_SPACE] = new FuncLoader("FuncNormalizeSpace", FUNC_NORMALIZE_SPACE);
    m_functions[FUNC_TRANSLATE] = new FuncLoader("FuncTranslate", FUNC_TRANSLATE);
    m_functions[FUNC_CONCAT] = new FuncLoader("FuncConcat", FUNC_CONCAT);
    //m_functions[FUNC_FORMAT_NUMBER] = new FuncFormatNumber();
    m_functions[FUNC_SYSTEM_PROPERTY] = new FuncLoader("FuncSystemProperty", FUNC_SYSTEM_PROPERTY);
    m_functions[FUNC_EXT_FUNCTION_AVAILABLE] = new FuncLoader("FuncExtFunctionAvailable", FUNC_EXT_FUNCTION_AVAILABLE);
    m_functions[FUNC_EXT_ELEM_AVAILABLE] = new FuncLoader("FuncExtElementAvailable", FUNC_EXT_ELEM_AVAILABLE);
    m_functions[FUNC_SUBSTRING] = new FuncLoader("FuncSubstring", FUNC_SUBSTRING);
    m_functions[FUNC_STRING_LENGTH] = new FuncLoader("FuncStringLength", FUNC_STRING_LENGTH);
    m_functions[FUNC_DOCLOCATION] = new FuncLoader("FuncDoclocation", FUNC_DOCLOCATION);
    m_functions[FUNC_UNPARSED_ENTITY_URI] = new FuncLoader("FuncUnparsedEntityURI", FUNC_UNPARSED_ENTITY_URI);
   
  }
     
  /**
   * <meta name="usage" content="advanced"/>
   * For match patterns.
   */
  public static final int MATCH_ATTRIBUTE = 94
     
  /**
   * <meta name="usage" content="advanced"/>
   * For match patterns.
   */
  public static final int MATCH_ANY_ANCESTOR = 95
     
  /**
   * <meta name="usage" content="advanced"/>
   * For match patterns.
   */
  public static final int MATCH_IMMEDIATE_ANCESTOR = 96;
 
  /**
   * <meta name="usage" content="advanced"/>
   * used mainly for keys in the pattern lookup table,
   * for those nodes that don't have unique lookup values.
   */
  public static final String PSEUDONAME_ANY = "*";
 
  /**
   * <meta name="usage" content="advanced"/>
   * used mainly for keys in the pattern lookup table,
   * for those nodes that don't have unique lookup values.
   */
  public static final String PSEUDONAME_ROOT = "/";
 
  /**
   * <meta name="usage" content="advanced"/>
   * used mainly for keys in the pattern lookup table,
   * for those nodes that don't have unique lookup values.
   */
  public static final String PSEUDONAME_TEXT = "#text";
 
  /**
   * <meta name="usage" content="advanced"/>
   * used mainly for keys in the pattern lookup table,
   * for those nodes that don't have unique lookup values.
   */
  public static final String PSEUDONAME_COMMENT = "#comment";
 
  /**
   * <meta name="usage" content="advanced"/>
   * used mainly for keys in the pattern lookup table,
   * for those nodes that don't have unique lookup values.
   */
  public static final String PSEUDONAME_PI = "#pi";
 
  /**
   * <meta name="usage" content="advanced"/>
   * used mainly for keys in the pattern lookup table,
   * for those nodes that don't have unique lookup values.
   */
  public static final String PSEUDONAME_OTHER = "*";
 
  private static final int NEXT_FREE_ID = 99;  
}
TOP

Related Classes of org.apache.xalan.xpath.XPath

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.