Project

Profile

Help

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

he / latest10 / hen / csource / api / Configuration.cs @ aac4a1be

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

    
71
        internal Processor(JProcessor p) {
72
            processor = p;
73
            processor.getUnderlyingConfiguration().setProcessor(this);
74
        }
75

    
76
        /// <summary>
77
        /// Create a new <c>Processor</c>. This <c>Processor</c> will have capabilities that depend on the version
78
        /// of the software that has been loaded, and on the features that have been licensed.
79
        /// </summary>
80

    
81
        public Processor()
82
        {
83
            processor = new JProcessor(false);
84
            processor.getUnderlyingConfiguration().setProcessor(this);
85
            processor.getUnderlyingConfiguration().registerExternalObjectModel(new DotNetObjectModelDefinition());
86
        }
87

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

    
97
        public Processor(bool licensedEdition)
98
            // newline needed by documentation stylesheet
99
            : this(licensedEdition, false) { }
100

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

    
111
        public Processor(bool licensedEdition, bool loadLocally)
112
        {
113
            processor = new JProcessor(licensedEdition);
114
            processor.getUnderlyingConfiguration().registerExternalObjectModel(new DotNetObjectModelDefinition());
115
        }
116

    
117
        /// <summary>
118
        /// Create a <c>Processor</c>, based on configuration information supplied in a configuration file.
119
        /// </summary>
120
        /// <param name="configurationFile">A stream holding the text of the XML configuration file. Details of the file format
121
        /// can be found in the Saxon documentation.</param>
122

    
123
        [Obsolete("Use the Processor(Stream, Uri) constructor instead.")]
124
        public Processor(Stream configurationFile)
125
        {
126
            JStreamSource ss = new JStreamSource(new JDotNetInputStream(configurationFile));
127
            JConfiguration config = JConfiguration.readConfiguration(ss);
128
            config.registerExternalObjectModel(new DotNetObjectModelDefinition());
129
            processor = new JProcessor(config);
130
        }
131

    
132
        /// <summary>
133
        /// Create a <c>Processor</c>, based on configuration information supplied in a configuration file.
134
        /// </summary>
135
        /// <param name="configurationFile">A stream holding the text of the XML configuration file. Details of the file format
136
        /// can be found in the Saxon documentation.</param>
137
        /// <param name="baseUri">baseUri of the configuration file used for resolving any relative URIs in the file</param> 
138

    
139
        public Processor(Stream configurationFile, Uri baseUri)
140
        {
141
            JStreamSource ss = new JStreamSource(new JDotNetInputStream(configurationFile), baseUri.AbsoluteUri);
142
            JConfiguration config = JConfiguration.readConfiguration(ss);
143
            config.registerExternalObjectModel(new DotNetObjectModelDefinition());
144
            processor = new JProcessor(config);
145
        }
146

    
147

    
148
        /// <summary>
149
        /// Declare a mapping from a specific namespace URI to a .NET class
150
        /// This will get applied to Saxon-PEN or Saxon-EEN product
151
        /// </summary>
152
        /// <param name="uri">the namespace URI of the function name</param>
153
        /// <param name="type">the .NET class that implements the functions in this namespace</param>
154
        public void BindExtensions(string uri, System.Type type) {
155
            JConfiguration config = processor.getUnderlyingConfiguration();
156
            config.bindExtensions(uri, type);
157
        }
158

    
159

    
160

    
161

    
162
        /// <summary>
163
		/// Get the full name of the Saxon product version implemented by this <c>Processor</c>
164
        /// </summary>
165

    
166
        public string ProductTitle
167
        {
168
            get { return JVersion.getProductTitle(); }
169
        }
170

    
171
        /// <summary>
172
        /// Get the Saxon product version number (for example, "9.2.0.2")
173
        /// </summary>
174

    
175
        public string ProductVersion
176
        {
177
            get { return JVersion.getProductVersion(); }
178
        }
179

    
180
        /// <summary>
181
        /// Get the Saxon product edition (for example, "EE" for Enterprise Edition)
182
        /// </summary>
183
        /// 
184

    
185
        public string Edition
186
        {
187
            get { return processor.getUnderlyingConfiguration().getEditionCode(); }
188
        }
189

    
190

    
191

    
192
        /// <summary>
193
		/// Gets the <c>SchemaManager</c> for the <c>Processor</c>. Returns null
194
		/// if the <c>Processor</c> is not schema-aware.
195
        /// </summary>
196

    
197
        public SchemaManager SchemaManager
198
        {
199
            get {
200
                if (schemaManager == null)
201
                {
202
                    schemaManager = new SchemaManager(this);
203
                }
204

    
205
                return schemaManager; }
206
        }
207

    
208
        /// <summary>
209
		/// An <c>XmlResolver</c>, which will be used while compiling and running queries, 
210
		/// XPath expressions, and stylesheets, if no other <c>XmlResolver</c> is nominated
211
        /// </summary>
212
        /// <remarks>
213
        /// <para>By default an <c>XmlUrlResolver</c> is used. This means that the responsibility
214
        /// for resolving and dereferencing URIs rests with the .NET platform, not with the
215
        /// IKVM/OpenJDK runtime.</para>
216
        /// <para>When Saxon invokes a user-written <c>XmlResolver</c>, the <c>GetEntity</c> method
217
        /// may return any of: a <c>System.IO.Stream</c>; a <c>System.IO.TextReader</c>; or a
218
        /// <c>java.xml.transform.Source</c>.</para>
219
        /// </remarks>
220

    
221
        public XmlResolver XmlResolver
222
        {
223
            get
224
            {
225
                javax.xml.transform.URIResolver resolver = processor.getUnderlyingConfiguration().getURIResolver();
226
                if (resolver is JDotNetURIResolver) {
227
                    return ((JDotNetURIResolver)resolver).getXmlResolver();
228
                } else {
229
                    return new XmlUrlResolver();
230
                }
231
            }
232
            set
233
            {
234
                processor.getUnderlyingConfiguration().setURIResolver(new JDotNetURIResolver(value));
235
            }
236
        }
237

    
238

    
239
        /// <summary>
240
		/// A <c>TextWriter</c> used as the destination of miscellaneous error, warning, and progress messages.
241
        /// </summary>
242
        /// <remarks>
243
        /// <para>By default the <c>Console.Error</c> is used for all such messages.</para>
244
        /// <para>A user can supply their own <c>TextWriter</c> to redirect error messages from the standard output.</para>
245
        /// </remarks>
246
        public TextWriter ErrorWriter
247
        {
248
            get
249
            {
250
                return textWriter;
251
            }
252
            set
253
            {
254
                textWriter = value;
255
                StandardLogger logger = new StandardLogger(value);
256
                processor.getUnderlyingConfiguration().setLogger(logger);
257
            }
258
        }
259

    
260
        /// <summary>
261
        /// Create a new <c>DocumentBuilder</c>, which may be used to build XDM documents from
262
        /// a variety of sources.
263
        /// </summary>
264
        /// <returns>A new <c>DocumentBuilder</c></returns>
265

    
266
        public DocumentBuilder NewDocumentBuilder()
267
        {
268
            DocumentBuilder builder = new DocumentBuilder(this);
269
            builder.XmlResolver = XmlResolver;
270
            return builder;
271
        }
272

    
273
        /// <summary>
274
		/// Create a new <c>XQueryCompiler</c>, which may be used to compile XQuery queries.
275
        /// </summary>
276
        /// <remarks>
277
		/// The returned <c>XQueryCompiler</c> retains a live link to the <c>Processor</c>, and
278
		/// may be affected by subsequent changes to the <c>Processor</c>.
279
        /// </remarks>
280
		/// <returns>A new <c>XQueryCompiler</c></returns>
