Project

Profile

Help

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

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

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 JSpaceStrippingRule = net.sf.saxon.om.SpaceStrippingRule;
34
using JWhitespace = net.sf.saxon.value.Whitespace;
35
using JXsltExecutable = net.sf.saxon.s9api.XsltExecutable;
36
using JFilterFactory = net.sf.saxon.@event.FilterFactory;
37
using JProxyReceiver = net.sf.saxon.@event.ProxyReceiver;
38
using JExpressionPresenter = net.sf.saxon.trace.ExpressionPresenter;
39
using JStripper = net.sf.saxon.@event.Stripper;
40
using JSchemaType = net.sf.saxon.type.SchemaType;
41
using JStreamResult = javax.xml.transform.stream.StreamResult;
42
using JSource = javax.xml.transform.Source;
43
using JStreamSource = javax.xml.transform.stream.StreamSource;
44

    
45
namespace Saxon.Api
46
{
47

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

    
56
    [Serializable]
57
    public class Processor : JConfiguration.ApiProvider
58
    {
59

    
60
        //Transformation data variables
61
        private SchemaManager schemaManager = null;
62
        /*internal JConfiguration config;
63
       */
64
        private TextWriter textWriter = Console.Error;
65
        private JProcessor processor;
66

    
67
        internal Processor(JProcessor p) {
68
            processor = p;
69
            processor.getUnderlyingConfiguration().setProcessor(this);
70
        }
71

    
72
        /// <summary>
73
        /// Create a new <c>Processor</c>. This <c>Processor</c> will have capabilities that depend on the version
74
        /// of the software that has been loaded, and on the features that have been licensed.
75
        /// </summary>
76

    
77
        public Processor()
78
        {
79
            processor = new JProcessor(false);
80
            processor.getUnderlyingConfiguration().setProcessor(this);
81
            processor.getUnderlyingConfiguration().registerExternalObjectModel(new DotNetObjectModelDefinition());
82
        }
83

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

    
93
        public Processor(bool licensedEdition)
94
            // newline needed by documentation stylesheet
95
            : this(licensedEdition, false) { }
96

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

    
107
        public Processor(bool licensedEdition, bool loadLocally)
108
        {
109
            processor = new JProcessor(licensedEdition);
110
            processor.getUnderlyingConfiguration().registerExternalObjectModel(new DotNetObjectModelDefinition());
111
        }
112

    
113

    
114

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

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

    
130
        /// <summary>
131
        /// Create a <c>Processor</c>, based on configuration information supplied in a configuration file.
132
        /// </summary>
133
        /// <param name="configurationFile">A stream holding the text of the XML configuration file. Details of the file format
134
        /// can be found in the Saxon documentation.</param>
135
        /// <param name="baseUri">baseUri of the configuration file used for resolving any relative URIs in the file</param> 
136
  
137
        public Processor(Stream configurationFile, Uri baseUri)
138
        {
139
            JStreamSource ss = new JStreamSource(new JDotNetInputStream(configurationFile), baseUri.AbsoluteUri);
140
            JConfiguration config = JConfiguration.readConfiguration(ss);
141
            config.registerExternalObjectModel(new DotNetObjectModelDefinition());
142
            processor = new JProcessor(config);
143
        }
144

    
145

    
146

    
147

    
148
        /// <summary>
149
		/// Get the full name of the Saxon product version implemented by this <c>Processor</c>
150
        /// </summary>
151

    
152
        public string ProductTitle
153
        {
154
            get { return JVersion.getProductTitle(); }
155
        }
156

    
157
        /// <summary>
158
        /// Get the Saxon product version number (for example, "9.2.0.2")
159
        /// </summary>
160

    
161
        public string ProductVersion
162
        {
163
            get { return JVersion.getProductVersion(); }
164
        }
165

    
166
        /// <summary>
167
        /// Get the Saxon product edition (for example, "EE" for Enterprise Edition)
168
        /// </summary>
169
        /// 
170

    
171
        public string Edition
172
        {
173
            get { return processor.getUnderlyingConfiguration().getEditionCode(); }
174
        }
175

    
176

    
177

    
178
        /// <summary>
179
		/// Gets the <c>SchemaManager</c> for the <c>Processor</c>. Returns null
180
		/// if the <c>Processor</c> is not schema-aware.
181
        /// </summary>
182

    
183
        public SchemaManager SchemaManager
184
        {
185
            get {
186
                if (schemaManager == null)
187
                {
188
                    schemaManager = new SchemaManager(this);
189
                }
190
                
191
                return schemaManager; }
192
        }
193

    
194
        /// <summary>
195
		/// An <c>XmlResolver</c>, which will be used while compiling and running queries, 
196
		/// XPath expressions, and stylesheets, if no other <c>XmlResolver</c> is nominated
197
        /// </summary>
198
        /// <remarks>
199
        /// <para>By default an <c>XmlUrlResolver</c> is used. This means that the responsibility
200
        /// for resolving and dereferencing URIs rests with the .NET platform, not with the
201
        /// IKVM/OpenJDK runtime.</para>
202
        /// <para>When Saxon invokes a user-written <c>XmlResolver</c>, the <c>GetEntity</c> method
203
        /// may return any of: a <c>System.IO.Stream</c>; a <c>System.IO.TextReader</c>; or a
204
        /// <c>java.xml.transform.Source</c>.</para>
205
        /// </remarks>
206

    
207
        public XmlResolver XmlResolver
208
        {
209
            get
210
            {
211
                javax.xml.transform.URIResolver resolver = processor.getUnderlyingConfiguration ().getURIResolver ();
212
				if (resolver is JDotNetURIResolver) {
213
					return ((JDotNetURIResolver)resolver).getXmlResolver ();
214
				} else {
215
					return new XmlUrlResolver();
216
				}
217
            }
218
            set
219
            {
220
                processor.getUnderlyingConfiguration().setURIResolver(new JDotNetURIResolver(value));
221
            }
222
        }
223

    
224

    
225
        /// <summary>
226
		/// A <c>TextWriter</c> used as the destination of miscellaneous error, warning, and progress messages.
227
        /// </summary>
228
        /// <remarks>
229
        /// <para>By default the <c>Console.Error</c> is used for all such messages.</para>
230
        /// <para>A user can supply their own <c>TextWriter</c> to redirect error messages from the standard output.</para>
231
        /// </remarks>
232
        public TextWriter ErrorWriter 
233
        {
234
            get 
235
            {
236
                return textWriter;            
237
            }
238
            set 
239
            {
240
                textWriter = value;
241
				StandardLogger logger = new StandardLogger (value); 
242
				processor.getUnderlyingConfiguration ().setLogger (logger);
243
            }
244
        }
245

    
246
        /// <summary>
247
        /// Create a new <c>DocumentBuilder</c>, which may be used to build XDM documents from
248
        /// a variety of sources.
249
        /// </summary>
250
        /// <returns>A new <c>DocumentBuilder</c></returns>
251

    
252
        public DocumentBuilder NewDocumentBuilder()
253
        {
254
            DocumentBuilder builder = new DocumentBuilder(this);
255
            builder.XmlResolver = XmlResolver;
256
            return builder;
257
        }
258

    
259
        /// <summary>
260
		/// Create a new <c>XQueryCompiler</c>, which may be used to compile XQuery queries.
261
        /// </summary>
262
        /// <remarks>
263
		/// The returned <c>XQueryCompiler</c> retains a live link to the <c>Processor</c>, and
264
		/// may be affected by subsequent changes to the <c>Processor</c>.
265
        /// </remarks>
266
		/// <returns>A new <c>XQueryCompiler</c></returns>
267

    
268
        public XQueryCompiler NewXQueryCompiler()
269
        {
270
            return new XQueryCompiler(this);
271
        }
272

    
273
        /// <summary>
274
		/// Create a new <c>XsltCompiler</c>, which may be used to compile XSLT stylesheets.
275
        /// </summary>
276
        /// <remarks>
277
		/// The returned <c>XsltCompiler</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>XsltCompiler</c></returns>
281

    
282
        public XsltCompiler NewXsltCompiler()
283
        {
284
            return new XsltCompiler(this);
285
        }
286

    
287
        /// <summary>
288
		/// Create a new <c>XPathCompiler</c>, which may be used to compile XPath expressions.
289
        /// </summary>
290
        /// <remarks>
291
		/// The returned <c>XPathCompiler</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>XPathCompiler</c></returns>
295

    
296
        public XPathCompiler NewXPathCompiler()
297
        {
298
            return new XPathCompiler(this, JProcessor.newXPathCompiler());
299
        }
300

    
301
        /// <summary>
302
		/// Create a <c>Serializer</c>
303
        /// </summary>
304
		/// <returns> a new <c>Serializer</c> </returns>
305
        public Serializer NewSerializer() {
306
            Serializer s = new Serializer(processor.newSerializer());
307
            s.SetProcessor(this); //TODO this method call might no longer be needed
308
            return s;
309
        }
310

    
311
        /// <summary>
312
        /// Create a <c>Serializer</c> initialized to write to a given <c>TextWriter</c>.
313
        /// Closing the writer after use is the responsibility of the caller.
314
        /// </summary>
315
        /// <param name="textWriter">The <c>TextWriter</c> to which the <c>Serializer</c> will write</param>
316
        /// <returns> a new <c>Serializer</c> </returns>
317
        public Serializer NewSerializer(TextWriter textWriter)
318
        {
319
            Serializer s = new Serializer(processor.newSerializer());
320
            s.SetOutputWriter(textWriter);
321
            return s;
322
        }
323

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

    
337
        /// <summary>
338
        /// The XML version used in this <c>Processor</c>
339
        /// </summary>
340
        /// <remarks>
341
        /// The value must be 1.0 or 1.1, as a <c>decimal</c>. The default version is currently 1.0, but may
342
        /// change in the future.
343
        /// </remarks>
344

    
345
        public decimal XmlVersion
346
        {
347
            get
348
            {
349
                return (processor.getUnderlyingConfiguration().getXMLVersion() == JConfiguration.XML10 ? 1.0m : 1.1m);
350
            }
351
            set
352
            {
353
                if (value == 1.0m)
354
                {
355
                    processor.setXmlVersion("1.0");
356
                }
357
                else if (value == 1.1m)
358
                {
359
                    processor.setXmlVersion("1.1");
360
                }
361
                else
362
                {
363
                    throw new ArgumentException("Invalid XML version: " + value);
364
                }
365
            }
366
        }
367

    
368
        /// <summary>
369
        /// Create a collation based on a given <c>CompareInfo</c> and <c>CompareOptions</c>    
370
        /// </summary>
371
        /// <param name="uri">The collation URI to be used within an XPath expression to refer to this collation</param>
372
        /// <param name="compareInfo">The <c>CompareInfo</c>, which determines the language-specific
373
        /// collation rules to be used</param>
374
        /// <param name="options">Options to be used in performing comparisons, for example
375
        /// whether they are to be case-blind and/or accent-blind</param>
376

    
377
        public void DeclareCollation(Uri uri, CompareInfo compareInfo, CompareOptions options)
378
        {
379
            JDotNetComparator comparator = new JDotNetComparator(uri.ToString(), compareInfo, options);
380
            Implementation.registerCollation(uri.ToString(), comparator);
381
        }
382

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

    
409
        public void RegisterCollection(Uri collectionUri, IEnumerable contents)
410
        {
411
            String u = (collectionUri == null ? null : collectionUri.ToString());
412
            JConfiguration config = processor.getUnderlyingConfiguration();
413
            config.registerCollection(u, new JDotNetEnumerableCollection(config, contents));
414
        }
415

    
416
        /// <summary>
417
		/// Register an extension function with the <c>Processor</c>
418
        /// </summary>
419
        /// <param name="function">
420
        /// An object that defines the extension function, including its name, arity, arguments types, and
421
        /// a reference to the class that implements the extension function call.
422
        /// </param>
423

    
424
        public void RegisterExtensionFunction(ExtensionFunctionDefinition function)
425
        {
426
            WrappedExtensionFunctionDefinition f = new WrappedExtensionFunctionDefinition(function);
427
            processor.registerExtensionFunction(f);
428
        }
429

    
430
        /// <summary>
431
        /// Register a simple external/extension function that is to be made available within any stylesheet, query
432
        /// or XPath expression compiled under the control of this <c>Processor</c>
433
        /// </summary>
434
        /// <param name="function">
435
        /// This interface provides only for simple extensions that have no side-effects and no
436
        /// dependencies on the static or dynamic context.
437
        /// </param>
438

    
439
        public void RegisterExtensionFunction(ExtensionFunction function)
440
        {
441
            WrappedExtensionFunction f = new WrappedExtensionFunction(function);
442
            processor.registerExtensionFunction(f);
443
        }
444

    
445
        /// <summary>
446
		/// Copy an <c>XdmValue</c> to an <c>XmlDestination</c>
447
        /// </summary>
448
        /// <remarks>
449
        /// In principle this method can be used to copy any kind of <c>XdmValue</c> to any kind
450
        /// of <c>XmlDestination</c>. However, some kinds of destination may not accept arbitrary
451
        /// sequences of items; for example, some may reject function items. Some destinations
452
        /// perform sequence normalization, as defined in the W3C serialization specification,
453
        /// to convert the supplied sequence to a well-formed XML document; it is a property
454
        /// of the chosen <c>XmlDestination</c> whether it does this or not.</remarks>
455
        /// <param name="sequence">The value to be written</param>
456
        /// <param name="destination">The destination to which the value should be written</param>
457
        /// 
458

    
459
        public void WriteXdmValue(XdmValue sequence, XmlDestination destination)
460
        {
461
            try
462
            {
463
                JPipelineConfiguration pipe = processor.getUnderlyingConfiguration().makePipelineConfiguration();
464
                JResult r = destination.GetUnderlyingDestination().getReceiver(pipe, pipe.getConfiguration().obtainDefaultSerializationProperties());
465
                r.open();
466
                foreach (XdmItem item  in sequence) {
467
                    r.append(item.Unwrap().head());
468
                }
469
                r.close();
470
            } catch(JXPathException err) {
471
                throw new DynamicError(err);
472
            }
473
        }
474

    
475

    
476
        /// <summary>
477
		/// The underlying <c>Configuration</c> object in the Saxon implementation
478
        /// </summary>
479
        /// <remarks>
480
        /// <para>This property provides access to internal methods in the Saxon engine that are
481
        /// not specifically exposed in the .NET API. In general these methods should be
482
        /// considered to be less stable than the classes in the Saxon.Api namespace.</para> 
483
        /// <para>The internal methods follow
484
        /// Java naming conventions rather than .NET conventions.</para>
485
		/// <para>Information about the returned <see cref="net.sf.saxon.Configuration"/> object 
486
		/// (and the objects it provides access to) is included in the Saxon JavaDoc docmentation.
487
        /// </para>
488
        /// </remarks>
489

    
490
        public JConfiguration Implementation
491
        {
492
            get { return processor.getUnderlyingConfiguration(); }
493
        }
494
        
495
        /// <summary>
496
        /// The underlying <c>net.sf.saxon.s9api.Processor</c> in the Java implementation
497
        /// </summary>
498

    
499
		public JProcessor JProcessor
500
        {
501
            get { return processor;}
502
        }
503

    
504
        /// <summary>
505
        /// Set a configuration property
506
        /// </summary>
507
        /// <remarks>
508
        /// <para>This method provides the ability to set named properties of the configuration.
509
        /// The property names are set as strings, whose values can be found in the Java
510
        /// class <c>net.sf.saxon.FeatureKeys</c>. The property values are always strings. 
511
        /// Properties whose values are other types are not available via this interface:
512
        /// however all properties have an effective equivalent whose value is a string.
513
        /// Note that on/off properties are set using the strings "true" and "false".</para>
514
        /// <para><i>Method added in Saxon 9.1</i></para>
515
        /// </remarks>
516
        /// <param name="name">The property name</param>
517
        /// <param name="value">The property value</param>
518

    
519
        public void SetProperty(String name, String value)
520
        {
521
            processor.setConfigurationProperty(name, value);
522
		}
523

    
524
		/// <summary>
525
		/// Set a configuration property
526
		/// </summary>
527
		/// <param name="feature">The property feature</param>
528
		/// <param name="value">The property value</param>
529

    
530
        public void SetProperty<T>(Feature<T> feature, T value) {
531
			processor.setConfigurationProperty(feature.JFeature, value);
532
        }
533

    
534
        /// <summary>
535
        /// Get the value of a configuration property
536
        /// </summary>
537
        /// <remarks>
538
        /// <para>This method provides the ability to get named properties of the configuration.
539
        /// The property names are supplied as strings, whose values can be found in the Java
540
        /// class <c>net.sf.saxon.FeatureKeys</c>. The property values are always returned as strings. 
541
        /// Properties whose values are other types are returned by converting the value to a string.
542
        /// Note that on/off properties are returned using the strings "true" and "false".</para>
543
        /// <para><i>Method added in Saxon 9.1</i></para>
544
        /// </remarks>
545
        /// <param name="name">The property name</param>
546
        /// <returns>The property value, as a string; or null if the property is unset.</returns>
547

    
548
        public String GetProperty(String name)
549
        {
550
            Object obj = processor.getConfigurationProperty(name);
551
            return (obj == null ? null : obj.ToString());
552
        }
553

    
554

    
555
        /// <summary>
556
        /// Get a property of the configuration
557
        /// </summary>
558
        /// <typeparam name="T">See the class <c>Feature</c> for constants 
559
        /// representing the properties that can be requested.</typeparam>
560
        /// <param name="feature">the required property. </param>
561
        /// <returns>the value of the property</returns>
562
        public T GetProperty<T>(Feature<T> feature) {
563
            return (T)processor.getConfigurationProperty(feature.JFeature);
564
        }
565

    
566
    }
567

    
568
    /// <summary>
569
    /// The <c>DocumentBuilder</c> class enables XDM documents to be built from various sources.
570
    /// The class is always instantiated using the <c>NewDocumentBuilder</c> method
571
    /// on the <c>Processor</c> object.
572
    /// </summary>
573

    
574
    [Serializable]
575
    public class DocumentBuilder
576
    {
577

    
578
        private Processor processor;
579
        private JConfiguration config;
580
        private XmlResolver xmlResolver;
581
        private SchemaValidationMode validation;
582
        private SchemaValidator schemaValidator;
583
        private bool dtdValidation;
584
        private bool lineNumbering;
585
        private WhitespacePolicy whitespacePolicy;
586
        private Uri baseUri;
587
        private QName topLevelElement;
588
        private TreeModel treeModel = TreeModel.Unspecified;
589
		private XQueryExecutable projectionQuery;
590
        
591

    
592
        internal DocumentBuilder(Processor processor)
593
        {
594
            this.processor = processor;
595
            this.config = processor.Implementation;
596
            this.xmlResolver = new XmlUrlResolver();
597
        }
598

    
599
        /// <summary>
600
		/// An <c>XmlResolver</c>, which will be used to resolve URIs of documents being loaded
601
        /// and of references to external entities within those documents (including any external DTD).
602
        /// </summary>
603
        /// <remarks>
604
        /// <para>By default an <c>XmlUrlResolver</c> is used. This means that the responsibility
605
        /// for resolving and dereferencing URIs rests with the .NET platform (and not with the
606
        /// GNU Classpath).</para>
607
        /// <para>When Saxon invokes a user-written <c>XmlResolver</c>, the <c>GetEntity</c> method
608
        /// may return any of: a <c>System.IO.Stream</c>; a <c>System.IO.TextReader</c>; or a
609
        /// <c>java.xml.transform.Source</c>. However, if the <c>XmlResolver</c> is called
610
        /// by the XML parser to resolve external entity references, then it must return an 
611
        /// instance of <c>System.IO.Stream</c>.</para>
612
        /// </remarks>
613

    
614
        public XmlResolver XmlResolver
615
        {
616
            get
617
            {
618
                return xmlResolver;
619
            }
620
            set
621
            {
622
                xmlResolver = value;
623
            }
624
        }
625

    
626
        /// <summary>
627
        /// Determines whether line numbering is enabled for documents loaded using this
628
        /// <c>DocumentBuilder</c>.
629
        /// </summary>
630
        /// <remarks>
631
        /// <para>By default, line numbering is disabled.</para>
632
        /// <para>Line numbering is not available for all kinds of source: in particular,
633
		/// it is not available when loading from an existing <c>XmlDocument</c>.</para>
634
        /// <para>The resulting line numbers are accessible to applications using the
635
		/// extension function <c>saxon:line-number()</c> applied to a node.</para>  
636
        /// <para>Line numbers are maintained only for element nodes; the line number
637
        /// returned for any other node will be that of the most recent element.</para> 
638
        /// </remarks>
639

    
640
        public bool IsLineNumbering
641
        {
642
            get
643
            {
644
                return lineNumbering;
645
            }
646
            set
647
            {
648
                lineNumbering = value;
649
            }
650
        }
651

    
652
        /// <summary>
653
        /// Determines whether schema validation is applied to documents loaded using this
654
        /// <c>DocumentBuilder</c>, and if so, whether it is strict or lax.
655
        /// </summary>
656
        /// <remarks>
657
        /// <para>By default, no schema validation takes place.</para>
658
        /// <para>This option requires Saxon Enterprise Edition (Saxon-EE).</para>
659
        /// </remarks>
660

    
661
        public SchemaValidationMode SchemaValidationMode
662
        {
663
            get
664
            {
665
                return validation;
666
            }
667
            set
668
            {
669
                validation = value;
670
            }
671
        }
672

    
673

    
674
        /// <summary>
675
        /// Property to set and get the schemaValidator to be used. This determines whether schema validation is applied
676
        /// to an input document and whether type annotations in a supplied document are retained. If no schemaValidator
677
        /// is supplied, then schema validation does not take place.
678
        /// </summary>
679
        public SchemaValidator SchemaValidator {
680
            get { return schemaValidator; }
681
            set { schemaValidator = value; }
682
        }
683

    
684
        /// <summary>
685
        /// The required name of the top level element in a document instance being validated
686
        /// against a schema.
687
        /// </summary>
688
        /// <remarks>
689
        /// <para>If this property is set, and if schema validation is requested, then validation will
690
        /// fail unless the outermost element of the document has the required name.</para>
691
        /// <para>This option requires the schema-aware version of the Saxon product (Saxon-EE).</para>
692
        /// </remarks> 
693

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

    
706
        /// <summary>
707
        /// Determines whether DTD validation is applied to documents loaded using this
708
        /// <c>DocumentBuilder</c>.
709
        /// </summary>
710
        /// <remarks>
711
        /// <para>By default, no DTD validation takes place.</para>
712
        /// </remarks>
713

    
714
        public bool DtdValidation
715
        {
716
            get
717
            {
718
                return dtdValidation;
719
            }
720
            set
721
            {
722
                dtdValidation = value;
723
            }
724
        }
725

    
726
        /// <summary>
727
        /// Determines the whitespace stripping policy applied when loading a document
728
        /// using this <c>DocumentBuilder</c>.
729
        /// </summary>
730
        /// <remarks>
731
        /// <para>By default, whitespace text nodes appearing in element-only content
732
        /// are stripped, and all other whitespace text nodes are retained.</para>
733
        /// </remarks>
734

    
735
        public WhitespacePolicy WhitespacePolicy
736
        {
737
            get
738
            {
739
                return whitespacePolicy;
740
            }
741
            set
742
            {
743
                whitespacePolicy = value;
744
            }
745
        }
746

    
747
        ///<summary>
748
        /// The Tree Model implementation to be used for the constructed document. By default
749
		/// the <c>TinyTree</c> is used. The main reason for using the <c>LinkedTree</c> alternative is if
750
		/// updating is required (the <c>TinyTree</c> is not updateable).
751
        ///</summary>
752

    
753
        public TreeModel TreeModel
754
        {
755
            get
756
            {
757
                return treeModel;
758
            }
759
            set
760
            {
761
                treeModel = value;
762
            }
763
        }
764

    
765
        /// <summary>
766
        /// The base URI of a document loaded using this <c>DocumentBuilder</c>.
767
        /// This is used for resolving any relative URIs appearing
768
        /// within the document, for example in references to DTDs and external entities.
769
        /// </summary>
770
        /// <remarks>
771
        /// This information is required when the document is loaded from a source that does not
772
		/// provide an intrinsic URI, notably when loading from a <c>Stream</c> or a <c>TextReader</c>.
773
        /// </remarks>
774

    
775

    
776
        public Uri BaseUri
777
        {
778
            get { return baseUri; }
779
            set { baseUri = value; }
780
        }
781

    
782

    
783
		/// <summary>
784
		/// Set a compiled query to be used for implementing document projection. 
785
		/// </summary>
786
		/// <remarks>
787
		/// <para>
788
		/// The effect of using this option is that the tree constructed by the 
789
		/// <c>DocumentBuilder</c> contains only those parts
790
    	/// of the source document that are needed to answer this query. Running this query against
791
    	/// the projected document should give the same results as against the raw document, but the
792
     	/// projected document typically occupies significantly less memory. It is permissible to run
793
    	/// other queries against the projected document, but unless they are carefully chosen, they
794
    	/// will give the wrong answer, because the document being used is different from the original.
795
		/// </para>
796
    	/// <para>The query should be written to use the projected document as its initial context item.
797
    	/// For example, if the query is <code>//ITEM[COLOR='blue']</code>, then only <code>ITEM</code>
798
    	/// elements and their <code>COLOR</code> children will be retained in the projected document.</para>
799
    	/// <para>This facility is only available in Saxon-EE; if the facility is not available,
800
    	/// calling this method has no effect.</para>
801
		/// </remarks>
802
    
803

    
804
		public XQueryExecutable DocumentProjectionQuery {
805
			get { return projectionQuery;}
806
			set { projectionQuery = value;}
807

    
808
		}
809

    
810
        /// <summary>
811
        /// Load an XML document, retrieving it via a URI.
812
        /// </summary>
813
        /// <remarks>
814
        /// <para>Note that the type <c>Uri</c> requires an absolute URI.</para>
815
        /// <para>The URI is dereferenced using the registered <c>XmlResolver</c>.</para>
816
        /// <para>This method takes no account of any fragment part in the URI.</para>
817
        /// <para>The <c>role</c> passed to the <c>GetEntity</c> method of the <c>XmlResolver</c> 
818
        /// is "application/xml", and the required return type is <c>System.IO.Stream</c>.</para>
819
        /// <para>The document located via the URI is parsed using the <c>System.Xml</c> parser.</para>
820
        /// <para>Note that the Microsoft <c>System.Xml</c> parser does not report whether attributes are
821
        /// defined in the DTD as being of type <c>ID</c> and <c>IDREF</c>. This is true whether or not
822
        /// DTD-based validation is enabled. This means that such attributes are not accessible to the 
823
        /// <c>id()</c> and <c>idref()</c> functions.</para>
824
        /// </remarks>
825
        /// <param name="uri">The URI identifying the location where the document can be
826
        /// found. This will also be used as the base URI of the document (regardless
827
		/// of the setting of the <c>BaseUri</c> property).</param>
828
		/// <returns>An <c>XdmNode</c>, the document node at the root of the tree of the resulting
829
		/// in-memory document.
830
		/// </returns>
831

    
832
        public XdmNode Build(Uri uri)
833
        {
834
            Object obj = XmlResolver.GetEntity(uri, "application/xml", System.Type.GetType("System.IO.Stream"));
835
            if (obj is Stream)
836
            {
837
                try
838
                {
839
                    return Build((Stream)obj, uri);
840
                }
841
                finally
842
                {
843
                    ((Stream)obj).Close();
844
                }
845
            }
846
            else
847
            {
848
                throw new ArgumentException("Invalid type of result from XmlResolver.GetEntity: " + obj);
849
            }
850
        }
851

    
852
        /// <summary>
853
		/// Load an XML document supplied as raw (lexical) XML on a <c>Stream</c>.
854
        /// </summary>
855
        /// <remarks>
856
        /// <para>The document is parsed using the Microsoft <c>System.Xml</c> parser if the
857
        /// "http://saxon.sf.net/feature/preferJaxpParser" property on the <c>Processor</c> is set to false;
858
        /// otherwise it is parsed using the Apache Xerces XML parser.</para>
859
        /// <para>Before calling this method, the <c>BaseUri</c> property must be set to identify the
860
        /// base URI of this document, used for resolving any relative URIs contained within it.</para>
861
        /// <para>Note that the Microsoft <c>System.Xml</c> parser does not report whether attributes are
862
        /// defined in the DTD as being of type <c>ID</c> and <c>IDREF</c>. This is true whether or not
863
        /// DTD-based validation is enabled. This means that such attributes are not accessible to the 
864
        /// <c>id()</c> and <c>idref()</c> functions.</para>         
865
        /// </remarks>
866
        /// <param name="input">The <c>Stream</c> containing the XML source to be parsed. Closing this stream
867
        /// on completion is the responsibility of the caller.</param>
868
        /// <returns>An <c>XdmNode</c>, the document node at the root of the tree of the resulting
869
        /// in-memory document.
870
        /// </returns>
871

    
872
        public XdmNode Build(Stream input)
873
        {
874
            if (baseUri == null)
875
            {
876
                throw new ArgumentException("No base URI supplied");
877
            }
878
            return Build(input, baseUri);
879
        }
880

    
881
        // Build a document from a given stream, with the base URI supplied
882
        // as an extra argument
883

    
884
        internal XdmNode Build(Stream input, Uri baseUri)
885
        {
886
            JSource source;
887
			JParseOptions options = new JParseOptions(config.getParseOptions());
888

    
889
            if (schemaValidator != null) {
890
                schemaValidator.IsLax = (validation == SchemaValidationMode.Lax ? true : false);
891
                options.setSchemaValidationMode(schemaValidator.IsLax ? JValidation.LAX : JValidation.STRICT);
892
                if (schemaValidator.DocumentElementName != null) {
893
                    QName qn = schemaValidator.DocumentElementName;
894
                    options.setTopLevelElement(qn.ToStructuredQName());
895

    
896
                }
897
                if (schemaValidator.DocumentElementTypeName != null) {
898
                    options.setTopLevelElement(schemaValidator.DocumentElementType.getStructuredQName());
899
                }
900
            }
901

    
902
            if (processor.GetProperty("http://saxon.sf.net/feature/preferJaxpParser") == "true")
903
            {
904
                source = new JStreamSource(new JDotNetInputStream(input), baseUri.ToString());
905
				options.setEntityResolver(new JDotNetURIResolver(XmlResolver));
906
            }
907
            else
908
            {
909

    
910
                XmlReaderSettings settings = new XmlReaderSettings();
911
				settings.DtdProcessing = DtdProcessing.Parse;   // must expand entity references
912

    
913

    
914
                //((XmlTextReader)parser).Normalization = true;
915
                if (whitespacePolicy != null) {
916
                    int optioni = whitespacePolicy.ordinal();
917
                    if (optioni == JWhitespace.XSLT)
918
                    {
919
                        options.setSpaceStrippingRule(WhitespacePolicy.PreserveAll.GetSpaceStrippingRules());
920
                        options.addFilter(whitespacePolicy.makeStripper());
921
                    }
922
                    else {
923
                        options.setSpaceStrippingRule(whitespacePolicy.GetSpaceStrippingRules());
924
                    }
925
                 
926

    
927
                }
928
               
929
                if (xmlResolver != null)
930
                {
931
                    settings.XmlResolver = xmlResolver;
932
                }
933
                
934
                settings.ValidationType = (dtdValidation ? ValidationType.DTD : ValidationType.None);
935
                
936
                XmlReader parser = XmlReader.Create(input, settings, baseUri.ToString());
937
                source = new JPullSource(new JDotNetPullProvider(parser));
938
                source.setSystemId(baseUri.ToString());
939
            }
940
            augmentParseOptions(options);
941
            try
942
            {
943
                JNodeInfo doc = config.buildDocument(source, options);
944
                XdmNode node = (XdmNode)XdmValue.Wrap(doc);
945
                node.SetProcessor(processor);
946
                return node;
947
            } catch(JXPathException ex)
948
            { throw new StaticError(ex); }
949

    
950
            
951
        }
952

    
953
        /// <summary>
954
		/// Load an XML document supplied using a <c>TextReader</c>.
955
        /// </summary>
956
        /// <remarks>
957
        /// <para>The document is parsed using the Microsoft <c>System.Xml</c> parser if the
958
        /// "http://saxon.sf.net/feature/preferJaxpParser" property on the <c>Processor</c> is set to false;
959
        /// otherwise it is parsed using the Apache Xerces XML parser.</para>
960
        /// <para>Before calling this method, the <c>BaseUri</c> property must be set to identify the
961
        /// base URI of this document, used for resolving any relative URIs contained within it.</para>
962
        /// <para>Note that the Microsoft <c>System.Xml</c> parser does not report whether attributes are
963
        /// defined in the DTD as being of type <c>ID</c> and <c>IDREF</c>. This is true whether or not
964
        /// DTD-based validation is enabled. This means that such attributes are not accessible to the 
965
        /// <c>id()</c> and <c>idref()</c> functions.</para>         
966
        /// </remarks>
967
        /// <param name="input">The <c>TextReader</c> containing the XML source to be parsed</param>
968
        /// <returns>An <c>XdmNode</c>, the document node at the root of the tree of the resulting
969
        /// in-memory document.
970
        /// </returns>
971

    
972
        public XdmNode Build(TextReader input)
973
        {
974
            if (baseUri == null)
975
            {
976
                throw new ArgumentException("No base URI supplied");
977
            }
978
            return Build(input, baseUri);
979
        }
980

    
981
        // Build a document from a given stream, with the base URI supplied
982
        // as an extra argument
983

    
984
        internal XdmNode Build(TextReader input, Uri baseUri)
985
        {
986
            JSource source;
987
			JParseOptions options = new JParseOptions(config.getParseOptions());
988
            if (processor.GetProperty("http://saxon.sf.net/feature/preferJaxpParser") == "true")
989
            {
990
                source = new JStreamSource(new JDotNetReader(input), baseUri.ToString());
991
                options.setEntityResolver(new JDotNetURIResolver(XmlResolver));
992
            }
993
            else
994
            {
995

    
996
                XmlReaderSettings settings = new XmlReaderSettings();
997
                settings.DtdProcessing = DtdProcessing.Parse;   // must expand entity references
998

    
999

    
1000
                //((XmlTextReader)parser).Normalization = true;
1001
                if (whitespacePolicy != null)
1002
                {
1003
                    int option = whitespacePolicy.ordinal();
1004
                    if (option == JWhitespace.XSLT) {
1005
                        options.setStripSpace(JWhitespace.NONE);
1006
                        options.addFilter(whitespacePolicy.makeStripper());
1007
                    } else {
1008
                        options.setStripSpace(option);
1009
                    }
1010
                
1011
                }
1012
                if (xmlResolver != null)
1013
                {
1014
                    settings.XmlResolver = xmlResolver;
1015
                }
1016

    
1017
                settings.ValidationType = (dtdValidation ? ValidationType.DTD : ValidationType.None);
1018

    
1019
                XmlReader parser = XmlReader.Create(input, settings, baseUri.ToString());
1020
                source = new JPullSource(new JDotNetPullProvider(parser));
1021
                source.setSystemId(baseUri.ToString());
1022
            }
1023
            augmentParseOptions(options);
1024
			JNodeInfo doc = config.buildDocument(source, options);
1025
            return (XdmNode)XdmValue.Wrap(doc);
1026
        }
1027

    
1028
        private JSource augmentSource(JSource source)
1029
        {
1030
            if (validation != SchemaValidationMode.None)
1031
            {
1032
                source = AugmentedSource.makeAugmentedSource(source);
1033
                if (validation == SchemaValidationMode.Strict)
1034
                {
1035
                    ((AugmentedSource)source).setSchemaValidationMode(JValidation.STRICT);
1036
                }
1037
                else if (validation == SchemaValidationMode.Lax)
1038
                {
1039
                    ((AugmentedSource)source).setSchemaValidationMode(JValidation.LAX);
1040
                }
1041
                else if (validation == SchemaValidationMode.None)
1042
                {
1043
                    ((AugmentedSource)source).setSchemaValidationMode(JValidation.STRIP);
1044
                }
1045
                else if (validation == SchemaValidationMode.Preserve)
1046
                {
1047
                    ((AugmentedSource)source).setSchemaValidationMode(JValidation.PRESERVE);
1048
                }
1049
            }
1050
            if (topLevelElement != null)
1051
            {
1052
                source = AugmentedSource.makeAugmentedSource(source);
1053
                ((AugmentedSource)source).setTopLevelElement(
1054
                    new FingerprintedQName(
1055
						topLevelElement.Prefix, topLevelElement.Uri.ToString(), topLevelElement.LocalName).getStructuredQName());
1056
            }
1057

    
1058
            if (whitespacePolicy != WhitespacePolicy.PreserveAll)
1059
            {
1060
                source = AugmentedSource.makeAugmentedSource(source);
1061
                if (whitespacePolicy == WhitespacePolicy.StripIgnorable)
1062
                {
1063
                    ((AugmentedSource)source).setStripSpace(Whitespace.IGNORABLE);
1064
                }
1065
                else
1066
                {
1067
                    ((AugmentedSource)source).setStripSpace(Whitespace.ALL);
1068
                }
1069
            }
1070
            if (treeModel != TreeModel.Unspecified)
1071
            {
1072
                source = AugmentedSource.makeAugmentedSource(source);
1073
                if (treeModel == TreeModel.TinyTree)
1074
                {
1075
                    ((AugmentedSource)source).setModel(net.sf.saxon.om.TreeModel.TINY_TREE);
1076
                }
1077
                else if (treeModel == TreeModel.TinyTreeCondensed)
1078
                {
1079
                    ((AugmentedSource)source).setModel(net.sf.saxon.om.TreeModel.TINY_TREE_CONDENSED);
1080
                }
1081
                else
1082
                {
1083
                    ((AugmentedSource)source).setModel(net.sf.saxon.om.TreeModel.LINKED_TREE);
1084
                }
1085
            }
1086
            if (lineNumbering)
1087
            {
1088
                source = AugmentedSource.makeAugmentedSource(source);
1089
                ((AugmentedSource)source).setLineNumbering(true);
1090
            }
1091
            if (dtdValidation)
1092
            {
1093
                source = AugmentedSource.makeAugmentedSource(source);
1094
                ((AugmentedSource)source).setDTDValidationMode(JValidation.STRICT);
1095
            }
1096
			if (projectionQuery != null) {
1097
				net.sf.saxon.s9api.XQueryExecutable exp = projectionQuery.getUnderlyingCompiledQuery();
1098
				net.sf.saxon.@event.FilterFactory ff = config.makeDocumentProjector(exp.getUnderlyingCompiledQuery());
1099
				if (ff != null) {
1100
					source = AugmentedSource.makeAugmentedSource(source);
1101
					((AugmentedSource)source).addFilter (ff);
1102
				}
1103
			}
1104
            return source;
1105
        }
1106

    
1107

    
1108
		private void augmentParseOptions(JParseOptions options)
1109
		{
1110
			if (validation != SchemaValidationMode.None)
1111
			{
1112
				
1113
				if (validation == SchemaValidationMode.Strict)
1114
				{
1115
					options.setSchemaValidationMode(JValidation.STRICT);
1116
				}
1117
				else if (validation == SchemaValidationMode.Lax)
1118
				{
1119
					options.setSchemaValidationMode(JValidation.LAX);
1120
				}
1121
				else if (validation == SchemaValidationMode.None)
1122
				{
1123
					options.setSchemaValidationMode(JValidation.STRIP);
1124
				}
1125
				else if (validation == SchemaValidationMode.Preserve)
1126
				{
1127
					options.setSchemaValidationMode(JValidation.PRESERVE);
1128
				}
1129
			}
1130
			if (topLevelElement != null)
1131
			{
1132
				
1133
				options.setTopLevelElement(
1134
					new FingerprintedQName(
1135
						topLevelElement.Prefix, topLevelElement.Uri.ToString(), topLevelElement.LocalName).getStructuredQName());
1136
			}
1137

    
1138
			if (whitespacePolicy != null)
1139
			{
1140
                int option = whitespacePolicy.ordinal();
1141
				if (option == JWhitespace.XSLT)
1142
				{
1143
                    options.setSpaceStrippingRule(WhitespacePolicy.PreserveAll.GetSpaceStrippingRules());
1144
                    options.addFilter(whitespacePolicy.makeStripper());
1145
				}
1146
				else
1147
				{
1148
                    options.setSpaceStrippingRule(whitespacePolicy.GetSpaceStrippingRules());
1149
                }
1150
			}
1151
			if (treeModel != TreeModel.Unspecified)
1152
			{
1153
				
1154
				if (treeModel == TreeModel.TinyTree)
1155
				{
1156
					options.setModel(net.sf.saxon.om.TreeModel.TINY_TREE);
1157
				}
1158
				else if (treeModel == TreeModel.TinyTreeCondensed)
1159
				{
1160
					options.setModel(net.sf.saxon.om.TreeModel.TINY_TREE_CONDENSED);
1161
				}
1162
				else
1163
				{
1164
					options.setModel(net.sf.saxon.om.TreeModel.LINKED_TREE);
1165
				}
1166
			}
1167
			if (lineNumbering)
1168
			{
1169

    
1170
				options.setLineNumbering(true);
1171
			}
1172
			if (dtdValidation)
1173
			{
1174
				
1175
				options.setDTDValidationMode(JValidation.STRICT);
1176
			}
1177
			if (projectionQuery != null) {
1178
				net.sf.saxon.s9api.XQueryExecutable exp = projectionQuery.getUnderlyingCompiledQuery();
1179
				net.sf.saxon.@event.FilterFactory ff = config.makeDocumentProjector(exp.getUnderlyingCompiledQuery());
1180
				if (ff != null) {
1181
					
1182
					options.addFilter (ff);
1183
				}
1184
			}
1185

    
1186
		}
1187

    
1188
        /// <summary>
1189
		/// Load an XML document, delivered using an <c>XmlReader</c>.
1190
        /// </summary>
1191
        /// <remarks>
1192
		/// <para>The <c>XmlReader</c> is responsible for parsing the document; this method builds a tree
1193
        /// representation of the document (in an internal Saxon format) and returns its document node.
1194
		/// The <c>XmlReader</c> is not required to perform validation but it must expand any entity references.
1195
        /// Saxon uses the properties of the <c>XmlReader</c> as supplied.</para>
1196
        /// <para>Use of a plain <c>XmlTextReader</c> is discouraged, because it does not expand entity
1197
        /// references. This should only be used if you know in advance that the document will contain
1198
        /// no entity references (or perhaps if your query or stylesheet is not interested in the content
1199
        /// of text and attribute nodes). Instead, with .NET 1.1 use an <c>XmlValidatingReader</c> (with <c>ValidationType</c>
1200
        /// set to <c>None</c>). The constructor for <c>XmlValidatingReader</c> is obsolete in .NET 2.0,
1201
        /// but the same effect can be achieved by using the <c>Create</c> method of <c>XmlReader</c> with
1202
        /// appropriate <c>XmlReaderSettings</c>.</para>
1203
        /// <para>Conformance with the W3C specifications requires that the <c>Normalization</c> property
1204
        /// of an <c>XmlTextReader</c> should be set to <c>true</c>. However, Saxon does not insist
1205
        /// on this.</para>
1206
        /// <para>If the <c>XmlReader</c> performs schema validation, Saxon will ignore any resulting type
1207
        /// information. Type information can only be obtained by using Saxon's own schema validator, which
1208
        /// will be run if the <c>SchemaValidationMode</c> property is set to <c>Strict</c> or <c>Lax</c>.</para>
1209
        /// <para>Note that the Microsoft <c>System.Xml</c> parser does not report whether attributes are
1210
        /// defined in the DTD as being of type <c>ID</c> and <c>IDREF</c>. This is true whether or not
1211
        /// DTD-based validation is enabled. This means that such attributes are not accessible to the 
1212
        /// <c>id()</c> and <c>idref()</c> functions.</para>
1213
        /// <para>Note that setting the <c>XmlResolver</c> property of the <c>DocumentBuilder</c>
1214
        /// has no effect when this method is used; if an <c>XmlResolver</c> is required, it must
1215
        /// be set on the <c>XmlReader</c> itself.</para>
1216
        /// </remarks>
1217
		/// <param name="reader">The <c>XMLReader</c> that supplies the parsed XML source</param>
1218
        /// <returns>An <c>XdmNode</c>, the document node at the root of the tree of the resulting
1219
        /// in-memory document.
1220
        /// </returns>
1221

    
1222
        public XdmNode Build(XmlReader reader)
1223
        {
1224
            JPullProvider pp = new JDotNetPullProvider(reader);
1225
            pp.setPipelineConfiguration(config.makePipelineConfiguration());
1226
            // pp = new PullTracer(pp);  /* diagnostics */
1227
            JSource source = new JPullSource(pp);
1228
            source.setSystemId(reader.BaseURI);
1229
			JParseOptions options = new JParseOptions(config.getParseOptions());
1230

    
1231
            augmentParseOptions(options);
1232
			JNodeInfo doc = config.buildDocument(source, options);
1233
            return (XdmNode)XdmValue.Wrap(doc);
1234
        }
1235

    
1236
        /// <summary>
1237
		/// Load an XML DOM document, supplied as an <c>XmlNode</c>, into a Saxon <c>XdmNode</c>.
1238
        /// </summary>
1239
        /// <remarks>
1240
        /// <para>
1241
        /// The returned document will contain only the subtree rooted at the supplied node.
1242
        /// </para>
1243
        /// <para>
1244
        /// This method copies the DOM tree to create a Saxon tree. See the <c>Wrap</c> method for
1245
        /// an alternative that creates a wrapper around the DOM tree, allowing it to be modified in situ.
1246
        /// </para>
1247
        /// </remarks>
1248
        /// <param name="source">The DOM Node to be copied to form a Saxon tree</param>
1249
        /// <returns>An <c>XdmNode</c>, the document node at the root of the tree of the resulting
1250
        /// in-memory document.
1251
        /// </returns>
1252

    
1253
        public XdmNode Build(XmlNode source)
1254
        {
1255
            return Build(new XmlNodeReader(source));
1256
        }
1257

    
1258

    
1259
        /// <summary>
1260
        /// Wrap an XML DOM document, supplied as an <c>XmlNode</c>, as a Saxon <c>XdmNode</c>.
1261
        /// </summary>
1262
        /// <remarks>
1263
        /// <para>
1264
        /// This method must be applied at the level of the Document Node. Unlike the
1265
        /// <c>Build</c> method, the original DOM is not copied. This saves memory and
1266
        /// time, but it also means that it is not possible to perform operations such as
1267
        /// whitespace stripping and schema validation.
1268
        /// </para>
1269
        /// </remarks>
1270
        /// <param name="doc">The DOM document node to be wrapped</param>
1271
        /// <returns>An <c>XdmNode</c>, the Saxon document node at the root of the tree of the resulting
1272
        /// in-memory document.
1273
        /// </returns>
1274

    
1275
        public XdmNode Wrap(XmlDocument doc)
1276
        {
1277
            String baseu = (baseUri == null ? null : baseUri.ToString());
1278
            JDotNetDocumentWrapper wrapper = new JDotNetDocumentWrapper(doc, baseu, config);
1279
			return (XdmNode)XdmValue.Wrap(wrapper.getRootNode());
1280
        }
1281
    }
1282
    
1283
    /// <summary>The default Logger used by Saxon on the .NET platform. All messages are written by
1284
    /// default to System.err. The logger can be configured by setting a different output
1285
    /// destination, and by setting a minimum threshold for the severity of messages to be output.</summary>
1286

    
1287
    public class StandardLogger : JLogger {
1288
		
1289
		private TextWriter outi = Console.Error;
1290
		JDotNetWriter writer;
1291
		int threshold = JLogger.INFO;
1292
		java.io.PrintStream stream;
1293

    
1294
        /// <summary>
1295
        /// Default constructor that wraps a <c>TextWriter</c> to write Saxon messages
1296
        /// </summary>
1297
		public StandardLogger() {
1298
			writer = new JDotNetWriter(outi);
1299
		}
1300

    
1301
        /// <summary>
1302
        /// Constructor method to supply a user defined TextWriter to the logger
1303
        /// </summary>
1304
        /// <param name="w"></param>
1305
		public StandardLogger(TextWriter w) {
1306
			writer = new JDotNetWriter(w);
1307

    
1308
		}
1309

    
1310
        /// <summary>
1311
        /// Property to get the udnerlying TextWriter object.
1312
        /// </summary>
1313
		public JDotNetWriter UnderlyingTextWriter {
1314
			set {
1315
				writer = value;
1316
			}
1317
			get {
1318
				return writer;
1319
			}
1320
		}
1321

    
1322
		/// <summary> Set the minimum threshold for the severity of messages to be output. Defaults to
1323
		/// <see cref="net.sf.saxon.lib.Logger#INFO"/>. Messages whose severity is below this threshold will be ignored. </summary>
1324
		/// <param name="threshold">the minimum severity of messages to be output. </param>
1325
     
1326
		public int Threshold {
1327

    
1328
			set { 
1329
				threshold = value;
1330
			}
1331

    
1332
			get { 
1333
				return threshold;
1334
			}
1335

    
1336
		}
1337

    
1338
        /// <summary>
1339
        /// Java internal streamResult object wrapping the TextWriter
1340
        /// </summary>
1341
        /// <returns></returns>
1342
        public override JStreamResult asStreamResult()
1343
        {
1344
			return new JStreamResult(writer);
1345
        }
1346

    
1347
        /// <summary>
1348
        /// Write the message to the TextWriter object
1349
        /// </summary>
1350
        /// <param name="str">The message</param>
1351
        /// <param name="severity">the severity of the error message</param>
1352
        public override void println(string str, int severity)
1353
        {
1354
			if (severity >= threshold) {
1355
				writer.write (str);
1356
			}
1357
        }
1358
    }
1359

    
1360

    
1361
    /// <summary>
1362
    /// Enumeration identifying the various Schema validation modes
1363
    /// </summary>
1364

    
1365
    public enum SchemaValidationMode
1366
    {
1367
        /// <summary>No validation (or strip validation, which removes existing type annotations)</summary> 
1368
        None,
1369
        /// <summary>Strict validation</summary>
1370
        Strict,
1371
        /// <summary>Lax validation</summary>
1372
        Lax,
1373
        /// <summary>Validation mode preserve, which preserves any existing type annotations</summary>
1374
        Preserve,
1375
        /// <summary>Unspecified validation: this means that validation is defined elsewhere, for example in the
1376
		/// Saxon <c>Configuration</c></summary>
1377
        Unspecified
1378
    }
1379

    
1380

    
1381
    /// <summary>
1382
	/// <c>WhitespacePolicy</c> is a class defining the possible policies for handling
1383
    /// whitespace text nodes in a source document.
1384
    /// </summary>
1385
	/// <remarks>
1386
	/// Please note that since Saxon 9.7.0.8 this class has been refactored from the enumeration
1387
	/// type with the same name and therefore will work as before.
1388
	/// </remarks>
1389
    
1390
	[Serializable]
1391
    public class WhitespacePolicy
1392
    {
1393
       private int policy;
1394
       JSpaceStrippingRule stripperRules;
1395

    
1396
        /// <summary>All whitespace text nodes are stripped</summary>
1397
        public static WhitespacePolicy StripAll = new WhitespacePolicy(JWhitespace.ALL, net.sf.saxon.om.AllElementsSpaceStrippingRule.getInstance());
1398

    
1399
        /// <summary>Whitespace text nodes appearing in element-only content are stripped</summary>
1400
        public static WhitespacePolicy StripIgnorable = new WhitespacePolicy(JWhitespace.IGNORABLE, net.sf.saxon.om.IgnorableSpaceStrippingRule.getInstance());
1401

    
1402
        /// <summary>No whitespace is stripped</summary>
1403
        public static WhitespacePolicy PreserveAll = new WhitespacePolicy(JWhitespace.NONE, net.sf.saxon.om.NoElementsSpaceStrippingRule.getInstance());
1404

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

    
1408
        private WhitespacePolicy(int policy, JSpaceStrippingRule stripperRules)
1409
        {
1410
            this.policy = policy;
1411
            this.stripperRules = stripperRules;
1412
        }
1413

    
1414
        internal JSpaceStrippingRule GetSpaceStrippingRules() {
1415
            return stripperRules;
1416
        }
1417

    
1418

    
1419
        internal WhitespacePolicy(JXsltExecutable executable)
1420
        {
1421
            policy = Whitespace.XSLT;
1422
            stripperRules = executable.getUnderlyingCompiledStylesheet().getTopLevelPackage().getStripperRules();
1423
        }
1424

    
1425

    
1426
        /// <summary>
1427
        /// Create a custom whitespace stripping policy
1428
        /// </summary>
1429
        /// <param name="elementTest">a predicate applied to element names, which should return true if whitespace-only
1430
        /// text node children of the element are to be stripped, false if they are to be retained.</param>
1431
		/// <returns>A <c>WhitespacePolicy</c> object</returns>
1432
        public static WhitespacePolicy makeCustomPolicy(Predicate<QName> elementTest) {
1433
            JSpaceStrippingRule rule = new SpaceStrippingRule(elementTest);
1434

    
1435
            WhitespacePolicy wsp = new WhitespacePolicy(JWhitespace.XSLT, net.sf.saxon.om.NoElementsSpaceStrippingRule.getInstance());
1436
            wsp.stripperRules = rule;
1437
            return wsp;
1438
        }
1439

    
1440
        internal int ordinal() {
1441
            return policy;
1442
        }
1443

    
1444
        internal net.sf.saxon.@event.FilterFactory makeStripper() {
1445
            return new FilterFactory(stripperRules);
1446
        }       
1447

    
1448
    }
1449

    
1450

    
1451
    /// <summary>
1452
    /// Interface defining the predicate function, to be implementated by the caller
1453
    /// </summary>
1454
    /// <typeparam name="T"></typeparam>
1455
    public interface Predicate<T> {
1456

    
1457
        /// <summary>
1458
        /// Test whether a given item, at a given position in the sequence, matches the filter
1459
        /// </summary>
1460
        /// <param name="value">the value to be matched</param>
1461
        /// <returns>true if a match is found, false otherwise.</returns>
1462
		/**public**/ bool matches(T value);
1463
    }
1464

    
1465
    internal class SpaceStrippingRule : JSpaceStrippingRule
1466
    {
1467
        private Predicate<QName> elementTest;
1468

    
1469
        public SpaceStrippingRule(Predicate<QName> elementTest)
1470
        {
1471
            this.elementTest = elementTest;
1472
        }
1473

    
1474
        public void export(JExpressionPresenter ep)
1475
        {
1476
            throw new NotImplementedException(); 
1477
        }
1478

    
1479

    
1480
        public int isSpacePreserving(NodeName nn, JSchemaType st)
1481
        {
1482
            return elementTest.matches(new QName(nn.getStructuredQName().ToString())) ?
1483
                JStripper.ALWAYS_STRIP :
1484
                JStripper.ALWAYS_PRESERVE;
1485
        }
1486

    
1487
        public JProxyReceiver makeStripper(JReceiver r)
1488
        {
1489
            return new net.sf.saxon.@event.Stripper(this, r);
1490
        }
1491
    }
1492

    
1493
    internal class FilterFactory : JFilterFactory
1494
    {
1495
        JSpaceStrippingRule stripperRules;
1496
        public FilterFactory(JSpaceStrippingRule sr)
1497
        {
1498
            stripperRules = sr;
1499
        }
1500
        public JProxyReceiver makeFilter(JReceiver r)
1501
        {
1502
            return new net.sf.saxon.@event.Stripper(stripperRules, r);
1503
        }
1504

    
1505
        JReceiver JFilterFactory.makeFilter(JReceiver r)
1506
        {
1507
            return (JReceiver)new JStripper(stripperRules, r);
1508
        }
1509
    }
1510

    
1511
    /// <summary>
1512
    /// Enumeration identifying the different tree model implementations
1513
    /// </summary>
1514
    /// 
1515
    public enum TreeModel
1516
    {
1517
        /// <summary>
1518
		/// Saxon <c>TinyTree</c>. This is the default model and is suitable for most purposes.
1519
        /// </summary>
1520
        TinyTree,
1521
        /// <summary>
1522
		/// Saxon Condensed <c>TinyTree</c>. This is a variant of the <c>TinyTree</c> that shares storage for 
1523
        /// duplicated text and attribute nodes. It gives a further saving in space occupied, at the cost
1524
        /// of some increase in the time taken for tree construction.
1525
        /// </summary>
1526
        TinyTreeCondensed,
1527
        /// <summary>
1528
		/// Saxon <c>LinkedTree</c>. This tree model is primarily useful when using XQuery Update, since it is the
1529
        /// only standard tree model to support updates.
1530
        /// </summary>
1531
        LinkedTree,
1532
        /// <summary>
1533
        /// Unspecified tree model. This value is used to indicate that there is no preference for any specific
1534
        /// tree model, which allows the choice to fall back to other interfaces.
1535
        /// </summary>
1536
        Unspecified
1537
    }
1538

    
1539
    internal class DotNetObjectModelDefinition : JDotNetObjectModel
1540
    {
1541

    
1542
        public override bool isXdmValue(object obj)
1543
        {
1544
            return obj is XdmValue;
1545
        }
1546

    
1547
        public override bool isXdmAtomicValueType(System.Type type)
1548
        {
1549
            return typeof(XdmAtomicValue).IsAssignableFrom(type);
1550
        }
1551

    
1552
        public override bool isXdmValueType(System.Type type)
1553
        {
1554
            return typeof(XdmValue).IsAssignableFrom(type);
1555
        }
1556

    
1557
        public override JSequence unwrapXdmValue(object obj)
1558
        {
1559
            return ((XdmValue)obj).Unwrap();
1560
        }
1561

    
1562
        public override object wrapAsXdmValue(JSequence value)
1563
        {
1564
            return XdmValue.Wrap(value);
1565
        }
1566

    
1567
        public override bool isXmlNodeType(System.Type type)
1568
        {
1569
            return typeof(System.Xml.XmlNode).IsAssignableFrom(type);
1570
        }
1571

    
1572
    }
1573

    
1574
}
1575

    
1576
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1577
// Copyright (c) 2018 Saxonica Limited.
1578
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
1579
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
1580
// This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0.
1581
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
(1-1/13)