You are viewing a plain text version of this content. The canonical link for it is here.
Posted to xindice-dev@xml.apache.org by vg...@apache.org on 2004/03/04 14:52:20 UTC

cvs commit: xml-xindice/java/src/org/apache/xindice/core/query XPathQueryResolver.java

vgritsenko    2004/03/04 05:52:20

  Modified:    java/src/org/apache/xindice/core/query
                        XPathQueryResolver.java
  Log:
  Zap tabs; reformat.
  
  Revision  Changes    Path
  1.29      +1190 -1410xml-xindice/java/src/org/apache/xindice/core/query/XPathQueryResolver.java
  
  Index: XPathQueryResolver.java
  ===================================================================
  RCS file: /home/cvs/xml-xindice/java/src/org/apache/xindice/core/query/XPathQueryResolver.java,v
  retrieving revision 1.28
  retrieving revision 1.29
  diff -u -r1.28 -r1.29
  --- XPathQueryResolver.java	4 Mar 2004 13:18:49 -0000	1.28
  +++ XPathQueryResolver.java	4 Mar 2004 13:52:20 -0000	1.29
  @@ -85,1464 +85,1244 @@
    *
    * @version CVS $Revision$, $Date$
    */
  -public final class XPathQueryResolver extends SimpleConfigurable implements QueryResolver
  -{
  -	private static final Log log = LogFactory.getLog(XPathQueryResolver.class);
  -
  -	private static final Key[] EMPTY_KEYS = new Key[0];
  -	private static final Key[][] EMPTY_KEYSET = new Key[0][0];
  -	private static final String WILDCARD = "*";
  -	// private static final String THISNODE = ".";
  -	// private static final String PARENTNODE = "..";
  +public final class XPathQueryResolver extends SimpleConfigurable implements QueryResolver {
  +    private static final Log log = LogFactory.getLog(XPathQueryResolver.class);
   
  -	private static final String AUTOINDEX = "autoindex";
  +    private static final Key[] EMPTY_KEYS = new Key[0];
  +    private static final Key[][] EMPTY_KEYSET = new Key[0][0];
  +    private static final String WILDCARD = "*";
  +    // private static final String THISNODE = ".";
  +    // private static final String PARENTNODE = "..";
   
  -	public static final String STYLE_XPATH = "XPath";
  +    private static final String AUTOINDEX = "autoindex";
   
  -	// Maps Xalan Comparisons To IndexQuery
  -	private static final int[] OpMap = {
  +    public static final String STYLE_XPATH = "XPath";
  +
  +    // Maps Xalan Comparisons To IndexQuery
  +    private static final int[] OpMap = {
           IndexQuery.NEQ, IndexQuery.EQ, IndexQuery.LEQ, IndexQuery.LT, IndexQuery.GEQ, IndexQuery.GT
       };
   
  -	private DefaultErrorHandler errorListener = new DefaultErrorHandler();
  -	private boolean autoIndex = false;
  +    private DefaultErrorHandler errorListener = new DefaultErrorHandler();
  +    private boolean autoIndex = false;
   
   
  -	public void setConfig(Configuration config) throws XindiceException
  -	{
  -		super.setConfig(config);
  -		autoIndex = config.getBooleanAttribute(AUTOINDEX, autoIndex);
  -	}
  -
  -	public String getQueryStyle()
  -	{
  -		return STYLE_XPATH;
  -	}
  -
  -	public void setQueryEngine(QueryEngine engine)
  -	{
  -		// Not used: this.engine = engine;
  -	}
  -
  -	public Query compileQuery(Collection context, String query, NamespaceMap nsMap, Key[] keys) throws QueryException
  -	{
  -		return new XPathQuery(context, query, nsMap, keys);
  -	}
  -
  -	public NodeSet query(Collection context, String query, NamespaceMap nsMap, Key[] keys) throws QueryException
  -	{
  -		XPathQuery xq = new XPathQuery(context, query, nsMap, keys);
  -		return xq.execute();
  -	}
  +    public void setConfig(Configuration config) throws XindiceException {
  +        super.setConfig(config);
  +        autoIndex = config.getBooleanAttribute(AUTOINDEX, autoIndex);
  +    }
  +
  +    public String getQueryStyle() {
  +        return STYLE_XPATH;
  +    }
  +
  +    public void setQueryEngine(QueryEngine engine) {
  +        // Not used: this.engine = engine;
  +    }
  +
  +    public Query compileQuery(Collection context, String query, NamespaceMap nsMap, Key[] keys)
  +            throws QueryException {
  +        return new XPathQuery(context, query, nsMap, keys);
  +    }
  +
  +    public NodeSet query(Collection context, String query, NamespaceMap nsMap, Key[] keys)
  +            throws QueryException {
  +        XPathQuery xq = new XPathQuery(context, query, nsMap, keys);
  +        return xq.execute();
  +    }
   
   	/**
  -	 * XPathQuery
  -	 */
  -	private class XPathQuery implements Query
  -	{
  -		public Collection context;
  -		public IndexManager idxMgr;
  -		public NamespaceMap nsMap;
  -		public PrefixResolver pr;
  -		public SymbolTable symbols;
  -		public String query;
  -		public Compiler cmp;
  -		public XPath xp;
  -		public Key[] keys;
  -
  -		public XPathQuery(Collection context, String query, NamespaceMap nsMap, Key[] keys) throws QueryException
  -		{
  -			this.context = context;
  -			this.query = query;
  -			this.nsMap = nsMap;
  -			this.keys = keys;
  -
  -			Expression ex = null;
  -
  -			try
  -			{
  -				if (nsMap != null)
  -				{
  -					Node n = nsMap.getContextNode();
  -					pr = new PrefixResolverDefault(n);
  -				}
  -
  -				XPathParser parser = new XPathParser(errorListener, null);
  -				cmp = new Compiler(errorListener, null);
  -				parser.initXPath(cmp, query, pr);
  -				ex = cmp.compile(0);
  -
  -				symbols = context.getSymbols();
  -				idxMgr = context.getIndexManager();
  -			}
  -			catch (Exception e)
  -			{
  -				throw new CompilationException("Error Compiling XPath Expression", e);
  -			}
  -			if (ex == null)
  -			{
  -				throw new CompilationException("Error Compiling XPath Expression: XPath Compiler.compile returned null");
  -			}
  -		}
  -
  -		public String getQueryStyle()
  -		{
  -			return STYLE_XPATH;
  -		}
  -
  -		public String getQueryString()
  -		{
  -			return query;
  -		}
  -
  -		public Collection getQueryContext()
  -		{
  -			return context;
  -		}
  -
  -		public NamespaceMap getNamespaceMap()
  -		{
  -			return nsMap;
  -		}
  -
  -		public Key[] getKeySet()
  -		{
  -			return keys;
  -		}
  -
  -		public NodeSet execute() throws QueryException
  -		{
  -			try
  -			{
  -				Key[] keySet = keys;
  -
  -				// TODO: Add logic to do an indexed check on provided
  -				//       keySets that are larger than a certain minimum
  -
  -				if (keys == null && idxMgr != null)
  -				{
  -					// Issue the query using Indexes
  -					try
  -					{
  -						Object obj = evaluate(null, 0);
  -						if (obj instanceof NamedKeys)
  -						{
  -							keySet = ((NamedKeys) obj).keys;
  -						}
  -					}
  -					catch (Exception e)
  -					{
  -						if (log.isWarnEnabled())
  -						{
  -							log.warn("ignored exception", e);
  -						}
  -					}
  -				}
  -
  -				if (keySet == null)
  -				{
  -					// Fall back to a Collection scan
  -					SortedSet set = new TreeSet();
  -					RecordSet rs = context.getFiler().getRecordSet();
  -					while (rs.hasMoreRecords())
  -					{
  -						set.add(rs.getNextKey());
  -					}
  -					keySet = (Key[]) set.toArray(EMPTY_KEYS);
  -				}
  -
  -				return new ResultSet(context, pr, keySet, query);
  -			}
  -			catch (Exception e)
  -			{
  -				if (e instanceof QueryException)
  -				{
  -					throw (QueryException) e.fillInStackTrace();
  -				}
  -				throw new ProcessingException("Error executing XPath query: " + e.getMessage());
  -			}
  -		}
  -
  -		private Key[] andKeys(List list)
  -		{
  -			if (!list.isEmpty())
  -			{
  -				if (list.size() > 1)
  -				{
  -					Key[][] keys = (Key[][]) list.toArray(EMPTY_KEYSET);
  -					return QueryEngine.andKeySets(keys);
  -				}
  -				else
  -					return (Key[]) list.get(0);
  -			}
  -			else
  -				return null;
  -		}
  +     * XPathQuery
  +     */
  +    private class XPathQuery implements Query {
  +        public Collection context;
  +        public IndexManager idxMgr;
  +        public NamespaceMap nsMap;
  +        public PrefixResolver pr;
  +        public SymbolTable symbols;
  +        public String query;
  +        public Compiler cmp;
  +        public XPath xp;
  +        public Key[] keys;
  +
  +		public XPathQuery(Collection context, String query, NamespaceMap nsMap, Key[] keys)
  +                throws QueryException {
  +            this.context = context;
  +            this.query = query;
  +            this.nsMap = nsMap;
  +            this.keys = keys;
   
  -		// Evaluation Methods
  +            Expression ex = null;
  +			try {
  +                if (nsMap != null) {
  +                    Node n = nsMap.getContextNode();
  +                    pr = new PrefixResolverDefault(n);
  +                }
  +
  +                XPathParser parser = new XPathParser(errorListener, null);
  +                cmp = new Compiler(errorListener, null);
  +                parser.initXPath(cmp, query, pr);
  +                ex = cmp.compile(0);
   
  -		/**
  -		 * evaluate does a partial evaluation of the XPath in
  -		 * order to determine the optimal indexes to prepare for
  -		 * the query and retrieve the Document subset that will be
  -		 * used for the actual XPath query.
  -		 * <br><br>
  -		 * This will return an instance of one of the following classes:
  -		 * <pre>
  -		 *    String    If the sub-expression resolves to a Node Name
  -		 *    XNumber   If the sub-expression resolves to a Number
  -		 *    XString   If the sub-expression resolves to a String
  -		 *    XBoolean  If the sub-expression resolves to a Boolean
  -		 *    NamedKeys If the sub-expression resolves to a Key set
  -		 *    null      If the sub-expression resolves to anything else
  -		 * </pre>
  -		 *
  -		 * @param owner The parent node name for this context
  -		 * @param pos The position to start at (recursively called)
  -		 * @return Some Object result
  -		 */
  -		private Object evaluate(String owner, int pos) throws Exception
  -		{
  -			int op = cmp.getOp(pos);
  -			if (op == -1)
  -			{
  -				return null;
  -			}
  -
  -			switch (op)
  -			{
  -
  -				case OpCodes.OP_LOCATIONPATH :
  -					return evalLocationPath(owner, pos);
  -
  -				case OpCodes.OP_ARGUMENT :
  -				case OpCodes.OP_XPATH :
  -				case OpCodes.OP_PREDICATE :
  -					return evaluate(owner, Compiler.getFirstChildPos(pos));
  -
  -				case OpCodes.OP_OR :
  -				case OpCodes.OP_AND :
  -					return evalSetComparison(op, owner, pos);
  -
  -				case OpCodes.OP_NOTEQUALS :
  -				case OpCodes.OP_EQUALS :
  -				case OpCodes.OP_LTE :
  -				case OpCodes.OP_LT :
  -				case OpCodes.OP_GTE :
  -				case OpCodes.OP_GT :
  -					return evalValComparison(op, owner, pos);
  -
  -				case OpCodes.OP_PLUS :
  -				case OpCodes.OP_MINUS :
  -				case OpCodes.OP_MULT :
  -				case OpCodes.OP_DIV :
  -				case OpCodes.OP_MOD :
  -				case OpCodes.OP_QUO :
  -					return evalMathOperation(op, owner, pos);
  -
  -				case OpCodes.OP_NEG :
  -				case OpCodes.OP_STRING :
  -				case OpCodes.OP_BOOL :
  -				case OpCodes.OP_NUMBER :
  -					return evalUnaryOperation(op, owner, pos);
  -
  -				case OpCodes.OP_UNION :
  -					return evalUnion(owner, pos);
  -
  -				case OpCodes.OP_VARIABLE :
  -					break;
  -
  -				case OpCodes.OP_GROUP :
  -					return evaluate(owner, Compiler.getFirstChildPos(pos));
  -
  -				case OpCodes.OP_EXTFUNCTION :
  -					break;
  -
  -				case OpCodes.OP_FUNCTION :
  -					return evalFunction(owner, pos);
  -
  -				case OpCodes.FROM_ANCESTORS :
  -				case OpCodes.FROM_ANCESTORS_OR_SELF :
  -				case OpCodes.FROM_ATTRIBUTES :
  -				case OpCodes.FROM_CHILDREN :
  -				case OpCodes.FROM_DESCENDANTS :
  -				case OpCodes.FROM_DESCENDANTS_OR_SELF :
  -				case OpCodes.FROM_FOLLOWING :
  -				case OpCodes.FROM_FOLLOWING_SIBLINGS :
  -				case OpCodes.FROM_PARENT :
  -				case OpCodes.FROM_PRECEDING :
  -				case OpCodes.FROM_PRECEDING_SIBLINGS :
  -				case OpCodes.FROM_NAMESPACE :
  -				case OpCodes.FROM_SELF :
  -				case OpCodes.FROM_ROOT :
  -					return evalAxis(op, owner, pos);
  -
  -				case OpCodes.NODENAME :
  -				case OpCodes.OP_LITERAL :
  -				case OpCodes.OP_NUMBERLIT :
  -					return evalLiteral(owner, pos);
  -
  -				case OpCodes.NODETYPE_TEXT :
  -				case OpCodes.NODETYPE_NODE :
  -					return owner;
  -
  -				case OpCodes.NODETYPE_ANYELEMENT :
  -				case OpCodes.ELEMWILDCARD :
  -					return WILDCARD;
  -
  -				case OpCodes.NODETYPE_ROOT :
  -				case OpCodes.NODETYPE_COMMENT :
  -				case OpCodes.NODETYPE_PI :
  -				case OpCodes.NODETYPE_FUNCTEST :
  -					break;
  -
  -				default :
  -					if (log.isWarnEnabled())
  -					{
  -						log.warn("Unknown: " + op);
  -					}
  -			}
  -			return null;
  -		}
  -
  -		private Object evalLocationPath(String owner, int pos) throws Exception
  -		{
  -			int lp = Compiler.getFirstChildPos(pos);
  -			List ks = new ArrayList();
  -			String name = null;
  -			boolean attr = false;
  -			while (cmp.getOp(lp) != -1)
  -			{
  -				Object obj = evaluate(owner, lp);
  -				if (obj instanceof NamedKeys)
  -				{
  -					NamedKeys nk = (NamedKeys) obj;
  -					if (nk.name != null)
  -					{
  -						attr = nk.attribute;
  -						if (attr)
  -						{
  -							if (name == null)
  -							{
  -								name = owner;
  -							}
  -							if (name != null)
  -							{
  -								StringBuffer sb = new StringBuffer(32);
  -								sb.append(name);
  -								sb.append('@');
  -								sb.append(nk.name);
  -								name = sb.toString();
  -							}
  -						}
  -						else
  -						{
  -							name = nk.name;
  -						}
  -					}
  -					if (nk.keys != null)
  -					{
  -						ks.add(nk.keys);
  -					}
  -					else if (name != null)
  -					{
  -						// Try to use a NameIndex to resolve the path component
  -						// can match a wildcard node name here if pattern is "*" then every document matches
  -						if (attr == false && "*".equals(name))
  -						{
  -							SortedSet set = new TreeSet();
  -							RecordSet rs = context.getFiler().getRecordSet();
  -							while (rs.hasMoreRecords())
  -							{
  -								set.add(rs.getNextKey());
  -							}
  -							ks.add(set.toArray(EMPTY_KEYS));
  -						}
  -						else
  -						{
  -							// Try to use a NameIndex to resolve the path component
  -							IndexPattern pattern = new IndexPattern(symbols, name, nsMap);
  -							Indexer idx = context.getIndexManager().getBestIndexer(Indexer.STYLE_NODENAME, pattern);
  -							if (idx != null)
  -							{
  -								IndexMatch[] matches = idx.queryMatches(new IndexQueryANY(pattern));
  -								Key[] keys = QueryEngine.getUniqueKeys(matches);
  -								ks.add(keys);
  -							}
  -						}
  -					}
  -				}
  -				lp = cmp.getNextOpPos(lp);
  -			}
  -			return new NamedKeys(name, attr, andKeys(ks));
  -		}
  -
  -		private Object evalUnion(String owner, int pos) throws Exception
  -		{
  -			int l = Compiler.getFirstChildPos(pos);
  -			int r = cmp.getNextOpPos(l);
  -			Object left = evaluate(owner, l);
  -
  -			if (left instanceof NamedKeys && ((NamedKeys) left).keys != null)
  -			{
  -				Object right = evaluate(owner, r);
  -
  -				if (right instanceof NamedKeys && ((NamedKeys) right).keys != null)
  -				{
  -					Key[][] keys = new Key[][] {((NamedKeys) left).keys, ((NamedKeys) right).keys };
  -					return new NamedKeys(null, false, QueryEngine.orKeySets(keys));
  -				}
  -			}
  -			// no index query of left part of union
  -			// or no index query of right part of union => must do
  -			/// collection scan
  -			return null;
  -		}
  -
  -		private Object evalSetComparison(int op, String owner, int pos) throws Exception
  -		{
  -			int l = Compiler.getFirstChildPos(pos);
  -			int r = cmp.getNextOpPos(l);
  -			Object left = evaluate(owner, l);
  -
  -			if (left instanceof NamedKeys && ((NamedKeys) left).keys != null)
  -			{
  -				// have left keys
  -				if (((NamedKeys) left).keys.length == 0 && op == OpCodes.OP_AND)
  -				{
  -					// left keyset empty implies result of AND would be empty
  -					return new NamedKeys(null, false, ((NamedKeys) left).keys);
  -				}
  -
  -				Object right = evaluate(owner, r);
  -				if (right instanceof NamedKeys && ((NamedKeys) right).keys != null)
  -				{
  -					// have keys for both left and right
  -
  -					if (op == OpCodes.OP_AND)
  -					{
  -						if (((NamedKeys) right).keys.length == 0)
  -						{
  -							// right keyset empty implies result of AND would be empty
  -							return new NamedKeys(null, false, ((NamedKeys) right).keys);
  -						}
  -
  -						Key[][] keys = new Key[][] {((NamedKeys) left).keys, ((NamedKeys) right).keys };
  -						return new NamedKeys(null, false, QueryEngine.andKeySets(keys));
  -					}
  -					else
  -					{
  -
  -						// OR operation
  -						if (((NamedKeys) left).keys.length == 0)
  -						{
  -							// OR operation and left empty implies result is right set
  -							return new NamedKeys(null, false, ((NamedKeys) right).keys);
  -						}
  -
  -						if (((NamedKeys) right).keys.length == 0)
  -						{
  -							// OR operation and right empty implies result is left set
  -							return new NamedKeys(null, false, ((NamedKeys) left).keys);
  -						}
  -
  -						Key[][] keys = new Key[][] {((NamedKeys) left).keys, ((NamedKeys) right).keys };
  -						return new NamedKeys(null, false, QueryEngine.orKeySets(keys));
  -					}
  -				}
  -				else
  -				{
  -					// have left keys but not right can infer that AND operation
  -					// result cannot contain more than left set so return that
  -					if (op == OpCodes.OP_AND)
  -					{
  -						return new NamedKeys(null, false, ((NamedKeys) left).keys);
  -					}
  -				}
  -			}
  -			else
  -			{
  -				// do not have left keys
  -				Object right = evaluate(owner, r);
  -				if (right instanceof NamedKeys && ((NamedKeys) right).keys != null)
  -				{
  -					// have right keys but not left can infer that AND operation
  -					// result cannot contain more than right set so return that
  -					if (op == OpCodes.OP_AND)
  -					{
  -						return new NamedKeys(null, false, ((NamedKeys) right).keys);
  -					}
  -				}
  -			}
  -
  -			// punt
  -			return null;
  -		}
  -
  -		private Object evalValComparison(int op, String owner, int pos) throws Exception
  -		{
  -
  -			int l = Compiler.getFirstChildPos(pos);
  -			int r = cmp.getNextOpPos(l);
  -
  -			Object left = evaluate(owner, l);
  -			if (!(left instanceof XObject || left instanceof NamedKeys))
  -			{
  -				// can't evaluate
  -				return null;
  -			}
  -
  -			Object right = evaluate(owner, r);
  -			if ((left instanceof NamedKeys && right instanceof XObject)
  -				|| (left instanceof XObject && right instanceof NamedKeys))
  -			{
  -				// try to evaluate through indexed search
  -				return queryComparison(op, owner, left, right);
  -			}
  -
  -			// could handle comparison of nodeset to boolean here
  -			// boolean converts to 1.0 (true) or 0.0 (false)
  -			// nodeset converts to 1.0 (non-empty) or 0.0 (empty)
  -			// but since this is a rare and odd comparison we don't bother now...
  -			if (left instanceof XObject && right instanceof XObject)
  -			{
  -				switch (op)
  -				{
  -					case OpCodes.OP_NOTEQUALS :
  -						return new XBoolean(((XObject) left).notEquals((XObject) right));
  -					case OpCodes.OP_EQUALS :
  -						return new XBoolean(((XObject) left).equals((XObject) right));
  -					case OpCodes.OP_LTE :
  -						return new XBoolean(((XObject) left).lessThanOrEqual((XObject) right));
  -					case OpCodes.OP_LT :
  -						return new XBoolean(((XObject) left).lessThan((XObject) right));
  -					case OpCodes.OP_GTE :
  -						return new XBoolean(((XObject) left).greaterThanOrEqual((XObject) right));
  -					case OpCodes.OP_GT :
  -						return new XBoolean(((XObject) left).greaterThan((XObject) right));
  -					default :
  -						return null; // Won't happen
  -				}
  -			}
  -
  -			// can't evaluate here...
  -			return null;
  -		}
  -
  -		private strictfp Object evalMathOperation(int op, String owner, int pos) throws Exception
  -		{
  -			int lc = Compiler.getFirstChildPos(pos);
  -			int rc = cmp.getNextOpPos(lc);
  -			Object left = evaluate(owner, lc);
  -
  -			if (left instanceof XObject)
  -			{
  -				Object right = evaluate(owner, rc);
  -				if (right instanceof XObject)
  -				{
  -					switch (op)
  -					{
  -						case OpCodes.OP_PLUS :
  -							return new XNumber(((XObject) left).num() + ((XObject) right).num());
  -						case OpCodes.OP_MINUS :
  -							return new XNumber(((XObject) left).num() - ((XObject) right).num());
  -						case OpCodes.OP_MULT :
  -							return new XNumber(((XObject) left).num() * ((XObject) right).num());
  -						case OpCodes.OP_DIV :
  -							return new XNumber(((XObject) left).num() / ((XObject) right).num());
  -						case OpCodes.OP_MOD :
  -							return new XNumber(((XObject) left).num() % ((XObject) right).num());
  -						case OpCodes.OP_QUO :
  -							return new XNumber(((XObject) left).num() / ((XObject) right).num());
  -						default :
  -							return null; // Won't happen
  -					}
  -				}
  -			}
  -
  -			// can't evaluate
  -			return null;
  -		}
  -
  -		private Object evalUnaryOperation(int op, String owner, int pos) throws Exception
  -		{
  -			Object val = evaluate(owner, Compiler.getFirstChildPos(pos));
  -			if (val instanceof XObject)
  -			{
  -				switch (op)
  -				{
  -					case OpCodes.OP_NEG :
  -						return new XNumber(- ((XObject) val).num());
  -					case OpCodes.OP_STRING :
  -						return new XString(((XObject) val).str());
  -					case OpCodes.OP_BOOL :
  -						return new XBoolean(((XObject) val).bool());
  -					case OpCodes.OP_NUMBER :
  -						return new XNumber(((XObject) val).num());
  -					default :
  -						return null; // Won't happen
  -				}
  -			}
  -			if (val instanceof NamedKeys)
  -			{
  -				NamedKeys nk = (NamedKeys) val;
  -				// we may be able to convert the nodeset to the proper type
  -				// and return an answer numeric operations imply conversion to
  -				// string and then to number
  -				// we can't convert to string
  -				// we can handle conversion to boolean (empty or not empty)
  -				if (nk.keys != null && op == OpCodes.OP_BOOL)
  -				{
  -					return nk.keys.length == 0 ? XBoolean.S_FALSE : XBoolean.S_TRUE;
  -				}
  -			}
  -			return null;
  -		}
  -
  -		private Object evalFunction(String owner, int pos) throws Exception
  -		{
  -			int idx = Compiler.getFirstChildPos(pos);
  -			int id = cmp.getOp(idx);
  -			// note: in the XPath op table, the
  -			// op code is stored at the current position index passed to us
  -			// the size of the current op is stored in the next location
  -			// thus, the index of the location just beyond the function
  -			// arguments for the current op (which is also the index of the next op)
  -			// is equal to the current postion + the size of the current operation - 1
  -			// (the getOp(index) method merely returns the int value stored in the op table
  -			// at the specified index. That value is an op code, a size, or the index
  -			// of an token or ... (see org.apache.xpath.compiler.OpCodes for the
  -			// various items that can be part of an operation)
  -			int endFunc = pos + cmp.getOp(pos + 1) - 1;
  -
  -			List args = new ArrayList();
  -			int lp = idx + 1;
  -			while (lp < endFunc)
  -			{
  -				args.add(evaluate(owner, lp));
  -				lp = cmp.getNextOpPos(lp);
  -			}
  -
  -			switch (id)
  -			{
  -				case FunctionTable.FUNC_BOOLEAN :
  -					return funcBoolean(args);
  -				case FunctionTable.FUNC_CEILING :
  -					return funcCeiling(args);
  -				case FunctionTable.FUNC_CONCAT :
  -					return funcConcat(args);
  -				case FunctionTable.FUNC_CONTAINS :
  -					return funcContains(args);
  -				case FunctionTable.FUNC_FALSE :
  -					return XBoolean.S_FALSE;
  -				case FunctionTable.FUNC_FLOOR :
  -					return funcFloor(args);
  -				case FunctionTable.FUNC_NORMALIZE_SPACE :
  -					return funcNormalizeSpace(args);
  -				case FunctionTable.FUNC_NOT :
  -					return funcNot(args);
  -				case FunctionTable.FUNC_NUMBER :
  -					return funcNumber(args);
  -				case FunctionTable.FUNC_ROUND :
  -					return funcRound(args);
  -				case FunctionTable.FUNC_STARTS_WITH :
  -					return funcStartsWith(owner, args);
  -				case FunctionTable.FUNC_STRING :
  -					return funcString(args);
  -				case FunctionTable.FUNC_STRING_LENGTH :
  -					return funcStringLength(args);
  -				case FunctionTable.FUNC_SUBSTRING :
  -					return funcSubstring(args);
  -				case FunctionTable.FUNC_SUBSTRING_AFTER :
  -					return funcSubstringAfter(args);
  -				case FunctionTable.FUNC_SUBSTRING_BEFORE :
  -					return funcSubstringBefore(args);
  -				case FunctionTable.FUNC_TRANSLATE :
  -					return funcTranslate(args);
  -				case FunctionTable.FUNC_TRUE :
  -					return XBoolean.S_TRUE;
  -				default :
  -					return null;
  -			}
  -		}
  -
  -		private Object evalAxis(int op, String owner, int pos) throws Exception
  -		{
  -			String nsURI = cmp.getStepNS(pos);
  -			owner = (String) evaluate(owner, Compiler.getFirstChildPosOfStep(pos));
  -			//owner = cmp.getStepLocalName(pos);
  -
  -			if (nsURI != null && nsMap != null)
  -			{
  -				// We have to determine the prefix that was used
  -				// There has to be an easier way to do this with Xalan
  -				String pfx = null;
  -				Iterator i = nsMap.keySet().iterator();
  -				while (i.hasNext())
  -				{
  -					String p = (String) i.next();
  -					if (nsMap.getNamespaceURI(p).equals(nsURI))
  -					{
  -						pfx = p;
  -						break;
  -					}
  -				}
  -				if (pfx != null)
  -				{
  -					StringBuffer sb = new StringBuffer(32);
  -					sb.append(pfx);
  -					sb.append(':');
  -					sb.append(owner);
  -					owner = sb.toString();
  -				}
  -			}
  -
  -			int rp = cmp.getFirstPredicateOpPos(pos);
  -
  -			List ks = new ArrayList();
  -			while (rp < pos + cmp.getOp(pos + 1))
  -			{
  -				Object obj = evaluate(owner, rp);
  -				if (obj instanceof NamedKeys)
  -				{
  -					NamedKeys nk = (NamedKeys) obj;
  -					if (nk.keys != null)
  -					{
  -						ks.add(nk.keys);
  -					}
  -				}
  -				rp = cmp.getNextOpPos(rp);
  -			}
  -			return new NamedKeys(owner, (op == OpCodes.FROM_ATTRIBUTES), andKeys(ks));
  -		}
  -
  -		private Object evalLiteral(String owner, int pos)
  -		{
  -			int idx = cmp.getOp(Compiler.getFirstChildPos(pos));
  -			switch (idx)
  -			{
  -				case OpCodes.EMPTY :
  -					return owner;
  -				case OpCodes.ELEMWILDCARD :
  -					return WILDCARD;
  -				default :
  -					return cmp.getToken(idx);
  -			}
  -		}
  -
  -		// XPath Functions
  -
  -		private Object funcBoolean(List args) throws Exception
  -		{
  -			if (args.size() == 1)
  -			{
  -				Object o = args.get(0);
  -				if (o instanceof XObject)
  -				{
  -					if (((XObject) o).bool())
  -					{
  -						return XBoolean.S_TRUE;
  -					}
  -					else
  -					{
  -						return XBoolean.S_FALSE;
  -					}
  -				}
  -				else
  -				{
  -					if (o instanceof NamedKeys)
  -					{
  -						NamedKeys nk = (NamedKeys) o;
  -						if (nk.keys == null)
  -						{
  -							return null;
  -						}
  -						if (nk.keys.length == 0)
  -						{
  -							// nodeset empty converts to boolean false
  -							return XBoolean.S_FALSE;
  -						}
  -						return XBoolean.S_TRUE;
  -					}
  -				}
  -			}
  -			return null;
  -		}
  -
  -		private Object funcCeiling(List args) throws Exception
  -		{
  -			if (args.size() == 1)
  -			{
  -				Object o = args.get(0);
  -				if (o instanceof XObject)
  -				{
  -					return new XNumber(Math.ceil(((XObject) o).num()));
  -				}
  -			}
  -			return null;
  -		}
  -
  -		private Object funcConcat(List args)
  -		{
  -			StringBuffer sb = new StringBuffer();
  -			for (int i = 0; i < args.size(); i++)
  -			{
  -				Object o = args.get(i);
  -				if (o instanceof XObject)
  -				{
  -					sb.append(((XObject) o).str());
  -				}
  -				else
  -				{
  -					return null;
  -				}
  -			}
  -			return new XString(sb.toString());
  -		}
  -
  -		private Object funcContains(List args)
  -		{
  -			if (args.size() == 2)
  -			{
  -				Object o = args.get(0);
  -				Object s = args.get(1);
  -				if (o instanceof XObject && s instanceof XObject)
  -				{
  -					if (((XObject) o).str().indexOf(((XObject) s).str()) != -1)
  -					{
  -						return XBoolean.S_TRUE;
  -					}
  -					else
  -					{
  -						return XBoolean.S_FALSE;
  -					}
  -				}
  -			}
  -			return null;
  -		}
  -
  -		private Object funcFloor(List args) throws Exception
  -		{
  -			if (args.size() == 1)
  -			{
  -				Object o = args.get(0);
  -				if (o instanceof XObject)
  -				{
  -					return new XNumber(Math.floor(((XObject) o).num()));
  -				}
  -			}
  -			return null;
  -		}
  -
  -		private Object funcNormalizeSpace(List args)
  -		{
  -			if (args.size() == 1)
  -			{
  -				Object o = args.get(0);
  -				if (o instanceof XObject)
  -				{
  -					return new XString(QueryEngine.normalizeString(((XObject) o).str()));
  -				}
  -			}
  -			return null;
  -		}
  -
  -		private Object funcNot(List args) throws Exception
  -		{
  -			if (args.size() == 1)
  -			{
  -				Object o = args.get(0);
  -				if (o instanceof XObject)
  -				{
  -					if (((XObject) o).bool())
  -					{
  -						return XBoolean.S_FALSE;
  -					}
  -					else
  -					{
  -						return XBoolean.S_TRUE;
  -					}
  -				}
  -				else
  -				{
  -					if (o instanceof NamedKeys)
  -					{
  -						NamedKeys nk = (NamedKeys) o;
  -						if (nk.keys == null)
  -						{
  -							return null;
  -						}
  -						if (nk.keys.length == 0)
  -						{
  -							// nodeset empty converts to boolean false => not false => true
  -							return XBoolean.S_TRUE;
  -						}
  -						return XBoolean.S_FALSE;
  -					}
  -					return null;
  -				}
  -
  -			}
  -			return null;
  -		}
  -
  -		private Object funcNumber(List args) throws Exception
  -		{
  -			if (args.size() == 1)
  -			{
  -				Object o = args.get(0);
  -				if (o instanceof XObject)
  -				{
  -					return new XNumber(((XObject) o).num());
  -				}
  -			}
  -			return null;
  -		}
  -
  -		private Object funcRound(List args) throws Exception
  -		{
  -			if (args.size() == 1)
  -			{
  -				Object o = args.get(0);
  -				if (o instanceof XObject)
  -				{
  -					return new XNumber(Math.round(((XObject) o).num()));
  -				}
  -			}
  -			return null;
  -		}
  -
  -		private Object funcStartsWith(String owner, List args)
  -		{
  -			if (args.size() == 2)
  -			{
  -				Object o = args.get(0);
  -				Object s = args.get(1);
  -
  -				if (o instanceof XObject && s instanceof XObject)
  -				{
  -					if (((XObject) o).str().startsWith(((XObject) s).str()))
  -					{
  -						return XBoolean.S_TRUE;
  -					}
  -					else
  -					{
  -						return XBoolean.S_FALSE;
  -					}
  -				}
  -				else if (o instanceof NamedKeys && s instanceof XObject)
  -				{
  -					NamedKeys nk = (NamedKeys) o;
  -					String ps;
  -					if (nk.attribute && nk.name.indexOf('@') == -1)
  -					{
  -						ps = owner + "@" + nk.name;
  -					}
  -					else
  -					{
  -						ps = nk.name;
  -					}
  -
  -					IndexPattern pattern = new IndexPattern(symbols, ps, nsMap);
  -
  -					XObject obj = (XObject) s;
  -					Value val1 = new Value(obj.str());
  -
  -					IndexQuery iq = new IndexQuerySW(pattern, val1);
  -					return queryIndexes(nk, iq, ps, obj.getType());
  -				}
  -			}
  -			return null;
  -		}
  -
  -		private Object funcString(List args)
  -		{
  -			if (args.size() == 1)
  -			{
  -				Object o = args.get(0);
  -				if (o instanceof XObject)
  -				{
  -					return new XString(((XObject) o).str());
  -				}
  -			}
  -			return null;
  -		}
  -
  -		private Object funcStringLength(List args)
  -		{
  -			if (args.size() == 1)
  -			{
  -				Object o = args.get(0);
  -				if (o instanceof XObject)
  -				{
  -					return new XNumber(((XObject) o).str().length());
  -				}
  -			}
  -			return null;
  -		}
  -
  -		private Object funcSubstring(List args) throws Exception
  -		{
  -			if (args.size() == 2 || args.size() == 3)
  -			{
  -				Object o = args.get(0);
  -				Object pos = args.get(1);
  -				Object len = args.size() == 3 ? args.get(2) : null;
  -				if (o instanceof XObject && pos instanceof XObject && (len == null || len instanceof XObject))
  -				{
  -					int ipos = (int) ((XObject) pos).num() - 1;
  -					if (len != null)
  -					{
  -						int ilen = (int) ((XObject) len).num();
  -						return new XString(((XObject) o).str().substring(ipos, ipos + ilen));
  -					}
  -					else
  -						return new XString(((XObject) o).str().substring(ipos));
  -				}
  -			}
  -			return null;
  -		}
  -
  -		private Object funcSubstringAfter(List args)
  -		{
  -			if (args.size() == 2)
  -			{
  -				Object o = args.get(0);
  -				Object s = args.get(1);
  -				if (o instanceof XObject && s instanceof XObject)
  -				{
  -					String val = ((XObject) o).str();
  -					String sub = ((XObject) s).str();
  -					int i = val.indexOf(sub);
  -					if (i == -1)
  -					{
  -						return new XString("");
  -					}
  -					else
  -					{
  -						return new XString(val.substring(i + sub.length()));
  -					}
  -				}
  -			}
  -			return null;
  -		}
  -
  -		private Object funcSubstringBefore(List args)
  -		{
  -			if (args.size() == 2)
  -			{
  -				Object o = args.get(0);
  -				Object s = args.get(1);
  -				if (o instanceof XObject && s instanceof XObject)
  -				{
  -					String val = ((XObject) o).str();
  -					String sub = ((XObject) s).str();
  -					int i = val.indexOf(sub);
  -					if (i == -1)
  -					{
  -						return new XString("");
  -					}
  -					else
  -					{
  -						return new XString(val.substring(0, i));
  -					}
  -				}
  -			}
  -			return null;
  -		}
  -
  -		private Object funcTranslate(List args)
  -		{
  -			if (args.size() == 3)
  -			{
  -				Object o = args.get(0);
  -				Object c1 = args.get(1);
  -				Object c2 = args.get(2);
  -				if (o instanceof XObject && c1 instanceof XObject && c2 instanceof XObject)
  -				{
  -					char ch1 = ((XObject) c1).str().charAt(0);
  -					char ch2 = ((XObject) c2).str().charAt(0);
  -					return new XString(((XObject) o).str().replace(ch1, ch2));
  -				}
  -			}
  -			return null;
  -		}
  +                symbols = context.getSymbols();
  +                idxMgr = context.getIndexManager();
  +            } catch (Exception e) {
  +                throw new CompilationException("Error Compiling XPath Expression: " + e.getMessage(), e);
  +            }
   
  -		// The Actual Querying Methods
  +            if (ex == null) {
  +                throw new CompilationException("Error Compiling XPath Expression: XPath Compiler.compile returned null");
  +            }
  +        }
  +
  +        public String getQueryStyle() {
  +            return STYLE_XPATH;
  +        }
  +
  +        public String getQueryString() {
  +            return query;
  +        }
  +
  +        public Collection getQueryContext() {
  +            return context;
  +        }
  +
  +        public NamespaceMap getNamespaceMap() {
  +            return nsMap;
  +        }
  +
  +        public Key[] getKeySet() {
  +            return keys;
  +        }
   
  -		/**
  -		 * queryIndexes actually performs index-based querying on behalf of
  -		 * the evaluation methods.
  -		 *
  -		 * @param nk The NamedKeys instance to use for matches
  -		 * @param iq The actual IndexQuery to use for resolution
  -		 * @param ps The pattern String to possibly use for index gen
  -		 * @param objType The object type to possibly use for index gen
  -		 * @return The resulting Keys (if any)
  -		 */
  -		private Object queryIndexes(NamedKeys nk, IndexQuery iq, String ps, int objType)
  -		{
  -			try
  -			{
  -				// TODO: Add logic to use an EmptyKeySet if a name doesn't already
  -				//       exist in the SymbolTable.  This will eliminate the need
  -				//       to do a collection scan in those cases where somebody
  -				//       typed an element or attribute name incorrectly.
  -
  -				IndexPattern pattern = iq.getPattern();
  -
  -				Indexer idx = context.getIndexManager().getBestIndexer(Indexer.STYLE_NODEVALUE, pattern);
  -				if (idx != null)
  -				{
  -					return new NamedKeys(nk.name, nk.attribute, QueryEngine.getUniqueKeys(idx.queryMatches(iq)));
  -				}
  -				else if (autoIndex)
  -				{
  -					// TODO: This has to *not* be hardcoded
  -					Element e = new DocumentImpl().createElement("index");
  -					e.setAttribute("class", "org.apache.xindice.core.indexer.ValueIndexer");
  -					e.setAttribute("name", "xp_" + ps);
  -					e.setAttribute("pattern", ps);
  -
  -					// Set the type for the index
  -					String type = null;
  -					switch (objType)
  -					{
  -						case XObject.CLASS_BOOLEAN :
  -							type = "boolean";
  -							break;
  -						case XObject.CLASS_NUMBER :
  -							type = "double";
  -							break;
  -						case XObject.CLASS_STRING :
  -							if (ps.indexOf('@') != -1)
  -							{
  -								type = "string";
  -							}
  -							else
  -							{
  -								type = "trimmed";
  -							}
  -							break;
  -						default :
  -							if (log.isWarnEnabled())
  -							{
  -								log.warn("invalid object type : " + objType);
  -							}
  -					}
  -					if (type != null)
  -					{
  -						e.setAttribute("type", type);
  -					}
  -
  -					idxMgr.create(new Configuration(e));
  -				}
  -			}
  -			catch (Exception e)
  -			{
  -				if (log.isWarnEnabled())
  -				{
  -					log.warn("ignored exception", e);
  -				}
  -			}
  -			return null;
  -		}
  +		public NodeSet execute() throws QueryException {
  +			try {
  +                Key[] keySet = keys;
  +
  +                // TODO: Add logic to do an indexed check on provided
  +                //       keySets that are larger than a certain minimum
  +
  +                if (keys == null && idxMgr != null) {
  +                    // Issue the query using Indexes
  +                    try {
  +                        Object obj = evaluate(null, 0);
  +                        if (obj instanceof NamedKeys) {
  +                            keySet = ((NamedKeys) obj).keys;
  +                        }
  +                    } catch (Exception e) {
  +                        if (log.isWarnEnabled()) {
  +                            log.warn("ignored exception", e);
  +                        }
  +                    }
  +                }
  +
  +                if (keySet == null) {
  +                    // Fall back to a Collection scan
  +                    SortedSet set = new TreeSet();
  +                    RecordSet rs = context.getFiler().getRecordSet();
  +                    while (rs.hasMoreRecords()) {
  +                        set.add(rs.getNextKey());
  +                    }
  +                    keySet = (Key[]) set.toArray(EMPTY_KEYS);
  +                }
  +
  +                return new ResultSet(context, pr, keySet, query);
  +            } catch (Exception e) {
  +                if (e instanceof QueryException) {
  +                    throw (QueryException) e.fillInStackTrace();
  +                }
  +                throw new ProcessingException("Error executing XPath query: " + e.getMessage(), e);
  +            }
  +        }
  +
  +        private Key[] andKeys(List list) {
  +            if (!list.isEmpty()) {
  +                if (list.size() > 1) {
  +                    Key[][] keys = (Key[][]) list.toArray(EMPTY_KEYSET);
  +                    return QueryEngine.andKeySets(keys);
  +                } else
  +                    return (Key[]) list.get(0);
  +            } else {
  +                return null;
  +            }
  +        }
  +
  +        // Evaluation Methods
   
   		/**
  -		 * queryComparison performs a comparison query use the operands that
  -		 * are passed to it, and returns the resulting Keys.
  -		 *
  -		 * @param op The Operator
  -		 * @param owner The Owner Node
  -		 * @param left The left Operand
  -		 * @param right The right Operand
  -		 * @return The resulting Keys (if any)
  -		 */
  -		private Object queryComparison(int op, String owner, Object left, Object right)
  -		{
  -			op = OpMap[op - OpCodes.OP_NOTEQUALS];
  -
  -			if (left instanceof XObject)
  -			{
  -				// Check if we have to switch the operation
  -				if (op == IndexQuery.GT || op == IndexQuery.LT || op == IndexQuery.GEQ || op == IndexQuery.LEQ)
  -				{
  -					op = -op;
  -				}
  -				// Swap the operands
  -				Object tmp = left;
  -				left = right;
  -				right = tmp;
  -			}
  -
  -			if (!(left instanceof NamedKeys && right instanceof XObject))
  -			{
  -				// can't handle it
  -				return null;
  -			}
  -
  -			NamedKeys nk = (NamedKeys) left;
  -			XObject obj = (XObject) right;
  -
  -			String ps;
  -			if (nk.attribute && nk.name.indexOf('@') == -1)
  -			{
  -				ps = owner + "@" + nk.name;
  -			}
  -			else
  -			{
  -				ps = nk.name;
  -			}
  -
  -			IndexQuery iq;
  -			IndexPattern pattern = new IndexPattern(symbols, ps, nsMap);
  -			String value = obj.str();
  -
  -			switch (op)
  -			{
  -				case IndexQuery.NEQ :
  -					iq = new IndexQueryNEQ(pattern, value);
  -					break;
  -				case IndexQuery.EQ :
  -					iq = new IndexQueryEQ(pattern, value);
  -					break;
  -				case IndexQuery.LEQ :
  -					iq = new IndexQueryLEQ(pattern, value);
  -					break;
  -				case IndexQuery.LT :
  -					iq = new IndexQueryLT(pattern, value);
  -					break;
  -				case IndexQuery.GEQ :
  -					iq = new IndexQueryGEQ(pattern, value);
  -					break;
  -				case IndexQuery.GT :
  -					iq = new IndexQueryGT(pattern, value);
  -					break;
  -				default :
  -					iq = null; // Won't happen
  -			}
  -
  -			return queryIndexes(nk, iq, ps, obj.getType());
  -		}
  -	}
  +         * evaluate does a partial evaluation of the XPath in order to
  +         * determine the optimal indexes to prepare for the query and retrieve
  +         * the Document subset that will be used for the actual XPath query.
  +         *
  +         * <p>This will return an instance of one of the following classes:
  +         * <pre>
  +         *    String    If the sub-expression resolves to a Node Name
  +         *    XNumber   If the sub-expression resolves to a Number
  +         *    XString   If the sub-expression resolves to a String
  +         *    XBoolean  If the sub-expression resolves to a Boolean
  +         *    NamedKeys If the sub-expression resolves to a Key set
  +         *    null      If the sub-expression resolves to anything else
  +         * </pre>
  +         *
  +         * @param owner The parent node name for this context
  +         * @param pos   The position to start at (recursively called)
  +         * @return Some Object result
  +         */
  +        private Object evaluate(String owner, int pos) throws Exception {
  +            int op = cmp.getOp(pos);
  +            if (op == -1) {
  +                return null;
  +            }
  +
  +			switch (op) {
  +                case OpCodes.OP_LOCATIONPATH:
  +                    return evalLocationPath(owner, pos);
  +
  +                case OpCodes.OP_ARGUMENT:
  +                case OpCodes.OP_XPATH:
  +                case OpCodes.OP_PREDICATE:
  +                    return evaluate(owner, Compiler.getFirstChildPos(pos));
  +
  +                case OpCodes.OP_OR:
  +                case OpCodes.OP_AND:
  +                    return evalSetComparison(op, owner, pos);
  +
  +                case OpCodes.OP_NOTEQUALS:
  +                case OpCodes.OP_EQUALS:
  +                case OpCodes.OP_LTE:
  +                case OpCodes.OP_LT:
  +                case OpCodes.OP_GTE:
  +                case OpCodes.OP_GT:
  +                    return evalValComparison(op, owner, pos);
  +
  +                case OpCodes.OP_PLUS:
  +                case OpCodes.OP_MINUS:
  +                case OpCodes.OP_MULT:
  +                case OpCodes.OP_DIV:
  +                case OpCodes.OP_MOD:
  +                case OpCodes.OP_QUO:
  +                    return evalMathOperation(op, owner, pos);
  +
  +                case OpCodes.OP_NEG:
  +                case OpCodes.OP_STRING:
  +                case OpCodes.OP_BOOL:
  +                case OpCodes.OP_NUMBER:
  +                    return evalUnaryOperation(op, owner, pos);
  +
  +                case OpCodes.OP_UNION:
  +                    return evalUnion(owner, pos);
  +
  +                case OpCodes.OP_VARIABLE:
  +                    break;
  +
  +                case OpCodes.OP_GROUP:
  +                    return evaluate(owner, Compiler.getFirstChildPos(pos));
  +
  +                case OpCodes.OP_EXTFUNCTION:
  +                    break;
  +
  +                case OpCodes.OP_FUNCTION:
  +                    return evalFunction(owner, pos);
  +
  +                case OpCodes.FROM_ANCESTORS:
  +                case OpCodes.FROM_ANCESTORS_OR_SELF:
  +                case OpCodes.FROM_ATTRIBUTES:
  +                case OpCodes.FROM_CHILDREN:
  +                case OpCodes.FROM_DESCENDANTS:
  +                case OpCodes.FROM_DESCENDANTS_OR_SELF:
  +                case OpCodes.FROM_FOLLOWING:
  +                case OpCodes.FROM_FOLLOWING_SIBLINGS:
  +                case OpCodes.FROM_PARENT:
  +                case OpCodes.FROM_PRECEDING:
  +                case OpCodes.FROM_PRECEDING_SIBLINGS:
  +                case OpCodes.FROM_NAMESPACE:
  +                case OpCodes.FROM_SELF:
  +                case OpCodes.FROM_ROOT:
  +                    return evalAxis(op, owner, pos);
  +
  +                case OpCodes.NODENAME:
  +                case OpCodes.OP_LITERAL:
  +                case OpCodes.OP_NUMBERLIT:
  +                    return evalLiteral(owner, pos);
  +
  +                case OpCodes.NODETYPE_TEXT:
  +                case OpCodes.NODETYPE_NODE:
  +                    return owner;
  +
  +                case OpCodes.NODETYPE_ANYELEMENT:
  +                case OpCodes.ELEMWILDCARD:
  +                    return WILDCARD;
  +
  +                case OpCodes.NODETYPE_ROOT:
  +                case OpCodes.NODETYPE_COMMENT:
  +                case OpCodes.NODETYPE_PI:
  +                case OpCodes.NODETYPE_FUNCTEST:
  +                    break;
  +
  +                default :
  +                    if (log.isWarnEnabled()) {
  +                        log.warn("Unknown: " + op);
  +                    }
  +            }
  +            return null;
  +        }
  +
  +		private Object evalLocationPath(String owner, int pos) throws Exception {
  +            int lp = Compiler.getFirstChildPos(pos);
  +            List ks = new ArrayList();
  +            String name = null;
  +            boolean attr = false;
  +			while (cmp.getOp(lp) != -1) {
  +                Object obj = evaluate(owner, lp);
  +				if (obj instanceof NamedKeys) {
  +                    NamedKeys nk = (NamedKeys) obj;
  +                    if (nk.name != null) {
  +                        attr = nk.attribute;
  +                        if (attr) {
  +                            if (name == null) {
  +                                name = owner;
  +                            }
  +                            if (name != null) {
  +                                StringBuffer sb = new StringBuffer(32);
  +                                sb.append(name);
  +                                sb.append('@');
  +                                sb.append(nk.name);
  +                                name = sb.toString();
  +                            }
  +                        } else {
  +                            name = nk.name;
  +                        }
  +                    }
  +					if (nk.keys != null) {
  +                        ks.add(nk.keys);
  +                    }
  +                    else if (name != null) {
  +                        // Try to use a NameIndex to resolve the path component
  +                        // can match a wildcard node name here if pattern is "*" then every document matches
  +                        if (attr == false && "*".equals(name)) {
  +                            SortedSet set = new TreeSet();
  +                            RecordSet rs = context.getFiler().getRecordSet();
  +                            while (rs.hasMoreRecords()) {
  +                                set.add(rs.getNextKey());
  +                            }
  +                            ks.add(set.toArray(EMPTY_KEYS));
  +                        } else {
  +                            // Try to use a NameIndex to resolve the path component
  +                            IndexPattern pattern = new IndexPattern(symbols, name, nsMap);
  +                            Indexer idx = context.getIndexManager().getBestIndexer(Indexer.STYLE_NODENAME, pattern);
  +                            if (idx != null) {
  +                                IndexMatch[] matches = idx.queryMatches(new IndexQueryANY(pattern));
  +                                Key[] keys = QueryEngine.getUniqueKeys(matches);
  +                                ks.add(keys);
  +                            }
  +                        }
  +                    }
  +                }
  +                lp = cmp.getNextOpPos(lp);
  +            }
  +            return new NamedKeys(name, attr, andKeys(ks));
  +        }
  +
  +        private Object evalUnion(String owner, int pos) throws Exception {
  +            int l = Compiler.getFirstChildPos(pos);
  +            int r = cmp.getNextOpPos(l);
  +            Object left = evaluate(owner, l);
  +
  +            if (left instanceof NamedKeys && ((NamedKeys) left).keys != null) {
  +                Object right = evaluate(owner, r);
  +
  +                if (right instanceof NamedKeys && ((NamedKeys) right).keys != null) {
  +                    Key[][] keys = new Key[][]{((NamedKeys) left).keys, ((NamedKeys) right).keys};
  +                    return new NamedKeys(null, false, QueryEngine.orKeySets(keys));
  +                }
  +            }
  +
  +            // no index query of left part of union
  +            // or no index query of right part of union => must do
  +            /// collection scan
  +            return null;
  +        }
  +
  +		private Object evalSetComparison(int op, String owner, int pos) throws Exception {
  +            int l = Compiler.getFirstChildPos(pos);
  +            int r = cmp.getNextOpPos(l);
  +            Object left = evaluate(owner, l);
  +
  +			if (left instanceof NamedKeys && ((NamedKeys) left).keys != null) {
  +                // have left keys
  +                if (((NamedKeys) left).keys.length == 0 && op == OpCodes.OP_AND) {
  +                    // left keyset empty implies result of AND would be empty
  +                    return new NamedKeys(null, false, ((NamedKeys) left).keys);
  +                }
  +
  +                Object right = evaluate(owner, r);
  +				if (right instanceof NamedKeys && ((NamedKeys) right).keys != null) {
  +                    // have keys for both left and right
  +					if (op == OpCodes.OP_AND) {
  +                        if (((NamedKeys) right).keys.length == 0) {
  +                            // right keyset empty implies result of AND would be empty
  +                            return new NamedKeys(null, false, ((NamedKeys) right).keys);
  +                        }
   
  -	/**
  -	 * NamedKeys
  -	 */
  +                        Key[][] keys = new Key[][]{((NamedKeys) left).keys, ((NamedKeys) right).keys};
  +                        return new NamedKeys(null, false, QueryEngine.andKeySets(keys));
  +                    } else {
  +                        // OR operation
  +                        if (((NamedKeys) left).keys.length == 0) {
  +                            // OR operation and left empty implies result is right set
  +                            return new NamedKeys(null, false, ((NamedKeys) right).keys);
  +                        }
  +
  +                        if (((NamedKeys) right).keys.length == 0) {
  +                            // OR operation and right empty implies result is left set
  +                            return new NamedKeys(null, false, ((NamedKeys) left).keys);
  +                        }
  +
  +                        Key[][] keys = new Key[][]{((NamedKeys) left).keys, ((NamedKeys) right).keys};
  +                        return new NamedKeys(null, false, QueryEngine.orKeySets(keys));
  +                    }
  +                } else {
  +                    // have left keys but not right can infer that AND operation
  +                    // result cannot contain more than left set so return that
  +                    if (op == OpCodes.OP_AND) {
  +                        return new NamedKeys(null, false, ((NamedKeys) left).keys);
  +                    }
  +                }
  +            } else {
  +                // do not have left keys
  +                Object right = evaluate(owner, r);
  +                if (right instanceof NamedKeys && ((NamedKeys) right).keys != null) {
  +                    // have right keys but not left can infer that AND operation
  +                    // result cannot contain more than right set so return that
  +                    if (op == OpCodes.OP_AND) {
  +                        return new NamedKeys(null, false, ((NamedKeys) right).keys);
  +                    }
  +                }
  +            }
  +
  +            // punt
  +            return null;
  +        }
  +
  +        private Object evalValComparison(int op, String owner, int pos) throws Exception {
  +            int l = Compiler.getFirstChildPos(pos);
  +            int r = cmp.getNextOpPos(l);
  +
  +            Object left = evaluate(owner, l);
  +            if (!(left instanceof XObject || left instanceof NamedKeys)) {
  +                // can't evaluate
  +                return null;
  +            }
  +
  +            Object right = evaluate(owner, r);
  +            if ((left instanceof NamedKeys && right instanceof XObject)
  +                    || (left instanceof XObject && right instanceof NamedKeys)) {
  +                // try to evaluate through indexed search
  +                return queryComparison(op, owner, left, right);
  +            }
  +
  +            // could handle comparison of nodeset to boolean here
  +            // boolean converts to 1.0 (true) or 0.0 (false)
  +            // nodeset converts to 1.0 (non-empty) or 0.0 (empty)
  +            // but since this is a rare and odd comparison we don't bother now...
  +            if (left instanceof XObject && right instanceof XObject) {
  +                switch (op) {
  +                    case OpCodes.OP_NOTEQUALS:
  +                        return new XBoolean(((XObject) left).notEquals((XObject) right));
  +                    case OpCodes.OP_EQUALS:
  +                        return new XBoolean(((XObject) left).equals((XObject) right));
  +                    case OpCodes.OP_LTE:
  +                        return new XBoolean(((XObject) left).lessThanOrEqual((XObject) right));
  +                    case OpCodes.OP_LT:
  +                        return new XBoolean(((XObject) left).lessThan((XObject) right));
  +                    case OpCodes.OP_GTE:
  +                        return new XBoolean(((XObject) left).greaterThanOrEqual((XObject) right));
  +                    case OpCodes.OP_GT:
  +                        return new XBoolean(((XObject) left).greaterThan((XObject) right));
  +                    default :
  +                        return null; // Won't happen
  +                }
  +            }
  +
  +            // can't evaluate here...
  +            return null;
  +        }
  +
  +        private strictfp Object evalMathOperation(int op, String owner, int pos) throws Exception {
  +            int lc = Compiler.getFirstChildPos(pos);
  +            int rc = cmp.getNextOpPos(lc);
  +            Object left = evaluate(owner, lc);
  +
  +            if (left instanceof XObject) {
  +                Object right = evaluate(owner, rc);
  +                if (right instanceof XObject) {
  +                    switch (op) {
  +                        case OpCodes.OP_PLUS:
  +                            return new XNumber(((XObject) left).num() + ((XObject) right).num());
  +                        case OpCodes.OP_MINUS:
  +                            return new XNumber(((XObject) left).num() - ((XObject) right).num());
  +                        case OpCodes.OP_MULT:
  +                            return new XNumber(((XObject) left).num() * ((XObject) right).num());
  +                        case OpCodes.OP_DIV:
  +                            return new XNumber(((XObject) left).num() / ((XObject) right).num());
  +                        case OpCodes.OP_MOD:
  +                            return new XNumber(((XObject) left).num() % ((XObject) right).num());
  +                        case OpCodes.OP_QUO:
  +                            return new XNumber(((XObject) left).num() / ((XObject) right).num());
  +                        default :
  +                            return null; // Won't happen
  +                    }
  +                }
  +            }
  +
  +            // can't evaluate
  +            return null;
  +        }
  +
  +        private Object evalUnaryOperation(int op, String owner, int pos) throws Exception {
  +            Object val = evaluate(owner, Compiler.getFirstChildPos(pos));
  +            if (val instanceof XObject) {
  +                switch (op) {
  +                    case OpCodes.OP_NEG:
  +                        return new XNumber(-((XObject) val).num());
  +                    case OpCodes.OP_STRING:
  +                        return new XString(((XObject) val).str());
  +                    case OpCodes.OP_BOOL:
  +                        return new XBoolean(((XObject) val).bool());
  +                    case OpCodes.OP_NUMBER:
  +                        return new XNumber(((XObject) val).num());
  +                    default:
  +                        return null; // Won't happen
  +                }
  +            }
  +            if (val instanceof NamedKeys) {
  +                NamedKeys nk = (NamedKeys) val;
  +                // we may be able to convert the nodeset to the proper type
  +                // and return an answer numeric operations imply conversion to
  +                // string and then to number
  +                // we can't convert to string
  +                // we can handle conversion to boolean (empty or not empty)
  +                if (nk.keys != null && op == OpCodes.OP_BOOL) {
  +                    return nk.keys.length == 0 ? XBoolean.S_FALSE : XBoolean.S_TRUE;
  +                }
  +            }
  +            return null;
  +        }
  +
  +        private Object evalFunction(String owner, int pos) throws Exception {
  +            int idx = Compiler.getFirstChildPos(pos);
  +            int id = cmp.getOp(idx);
  +
  +            // NOTE: In the XPath op table, the
  +            // op code is stored at the current position index passed to us
  +            // the size of the current op is stored in the next location
  +            // thus, the index of the location just beyond the function
  +            // arguments for the current op (which is also the index of the next op)
  +            // is equal to the current postion + the size of the current operation - 1
  +            // (the getOp(index) method merely returns the int value stored in the op table
  +            // at the specified index. That value is an op code, a size, or the index
  +            // of an token or ... (see org.apache.xpath.compiler.OpCodes for the
  +            // various items that can be part of an operation)
  +            int endFunc = pos + cmp.getOp(pos + 1) - 1;
  +
  +            List args = new ArrayList();
  +            int lp = idx + 1;
  +            while (lp < endFunc) {
  +                args.add(evaluate(owner, lp));
  +                lp = cmp.getNextOpPos(lp);
  +            }
  +
  +            switch (id) {
  +                case FunctionTable.FUNC_BOOLEAN:
  +                    return funcBoolean(args);
  +                case FunctionTable.FUNC_CEILING:
  +                    return funcCeiling(args);
  +                case FunctionTable.FUNC_CONCAT:
  +                    return funcConcat(args);
  +                case FunctionTable.FUNC_CONTAINS:
  +                    return funcContains(args);
  +                case FunctionTable.FUNC_FALSE:
  +                    return XBoolean.S_FALSE;
  +                case FunctionTable.FUNC_FLOOR:
  +                    return funcFloor(args);
  +                case FunctionTable.FUNC_NORMALIZE_SPACE:
  +                    return funcNormalizeSpace(args);
  +                case FunctionTable.FUNC_NOT:
  +                    return funcNot(args);
  +                case FunctionTable.FUNC_NUMBER:
  +                    return funcNumber(args);
  +                case FunctionTable.FUNC_ROUND:
  +                    return funcRound(args);
  +                case FunctionTable.FUNC_STARTS_WITH:
  +                    return funcStartsWith(owner, args);
  +                case FunctionTable.FUNC_STRING:
  +                    return funcString(args);
  +                case FunctionTable.FUNC_STRING_LENGTH:
  +                    return funcStringLength(args);
  +                case FunctionTable.FUNC_SUBSTRING:
  +                    return funcSubstring(args);
  +                case FunctionTable.FUNC_SUBSTRING_AFTER:
  +                    return funcSubstringAfter(args);
  +                case FunctionTable.FUNC_SUBSTRING_BEFORE:
  +                    return funcSubstringBefore(args);
  +                case FunctionTable.FUNC_TRANSLATE:
  +                    return funcTranslate(args);
  +                case FunctionTable.FUNC_TRUE:
  +                    return XBoolean.S_TRUE;
  +                default:
  +                    return null;
  +            }
  +        }
  +
  +        private Object evalAxis(int op, String owner, int pos) throws Exception {
  +            String nsURI = cmp.getStepNS(pos);
  +            owner = (String) evaluate(owner, Compiler.getFirstChildPosOfStep(pos));
  +            // owner = cmp.getStepLocalName(pos);
  +
  +            if (nsURI != null && nsMap != null) {
  +                // We have to determine the prefix that was used
  +                // There has to be an easier way to do this with Xalan
  +                String pfx = null;
  +                Iterator i = nsMap.keySet().iterator();
  +                while (i.hasNext()) {
  +                    String p = (String) i.next();
  +                    if (nsMap.getNamespaceURI(p).equals(nsURI)) {
  +                        pfx = p;
  +                        break;
  +                    }
  +                }
  +                if (pfx != null) {
  +                    StringBuffer sb = new StringBuffer(32);
  +                    sb.append(pfx);
  +                    sb.append(':');
  +                    sb.append(owner);
  +                    owner = sb.toString();
  +                }
  +            }
  +
  +            int rp = cmp.getFirstPredicateOpPos(pos);
  +
  +            List ks = new ArrayList();
  +            while (rp < pos + cmp.getOp(pos + 1)) {
  +                Object obj = evaluate(owner, rp);
  +                if (obj instanceof NamedKeys) {
  +                    NamedKeys nk = (NamedKeys) obj;
  +                    if (nk.keys != null) {
  +                        ks.add(nk.keys);
  +                    }
  +                }
  +                rp = cmp.getNextOpPos(rp);
  +            }
  +            return new NamedKeys(owner, (op == OpCodes.FROM_ATTRIBUTES), andKeys(ks));
  +        }
  +
  +        private Object evalLiteral(String owner, int pos) {
  +            int idx = cmp.getOp(Compiler.getFirstChildPos(pos));
  +            switch (idx) {
  +                case OpCodes.EMPTY:
  +                    return owner;
  +                case OpCodes.ELEMWILDCARD:
  +                    return WILDCARD;
  +                default:
  +                    return cmp.getToken(idx);
  +            }
  +        }
  +
  +        // XPath Functions
  +
  +        private Object funcBoolean(List args) throws Exception {
  +            if (args.size() == 1) {
  +                Object o = args.get(0);
  +                if (o instanceof XObject) {
  +                    if (((XObject) o).bool()) {
  +                        return XBoolean.S_TRUE;
  +                    } else {
  +                        return XBoolean.S_FALSE;
  +                    }
  +                } else {
  +                    if (o instanceof NamedKeys) {
  +                        NamedKeys nk = (NamedKeys) o;
  +                        if (nk.keys == null) {
  +                            return null;
  +                        }
  +                        if (nk.keys.length == 0) {
  +                            // nodeset empty converts to boolean false
  +                            return XBoolean.S_FALSE;
  +                        }
  +                        return XBoolean.S_TRUE;
  +                    }
  +                }
  +            }
  +            return null;
  +        }
  +
  +        private Object funcCeiling(List args) throws Exception {
  +            if (args.size() == 1) {
  +                Object o = args.get(0);
  +                if (o instanceof XObject) {
  +                    return new XNumber(Math.ceil(((XObject) o).num()));
  +                }
  +            }
  +            return null;
  +        }
  +
  +        private Object funcConcat(List args) {
  +            StringBuffer sb = new StringBuffer();
  +            for (int i = 0; i < args.size(); i++) {
  +                Object o = args.get(i);
  +                if (o instanceof XObject) {
  +                    sb.append(((XObject) o).str());
  +                } else {
  +                    return null;
  +                }
  +            }
  +            return new XString(sb.toString());
  +        }
  +
  +        private Object funcContains(List args) {
  +            if (args.size() == 2) {
  +                Object o = args.get(0);
  +                Object s = args.get(1);
  +                if (o instanceof XObject && s instanceof XObject) {
  +                    if (((XObject) o).str().indexOf(((XObject) s).str()) != -1) {
  +                        return XBoolean.S_TRUE;
  +                    } else {
  +                        return XBoolean.S_FALSE;
  +                    }
  +                }
  +            }
  +            return null;
  +        }
  +
  +        private Object funcFloor(List args) throws Exception {
  +            if (args.size() == 1) {
  +                Object o = args.get(0);
  +                if (o instanceof XObject) {
  +                    return new XNumber(Math.floor(((XObject) o).num()));
  +                }
  +            }
  +            return null;
  +        }
  +
  +        private Object funcNormalizeSpace(List args) {
  +            if (args.size() == 1) {
  +                Object o = args.get(0);
  +                if (o instanceof XObject) {
  +                    return new XString(QueryEngine.normalizeString(((XObject) o).str()));
  +                }
  +            }
  +            return null;
  +        }
  +
  +        private Object funcNot(List args) throws Exception {
  +            if (args.size() == 1) {
  +                Object o = args.get(0);
  +                if (o instanceof XObject) {
  +                    if (((XObject) o).bool()) {
  +                        return XBoolean.S_FALSE;
  +                    } else {
  +                        return XBoolean.S_TRUE;
  +                    }
  +                } else {
  +                    if (o instanceof NamedKeys) {
  +                        NamedKeys nk = (NamedKeys) o;
  +                        if (nk.keys == null) {
  +                            return null;
  +                        }
  +                        if (nk.keys.length == 0) {
  +                            // nodeset empty converts to boolean false => not false => true
  +                            return XBoolean.S_TRUE;
  +                        }
  +                        return XBoolean.S_FALSE;
  +                    }
  +                    return null;
  +                }
  +
  +            }
  +            return null;
  +        }
  +
  +        private Object funcNumber(List args) throws Exception {
  +            if (args.size() == 1) {
  +                Object o = args.get(0);
  +                if (o instanceof XObject) {
  +                    return new XNumber(((XObject) o).num());
  +                }
  +            }
  +            return null;
  +        }
  +
  +        private Object funcRound(List args) throws Exception {
  +            if (args.size() == 1) {
  +                Object o = args.get(0);
  +                if (o instanceof XObject) {
  +                    return new XNumber(Math.round(((XObject) o).num()));
  +                }
  +            }
  +            return null;
  +        }
  +
  +        private Object funcStartsWith(String owner, List args) {
  +            if (args.size() == 2) {
  +                Object o = args.get(0);
  +                Object s = args.get(1);
  +
  +                if (o instanceof XObject && s instanceof XObject) {
  +                    if (((XObject) o).str().startsWith(((XObject) s).str())) {
  +                        return XBoolean.S_TRUE;
  +                    } else {
  +                        return XBoolean.S_FALSE;
  +                    }
  +                } else if (o instanceof NamedKeys && s instanceof XObject) {
  +                    NamedKeys nk = (NamedKeys) o;
  +                    String ps;
  +                    if (nk.attribute && nk.name.indexOf('@') == -1) {
  +                        ps = owner + "@" + nk.name;
  +                    } else {
  +                        ps = nk.name;
  +                    }
  +
  +                    IndexPattern pattern = new IndexPattern(symbols, ps, nsMap);
  +
  +                    XObject obj = (XObject) s;
  +                    Value val1 = new Value(obj.str());
  +
  +                    IndexQuery iq = new IndexQuerySW(pattern, val1);
  +                    return queryIndexes(nk, iq, ps, obj.getType());
  +                }
  +            }
  +            return null;
  +        }
  +
  +        private Object funcString(List args) {
  +            if (args.size() == 1) {
  +                Object o = args.get(0);
  +                if (o instanceof XObject) {
  +                    return new XString(((XObject) o).str());
  +                }
  +            }
  +            return null;
  +        }
  +
  +        private Object funcStringLength(List args) {
  +            if (args.size() == 1) {
  +                Object o = args.get(0);
  +                if (o instanceof XObject) {
  +                    return new XNumber(((XObject) o).str().length());
  +                }
  +            }
  +            return null;
  +        }
  +
  +        private Object funcSubstring(List args) throws Exception {
  +            if (args.size() == 2 || args.size() == 3) {
  +                Object o = args.get(0);
  +                Object pos = args.get(1);
  +                Object len = args.size() == 3 ? args.get(2) : null;
  +                if (o instanceof XObject && pos instanceof XObject && (len == null || len instanceof XObject)) {
  +                    int ipos = (int) ((XObject) pos).num() - 1;
  +                    if (len != null) {
  +                        int ilen = (int) ((XObject) len).num();
  +                        return new XString(((XObject) o).str().substring(ipos, ipos + ilen));
  +                    } else
  +                        return new XString(((XObject) o).str().substring(ipos));
  +                }
  +            }
  +            return null;
  +        }
  +
  +        private Object funcSubstringAfter(List args) {
  +            if (args.size() == 2) {
  +                Object o = args.get(0);
  +                Object s = args.get(1);
  +                if (o instanceof XObject && s instanceof XObject) {
  +                    String val = ((XObject) o).str();
  +                    String sub = ((XObject) s).str();
  +                    int i = val.indexOf(sub);
  +                    if (i == -1) {
  +                        return new XString("");
  +                    } else {
  +                        return new XString(val.substring(i + sub.length()));
  +                    }
  +                }
  +            }
  +            return null;
  +        }
  +
  +        private Object funcSubstringBefore(List args) {
  +            if (args.size() == 2) {
  +                Object o = args.get(0);
  +                Object s = args.get(1);
  +                if (o instanceof XObject && s instanceof XObject) {
  +                    String val = ((XObject) o).str();
  +                    String sub = ((XObject) s).str();
  +                    int i = val.indexOf(sub);
  +                    if (i == -1) {
  +                        return new XString("");
  +                    } else {
  +                        return new XString(val.substring(0, i));
  +                    }
  +                }
  +            }
  +            return null;
  +        }
  +
  +        private Object funcTranslate(List args) {
  +            if (args.size() == 3) {
  +                Object o = args.get(0);
  +                Object c1 = args.get(1);
  +                Object c2 = args.get(2);
  +                if (o instanceof XObject && c1 instanceof XObject && c2 instanceof XObject) {
  +                    char ch1 = ((XObject) c1).str().charAt(0);
  +                    char ch2 = ((XObject) c2).str().charAt(0);
  +                    return new XString(((XObject) o).str().replace(ch1, ch2));
  +                }
  +            }
  +            return null;
  +        }
  +
  +        // The Actual Querying Methods
  +
  +		/**
  +         * queryIndexes actually performs index-based querying on behalf of the evaluation methods.
  +         *
  +         * @param nk      The NamedKeys instance to use for matches
  +         * @param iq      The actual IndexQuery to use for resolution
  +         * @param ps      The pattern String to possibly use for index gen
  +         * @param objType The object type to possibly use for index gen
  +         * @return The resulting Keys (if any)
  +         */
  +        private Object queryIndexes(NamedKeys nk, IndexQuery iq, String ps, int objType) {
  +			try {
  +                // TODO: Add logic to use an EmptyKeySet if a name doesn't already
  +                //       exist in the SymbolTable.  This will eliminate the need
  +                //       to do a collection scan in those cases where somebody
  +                //       typed an element or attribute name incorrectly.
  +
  +                IndexPattern pattern = iq.getPattern();
  +
  +                Indexer idx = context.getIndexManager().getBestIndexer(Indexer.STYLE_NODEVALUE, pattern);
  +				if (idx != null) {
  +                    return new NamedKeys(nk.name, nk.attribute, QueryEngine.getUniqueKeys(idx.queryMatches(iq)));
  +                } else if (autoIndex) {
  +                    // TODO: This has to *not* be hardcoded
  +                    Element e = new DocumentImpl().createElement("index");
  +                    e.setAttribute("class", "org.apache.xindice.core.indexer.ValueIndexer");
  +                    e.setAttribute("name", "xp_" + ps);
  +                    e.setAttribute("pattern", ps);
  +
  +                    // Set the type for the index
  +                    String type = null;
  +                    switch (objType) {
  +                        case XObject.CLASS_BOOLEAN:
  +                            type = "boolean";
  +                            break;
  +                        case XObject.CLASS_NUMBER:
  +                            type = "double";
  +                            break;
  +                        case XObject.CLASS_STRING:
  +                            if (ps.indexOf('@') != -1) {
  +                                type = "string";
  +                            } else {
  +                                type = "trimmed";
  +                            }
  +                            break;
  +                        default :
  +                            if (log.isWarnEnabled()) {
  +                                log.warn("invalid object type : " + objType);
  +                            }
  +                    }
  +
  +                    if (type != null) {
  +                        e.setAttribute("type", type);
  +                    }
   
  -	private class NamedKeys
  -	{
  -		public boolean attribute = false;
  -		public String name;
  -		public Key[] keys;
  -
  -		public NamedKeys(String name, boolean attribute, Key[] keys)
  -		{
  -			this.name = name;
  -			this.attribute = attribute;
  -			this.keys = keys;
  -		}
  -	}
  +                    idxMgr.create(new Configuration(e));
  +                }
  +            } catch (Exception e) {
  +                if (log.isWarnEnabled()) {
  +                    log.warn("ignored exception", e);
  +                }
  +            }
  +            return null;
  +        }
  +
  +        /**
  +         * queryComparison performs a comparison query use the operands that are passed to it, and returns the resulting
  +         * Keys.
  +         *
  +         * @param op    The Operator
  +         * @param owner The Owner Node
  +         * @param left  The left Operand
  +         * @param right The right Operand
  +         * @return The resulting Keys (if any)
  +         */
  +        private Object queryComparison(int op, String owner, Object left, Object right) {
  +            op = OpMap[op - OpCodes.OP_NOTEQUALS];
  +
  +            if (left instanceof XObject) {
  +                // Check if we have to switch the operation
  +                if (op == IndexQuery.GT || op == IndexQuery.LT || op == IndexQuery.GEQ || op == IndexQuery.LEQ) {
  +                    op = -op;
  +                }
  +                // Swap the operands
  +                Object tmp = left;
  +                left = right;
  +                right = tmp;
  +            }
  +
  +            if (!(left instanceof NamedKeys && right instanceof XObject)) {
  +                // can't handle it
  +                return null;
  +            }
  +
  +            NamedKeys nk = (NamedKeys) left;
  +            XObject obj = (XObject) right;
  +
  +            String ps;
  +            if (nk.attribute && nk.name.indexOf('@') == -1) {
  +                ps = owner + "@" + nk.name;
  +            } else {
  +                ps = nk.name;
  +            }
  +
  +            IndexQuery iq;
  +            IndexPattern pattern = new IndexPattern(symbols, ps, nsMap);
  +            String value = obj.str();
  +
  +            switch (op) {
  +                case IndexQuery.NEQ:
  +                    iq = new IndexQueryNEQ(pattern, value);
  +                    break;
  +                case IndexQuery.EQ:
  +                    iq = new IndexQueryEQ(pattern, value);
  +                    break;
  +                case IndexQuery.LEQ:
  +                    iq = new IndexQueryLEQ(pattern, value);
  +                    break;
  +                case IndexQuery.LT:
  +                    iq = new IndexQueryLT(pattern, value);
  +                    break;
  +                case IndexQuery.GEQ:
  +                    iq = new IndexQueryGEQ(pattern, value);
  +                    break;
  +                case IndexQuery.GT:
  +                    iq = new IndexQueryGT(pattern, value);
  +                    break;
  +                default :
  +                    iq = null; // Won't happen
  +            }
  +
  +            return queryIndexes(nk, iq, ps, obj.getType());
  +        }
  +    }
  +
  +    /**
  +     * NamedKeys
  +     */
  +
  +    private class NamedKeys {
  +        public boolean attribute = false;
  +        public String name;
  +        public Key[] keys;
  +
  +        public NamedKeys(String name, boolean attribute, Key[] keys) {
  +            this.name = name;
  +            this.attribute = attribute;
  +            this.keys = keys;
  +        }
  +    }
   
   	/**
  -	 * ResultSet
  -	 */
  +     * ResultSet
  +     */
   
  -	private class ResultSet implements NodeSet {
  -		public Collection context;
  -		public String query;
  -		public ErrorListener errors;
  -		public PrefixResolver pr;
  -		public XPath xp;
  -
  -		public Key[] keySet;
  -		public int keyPos = 0;
  -		public NodeIterator ni;
  -		public Object node;
  +    private class ResultSet implements NodeSet {
  +        public Collection context;
  +        public String query;
  +        public ErrorListener errors;
  +        public PrefixResolver pr;
  +        public XPath xp;
  +
  +        public Key[] keySet;
  +        public int keyPos = 0;
  +        public NodeIterator ni;
  +        public Object node;
   
   		public ResultSet(Collection context, PrefixResolver pr, Key[] keySet, String query) {
  -			this.context = context;
  -			this.pr = pr;
  -			this.keySet = keySet;
  -			this.query = query;
  -
  -			errors = new ErrorListener() {
  -				public void fatalError(TransformerException te) {
  -					if (log.isFatalEnabled()) {
  -						log.fatal("No message", te);
  -					}
  -				}
  -
  -				public void error(TransformerException te) {
  -					if (log.isErrorEnabled()) {
  -						log.error("No message", te);
  -					}
  -				}
  -
  -				public void warning(TransformerException te) {
  -					if (log.isWarnEnabled()) {
  -						log.warn("No message", te);
  -					}
  -				}
  -			};
  +            this.context = context;
  +            this.pr = pr;
  +            this.keySet = keySet;
  +            this.query = query;
  +
  +            errors = new ErrorListener() {
  +                public void fatalError(TransformerException te) {
  +                    if (log.isFatalEnabled()) {
  +                        log.fatal("No message", te);
  +                    }
  +                }
  +
  +                public void error(TransformerException te) {
  +                    if (log.isErrorEnabled()) {
  +                        log.error("No message", te);
  +                    }
  +                }
  +
  +                public void warning(TransformerException te) {
  +                    if (log.isWarnEnabled()) {
  +                        log.warn("No message", te);
  +                    }
  +                }
  +            };
   
  -			try {
  -				prepareNextNode();
  +            try {
  +                prepareNextNode();
               } catch (Exception e) {
  -				throw new XindiceRuntimeException(e.getMessage());
  -			}
  -		}
  +                throw new XindiceRuntimeException(e.getMessage());
  +            }
  +        }
   
   		private void prepareNextNode() throws XMLDBException, TransformerException, DBException {
  -			node = null;
  +            node = null;
   
   			while (keyPos < keySet.length) {
  -				DBDocument d = (DBDocument) context.getDocument(keySet[keyPos++]);
  -				if (d == null) {
  -					continue;
  -				}
  -
  -				Node n = d.getDocumentElement();
  -
  -				XPathContext xpc = new XPathContext();
  -				PrefixResolver pfx;
  -				if (pr == null) {
  -					pfx = new PrefixResolverDefault(d.getDocumentElement());
  -					xp = new XPath(query, null, pfx, XPath.SELECT, errors);
  -				} else {
  -					pfx = pr;
  -					if (xp == null) {
  -						xp = new XPath(query, null, pfx, XPath.SELECT, errors);
  -					}
  -				}
  +                DBDocument d = (DBDocument) context.getDocument(keySet[keyPos++]);
  +                if (d == null) {
  +                    continue;
  +                }
  +
  +                Node n = d.getDocumentElement();
  +
  +                XPathContext xpc = new XPathContext();
  +                PrefixResolver pfx;
  +                if (pr == null) {
  +                    pfx = new PrefixResolverDefault(d.getDocumentElement());
  +                    xp = new XPath(query, null, pfx, XPath.SELECT, errors);
  +                } else {
  +                    pfx = pr;
  +                    if (xp == null) {
  +                        xp = new XPath(query, null, pfx, XPath.SELECT, errors);
  +                    }
  +                }
   
  -				final XObject xobject = xp.execute(xpc, n, pfx);
  +                final XObject xobject = xp.execute(xpc, n, pfx);
   				switch (xobject.getType()) {
                       // case XObject.CLASS_RTREEEFRAG :
  -					default :
  -						throw new XMLDBException(
  -							ErrorCodes.NOT_IMPLEMENTED,
  -							"Unsupported result type: " + xobject.getTypeString());
  -
  -					case XObject.CLASS_NODESET :
  -						ni = xobject.nodeset();
  -						node = ni.nextNode();
  -						break;
  +                    default :
  +                        throw new XMLDBException(ErrorCodes.NOT_IMPLEMENTED,
  +                                                 "Unsupported result type: " + xobject.getTypeString());
  +
  +                    case XObject.CLASS_NODESET:
  +                        ni = xobject.nodeset();
  +                        node = ni.nextNode();
  +                        break;
   
  -					case XObject.CLASS_BOOLEAN :
  -						ni = EMPTY_NODE_ITERATOR;
  +                    case XObject.CLASS_BOOLEAN:
  +                        ni = EMPTY_NODE_ITERATOR;
   
                           node = new DocumentImpl().createTextNode(Boolean.toString(xobject.bool()));
                           if (n instanceof DBNode) {
  -                            ((TextImpl)node).setSource(((DBNode)n).getSource());
  +                            ((TextImpl) node).setSource(((DBNode) n).getSource());
                           }
  -						break;
  +                        break;
   
  -					case XObject.CLASS_STRING :
  -						ni = EMPTY_NODE_ITERATOR;
  +                    case XObject.CLASS_STRING:
  +                        ni = EMPTY_NODE_ITERATOR;
   
                           node = new DocumentImpl().createTextNode(xobject.str());
                           if (n instanceof DBNode) {
  -                            ((TextImpl)node).setSource(((DBNode)n).getSource());
  +                            ((TextImpl) node).setSource(((DBNode) n).getSource());
                           }
  -						break;
  +                        break;
   
  -					case XObject.CLASS_NUMBER :
  -						ni = EMPTY_NODE_ITERATOR;
  +                    case XObject.CLASS_NUMBER:
  +                        ni = EMPTY_NODE_ITERATOR;
   
                           node = new DocumentImpl().createTextNode(Double.toString(xobject.num()));
                           if (n instanceof DBNode) {
  -                            ((TextImpl)node).setSource(((DBNode)n).getSource());
  +                            ((TextImpl) node).setSource(((DBNode) n).getSource());
                           }
  -						break;
  -				}
  +                        break;
  +                }
   
  -				if (node != null) {
  -					break;
  -				}
  -			}
  -		}
  -
  -		public boolean hasMoreNodes() {
  -			return node != null;
  -		}
  -
  -		public Object getNextNode() {
  -			Object n = node;
  -
  -			node = ni.nextNode();
  -			if (node == null) {
  -				try {
  -					prepareNextNode();
  -				} catch (Exception e) {
  -					throw new XindiceRuntimeException(e.getMessage());
  -				}
  -			}
  -
  -			return n;
  -		}
  -	}
  +                if (node != null) {
  +                    break;
  +                }
  +            }
  +        }
  +
  +        public boolean hasMoreNodes() {
  +            return node != null;
  +        }
  +
  +        public Object getNextNode() {
  +            Object n = node;
  +
  +            node = ni.nextNode();
  +            if (node == null) {
  +                try {
  +                    prepareNextNode();
  +                } catch (Exception e) {
  +                    throw new XindiceRuntimeException(e.getMessage());
  +                }
  +            }
  +
  +            return n;
  +        }
  +    }
   
   	/* This only implements what we need internally */
  -	private static class EmptyNodeIterator implements NodeIterator
  -	{
  +    private static class EmptyNodeIterator implements NodeIterator {
   
  -		/* (non-Javadoc)
  -		 * @see org.w3c.dom.traversal.NodeIterator#getWhatToShow()
  -		 */
  -		public int getWhatToShow()
  -		{
  -			throw new UnsupportedOperationException();
  -		}
  -
  -		/* (non-Javadoc)
  -		 * @see org.w3c.dom.traversal.NodeIterator#detach()
  -		 */
  -		public void detach()
  -		{
  -			throw new UnsupportedOperationException();
  -		}
  -
  -		/* (non-Javadoc)
  -		 * @see org.w3c.dom.traversal.NodeIterator#getExpandEntityReferences()
  -		 */
  -		public boolean getExpandEntityReferences()
  -		{
  -			throw new UnsupportedOperationException();
  -		}
  -
  -		/* (non-Javadoc)
  -		 * @see org.w3c.dom.traversal.NodeIterator#getRoot()
  -		 */
  -		public Node getRoot()
  -		{
  -			throw new UnsupportedOperationException();
  -		}
  -
  -		/* (non-Javadoc)
  -		 * @see org.w3c.dom.traversal.NodeIterator#nextNode()
  -		 */
  -		public Node nextNode() throws DOMException
  -		{
  -			return null;
  -		}
  -
  -		/* (non-Javadoc)
  -		 * @see org.w3c.dom.traversal.NodeIterator#previousNode()
  -		 */
  -		public Node previousNode() throws DOMException
  -		{
  -			throw new UnsupportedOperationException();
  -		}
  -
  -		/* (non-Javadoc)
  -		 * @see org.w3c.dom.traversal.NodeIterator#getFilter()
  -		 */
  -		public NodeFilter getFilter()
  -		{
  -			throw new UnsupportedOperationException();
  -		}
  -	}
  +        /* (non-Javadoc)
  +         * @see org.w3c.dom.traversal.NodeIterator#getWhatToShow()
  +         */
  +        public int getWhatToShow() {
  +            throw new UnsupportedOperationException();
  +        }
  +
  +        /* (non-Javadoc)
  +         * @see org.w3c.dom.traversal.NodeIterator#detach()
  +         */
  +        public void detach() {
  +            throw new UnsupportedOperationException();
  +        }
  +
  +        /* (non-Javadoc)
  +         * @see org.w3c.dom.traversal.NodeIterator#getExpandEntityReferences()
  +         */
  +        public boolean getExpandEntityReferences() {
  +            throw new UnsupportedOperationException();
  +        }
  +
  +        /* (non-Javadoc)
  +         * @see org.w3c.dom.traversal.NodeIterator#getRoot()
  +         */
  +        public Node getRoot() {
  +            throw new UnsupportedOperationException();
  +        }
  +
  +        /* (non-Javadoc)
  +         * @see org.w3c.dom.traversal.NodeIterator#nextNode()
  +         */
  +        public Node nextNode() throws DOMException {
  +            return null;
  +        }
  +
  +        /* (non-Javadoc)
  +         * @see org.w3c.dom.traversal.NodeIterator#previousNode()
  +         */
  +        public Node previousNode() throws DOMException {
  +            throw new UnsupportedOperationException();
  +        }
  +
  +        /* (non-Javadoc)
  +         * @see org.w3c.dom.traversal.NodeIterator#getFilter()
  +         */
  +        public NodeFilter getFilter() {
  +            throw new UnsupportedOperationException();
  +        }
  +    }
   
  -	private final static NodeIterator EMPTY_NODE_ITERATOR = new EmptyNodeIterator();
  +    private final static NodeIterator EMPTY_NODE_ITERATOR = new EmptyNodeIterator();
   }