281

    
282
        public XQueryCompiler NewXQueryCompiler()
283
        {
284
            return new XQueryCompiler(this);
285
        }
286

    
287
        /// <summary>
288
		/// Create a new <c>XsltCompiler</c>, which may be used to compile XSLT stylesheets.
289
        /// </summary>
290
        /// <remarks>
291
		/// The returned <c>XsltCompiler</c> retains a live link to the <c>Processor</c>, and
292
		/// may be affected by subsequent changes to the <c>Processor</c>.
293
        /// </remarks>
294
		/// <returns>A new <c>XsltCompiler</c></returns>
295

    
296
        public XsltCompiler NewXsltCompiler()
297
        {
298
            return new XsltCompiler(this);
299
        }
300

    
301
        /// <summary>
302
		/// Create a new <c>XPathCompiler</c>, which may be used to compile XPath expressions.
303
        /// </summary>
304
        /// <remarks>
305
		/// The returned <c>XPathCompiler</c> retains a live link to the <c>Processor</c>, and
306
		/// may be affected by subsequent changes to the <c>Processor</c>.
307
        /// </remarks>
308
		/// <returns>A new <c>XPathCompiler</c></returns>
309

    
310
        public XPathCompiler NewXPathCompiler()
311
        {
312
            return new XPathCompiler(this, JProcessor.newXPathCompiler());
313
        }
314

    
315
        /// <summary>
316
		/// Create a <c>Serializer</c>
317
        /// </summary>
318
		/// <returns> a new <c>Serializer</c> </returns>
319
        public Serializer NewSerializer() {
320
            Serializer s = new Serializer(processor.newSerializer());
321
            s.SetProcessor(this); //TODO this method call might no longer be needed
322
            return s;
323
        }
324

    
325
        /// <summary>
326
        /// Create a <c>Serializer</c> initialized to write to a given <c>TextWriter</c>.
327
        /// Closing the writer after use is the responsibility of the caller.
328
        /// </summary>
329
        /// <param name="textWriter">The <c>TextWriter</c> to which the <c>Serializer</c> will write</param>
330
        /// <returns> a new <c>Serializer</c> </returns>
331
        public Serializer NewSerializer(TextWriter textWriter)
332
        {
333
            Serializer s = new Serializer(processor.newSerializer());
334
            s.SetOutputWriter(textWriter);
335
            return s;
336
        }
337

    
338
        /// <summary>
339
        /// Create a <c>Serializer</c> initialized to write to a given output <c>Stream</c>.
340
        /// Closing the output stream after use is the responsibility of the caller.
341
        /// </summary>
342
        /// <param name="stream">The output <c>Stream</c> to which the <c>Serializer</c> will write</param>
343
        /// <returns> a new Serializer </returns>
344
        public Serializer NewSerializer(Stream stream)
345
        {
346
            Serializer s = new Serializer(processor.newSerializer());
347
            s.SetOutputStream(stream);
348
            return s;
349
        }
350

    
351
        /// <summary>
352
        /// The XML version used in this <c>Processor</c>
353
        /// </summary>
354
        /// <remarks>
355
        /// The value must be 1.0 or 1.1, as a <c>decimal</c>. The default version is currently 1.0, but may
356
        /// change in the future.
357
        /// </remarks>
358

    
359
        public decimal XmlVersion
360
        {
361
            get
362
            {
363
                return (processor.getUnderlyingConfiguration().getXMLVersion() == JConfiguration.XML10 ? 1.0m : 1.1m);
364
            }
365
            set
366
            {
367
                if (value == 1.0m)
368
                {
369
                    processor.setXmlVersion("1.0");
370
                }
371
                else if (value == 1.1m)
372
                {
373
                    processor.setXmlVersion("1.1");
374
                }
375
                else
376
                {
377
                    throw new ArgumentException("Invalid XML version: " + value);
378
                }
379
            }
380
        }
381

    
382
        /// <summary>
383
        /// Create a collation based on a given <c>CompareInfo</c> and <c>CompareOptions</c>    
384
        /// </summary>
385
        /// <param name="uri">The collation URI to be used within an XPath expression to refer to this collation</param>
386
        /// <param name="compareInfo">The <c>CompareInfo</c>, which determines the language-specific
387
        /// collation rules to be used</param>
388
        /// <param name="options">Options to be used in performing comparisons, for example
389
        /// whether they are to be case-blind and/or accent-blind</param>
390

    
391
        public void DeclareCollation(Uri uri, CompareInfo compareInfo, CompareOptions options)
392
        {
393
            JDotNetComparator comparator = new JDotNetComparator(uri.ToString(), compareInfo, options);
394
            Implementation.registerCollation(uri.ToString(), comparator);
395
        }
396

    
397
        /// <summary>
398
        /// Register a named collection. A collection is identified by a URI (the collection URI),
399
        /// and its content is represented by an <c>IEnumerable</c> that enumerates the contents
400
        /// of the collection. The values delivered by this enumeration are Uri values, which 
401
        /// can be mapped to nodes using the registered <c>XmlResolver</c>.
402
        /// </summary>
403
        /// <param name="collectionUri">The URI used to identify the collection in a call
404
        /// of the XPath <c>collection()</c> function. The default collection is registered
405
        /// by supplying null as the value of this argument (this is the collection returned
406
        /// when the XPath <c>collection()</c> function is called with no arguments).</param> 
407
        /// <param name="contents">An enumerable object that represents the contents of the
408
        /// collection, as a sequence of document URIs. The enumerator returned by this
409
        /// IEnumerable object must return instances of the Uri class.</param>
410
        /// <remarks>
411
        /// <para>Collections should be stable: that is, two calls to retrieve the same collection URI
412
        /// should return the same sequence of document URIs. This requirement is imposed by the
413
        /// W3C specifications, but in the case of a user-defined collection it is not enforced by
414
        /// the Saxon product.</para>
415
        /// <para>A collection may be replaced by specifying the URI of an existing
416
        /// collection.</para>
417
        /// <para>Collections registered with a processor are available to all queries and stylesheets
418
        /// running under the control of that processor. Collections should not normally be registered
419
        /// while queries and transformations are in progress.</para>
420
        /// </remarks>
421
        /// 
422

    
423
        public void RegisterCollection(Uri collectionUri, IEnumerable contents)
424
        {
425
            String u = (collectionUri == null ? null : collectionUri.ToString());
426
            JConfiguration config = processor.getUnderlyingConfiguration();
427
            config.registerCollection(u, new JDotNetEnumerableCollection(config, contents));
428
        }
429

    
430
        /// <summary>
431
		/// Register an extension function with the <c>Processor</c>
432
        /// </summary>
433
        /// <param name="function">
434
        /// An object that defines the extension function, including its name, arity, arguments types, and
435
        /// a reference to the class that implements the extension function call.
436
        /// </param>
437

    
438
        public void RegisterExtensionFunction(ExtensionFunctionDefinition function)
439
        {
440
            WrappedExtensionFunctionDefinition f = new WrappedExtensionFunctionDefinition(function);
441
            processor.registerExtensionFunction(f);
442
        }
443

    
444
        /// <summary>
445
        /// Register a simple external/extension function that is to be made available within any stylesheet, query
446
        /// or XPath expression compiled under the control of this <c>Processor</c>
447
        /// </summary>
448
        /// <param name="function">
449
        /// This interface provides only for simple extensions that have no side-effects and no
450
        /// dependencies on the static or dynamic context.
451
        /// </param>
452

    
453
        public void RegisterExtensionFunction(ExtensionFunction function)
454
        {
455
            WrappedExtensionFunction f = new WrappedExtensionFunction(function);
456
            processor.registerExtensionFunction(f);
457
        }
458

    
459
        /// <summary>
