1 //------------------------------------------------------------------------------
2 // <copyright file="XmlSchemaCollection.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 // <owner current="true" primary="true">Microsoft</owner>
6 //------------------------------------------------------------------------------
8 namespace System.Xml.Schema {
11 using System.Threading;
12 using System.Collections;
13 using System.Xml.Schema;
14 using System.Runtime.Versioning;
17 /// <include file='doc\XmlSchemaCollection.uex' path='docs/doc[@for="XmlSchemaCollection"]/*' />
19 /// <para>The XmlSchemaCollection contains a set of namespace URI's.
20 /// Each namespace also have an associated private data cache
21 /// corresponding to the XML-Data Schema or W3C XML Schema.
22 /// The XmlSchemaCollection will able to load XSD and XDR schemas,
23 /// and compile them into an internal "cooked schema representation".
24 /// The Validate method then uses this internal representation for
25 /// efficient runtime validation of any given subtree.</para>
27 [Obsolete("Use System.Xml.Schema.XmlSchemaSet for schema compilation and validation. http://go.microsoft.com/fwlink/?linkid=14202")]
28 public sealed class XmlSchemaCollection: ICollection {
29 private Hashtable collection;
30 private XmlNameTable nameTable;
31 private SchemaNames schemaNames;
32 private ReaderWriterLock wLock;
33 private int timeout = Timeout.Infinite;
34 private bool isThreadSafe = true;
35 private ValidationEventHandler validationEventHandler = null;
36 private XmlResolver xmlResolver = null;
39 /// <include file='doc\XmlSchemaCollection.uex' path='docs/doc[@for="XmlSchemaCollection.XmlSchemaCollection"]/*' />
41 /// <para>Construct a new empty schema collection.</para>
43 public XmlSchemaCollection() : this(new NameTable()) {
46 /// <include file='doc\XmlSchemaCollection.uex' path='docs/doc[@for="XmlSchemaCollection.XmlSchemaCollection1"]/*' />
48 /// <para>Construct a new empty schema collection with associated XmlNameTable.
49 /// The XmlNameTable is used when loading schemas</para>
51 public XmlSchemaCollection(XmlNameTable nametable) {
52 if (nametable == null) {
53 throw new ArgumentNullException("nametable");
55 nameTable = nametable;
56 collection = Hashtable.Synchronized(new Hashtable());
57 xmlResolver = System.Xml.XmlConfiguration.XmlReaderSection.CreateDefaultResolver();
60 wLock = new ReaderWriterLock();
64 /// <include file='doc\XmlSchemaCollection.uex' path='docs/doc[@for="XmlSchemaCollection.Count"]/*' />
66 /// <para>Returns the number of namespaces defined in this collection
67 /// (whether or not there is an actual schema associated with those namespaces or not).</para>
70 get { return collection.Count;}
73 /// <include file='doc\XmlSchemaCollection.uex' path='docs/doc[@for="XmlSchemaCollection.NameTable"]/*' />
75 /// <para>The default XmlNameTable used by the XmlSchemaCollection when loading new schemas.</para>
77 public XmlNameTable NameTable {
78 get { return nameTable;}
81 /// <include file='doc\XmlSchemaCollection.uex' path='docs/doc[@for="XmlSchemaCollection.ValidationEventHandler"]/*' />
82 public event ValidationEventHandler ValidationEventHandler {
83 add { validationEventHandler += value; }
84 remove { validationEventHandler -= value; }
87 internal XmlResolver XmlResolver
95 /// <include file='doc\XmlSchemaCollection.uex' path='docs/doc[@for="XmlSchemaCollection.Add"]/*' />
97 /// <para>Add the schema located by the given URL into the schema collection.
98 /// If the given schema references other namespaces, the schemas for those other
99 /// namespaces are NOT automatically loaded.</para>
101 [ResourceConsumption(ResourceScope.Machine)]
102 [ResourceExposure(ResourceScope.Machine)]
103 public XmlSchema Add(string ns, string uri) {
104 if (uri == null || uri.Length == 0)
105 throw new ArgumentNullException("uri");
106 XmlTextReader reader = new XmlTextReader(uri, nameTable);
107 reader.XmlResolver = xmlResolver;
109 XmlSchema schema = null;
111 schema = Add(ns, reader, xmlResolver);
112 while(reader.Read());// wellformness check
120 /// <include file='doc\XmlSchemaCollection.uex' path='docs/doc[@for="XmlSchemaCollection.Add4"]/*' />
121 public XmlSchema Add(String ns, XmlReader reader) {
122 return Add(ns, reader, xmlResolver);
125 /// <include file='doc\XmlSchemaCollection.uex' path='docs/doc[@for="XmlSchemaCollection.Add1"]/*' />
127 /// <para>Add the given schema into the schema collection.
128 /// If the given schema references other namespaces, the schemas for those
129 /// other namespaces are NOT automatically loaded.</para>
131 public XmlSchema Add(String ns, XmlReader reader, XmlResolver resolver) {
133 throw new ArgumentNullException("reader");
134 XmlNameTable readerNameTable = reader.NameTable;
135 SchemaInfo schemaInfo = new SchemaInfo();
137 Parser parser = new Parser(SchemaType.None, readerNameTable, GetSchemaNames(readerNameTable), validationEventHandler);
138 parser.XmlResolver = resolver;
139 SchemaType schemaType;
141 schemaType = parser.Parse(reader, ns);
143 catch (XmlSchemaException e) {
144 SendValidationEvent(e);
148 if (schemaType == SchemaType.XSD) {
149 schemaInfo.SchemaType = SchemaType.XSD;
150 return Add(ns, schemaInfo, parser.XmlSchema, true, resolver);
153 SchemaInfo xdrSchema = parser.XdrSchema;
154 return Add(ns, parser.XdrSchema, null, true, resolver);
158 /// <include file='doc\XmlSchemaCollection.uex' path='docs/doc[@for="XmlSchemaCollection.Add2"]/*' />
160 /// <para>[To be supplied.]</para>
162 public XmlSchema Add(XmlSchema schema) {
163 return Add(schema, xmlResolver);
166 /// <include file='doc\XmlSchemaCollection.uex' path='docs/doc[@for="XmlSchemaCollection.Add5"]/*' />
167 public XmlSchema Add(XmlSchema schema, XmlResolver resolver) {
169 throw new ArgumentNullException("schema");
171 SchemaInfo schemaInfo = new SchemaInfo();
172 schemaInfo.SchemaType = SchemaType.XSD;
173 return Add(schema.TargetNamespace, schemaInfo, schema, true, resolver);
176 /// <include file='doc\XmlSchemaCollection.uex' path='docs/doc[@for="XmlSchemaCollection.Add3"]/*' />
178 /// <para>Adds all the namespaces defined in the given collection
179 /// (including their associated schemas) to this collection.</para>
181 public void Add(XmlSchemaCollection schema) {
183 throw new ArgumentNullException("schema");
186 IDictionaryEnumerator enumerator = schema.collection.GetEnumerator();
187 while (enumerator.MoveNext()) {
188 XmlSchemaCollectionNode node = (XmlSchemaCollectionNode) enumerator.Value;
189 Add(node.NamespaceURI, node);
194 /// <include file='doc\XmlSchemaCollection.uex' path='docs/doc[@for="XmlSchemaCollection.this"]/*' />
196 /// <para>Looks up the schema by it's associated namespace URI</para>
198 public XmlSchema this[string ns] {
200 XmlSchemaCollectionNode node = (XmlSchemaCollectionNode)collection[(ns != null) ? ns: string.Empty];
201 return (node != null) ? node.Schema : null;
205 /// <include file='doc\XmlSchemaCollection.uex' path='docs/doc[@for="XmlSchemaCollection.Contains"]/*' />
207 /// <para>[To be supplied.]</para>
209 public bool Contains(XmlSchema schema) {
210 if (schema == null) {
211 throw new ArgumentNullException("schema");
213 return this[schema.TargetNamespace] != null;
216 /// <include file='doc\XmlSchemaCollection.uex' path='docs/doc[@for="XmlSchemaCollection.Contains1"]/*' />
217 public bool Contains(string ns) {
218 return collection[(ns != null) ? ns : string.Empty] != null;
221 /// <include file='doc\XmlSchemaCollection.uex' path='docs/doc[@for="XmlSchemaCollection.IEnumerable.GetEnumerator"]/*' />
224 /// Get a IEnumerator of the XmlSchemaCollection.
226 IEnumerator IEnumerable.GetEnumerator() {
227 return new XmlSchemaCollectionEnumerator(collection);
230 /// <include file='doc\XmlSchemaCollection.uex' path='docs/doc[@for="XmlSchemaCollection.GetEnumerator"]/*' />
231 public XmlSchemaCollectionEnumerator GetEnumerator() {
232 return new XmlSchemaCollectionEnumerator(collection);
235 /// <include file='doc\XmlSchemaCollection.uex' path='docs/doc[@for="XmlSchemaCollection.ICollection.CopyTo"]/*' />
237 void ICollection.CopyTo(Array array, int index) {
239 throw new ArgumentNullException("array");
241 throw new ArgumentOutOfRangeException("index");
242 for (XmlSchemaCollectionEnumerator e = this.GetEnumerator(); e.MoveNext();) {
243 if (index == array.Length && array.IsFixedSize) {
244 throw new ArgumentOutOfRangeException("index");
246 array.SetValue(e.Current, index++);
250 /// <include file='doc\XmlSchemaCollection.uex' path='docs/doc[@for="XmlSchemaCollection.CopyTo"]/*' />
252 /// <para>[To be supplied.]</para>
254 public void CopyTo(XmlSchema[] array, int index) {
256 throw new ArgumentNullException("array");
258 throw new ArgumentOutOfRangeException("index");
259 for (XmlSchemaCollectionEnumerator e = this.GetEnumerator(); e.MoveNext();) {
260 XmlSchema schema = e.Current;
261 if (schema != null) {
262 if (index == array.Length) {
263 throw new ArgumentOutOfRangeException("index");
265 array[index++] = e.Current;
270 /// <include file='doc\XmlSchemaCollection.uex' path='docs/doc[@for="XmlSchemaCollection.ICollection.IsSynchronized"]/*' />
272 bool ICollection.IsSynchronized {
276 /// <include file='doc\XmlSchemaCollection.uex' path='docs/doc[@for="XmlSchemaCollection.ICollection.SyncRoot"]/*' />
278 object ICollection.SyncRoot {
282 /// <include file='doc\XmlSchemaCollection.uex' path='docs/doc[@for="XmlSchemaCollection.ICollection.Count"]/*' />
284 int ICollection.Count {
285 get { return collection.Count; }
288 internal SchemaInfo GetSchemaInfo(string ns) {
289 XmlSchemaCollectionNode node = (XmlSchemaCollectionNode)collection[(ns != null) ? ns : string.Empty];
290 return (node != null) ? node.SchemaInfo : null;
293 internal SchemaNames GetSchemaNames(XmlNameTable nt) {
294 if (nameTable != nt) {
295 return new SchemaNames(nt);
298 if (schemaNames == null) {
299 schemaNames = new SchemaNames( nameTable );
305 internal XmlSchema Add(string ns, SchemaInfo schemaInfo, XmlSchema schema, bool compile) {
306 return Add(ns, schemaInfo, schema, compile, xmlResolver);
309 private XmlSchema Add(string ns, SchemaInfo schemaInfo, XmlSchema schema, bool compile, XmlResolver resolver) {
311 if (schema != null) {
312 if (schema.ErrorCount == 0 && compile) {
313 if (!schema.CompileSchema(this, resolver, schemaInfo, ns, validationEventHandler, nameTable, true)) {
316 ns = schema.TargetNamespace == null ? string.Empty : schema.TargetNamespace;
318 errorCount += schema.ErrorCount;
321 errorCount += schemaInfo.ErrorCount;
322 //ns = ns == null? string.Empty : NameTable.Add(ns);
323 ns = NameTable.Add(ns); //Added without checking for ns == null, since XDR cannot have null namespace
325 if (errorCount == 0) {
326 XmlSchemaCollectionNode node = new XmlSchemaCollectionNode();
327 node.NamespaceURI = ns;
328 node.SchemaInfo = schemaInfo;
329 node.Schema = schema;
336 private void Add(string ns, XmlSchemaCollectionNode node) {
338 wLock.AcquireWriterLock(timeout);
340 if (collection[ns] != null)
341 collection.Remove(ns);
342 collection.Add(ns, node);
346 wLock.ReleaseWriterLock();
350 private void SendValidationEvent(XmlSchemaException e) {
351 if (validationEventHandler != null) {
352 validationEventHandler(this, new ValidationEventArgs(e));
359 internal ValidationEventHandler EventHandler {
361 return validationEventHandler;
364 validationEventHandler = value;
370 internal sealed class XmlSchemaCollectionNode {
371 private String namespaceUri;
372 private SchemaInfo schemaInfo;
373 private XmlSchema schema;
375 internal String NamespaceURI {
376 get { return namespaceUri;}
377 set { namespaceUri = value;}
380 internal SchemaInfo SchemaInfo {
381 get { return schemaInfo;}
382 set { schemaInfo = value;}
385 internal XmlSchema Schema {
386 get { return schema;}
387 set { schema = value;}
392 /// <include file='doc\XmlSchemaCollection.uex' path='docs/doc[@for="XmlSchemaCollectionEnumerator"]/*' />
394 /// <para>[To be supplied.]</para>
396 public sealed class XmlSchemaCollectionEnumerator: IEnumerator {
397 private IDictionaryEnumerator enumerator;
399 internal XmlSchemaCollectionEnumerator( Hashtable collection ) {
400 enumerator = collection.GetEnumerator();
403 /// <include file='doc\XmlSchemaCollection.uex' path='docs/doc[@for="XmlSchemaCollectionEnumerator.IEnumerator.Reset"]/*' />
405 void IEnumerator.Reset() {
409 /// <include file='doc\XmlSchemaCollection.uex' path='docs/doc[@for="XmlSchemaCollectionEnumerator.IEnumerator.MoveNext"]/*' />
411 bool IEnumerator.MoveNext() {
412 return enumerator.MoveNext();
415 /// <include file='doc\XmlSchemaCollection.uex' path='docs/doc[@for="XmlSchemaCollectionEnumerator.MoveNext"]/*' />
417 /// <para>[To be supplied.]</para>
419 public bool MoveNext() {
420 return enumerator.MoveNext();
423 /// <include file='doc\XmlSchemaCollection.uex' path='docs/doc[@for="XmlSchemaCollectionEnumerator.IEnumerator.Current"]/*' />
425 object IEnumerator.Current {
426 get { return this.Current; }
429 /// <include file='doc\XmlSchemaCollection.uex' path='docs/doc[@for="XmlSchemaCollectionEnumerator.Current"]/*' />
431 /// <para>[To be supplied.]</para>
433 public XmlSchema Current {
435 XmlSchemaCollectionNode n = (XmlSchemaCollectionNode)enumerator.Value;
443 internal XmlSchemaCollectionNode CurrentNode {
445 XmlSchemaCollectionNode n = (XmlSchemaCollectionNode)enumerator.Value;