Project

Profile

Help

How to connect?
Download (38 KB) Statistics
| Branch: | Revision:

he / src / main / csharp / api / Saxon.Api / XQuery.cs @ 2cd2299c

1
using System;
2
using System.IO;
3
using System.Xml;
4
using System.Collections;
5
using System.Globalization;
6
using System.Collections.Generic;
7
using JConfiguration = net.sf.saxon.Configuration;
8
using JXQueryEvaluator = net.sf.saxon.s9api.XQueryEvaluator;
9
using JXQName = net.sf.saxon.s9api.QName;
10
using JXdmValue = net.sf.saxon.s9api.XdmValue;
11
using JNodeInfo = net.sf.saxon.om.NodeInfo;
12
using JSequence = net.sf.saxon.om.Sequence;
13
using JDynamicQueryContext = net.sf.saxon.query.DynamicQueryContext;
14
using JDotNetStandardModuleURIResolver = net.sf.saxon.dotnet.DotNetStandardModuleURIResolver;
15
using JDotNetComparator = net.sf.saxon.dotnet.DotNetComparator;
16
using JDotNetInputStream = net.sf.saxon.dotnet.DotNetInputStream;
17
using JDotNetURIResolver = net.sf.saxon.dotnet.DotNetURIResolver;
18
using JDotNetReader = net.sf.saxon.dotnet.DotNetReader;
19
using JValidation = net.sf.saxon.lib.Validation;
20
using JXPathException = net.sf.saxon.trans.XPathException;
21
using JStreamSource = javax.xml.transform.stream.StreamSource;
22
using JXQueryCompiler = net.sf.saxon.s9api.XQueryCompiler;
23
using JXQueryExecutable = net.sf.saxon.s9api.XQueryExecutable;
24
using JSaxonApiException = net.sf.saxon.s9api.SaxonApiException;
25

    
26
namespace Saxon.Api
27
{
28

    
29
    /// <summary>
30
    /// The <c>XQueryCompiler</c> object allows XQuery queries to be compiled.
31
    /// </summary>
32
    /// <remarks>
33
    /// <para>To construct an <c>XQueryCompiler</c>, use the factory method
34
	/// <c>NewXQueryCompiler</c> on the <see cref="Processor"/> object.</para>
35
    /// <para>The <c>XQueryCompiler</c> holds information that represents the static context
36
    /// for the queries that it compiles. This information remains intact after performing
37
    /// a compilation. An <c>XQueryCompiler</c> may therefore be used repeatedly to compile multiple
38
    /// queries. Any changes made to the <c>XQueryCompiler</c> (that is, to the
39
    /// static context) do not affect queries that have already been compiled.</para>
40
    /// <para>An <c>XQueryCompiler</c> may be used concurrently in multiple threads, but
41
    /// it should not then be modified once initialized.</para>
42
    /// </remarks>
43

    
44
    [Serializable]
45
    public class XQueryCompiler
46
    {
47

    
48
        private JConfiguration config;
49
        private Processor processor;
50
        private IQueryResolver moduleResolver;
51
        private IList<StaticError> errorList;
52
        private ErrorReporterToStaticError errorGatherer;
53
        private ErrorReporter errorReporter;
54
        private JXQueryCompiler compiler;
55

    
56
        // internal constructor: the public interface is a factory method
57
        // on the Processor object
58

    
59
        internal XQueryCompiler(Processor processor)
60
        {
61
            this.processor = processor;
62
			this.config = processor.Implementation;
63
            compiler = processor.JProcessor.newXQueryCompiler();
64
            compiler.setModuleURIResolver(new JDotNetStandardModuleURIResolver(processor.XmlResolver));
65
        }
66

    
67
        /// <summary>
68
        /// Create a collation based on a given <c>CompareInfo</c> and <c>CompareOptions</c>    
69
        /// </summary>
70
        /// <remarks>
71
        /// In the current and recent releases of Saxon, collations are always defined at the level of a <c>Configuration</c>.
72
        /// Declaring a collation here may therefore have wider effects than intended. It is recommended not to use
73
        /// this method, but to use <see cref="Processor.DeclareCollation(Uri, CompareInfo, CompareOptions)"/> instead.
74
        /// </remarks>
75
        /// <param name="uri">The collation URI to be used within the XPath expression to refer to this collation</param>
76
        /// <param name="compareInfo">The <c>CompareInfo</c>, which determines the language-specific
77
        /// collation rules to be used</param>
78
        /// <param name="options">Options to be used in performing comparisons, for example
79
        /// whether they are to be case-blind and/or accent-blind</param>
80
        /// <param name="isDefault">If true, this collation will be used as the default collation</param>
81

    
82
        public void DeclareCollation(Uri uri, CompareInfo compareInfo, CompareOptions options, Boolean isDefault) {
83
			JDotNetComparator comparator = new JDotNetComparator(uri.ToString(), compareInfo, options);
84
			config.registerCollation(uri.ToString(), comparator);
85
            if (isDefault) {
86
                compiler.declareDefaultCollation(uri.ToString());
87
            }
88
        }
89

    
90

    
91
        /// <summary>
92
        /// Declare a namespace for use by the query. This has the same
93
        /// status as a namespace appearing within the query prolog (though
94
        /// a declaration in the query prolog of the same prefix will take
95
        /// precedence).
96
        /// </summary>
97
        /// <param name="prefix">The namespace prefix to be declared. Use
98
        /// a zero-length string to declare the default namespace (that is, the
99
        /// default namespace for elements and types).</param>
100
        /// <param name="uri">The namespace URI. It is possible to specify
101
        /// a zero-length string to "undeclare" a namespace.</param>
102

    
103
        public void DeclareNamespace(String prefix, String uri)
104
        {
105
            compiler.declareNamespace(prefix, uri);
106
        }
107

    
108

    
109
        /// <summary>
110
		/// Get the <c>Processor</c> from which this <c>XQueryCompiler</c> was constructed
111
        /// </summary>
112
        
113
		public Processor Processor
114
        {
115
            get {return processor;}
116
        }
117

    
118
        /// <summary>
119
        /// The required context item type for the expression. This is used for
120
        /// optimizing the expression at compile time, and to check at run-time
121
        /// that the value supplied for the context item is the correct type.
122
        /// </summary>
123

    
124
        public XdmItemType ContextItemType
125
        {
126
            get { return XdmItemType.MakeXdmItemType(compiler.getRequiredContextItemType().getUnderlyingItemType()); }
127
            set { compiler.setRequiredContextItemType(value.Unwrap()); }
128
        }
129

    
130
        /// <summary>
131
        /// The base URI of the query, which forms part of the static context
132
        /// of the query. This is used for resolving any relative URIs appearing
133
        /// within the query, for example in references to library modules, schema
134
        /// locations, or as an argument to the <c>doc()</c> function.
135
        /// </summary>
136

    
137

    
138
        public String BaseUri
139
        {
140
            get { return compiler.getBaseURI().toASCIIString(); }
141
            set { compiler.setBaseURI(new java.net.URI(value)); }
142
        }
143

    
144

    
145
        /// <summary>
146
        /// Say that the query must be compiled to be schema-aware, even if it contains no
147
        /// "import schema" declarations. Normally a query is treated as schema-aware
148
		/// only if it contains one or more "import schema" declarations. 
149
		/// </summary>
150
		/// <remarks>
151
		/// <para>If the query is not schema-aware, then all input documents must be untyped 
152
		/// (or <c>xs:anyType</c>), and validation of temporary nodes is disallowed
153
        /// (though validation of the final result tree is permitted). Setting the argument to true
154
		/// means that schema-aware code will be compiled regardless.</para>
155
		/// </remarks>
156

    
157
        public Boolean SchemaAware
158
        {
159
            get
160
            {
161
                return compiler.isSchemaAware();
162
            }
163
            set
164
            {
165
                compiler.setSchemaAware(value);
166
            }
167
        }
168

    
169
        /// <summary>
170
        /// This property indicates whether XQuery Update syntax is accepted. The default
171
        /// value is false. This property must be set to true before compiling a query that
172
        /// uses update syntax.
173
        /// </summary>
174
        /// <remarks>
175
        /// <para>This propery must be set to true before any query can be compiled
176
        /// that uses updating syntax. This applies even if the query is not actually an updating
177
        /// query (for example, a copy-modify expression). XQuery Update syntax is accepted
178
        /// only by Saxon-EE. Non-updating queries are accepted regardless of the value of this
179
        /// property.</para>
180
		/// </remarks>
181

    
182

    
183
        public bool UpdatingEnabled
184
        {
185
            get { return compiler.isUpdatingEnabled(); }
186
            set { compiler.setUpdatingEnabled(value); }
187
        }
188

    
189
        /// <summary>
190
        /// This property indicates which version of XQuery language syntax is accepted. In this version
191
        /// of Saxon the version is always "3.1"; any attempt to set a different value is ignored.
192
        /// </summary>
193

    
194
        public string XQueryLanguageVersion
195
        {
196
			get { 
197
				return "3.1";
198
			}
199
            set {}
200
        }
201

    
202

    
203
        /// <summary>
204
        /// A user-supplied <c>IQueryResolver</c> used to resolve location hints appearing in an
205
        /// <c>import module</c> declaration.
206
        /// </summary>
207
        /// <remarks>
208
        /// <para>In the absence of a user-supplied <c>QueryResolver</c>, an <c>import module</c> declaration
209
        /// is interpreted as follows. First, if the module URI identifies an already loaded module, that module
210
        /// is used and the location hints are ignored. Otherwise, each URI listed in the location hints is
211
        /// resolved using the <c>XmlResolver</c> registered with the <c>Processor</c>.</para>
212
        /// </remarks>
213

    
214
        public IQueryResolver QueryResolver
215
        {
216
            get { return moduleResolver; }
217
            set
218
            {
219
                moduleResolver = value;
220
                compiler.setModuleURIResolver(new DotNetModuleURIResolver(value));
221
            }
222
        }
223

    
224
        /// <summary>
225
        /// List of errors. The caller should supply an empty list before calling <c>Compile()</c>;
226
        /// the processor will then populate the list with error information obtained during
227
        /// the compilation. Each error will be included as an object of type <c>StaticError</c>.
228
        /// If no error list is supplied by the caller, error information will be written to
229
        /// the standard error stream.
230
        /// </summary>
231
        /// <remarks>
232
		/// By supplying a custom <c>List</c> with a user-written <c>add()</c> method, it is possible to
233
        /// intercept error conditions as they occur.
234
        /// </remarks>
235
        [Obsolete("IList<StaticError> ErrorList is deprecated, please use the methods SetErrorList and GetErrorList which hanldes IList<XmlProcessingError>.")]
236
        public IList<StaticError> ErrorList
237
        {
238
            set
239
            {
240
                errorGatherer = new ErrorReporterToStaticError(value);
241
                compiler.setErrorReporter(errorGatherer);
242
            }
243
            get
244
            {
245
                return errorList;
246
            }
247
        }
248

    
249

    
250
        /// <summary>Set the <c>ErrorReporter</c> to be used when validating instance documents as a user defined IErrorReporter.
251
        ///  Requirements here is IErrorReport implementation with a user-written <c>report()</c> method, it is possible to
252
        /// intercept error conditions as they occur.
253
        /// If this property is used then the ErrorList property and SetErrorList method is overriden.</summary>
254
        /// <remarks>The <c>IErrorReporter</c> to be used</remarks>
255
        public IErrorReporter ErrorReporter
256
        {
257
            set
258
            {
259
                errorReporter = null;
260
                compiler.setErrorReporter(new ErrorReporterWrapper(value));
261
            }
262

    
263
        }
264

    
265
        /// <summary>
266
        /// List of errors. The caller may supply an empty list before calling <c>Compile</c>;
267
        /// the processor will then populate the list with error information obtained during
268
        /// the query compilation. Each error will be included as an object of type <c>XmlProcessingError</c>.
269
        /// If no error list is supplied by the caller, error information will be written to
270
        /// the standard error stream.
271
        /// </summary>
272
		/// <remarks>
273
		/// <para>By supplying a custom <c>List</c> with a user-written <c>add()</c> method, it is possible to
274
		/// intercept error conditions as they occur.</para>
275
        /// <para>Note that this error list is used only for errors detected during the compilation
276
        /// of the stylesheet. It is not used for errors detected when executing the stylesheet.</para>
277
		/// </remarks>
278
		/// <param name="value">Supplied list.</param>
279
        public void SetErrorList(IList<XmlProcessingError> value)
280
        {
281
            errorReporter = new ErrorReporter(value);
282
            compiler.setErrorReporter(errorReporter);
283
        }
284

    
285
		/// <summary>
286
		/// Get list of errors as <code>IList&lt;XmlProcessingError&gt;</code>
287
		/// </summary>
288
        public IList<XmlProcessingError> GetErrorList()
289
        {
290
            if(errorReporter == null)
291
            {
292
                return new List<XmlProcessingError>();
293
            }
294
            return errorReporter.ErrorList;
295

    
296
        }
297

    
298
        /// <summary>
299
		/// Compile a query supplied as a <c>Stream</c>.
300
        /// </summary>
301
        /// <remarks>
302
        /// <para>The XQuery processor attempts to deduce the encoding of the query
303
        /// by looking for a byte-order-mark, or if none is present, by looking
304
        /// for the encoding declaration in the XQuery version declaration.
305
        /// For this to work, the stream must have the <c>CanSeek</c> property.
306
        /// If no encoding information is present, UTF-8 is assumed.</para>
307
        /// <para>The base URI of the query is set to the value of the <c>BaseUri</c>
308
        /// property. If this has not been set, then the base URI will be undefined, which
309
        /// means that any use of an expression that depends on the base URI will cause
310
        /// an error.</para>
311
        /// </remarks>
312
        /// <example>
313
        /// <code>
314
        /// XQueryExecutable q = compiler.Compile(new FileStream("input.xq", FileMode.Open, FileAccess.Read));
315
        /// </code>
316
        /// </example>
317
        /// <param name="query">A stream containing the source text of the query</param>
318
        /// <returns>An <c>XQueryExecutable</c> which represents the compiled query object.
319
        /// The <c>XQueryExecutable</c> may be run as many times as required, in the same or a different
320
        /// thread. The <c>XQueryExecutable</c> is not affected by any changes made to the <c>XQueryCompiler</c>
321
        /// once it has been compiled.</returns>
322
        /// <exception cref="StaticError">Throws a <c>StaticError</c> if errors were detected
323
        /// during static analysis of the query. Details of the errors will be added as <c>StaticError</c>
324
        /// objects to the <c>ErrorList</c> if supplied; otherwise they will be written to the standard
325
        /// error stream. The exception that is returned is merely a summary indicating the
326
        /// status.</exception>
327

    
328
        public XQueryExecutable Compile(Stream query)
329
        {
330
            try
331
            {
332
                JXQueryExecutable exec = compiler.compile(new JDotNetInputStream(query));
333
                return new XQueryExecutable(exec);
334
            }
335
            catch (JSaxonApiException e)
336
            {
337
                throw new StaticError(e);
338
            }
339
        }
340

    
341
        /// <summary>
342
		/// Compile a query supplied as a <c>String</c>.
343
        /// </summary>
344
        /// <remarks>
345
        /// Using this method the query processor is provided with a string of Unicode
346
        /// characters, so no decoding is necessary. Any encoding information present in the
347
        /// version declaration is therefore ignored.
348
        /// </remarks>
349
        /// <example>
350
        /// <code>
351
        /// XQueryExecutable q = compiler.Compile("distinct-values(//*/node-name()");
352
        /// </code>
353
        /// </example>
354
        /// <param name="query">A string containing the source text of the query</param>
355
        /// <returns>An <c>XQueryExecutable</c> which represents the compiled query object.
356
        /// The <c>XQueryExecutable</c> may be run as many times as required, in the same or a different
357
        /// thread. The <c>XQueryExecutable</c> is not affected by any changes made to the <c>XQueryCompiler</c>
358
        /// once it has been compiled.</returns>
359
        /// <exception cref="StaticError">Throws a <c>StaticError</c> if errors were detected
360
        /// during static analysis of the query. Details of the errors will be added as <c>StaticError</c>
361
        /// objects to the <c>ErrorList</c> if supplied; otherwise they will be written to the standard
362
        /// error stream. The exception that is returned is merely a summary indicating the
363
        /// status.</exception>        
364

    
365
        public XQueryExecutable Compile(String query)
366
        {
367
            try
368
            {
369
                JXQueryExecutable exec = compiler.compile(query);
370
                return new XQueryExecutable(exec);
371
            }
372
            catch (JSaxonApiException e)
373
            {
374
                throw new StaticError(e);
375
            }
376
        }
377

    
378
        /// <summary>
379
        /// Escape hatch to the underlying Java implementation
380
        /// </summary>
381

    
382
        public JXQueryCompiler Implementation
383
        {
384
            get { return compiler; }
385
        }
386

    
387

    
388
		/// <summary>
389
		/// Request fast compilation. Fast compilation will generally be achieved at the expense of run-time performance
390
		/// and quality of diagnostics. Fast compilation is a good trade-off if (a) the expression is known to be correct,
391
		/// and (b) once compiled, the expression is only executed once against a document of modest size.
392
		/// </summary>
393
		/// <remarks>
394
		/// <para><i>The current implementation is equivalent to switching off all optimizations. Setting this option, however,
395
		/// indicates an intent rather than a mechanism, and the implementation details may change in future to reflect
396
		/// the intent.</i></para>
397
		/// <para>Set to true to request fast compilation; set to false to revert to the optimization options
398
		/// defined in the Configuration.</para>
399
		/// </remarks>
400

    
401
		public bool FastCompliation
402
        {
403

    
404
            set { compiler.setFastCompilation(value); }
405
            get { return compiler.isFastCompilation(); }
406
        }
407
    }
408

    
409

    
410

    
411
    /// <summary>
412
    /// An <c>XQueryExecutable</c> represents the compiled form of a query. To execute the query,
413
    /// it must first be loaded to form an <c>XQueryEvaluator</c>.
414
    /// </summary>
415
    /// <remarks>
416
    /// <para>An <c>XQueryExecutable</c> is immutable, and therefore thread-safe. It is simplest to
417
    /// load a new <c>XQueryEvaluator</c> each time the query is to be run. However, the 
418
    /// <c>XQueryEvaluator</c> is serially reusable within a single thread.</para>
419
    /// <para>An <c>XQueryExecutable</c> is created by using one of the <c>Compile</c>
420
    /// methods on the <c>XQueryCompiler</c> class.</para>
421
    /// </remarks>    
422

    
423
    [Serializable]
424
    public class XQueryExecutable
425
    {
426

    
427
        private JXQueryExecutable executable;
428

    
429
        // internal constructor
430

    
431
        internal XQueryExecutable(JXQueryExecutable exec)
432
        {
433
            this.executable = exec;
434
        }
435

    
436
        /// <summary>Ask whether this is an updating query (that is, one that returns a pending
437
        /// update list rather than a conventional value).</summary>
438

    
439
        public bool IsUpdateQuery
440
        {
441
            get { return executable.isUpdateQuery(); }
442
        }
443
        
444
        /// <summary>Escape-hatch method to get the underlying Saxon implementation object if required.
445
        /// This provides access to methods that may not be stable from release to release.</summary>
446

    
447
		public JXQueryExecutable getUnderlyingCompiledQuery(){
448
			return executable;
449
		}
450

    
451
        /// <summary>
452
        /// Load the query to prepare it for execution.
453
        /// </summary>
454
        /// <returns>
455
        /// An <c>XQueryEvaluator</c>. The returned <c>XQueryEvaluator</c> can be used to
456
        /// set up the dynamic context for query evaluation, and to run the query.
457
        /// </returns>
458

    
459
        public XQueryEvaluator Load()
460
        {
461
            return  new XQueryEvaluator(executable.load());
462
        }
463
    }
464

    
465
    /// <summary inherits="IEnumerable">
466
    /// An <c>XQueryEvaluator</c> represents a compiled and loaded query ready for execution.
467
    /// The <c>XQueryEvaluator</c> holds details of the dynamic evaluation context for the query.
468
    /// </summary>
469
    /// <remarks>
470
    /// <para>An <c>XQueryEvaluator</c> must not be used concurrently in multiple threads. It is safe,
471
    /// however, to reuse the object within a single thread to run the same query several times.
472
    /// Running the query does not change the context that has been established.</para>
473
    /// <para>An <c>XQueryEvaluator</c> is always constructed by running the <c>Load</c> method of
474
    /// an <c>XQueryExecutable</c>.</para>
475
    /// </remarks>     
476

    
477
    [Serializable]
478
    public class XQueryEvaluator : IEnumerable
479
    {
480
        private JXQueryEvaluator evaluator;
481
        private StandardLogger traceFunctionDestination;
482

    
483
        //private JXQueryExpression exp;
484
        //private JDynamicQueryContext context;
485
        //private JController controller;
486
        //private StandardLogger traceFunctionDestination;
487

    
488
        // internal constructor
489

    
490
        internal XQueryEvaluator(JXQueryEvaluator eval)
491
        {
492
            this.evaluator = eval;
493
            //this.exp = exp;
494
            //this.context =
495
			//	new JDynamicQueryContext(exp.getConfiguration());
496
        }
497

    
498
        /// <summary>
499
        /// The context item for the query.
500
        /// </summary>
501
        /// <remarks> This may be a node, an atomic value, or a function item such as a map or array.
502
        /// Most commonly it will be a document node, which might be constructed
503
        /// using a <c>DocumentBuilder</c> created from the <c>Processor</c> object.
504
        /// </remarks>
505

    
506
        public XdmItem ContextItem
507
        {
508
            get { return (XdmItem)XdmValue.Wrap(evaluator.getContextItem().getUnderlyingValue()); }
509
            set { evaluator.setContextItem((net.sf.saxon.s9api.XdmItem)XdmValue.FromGroundedValueToJXdmValue(value.value)); }
510
        }
511

    
512
        /// <summary>
513
        /// The <c>SchemaValidationMode</c> to be used in this query, especially for documents
514
        /// loaded using the <c>doc()</c>, <c>document()</c>, or <c>collection()</c> functions.
515
        /// </summary>
516
        /// <remarks>
517
        /// This does not affect any document supplied as the context item for the query, or as the values
518
        /// of external variables.
519
        /// </remarks>
520

    
521
        public SchemaValidationMode SchemaValidationMode
522
        {
523
            get
524
            {
525
                switch (evaluator.getUnderlyingQueryContext().getSchemaValidationMode())
526
                {
527
                    case JValidation.STRICT:
528
                        return SchemaValidationMode.Strict;
529
                    case JValidation.LAX:
530
                        return SchemaValidationMode.Lax;
531
                    case JValidation.STRIP:
532
                        return SchemaValidationMode.None;
533
                    case JValidation.PRESERVE:
534
                        return SchemaValidationMode.Preserve;
535
                    case JValidation.DEFAULT:
536
                    default:
537
                        return SchemaValidationMode.Unspecified;
538
                }
539
            }
540

    
541
            set
542
            {
543
                JDynamicQueryContext context = evaluator.getUnderlyingQueryContext();
544
                switch (value)
545
                {
546
                    case SchemaValidationMode.Strict:
547
                        context.setSchemaValidationMode(JValidation.STRICT);
548
                        break;
549
                    case SchemaValidationMode.Lax:
550
                        context.setSchemaValidationMode(JValidation.LAX);
551
                        break;
552
                    case SchemaValidationMode.None:
553
                        context.setSchemaValidationMode(JValidation.STRIP);
554
                        break;
555
                    case SchemaValidationMode.Preserve:
556
                        context.setSchemaValidationMode(JValidation.PRESERVE);
557
                        break;
558
                    case SchemaValidationMode.Unspecified:
559
                    default:
560
                        context.setSchemaValidationMode(JValidation.DEFAULT);
561
                        break;
562
                }
563
            }
564
        }
565

    
566
        /// <summary>
567
        /// The <code>XmlResolver</code> to be used at run-time to resolve and dereference URIs
568
        /// supplied to the <c>doc()</c> function.
569
        /// </summary>
570

    
571
        public XmlResolver InputXmlResolver
572
        {
573
            get
574
            {
575
                return ((JDotNetURIResolver)evaluator.getURIResolver()).getXmlResolver();
576
            }
577
            set
578
            {
579
                evaluator.setURIResolver(new JDotNetURIResolver(value));
580
            }
581
        }
582

    
583
        /// <summary>
584
        /// Set the value of an external variable declared in the query.
585
        /// </summary>
586
        /// <param name="name">The name of the external variable, expressed
587
		/// as a <c>QName</c>. If an external variable of this name has been declared in the
588
        /// query prolog, the given value will be assigned to the variable. If the
589
        /// variable has not been declared, calling this method has no effect (it is
590
        /// not an error).</param>
591
        /// <param name="value">The value to be given to the external variable.
592
        /// If the variable declaration defines a required type for the variable, then
593
        /// this value must match the required type: no conversions are applied.</param>
594

    
595
        public void SetExternalVariable(QName name, XdmValue value)
596
        {
597
            evaluator.setExternalVariable(new JXQName(name.ToStructuredQName()), value == null ? null : XdmValue.FromGroundedValueToJXdmValue(value.value));
598
        }
599

    
600
        /// <summary>
601
        /// Destination for output of messages produced using the <c>trace()</c> function. 
602
        /// </summary>
603
		/// <remarks>
604
		/// <para>If no specific destination is supplied by the caller, message information will be written to
605
		/// the standard error stream.</para>
606
        /// <para>The supplied destination is ignored if a <c>TraceListener</c> is in use.</para>
607
        /// </remarks>
608

    
609
        public StandardLogger TraceFunctionDestination
610
        {
611
            set
612
            {
613
				traceFunctionDestination = value;
614
				evaluator.setTraceFunctionDestination(value);
615
            }
616
            get
617
            {
618
                return traceFunctionDestination;
619
            }
620
        }
621

    
622

    
623
        /// <summary>
624
        /// Evaluate the query, returning the result as an <c>XdmValue</c> (that is,
625
        /// a sequence of nodes and/or atomic values).
626
        /// </summary>
627
        /// <returns>
628
        /// An <c>XdmValue</c> representing the results of the query
629
        /// </returns>
630
		/// <exception cref="DynamicError">Throws a <c>DynamicError</c> if any run-time failure
631
        /// occurs while evaluating the query.</exception>
632

    
633
        public XdmValue Evaluate()
634
        {
635
            try
636
            {
637
                JXdmValue value = evaluator.evaluate();
638
                return XdmValue.Wrap(value.getUnderlyingValue());
639
            }
640
            catch (JSaxonApiException err)
641
            {
642
                throw new DynamicError(err);
643
            }
644
        }
645

    
646
        /// <summary>
647
        /// Evaluate the query, returning the result as an <c>XdmItem</c> (that is,
648
        /// a single node or atomic value).
649
        /// </summary>
650
        /// <returns>
651
        /// An <c>XdmItem</c> representing the result of the query, or null if the query
652
        /// returns an empty sequence. If the query returns a sequence of more than one item,
653
        /// any items after the first are ignored.
654
        /// </returns>
655
		/// <exception cref="DynamicError">Throws a <c>DynamicError</c> if any run-time failure
656
        /// occurs while evaluating the expression.</exception>
657

    
658
        public XdmItem EvaluateSingle()
659
        {
660
            try
661
            {
662
                return (XdmItem)XdmValue.Wrap(evaluator.evaluateSingle().getUnderlyingValue());
663
            }
664
            catch (JSaxonApiException err)
665
            {
666
                throw new DynamicError(err);
667
            }
668
        }
669

    
670
        /// <summary>
671
        /// Evaluate the query, returning the result as an <c>IEnumerator</c> (that is,
672
        /// an enumerator over a sequence of nodes and/or atomic values).
673
        /// </summary>
674
        /// <returns>
675
        /// An enumerator over the sequence that represents the results of the query.
676
        /// Each object in this sequence will be an instance of <c>XdmItem</c>. Note
677
        /// that the query may be evaluated lazily, which means that a successful response
678
        /// from this method does not imply that the query has executed successfully: failures
679
        /// may be reported later while retrieving items from the iterator. 
680
        /// </returns>
681
		/// <exception cref="DynamicError">Throws a <c>DynamicError</c> if any run-time failure
682
        /// occurs while evaluating the expression.</exception>
683

    
684
        public IEnumerator GetEnumerator()
685
        {
686
            try
687
            {
688
                return new SequenceEnumerator<XdmItem>(evaluator.iterator());
689
            }
690
            catch (net.sf.saxon.s9api.SaxonApiUncheckedException err)
691
            {
692
                throw new DynamicError(JXPathException.makeXPathException(err));
693
            }
694
        }
695

    
696
        
697

    
698
        /// <summary>
699
        /// Evaluate the query, sending the result to a specified destination.
700
        /// </summary>
701
        /// <param name="destination">
702
        /// The destination for the results of the query. The class <c>XmlDestination</c>
703
        /// is an abstraction that allows a number of different kinds of destination
704
        /// to be specified.
705
        /// </param>
706
		/// <exception cref="DynamicError">Throws a <c>DynamicError</c> if any run-time failure
707
        /// occurs while evaluating the expression.</exception>
708

    
709
        public void Run(XmlDestination destination)
710
        {
711
            try
712
            {
713
                evaluator.setDestination(destination.GetUnderlyingDestination());
714
                evaluator.run();
715
    
716
            }
717
            catch (JSaxonApiException err)
718
            {
719
                throw new DynamicError(err);
720
            }
721
         
722
        }
723

    
724
        /// <summary>
725
        /// Execute an updating query.
726
        /// </summary>
727
        /// <returns>An array containing the root nodes of documents that have been
728
        /// updated by the query.</returns>
729
		/// <exception cref="DynamicError">Throws a <c>DynamicError</c> if any run-time failure
730
        /// occurs while evaluating the expression, or if the expression is not an
731
        /// updating query.</exception>
732

    
733
        public XdmNode[] RunUpdate()
734
        {
735
            try
736
            {
737

    
738
                evaluator.run();
739
                java.util.Iterator updatedDocsIter = evaluator.getUpdatedDocuments();
740
                List<XdmNode> resultList = new List<XdmNode>();
741

    
742
                for (; updatedDocsIter.hasNext(); )
743

    
744
                {
745
                    resultList.Add((XdmNode)XdmValue.Wrap( ((net.sf.saxon.s9api.XdmNode)updatedDocsIter.next()).getUnderlyingNode()));
746
                }
747
                XdmNode[] result = resultList.ToArray();
748
                return result;
749
            }
750
            catch (JSaxonApiException err)
751
            {
752
                throw new DynamicError(err);
753
            }
754
        }
755

    
756
    /// <summary>
757
    /// Call a global user-defined function in the compiled query.
758
    /// </summary>
759
    /// <remarks>
760
    /// If this is called more than once (to evaluate the same function repeatedly with different arguments,
761
    /// or to evaluate different functions) then the sequence of evaluations uses the same values of global
762
    /// variables including external variables (query parameters); the effect of any changes made to query parameters
763
    /// between calls is undefined.
764
    /// </remarks>
765
    /// <param name="function">
766
    /// The name of the function to be called
767
    /// </param>
768
    /// <param name="arguments">
769
    /// The values of the arguments to be supplied to the function. These
770
    /// must be of the correct type as defined in the function signature (there is no automatic
771
    /// conversion to the required type).
772
    /// </param>
773
    /// <exception cref="ArgumentException">If no function has been defined with the given name and arity
774
    /// or if any of the arguments does not match its required type according to the function
775
    /// signature.</exception>
776
    /// <exception cref="DynamicError">If a dynamic error occurs in evaluating the function.
777
    /// </exception>
778

    
779
    public XdmValue CallFunction(QName function, XdmValue[] arguments) {    
780
        try {
781
            JXdmValue[] vr = new JXdmValue[arguments.Length];
782
            for (int i=0; i<arguments.Length; i++) {
783
                vr[i] = XdmValue.FromGroundedValueToJXdmValue(arguments[i].value);
784
            }
785
            JSequence result = evaluator.callFunction(function.UnderlyingQName(), vr).getUnderlyingValue();
786
            return XdmValue.Wrap(result);
787
        } catch (JSaxonApiException e) {
788
            throw new DynamicError(e);
789
        }
790
    }
791

    
792

    
793

    
794
        /// <summary>
795
        /// Escape hatch to the <c>net.sf.saxon.query.DynamicQueryContext</c> object in the underlying Java implementation
796
        /// </summary>
797

    
798
        public JXQueryEvaluator Implementation
799
        {
800
            get { return evaluator; }
801
        }
802

    
803
    }
804

    
805

    
806
    /// <summary>
807
    /// Interface defining a user-supplied class used to retrieve XQuery library modules listed
808
    /// in an <c>import module</c> declaration in the query prolog.
809
    /// </summary>
810

    
811

    
812
    public interface IQueryResolver
813
    {
814

    
815
        /// <summary>
816
        /// Given a module URI and a set of location hints, return a set of query modules.
817
        /// </summary>
818
        /// <param name="moduleUri">The URI of the required library module as written in the
819
        /// <c>import module</c> declaration</param>
820
        /// <param name="baseUri">The base URI of the module containing the <c>import module</c>
821
        /// declaration</param>
822
        /// <param name="locationHints">The sequence of URIs (if any) listed as location hints
823
        /// in the <c>import module</c> declaration in the query prolog.</param>
824
        /// <returns>A set of absolute URIs identifying the query modules to be loaded. There is no requirement
825
        /// that these correspond one-to-one with the URIs defined in the <c>locationHints</c>. The 
826
        /// returned URIs will be dereferenced by calling the <c>GetEntity</c> method.
827
        /// </returns>
828

    
829
		/**public**/ Uri[] GetModules(String moduleUri, Uri baseUri, String[] locationHints);
830

    
831
        /// <summary>
832
        /// Dereference a URI returned by <c>GetModules</c> to retrieve a <c>Stream</c> containing
833
        /// the actual query text.
834
        /// </summary>
835
        /// <param name="absoluteUri">A URI returned by the <code>GetModules</code> method.</param>
836
        /// <returns>Either a <c>Stream</c> or a <c>String</c> containing the query text. 
837
        /// The supplied URI will be used as the base URI of the query module.</returns>
838

    
839
		/**public**/ Object GetEntity(Uri absoluteUri);
840

    
841
    }
842

    
843
    /// <summary>
844
	/// Internal class that wraps a (.NET) <c>IQueryResolver</c> to create a (Java) <c>ModuleURIResolver</c>.
845
	/// <para>A <c>ModuleURIResolver</c> is used when resolving references to
846
	/// query modules. It takes as input a URI that identifies the module to be loaded, and a set of
847
	/// location hints, and returns one or more <c>StreamSource</c> obects containing the queries
848
	/// to be imported.</para>
849
    /// </summary>
850

    
851
    internal class DotNetModuleURIResolver : net.sf.saxon.lib.ModuleURIResolver
852
    {
853

    
854
        private IQueryResolver resolver;
855

    
856
		/// <summary>
857
		/// Initializes a new instance of the <see cref="Saxon.Api.DotNetModuleURIResolver"/> class.
858
		/// </summary>
859
		/// <param name="resolver">Resolver.</param>
860
        public DotNetModuleURIResolver(IQueryResolver resolver)
861
        {
862
            this.resolver = resolver;
863
        }
864

    
865

    
866
		/// <summary>
867
		/// Resolve a module URI and associated location hints.
868
		/// </summary>
869
		/// <param name="moduleURI">ModuleURI. The module namespace URI of the module to be imported; or null when
870
		/// loading a non-library module.</param>
871
		/// <param name="baseURI">BaseURI. The base URI of the module containing the "import module" declaration;
872
		/// null if no base URI is known</param>
873
		/// <param name="locations">Locations. The set of URIs specified in the "at" clause of "import module",
874
		/// which serve as location hints for the module</param>
875
		/// <returns>an array of StreamSource objects each identifying the contents of a module to be
876
		/// imported. Each StreamSource must contain a
877
		/// non-null absolute System ID which will be used as the base URI of the imported module,
878
		/// and either an InputSource or a Reader representing the text of the module. The method
879
		/// may also return null, in which case the system attempts to resolve the URI using the
880
		/// standard module URI resolver.</returns>
881
        public JStreamSource[] resolve(String moduleURI, String baseURI, String[] locations)
882
        {
883
            Uri baseU = (baseURI == null ? null : new Uri(baseURI));
884
            Uri[] modules = resolver.GetModules(moduleURI, baseU, locations);
885
            JStreamSource[] ss = new JStreamSource[modules.Length];
886
            for (int i = 0; i < ss.Length; i++)
887
            {
888
                ss[i] = new JStreamSource();
889
                ss[i].setSystemId(modules[i].ToString());
890
                Object query = resolver.GetEntity(modules[i]);
891
                if (query is Stream)
892
                {
893
                    ss[i].setInputStream(new JDotNetInputStream((Stream)query));
894
                }
895
                else if (query is String)
896
                {
897
                    ss[i].setReader(new JDotNetReader(new StringReader((String)query)));
898
                }
899
                else
900
                {
901
                    throw new ArgumentException("Invalid response from GetEntity()");
902
                }
903
            }
904
            return ss;
905
        }
906
    }
907

    
908

    
909

    
910

    
911

    
912

    
913
}
914

    
915

    
916
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
917
// Copyright (c) 2020 Saxonica Limited.
918
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
919
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
920
// This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0.
921
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
(10-10/11)