460
		/// Copy an <c>XdmValue</c> to an <c>XmlDestination</c>
461
        /// </summary>
462
        /// <remarks>
463
        /// In principle this method can be used to copy any kind of <c>XdmValue</c> to any kind
464
        /// of <c>XmlDestination</c>. However, some kinds of destination may not accept arbitrary
465
        /// sequences of items; for example, some may reject function items. Some destinations
466
        /// perform sequence normalization, as defined in the W3C serialization specification,
467
        /// to convert the supplied sequence to a well-formed XML document; it is a property
468
        /// of the chosen <c>XmlDestination</c> whether it does this or not.</remarks>
469
        /// <param name="sequence">The value to be written</param>
470
        /// <param name="destination">The destination to which the value should be written</param>
471
        /// 
472

    
473
        public void WriteXdmValue(XdmValue sequence, XmlDestination destination)
474
        {
475
            try
476
            {
477
                JPipelineConfiguration pipe = processor.getUnderlyingConfiguration().makePipelineConfiguration();
478
                JResult r = destination.GetUnderlyingDestination().getReceiver(pipe, pipe.getConfiguration().obtainDefaultSerializationProperties());
479
                r.open();
480
                foreach (XdmItem item in sequence) {
481
                    r.append(item.Unwrap().head());
482
                }
483
                r.close();
484
            } catch (JXPathException err) {
485
                throw new DynamicError(err);
486
            }
487
        }
488

    
489

    
490
        /// <summary>
491
		/// The underlying <c>Configuration</c> object in the Saxon implementation
492
        /// </summary>
493
        /// <remarks>
494
        /// <para>This property provides access to internal methods in the Saxon engine that are
495
        /// not specifically exposed in the .NET API. In general these methods should be
496
        /// considered to be less stable than the classes in the Saxon.Api namespace.</para> 
497
        /// <para>The internal methods follow
498
        /// Java naming conventions rather than .NET conventions.</para>
499
		/// <para>Information about the returned <see cref="net.sf.saxon.Configuration"/> object 
500
		/// (and the objects it provides access to) is included in the Saxon JavaDoc docmentation.
501
        /// </para>
502
        /// </remarks>
503

    
504
        public JConfiguration Implementation
505
        {
506
            get { return processor.getUnderlyingConfiguration(); }
507
        }
508

    
509
        /// <summary>
510
        /// A user-supplied <c>IQueryResolver</c> used to resolve location hints appearing in an
511
        /// <c>import module</c> declaration.
512
        /// </summary>
513
        /// <remarks>
514
        /// <para>This acts as the default value for the ModuleURIResolver.</para>
515
        /// <para> The URI Resolver for XQuery modules. May be null, in which case any 
516
        /// existing Module URI Resolver is removed  from the Configuration</para>
517
        /// </remarks>
518
        public IQueryResolver QueryResolver
519
        {
520
            get { return moduleResolver; }
521
            set
522
            {
523
                moduleResolver = value;
524
                processor.getUnderlyingConfiguration().setModuleURIResolver((value == null ? null : new DotNetModuleURIResolver(value)));
525
            }
526
        }
527

    
528
        /// <summary>
529
        /// The underlying <c>net.sf.saxon.s9api.Processor</c> in the Java implementation
530
        /// </summary>
531

    
532
        public JProcessor JProcessor
533
        {
534
            get { return processor; }
535
        }
536

    
537
        /// <summary>
538
        /// Set a configuration property
539
        /// </summary>
540
        /// <remarks>
541
        /// <para>This method provides the ability to set named properties of the configuration.
542
        /// The property names are set as strings, whose values can be found in the Java
543
        /// class <c>net.sf.saxon.FeatureKeys</c>. The property values are always strings. 
544
        /// Properties whose values are other types are not available via this interface:
545
        /// however all properties have an effective equivalent whose value is a string.
546
        /// Note that on/off properties are set using the strings "true" and "false".</para>
547
        /// <para><i>Method added in Saxon 9.1</i></para>
548
        /// </remarks>
549
        /// <param name="name">The property name</param>
550
        /// <param name="value">The property value</param>
551
        [Obsolete("Use the SetProperty<T>(Feature<T> feature, T value) method instead.")]
552
        public void SetProperty(String name, String value)
553
        {
554
            processor.setConfigurationProperty(net.sf.saxon.lib.Feature.byName(name), value);
555
        }
556

    
557
        /// <summary>
558
        /// Set a configuration property
559
        /// </summary>
560
        /// <param name="feature">The property feature</param>
561
        /// <param name="value">The property value</param>
562

    
563
        public void SetProperty<T>(Feature<T> feature, T value) {
564
            processor.setConfigurationProperty(feature.JFeature, value);
565
        }
566

    
567
        /// <summary>
568
        /// Get the value of a configuration property
569
        /// </summary>
570
        /// <remarks>
571
        /// <para>This method provides the ability to get named properties of the configuration.
572
        /// The property names are supplied as strings, whose values can be found in the Java
573
        /// class <c>net.sf.saxon.FeatureKeys</c>. The property values are always returned as strings. 
574
        /// Properties whose values are other types are returned by converting the value to a string.
575
        /// Note that on/off properties are returned using the strings "true" and "false".</para>
576
        /// <para><i>Method added in Saxon 9.1</i></para>
577
        /// </remarks>
578
        /// <param name="name">The property name</param>
579
        /// <returns>The property value, as a string; or null if the property is unset.</returns>
580

    
581
        public String GetProperty(String name)
582
        {
583
            Object obj = processor.getConfigurationProperty(net.sf.saxon.lib.Feature.byName(name));
584
            return (obj == null ? null : obj.ToString());
585
        }
586

    
587

    
588
        /// <summary>
589
        /// Get a property of the configuration
590
        /// </summary>
591
        /// <typeparam name="T">See the class <c>Feature</c> for constants 
592
        /// representing the properties that can be requested.</typeparam>
593
        /// <param name="feature">the required property. </param>
594
        /// <returns>the value of the property</returns>
595
        public T GetProperty<T>(Feature<T> feature) {
596
            return (T)processor.getConfigurationProperty(feature.JFeature);
597
        }
598

    
599
    }
600

    
601
    /// <summary>
602
    /// The <c>DocumentBuilder</c> class enables XDM documents to be built from various sources.
603
    /// The class is always instantiated using the <c>NewDocumentBuilder</c> method
604
    /// on the <c>Processor</c> object.
605
    /// </summary>
606

    
607
    [Serializable]
608
    public class DocumentBuilder
