All Downloads are FREE. Search and download functionalities are using the official Maven repository.

api.Saxon.Api.XQuery.cs Maven / Gradle / Ivy

Go to download

Saxon a complete and conformant implementation of the XSLT 2.0, XQuery 1.0, and XPath 2.0 Recommendations published on 23 January 2007 by W3C

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

        /// 
        /// This property indicates whether XQuery Update syntax is accepted. The default
        /// value is false. This property must be set to true before compiling a query that
        /// uses update syntax.
        /// 
        /// 
        /// This propery must be set to true before any query can be compiled
        /// that uses updating syntax. This applies even if the query is not actually an updating
        /// query (for example, a copy-modify expression). XQuery Update syntax is accepted
        /// only by Saxon-SA. Non-updating queries are accepted regardless of the value of this
        /// property.
        /// Property added in Saxon 9.1


        public bool UpdatingEnabled
        {
            get { return env.isUpdatingEnabled(); }
            set { env.setUpdatingEnabled(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 net.sf.saxon.query.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;
        }

        /// Ask whether this is an updating query (that is, one that returns a pending
        /// update list rather than a convensional value).
        /// Property added in Saxon 9.1

        public bool IsUpdateQuery
        {
            get { return exp.isUpdateQuery(); }
        }

        /// 
        /// 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;
        private Stream traceFunctionDestination;

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

        /// 
        /// Destination for output of messages produced using <trace()>. 
        /// If no specific destination is supplied by the caller, message information will be written to
        /// the standard error stream.
        /// 
        /// 
        /// The supplied destination is ignored if a TraceListener is in use.
        /// Property added in Saxon 9.1
        /// 

        public Stream TraceFunctionDestination
        {
            set
            {
                traceFunctionDestination = value;
                context.setTraceFunctionDestination(
                    new java.io.PrintStream(new DotNetOutputStream(value)));
            }
            get
            {
                return traceFunctionDestination;
            }
        }


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

        /// 
        /// Execute an updating query.
        /// 
        /// An array containing the root nodes of documents that have been
        /// updated by the query.
        /// Throws a DynamicError if any run-time failure
        /// occurs while evaluating the expression, or if the expression is not an
        /// updating query.

        public XdmNode[] RunUpdate()
        {
            if (!exp.isUpdateQuery())
            {
                throw new DynamicError("Not an updating query");
            }
            try
            {
                java.util.Set updatedDocs = exp.runUpdate(context);
                XdmNode[] result = new XdmNode[updatedDocs.size()];
                int i = 0;
                for (java.util.Iterator iter = updatedDocs.iterator(); iter.hasNext(); )
                {
                    result[i++] = (XdmNode)XdmValue.Wrap((NodeInfo)iter.next());
                }
                return result;
            }
            catch (JXPathException err)
            {
                throw new DynamicError(err);
            }
        }

    }


    /// 
    /// 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 - 2024 Weber Informatics LLC | Privacy Policy