Project

Profile

Help

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

he / latest9.9 / hen / csource / api / Saxon.Api / XQuery.cs @ a2e6e9df

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 JXQueryCompiler compiler;
53

    
54
        // internal constructor: the public interface is a factory method
55
        // on the Processor object
56

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

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

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

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

    
100
        public void DeclareNamespace(String prefix, String uri)
101
        {
102
            compiler.declareNamespace(prefix, uri);
103
        }
104

    
105

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

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

    
121
        public XdmItemType ContextItemType
122
        {
123
            get { return XdmItemType.MakeXdmItemType(compiler.getRequiredContextItemType().getUnderlyingItemType()); }
124
            set { compiler.setRequiredContextItemType(value.Unwrap()); }
125
        }
126

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

    
134

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

    
141

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

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

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

    
179

    
180
        public bool UpdatingEnabled
181
        {
182
            get { return compiler.isUpdatingEnabled(); }
183
            set { compiler.setUpdatingEnabled(value); }
184
        }
185

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

    
191
        public string XQueryLanguageVersion
192
        {
193
			get { 
194
				return "3.1";
195
			}
196
            set {}
197
        }
198

    
199

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

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

    
221
        /// <summary>
222
        /// List of errors. The caller should supply an empty list before calling <c>Compile()</c>;
223
        /// the processor will then populate the list with error information obtained during
224
        /// the compilation. Each error will be included as an object of type <c>StaticError</c>.
225
        /// If no error list is supplied by the caller, error information will be written to
226
        /// the standard error stream.
227
        /// </summary>
228
        /// <remarks>
229
		/// By supplying a custom <c>List</c> with a user-written <c>add()</c> method, it is possible to
230
        /// intercept error conditions as they occur.
231
        /// </remarks>
232

    
233
        public IList<StaticError> ErrorList
234
        {
235
            set
236
            {
237
                errorList = value;
238
                compiler.setErrorListener(new ErrorGatherer(value));
239
            }
240
            get
241
            {
242
                return errorList;
243
            }
244
        }
245

    
246
        /// <summary>
247
		/// Compile a query supplied as a <c>Stream</c>.
248
        /// </summary>
249
        /// <remarks>
250
        /// <para>The XQuery processor attempts to deduce the encoding of the query
251
        /// by looking for a byte-order-mark, or if none is present, by looking
252
        /// for the encoding declaration in the XQuery version declaration.
253
        /// For this to work, the stream must have the <c>CanSeek</c> property.
254
        /// If no encoding information is present, UTF-8 is assumed.</para>
255
        /// <para>The base URI of the query is set to the value of the <c>BaseUri</c>
256
        /// property. If this has not been set, then the base URI will be undefined, which
257
        /// means that any use of an expression that depends on the base URI will cause
258
        /// an error.</para>
259
        /// </remarks>
260
        /// <example>
261
        /// <code>
262
        /// XQueryExecutable q = compiler.Compile(new FileStream("input.xq", FileMode.Open, FileAccess.Read));
263
        /// </code>
264
        /// </example>
265
        /// <param name="query">A stream containing the source text of the query</param>
266
        /// <returns>An <c>XQueryExecutable</c> which represents the compiled query object.
267
        /// The <c>XQueryExecutable</c> may be run as many times as required, in the same or a different
268
        /// thread. The <c>XQueryExecutable</c> is not affected by any changes made to the <c>XQueryCompiler</c>
269
        /// once it has been compiled.</returns>
270
        /// <exception cref="StaticError">Throws a <c>StaticError</c> if errors were detected
271
        /// during static analysis of the query. Details of the errors will be added as <c>StaticError</c>
272
        /// objects to the <c>ErrorList</c> if supplied; otherwise they will be written to the standard
273
        /// error stream. The exception that is returned is merely a summary indicating the
274
        /// status.</exception>
275

    
276
        public XQueryExecutable Compile(Stream query)