609
    {
610

    
611
        private Processor processor;
612
        private JConfiguration config;
613
        private XmlResolver xmlResolver;
614
        private SchemaValidationMode validation;
615
        private SchemaValidator schemaValidator;
616
        private WhitespacePolicy whitespacePolicy;
617
        private Uri baseUri;
618
        private QName topLevelElement;
619
        private XQueryExecutable projectionQuery;
620

    
621
        private JDocumentBuilder builder;
622

    
623

    
624
        internal DocumentBuilder(Processor processor)
625
        {
626
            this.processor = processor;
627
            this.builder = processor.JProcessor.newDocumentBuilder();
628
            this.config = processor.Implementation;
629
            this.xmlResolver = new XmlUrlResolver();
630
        }
631

    
632
        /// <summary>
633
		/// An <c>XmlResolver</c>, which will be used to resolve URIs of documents being loaded
634
        /// and of references to external entities within those documents (including any external DTD).
635
        /// </summary>
636
        /// <remarks>
637
        /// <para>By default an <c>XmlUrlResolver</c> is used. This means that the responsibility
638
        /// for resolving and dereferencing URIs rests with the .NET platform (and not with the
639
        /// GNU Classpath).</para>
640
        /// <para>When Saxon invokes a user-written <c>XmlResolver</c>, the <c>GetEntity</c> method
641
        /// may return any of: a <c>System.IO.Stream</c>; a <c>System.IO.TextReader</c>; or a
642
        /// <c>java.xml.transform.Source</c>. However, if the <c>XmlResolver</c> is called
643
        /// by the XML parser to resolve external entity references, then it must return an 
644
        /// instance of <c>System.IO.Stream</c>.</para>
645
        /// </remarks>
646

    
647
        public XmlResolver XmlResolver
648
        {
649
            get
650
            {
651
                return xmlResolver;
652
            }
653
            set
654
            {
655
                xmlResolver = value;
656
            }
657
        }
658

    
659
        /// <summary>
660
        /// Determines whether line numbering is enabled for documents loaded using this
661
        /// <c>DocumentBuilder</c>.
662
        /// </summary>
663
        /// <remarks>
664
        /// <para>By default, line numbering is disabled.</para>
665
        /// <para>Line numbering is not available for all kinds of source: in particular,
666
		/// it is not available when loading from an existing <c>XmlDocument</c>.</para>
667
        /// <para>The resulting line numbers are accessible to applications using the
668
		/// extension function <c>saxon:line-number()</c> applied to a node.</para>  
669
        /// <para>Line numbers are maintained only for element nodes; the line number
670
        /// returned for any other node will be that of the most recent element.</para> 
671
        /// </remarks>
672

    
673
        public bool IsLineNumbering
674
        {
675
            get
676
            {
677
                return builder.isLineNumbering();
678
            }
679
            set
680
            {
681
                builder.setLineNumbering(value);
682
            }
683
        }
684

    
685
        /// <summary>
686
        /// Determines whether schema validation is applied to documents loaded using this
687
        /// <c>DocumentBuilder</c>, and if so, whether it is strict or lax.
688
        /// </summary>
689
        /// <remarks>
690
        /// <para>By default, no schema validation takes place.</para>
691
        /// <para>This option requires Saxon Enterprise Edition (Saxon-EE).</para>
692
        /// </remarks>
693

    
694
        public SchemaValidationMode SchemaValidationMode
695
        {
696
            get
697
            {
698
                return validation;
699
            }
700
            set
701
            {
702
                validation = value;
703
            }
704
        }
705

    
706

    
707
        /// <summary>
708
        /// Property to set and get the schemaValidator to be used. This determines whether schema validation is applied
709
        /// to an input document and whether type annotations in a supplied document are retained. If no schemaValidator
710
        /// is supplied, then schema validation does not take place.
711
        /// </summary>
712
        public SchemaValidator SchemaValidator {
713
            get { return schemaValidator; }
714
            set {
715
                schemaValidator = value;
716
                builder.setSchemaValidator(schemaValidator == null ? null : schemaValidator.UnderlyingSchemaValidator);
717
            }
718
        }
719

    
720
        /// <summary>
721
        /// The required name of the top level element in a document instance being validated
722
        /// against a schema.
723
        /// </summary>
724
        /// <remarks>
725
        /// <para>If this property is set, and if schema validation is requested, then validation will
726
        /// fail unless the outermost element of the document has the required name.</para>
727
        /// <para>This option requires the schema-aware version of the Saxon product (Saxon-EE).</para>
728
        /// </remarks> 
729

    
730
        public QName TopLevelElementName
731
        {
732
            get
733
            {
734
                return topLevelElement;
735
            }
736
            set
737
            {
738
                topLevelElement = value;
739
                schemaValidator.UnderlyingSchemaValidator.setDocumentElementName(topLevelElement == null ? null : topLevelElement.UnderlyingQName());
740
            }
741
        }
742

    
743
        /// <summary>
744
        /// Determines whether DTD validation is applied to documents loaded using this
745
        /// <c>DocumentBuilder</c>.
746
        /// </summary>
747
        /// <remarks>
748
        /// <para>By default, no DTD validation takes place.</para>
749
        /// </remarks>
750

    
751
        public bool DtdValidation
752
        {
753
            get
754
            {
755
                return builder.isDTDValidation();
756
            }
757
            set
758
            {
759
                builder.setDTDValidation(value);
760
            }
761
        }
762

    
763
        /// <summary>
764
        /// Determines the whitespace stripping policy applied when loading a document
765
        /// using this <c>DocumentBuilder</c>.
766
        /// </summary>
767
        /// <remarks>
768
        /// <para>By default, whitespace text nodes appearing in element-only content
769
        /// are stripped, and all other whitespace text nodes are retained.</para>
770
        /// </remarks>
771

    
772
        public WhitespacePolicy WhitespacePolicy
773
        {
774
            get
775
            {
776
                return whitespacePolicy;
777
            }
778
            set
779
            {
780
                whitespacePolicy = value;
781
                builder.setWhitespaceStrippingPolicy(whitespacePolicy == null ? null : whitespacePolicy.GetJWhiteSpaceStrippingPolicy());
782
            }
783
        }
784

    
785

    
786

    
787
        ///<summary>
788
        /// The Tree Model implementation to be used for the constructed document. By default
789
		/// the <c>TinyTree</c> is used. The main reason for using the <c>LinkedTree</c> alternative is if
790
		/// updating is required (the <c>TinyTree</c> is not updateable).
791
        ///</summary>
792

    
793
        public TreeModel TreeModel
794
        {
795
            get
796
            {
797
                return (TreeModel)builder.getTreeModel().getSymbolicValue();
798
            }
799
            set
800
            {
801
                builder.setTreeModel(net.sf.saxon.om.TreeModel.getTreeModel((int)value));
802
            }
803
        }
804

    
805
        /// <summary>
806
        /// The base URI of a document loaded using this <c>DocumentBuilder</c>.
807
        /// This is used for resolving any relative URIs appearing
808
        /// within the document, for example in references to DTDs and external entities.
809
        /// </summary>
810
        /// <remarks>
811
        /// This information is required when the document is loaded from a source that does not
812
		/// provide an intrinsic URI, notably when loading from a <c>Stream</c> or a <c>TextReader</c>.
813
        /// </remarks>
814

    
815

    
816
        public Uri BaseUri
817
        {
818
            get { return baseUri; }
819
            set { baseUri = value;
820
                if (baseUri != null)
821
                {
822
                    builder.setBaseURI(new java.net.URI(value.AbsoluteUri));
823
                }
824
            }
825
        }
826

    
827

    
828
        /// <summary>
829
        /// Set a compiled query to be used for implementing document projection. 
830
        /// </summary>
831
        /// <remarks>
832
        /// <para>
833
        /// The effect of using this option is that the tree constructed by the 
834
        /// <c>DocumentBuilder</c> contains only those parts
835
        /// of the source document that are needed to answer this query. Running this query against
836
        /// the projected document should give the same results as against the raw document, but the
837
        /// projected document typically occupies significantly less memory. It is permissible to run
838
        /// other queries against the projected document, but unless they are carefully chosen, they
839
        /// will give the wrong answer, because the document being used is different from the original.
840
        /// </para>
841
        /// <para>The query should be written to use the projected document as its initial context item.
842
        /// For example, if the query is <code>//ITEM[COLOR='blue']</code>, then only <code>ITEM</code>
843
        /// elements and their <code>COLOR</code> children will be retained in the projected document.</para>
844
        /// <para>This facility is only available in Saxon-EE; if the facility is not available,
845
        /// calling this method has no effect.</para>
846
        /// </remarks>
847

    
848

    
849
        public XQueryExecutable DocumentProjectionQuery {
850
            get { return projectionQuery; }
851
            set {
852
                projectionQuery = value;
853
                builder.setDocumentProjectionQuery(projectionQuery == null ? null : projectionQuery.getUnderlyingCompiledQuery());
854
            }
855

    
856
        }
857

    
858
        /// <summary>
859
        /// Load an XML document, retrieving it via a URI.
860
        /// </summary>
861
        /// <remarks>
862
        /// <para>Note that the type <c>Uri</c> requires an absolute URI.</para>
863
        /// <para>The URI is dereferenced using the registered <c>XmlResolver</c>.</para>
864
        /// <para>This method takes no account of any fragment part in the URI.</para>
865
        /// <para>The <c>role</c> passed to the <c>GetEntity</c> method of the <c>XmlResolver</c> 
866
        /// is "application/xml", and the required return type is <c>System.IO.Stream</c>.</para>
867
        /// <para>The document located via the URI is parsed using the <c>System.Xml</c> parser.</para>
868
        /// <para>Note that the Microsoft <c>System.Xml</c> parser does not report whether attributes are
869
        /// defined in the DTD as being of type <c>ID</c> and <c>IDREF</c>. This is true whether or not
870
        /// DTD-based validation is enabled. This means that such attributes are not accessible to the 
871
        /// <c>id()</c> and <c>idref()</c> functions.</para>
872
        /// </remarks>
873
        /// <param name="uri">The URI identifying the location where the document can be
874
        /// found. This will also be used as the base URI of the document (regardless
875
		/// of the setting of the <c>BaseUri</c> property).</param>
876
		/// <returns>An <c>XdmNode</c>, the document node at the root of the tree of the resulting
877
		/// in-memory document.
878
		/// </returns>
879

    
880
        public XdmNode Build(Uri uri)
881
        {
882
            Object obj = XmlResolver.GetEntity(uri, "application/xml", System.Type.GetType("System.IO.Stream"));
883
            if (obj is Stream)
884
            {
885
                try
886
                {
887
                    return Build((Stream)obj, uri);
888
                }
889
                finally
890
                {
891
                    ((Stream)obj).Close();
892
                }
893
            }
894
            else
895
            {
896
                throw new ArgumentException("Invalid type of result from XmlResolver.GetEntity: " + obj);
897
            }
898
        }
899

    
900
        /// <summary>
901
		/// Load an XML document supplied as raw (lexical) XML on a <c>Stream</c>.
902
        /// </summary>
903
        /// <remarks>
904
        /// <para>The document is parsed using the Microsoft <c>System.Xml</c> parser if the
905
        /// "http://saxon.sf.net/feature/preferJaxpParser" property on the <c>Processor</c> is set to false;
906
        /// otherwise it is parsed using the Apache Xerces XML parser.</para>
907
        /// <para>Before calling this method, the <c>BaseUri</c> property must be set to identify the
908
        /// base URI of this document, used for resolving any relative URIs contained within it.</para>
909
        /// <para>Note that the Microsoft <c>System.Xml</c> parser does not report whether attributes are
910
        /// defined in the DTD as being of type <c>ID</c> and <c>IDREF</c>. This is true whether or not
911
        /// DTD-based validation is enabled. This means that such attributes are not accessible to the 
912
        /// <c>id()</c> and <c>idref()</c> functions.</para>         
913
        /// </remarks>
914
        /// <param name="input">The <c>Stream</c> containing the XML source to be parsed. Closing this stream
915
        /// on completion is the responsibility of the caller.</param>
916
        /// <returns>An <c>XdmNode</c>, the document node at the root of the tree of the resulting
917
        /// in-memory document.
918
        /// </returns>
919

    
920
        public XdmNode Build(Stream input)
921
        {
922
            if (baseUri == null)
923
            {
924
                throw new ArgumentException("No base URI supplied");
925
            }
926
            return Build(input, baseUri);
927
        }
928

    
929
        // Build a document from a given stream, with the base URI supplied
930
        // as an extra argument
931

    
932
        internal XdmNode Build(Stream input, Uri baseUri)
933
        {
934
            JSource source;
935
            JParseOptions options = new JParseOptions(config.getParseOptions());
936

    
937
            if (processor.GetProperty("http://saxon.sf.net/feature/preferJaxpParser") == "true")
938
            {
939
                source = new JStreamSource(new JDotNetInputStream(input), baseUri.ToString());
940
                options.setEntityResolver(new JDotNetURIResolver(XmlResolver));
941
                source = augmentSource(source, options);
942
            }
943
            else
944
            {
945

    
946
                XmlReaderSettings settings = new XmlReaderSettings();
947
                settings.DtdProcessing = DtdProcessing.Parse;   // must expand entity references
948

    
949

    
950
                //((XmlTextReader)parser).Normalization = true;
951
                /*if (whitespacePolicy != null) {
952
                    int optioni = whitespacePolicy.ordinal();
953
                    if (optioni == JWhitespace.XSLT)
954
                    {
955
                        options.setSpaceStrippingRule(WhitespacePolicy.PreserveAll.GetJWhiteSpaceStrippingPolicy());
956
                        options.addFilter(whitespacePolicy.makeStripper());
957
                    }
958
                    else {
959
                        options.setSpaceStrippingRule(whitespacePolicy.GetJWhiteSpaceStrippingPolicy());
960
                    }
961
                 
962

    
963
                }*/
964

    
965
                if (xmlResolver != null)
966
                {
967
                    settings.XmlResolver = xmlResolver;
968
                }
969

    
970
                settings.ValidationType = (DtdValidation ? ValidationType.DTD : ValidationType.None);
971

    
972
                XmlReader parser = XmlReader.Create(input, settings, baseUri.ToString());
973
                source = new JPullSource(new JDotNetPullProvider(parser));
974
                source.setSystemId(baseUri.ToString());
975
            }
976

    
977
            try
978
            {
979
                XdmNode node = (XdmNode)XdmNode.Wrap(builder.build(source).getUnderlyingNode());
980
                node.SetProcessor(processor);
981
                return node;
982
            } catch (JXPathException ex)
983
            { throw new StaticError(ex); }
984

    
985

    
986
        }
987

    
988
        /// <summary>
989
		/// Load an XML document supplied using a <c>TextReader</c>.
990
        /// </summary>
991
        /// <remarks>
992
        /// <para>The document is parsed using the Microsoft <c>System.Xml</c> parser if the
993
        /// "http://saxon.sf.net/feature/preferJaxpParser" property on the <c>Processor</c> is set to false;
994
        /// otherwise it is parsed using the Apache Xerces XML parser.</para>
995
        /// <para>Before calling this method, the <c>BaseUri</c> property must be set to identify the
996
        /// base URI of this document, used for resolving any relative URIs contained within it.</para>
997
        /// <para>Note that the Microsoft <c>System.Xml</c> parser does not report whether attributes are
998
        /// defined in the DTD as being of type <c>ID</c> and <c>IDREF</c>. This is true whether or not
999
        /// DTD-based validation is enabled. This means that such attributes are not accessible to the 
1000
        /// <c>id()</c> and <c>idref()</c> functions.</para>         
1001
        /// </remarks>
1002
        /// <param name="input">The <c>TextReader</c> containing the XML source to be parsed</param>
1003
        /// <returns>An <c>XdmNode</c>, the document node at the root of the tree of the resulting
1004
        /// in-memory document.
1005
        /// </returns>
1006

    
1007
        public XdmNode Build(TextReader input)
1008
        {
1009
            if (baseUri == null)
1010
            {
1011
                throw new ArgumentException("No base URI supplied");
1012
            }
1013
            return Build(input, baseUri);
1014
        }
1015

    
1016
        // Build a document from a given stream, with the base URI supplied
1017
        // as an extra argument
1018

    
1019
        internal XdmNode Build(TextReader input, Uri baseUri)
1020
        {
1021
            JSource source;
1022
            JParseOptions options = new JParseOptions(config.getParseOptions());
1023
            if (processor.GetProperty("http://saxon.sf.net/feature/preferJaxpParser") == "true")
1024
            {
1025
                source = new JStreamSource(new JDotNetReader(input), baseUri.ToString());
1026
                options.setEntityResolver(new JDotNetURIResolver(XmlResolver));
1027
                source = augmentSource(source, options);
1028
            }
1029
            else
1030
            {
1031

    
1032
                XmlReaderSettings settings = new XmlReaderSettings();
1033
                settings.DtdProcessing = DtdProcessing.Parse;   // must expand entity references
1034

    
1035

    
1036
                //((XmlTextReader)parser).Normalization = true;
1037

    
1038
                if (xmlResolver != null)
1039
                {
1040
                    settings.XmlResolver = xmlResolver;
1041
                }
1042

    
1043
                settings.ValidationType = (DtdValidation ? ValidationType.DTD : ValidationType.None);
1044

    
1045
                XmlReader parser = XmlReader.Create(input, settings, baseUri.ToString());
1046
                source = new JPullSource(new JDotNetPullProvider(parser));
1047
                source.setSystemId(baseUri.ToString());
1048
            }
1049
            //augmentParseOptions(options);
1050
            JNodeInfo doc = null;
1051
            try
1052
            {
1053
                doc = builder.build(source).getUnderlyingNode(); //config.buildDocumentTree(source, options).getRootNode();
1054
            } catch (net.sf.saxon.s9api.SaxonApiException ex) {
1055
                throw new Exception(ex.getMessage());
1056
            }
1057
            return (XdmNode)XdmValue.Wrap(doc);
1058
        }
1059

    
1060
        private JSource augmentSource(JSource source, JParseOptions options)
1061
        {
1062

    
1063
            return new AugmentedSource(source, options);
1064
        }
1065

    
1066

    
1067
        /*private void augmentParseOptions(JParseOptions options)
1068
		{
1069
			if (validation != SchemaValidationMode.None)
1070
			{
1071
				
1072
				if (validation == SchemaValidationMode.Strict)
1073
				{
1074
					options.setSchemaValidationMode(JValidation.STRICT);
1075
				}
1076
				else if (validation == SchemaValidationMode.Lax)
1077
				{
1078
					options.setSchemaValidationMode(JValidation.LAX);
1079
				}
1080
				else if (validation == SchemaValidationMode.None)
1081
				{
1082
					options.setSchemaValidationMode(JValidation.STRIP);
1083
				}
1084
				else if (validation == SchemaValidationMode.Preserve)
1085
				{
1086
					options.setSchemaValidationMode(JValidation.PRESERVE);
1087
				}
1088
			}
1089
			if (topLevelElement != null)
1090
			{
1091
				
1092
				options.setTopLevelElement(
1093
					new FingerprintedQName(
1094
						topLevelElement.Prefix, topLevelElement.Uri.ToString(), topLevelElement.LocalName).getStructuredQName());
1095
			}
1096

    
1097
			if (whitespacePolicy != null)
1098
			{
1099
                int option = whitespacePolicy.ordinal();
1100
				if (option == JWhitespace.XSLT)
1101
				{
1102
                    options.setSpaceStrippingRule(WhitespacePolicy.PreserveAll.GetJWhiteSpaceStrippingPolicy());
1103
                    options.addFilter(whitespacePolicy.makeStripper());
1104
				}
1105
				else
1106
				{
1107
                    options.setSpaceStrippingRule(whitespacePolicy.GetJWhiteSpaceStrippingPolicy());
1108
                }
1109
			}
1110
			if (treeModel != TreeModel.Unspecified)
1111
			{
1112
				
1113
				if (treeModel == TreeModel.TinyTree)
1114
				{
1115
					options.setModel(net.sf.saxon.om.TreeModel.TINY_TREE);
1116
				}
1117
				else if (treeModel == TreeModel.TinyTreeCondensed)
1118
				{
1119
					options.setModel(net.sf.saxon.om.TreeModel.TINY_TREE_CONDENSED);
1120
				}
1121
				else
1122
				{
1123
					options.setModel(net.sf.saxon.om.TreeModel.LINKED_TREE);
1124
				}
1125
			}
1126
			if (lineNumbering)
1127
			{
1128

    
1129
				options.setLineNumbering(true);
1130
			}
1131
			if (dtdValidation)
1132
			{
1133
				
1134
				options.setDTDValidationMode(JValidation.STRICT);
1135
			}
1136
			if (projectionQuery != null) {
1137
				net.sf.saxon.s9api.XQueryExecutable exp = projectionQuery.getUnderlyingCompiledQuery();
1138
				net.sf.saxon.@event.FilterFactory ff = config.makeDocumentProjector(exp.getUnderlyingCompiledQuery());
1139
				if (ff != null) {
1140
					
1141
					options.addFilter (ff);
1142
				}
1143
			}
1144

    
1145
		} */
1146

    
1147
        /// <summary>
1148
        /// Load an XML document, delivered using an <c>XmlReader</c>.
1149
        /// </summary>
1150
        /// <remarks>
1151
        /// <para>The <c>XmlReader</c> is responsible for parsing the document; this method builds a tree
1152
        /// representation of the document (in an internal Saxon format) and returns its document node.
1153
        /// The <c>XmlReader</c> is not required to perform validation but it must expand any entity references.
1154
        /// Saxon uses the properties of the <c>XmlReader</c> as supplied.</para>
1155
        /// <para>Use of a plain <c>XmlTextReader</c> is discouraged, because it does not expand entity
1156
        /// references. This should only be used if you know in advance that the document will contain
1157
        /// no entity references (or perhaps if your query or stylesheet is not interested in the content
1158
        /// of text and attribute nodes). Instead, with .NET 1.1 use an <c>XmlValidatingReader</c> (with <c>ValidationType</c>
1159
        /// set to <c>None</c>). The constructor for <c>XmlValidatingReader</c> is obsolete in .NET 2.0,
1160
        /// but the same effect can be achieved by using the <c>Create</c> method of <c>XmlReader</c> with
1161
        /// appropriate <c>XmlReaderSettings</c>.</para>
1162
        /// <para>Conformance with the W3C specifications requires that the <c>Normalization</c> property
1163
        /// of an <c>XmlTextReader</c> should be set to <c>true</c>. However, Saxon does not insist
1164
        /// on this.</para>
1165
        /// <para>If the <c>XmlReader</c> performs schema validation, Saxon will ignore any resulting type
1166
        /// information. Type information can only be obtained by using Saxon's own schema validator, which
1167
        /// will be run if the <c>SchemaValidationMode</c> property is set to <c>Strict</c> or <c>Lax</c>.</para>
1168
        /// <para>Note that the Microsoft <c>System.Xml</c> parser does not report whether attributes are
1169
        /// defined in the DTD as being of type <c>ID</c> and <c>IDREF</c>. This is true whether or not
1170
        /// DTD-based validation is enabled. This means that such attributes are not accessible to the 
1171
        /// <c>id()</c> and <c>idref()</c> functions.</para>
1172
        /// <para>Note that setting the <c>XmlResolver</c> property of the <c>DocumentBuilder</c>
1173
        /// has no effect when this method is used; if an <c>XmlResolver</c> is required, it must
1174
        /// be set on the <c>XmlReader</c> itself.</para>
1175
        /// </remarks>
1176
        /// <param name="reader">The <c>XMLReader</c> that supplies the parsed XML source</param>
1177
        /// <returns>An <c>XdmNode</c>, the document node at the root of the tree of the resulting
1178
        /// in-memory document.
1179
        /// </returns>
1180

    
1181
        public XdmNode Build(XmlReader reader)
1182
        {
1183
            JPullProvider pp = new JDotNetPullProvider(reader);
1184
            pp.setPipelineConfiguration(config.makePipelineConfiguration());
1185
            // pp = new PullTracer(pp);  /* diagnostics */
1186
            JSource source = new JPullSource(pp);
1187
            source.setSystemId(reader.BaseURI);
1188
            JParseOptions options = new JParseOptions(config.getParseOptions());
1189

    
1190
            source = augmentSource(source, options);
1191
            JNodeInfo doc = builder.build(source).getUnderlyingNode(); //config.buildDocumentTree(source, options).getRootNode();
1192
            return (XdmNode)XdmValue.Wrap(doc);
1193
        }
1194

    
1195
        /// <summary>
1196
		/// Load an XML DOM document, supplied as an <c>XmlNode</c>, into a Saxon <c>XdmNode</c>.
1197
        /// </summary>
1198
        /// <remarks>
1199
        /// <para>
1200
        /// The returned document will contain only the subtree rooted at the supplied node.
1201
        /// </para>
1202
        /// <para>
1203
        /// This method copies the DOM tree to create a Saxon tree. See the <c>Wrap</c> method for
1204
        /// an alternative that creates a wrapper around the DOM tree, allowing it to be modified in situ.
1205
        /// </para>
1206
        /// </remarks>
1207
        /// <param name="source">The DOM Node to be copied to form a Saxon tree</param>
1208
        /// <returns>An <c>XdmNode</c>, the document node at the root of the tree of the resulting
1209
        /// in-memory document.
1210
        /// </returns>
1211

    
1212
        public XdmNode Build(XmlNode source)
1213
        {
1214
            return Build(new XmlNodeReader(source));
1215
        }
1216

    
1217

    
1218
        /// <summary>
1219
        /// Wrap an XML DOM document, supplied as an <c>XmlNode</c>, as a Saxon <c>XdmNode</c>.
1220
        /// </summary>
1221
        /// <remarks>
1222
        /// <para>
1223
        /// This method must be applied at the level of the Document Node. Unlike the
1224
        /// <c>Build</c> method, the original DOM is not copied. This saves memory and
1225
        /// time, but it also means that it is not possible to perform operations such as
1226
        /// whitespace stripping and schema validation.
1227
        /// </para>
1228
        /// </remarks>
1229
        /// <param name="doc">The DOM document node to be wrapped</param>
1230
        /// <returns>An <c>XdmNode</c>, the Saxon document node at the root of the tree of the resulting
1231
        /// in-memory document.
1232
        /// </returns>
1233

    
1234
        public XdmNode Wrap(XmlDocument doc)
1235
        {
1236
            String baseu = (baseUri == null ? null : baseUri.ToString());
1237
            JDotNetDocumentWrapper wrapper = new JDotNetDocumentWrapper(doc, baseu, config);
1238
            return (XdmNode)XdmValue.Wrap(wrapper.getRootNode());
1239
        }
1240
    }
