/** * The constructor is protected, to ensure that instances can only be created using the * compileQuery() methods of StaticQueryContext * * @param exp an expression to be wrapped as an XQueryExpression * @param exec the executable * @param mainModule the static context of the main module * @param config the configuration * @throws XPathException if an error occurs */ protected XQueryExpression( Expression exp, Executable exec, QueryModule mainModule, Configuration config) throws XPathException { stackFrameMap = config.makeSlotManager(); executable = exec; exp.setContainer(this); try { ExpressionVisitor visitor = ExpressionVisitor.make(mainModule); visitor.setExecutable(exec); exp = visitor.simplify(exp); exp.checkForUpdatingSubexpressions(); exp = visitor.typeCheck(exp, mainModule.getUserQueryContext().getRequiredContextItemType()); // ExpressionPresenter presenter = new ExpressionPresenter(config, // ExpressionPresenter.defaultDestination(config, new // FileOutputStream("c:/projects/montreal/before50.xml"))); // exp.explain(presenter); // presenter.close(); exp = exp.optimize(visitor, Type.ITEM_TYPE); } catch (XPathException err) { // err.printStackTrace(); mainModule.reportFatalError(err); throw err; } ExpressionTool.allocateSlots(exp, 0, stackFrameMap); expression = exp; executable.setConfiguration(config); executable.setDefaultCollationName(mainModule.getDefaultCollationName()); executable.setCollationTable(mainModule.getUserQueryContext().getAllCollations()); staticContext = mainModule; isUpdating = exp.isUpdatingExpression(); }
/** * Get the path map for the query expression * * @return the path map (which is constructed if this has not already been done) */ public PathMap getPathMap() { if (pathMap == null) { pathMap = new PathMap(expression); } HashMap map = executable.getCompiledGlobalVariables(); if (map != null) { Iterator iter = map.values().iterator(); while (iter.hasNext()) { GlobalVariable var = (GlobalVariable) iter.next(); Expression select = var.getSelectExpression(); select.addToPathMap(pathMap, null); } } return pathMap; }
/** * Run an updating query, writing back eligible updated node to persistent storage. * * <p>A node is eligible to be written back to disk if it is present in the document pool, which * generally means that it was originally read using the doc() or collection() function. * * <p>On completion of this method it is generally unsafe to rely on the contents or relationships * of NodeInfo objects that were obtained before the updating query was run. Such objects may or * may not reflect the results of the update operations. This is especially true in the case of * nodes that are part of a subtree that has been deleted (detached from its parent). Instead, the * new updated tree should be accessed by navigation from the root nodes returned by this method. * * <p>If one or more eligible updated nodes cannot be written back to disk, perhaps because the * URI identifies a non-updatable location, then an exception is thrown. In this case it is * undefined * * @param dynamicEnv the dynamic context for query execution * @throws XPathException if evaluation of the update query fails, or it this is not an updating * query */ public void runUpdate(DynamicQueryContext dynamicEnv, UpdateAgent agent) throws XPathException { if (!isUpdating) { throw new XPathException("Calling runUpdate() on a non-updating query"); } Configuration config = executable.getConfiguration(); Controller controller = newController(); initializeController(dynamicEnv, controller); XPathContextMajor context = initialContext(dynamicEnv, controller); try { PendingUpdateList pul = config.newPendingUpdateList(); context.openStackFrame(stackFrameMap); expression.evaluatePendingUpdates(context, pul); pul.apply(context, staticContext.getRevalidationMode()); for (Iterator iter = pul.getAffectedTrees().iterator(); iter.hasNext(); ) { NodeInfo node = (NodeInfo) iter.next(); agent.update(node, controller); } } catch (XPathException e) { if (!e.hasBeenReported()) { try { controller.getErrorListener().fatalError(e); } catch (TransformerException e2) { // ignore secondary error } } throw e; } }
/** * Ask whether this query uses the context item * * @return true if the context item is referenced either in the query body or in the initializer * of any global variable */ public boolean usesContextItem() { if ((expression.getDependencies() & StaticProperty.DEPENDS_ON_FOCUS) != 0) { return true; } HashMap map = executable.getCompiledGlobalVariables(); if (map != null) { Iterator iter = map.values().iterator(); while (iter.hasNext()) { GlobalVariable var = (GlobalVariable) iter.next(); Expression select = var.getSelectExpression(); if (select != null && (select.getDependencies() & StaticProperty.DEPENDS_ON_FOCUS) != 0) { return true; } } } return false; }
/** * Run the query, sending the results directly to a JAXP Result object. This way of executing the * query is most efficient in the case of queries that produce a single document (or parentless * element) as their output, because it avoids constructing the result tree in memory: instead, it * is piped straight to the serializer. * * @param env the dynamic query context * @param result the destination for the results of the query. The query is effectively wrapped in * a document{} constructor, so that the items in the result are concatenated to form a single * document; this is then written to the requested Result destination, which may be (for * example) a DOMResult, a SAXResult, or a StreamResult * @param outputProperties Supplies serialization properties, in JAXP format, if the result is to * be serialized. This parameter can be defaulted to null. * @throws XPathException if the query fails. */ public void run(DynamicQueryContext env, Result result, Properties outputProperties) throws XPathException { if (isUpdating) { throw new XPathException("Cannot call run() on an updating query"); } Controller controller = newController(); initializeController(env, controller); if (allowDocumentProjection) { controller.setUseDocumentProjection(getPathMap()); } Properties actualProperties = validateOutputProperties(controller, outputProperties); controller.defineGlobalParameters(); XPathContextMajor context = initialContext(env, controller); // In tracing/debugging mode, evaluate all the global variables first TraceListener tracer = controller.getTraceListener(); if (tracer != null) { controller.preEvaluateGlobals(context); tracer.open(); } context.openStackFrame(stackFrameMap); boolean mustClose = (result instanceof StreamResult && ((StreamResult) result).getOutputStream() == null); context.changeOutputDestination( actualProperties, result, true, Configuration.XQUERY, Validation.PRESERVE, null); context.getReceiver().open(); // Run the query try { expression.process(context); } catch (XPathException err) { controller.reportFatalError(err); throw err; } if (tracer != null) { tracer.close(); } context.getReceiver().close(); if (mustClose) { OutputStream os = ((StreamResult) result).getOutputStream(); if (os != null) { try { os.close(); } catch (java.io.IOException err) { throw new XPathException(err); } } } }
/** * Diagnostic method: display a representation of the compiled query on the selected output * stream. * * @param out an ExpressionPresenter to which the XML representation of the compiled query will be * sent */ public void explain(ExpressionPresenter out) { out.startElement("query"); staticContext.getExecutable().getKeyManager().explainKeys(out); staticContext.getExecutable().explainGlobalVariables(out); staticContext.explainGlobalFunctions(out); out.startElement("body"); expression.explain(out); out.endElement(); out.endElement(); out.close(); }
/** * Get an iterator over the results of the expression. This returns results without any conversion * of the returned items to "native" Java classes. The iterator will deliver a sequence of Item * objects, each item being either a NodeInfo (representing a node) or an AtomicValue * (representing an atomic value). * * <p> * * <p>To get the results of the query in the form of an XML document in which each item is wrapped * by an element indicating its type, use: * * <p> * * <p><code>QueryResult.wrap(iterator(env))</code> * * <p> * * <p>To serialize the results to a file, use the QueryResult.serialize() method. * * @param env Provides the dynamic query evaluation context * @return an iterator over the results of the query. The class SequenceIterator is modeled on the * standard Java Iterator class, but has extra functionality and can throw exceptions when * errors occur. * @throws XPathException if a dynamic error occurs in evaluating the query. Some dynamic errors * will not be reported by this method, but will only be reported when the individual items of * the result are accessed using the returned iterator. */ public SequenceIterator iterator(DynamicQueryContext env) throws XPathException { if (isUpdating) { throw new XPathException("Cannot call iterator() on an updating query"); } Controller controller = newController(); initializeController(env, controller); try { Item contextItem = env.getContextItem(); // Bindery bindery = controller.getBindery(); // bindery.openStackFrame(); controller.defineGlobalParameters(); XPathContextMajor context = controller.newXPathContext(); if (contextItem != null) { if (!staticContext .getUserQueryContext() .getRequiredContextItemType() .matchesItem(contextItem, false, env.getConfiguration())) { throw new XPathException( "The supplied context item does not match the required context item type"); } UnfailingIterator single = SingletonIterator.makeIterator(contextItem); single.next(); context.setCurrentIterator(single); controller.setInitialContextItem(contextItem); } // In tracing/debugging mode, evaluate all the global variables first if (controller.getTraceListener() != null) { controller.preEvaluateGlobals(context); } context.openStackFrame(stackFrameMap); SequenceIterator iterator = expression.iterate(context); return new ErrorReportingIterator(iterator, controller.getErrorListener()); } catch (XPathException err) { TransformerException terr = err; while (terr.getException() instanceof TransformerException) { terr = (TransformerException) terr.getException(); } XPathException de = XPathException.makeXPathException(terr); controller.reportFatalError(de); throw de; } }
/** * Run the query returning the results as an EventIterator * * @param controller The Controller used to run the query * @param dynamicEnv the XQuery dynamic context for evaluating the query * @return an EventIterator representing the results of the query as a sequence of events */ public EventIterator iterateEvents(Controller controller, DynamicQueryContext dynamicEnv) throws XPathException { if (isUpdating) { throw new XPathException("Cannot call iterateEvents() on an updating query"); } initializeController(dynamicEnv, controller); XPathContextMajor context = initialContext(dynamicEnv, controller); // In tracing/debugging mode, evaluate all the global variables first if (controller.getTraceListener() != null) { controller.preEvaluateGlobals(context); } context.openStackFrame(stackFrameMap); final Configuration config = executable.getConfiguration(); EventIterator ei = expression.iterateEvents(context); // ei = new TracingEventIterator(EventStackIterator.flatten(ei)); return new ComplexContentProcessor(config, ei); }