277
        {
278
            try
279
            {
280
                JXQueryExecutable exec = compiler.compile(new JDotNetInputStream(query));
281
                return new XQueryExecutable(exec);
282
            }
283
            catch (JSaxonApiException e)
284
            {
285
                throw new StaticError(e);
286
            }
287
        }
288

    
289
        /// <summary>
290
		/// Compile a query supplied as a <c>String</c>.
291
        /// </summary>
292
        /// <remarks>
293
        /// Using this method the query processor is provided with a string of Unicode
294
        /// characters, so no decoding is necessary. Any encoding information present in the
295
        /// version declaration is therefore ignored.
296
        /// </remarks>
297
        /// <example>
298
        /// <code>
299
        /// XQueryExecutable q = compiler.Compile("distinct-values(//*/node-name()");
300
        /// </code>
301
        /// </example>
302
        /// <param name="query">A string containing the source text of the query</param>
303
        /// <returns>An <c>XQueryExecutable</c> which represents the compiled query object.
304
        /// The <c>XQueryExecutable</c> may be run as many times as required, in the same or a different
305
        /// thread. The <c>XQueryExecutable</c> is not affected by any changes made to the <c>XQueryCompiler</c>
306
        /// once it has been compiled.</returns>
307
        /// <exception cref="StaticError">Throws a <c>StaticError</c> if errors were detected
308
        /// during static analysis of the query. Details of the errors will be added as <c>StaticError</c>
309
        /// objects to the <c>ErrorList</c> if supplied; otherwise they will be written to the standard
310
        /// error stream. The exception that is returned is merely a summary indicating the
311
        /// status.</exception>        
312

    
313
        public XQueryExecutable Compile(String query)
314
        {
315
            try
316
            {
317
                JXQueryExecutable exec = compiler.compile(query);
318
                return new XQueryExecutable(exec);
319
            }
320
            catch (JSaxonApiException e)
321
            {
322
                throw new StaticError(e);
323
            }
324
        }
325

    
326
        /// <summary>
327
        /// Escape hatch to the underlying Java implementation
328
        /// </summary>
329

    
330
        public JXQueryCompiler Implementation
331
        {
332
            get { return compiler; }
333
        }
334

    
335

    
336
		/// <summary>
337
		/// Request fast compilation. Fast compilation will generally be achieved at the expense of run-time performance
338
		/// and quality of diagnostics. Fast compilation is a good trade-off if (a) the expression is known to be correct,
339
		/// and (b) once compiled, the expression is only executed once against a document of modest size.
340
		/// </summary>
341
		/// <remarks>
342
		/// <para><i>The current implementation is equivalent to switching off all optimizations. Setting this option, however,
343
		/// indicates an intent rather than a mechanism, and the implementation details may change in future to reflect
344
		/// the intent.</i></para>
345
		/// <para>Set to true to request fast compilation; set to false to revert to the optimization options
346
		/// defined in the Configuration.</para>
347
		/// </remarks>
348

    
349
		public bool FastCompliation
350
        {
351

    
352
            set { compiler.setFastCompilation(value); }
353
            get { return compiler.isFastCompilation(); }
354
        }
355
    }
356

    
357

    
358

    
359
    /// <summary>
360
    /// An <c>XQueryExecutable</c> represents the compiled form of a query. To execute the query,
361
    /// it must first be loaded to form an <c>XQueryEvaluator</c>.
362
    /// </summary>
363
    /// <remarks>
364
    /// <para>An <c>XQueryExecutable</c> is immutable, and therefore thread-safe. It is simplest to
365
    /// load a new <c>XQueryEvaluator</c> each time the query is to be run. However, the 
366
    /// <c>XQueryEvaluator</c> is serially reusable within a single thread.</para>
367
    /// <para>An <c>XQueryExecutable</c> is created by using one of the <c>Compile</c>
368
    /// methods on the <c>XQueryCompiler</c> class.</para>
369
    /// </remarks>    
