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();
}