Project

Profile

Help

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

he / latest9.4 / hen / csource / api / Saxon.Api / Schema.cs @ c3c84ba2

1
using System;
2
using System.IO;
3
using System.Xml;
4
using System.Collections;
5
using javax.xml.transform;
6
using javax.xml.transform.stream;
7
using JAugmentedSource = net.sf.saxon.lib.AugmentedSource;
8
using JConfiguration = net.sf.saxon.Configuration;
9
using JController = net.sf.saxon.Controller;
10
using JFeatureKeys = net.sf.saxon.lib.FeatureKeys;
11
using JSchemaURIResolver = net.sf.saxon.lib.SchemaURIResolver;
12
using JReceiver = net.sf.saxon.@event.Receiver;
13
using JAtomicType = net.sf.saxon.type.AtomicType;
14
using JSchemaType = net.sf.saxon.type.SchemaType;
15
using JBuiltInAtomicType = net.sf.saxon.type.BuiltInAtomicType;
16
using JValidation = net.sf.saxon.lib.Validation;
17
using net.sf.saxon;
18
using net.sf.saxon.om;
19
using net.sf.saxon.pull;
20
using net.sf.saxon.@event;
21
using net.sf.saxon.dotnet;
22
using net.sf.saxon.type;
23

    
24

    
25
namespace Saxon.Api
26
{
27

    
28
    /// <summary>
29
    /// A <c>SchemaManager</c> is responsible for compiling schemas and
30
    /// maintaining a cache of compiled schemas that can be used for validating
31
    /// instance documents.
32
    /// </summary>
33
    /// <remarks>
34
    /// <para>To obtain a <c>SchemaManager</c>, use the 
35
    /// <c>SchemaManager</c> property of the <c>Processor</c> object.</para>
36
    /// <para>In a schema-aware Processor there is exactly one
37
    /// <c>SchemaManager</c> (in a non-schema-aware Processor there is none).</para>
38
    /// <para>The cache of compiled schema definitions can include only one schema
39
    /// component (for example a type, or an element declaration) with any given name.
40
    /// An attempt to compile two different schemas in the same namespace will usually
41
    /// therefore fail.</para>
42
    /// <para>As soon as a type definition or element declaration is used for the first
43
    /// time in a validation episode, it is marked as being "sealed": this prevents subsequent
44
    /// modifications to the component. Examples of modifications that are thereby disallowed
45
    /// include adding to the substitution group of an existing element declaration, adding subtypes
46
    /// to an existing type, or redefining components using &lt;xs:redefine&gt;</para>
47
    /// </remarks>
48

    
49
    [Serializable]
50
    public class SchemaManager
51
    {
52

    
53
        private JConfiguration config;
54
        private IList errorList = null;
55

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

    
59
        internal SchemaManager(net.sf.saxon.Configuration config)
60
        {
61
            this.config = (JConfiguration)config;
62
        }
63

    
64
        /// <summary>
65
        /// The version of the W3C XML Schema Specification handled by this SchemaManager
66
        /// </summary>
67
        /// <remarks>
68
        /// <para>The value must be "1.0" (indicating XML Schema 1.0) or "1.1" (indicating XML Schema 1.1.
69
        /// The default is "1.0". New constructs defined in XSD 1.1 are rejected unless this property
70
        /// is set to "1.1" before compiling the schema.
71
        /// </para>
72
        /// </remarks>
73
        /// 
74
        public String XsdVersion {
75
            get {
76
                return (String)config.getConfigurationProperty("http://saxon.sf.net/feature/xsd-version");
77
            }
78
            set {
79
                config.setConfigurationProperty("http://saxon.sf.net/feature/xsd-version", value);
80
            }
81
        }
82

    
83
        /// <summary>
84
        /// The SchemaResolver is a user-supplied class used for resolving references to
85
        /// schema documents. It applies to references from one schema document to another
86
        /// appearing in <c>xs:import</c>, <c>xs:include</c>, and <c>xs:redefine</c>; to
87
        /// references from an instance document to a schema in <c>xsi:schemaLocation</c> and
88
        /// <c>xsi:noNamespaceSchemaLocation</c>, to <c>xsl:import-schema</c> in XSLT, and to
89
        /// the <c>import schema</c> declaration in XQuery.
90
        /// </summary>
91

    
92
        public SchemaResolver SchemaResolver
93
        {
94
            get
95
            {
96
                JSchemaURIResolver r = config.getSchemaURIResolver();
97
                if (r is DotNetSchemaURIResolver)
98
                {
99
                    return ((DotNetSchemaURIResolver)r).resolver;
100
                }
101
                else
102
                {
103
                    return null;
104
                }
105
            }
106
            set
107
            {
108
                config.setSchemaURIResolver(new DotNetSchemaURIResolver(value));
109
            }
110
        }
111

    
112
        /// <summary>
113
        /// List of errors. The caller may supply an empty list before calling Compile;
114
        /// the processor will then populate the list with error information obtained during
115
        /// the schema compilation. Each error will be included as an object of type StaticError.
116
        /// If no error list is supplied by the caller, error information will be written to
117
        /// the standard error stream.
118
        /// </summary>
119
        /// <remarks>
120
        /// <para>By supplying a custom List with a user-written add() method, it is possible to
121
        /// intercept error conditions as they occur.</para>
122
        /// <para>Note that this error list is used only for errors detected during the compilation
123
        /// of the schema. It is not used for errors detected when using the schema to validate
124
        /// a source document.</para>
125
        /// </remarks>
126

    
127
        public IList ErrorList
128
        {
129
            set
130
            {
131
                errorList = value;
132
            }
133
            get
134
            {
135
                return errorList;
136
            }
137
        }
138

    
139
        /// <summary>
140
        /// Compile a schema supplied as a Stream. The resulting schema components are added
141
        /// to the cache.
142
        /// </summary>
143
        /// <param name="input">A stream containing the source text of the schema. This method
144
        /// will consume the supplied stream. It is the caller's responsibility to close the stream
145
        /// after use.</param>
146
        /// <param name="baseUri">The base URI of the schema document, for resolving any references to other
147
        /// schema documents</param>        
148

    
149
        public void Compile(Stream input, Uri baseUri)
150
        {
151
            StreamSource ss = new StreamSource(new DotNetInputStream(input));
152
            ss.setSystemId(baseUri.ToString());
153
            if (errorList == null)
154
            {
155
                config.addSchemaSource(ss);
156
            }
157
            else
158
            {
159
                config.addSchemaSource(ss, new ErrorGatherer(errorList));
160
            }
161
        }
162

    
163
        /// <summary>
164
        /// Compile a schema, retrieving the source using a URI. The resulting schema components are added
165
        /// to the cache.
166
        /// </summary>
167
        /// <remarks>
168
        /// The document located via the URI is parsed using the <c>System.Xml</c> parser.
169
        /// </remarks>
170
        /// <param name="uri">The URI identifying the location where the schema document can be
171
        /// found</param>
172

    
173
        public void Compile(Uri uri)
174
        {
175
            StreamSource ss = new StreamSource(uri.ToString());
176
            JAugmentedSource aug = JAugmentedSource.makeAugmentedSource(ss);
177
            aug.setPleaseCloseAfterUse(true);
178
            if (errorList == null)
179
            {
180
                config.addSchemaSource(aug);
181
            }
182
            else
183
            {
184
                config.addSchemaSource(aug, new ErrorGatherer(errorList));
185
            }
186
        }
187

    
188
        /// <summary>
189
        /// Compile a schema, delivered using an XmlReader. The resulting schema components are added
190
        /// to the cache.
191
        /// </summary>
192
        /// <remarks>
193
        /// The <c>XmlReader</c> is responsible for parsing the document; this method builds a tree
194
        /// representation of the document (in an internal Saxon format) and compiles it.
195
        /// The <c>XmlReader</c> is used as supplied; it is the caller's responsibility to ensure that
196
        /// its settings are appropriate for parsing a schema document (for example, that entity references
197
        /// are expanded and whitespace is retained.)
198
        /// </remarks>
199
        /// <param name="reader">The XmlReader (that is, the XML parser) used to supply the source schema document</param>
200

    
201
        public void Compile(XmlReader reader)
202
        {
203
            PullProvider pp = new DotNetPullProvider(reader);
204
            pp.setPipelineConfiguration(config.makePipelineConfiguration());
205
            // pp = new PullTracer(pp);  /* diagnostics */
206
            PullSource ss = new PullSource(pp);
207
            ss.setSystemId(reader.BaseURI);
208
            if (errorList == null)
209
            {
210
                config.addSchemaSource(ss);
211
            }
212
            else
213
            {
214
                config.addSchemaSource(ss, new ErrorGatherer(errorList));
215
            }
216
        }
217

    
218
        /// <summary>
219
        /// Compile a schema document, located at an XdmNode. This may be a document node whose
220
        /// child is an <c>xs:schema</c> element, or it may be
221
        /// the <c>xs:schema</c> element itself. The resulting schema components are added
222
        /// to the cache.
223
        /// </summary>
224
        /// <param name="node">The document node or the outermost element node of a schema document.</param>
225

    
226
        public void Compile(XdmNode node)
227
        {
228
            ErrorGatherer eg = null;
229
            if (errorList != null)
230
            {
231
                eg = new ErrorGatherer(errorList);
232
            }
233
            try
234
            {
235
                config.readInlineSchema((NodeInfo)node.value, null, eg);
236
            }
237
            catch (SchemaException e)
238
            {
239
                throw new StaticError(e);
240
            }
241
        }
242

    
243
        /// <summary>
244
        /// Create a new <c>SchemaValidator</c>, which may be used for validating instance
245
        /// documents.
246
        /// </summary>
247
        /// <remarks>
248
        /// <para>The <c>SchemaValidator</c> uses the cache of schema components held by the
249
        /// <c>SchemaManager</c>. It may also add new components to this cache (for example,
250
        /// when the instance document references a schema using <c>xsi:schemaLocation</c>).
251
        /// It is also affected by changes to the schema cache that occur after the 
252
        /// <c>SchemaValidator</c> is created.</para>
253
        /// <para>When schema components are used for validating instance documents (or for compiling
254
        /// schema-aware queries and stylesheets) they are <i>sealed</i> to prevent subsequent modification.
255
        /// The modifications disallowed once a component is sealed include adding to the substitution group
256
        /// of an element declaration, adding subtypes derived by extension to an existing complex type, and
257
        /// use of <c>&lt;xs:redefine&gt;</c></para>
258
        /// </remarks>
259

    
260
        public SchemaValidator NewSchemaValidator()
261
        {
262
            return new SchemaValidator(config);
263
        }
264

    
265
        /// <summary>
266
        /// Factory method to get an <c>AtomicType</c> object representing the atomic type with a given QName.
267
        /// </summary>
268
        /// <remarks>
269
        /// It is undefined whether two calls on this method supplying the same QName will return the same
270
        /// <c>XdmAtomicType</c> object instance.
271
        /// </remarks>
272
        /// <param name="qname">The QName of the required type</param>
273
        /// <returns>An <c>AtomicType</c> object representing this type if it is present in this schema (and is an
274
        /// atomic type); otherwise, null. </returns>
275

    
276
        public XdmAtomicType GetAtomicType(QName qname)
277
        {
278
            int fp = qname.GetFingerprint(config);
279
            JSchemaType type = config.getSchemaType(fp);
280
            if (type is JBuiltInAtomicType)
281
            {
282
                return XdmAtomicType.BuiltInAtomicType(qname);
283
            }
284
            else if (type is JAtomicType)
285
            {
286
                return new XdmAtomicType((JAtomicType)type);
287
            }
288
            else
289
            {
290
                return null;
291
            }
292
        }
293

    
294
    }
295

    
296
    /// <summary>
297
    /// A <c>SchemaValidator</c> is an object that is used for validating instance documents
298
    /// against a schema. The schema consists of the collection of schema components that are
299
    /// available within the schema cache maintained by the <c>SchemaManager</c>, together with
300
    /// any additional schema components located during the course of validation by means of an
301
    /// <c>xsl:schemaLocation</c> or <c>xsi:noNamespaceSchemaLocation</c> attribute within the
302
    /// instance document.
303
    /// </summary>
304
    /// <remarks>
305
    /// If validation fails, an exception is thrown. If validation succeeds, the validated
306
    /// document can optionally be written to a specified destination. This will be a copy of
307
    /// the original document, augmented with default values for absent elements and attributes,
308
    /// and carrying type annotations derived from the schema processing. Saxon does not deliver
309
    /// the full PSVI as described in the XML schema specifications, only the subset of the
310
    /// PSVI properties featured in the XDM data model.
311
    /// </remarks>    
312

    
313
    [Serializable]
314
    public class SchemaValidator
315
    {
316

    
317
        private JConfiguration config;
318
        private bool lax = false;
319
        private Source source;
320
        private XmlDestination destination;
321
        private IList errorList = null;
322
        private bool useXsiSchemaLocation;
323

    
324
        // internal constructor
325

    
326
        internal SchemaValidator(JConfiguration config)
327
        {
328
            this.config = config;
329
            Object obj = config.getConfigurationProperty(JFeatureKeys.USE_XSI_SCHEMA_LOCATION);
330
            useXsiSchemaLocation = ((java.lang.Boolean)obj).booleanValue();
331
        }
332

    
333
        /// <summary>
334
        /// The validation mode may be either strict or lax. The default is strict;
335
        /// this property is set to indicate that lax validation is required. With strict validation,
336
        /// validation fails if no element declaration can be located for the outermost element. With lax
337
        /// validation, the absence of an element declaration results in the content being considered valid.
338
        /// </summary>
339

    
340
        public bool IsLax
341
        {
342
            get { return lax; }
343
            set { lax = value; }
344
        }
345

    
346
        /// <summary>
347
        /// This property defines whether the schema processor will recognize, and attempt to
348
        /// dereference, any <c>xsi:schemaLocation</c> and <c>xsi:noNamespaceSchemaLocation</c>
349
        /// attributes encountered in the instance document. The default value is true.
350
        /// </summary>
351

    
352
        public Boolean UseXsiSchemaLocation
353
        {
354
            get
355
            {
356
                return useXsiSchemaLocation;
357
            }
358
            set
359
            {
360
                useXsiSchemaLocation = value;
361
            }
362
        }
363

    
364
        /// <summary>
365
        /// Supply the instance document to be validated in the form of a Stream
366
        /// </summary>
367
        /// <param name="source">A stream containing the XML document to be parsed
368
        /// and validated. This stream will be consumed by the validation process,
369
        /// but it will not be closed after use: that is the responsibility of the
370
        /// caller.</param>
371
        /// <param name="baseUri">The base URI to be used for resolving any relative
372
        /// references, for example a reference to an <c>xsi:schemaLocation</c></param>                  
373

    
374
        public void SetSource(Stream source, Uri baseUri)
375
        {
376
            StreamSource ss = new StreamSource(new DotNetInputStream(source));
377
            ss.setSystemId(baseUri.ToString());
378
            this.source = ss;
379
        }
380

    
381
        /// <summary>
382
        /// Supply the instance document to be validated in the form of a Uri reference
383
        /// </summary>
384
        /// <param name="uri">URI of the document to be validated</param>                  
385

    
386
        public void SetSource(Uri uri)
387
        {
388
            StreamSource ss = new StreamSource(uri.ToString());
389
            JAugmentedSource aug = JAugmentedSource.makeAugmentedSource(ss);
390
            aug.setPleaseCloseAfterUse(true);
391
            this.source = aug;
392
        }
393

    
394
        /// <summary>
395
        /// Supply the instance document to be validated, in the form of an XmlReader.
396
        /// </summary>
397
        /// <remarks>
398
        /// The XmlReader is responsible for parsing the document; this method validates it.
399
        /// </remarks>
400
        /// <param name="reader">The <c>XmlReader</c> used to read and parse the instance
401
        /// document being validated. This is used as supplied. For conformance, use of a
402
        /// plain <c>XmlTextReader</c> is discouraged, because it does not expand entity
403
        /// references. This may cause validation failures.
404
        /// </param>
405

    
406
        public void SetSource(XmlReader reader)
407
        {
408
            PullProvider pp = new DotNetPullProvider(reader);
409
            PipelineConfiguration pipe = config.makePipelineConfiguration();
410
            pipe.setUseXsiSchemaLocation(useXsiSchemaLocation);
411
            pp.setPipelineConfiguration(pipe);
412
            // pp = new PullTracer(pp);  /* diagnostics */
413
            PullSource psource = new PullSource(pp);
414
            psource.setSystemId(reader.BaseURI);
415
            this.source = psource;
416
        }
417

    
418
        /// <summary>
419
        /// Supply the instance document to be validated in the form of an XdmNode
420
        /// </summary>
421
        /// <remarks>
422
        /// <para>The supplied node must be either a document node or an element node.
423
        /// If an element node is supplied, then the subtree rooted at this element is
424
        /// validated as if it were a complete document: that is, it must not only conform
425
        /// to the structure required of that element, but any referential constraints
426
        /// (keyref, IDREF) must be satisfied within that subtree.
427
        /// </para>
428
        /// </remarks>
429
        /// <param name="source">The document or element node at the root of the tree
430
        /// to be validated</param>        
431

    
432
        public void SetSource(XdmNode source)
433
        {
434
            this.source = (NodeInfo)source.value;
435
        }
436

    
437
        /// <summary>
438
        /// Supply the destination to hold the validated document. If no destination
439
        /// is supplied, the validated document is discarded.
440
        /// </summary>
441
        /// <remarks>
442
        /// The destination differs from the source in that (a) default values of missing
443
        /// elements and attributes are supplied, and (b) the typed values of elements and
444
        /// attributes are available. However, typed values can only be accessed if the result
445
        /// is represented using the XDM data model, that is, if the destination is supplied
446
        /// as an XdmDestination.
447
        /// </remarks>
448
        /// <param name="destination">
449
        /// The destination to hold the validated document.
450
        /// </param>
451

    
452
        public void SetDestination(XmlDestination destination)
453
        {
454
            this.destination = destination;
455
        }
456

    
457
        /// <summary>
458
        /// List of errors. The caller may supply an empty list before calling Compile;
459
        /// the processor will then populate the list with error information obtained during
460
        /// the schema compilation. Each error will be included as an object of type StaticError.
461
        /// If no error list is supplied by the caller, error information will be written to
462
        /// the standard error stream.
463
        /// </summary>
464
        /// <remarks>
465
        /// <para>By supplying a custom List with a user-written add() method, it is possible to
466
        /// intercept error conditions as they occur.</para>
467
        /// <para>Note that this error list is used only for errors detected while 
468
        /// using the schema to validate a source document. It is not used to report errors
469
        /// in the schema itself.</para>
470
        /// </remarks>
471

    
472
        public IList ErrorList
473
        {
474
            set
475
            {
476
                errorList = value;
477
            }
478
            get
479
            {
480
                return errorList;
481
            }
482
        }
483

    
484

    
485
        /// <summary>
486
        /// Run the validation of the supplied source document, optionally
487
        /// writing the validated document to the supplied destination.
488
        /// </summary>
489

    
490
        public void Run()
491
        {
492
            JAugmentedSource aug = JAugmentedSource.makeAugmentedSource(source);
493
            aug.setSchemaValidationMode(lax ? JValidation.LAX : JValidation.STRICT);
494
            JReceiver receiver;
495
            PipelineConfiguration pipe = config.makePipelineConfiguration();
496
            if (destination == null)
497
            {               
498
                receiver = new Sink(pipe);
499
            }
500
            else if (destination is Serializer)
501
            {
502
                receiver = ((Serializer)destination).GetReceiver(config);
503
            }
504
            else
505
            {
506
                Result result = destination.GetResult(pipe);
507
                if (result is JReceiver)
508
                {
509
                    receiver = (JReceiver)result;
510
                }
511
                else
512
                {
513
                    throw new ArgumentException("Unknown type of destination");
514
                }
515
            }
516
            pipe.setUseXsiSchemaLocation(useXsiSchemaLocation);
517
            receiver.setPipelineConfiguration(pipe);
518
            if (errorList != null)
519
            {
520
                pipe.setErrorListener(new ErrorGatherer(errorList));
521
            }
522
            Sender.send(aug, receiver, null);
523
        }
524

    
525
    }
526

    
527

    
528
    /// <summary>
529
    /// The SchemaResolver is a user-supplied class used for resolving references to
530
    /// schema documents. It applies to references from one schema document to another
531
    /// appearing in <c>xs:import</c>, <c>xs:include</c>, and <c>xs:redefine</c>; to
532
    /// references from an instance document to a schema in <c>xsi:schemaLocation</c> and
533
    /// <c>xsi:noNamespaceSchemaLocation</c>, to <c>xsl:import-schema</c> in XSLT, and to
534
    /// the <c>import schema</c> declaration in XQuery.
535
    /// </summary>
536

    
537

    
538
    public interface SchemaResolver
539
    {
540

    
541
        /// <summary>
542
        /// Given a targetNamespace and a set of location hints, return a set of schema documents.
543
        /// </summary>
544
        /// <param name="targetNamespace">The target namespace of the required schema components</param>
545
        /// <param name="baseUri">The base URI of the module containing the reference to a schema document
546
        /// declaration</param>
547
        /// <param name="locationHints">The sequence of URIs (if any) listed as location hints.
548
        /// In most cases there will only be one; but the <c>import schema</c> declaration in
549
        /// XQuery permits several.</param>
550
        /// <returns>A set of absolute Uris identifying the query modules to be loaded. There is no requirement
551
        /// that these correspond one-to-one with the URIs defined in the <c>locationHints</c>. The 
552
        /// returned URIs will be dereferenced by calling the <c>GetEntity</c> method.
553
        /// </returns>
554

    
555
        Uri[] GetSchemaDocuments(String targetNamespace, Uri baseUri, String[] locationHints);
556

    
557
        /// <summary>
558
        /// Dereference a URI returned by <c>GetModules</c> to retrieve a <c>Stream</c> containing
559
        /// the actual XML schema document.
560
        /// </summary>
561
        /// <param name="absoluteUri">A URI returned by the <code>GetSchemaDocuments</code> method.</param>
562
        /// <returns>Either a <c>Stream</c> or a <c>String</c> containing the query text. 
563
        /// The supplied URI will be used as the base URI of the query module.</returns>
564

    
565
        Object GetEntity(Uri absoluteUri);
566

    
567
    }
568

    
569
    // internal class that wraps a (.NET) QueryResolver to create a (Java) SchemaURIResolver
570

    
571
    internal class DotNetSchemaURIResolver : net.sf.saxon.lib.SchemaURIResolver
572
    {
573

    
574
        internal SchemaResolver resolver;
575
        internal JConfiguration config;
576

    
577
        public DotNetSchemaURIResolver(SchemaResolver resolver)
578
        {
579
            this.resolver = resolver;
580
        }
581

    
582
        public void setConfiguration(JConfiguration config)
583
        {
584
            this.config = config;
585
        }
586

    
587
        public Source[] resolve(String targetNamespace, String baseURI, String[] locations)
588
        {
589
            if (config.isSchemaAvailable(targetNamespace))
590
            {
591
                return new Source[0];
592
            }
593
            Uri baseU = (baseURI == null ? null : new Uri(baseURI));
594
            Uri[] modules = resolver.GetSchemaDocuments(targetNamespace, baseU, locations);
595
            StreamSource[] ss = new StreamSource[modules.Length];
596
            for (int i = 0; i < ss.Length; i++)
597
            {
598
                ss[i] = new StreamSource();
599
                ss[i].setSystemId(modules[i].ToString());
600
                Object doc = resolver.GetEntity(modules[i]);
601
                if (doc is Stream)
602
                {
603
                    ss[i].setInputStream(new DotNetInputStream((Stream)doc));
604
                }
605
                else if (doc is String)
606
                {
607
                    ss[i].setReader(new DotNetReader(new StringReader((String)doc)));
608
                }
609
                else
610
                {
611
                    throw new ArgumentException("Invalid response from GetEntity()");
612
                }
613
            }
614
            return ss;
615
        }
616
    }
617

    
618

    
619

    
620

    
621

    
622

    
623
}
624

    
625
//
626
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
627
// you may not use this file except in compliance with the License. You may obtain a copy of the
628
// License at http://www.mozilla.org/MPL/
629
//
630
// Software distributed under the License is distributed on an "AS IS" basis,
631
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
632
// See the License for the specific language governing rights and limitations under the License.
633
//
634
// The Original Code is: all this file.
635
//
636
// The Initial Developer of the Original Code is Michael H. Kay.
637
//
638
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
639
//
640
// Contributor(s): none.
641
//
(8-8/12)