Project

Profile

Help

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

he / src / main / csharp / api / Saxon.Api / Configuration.cs @ c7deb2a9

1
using System;
2
using System.IO;
3
using System.Xml;
4
using System.Collections;
5
using System.Globalization;
6
using JResult = net.sf.saxon.@event.Receiver;
7
using JConfiguration = net.sf.saxon.Configuration;
8
using JVersion = net.sf.saxon.Version;
9
using JLogger = net.sf.saxon.lib.Logger;
10
using JDotNetDocumentWrapper = net.sf.saxon.dotnet.DotNetDocumentWrapper;
11
using JDotNetObjectModel = net.sf.saxon.dotnet.DotNetObjectModel;
12
using JNodeInfo = net.sf.saxon.om.NodeInfo;
13
using JSequence = net.sf.saxon.om.Sequence;
14
using JPipelineConfiguration = net.sf.saxon.@event.PipelineConfiguration;
15
using AugmentedSource = net.sf.saxon.lib.AugmentedSource;
16
using NodeName = net.sf.saxon.om.NodeName;
17
using FingerprintedQName = net.sf.saxon.om.FingerprintedQName;
18
using Whitespace = net.sf.saxon.value.Whitespace;
19
using JReceiver = net.sf.saxon.@event.Receiver;
20
using JValidation = net.sf.saxon.lib.Validation;
21
using JXPathException = net.sf.saxon.trans.XPathException;
22
using JProcessor = net.sf.saxon.s9api.Processor;
23
using JParseOptions = net.sf.saxon.lib.ParseOptions;
24
using JPullSource = net.sf.saxon.pull.PullSource;
25
using JPullProvider = net.sf.saxon.pull.PullProvider;
26
using JDotNetWriter = net.sf.saxon.dotnet.DotNetWriter;
27
using JDotNetInputStream = net.sf.saxon.dotnet.DotNetInputStream;
28
using JDotNetURIResolver = net.sf.saxon.dotnet.DotNetURIResolver;
29
using JDotNetEnumerableCollection = net.sf.saxon.dotnet.DotNetEnumerableCollection;
30
using JDotNetPullProvider = net.sf.saxon.dotnet.DotNetPullProvider;
31
using JDotNetReader = net.sf.saxon.dotnet.DotNetReader;
32
using JDotNetComparator = net.sf.saxon.dotnet.DotNetComparator;
33
using JDocumentBuilder = net.sf.saxon.s9api.DocumentBuilder;
34
using JWhiteSpaceStrippingPolicy = net.sf.saxon.s9api.WhitespaceStrippingPolicy;
35
using JSpaceStrippingRule = net.sf.saxon.om.SpaceStrippingRule;
36
using JWhitespace = net.sf.saxon.value.Whitespace;
37
using JXsltExecutable = net.sf.saxon.s9api.XsltExecutable;
38
using JFilterFactory = net.sf.saxon.@event.FilterFactory;
39
using JProxyReceiver = net.sf.saxon.@event.ProxyReceiver;
40
using JExpressionPresenter = net.sf.saxon.trace.ExpressionPresenter;
41
using JStripper = net.sf.saxon.@event.Stripper;
42
using JSchemaType = net.sf.saxon.type.SchemaType;
43
using JStreamResult = javax.xml.transform.stream.StreamResult;
44
using JSource = javax.xml.transform.Source;
45
using JStreamSource = javax.xml.transform.stream.StreamSource;
46
using java.util.function;
47

    
48
namespace Saxon.Api
49
{
50

    
51
    /// <summary>
52
	/// The <c>Processor</c> class serves three purposes: it allows global Saxon configuration
53
    /// options to be set; it acts as a factory for generating XQuery, XPath, and XSLT
54
	/// compilers; and it owns certain shared resources such as the Saxon <c>NamePool</c> and 
55
    /// compiled schemas. This is the first object that a Saxon application should create. Once
56
	/// established, a <c>Processor</c> may be used in multiple threads.
57
    /// </summary>
58

    
59
    [Serializable]
60
    public class Processor : JConfiguration.ApiProvider
61
    {
62

    
63
        //Transformation data variables
64
        private SchemaManager schemaManager = null;
65
        /*internal JConfiguration config;
66
       */
67
        private TextWriter textWriter = Console.Error;
68
        private JProcessor processor;
69
        private IQueryResolver moduleResolver;
70
        private ICollectionFinder collectionFinder = null;
71
        private StandardCollectionFinder standardCollectionFinder;
72

    
73
        internal Processor(JProcessor p) {
74
            processor = p;
75
            processor.getUnderlyingConfiguration().setProcessor(this);
76
            collectionFinder = new StandardCollectionFinder(Implementation.getCollectionFinder());
77
            standardCollectionFinder = new StandardCollectionFinder(Implementation.getStandardCollectionFinder());
78
        }
79

    
80
        /// <summary>
81
        /// Create a new <c>Processor</c>. This <c>Processor</c> will have capabilities that depend on the version
82
        /// of the software that has been loaded, and on the features that have been licensed.
83
        /// </summary>
84

    
85
        public Processor()
86
        {
87
            processor = new JProcessor(false);
88
            processor.getUnderlyingConfiguration().setProcessor(this);
89
            processor.getUnderlyingConfiguration().registerExternalObjectModel(new DotNetObjectModelDefinition());
90
            collectionFinder = new StandardCollectionFinder(Implementation.getCollectionFinder());
91
            standardCollectionFinder = new StandardCollectionFinder(Implementation.getStandardCollectionFinder());
92
        }
93

    
94
        /// <summary>
95
		/// Create a <c>Processor</c>.
96
        /// </summary>
97
		/// <param name="licensedEdition">Set to true if the <c>Processor</c> is to use a licensed edition of Saxon
98
		/// (that is, Saxon-PE or Saxon-EE). If true, the <c>Processor</c> will attempt to enable the capabilities
99
        /// of the licensed edition of Saxon, according to the version of the software that is loaded, and will
100
		/// verify the license key. If false, the <c>Processor</c> will load a default <c>Configuration</c> that gives restricted
101
        /// capability and does not require a license, regardless of which version of the software is actually being run.</param>
102

    
103
        public Processor(bool licensedEdition)
104
            // newline needed by documentation stylesheet
105
            : this(licensedEdition, false) { }
106

    
107
        /// <summary>
108
		/// Create a <c>Processor</c>.
109
        /// </summary>
110
		/// <param name="licensedEdition">Set to true if the <c>Processor</c> is to use a licensed edition of Saxon
111
		/// (that is, Saxon-PE or Saxon-EE). If true, the <c>Processor</c> will attempt to enable the capabilities
112
        /// of the licensed edition of Saxon, according to the version of the software that is loaded, and will
113
		/// verify the license key. If false, the <c>Processor</c> will load a default <c>Configuration</c> that gives restricted
114
        /// capability and does not require a license, regardless of which version of the software is actually being run.</param>
115
        /// <param name="loadLocally">This option has no effect at this release.</param>
116

    
117
        public Processor(bool licensedEdition, bool loadLocally)
118
        {
119
            processor = new JProcessor(licensedEdition);
120
            processor.getUnderlyingConfiguration().registerExternalObjectModel(new DotNetObjectModelDefinition());
121
        }
122

    
123
        /// <summary>
124
        /// Create a <c>Processor</c>, based on configuration information supplied in a configuration file.
125
        /// </summary>
126
        /// <param name="configurationFile">A stream holding the text of the XML configuration file. Details of the file format
127
        /// can be found in the Saxon documentation.</param>
128

    
129
        [Obsolete("Use the Processor(Stream, Uri) constructor instead.")]
130
        public Processor(Stream configurationFile)
131
        {
132
            JStreamSource ss = new JStreamSource(new JDotNetInputStream(configurationFile));
133
            JConfiguration config = JConfiguration.readConfiguration(ss);
134
            config.registerExternalObjectModel(new DotNetObjectModelDefinition());
135
            processor = new JProcessor(config);
136
        }
137

    
138
        /// <summary>
139
        /// Create a <c>Processor</c>, based on configuration information supplied in a configuration file.
140
        /// </summary>
141
        /// <param name="configurationFile">A stream holding the text of the XML configuration file. Details of the file format
142
        /// can be found in the Saxon documentation.</param>
143
        /// <param name="baseUri">baseUri of the configuration file used for resolving any relative URIs in the file</param> 
144

    
145
        public Processor(Stream configurationFile, Uri baseUri)
146
        {
147
            JStreamSource ss = new JStreamSource(new JDotNetInputStream(configurationFile), baseUri.AbsoluteUri);
148
            JConfiguration config = JConfiguration.readConfiguration(ss);
149
            config.registerExternalObjectModel(new DotNetObjectModelDefinition());
150
            processor = new JProcessor(config);
151
        }
152

    
153
        public ICollectionFinder CollectionFinder
154
		{  
155
            set {
156
                if (value != null)
157
                {
158
                    collectionFinder = value;
159
                    Implementation.setCollectionFinder(new CollectionFinderWrapper(collectionFinder));
160

    
161
                }
162

    
163
            }
164
            get {
165
                return collectionFinder;
166
            }
167

    
168
        }
169

    
170

    
171
        public StandardCollectionFinder StandardCollectionFinder
172
        {
173
            get
174
            {
175
                return standardCollectionFinder;
176
            }
177

    
178
        }
179

    
180
		/// <summary>
181
		/// Register a specific URI and bind it to a specific <c>ResourceCollection</c>
182
		/// </summary>
183
		/// <param name="collectionURI">the collection URI to be registered. Must not be null.</param>
184
		/// <param name="collection">the ResourceCollection to be associated with this URI. Must not be null.</param>
185
        public void RegisterCollection(String collectionURI, IResourceCollection collection) {
186
            StandardCollectionFinder.RegisterCollection(collectionURI, collection);
187
            if (CollectionFinder is StandardCollectionFinder && collectionFinder != standardCollectionFinder) {
188
                ((StandardCollectionFinder)collectionFinder).RegisterCollection(collectionURI, collection);
189
            }
190
        }
191

    
192

    
193

    
194
        /// <summary>
195
        /// Declare a mapping from a specific namespace URI to a .NET class
196
        /// This will get applied to Saxon-PEN or Saxon-EEN product
197
        /// </summary>
198
        /// <param name="uri">the namespace URI of the function name</param>
199
        /// <param name="type">the .NET class that implements the functions in this namespace</param>
200
        public void BindExtensions(string uri, System.Type type) {
201
            JConfiguration config = processor.getUnderlyingConfiguration();
202
            config.bindExtensions(uri, type);
203
        }
204

    
205

    
206

    
207

    
208
        /// <summary>
209
		/// Get the full name of the Saxon product version implemented by this <c>Processor</c>
210
        /// </summary>
211

    
212
        public string ProductTitle
213
        {
214
            get { return JVersion.getProductTitle(); }
215
        }
216

    
217
        /// <summary>
218
        /// Get the Saxon product version number (for example, "9.2.0.2")
219
        /// </summary>
220

    
221
        public string ProductVersion
222
        {
223
            get { return JVersion.getProductVersion(); }
224
        }
225

    
226
        /// <summary>
227
        /// Get the Saxon product edition (for example, "EE" for Enterprise Edition)
228
        /// </summary>
229
        /// 
230

    
231
        public string Edition
232
        {
233
            get { return processor.getUnderlyingConfiguration().getEditionCode(); }
234
        }
235

    
236

    
237

    
238
        /// <summary>
239
		/// Gets the <c>SchemaManager</c> for the <c>Processor</c>. Returns null
240
		/// if the <c>Processor</c> is not schema-aware.
241
        /// </summary>
242

    
243
        public SchemaManager SchemaManager
244
        {
245
            get {
246
                if (schemaManager == null)
247
                {
248
                    schemaManager = new SchemaManager(this);
249
                }
250

    
251
                return schemaManager; }
252
        }
253

    
254
        /// <summary>
255
		/// An <c>XmlResolver</c>, which will be used while compiling and running queries, 
256
		/// XPath expressions, and stylesheets, if no other <c>XmlResolver</c> is nominated
257
        /// </summary>
258
        /// <remarks>
259
        /// <para>By default an <c>XmlUrlResolver</c> is used. This means that the responsibility
260
        /// for resolving and dereferencing URIs rests with the .NET platform, not with the
261
        /// IKVM/OpenJDK runtime.</para>
262
        /// <para>When Saxon invokes a user-written <c>XmlResolver</c>, the <c>GetEntity</c> method
263
        /// may return any of: a <c>System.IO.Stream</c>; a <c>System.IO.TextReader</c>; or a
264
        /// <c>java.xml.transform.Source</c>.</para>
265
        /// </remarks>
266

    
267
        public XmlResolver XmlResolver
268
        {
269
            get
270
            {
271
                javax.xml.transform.URIResolver resolver = processor.getUnderlyingConfiguration().getURIResolver();
272
                if (resolver is JDotNetURIResolver) {
273
                    return ((JDotNetURIResolver)resolver).getXmlResolver();
274
                } else {
275
                    return new XmlUrlResolver();
276
                }
277
            }
278
            set
279
            {
280
                processor.getUnderlyingConfiguration().setURIResolver(new JDotNetURIResolver(value));
281
            }
282
        }
283

    
284

    
285
        /// <summary>
286
		/// A <c>TextWriter</c> used as the destination of miscellaneous error, warning, and progress messages.
287
        /// </summary>
288
        /// <remarks>
289
        /// <para>By default the <c>Console.Error</c> is used for all such messages.</para>
290
        /// <para>A user can supply their own <c>TextWriter</c> to redirect error messages from the standard output.</para>
291
        /// </remarks>
292
        public TextWriter ErrorWriter
293
        {
294
            get
295
            {
296
                return textWriter;
297
            }
298
            set
299
            {
300
                textWriter = value;
301
                StandardLogger logger = new StandardLogger(value);
302
                processor.getUnderlyingConfiguration().setLogger(logger);
303
            }
304
        }
305

    
306
        /// <summary>
307
        /// Create a new <c>DocumentBuilder</c>, which may be used to build XDM documents from
308
        /// a variety of sources.
309
        /// </summary>
310
        /// <returns>A new <c>DocumentBuilder</c></returns>
311

    
312
        public DocumentBuilder NewDocumentBuilder()
313
        {
314
            DocumentBuilder builder = new DocumentBuilder(this);
315
            builder.XmlResolver = XmlResolver;
316
            return builder;
317
        }
318

    
319
        /// <summary>
320
		/// Create a new <c>XQueryCompiler</c>, which may be used to compile XQuery queries.
321
        /// </summary>
322
        /// <remarks>
323
		/// The returned <c>XQueryCompiler</c> retains a live link to the <c>Processor</c>, and
324
		/// may be affected by subsequent changes to the <c>Processor</c>.
325
        /// </remarks>
326
		/// <returns>A new <c>XQueryCompiler</c></returns>
327

    
328
        public XQueryCompiler NewXQueryCompiler()
329
        {
330
            return new XQueryCompiler(this);
331
        }
332

    
333
        /// <summary>
334
		/// Create a new <c>XsltCompiler</c>, which may be used to compile XSLT stylesheets.
335
        /// </summary>
336
        /// <remarks>
337
		/// The returned <c>XsltCompiler</c> retains a live link to the <c>Processor</c>, and
338
		/// may be affected by subsequent changes to the <c>Processor</c>.
339
        /// </remarks>
340
		/// <returns>A new <c>XsltCompiler</c></returns>
341

    
342
        public XsltCompiler NewXsltCompiler()
343
        {
344
            return new XsltCompiler(this);
345
        }
346

    
347
        /// <summary>
348
		/// Create a new <c>XPathCompiler</c>, which may be used to compile XPath expressions.
349
        /// </summary>
350
        /// <remarks>
351
		/// The returned <c>XPathCompiler</c> retains a live link to the <c>Processor</c>, and
352
		/// may be affected by subsequent changes to the <c>Processor</c>.
353
        /// </remarks>
354
		/// <returns>A new <c>XPathCompiler</c></returns>
355

    
356
        public XPathCompiler NewXPathCompiler()
357
        {
358
            return new XPathCompiler(this, JProcessor.newXPathCompiler());
359
        }
360

    
361
        /// <summary>
362
		/// Create a <c>Serializer</c>
363
        /// </summary>
364
		/// <returns> a new <c>Serializer</c> </returns>
365
        public Serializer NewSerializer() {
366
            Serializer s = new Serializer(processor.newSerializer());
367
            s.SetProcessor(this); //TODO this method call might no longer be needed
368
            return s;
369
        }
370

    
371
        /// <summary>
372
        /// Create a <c>Serializer</c> initialized to write to a given <c>TextWriter</c>.
373
        /// Closing the writer after use is the responsibility of the caller.
374
        /// </summary>
375
        /// <param name="textWriter">The <c>TextWriter</c> to which the <c>Serializer</c> will write</param>
376
        /// <returns> a new <c>Serializer</c> </returns>
377
        public Serializer NewSerializer(TextWriter textWriter)
378
        {
379
            Serializer s = new Serializer(processor.newSerializer());
380
            s.SetOutputWriter(textWriter);
381
            return s;
382
        }
383

    
384
        /// <summary>
385
        /// Create a <c>Serializer</c> initialized to write to a given output <c>Stream</c>.
386
        /// Closing the output stream after use is the responsibility of the caller.
387
        /// </summary>
388
        /// <param name="stream">The output <c>Stream</c> to which the <c>Serializer</c> will write</param>
389
        /// <returns> a new Serializer </returns>
390
        public Serializer NewSerializer(Stream stream)
391
        {
392
            Serializer s = new Serializer(processor.newSerializer());
393
            s.SetOutputStream(stream);
394
            return s;
395
        }
396

    
397
        /// <summary>
398
        /// The XML version used in this <c>Processor</c>
399
        /// </summary>
400
        /// <remarks>
401
        /// The value must be 1.0 or 1.1, as a <c>decimal</c>. The default version is currently 1.0, but may
402
        /// change in the future.
403
        /// </remarks>
404

    
405
        public decimal XmlVersion
406
        {
407
            get
408
            {
409
                return (processor.getUnderlyingConfiguration().getXMLVersion() == JConfiguration.XML10 ? 1.0m : 1.1m);
410
            }
411
            set
412
            {
413
                if (value == 1.0m)
414
                {
415
                    processor.setXmlVersion("1.0");
416
                }
417
                else if (value == 1.1m)
418
                {
419
                    processor.setXmlVersion("1.1");
420
                }
421
                else
422
                {
423
                    throw new ArgumentException("Invalid XML version: " + value);
424
                }
425
            }
426
        }
427

    
428
        /// <summary>
429
        /// Create a collation based on a given <c>CompareInfo</c> and <c>CompareOptions</c>    
430
        /// </summary>
431
        /// <param name="uri">The collation URI to be used within an XPath expression to refer to this collation</param>
432
        /// <param name="compareInfo">The <c>CompareInfo</c>, which determines the language-specific
433
        /// collation rules to be used</param>
434
        /// <param name="options">Options to be used in performing comparisons, for example
435
        /// whether they are to be case-blind and/or accent-blind</param>
436

    
437
        public void DeclareCollation(Uri uri, CompareInfo compareInfo, CompareOptions options)
438
        {
439
            JDotNetComparator comparator = new JDotNetComparator(uri.ToString(), compareInfo, options);
440
            Implementation.registerCollation(uri.ToString(), comparator);
441
        }
442

    
443
        /// <summary>
444
        /// Register a named collection. A collection is identified by a URI (the collection URI),
445
        /// and its content is represented by an <c>IEnumerable</c> that enumerates the contents
446
        /// of the collection. The values delivered by this enumeration are Uri values, which 
447
        /// can be mapped to nodes using the registered <c>XmlResolver</c>.
448
        /// </summary>
449
        /// <param name="collectionUri">The URI used to identify the collection in a call
450
        /// of the XPath <c>collection()</c> function. The default collection is registered
451
        /// by supplying null as the value of this argument (this is the collection returned
452
        /// when the XPath <c>collection()</c> function is called with no arguments).</param> 
453
        /// <param name="contents">An enumerable object that represents the contents of the
454
        /// collection, as a sequence of document URIs. The enumerator returned by this
455
        /// IEnumerable object must return instances of the Uri class.</param>
456
        /// <remarks>
457
        /// <para>Collections should be stable: that is, two calls to retrieve the same collection URI
458
        /// should return the same sequence of document URIs. This requirement is imposed by the
459
        /// W3C specifications, but in the case of a user-defined collection it is not enforced by
460
        /// the Saxon product.</para>
461
        /// <para>A collection may be replaced by specifying the URI of an existing
462
        /// collection.</para>
463
        /// <para>Collections registered with a processor are available to all queries and stylesheets
464
        /// running under the control of that processor. Collections should not normally be registered
465
        /// while queries and transformations are in progress.</para>
466
        /// </remarks>
467
        /// 
468

    
469
        public void RegisterCollection(Uri collectionUri, IEnumerable contents)
470
        {
471
            String u = (collectionUri == null ? null : collectionUri.ToString());
472
            JConfiguration config = processor.getUnderlyingConfiguration();
473
            config.registerCollection(u, new JDotNetEnumerableCollection(config, contents));
474
        }
475

    
476
        /// <summary>
477
		/// Register an extension function with the <c>Processor</c>
478
        /// </summary>
479
        /// <param name="function">
480
        /// An object that defines the extension function, including its name, arity, arguments types, and
481
        /// a reference to the class that implements the extension function call.
482
        /// </param>
483

    
484
        public void RegisterExtensionFunction(ExtensionFunctionDefinition function)
485
        {
486
            WrappedExtensionFunctionDefinition f = new WrappedExtensionFunctionDefinition(function);
487
            processor.registerExtensionFunction(f);
488
        }
489

    
490
        /// <summary>
491
        /// Register a simple external/extension function that is to be made available within any stylesheet, query
492
        /// or XPath expression compiled under the control of this <c>Processor</c>
493
        /// </summary>
494
        /// <param name="function">
495
        /// This interface provides only for simple extensions that have no side-effects and no
496
        /// dependencies on the static or dynamic context.
497
        /// </param>
498

    
499
        public void RegisterExtensionFunction(ExtensionFunction function)
500
        {
501
            WrappedExtensionFunction f = new WrappedExtensionFunction(function);
502
            processor.registerExtensionFunction(f);
503
        }
504

    
505

    
506
        /// <summary>
507
        /// Set the media type to be associated with a file extension by  the standard collection handler
508
        /// </summary>
509
        /// <param name="extension">the file extension, for exmaple "xml". The value "" sets the 
510
        /// default media type to be used for unregistered file extensions</param>
511
        /// <param name="mediaType">the corresponding media type, for example "application/xml". The
512
        /// choice of media type determines how a resource with this extension gets parsed, when the file 
513
        /// appears as part of a collection</param>
514
        public void RegisterFileExtension(String extension, String mediaType) {
515
            Implementation.registerFileExtension(extension, mediaType);
516
        }
517

    
518
        /// <summary>
519
        /// Associated a media type with a resource factory. This methodm may be called
520
        /// to customize the behaviour of a collection to recognize different file extensions
521
        /// </summary>
522
        /// <param name="contentType">a media type or MIME type, for example application/xsd+xml</param>
523
        /// <param name="factory">a ResourceFactory used to parse (or otherweise process) resource of that type</param>
524
        public void RegisterMediaType(String contentType, IResourceFactory factory) {
525
            Implementation.registerMediaType(contentType, new ResourceFactoryWrapper(factory, this));
526
        }
527

    
528

    
529
        /// <summary>
530
        /// Get the media type to be associated with a file extension by the standard 
531
        /// collection handler
532
        /// </summary>
533
        /// <param name="extension">the file extension, for example "xml". The value "" gets
534
        /// the default media type to be used for unregistered file extensions. The default 
535
        /// media type is also returned if the supplied file extension is not registered</param>
536
        /// <returns>the corresponding media type, for example "application/xml". The choice
537
        /// of media type determines how a resource with this extension gets parsed, when the file
538
        /// appears as part of a collection.</returns>
539
        public String GetMediaTypeForFileExtension(String extension) {
540
            return Implementation.getMediaTypeForFileExtension(extension);
541
        }
542

    
543
        /// <summary>
544
		/// Copy an <c>XdmValue</c> to an <c>XmlDestination</c>
545
        /// </summary>
546
        /// <remarks>
547
        /// In principle this method can be used to copy any kind of <c>XdmValue</c> to any kind
548
        /// of <c>XmlDestination</c>. However, some kinds of destination may not accept arbitrary
549
        /// sequences of items; for example, some may reject function items. Some destinations
550
        /// perform sequence normalization, as defined in the W3C serialization specification,
551
        /// to convert the supplied sequence to a well-formed XML document; it is a property
552
        /// of the chosen <c>XmlDestination</c> whether it does this or not.</remarks>
553
        /// <param name="sequence">The value to be written</param>
554
        /// <param name="destination">The destination to which the value should be written</param>
555
        /// 
556

    
557
        public void WriteXdmValue(XdmValue sequence, XmlDestination destination)
558
        {
559
            try
560
            {
561
                JPipelineConfiguration pipe = processor.getUnderlyingConfiguration().makePipelineConfiguration();
562
                JResult r = destination.GetUnderlyingDestination().getReceiver(pipe, pipe.getConfiguration().obtainDefaultSerializationProperties());
563
                r.open();
564
                foreach (XdmItem item in sequence) {
565
                    r.append(item.Unwrap().head());
566
                }
567
                r.close();
568
            } catch (JXPathException err) {
569
                throw new DynamicError(err);
570
            }
571
        }
572

    
573

    
574
        /// <summary>
575
		/// The underlying <c>Configuration</c> object in the Saxon implementation
576
        /// </summary>
577
        /// <remarks>
578
        /// <para>This property provides access to internal methods in the Saxon engine that are
579
        /// not specifically exposed in the .NET API. In general these methods should be
580
        /// considered to be less stable than the classes in the Saxon.Api namespace.</para> 
581
        /// <para>The internal methods follow
582
        /// Java naming conventions rather than .NET conventions.</para>
583
		/// <para>Information about the returned <see cref="net.sf.saxon.Configuration"/> object 
584
		/// (and the objects it provides access to) is included in the Saxon JavaDoc docmentation.
585
        /// </para>
586
        /// </remarks>
587

    
588
        public JConfiguration Implementation
589
        {
590
            get { return processor.getUnderlyingConfiguration(); }
591
        }
592

    
593
        /// <summary>
594
        /// A user-supplied <c>IQueryResolver</c> used to resolve location hints appearing in an
595
        /// <c>import module</c> declaration.
596
        /// </summary>
597
        /// <remarks>
598
        /// <para>This acts as the default value for the ModuleURIResolver.</para>
599
        /// <para> The URI Resolver for XQuery modules. May be null, in which case any 
600
        /// existing Module URI Resolver is removed  from the Configuration</para>
601
        /// </remarks>
602
        public IQueryResolver QueryResolver
603
        {
604
            get { return moduleResolver; }
605
            set
606
            {
607
                moduleResolver = value;
608
                processor.getUnderlyingConfiguration().setModuleURIResolver((value == null ? null : new DotNetModuleURIResolver(value)));
609
            }
610
        }
611

    
612
        /// <summary>
613
        /// The underlying <c>net.sf.saxon.s9api.Processor</c> in the Java implementation
614
        /// </summary>
615

    
616
        public JProcessor JProcessor
617
        {
618
            get { return processor; }
619
        }
620

    
621
        /// <summary>
622
        /// Set a configuration property
623
        /// </summary>
624
        /// <remarks>
625
        /// <para>This method provides the ability to set named properties of the configuration.
626
        /// The property names are set as strings, whose values can be found in the Java
627
        /// class <c>net.sf.saxon.FeatureKeys</c>. The property values are always strings. 
628
        /// Properties whose values are other types are not available via this interface:
629
        /// however all properties have an effective equivalent whose value is a string.
630
        /// Note that on/off properties are set using the strings "true" and "false".</para>
631
        /// <para><i>Method added in Saxon 9.1</i></para>
632
        /// </remarks>
633
        /// <param name="name">The property name</param>
634
        /// <param name="value">The property value</param>
635
        public void SetProperty(String name, String value)
636
        {
637
            if (name.Equals("http://saxonica.com/oem-data"))
638
            {
639
                processor.setConfigurationProperty("http://saxonica.com/oem-data", value);
640
            }
641
            else
642
            {
643
                processor.setConfigurationProperty(net.sf.saxon.lib.Feature.byName(name), value);
644
            }
645
        }
646

    
647
        /// <summary>
648
        /// Set a configuration property
649
        /// </summary>
650
        /// <param name="feature">The property feature</param>
651
        /// <param name="value">The property value</param>
652

    
653
        public void SetProperty<T>(Feature<T> feature, T value)
654
        {
655
            if (value.GetType() == typeof(Boolean))
656
            {
657
                processor.setConfigurationProperty(feature.JFeature, java.lang.Boolean.valueOf((bool)(object)value));
658
            }
659
            else
660
            {
661
                processor.setConfigurationProperty(feature.JFeature, (object)value);
662
            }
663
        }
664

    
665
        /// <summary>
666
        /// Get the value of a configuration property
667
        /// </summary>
668
        /// <remarks>
669
        /// <para>This method provides the ability to get named properties of the configuration.
670
        /// The property names are supplied as strings, whose values can be found in the Java
671
        /// class <c>net.sf.saxon.FeatureKeys</c>. The property values are always returned as strings. 
672
        /// Properties whose values are other types are returned by converting the value to a string.
673
        /// Note that on/off properties are returned using the strings "true" and "false".</para>
674
        /// <para><i>Method added in Saxon 9.1</i></para>
675
        /// </remarks>
676
        /// <param name="name">The property name</param>
677
        /// <returns>The property value, as a string; or null if the property is unset.</returns>
678

    
679
        public String GetProperty(String name)
680
        {
681
            Object obj = processor.getConfigurationProperty(net.sf.saxon.lib.Feature.byName(name));
682
            return (obj == null ? null : obj.ToString());
683
        }
684

    
685

    
686
        /// <summary>
687
        /// Get a property of the configuration
688
        /// </summary>
689
        /// <typeparam name="T">See the class <c>Feature</c> for constants 
690
        /// representing the properties that can be requested.</typeparam>
691
        /// <param name="feature">the required property. </param>
692
        /// <returns>the value of the property</returns>
693
        public T GetProperty<T>(Feature<T> feature) {
694
            return (T)processor.getConfigurationProperty(feature.JFeature);
695
        }
696

    
697
    }
698

    
699
    /// <summary>
700
    /// The <c>DocumentBuilder</c> class enables XDM documents to be built from various sources.
701
    /// The class is always instantiated using the <c>NewDocumentBuilder</c> method
702
    /// on the <c>Processor</c> object.
703
    /// </summary>
704

    
705
    [Serializable]
706
    public class DocumentBuilder
707
    {
708

    
709
        private Processor processor;
710
        private JConfiguration config;
711
        private XmlResolver xmlResolver;
712
        private SchemaValidationMode validation;
713
        private SchemaValidator schemaValidator;
714
        private WhitespacePolicy whitespacePolicy;
715
        private Uri baseUri;
716
        private QName topLevelElement;
717
        private XQueryExecutable projectionQuery;
718

    
719
        private JDocumentBuilder builder;
720

    
721

    
722
        internal DocumentBuilder(Processor processor)
723
        {
724
            this.processor = processor;
725
            this.builder = processor.JProcessor.newDocumentBuilder();
726
            this.config = processor.Implementation;
727
            this.xmlResolver = new XmlUrlResolver();
728
        }
729

    
730
        /// <summary>
731
		/// An <c>XmlResolver</c>, which will be used to resolve URIs of documents being loaded
732
        /// and of references to external entities within those documents (including any external DTD).
733
        /// </summary>
734
        /// <remarks>
735
        /// <para>By default an <c>XmlUrlResolver</c> is used. This means that the responsibility
736
        /// for resolving and dereferencing URIs rests with the .NET platform (and not with the
737
        /// GNU Classpath).</para>
738
        /// <para>When Saxon invokes a user-written <c>XmlResolver</c>, the <c>GetEntity</c> method
739
        /// may return any of: a <c>System.IO.Stream</c>; a <c>System.IO.TextReader</c>; or a
740
        /// <c>java.xml.transform.Source</c>. However, if the <c>XmlResolver</c> is called
741
        /// by the XML parser to resolve external entity references, then it must return an 
742
        /// instance of <c>System.IO.Stream</c>.</para>
743
        /// </remarks>
744

    
745
        public XmlResolver XmlResolver
746
        {
747
            get
748
            {
749
                return xmlResolver;
750
            }
751
            set
752
            {
753
                xmlResolver = value;
754
            }
755
        }
756

    
757
        /// <summary>
758
        /// Determines whether line numbering is enabled for documents loaded using this
759
        /// <c>DocumentBuilder</c>.
760
        /// </summary>
761
        /// <remarks>
762
        /// <para>By default, line numbering is disabled.</para>
763
        /// <para>Line numbering is not available for all kinds of source: in particular,
764
		/// it is not available when loading from an existing <c>XmlDocument</c>.</para>
765
        /// <para>The resulting line numbers are accessible to applications using the
766
		/// extension function <c>saxon:line-number()</c> applied to a node.</para>  
767
        /// <para>Line numbers are maintained only for element nodes; the line number
768
        /// returned for any other node will be that of the most recent element.</para> 
769
        /// </remarks>
770

    
771
        public bool IsLineNumbering
772
        {
773
            get
774
            {
775
                return builder.isLineNumbering();
776
            }
777
            set
778
            {
779
                builder.setLineNumbering(value);
780
            }
781
        }
782

    
783
        /// <summary>
784
        /// Determines whether schema validation is applied to documents loaded using this
785
        /// <c>DocumentBuilder</c>, and if so, whether it is strict or lax.
786
        /// </summary>
787
        /// <remarks>
788
        /// <para>By default, no schema validation takes place.</para>
789
        /// <para>This option requires Saxon Enterprise Edition (Saxon-EE).</para>
790
        /// </remarks>
791

    
792
        public SchemaValidationMode SchemaValidationMode
793
        {
794
            get
795
            {
796
                return validation;
797
            }
798
            set
799
            {
800
                validation = value;
801
            }
802
        }
803

    
804

    
805
        /// <summary>
806
        /// Property to set and get the schemaValidator to be used. This determines whether schema validation is applied
807
        /// to an input document and whether type annotations in a supplied document are retained. If no schemaValidator
808
        /// is supplied, then schema validation does not take place.
809
        /// </summary>
810
        public SchemaValidator SchemaValidator {
811
            get { return schemaValidator; }
812
            set {
813
                schemaValidator = value;
814
                builder.setSchemaValidator(schemaValidator == null ? null : schemaValidator.UnderlyingSchemaValidator);
815
            }
816
        }
817

    
818
        /// <summary>
819
        /// The required name of the top level element in a document instance being validated
820
        /// against a schema.
821
        /// </summary>
822
        /// <remarks>
823
        /// <para>If this property is set, and if schema validation is requested, then validation will
824
        /// fail unless the outermost element of the document has the required name.</para>
825
        /// <para>This option requires the schema-aware version of the Saxon product (Saxon-EE).</para>
826
        /// </remarks> 
827

    
828
        public QName TopLevelElementName
829
        {
830
            get
831
            {
832
                return topLevelElement;
833
            }
834
            set
835
            {
836
                topLevelElement = value;
837
                schemaValidator.UnderlyingSchemaValidator.setDocumentElementName(topLevelElement == null ? null : topLevelElement.UnderlyingQName());
838
            }
839
        }
840

    
841
        /// <summary>
842
        /// Determines whether DTD validation is applied to documents loaded using this
843
        /// <c>DocumentBuilder</c>.
844
        /// </summary>
845
        /// <remarks>
846
        /// <para>By default, no DTD validation takes place.</para>
847
        /// </remarks>
848

    
849
        public bool DtdValidation
850
        {
851
            get
852
            {
853
                return builder.isDTDValidation();
854
            }
855
            set
856
            {
857
                builder.setDTDValidation(value);
858
            }
859
        }
860

    
861
        /// <summary>
862
        /// Determines the whitespace stripping policy applied when loading a document
863
        /// using this <c>DocumentBuilder</c>.
864
        /// </summary>
865
        /// <remarks>
866
        /// <para>By default, whitespace text nodes appearing in element-only content
867
        /// are stripped, and all other whitespace text nodes are retained.</para>
868
        /// </remarks>
869

    
870
        public WhitespacePolicy WhitespacePolicy
871
        {
872
            get
873
            {
874
                return whitespacePolicy;
875
            }
876
            set
877
            {
878
                whitespacePolicy = value;
879
                builder.setWhitespaceStrippingPolicy(whitespacePolicy == null ? null : whitespacePolicy.GetJWhiteSpaceStrippingPolicy());
880
            }
881
        }
882

    
883

    
884

    
885
        ///<summary>
886
        /// The Tree Model implementation to be used for the constructed document. By default
887
		/// the <c>TinyTree</c> is used. The main reason for using the <c>LinkedTree</c> alternative is if
888
		/// updating is required (the <c>TinyTree</c> is not updateable).
889
        ///</summary>
890

    
891
        public TreeModel TreeModel
892
        {
893
            get
894
            {
895
                return (TreeModel)builder.getTreeModel().getSymbolicValue();
896
            }
897
            set
898
            {
899
                builder.setTreeModel(net.sf.saxon.om.TreeModel.getTreeModel((int)value));
900
            }
901
        }
902

    
903
        /// <summary>
904
        /// The base URI of a document loaded using this <c>DocumentBuilder</c>.
905
        /// This is used for resolving any relative URIs appearing
906
        /// within the document, for example in references to DTDs and external entities.
907
        /// </summary>
908
        /// <remarks>
909
        /// This information is required when the document is loaded from a source that does not
910
		/// provide an intrinsic URI, notably when loading from a <c>Stream</c> or a <c>TextReader</c>.
911
        /// </remarks>
912

    
913

    
914
        public Uri BaseUri
915
        {
916
            get { return baseUri; }
917
            set { baseUri = value;
918
                if (baseUri != null)
919
                {
920
                    builder.setBaseURI(new java.net.URI(value.AbsoluteUri));
921
                }
922
            }
923
        }
924

    
925

    
926
        /// <summary>
927
        /// Set a compiled query to be used for implementing document projection. 
928
        /// </summary>
929
        /// <remarks>
930
        /// <para>
931
        /// The effect of using this option is that the tree constructed by the 
932
        /// <c>DocumentBuilder</c> contains only those parts
933
        /// of the source document that are needed to answer this query. Running this query against
934
        /// the projected document should give the same results as against the raw document, but the
935
        /// projected document typically occupies significantly less memory. It is permissible to run
936
        /// other queries against the projected document, but unless they are carefully chosen, they
937
        /// will give the wrong answer, because the document being used is different from the original.
938
        /// </para>
939
        /// <para>The query should be written to use the projected document as its initial context item.
940
        /// For example, if the query is <code>//ITEM[COLOR='blue']</code>, then only <code>ITEM</code>
941
        /// elements and their <code>COLOR</code> children will be retained in the projected document.</para>
942
        /// <para>This facility is only available in Saxon-EE; if the facility is not available,
943
        /// calling this method has no effect.</para>
944
        /// </remarks>
945

    
946

    
947
        public XQueryExecutable DocumentProjectionQuery {
948
            get { return projectionQuery; }
949
            set {
950
                projectionQuery = value;
951
                builder.setDocumentProjectionQuery(projectionQuery == null ? null : projectionQuery.getUnderlyingCompiledQuery());
952
            }
953

    
954
        }
955

    
956
        /// <summary>
957
        /// Load an XML document, retrieving it via a URI.
958
        /// </summary>
959
        /// <remarks>
960
        /// <para>Note that the type <c>Uri</c> requires an absolute URI.</para>
961
        /// <para>The URI is dereferenced using the registered <c>XmlResolver</c>.</para>
962
        /// <para>This method takes no account of any fragment part in the URI.</para>
963
        /// <para>The <c>role</c> passed to the <c>GetEntity</c> method of the <c>XmlResolver</c> 
964
        /// is "application/xml", and the required return type is <c>System.IO.Stream</c>.</para>
965
        /// <para>The document located via the URI is parsed using the <c>System.Xml</c> parser.</para>
966
        /// <para>Note that the Microsoft <c>System.Xml</c> parser does not report whether attributes are
967
        /// defined in the DTD as being of type <c>ID</c> and <c>IDREF</c>. This is true whether or not
968
        /// DTD-based validation is enabled. This means that such attributes are not accessible to the 
969
        /// <c>id()</c> and <c>idref()</c> functions.</para>
970
        /// </remarks>
971
        /// <param name="uri">The URI identifying the location where the document can be
972
        /// found. This will also be used as the base URI of the document (regardless
973
		/// of the setting of the <c>BaseUri</c> property).</param>
974
		/// <returns>An <c>XdmNode</c>, the document node at the root of the tree of the resulting
975
		/// in-memory document.
976
		/// </returns>
977

    
978
        public XdmNode Build(Uri uri)
979
        {
980
            Object obj = XmlResolver.GetEntity(uri, "application/xml", System.Type.GetType("System.IO.Stream"));
981
            if (obj is Stream)
982
            {
983
                try
984
                {
985
                    return Build((Stream)obj, uri);
986
                }
987
                finally
988
                {
989
                    ((Stream)obj).Close();
990
                }
991
            }
992
            else
993
            {
994
                throw new ArgumentException("Invalid type of result from XmlResolver.GetEntity: " + obj);
995
            }
996
        }
997

    
998
        /// <summary>
999
		/// Load an XML document supplied as raw (lexical) XML on a <c>Stream</c>.
1000
        /// </summary>
1001
        /// <remarks>
1002
        /// <para>The document is parsed using the Microsoft <c>System.Xml</c> parser if the
1003
        /// "http://saxon.sf.net/feature/preferJaxpParser" property on the <c>Processor</c> is set to false;
1004
        /// otherwise it is parsed using the Apache Xerces XML parser.</para>
1005
        /// <para>Before calling this method, the <c>BaseUri</c> property must be set to identify the
1006
        /// base URI of this document, used for resolving any relative URIs contained within it.</para>
1007
        /// <para>Note that the Microsoft <c>System.Xml</c> parser does not report whether attributes are
1008
        /// defined in the DTD as being of type <c>ID</c> and <c>IDREF</c>. This is true whether or not
1009
        /// DTD-based validation is enabled. This means that such attributes are not accessible to the 
1010
        /// <c>id()</c> and <c>idref()</c> functions.</para>         
1011
        /// </remarks>
1012
        /// <param name="input">The <c>Stream</c> containing the XML source to be parsed. Closing this stream
1013
        /// on completion is the responsibility of the caller.</param>
1014
        /// <returns>An <c>XdmNode</c>, the document node at the root of the tree of the resulting
1015
        /// in-memory document.
1016
        /// </returns>
1017

    
1018
        public XdmNode Build(Stream input)
1019
        {
1020
            if (baseUri == null)
1021
            {
1022
                throw new ArgumentException("No base URI supplied");
1023
            }
1024
            return Build(input, baseUri);
1025
        }
1026

    
1027
        // Build a document from a given stream, with the base URI supplied
1028
        // as an extra argument
1029

    
1030
        internal XdmNode Build(Stream input, Uri baseUri)
1031
        {
1032
            JSource source;
1033
            JParseOptions options = new JParseOptions(config.getParseOptions());
1034

    
1035
            if (processor.GetProperty("http://saxon.sf.net/feature/preferJaxpParser") == "true")
1036
            {
1037
                source = new JStreamSource(new JDotNetInputStream(input), baseUri.ToString());
1038
                options.setEntityResolver(new JDotNetURIResolver(XmlResolver));
1039
                source = augmentSource(source, options);
1040
            }
1041
            else
1042
            {
1043

    
1044
                XmlReaderSettings settings = new XmlReaderSettings();
1045
                settings.DtdProcessing = DtdProcessing.Parse;   // must expand entity references
1046

    
1047

    
1048
                //((XmlTextReader)parser).Normalization = true;
1049
                /*if (whitespacePolicy != null) {
1050
                    int optioni = whitespacePolicy.ordinal();
1051
                    if (optioni == JWhitespace.XSLT)
1052
                    {
1053
                        options.setSpaceStrippingRule(WhitespacePolicy.PreserveAll.GetJWhiteSpaceStrippingPolicy());
1054
                        options.addFilter(whitespacePolicy.makeStripper());
1055
                    }
1056
                    else {
1057
                        options.setSpaceStrippingRule(whitespacePolicy.GetJWhiteSpaceStrippingPolicy());
1058
                    }
1059
                 
1060

    
1061
                }*/
1062

    
1063
                if (xmlResolver != null)
1064
                {
1065
                    settings.XmlResolver = xmlResolver;
1066
                }
1067

    
1068
                settings.ValidationType = (DtdValidation ? ValidationType.DTD : ValidationType.None);
1069

    
1070
                XmlReader parser = XmlReader.Create(input, settings, baseUri.ToString());
1071
                source = new JPullSource(new JDotNetPullProvider(parser));
1072
                source.setSystemId(baseUri.ToString());
1073
            }
1074

    
1075
            try
1076
            {
1077
                XdmNode node = (XdmNode)XdmNode.Wrap(builder.build(source).getUnderlyingNode());
1078
                node.SetProcessor(processor);
1079
                return node;
1080
            } catch (JXPathException ex)
1081
            { throw new StaticError(ex); }
1082

    
1083

    
1084
        }
1085

    
1086
        /// <summary>
1087
		/// Load an XML document supplied using a <c>TextReader</c>.
1088
        /// </summary>
1089
        /// <remarks>
1090
        /// <para>The document is parsed using the Microsoft <c>System.Xml</c> parser if the
1091
        /// "http://saxon.sf.net/feature/preferJaxpParser" property on the <c>Processor</c> is set to false;
1092
        /// otherwise it is parsed using the Apache Xerces XML parser.</para>
1093
        /// <para>Before calling this method, the <c>BaseUri</c> property must be set to identify the
1094
        /// base URI of this document, used for resolving any relative URIs contained within it.</para>
1095
        /// <para>Note that the Microsoft <c>System.Xml</c> parser does not report whether attributes are
1096
        /// defined in the DTD as being of type <c>ID</c> and <c>IDREF</c>. This is true whether or not
1097
        /// DTD-based validation is enabled. This means that such attributes are not accessible to the 
1098
        /// <c>id()</c> and <c>idref()</c> functions.</para>         
1099
        /// </remarks>
1100
        /// <param name="input">The <c>TextReader</c> containing the XML source to be parsed</param>
1101
        /// <returns>An <c>XdmNode</c>, the document node at the root of the tree of the resulting
1102
        /// in-memory document.
1103
        /// </returns>
1104

    
1105
        public XdmNode Build(TextReader input)
1106
        {
1107
            if (baseUri == null)
1108
            {
1109
                throw new ArgumentException("No base URI supplied");
1110
            }
1111
            return Build(input, baseUri);
1112
        }
1113

    
1114
        // Build a document from a given stream, with the base URI supplied
1115
        // as an extra argument
1116

    
1117
        internal XdmNode Build(TextReader input, Uri baseUri)
1118
        {
1119
            JSource source;
1120
            JParseOptions options = new JParseOptions(config.getParseOptions());
1121
            if (processor.GetProperty("http://saxon.sf.net/feature/preferJaxpParser") == "true")
1122
            {
1123
                source = new JStreamSource(new JDotNetReader(input), baseUri.ToString());
1124
                options.setEntityResolver(new JDotNetURIResolver(XmlResolver));
1125
                source = augmentSource(source, options);
1126
            }
1127
            else
1128
            {
1129

    
1130
                XmlReaderSettings settings = new XmlReaderSettings();
1131
                settings.DtdProcessing = DtdProcessing.Parse;   // must expand entity references
1132

    
1133

    
1134
                //((XmlTextReader)parser).Normalization = true;
1135

    
1136
                if (xmlResolver != null)
1137
                {
1138
                    settings.XmlResolver = xmlResolver;
1139
                }
1140

    
1141
                settings.ValidationType = (DtdValidation ? ValidationType.DTD : ValidationType.None);
1142

    
1143
                XmlReader parser = XmlReader.Create(input, settings, baseUri.ToString());
1144
                source = new JPullSource(new JDotNetPullProvider(parser));
1145
                source.setSystemId(baseUri.ToString());
1146
            }
1147
            //augmentParseOptions(options);
1148
            JNodeInfo doc = null;
1149
            try
1150
            {
1151
                doc = builder.build(source).getUnderlyingNode(); //config.buildDocumentTree(source, options).getRootNode();
1152
            } catch (net.sf.saxon.s9api.SaxonApiException ex) {
1153
                throw new Exception(ex.getMessage());
1154
            }
1155
            return (XdmNode)XdmValue.Wrap(doc);
1156
        }
1157

    
1158
        private JSource augmentSource(JSource source, JParseOptions options)
1159
        {
1160

    
1161
            return new AugmentedSource(source, options);
1162
        }
1163

    
1164

    
1165
        /*private void augmentParseOptions(JParseOptions options)
1166
		{
1167
			if (validation != SchemaValidationMode.None)
1168
			{
1169
				
1170
				if (validation == SchemaValidationMode.Strict)
1171
				{
1172
					options.setSchemaValidationMode(JValidation.STRICT);
1173
				}
1174
				else if (validation == SchemaValidationMode.Lax)
1175
				{
1176
					options.setSchemaValidationMode(JValidation.LAX);
1177
				}
1178
				else if (validation == SchemaValidationMode.None)
1179
				{
1180
					options.setSchemaValidationMode(JValidation.STRIP);
1181
				}
1182
				else if (validation == SchemaValidationMode.Preserve)
1183
				{
1184
					options.setSchemaValidationMode(JValidation.PRESERVE);
1185
				}
1186
			}
1187
			if (topLevelElement != null)
1188
			{
1189
				
1190
				options.setTopLevelElement(
1191
					new FingerprintedQName(
1192
						topLevelElement.Prefix, topLevelElement.Uri.ToString(), topLevelElement.LocalName).getStructuredQName());
1193
			}
1194

    
1195
			if (whitespacePolicy != null)
1196
			{
1197
                int option = whitespacePolicy.ordinal();
1198
				if (option == JWhitespace.XSLT)
1199
				{
1200
                    options.setSpaceStrippingRule(WhitespacePolicy.PreserveAll.GetJWhiteSpaceStrippingPolicy());
1201
                    options.addFilter(whitespacePolicy.makeStripper());
1202
				}
1203
				else
1204
				{
1205
                    options.setSpaceStrippingRule(whitespacePolicy.GetJWhiteSpaceStrippingPolicy());
1206
                }
1207
			}
1208
			if (treeModel != TreeModel.Unspecified)
1209
			{
1210
				
1211
				if (treeModel == TreeModel.TinyTree)
1212
				{
1213
					options.setModel(net.sf.saxon.om.TreeModel.TINY_TREE);
1214
				}
1215
				else if (treeModel == TreeModel.TinyTreeCondensed)
1216
				{
1217
					options.setModel(net.sf.saxon.om.TreeModel.TINY_TREE_CONDENSED);
1218
				}
1219
				else
1220
				{
1221
					options.setModel(net.sf.saxon.om.TreeModel.LINKED_TREE);
1222
				}
1223
			}
1224
			if (lineNumbering)
1225
			{
1226

    
1227
				options.setLineNumbering(true);
1228
			}
1229
			if (dtdValidation)
1230
			{
1231
				
1232
				options.setDTDValidationMode(JValidation.STRICT);
1233
			}
1234
			if (projectionQuery != null) {
1235
				net.sf.saxon.s9api.XQueryExecutable exp = projectionQuery.getUnderlyingCompiledQuery();
1236
				net.sf.saxon.@event.FilterFactory ff = config.makeDocumentProjector(exp.getUnderlyingCompiledQuery());
1237
				if (ff != null) {
1238
					
1239
					options.addFilter (ff);
1240
				}
1241
			}
1242

    
1243
		} */
1244

    
1245
        /// <summary>
1246
        /// Load an XML document, delivered using an <c>XmlReader</c>.
1247
        /// </summary>
1248
        /// <remarks>
1249
        /// <para>The <c>XmlReader</c> is responsible for parsing the document; this method builds a tree
1250
        /// representation of the document (in an internal Saxon format) and returns its document node.
1251
        /// The <c>XmlReader</c> is not required to perform validation but it must expand any entity references.
1252
        /// Saxon uses the properties of the <c>XmlReader</c> as supplied.</para>
1253
        /// <para>Use of a plain <c>XmlTextReader</c> is discouraged, because it does not expand entity
1254
        /// references. This should only be used if you know in advance that the document will contain
1255
        /// no entity references (or perhaps if your query or stylesheet is not interested in the content
1256
        /// of text and attribute nodes). Instead, with .NET 1.1 use an <c>XmlValidatingReader</c> (with <c>ValidationType</c>
1257
        /// set to <c>None</c>). The constructor for <c>XmlValidatingReader</c> is obsolete in .NET 2.0,
1258
        /// but the same effect can be achieved by using the <c>Create</c> method of <c>XmlReader</c> with
1259
        /// appropriate <c>XmlReaderSettings</c>.</para>
1260
        /// <para>Conformance with the W3C specifications requires that the <c>Normalization</c> property
1261
        /// of an <c>XmlTextReader</c> should be set to <c>true</c>. However, Saxon does not insist
1262
        /// on this.</para>
1263
        /// <para>If the <c>XmlReader</c> performs schema validation, Saxon will ignore any resulting type
1264
        /// information. Type information can only be obtained by using Saxon's own schema validator, which
1265
        /// will be run if the <c>SchemaValidationMode</c> property is set to <c>Strict</c> or <c>Lax</c>.</para>
1266
        /// <para>Note that the Microsoft <c>System.Xml</c> parser does not report whether attributes are
1267
        /// defined in the DTD as being of type <c>ID</c> and <c>IDREF</c>. This is true whether or not
1268
        /// DTD-based validation is enabled. This means that such attributes are not accessible to the 
1269
        /// <c>id()</c> and <c>idref()</c> functions.</para>
1270
        /// <para>Note that setting the <c>XmlResolver</c> property of the <c>DocumentBuilder</c>
1271
        /// has no effect when this method is used; if an <c>XmlResolver</c> is required, it must
1272
        /// be set on the <c>XmlReader</c> itself.</para>
1273
        /// </remarks>
1274
        /// <param name="reader">The <c>XMLReader</c> that supplies the parsed XML source</param>
1275
        /// <returns>An <c>XdmNode</c>, the document node at the root of the tree of the resulting
1276
        /// in-memory document.
1277
        /// </returns>
1278

    
1279
        public XdmNode Build(XmlReader reader)
1280
        {
1281
            JPullProvider pp = new JDotNetPullProvider(reader);
1282
            pp.setPipelineConfiguration(config.makePipelineConfiguration());
1283
            // pp = new PullTracer(pp);  /* diagnostics */
1284
            JSource source = new JPullSource(pp);
1285
            source.setSystemId(reader.BaseURI);
1286
            JParseOptions options = new JParseOptions(config.getParseOptions());
1287

    
1288
            source = augmentSource(source, options);
1289
            JNodeInfo doc = builder.build(source).getUnderlyingNode(); //config.buildDocumentTree(source, options).getRootNode();
1290
            return (XdmNode)XdmValue.Wrap(doc);
1291
        }
1292

    
1293
        /// <summary>
1294
		/// Load an XML DOM document, supplied as an <c>XmlNode</c>, into a Saxon <c>XdmNode</c>.
1295
        /// </summary>
1296
        /// <remarks>
1297
        /// <para>
1298
        /// The returned document will contain only the subtree rooted at the supplied node.
1299
        /// </para>
1300
        /// <para>
1301
        /// This method copies the DOM tree to create a Saxon tree. See the <c>Wrap</c> method for
1302
        /// an alternative that creates a wrapper around the DOM tree, allowing it to be modified in situ.
1303
        /// </para>
1304
        /// </remarks>
1305
        /// <param name="source">The DOM Node to be copied to form a Saxon tree</param>
1306
        /// <returns>An <c>XdmNode</c>, the document node at the root of the tree of the resulting
1307
        /// in-memory document.
1308
        /// </returns>
1309

    
1310
        public XdmNode Build(XmlNode source)
1311
        {
1312
            return Build(new XmlNodeReader(source));
1313
        }
1314

    
1315

    
1316
        /// <summary>
1317
        /// Wrap an XML DOM document, supplied as an <c>XmlNode</c>, as a Saxon <c>XdmNode</c>.
1318
        /// </summary>
1319
        /// <remarks>
1320
        /// <para>
1321
        /// This method must be applied at the level of the Document Node. Unlike the
1322
        /// <c>Build</c> method, the original DOM is not copied. This saves memory and
1323
        /// time, but it also means that it is not possible to perform operations such as
1324
        /// whitespace stripping and schema validation.
1325
        /// </para>
1326
        /// </remarks>
1327
        /// <param name="doc">The DOM document node to be wrapped</param>
1328
        /// <returns>An <c>XdmNode</c>, the Saxon document node at the root of the tree of the resulting
1329
        /// in-memory document.
1330
        /// </returns>
1331

    
1332
        public XdmNode Wrap(XmlDocument doc)
1333
        {
1334
            String baseu = (baseUri == null ? null : baseUri.ToString());
1335
            JDotNetDocumentWrapper wrapper = new JDotNetDocumentWrapper(doc, baseu, config);
1336
            return (XdmNode)XdmValue.Wrap(wrapper.getRootNode());
1337
        }
1338
    }
1339

    
1340
    /// <summary>The default Logger used by Saxon on the .NET platform. All messages are written by
1341
    /// default to System.err. The logger can be configured by setting a different output
1342
    /// destination, and by setting a minimum threshold for the severity of messages to be output.</summary>
1343

    
1344
    public class StandardLogger : JLogger {
1345

    
1346
        private TextWriter outi = Console.Error;
1347
        JDotNetWriter writer;
1348
        int threshold = JLogger.INFO;
1349
        java.io.PrintStream stream;
1350

    
1351
        /// <summary>
1352
        /// Default constructor that wraps a <c>TextWriter</c> to write Saxon messages
1353
        /// </summary>
1354
		public StandardLogger() {
1355
            writer = new JDotNetWriter(outi);
1356
        }
1357

    
1358
        /// <summary>
1359
        /// Constructor method to supply a user defined TextWriter to the logger
1360
        /// </summary>
1361
        /// <param name="w"></param>
1362
		public StandardLogger(TextWriter w) {
1363
            writer = new JDotNetWriter(w);
1364

    
1365
        }
1366

    
1367
        /// <summary>
1368
        /// Property to get the udnerlying TextWriter object.
1369
        /// </summary>
1370
		public JDotNetWriter UnderlyingTextWriter {
1371
            set {
1372
                writer = value;
1373
            }
1374
            get {
1375
                return writer;
1376
            }
1377
        }
1378

    
1379
        /// <summary> Set the minimum threshold for the severity of messages to be output. Defaults to
1380
        /// <see cref="net.sf.saxon.lib.Logger#INFO"/>. Messages whose severity is below this threshold will be ignored. </summary>
1381
        /// <param name="threshold">the minimum severity of messages to be output. </param>
1382

    
1383
        public int Threshold {
1384

    
1385
            set {
1386
                threshold = value;
1387
            }
1388

    
1389
            get {
1390
                return threshold;
1391
            }
1392

    
1393
        }
1394

    
1395
        /// <summary>
1396
        /// Java internal streamResult object wrapping the TextWriter
1397
        /// </summary>
1398
        /// <returns></returns>
1399
        public override JStreamResult asStreamResult()
1400
        {
1401
            return new JStreamResult(writer);
1402
        }
1403

    
1404
        /// <summary>
1405
        /// Write the message to the TextWriter object
1406
        /// </summary>
1407
        /// <param name="str">The message</param>
1408
        /// <param name="severity">the severity of the error message</param>
1409
        public override void println(string str, int severity)
1410
        {
1411
            if (severity >= threshold) {
1412
                writer.write(str);
1413
            }
1414
        }
1415
    }
1416

    
1417

    
1418
    /// <summary>
1419
    /// Enumeration identifying the various Schema validation modes
1420
    /// </summary>
1421

    
1422
    public enum SchemaValidationMode
1423
    {
1424
        /// <summary>No validation (or strip validation, which removes existing type annotations)</summary> 
1425
        None,
1426
        /// <summary>Strict validation</summary>
1427
        Strict,
1428
        /// <summary>Lax validation</summary>
1429
        Lax,
1430
        /// <summary>Validation mode preserve, which preserves any existing type annotations</summary>
1431
        Preserve,
1432
        /// <summary>Unspecified validation: this means that validation is defined elsewhere, for example in the
1433
		/// Saxon <c>Configuration</c></summary>
1434
        Unspecified
1435
    }
1436

    
1437

    
1438
    /// <summary>
1439
    /// Identifiies a host language in which XPath expressions appear. Generally used when different error codes
1440
    /// need to be returned depending on the host language.
1441
    /// </summary>
1442
    public enum HostLanguage
1443
    {
1444
        XSLT,
1445
        XQUERY,
1446
        XML_SCHEMA,
1447
        XPATH,
1448
        XSLT_PATTERN
1449
    }
1450

    
1451

    
1452
    internal class JPredicateImpl : java.util.function.Predicate
1453
    {
1454

    
1455
        System.Predicate<QName> predicate;
1456

    
1457
        public JPredicateImpl(System.Predicate<QName> p) {
1458
            predicate = p;
1459

    
1460
        }
1461

    
1462
        public Predicate and(Predicate value1, Predicate value2)
1463
        {
1464
            throw new NotImplementedException();
1465
        }
1466

    
1467
        public Predicate negate(Predicate value)
1468
        {
1469
            throw new NotImplementedException();
1470
        }
1471

    
1472
        public Predicate or(Predicate value1, Predicate value2)
1473
        {
1474
            throw new NotImplementedException();
1475
        }
1476

    
1477
        public Predicate and(Predicate other)
1478
        {
1479
            throw new NotImplementedException();
1480
        }
1481

    
1482
        public Predicate isEqual(object targetRef)
1483
        {
1484
            throw new NotImplementedException();
1485
        }
1486

    
1487
        public Predicate negate()
1488
        {
1489
            throw new NotImplementedException();
1490
        }
1491

    
1492
        public Predicate or(Predicate other)
1493
        {
1494
            throw new NotImplementedException();
1495
        }
1496

    
1497
        public bool test(object t)
1498
        {
1499
            return predicate.Invoke(new QName((net.sf.saxon.s9api.QName)t));
1500
        }
1501
    }
1502

    
1503

    
1504

    
1505
    /// <summary>
1506
    /// <c>WhitespacePolicy</c> is a class defining the possible policies for handling
1507
    /// whitespace text nodes in a source document.
1508
    /// </summary>
1509
    /// <remarks>
1510
    /// Please note that since Saxon 9.7.0.8 this class has been refactored from the enumeration
1511
    /// type with the same name and therefore will work as before.
1512
    /// </remarks>
1513

    
1514
    [Serializable]
1515
    public class WhitespacePolicy
1516
    {
1517
       private int policy;
1518
       JWhiteSpaceStrippingPolicy strippingPolicy = null;
1519

    
1520
        /// <summary>All whitespace text nodes are stripped</summary>
1521
        public static WhitespacePolicy StripAll = new WhitespacePolicy(JWhitespace.ALL, JWhiteSpaceStrippingPolicy.ALL);
1522

    
1523
        /// <summary>Whitespace text nodes appearing in element-only content are stripped</summary>
1524
        public static WhitespacePolicy StripIgnorable = new WhitespacePolicy(JWhitespace.IGNORABLE, JWhiteSpaceStrippingPolicy.IGNORABLE);
1525

    
1526
        /// <summary>No whitespace is stripped</summary>
1527
        public static WhitespacePolicy PreserveAll = new WhitespacePolicy(JWhitespace.NONE, JWhiteSpaceStrippingPolicy.NONE);
1528

    
1529
        /// <summary>Unspecified means that no other value has been specifically requested</summary>
1530
        public static WhitespacePolicy Unspecified = new WhitespacePolicy(JWhitespace.UNSPECIFIED,  null);
1531

    
1532
        private WhitespacePolicy(int policy, JWhiteSpaceStrippingPolicy strippingPolicy)
1533
        {
1534
            this.policy = policy;
1535
            this.strippingPolicy = strippingPolicy;
1536
        }
1537

    
1538

    
1539
        internal JWhiteSpaceStrippingPolicy GetJWhiteSpaceStrippingPolicy() {
1540
            if (strippingPolicy != null) {
1541
                return strippingPolicy;
1542
            }
1543
            return null;
1544
        }
1545

    
1546

    
1547
        internal WhitespacePolicy(JXsltExecutable executable)
1548
        {
1549
            policy = Whitespace.XSLT;
1550
            strippingPolicy = executable.getWhitespaceStrippingPolicy();
1551
        }
1552

    
1553

    
1554
        /// <summary>
1555
        /// Create a custom whitespace stripping policy
1556
        /// </summary>
1557
        /// <param name="elementTest">a predicate applied to element names, which should return true if whitespace-only
1558
        /// text node children of the element are to be stripped, false if they are to be retained.</param>
1559
		/// <returns>A <c>WhitespacePolicy</c> object</returns>
1560
        [Obsolete("This method has been replaced by MakeCustomPolicy.")]
1561
        public static WhitespacePolicy makeCustomPolicy(System.Predicate<QName> elementTest) {
1562
            JWhiteSpaceStrippingPolicy policy = JWhiteSpaceStrippingPolicy.makeCustomPolicy(new JPredicateImpl(elementTest));
1563
            WhitespacePolicy wsp = new WhitespacePolicy(JWhitespace.XSLT, null);
1564
            wsp.strippingPolicy = policy;
1565
            return wsp;
1566
        }
1567

    
1568
        /// <summary>
1569
        /// Create a custom whitespace stripping policy
1570
        /// </summary>
1571
        /// <param name="elementTest">a predicate applied to element names, which should return true if whitespace-only
1572
        /// text node children of the element are to be stripped, false if they are to be retained.</param>
1573
        /// <returns>A <c>WhitespacePolicy</c> object</returns>
1574
        public static WhitespacePolicy MakeCustomPolicy(System.Predicate<QName> elementTest)
1575
        {
1576
            JWhiteSpaceStrippingPolicy policy = JWhiteSpaceStrippingPolicy.makeCustomPolicy(new JPredicateImpl(elementTest));
1577
            WhitespacePolicy wsp = new WhitespacePolicy(JWhitespace.XSLT, null);
1578
            wsp.strippingPolicy = policy;
1579
            return wsp;
1580
        }
1581

    
1582
        internal int ordinal() {
1583
            return policy;
1584
        }
1585

    
1586
        /*internal net.sf.saxon.@event.FilterFactory makeStripper() {
1587
            return new FilterFactory(strippingPolicy);
1588
        }      */ 
1589

    
1590
    }
1591

    
1592

    
1593

    
1594
    internal class SpaceStrippingRule : net.sf.saxon.om.SpaceStrippingRule
1595
    {
1596
        private System.Predicate<QName> elementTest;
1597

    
1598
        public SpaceStrippingRule(System.Predicate<QName> elementTest)
1599
        {
1600
            this.elementTest = elementTest;
1601
        }
1602

    
1603
        public void export(JExpressionPresenter ep)
1604
        {
1605
            throw new NotImplementedException(); 
1606
        }
1607

    
1608

    
1609
        public int isSpacePreserving(NodeName nn, JSchemaType st)
1610
        {
1611
            return elementTest(new QName(nn.getStructuredQName().ToString())) ?
1612
                JStripper.ALWAYS_STRIP :
1613
                JStripper.ALWAYS_PRESERVE;
1614
        }
1615

    
1616
        public JProxyReceiver makeStripper(JReceiver r)
1617
        {
1618
            return new net.sf.saxon.@event.Stripper(this, r);
1619
        }
1620
    }
1621

    
1622
    internal class FilterFactory : JFilterFactory
1623
    {
1624
        JSpaceStrippingRule stripperRules;
1625
        public FilterFactory(JSpaceStrippingRule sr)
1626
        {
1627
            stripperRules = sr;
1628
        }
1629
        public JProxyReceiver makeFilter(JReceiver r)
1630
        {
1631
            return new net.sf.saxon.@event.Stripper(stripperRules, r);
1632
        }
1633

    
1634
        JReceiver JFilterFactory.makeFilter(JReceiver r)
1635
        {
1636
            return (JReceiver)new JStripper(stripperRules, r);
1637
        }
1638
    }
1639

    
1640
    /// <summary>
1641
    /// Enumeration identifying the different tree model implementations
1642
    /// </summary>
1643
    /// 
1644
    public enum TreeModel
1645
    {
1646
        /// <summary>
1647
        /// Saxon <c>LinkedTree</c>. This tree model is primarily useful when using XQuery Update, since it is the
1648
        /// only standard tree model to support updates.
1649
        /// </summary>
1650
        LinkedTree,
1651
        /// <summary>
1652
		/// Saxon <c>TinyTree</c>. This is the default model and is suitable for most purposes.
1653
        /// </summary>
1654
        TinyTree,
1655
        /// <summary>
1656
		/// Saxon Condensed <c>TinyTree</c>. This is a variant of the <c>TinyTree</c> that shares storage for 
1657
        /// duplicated text and attribute nodes. It gives a further saving in space occupied, at the cost
1658
        /// of some increase in the time taken for tree construction.
1659
        /// </summary>
1660
        TinyTreeCondensed,
1661
        /// <summary>
1662
        /// Unspecified tree model. This value is used to indicate that there is no preference for any specific
1663
        /// tree model, which allows the choice to fall back to other interfaces.
1664
        /// </summary>
1665
        Unspecified = -1
1666
    }
1667

    
1668
    internal class DotNetObjectModelDefinition : JDotNetObjectModel
1669
    {
1670

    
1671
        public override bool isXdmValue(object obj)
1672
        {
1673
            return obj is XdmValue;
1674
        }
1675

    
1676
        public override bool isXdmAtomicValueType(System.Type type)
1677
        {
1678
            return typeof(XdmAtomicValue).IsAssignableFrom(type);
1679
        }
1680

    
1681
        public override bool isXdmValueType(System.Type type)
1682
        {
1683
            return typeof(XdmValue).IsAssignableFrom(type);
1684
        }
1685

    
1686
        public override JSequence unwrapXdmValue(object obj)
1687
        {
1688
            return ((XdmValue)obj).Unwrap();
1689
        }
1690

    
1691
        public override object wrapAsXdmValue(JSequence value)
1692
        {
1693
            return XdmValue.Wrap(value);
1694
        }
1695

    
1696
        public override bool isXmlNodeType(System.Type type)
1697
        {
1698
            return typeof(System.Xml.XmlNode).IsAssignableFrom(type);
1699
        }
1700

    
1701
    }
1702

    
1703
}
1704

    
1705
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1706
// Copyright (c) 2020 Saxonica Limited.
1707
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
1708
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
1709
// This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0.
1710
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
(1-1/11)