370

    
371
    [Serializable]
372
    public class XQueryExecutable
373
    {
374

    
375
        private JXQueryExecutable executable;
376

    
377
        // internal constructor
378

    
379
        internal XQueryExecutable(JXQueryExecutable exec)
380
        {
381
            this.executable = exec;
382
        }
383

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

    
387
        public bool IsUpdateQuery
388
        {
389
            get { return executable.isUpdateQuery(); }
390
        }
391
        
392
        /// <summary>Escape-hatch method to get the underlying Saxon implementation object if required.
393
        /// This provides access to methods that may not be stable from release to release.</summary>
394

    
395
		public JXQueryExecutable getUnderlyingCompiledQuery(){
396
			return executable;
397
		}
398

    
399
        /// <summary>
400
        /// Load the query to prepare it for execution.
401
        /// </summary>
402
        /// <returns>
403
        /// An <c>XQueryEvaluator</c>. The returned <c>XQueryEvaluator</c> can be used to
404
        /// set up the dynamic context for query evaluation, and to run the query.
405
        /// </returns>
406

    
407
        public XQueryEvaluator Load()
408
        {
409
            return  new XQueryEvaluator(executable.load());
410
        }
411
    }
412

    
413
    /// <summary inherits="IEnumerable">
414
    /// An <c>XQueryEvaluator</c> represents a compiled and loaded query ready for execution.
415
    /// The <c>XQueryEvaluator</c> holds details of the dynamic evaluation context for the query.
416
    /// </summary>
417
    /// <remarks>
418
    /// <para>An <c>XQueryEvaluator</c> must not be used concurrently in multiple threads. It is safe,
419
    /// however, to reuse the object within a single thread to run the same query several times.
420
    /// Running the query does not change the context that has been established.</para>
421
    /// <para>An <c>XQueryEvaluator</c> is always constructed by running the <c>Load</c> method of
422
    /// an <c>XQueryExecutable</c>.</para>
423
    /// </remarks>     
424

    
425
    [Serializable]
426
    public class XQueryEvaluator : IEnumerable