1241

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

    
1246
    public class StandardLogger : JLogger {
1247

    
1248
        private TextWriter outi = Console.Error;
1249
        JDotNetWriter writer;
1250
        int threshold = JLogger.INFO;
1251
        java.io.PrintStream stream;
1252

    
1253
        /// <summary>
1254
        /// Default constructor that wraps a <c>TextWriter</c> to write Saxon messages
1255
        /// </summary>
1256
		public StandardLogger() {
1257
            writer = new JDotNetWriter(outi);
1258
        }
1259

    
1260
        /// <summary>
1261
        /// Constructor method to supply a user defined TextWriter to the logger
1262
        /// </summary>
1263
        /// <param name="w"></param>
1264
		public StandardLogger(TextWriter w) {
1265
            writer = new JDotNetWriter(w);
1266

    
1267
        }
1268

    
1269
        /// <summary>
1270
        /// Property to get the udnerlying TextWriter object.
1271
        /// </summary>
1272
		public JDotNetWriter UnderlyingTextWriter {
1273
            set {
1274
                writer = value;
1275
            }
1276
            get {
1277
                return writer;
1278
            }
1279
        }
1280

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

    
1285
        public int Threshold {
1286

    
1287
            set {
1288
                threshold = value;
1289
            }
1290

    
1291
            get {
1292
                return threshold;
1293
            }
1294

    
1295
        }
1296

    
1297
        /// <summary>
1298
        /// Java internal streamResult object wrapping the TextWriter
1299
        /// </summary>
1300
        /// <returns></returns>
1301
        public override JStreamResult asStreamResult()
1302
        {
1303
            return new JStreamResult(writer);
1304
        }
1305

    
1306
        /// <summary>
1307
        /// Write the message to the TextWriter object
1308
        /// </summary>
1309
        /// <param name="str">The message</param>
1310
        /// <param name="severity">the severity of the error message</param>
1311
        public override void println(string str, int severity)
1312
        {
1313
            if (severity >= threshold) {
1314
                writer.write(str);
1315
            }
1316
        }
1317
    }
