aSaxon-B-9-0-0-8sources.api.Saxon.Api.XQuery.cs Maven / Gradle / Ivy
The newest version!
using System;
using System.IO;
using System.Xml;
using System.Collections;
using JConfiguration = net.sf.saxon.Configuration;
using net.sf.saxon.om;
using net.sf.saxon.value;
using net.sf.saxon.query;
using net.sf.saxon.dotnet;
using JXPathException = net.sf.saxon.trans.XPathException;
using JStreamSource = javax.xml.transform.stream.StreamSource;
namespace Saxon.Api {
///
/// An XQueryCompiler object allows XQuery queries to be compiled.
///
///
/// To construct an XQueryCompiler , use the factory method
/// newXQueryCompiler on the Processor object.
/// The XQueryCompiler holds information that represents the static context
/// for the queries that it compiles. This information remains intact after performing
/// a compilation. An XQueryCompiler may therefore be used repeatedly to compile multiple
/// queries. Any changes made to the XQueryCompiler (that is, to the
/// static context) do not affect queries that have already been compiled.
/// An XQueryCompiler may be used concurrently in multiple threads, but
/// it should not then be modified once initialized.
///
///
[Serializable]
public class XQueryCompiler {
private JConfiguration config;
private StaticQueryContext env;
private IQueryResolver moduleResolver;
private IList errorList;
// internal constructor: the public interface is a factory method
// on the Processor object
internal XQueryCompiler(Processor processor) {
this.config = processor.config;
this.env = new StaticQueryContext(config);
env.setModuleURIResolver(new DotNetStandardModuleURIResolver(processor.XmlResolver));
}
///
/// Declare a namespace for use by the query. This has the same
/// status as a namespace appearing within the query prolog (though
/// a declaration in the query prolog of the same prefix will take
/// precedence)
///
/// The namespace prefix to be declared. Use
/// a zero-length string to declare the default namespace (that is, the
/// default namespace for elements and types).
/// The namespace URI. It is possible to specify
/// a zero-length string to "undeclare" a namespace.
public void DeclareNamespace(String prefix, String uri) {
env.declareNamespace(prefix, uri);
}
///
/// The base URI of the query, which forms part of the static context
/// of the query. This is used for resolving any relative URIs appearing
/// within the query, for example in references to library modules, schema
/// locations, or as an argument to the doc() function.
///
public String BaseUri {
get { return env.getBaseURI(); }
set { env.setBaseURI(value); }
}
///
/// A user-supplied IQueryResolver used to resolve location hints appearing in an
/// import module declaration.
///
///
/// In the absence of a user-supplied QueryResolver , an import module declaration
/// is interpreted as follows. First, if the module URI identifies an already loaded module, that module
/// is used and the location hints are ignored. Otherwise, each URI listed in the location hints is
/// resolved using the XmlResolver registered with the Processor .
///
public IQueryResolver QueryResolver {
get { return moduleResolver; }
set {
moduleResolver = value;
env.setModuleURIResolver(new DotNetModuleURIResolver(value));
}
}
///
/// List of errors. The caller should supply an empty list before calling Compile;
/// the processor will then populate the list with error information obtained during
/// the compilation. Each error will be included as an object of type StaticError.
/// If no error list is supplied by the caller, error information will be written to
/// the standard error stream.
///
///
/// By supplying a custom List with a user-written add() method, it is possible to
/// intercept error conditions as they occur.
///
public IList ErrorList {
set {
errorList = value;
env.setErrorListener(new ErrorGatherer(value));
}
get {
return errorList;
}
}
///
/// Compile a query supplied as a Stream.
///
///
/// The XQuery processor attempts to deduce the encoding of the query
/// by looking for a byte-order-mark, or if none is present, by looking
/// for the encoding declaration in the XQuery version declaration.
/// For this to work, the stream must have the CanSeek property.
/// If no encoding information is present, UTF-8 is assumed.
/// The base URI of the query is set to the value of the BaseUri
/// property. If this has not been set, then the base URI will be undefined, which
/// means that any use of an expression that depends on the base URI will cause
/// an error.
///
///
///
/// XQueryExecutable q = compiler.Compile(new FileStream("input.xq", FileMode.Open, FileAccess.Read));
///
///
/// A stream containing the source text of the query
/// An XQueryExecutable which represents the compiled query object.
/// The XQueryExecutable may be run as many times as required, in the same or a different
/// thread. The XQueryExecutable is not affected by any changes made to the XQueryCompiler
/// once it has been compiled.
/// Throws a StaticError if errors were detected
/// during static analysis of the query. Details of the errors will be added as StaticError
/// objects to the ErrorList if supplied; otherwise they will be written to the standard
/// error stream. The exception that is returned is merely a summary indicating the
/// status.
public XQueryExecutable Compile(Stream query) {
try {
XQueryExpression exp = env.compileQuery(new DotNetInputStream(query), null);
return new XQueryExecutable(exp);
} catch (JXPathException e) {
throw new StaticError(e);
}
}
///
/// Compile a query supplied as a String.
///
///
/// Using this method the query processor is provided with a string of Unicode
/// characters, so no decoding is necessary. Any encoding information present in the
/// version declaration is therefore ignored.
///
///
///
/// XQueryExecutable q = compiler.Compile("distinct-values(//*/node-name()");
///
///
/// A string containing the source text of the query
/// An XQueryExecutable which represents the compiled query object.
/// The XQueryExecutable may be run as many times as required, in the same or a different
/// thread. The XQueryExecutable is not affected by any changes made to the XQueryCompiler
/// once it has been compiled.
/// Throws a StaticError if errors were detected
/// during static analysis of the query. Details of the errors will be added as StaticError
/// objects to the ErrorList if supplied; otherwise they will be written to the standard
/// error stream. The exception that is returned is merely a summary indicating the
/// status.
public XQueryExecutable Compile(String query) {
try {
XQueryExpression exp = env.compileQuery(query);
return new XQueryExecutable(exp);
} catch (JXPathException e) {
throw new StaticError(e);
}
}
///
/// Escape hatch to the underying Java implementation
///
public StaticQueryContext Implementation {
get { return env; }
}
}
///
/// An XQueryExecutable represents the compiled form of a query. To execute the query,
/// it must first be loaded to form an XQueryEvaluator .
///
///
/// An XQueryExecutable is immutable, and therefore thread-safe. It is simplest to
/// load a new XQueryEvaluator each time the query is to be run. However, the
/// XQueryEvaluator is serially reusable within a single thread.
/// An XQueryExecutable is created by using one of the Compile
/// methods on the XQueryCompiler class.
///
[Serializable]
public class XQueryExecutable {
private XQueryExpression exp;
// internal constructor
internal XQueryExecutable(XQueryExpression exp) {
this.exp = exp;
}
///
/// Load the query to prepare it for execution.
///
///
/// An XQueryEvaluator . The returned XQueryEvaluator can be used to
/// set up the dynamic context for query evaluation, and to run the query.
///
public XQueryEvaluator Load() {
return new XQueryEvaluator(exp);
}
}
///
/// An XQueryEvaluator represents a compiled and loaded query ready for execution.
/// The XQueryEvaluator holds details of the dynamic evaluation context for the query.
///
///
/// An XQueryEvaluator should not be used concurrently in multiple threads. It is safe,
/// however, to reuse the object within a single thread to run the same query several times.
/// Running the query does not change the context that has been established.
/// An XQueryEvaluator is always constructed by running the Load method of
/// an XQueryExecutable .
///
[Serializable]
public class XQueryEvaluator : IEnumerable {
private XQueryExpression exp;
private DynamicQueryContext context;
// internal constructor
internal XQueryEvaluator(XQueryExpression exp) {
this.exp = exp;
this.context =
new DynamicQueryContext(exp.getStaticContext().getConfiguration());
}
///
/// The context item for the query.
///
/// This may be either a node or an atomic
/// value. Most commonly it will be a document node, which might be constructed
/// using the LoadDocument method of the Processor object.
///
public XdmItem ContextItem {
get { return (XdmItem)XdmValue.Wrap(context.getContextItem()); }
set { context.setContextItem((Item)value.Unwrap()); }
}
///
/// The XmlResolver
to be used at run-time to resolve and dereference URIs
/// supplied to the doc() function.
///
public XmlResolver InputXmlResolver {
get {
return ((DotNetURIResolver)context.getURIResolver()).getXmlResolver();
}
set {
context.setURIResolver(new DotNetURIResolver(value));
}
}
///
/// Set the value of an external variable declared in the query.
///
/// The name of the external variable, expressed
/// as a QName. If an external variable of this name has been declared in the
/// query prolog, the given value will be assigned to the variable. If the
/// variable has not been declared, calling this method has no effect (it is
/// not an error).
/// The value to be given to the external variable.
/// If the variable declaration defines a required type for the variable, then
/// this value must match the required type: no conversions are applied.
public void SetExternalVariable(QName name, XdmValue value) {
context.setParameter(name.ClarkName, value.Unwrap());
}
///
/// Evaluate the query, returning the result as an XdmValue (that is,
/// a sequence of nodes and/or atomic values).
///
///
/// An XdmValue representing the results of the query
///
/// Throws a DynamicError if any run-time failure
/// occurs while evaluating the query.
public XdmValue Evaluate() {
try {
ValueRepresentation value = SequenceExtent.makeSequenceExtent(exp.iterator(context));
return XdmValue.Wrap(value);
} catch (JXPathException err) {
throw new DynamicError(err);
}
}
///
/// Evaluate the query, returning the result as an XdmItem (that is,
/// a single node or atomic value).
///
///
/// An XdmItem representing the result of the query, or null if the query
/// returns an empty sequence. If the query returns a sequence of more than one item,
/// any items after the first are ignored.
///
/// Throws a DynamicError if any run-time failure
/// occurs while evaluating the expression.
public XdmItem EvaluateSingle() {
try {
return (XdmItem)XdmValue.Wrap(exp.iterator(context).next());
} catch (JXPathException err) {
throw new DynamicError(err);
}
}
///
/// Evaluate the query, returning the result as an IEnumerator (that is,
/// an enumerator over a sequence of nodes and/or atomic values).
///
///
/// An enumerator over the sequence that represents the results of the query.
/// Each object in this sequence will be an instance of XdmItem . Note
/// that the query may be evaluated lazily, which means that a successful response
/// from this method does not imply that the query has executed successfully: failures
/// may be reported later while retrieving items from the iterator.
///
/// Throws a DynamicError if any run-time failure
/// occurs while evaluating the expression.
public IEnumerator GetEnumerator() {
try {
return new SequenceEnumerator(exp.iterator(context));
} catch (JXPathException err) {
throw new DynamicError(err);
}
}
///
/// Evaluate the query, sending the result to a specified destination.
///
///
/// The destination for the results of the query. The class XmlDestination
/// is an abstraction that allows a number of different kinds of destination
/// to be specified.
///
/// Throws a DynamicError if any run-time failure
/// occurs while evaluating the expression.
public void Run(XmlDestination destination) {
try {
exp.run(context, destination.GetResult(), destination.GetOutputProperties());
} catch (JXPathException err) {
throw new DynamicError(err);
}
destination.Close();
}
}
///
/// Interface defining a user-supplied class used to retrieve XQUery library modules listed
/// in an import module declaration in the query prolog.
///
public interface IQueryResolver {
///
/// Given a module URI and a set of location hints, return a set of query modules.
///
/// The URI of the required library module as written in the
/// import module declaration
/// The base URI of the module containing the import module
/// declaration
/// The sequence of URIs (if any) listed as location hints
/// in the import module declaration in the query prolog.
/// A set of absolute Uris identifying the query modules to be loaded. There is no requirement
/// that these correspond one-to-one with the URIs defined in the locationHints . The
/// returned URIs will be dereferenced by calling the GetEntity method.
///
Uri[] GetModules(String moduleUri, Uri baseUri, String[] locationHints);
///
/// Dereference a URI returned by GetModules to retrieve a Stream containing
/// the actual query text.
///
/// A URI returned by the GetModules
method.
/// Either a Stream or a String containing the query text.
/// The supplied URI will be used as the base URI of the query module.
Object GetEntity(Uri absoluteUri);
}
// internal class that wraps a (.NET) IQueryResolver to create a (Java) ModuleURIResolver
internal class DotNetModuleURIResolver : net.sf.saxon.query.ModuleURIResolver {
private IQueryResolver resolver;
public DotNetModuleURIResolver(IQueryResolver resolver) {
this.resolver = resolver;
}
public JStreamSource[] resolve(String moduleURI, String baseURI, String[] locations) {
Uri baseU = (baseURI == null ? null : new Uri(baseURI));
Uri[] modules = resolver.GetModules(moduleURI, baseU, locations);
JStreamSource[] ss = new JStreamSource[modules.Length];
for (int i = 0; i < ss.Length; i++) {
ss[i] = new JStreamSource();
ss[i].setSystemId(modules[i].ToString());
Object query = resolver.GetEntity(modules[i]);
if (query is Stream) {
ss[i].setInputStream(new DotNetInputStream((Stream)query));
} else if (query is String) {
ss[i].setReader(new DotNetReader(new StringReader((String)query)));
} else {
throw new ArgumentException("Invalid response from GetEntity()");
}
}
return ss;
}
}
}
//
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
// you may not use this file except in compliance with the License. You may obtain a copy of the
// License at http://www.mozilla.org/MPL/
//
// Software distributed under the License is distributed on an "AS IS" basis,
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
// See the License for the specific language governing rights and limitations under the License.
//
// The Original Code is: all this file.
//
// The Initial Developer of the Original Code is Michael H. Kay.
//
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
//
// Contributor(s): none.
//
© 2015 - 2025 Weber Informatics LLC | Privacy Policy