427
    {
428
        private JXQueryEvaluator evaluator;
429
        private StandardLogger traceFunctionDestination;
430

    
431
        //private JXQueryExpression exp;
432
        //private JDynamicQueryContext context;
433
        //private JController controller;
434
        //private StandardLogger traceFunctionDestination;
435

    
436
        // internal constructor
437

    
438
        internal XQueryEvaluator(JXQueryEvaluator eval)
439
        {
440
            this.evaluator = eval;
441
            //this.exp = exp;
442
            //this.context =
443
			//	new JDynamicQueryContext(exp.getConfiguration());
444
        }
445

    
446
        /// <summary>
447
        /// The context item for the query.
448
        /// </summary>
449
        /// <remarks> This may be a node, an atomic value, or a function item such as a map or array.
450
        /// Most commonly it will be a document node, which might be constructed
451
        /// using a <c>DocumentBuilder</c> created from the <c>Processor</c> object.
452
        /// </remarks>
453

    
454
        public XdmItem ContextItem
455
        {
456
            get { return (XdmItem)XdmValue.Wrap(evaluator.getContextItem().getUnderlyingValue()); }
457
            set { evaluator.setContextItem((net.sf.saxon.s9api.XdmItem)XdmValue.FromGroundedValueToJXdmValue(value.value)); }
458
        }
459

    
460
        /// <summary>
461
        /// The <c>SchemaValidationMode</c> to be used in this query, especially for documents
462
        /// loaded using the <c>doc()</c>, <c>document()</c>, or <c>collection()</c> functions.
463
        /// </summary>
464
        /// <remarks>
465
        /// This does not affect any document supplied as the context item for the query, or as the values
466
        /// of external variables.
467
        /// </remarks>
468

    
469
        public SchemaValidationMode SchemaValidationMode
470
        {
471
            get
472
            {
473
                switch (evaluator.getUnderlyingQueryContext().getSchemaValidationMode())
474
                {
475
                    case JValidation.STRICT:
476
                        return SchemaValidationMode.Strict;
477
                    case JValidation.LAX:
478
                        return SchemaValidationMode.Lax;
479
                    case JValidation.STRIP:
480
                        return SchemaValidationMode.None;
481
                    case JValidation.PRESERVE:
482
                        return SchemaValidationMode.Preserve;
483
                    case JValidation.DEFAULT:
484
                    default:
485
                        return SchemaValidationMode.Unspecified;
486
                }
487
            }
488

    
489
            set
490
            {
491
                JDynamicQueryContext context = evaluator.getUnderlyingQueryContext();
492
                switch (value)
493
                {
494
                    case SchemaValidationMode.Strict:
495
                        context.setSchemaValidationMode(JValidation.STRICT);
496
                        break;
497
                    case SchemaValidationMode.Lax:
498
                        context.setSchemaValidationMode(JValidation.LAX);
499
                        break;
500
                    case SchemaValidationMode.None:
501
                        context.setSchemaValidationMode(JValidation.STRIP);
502
                        break;
503
                    case SchemaValidationMode.Preserve:
504
                        context.setSchemaValidationMode(JValidation.PRESERVE);
505
                        break;
506
                    case SchemaValidationMode.Unspecified:
507
                    default:
508
                        context.setSchemaValidationMode(JValidation.DEFAULT);
509
                        break;
510
                }
511
            }
512
        }
513

    
514
        /// <summary>
515
        /// The <code>XmlResolver</code> to be used at run-time to resolve and dereference URIs
516
        /// supplied to the <c>doc()</c> function.
517
        /// </summary>
518

    
519
        public XmlResolver InputXmlResolver
520
        {
521
            get
522
            {
523
                return ((JDotNetURIResolver)evaluator.getURIResolver()).getXmlResolver();
524
            }
525
            set
526
            {
527
                evaluator.setURIResolver(new JDotNetURIResolver(value));
528
            }
529
        }
530

    
531
        /// <summary>
532
        /// Set the value of an external variable declared in the query.
533
        /// </summary>
534
        /// <param name="name">The name of the external variable, expressed
535
		/// as a <c>QName</c>. If an external variable of this name has been declared in the
536
        /// query prolog, the given value will be assigned to the variable. If the
537
        /// variable has not been declared, calling this method has no effect (it is
538
        /// not an error).</param>
539
        /// <param name="value">The value to be given to the external variable.
540
        /// If the variable declaration defines a required type for the variable, then
541
        /// this value must match the required type: no conversions are applied.</param>
542

    
543
        public void SetExternalVariable(QName name, XdmValue value)
544
        {
545
            evaluator.setExternalVariable(new JXQName(name.ToStructuredQName()), value == null ? null : XdmValue.FromGroundedValueToJXdmValue(value.value));
546
        }
547

    
548
        /// <summary>
549
        /// Destination for output of messages produced using the <c>trace()</c> function. 
550
        /// </summary>
551
		/// <remarks>
552
		/// <para>If no specific destination is supplied by the caller, message information will be written to
553
		/// the standard error stream.</para>
554
        /// <para>The supplied destination is ignored if a <c>TraceListener</c> is in use.</para>
555
        /// </remarks>
556

    
557
        public StandardLogger TraceFunctionDestination
558
        {
559
            set
560
            {
561
				traceFunctionDestination = value;
562
				evaluator.setTraceFunctionDestination(value);
563
            }
564
            get
565
            {
566
                return traceFunctionDestination;
567
            }
568
        }
569

    
570

    
571
        /// <summary>
572
        /// Evaluate the query, returning the result as an <c>XdmValue</c> (that is,
573
        /// a sequence of nodes and/or atomic values).
574
        /// </summary>
575
        /// <returns>
576
        /// An <c>XdmValue</c> representing the results of the query
577
        /// </returns>
578
		/// <exception cref="DynamicError">Throws a <c>DynamicError</c> if any run-time failure
579
        /// occurs while evaluating the query.</exception>
580

    
581
        public XdmValue Evaluate()
582
        {
583
            try
584
            {
585
                JXdmValue value = evaluator.evaluate();
586
                return XdmValue.Wrap(value.getUnderlyingValue());
587
            }
588
            catch (JSaxonApiException err)
589
            {
590
                throw new DynamicError(err);
591
            }
592
        }
593

    
594
        /// <summary>
595
        /// Evaluate the query, returning the result as an <c>XdmItem</c> (that is,
596
        /// a single node or atomic value).
597
        /// </summary>
598
        /// <returns>
599
        /// An <c>XdmItem</c> representing the result of the query, or null if the query
600
        /// returns an empty sequence. If the query returns a sequence of more than one item,
601
        /// any items after the first are ignored.
602
        /// </returns>
603
		/// <exception cref="DynamicError">Throws a <c>DynamicError</c> if any run-time failure
604
        /// occurs while evaluating the expression.</exception>
605

    
606
        public XdmItem EvaluateSingle()
607
        {
608
            try
609
            {
610
                return (XdmItem)XdmValue.Wrap(evaluator.evaluateSingle().getUnderlyingValue());
611
            }
612
            catch (JSaxonApiException err)
613
            {
614
                throw new DynamicError(err);
615
            }
616
        }
617

    
618
        /// <summary>
619
        /// Evaluate the query, returning the result as an <c>IEnumerator</c> (that is,
620
        /// an enumerator over a sequence of nodes and/or atomic values).
621
        /// </summary>
622
        /// <returns>
623
        /// An enumerator over the sequence that represents the results of the query.
624
        /// Each object in this sequence will be an instance of <c>XdmItem</c>. Note
625
        /// that the query may be evaluated lazily, which means that a successful response
626
        /// from this method does not imply that the query has executed successfully: failures
627
        /// may be reported later while retrieving items from the iterator. 
628
        /// </returns>
629
		/// <exception cref="DynamicError">Throws a <c>DynamicError</c> if any run-time failure
630
        /// occurs while evaluating the expression.</exception>
631

    
632
        public IEnumerator GetEnumerator()
633
        {
634
            try
635
            {
636
                return new SequenceEnumerator<XdmItem>(evaluator.iterator());
637
            }
638
            catch (net.sf.saxon.s9api.SaxonApiUncheckedException err)
639
            {
640
                throw new DynamicError(JXPathException.makeXPathException(err));
641
            }
642
        }
643

    
644
        
645

    
646
        /// <summary>
647
        /// Evaluate the query, sending the result to a specified destination.
648
        /// </summary>
649
        /// <param name="destination">
650
        /// The destination for the results of the query. The class <c>XmlDestination</c>
651
        /// is an abstraction that allows a number of different kinds of destination
652
        /// to be specified.
653
        /// </param>
654
		/// <exception cref="DynamicError">Throws a <c>DynamicError</c> if any run-time failure
655
        /// occurs while evaluating the expression.</exception>
656

    
657
        public void Run(XmlDestination destination)
658
        {
659
            try
660
            {
661
                evaluator.setDestination(destination.GetUnderlyingDestination());
662
                evaluator.run();
663
    
664
            }
665
            catch (JSaxonApiException err)
666
            {
667
                throw new DynamicError(err);
668
            }
669
         
670
        }
671

    
672
        /// <summary>
673
        /// Execute an updating query.
674
        /// </summary>
675
        /// <returns>An array containing the root nodes of documents that have been
676
        /// updated by the query.</returns>
677
		/// <exception cref="DynamicError">Throws a <c>DynamicError</c> if any run-time failure
678
        /// occurs while evaluating the expression, or if the expression is not an
679
        /// updating query.</exception>
680

    
681
        public XdmNode[] RunUpdate()
682
        {
683
            try
684
            {
685

    
686
                evaluator.run();
687
                java.util.Iterator updatedDocsIter = evaluator.getUpdatedDocuments();
688
                List<XdmNode> resultList = new List<XdmNode>();
689

    
690
                for (; updatedDocsIter.hasNext(); )
691

    
692
                {
693
                    resultList.Add((XdmNode)XdmValue.Wrap( ((net.sf.saxon.s9api.XdmNode)updatedDocsIter.next()).getUnderlyingNode()));
694
                }
695
                XdmNode[] result = resultList.ToArray();
696
                return result;
697
            }
698
            catch (JSaxonApiException err)
699
            {
700
                throw new DynamicError(err);
701
            }
702
        }
703

    
704
    /// <summary>
705
    /// Call a global user-defined function in the compiled query.
706
    /// </summary>
707
    /// <remarks>
708
    /// If this is called more than once (to evaluate the same function repeatedly with different arguments,
709
    /// or to evaluate different functions) then the sequence of evaluations uses the same values of global
710
    /// variables including external variables (query parameters); the effect of any changes made to query parameters
711
    /// between calls is undefined.
712
    /// </remarks>
713
    /// <param name="function">
714
    /// The name of the function to be called
715
    /// </param>
716
    /// <param name="arguments">
717
    /// The values of the arguments to be supplied to the function. These
718
    /// must be of the correct type as defined in the function signature (there is no automatic
719
    /// conversion to the required type).
720
    /// </param>
721
    /// <exception cref="ArgumentException">If no function has been defined with the given name and arity
722
    /// or if any of the arguments does not match its required type according to the function
723
    /// signature.</exception>
724
    /// <exception cref="DynamicError">If a dynamic error occurs in evaluating the function.
725
    /// </exception>
726

    
727
    public XdmValue CallFunction(QName function, XdmValue[] arguments) {    
728
        try {
729
            JXdmValue[] vr = new JXdmValue[arguments.Length];
730
            for (int i=0; i<arguments.Length; i++) {
731
                vr[i] = XdmValue.FromGroundedValueToJXdmValue(arguments[i].value);
732
            }
733
            JSequence result = evaluator.callFunction(function.UnderlyingQName(), vr).getUnderlyingValue();
734
            return XdmValue.Wrap(result);
735
        } catch (JSaxonApiException e) {
736
            throw new DynamicError(e);
737
        }
738
    }
739

    
740

    
741

    
742
        /// <summary>
743
        /// Escape hatch to the <c>net.sf.saxon.query.DynamicQueryContext</c> object in the underlying Java implementation
744
        /// </summary>
745

    
746
        public JXQueryEvaluator Implementation
747
        {
748
            get { return evaluator; }
749
        }
750

    
751
    }