1318

    
1319

    
1320
    /// <summary>
1321
    /// Enumeration identifying the various Schema validation modes
1322
    /// </summary>
1323

    
1324
    public enum SchemaValidationMode
1325
    {
1326
        /// <summary>No validation (or strip validation, which removes existing type annotations)</summary> 
1327
        None,
1328
        /// <summary>Strict validation</summary>
1329
        Strict,
1330
        /// <summary>Lax validation</summary>
1331
        Lax,
1332
        /// <summary>Validation mode preserve, which preserves any existing type annotations</summary>
1333
        Preserve,
1334
        /// <summary>Unspecified validation: this means that validation is defined elsewhere, for example in the
1335
		/// Saxon <c>Configuration</c></summary>
1336
        Unspecified
1337
    }
1338

    
1339

    
1340
    /// <summary>
1341
    /// Identifiies a host language in which XPath expressions appear. Generally used when different error codes
1342
    /// need to be returned depending on the host language.
1343
    /// </summary>
1344
    public enum HostLanguage
1345
    {
1346
        XSLT,
1347
        XQUERY,
1348
        XML_SCHEMA,
1349
        XPATH,
1350
        XSLT_PATTERN
1351
    }
1352

    
1353

    
1354
    internal class JPredicateImpl : java.util.function.Predicate