752

    
753

    
754
    /// <summary>
755
    /// Interface defining a user-supplied class used to retrieve XQuery library modules listed
756
    /// in an <c>import module</c> declaration in the query prolog.
757
    /// </summary>
758

    
759

    
760
    public interface IQueryResolver
761
    {
762

    
763
        /// <summary>
764
        /// Given a module URI and a set of location hints, return a set of query modules.
765
        /// </summary>
766
        /// <param name="moduleUri">The URI of the required library module as written in the
767
        /// <c>import module</c> declaration</param>
768
        /// <param name="baseUri">The base URI of the module containing the <c>import module</c>
769
        /// declaration</param>
770
        /// <param name="locationHints">The sequence of URIs (if any) listed as location hints
771
        /// in the <c>import module</c> declaration in the query prolog.</param>
772
        /// <returns>A set of absolute URIs identifying the query modules to be loaded. There is no requirement
773
        /// that these correspond one-to-one with the URIs defined in the <c>locationHints</c>. The 
774
        /// returned URIs will be dereferenced by calling the <c>GetEntity</c> method.
775
        /// </returns>
776

    
777
		/**public**/ Uri[] GetModules(String moduleUri, Uri baseUri, String[] locationHints);
778

    
779
        /// <summary>
780
        /// Dereference a URI returned by <c>GetModules</c> to retrieve a <c>Stream</c> containing
781
        /// the actual query text.
782
        /// </summary>
783
        /// <param name="absoluteUri">A URI returned by the <code>GetModules</code> method.</param>
784
        /// <returns>Either a <c>Stream</c> or a <c>String</c> containing the query text. 
785
        /// The supplied URI will be used as the base URI of the query module.</returns>
786

    
787
		/**public**/ Object GetEntity(Uri absoluteUri);
788

    
789
    }
790

    
791
    /// <summary>
792
	/// Internal class that wraps a (.NET) <c>IQueryResolver</c> to create a (Java) <c>ModuleURIResolver</c>.
793
	/// <para>A <c>ModuleURIResolver</c> is used when resolving references to
794
	/// query modules. It takes as input a URI that identifies the module to be loaded, and a set of
795
	/// location hints, and returns one or more <c>StreamSource</c> obects containing the queries
796
	/// to be imported.</para>
797
    /// </summary>
798

    
799
    internal class DotNetModuleURIResolver : net.sf.saxon.lib.ModuleURIResolver
800
    {
801

    
802
        private IQueryResolver resolver;
803

    
804
		/// <summary>
805
		/// Initializes a new instance of the <see cref="Saxon.Api.DotNetModuleURIResolver"/> class.
806
		/// </summary>
807
		/// <param name="resolver">Resolver.</param>
808
        public DotNetModuleURIResolver(IQueryResolver resolver)
809
        {
810
            this.resolver = resolver;
811
        }
812

    
813

    
814
		/// <summary>
815
		/// Resolve a module URI and associated location hints.
816
		/// </summary>
817
		/// <param name="moduleURI">ModuleURI. The module namespace URI of the module to be imported; or null when
818
		/// loading a non-library module.</param>
819
		/// <param name="baseURI">BaseURI. The base URI of the module containing the "import module" declaration;
820
		/// null if no base URI is known</param>
821
		/// <param name="locations">Locations. The set of URIs specified in the "at" clause of "import module",
822
		/// which serve as location hints for the module</param>
823
		/// <returns>an array of StreamSource objects each identifying the contents of a module to be
824
		/// imported. Each StreamSource must contain a
825
		/// non-null absolute System ID which will be used as the base URI of the imported module,
826
		/// and either an InputSource or a Reader representing the text of the module. The method
827
		/// may also return null, in which case the system attempts to resolve the URI using the
828
		/// standard module URI resolver.</returns>
829
        public JStreamSource[] resolve(String moduleURI, String baseURI, String[] locations)
830
        {
831
            Uri baseU = (baseURI == null ? null : new Uri(baseURI));
832
            Uri[] modules = resolver.GetModules(moduleURI, baseU, locations);
833
            JStreamSource[] ss = new JStreamSource[modules.Length];
834
            for (int i = 0; i < ss.Length; i++)
835
            {
836
                ss[i] = new JStreamSource();
837
                ss[i].setSystemId(modules[i].ToString());
838
                Object query = resolver.GetEntity(modules[i]);
839
                if (query is Stream)
840
                {
841
                    ss[i].setInputStream(new JDotNetInputStream((Stream)query));
842
                }
843
                else if (query is String)
844
                {
845
                    ss[i].setReader(new JDotNetReader(new StringReader((String)query)));
846
                }
847
                else
848
                {
849
                    throw new ArgumentException("Invalid response from GetEntity()");
850
                }
851
            }
852
            return ss;
853
        }
854
    }
855

    
856

    
857

    
858

    
859

    
860

    
861
}
862

    
863

    
864
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
865
// Copyright (c) 2018 Saxonica Limited.
866
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
867
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
868
// This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0.
869
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
(12-12/13)