1355
    {
1356

    
1357
        System.Predicate<QName> predicate;
1358

    
1359
        public JPredicateImpl(System.Predicate<QName> p) {
1360
            predicate = p;
1361

    
1362
        }
1363

    
1364
        public Predicate and(Predicate value1, Predicate value2)
1365
        {
1366
            throw new NotImplementedException();
1367
        }
1368

    
1369
        public Predicate negate(Predicate value)
1370
        {
1371
            throw new NotImplementedException();
1372
        }
1373

    
1374
        public Predicate or(Predicate value1, Predicate value2)
1375
        {
1376
            throw new NotImplementedException();
1377
        }
1378

    
1379
        public Predicate and(Predicate other)
1380
        {
1381
            throw new NotImplementedException();
1382
        }
1383

    
1384
        public Predicate isEqual(object targetRef)
1385
        {
1386
            throw new NotImplementedException();
1387
        }
1388

    
1389
        public Predicate negate()
1390
        {
1391
            throw new NotImplementedException();
1392
        }
1393

    
1394
        public Predicate or(Predicate other)
1395
        {
1396
            throw new NotImplementedException();
1397
        }
1398

    
1399
        public bool test(object t)
1400
        {
1401
            return predicate.Invoke(new QName((net.sf.saxon.s9api.QName)t));
1402
        }
1403
    }
1404

    
1405

    
1406

    
1407
    /// <summary>
1408
    /// <c>WhitespacePolicy</c> is a class defining the possible policies for handling
1409
    /// whitespace text nodes in a source document.
1410
    /// </summary>
1411
    /// <remarks>
1412
    /// Please note that since Saxon 9.7.0.8 this class has been refactored from the enumeration
1413
    /// type with the same name and therefore will work as before.
1414
    /// </remarks>
1415

    
1416
    [Serializable]
1417
    public class WhitespacePolicy
1418
    {
1419
       private int policy;
1420
       JWhiteSpaceStrippingPolicy strippingPolicy = null;
1421

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

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

    
1428
        /// <summary>No whitespace is stripped</summary>
1429
        public static WhitespacePolicy PreserveAll = new WhitespacePolicy(JWhitespace.NONE, JWhiteSpaceStrippingPolicy.NONE);
1430

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

    
1434
        private WhitespacePolicy(int policy, JWhiteSpaceStrippingPolicy strippingPolicy)
1435
        {
1436
            this.policy = policy;
1437
            this.strippingPolicy = strippingPolicy;
1438
        }
1439

    
1440

    
1441
        internal JWhiteSpaceStrippingPolicy GetJWhiteSpaceStrippingPolicy() {
1442
            if (strippingPolicy != null) {
1443
                return strippingPolicy;
1444
            }
1445
            return null;
1446
        }
1447

    
1448

    
1449
        internal WhitespacePolicy(JXsltExecutable executable)
1450
        {
1451
            policy = Whitespace.XSLT;
1452
            strippingPolicy = executable.getWhitespaceStrippingPolicy();
1453
        }
1454

    
1455

    
1456
        /// <summary>
1457
        /// Create a custom whitespace stripping policy
1458
        /// </summary>
1459
        /// <param name="elementTest">a predicate applied to element names, which should return true if whitespace-only
1460
        /// text node children of the element are to be stripped, false if they are to be retained.</param>
1461
		/// <returns>A <c>WhitespacePolicy</c> object</returns>
1462
        [Obsolete("This method has been replaced by MakeCustomPolicy.")]
1463
        public static WhitespacePolicy makeCustomPolicy(System.Predicate<QName> elementTest) {
1464
            JWhiteSpaceStrippingPolicy policy = JWhiteSpaceStrippingPolicy.makeCustomPolicy(new JPredicateImpl(elementTest));
1465
            WhitespacePolicy wsp = new WhitespacePolicy(JWhitespace.XSLT, null);
1466
            wsp.strippingPolicy = policy;
1467
            return wsp;
1468
        }
1469

    
1470
        /// <summary>
1471
        /// Create a custom whitespace stripping policy
1472
        /// </summary>
1473
        /// <param name="elementTest">a predicate applied to element names, which should return true if whitespace-only
1474
        /// text node children of the element are to be stripped, false if they are to be retained.</param>
1475
        /// <returns>A <c>WhitespacePolicy</c> object</returns>
1476
        public static WhitespacePolicy MakeCustomPolicy(System.Predicate<QName> elementTest)
1477
        {
1478
            JWhiteSpaceStrippingPolicy policy = JWhiteSpaceStrippingPolicy.makeCustomPolicy(new JPredicateImpl(elementTest));
1479
            WhitespacePolicy wsp = new WhitespacePolicy(JWhitespace.XSLT, null);
1480
            wsp.strippingPolicy = policy;
1481
            return wsp;
1482
        }
1483

    
1484
        internal int ordinal() {
1485
            return policy;
1486
        }
1487

    
1488
        /*internal net.sf.saxon.@event.FilterFactory makeStripper() {
1489
            return new FilterFactory(strippingPolicy);
1490
        }      */ 
1491

    
1492
    }
1493

    
1494

    
1495

    
1496
    internal class SpaceStrippingRule : net.sf.saxon.om.SpaceStrippingRule
1497
    {
1498
        private System.Predicate<QName> elementTest;
1499

    
1500
        public SpaceStrippingRule(System.Predicate<QName> elementTest)
1501
        {
1502
            this.elementTest = elementTest;
1503
        }
1504

    
1505
        public void export(JExpressionPresenter ep)
1506
        {
1507
            throw new NotImplementedException(); 
1508
        }
1509

    
1510

    
1511
        public int isSpacePreserving(NodeName nn, JSchemaType st)
1512
        {
1513
            return elementTest(new QName(nn.getStructuredQName().ToString())) ?
1514
                JStripper.ALWAYS_STRIP :
1515
                JStripper.ALWAYS_PRESERVE;
1516
        }
1517

    
1518
        public JProxyReceiver makeStripper(JReceiver r)
1519
        {
1520
            return new net.sf.saxon.@event.Stripper(this, r);
1521
        }
1522
    }
1523

    
1524
    internal class FilterFactory : JFilterFactory
1525
    {
1526
        JSpaceStrippingRule stripperRules;
1527
        public FilterFactory(JSpaceStrippingRule sr)
1528
        {
1529
            stripperRules = sr;
1530
        }
1531
        public JProxyReceiver makeFilter(JReceiver r)
1532
        {
1533
            return new net.sf.saxon.@event.Stripper(stripperRules, r);
1534
        }
1535

    
1536
        JReceiver JFilterFactory.makeFilter(JReceiver r)
1537
        {
1538
            return (JReceiver)new JStripper(stripperRules, r);
1539
        }
1540
    }
1541

    
1542
    /// <summary>
1543
    /// Enumeration identifying the different tree model implementations
1544
    /// </summary>
1545
    /// 
1546
    public enum TreeModel
1547
    {
1548
        /// <summary>
1549
        /// Saxon <c>LinkedTree</c>. This tree model is primarily useful when using XQuery Update, since it is the
1550
        /// only standard tree model to support updates.
1551
        /// </summary>
1552
        LinkedTree,
1553
        /// <summary>
1554
		/// Saxon <c>TinyTree</c>. This is the default model and is suitable for most purposes.
1555
        /// </summary>
1556
        TinyTree,
1557
        /// <summary>
1558
		/// Saxon Condensed <c>TinyTree</c>. This is a variant of the <c>TinyTree</c> that shares storage for 
1559
        /// duplicated text and attribute nodes. It gives a further saving in space occupied, at the cost
1560
        /// of some increase in the time taken for tree construction.
1561
        /// </summary>
1562
        TinyTreeCondensed,
1563
        /// <summary>
1564
        /// Unspecified tree model. This value is used to indicate that there is no preference for any specific
1565
        /// tree model, which allows the choice to fall back to other interfaces.
1566
        /// </summary>
1567
        Unspecified = -1
1568
    }
1569

    
1570
    internal class DotNetObjectModelDefinition : JDotNetObjectModel
1571
    {
1572

    
1573
        public override bool isXdmValue(object obj)
1574
        {
1575
            return obj is XdmValue;
1576
        }
1577

    
1578
        public override bool isXdmAtomicValueType(System.Type type)
1579
        {
1580
            return typeof(XdmAtomicValue).IsAssignableFrom(type);
1581
        }
1582

    
1583
        public override bool isXdmValueType(System.Type type)
1584
        {
1585
            return typeof(XdmValue).IsAssignableFrom(type);
1586
        }
1587

    
1588
        public override JSequence unwrapXdmValue(object obj)
1589
        {
1590
            return ((XdmValue)obj).Unwrap();
1591
        }
1592

    
1593
        public override object wrapAsXdmValue(JSequence value)
1594
        {
1595
            return XdmValue.Wrap(value);
1596
        }
1597

    
1598
        public override bool isXmlNodeType(System.Type type)
1599
        {
1600
            return typeof(System.Xml.XmlNode).IsAssignableFrom(type);
1601
        }
1602

    
1603
    }
1604

    
1605
}
1606

    
1607
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1608
// Copyright (c) 2020 Saxonica Limited.
1609
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
1610
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
1611
// This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0.
1612
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
(1-1/13)