Copied remotely
[mono.git] / mcs / class / System.XML / System.Xml.Schema / XmlSchema.cs
1 //
2 // System.Xml.Schema.XmlSchema.cs
3 //
4 // Author:
5 //      Dwivedi, Ajay kumar  Adwiv@Yahoo.com
6 //      Atsushi Enomoto  ginga@kit.hi-ho.ne.jp
7 //
8
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
17 // 
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 // 
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 //
29 using System;
30 using System.Collections;
31 using System.Xml;
32 using System.IO;
33 using System.Xml.Serialization;
34 using System.ComponentModel;
35
36 namespace System.Xml.Schema
37 {
38         /// <summary>
39         /// Summary description for XmlSchema.
40         /// </summary>
41         [XmlRoot ("schema",Namespace=XmlSchema.Namespace)]
42         public class XmlSchema : XmlSchemaObject
43         {
44                 //public constants
45                 public const string Namespace = "http://www.w3.org/2001/XMLSchema";
46                 public const string InstanceNamespace = "http://www.w3.org/2001/XMLSchema-instance";
47                 internal const string XdtNamespace = "http://www.w3.org/2003/11/xpath-datatypes";
48
49                 //private fields
50                 private XmlSchemaForm attributeFormDefault ;
51                 private XmlSchemaObjectTable attributeGroups ;
52                 private XmlSchemaObjectTable attributes ;
53                 private XmlSchemaDerivationMethod blockDefault ;
54                 private XmlSchemaForm elementFormDefault ;
55                 private XmlSchemaObjectTable elements ;
56                 private XmlSchemaDerivationMethod finalDefault ;
57                 private XmlSchemaObjectTable groups ;
58                 private string id ;
59                 private XmlSchemaObjectCollection includes ;
60                 private XmlSchemaObjectCollection items ;
61                 private XmlSchemaObjectTable notations ;
62                 private XmlSchemaObjectTable schemaTypes ;
63                 private string targetNamespace ;
64                 private XmlAttribute[] unhandledAttributes ;
65                 private string version;
66
67                 // other post schema compilation infoset
68                 private Hashtable idCollection;
69                 private XmlSchemaObjectTable namedIdentities;
70                 private XmlSchemaSet schemas;
71
72                 private XmlNameTable nameTable;
73
74                 internal bool missedSubComponents;
75
76                 // Only compilation-time use
77                 private XmlSchemaObjectCollection compilationItems;
78                 private Hashtable handledUris;
79
80                 // Compiler specific things
81                 const string xmlname = "schema";
82
83                 public XmlSchema ()
84                 {
85                         attributeFormDefault= XmlSchemaForm.None;
86                         blockDefault = XmlSchemaDerivationMethod.None;
87                         elementFormDefault = XmlSchemaForm.None;
88                         finalDefault = XmlSchemaDerivationMethod.None;
89                         includes = new XmlSchemaObjectCollection();
90                         isCompiled = false;
91                         items = new XmlSchemaObjectCollection();
92                         attributeGroups = new XmlSchemaObjectTable();
93                         attributes = new XmlSchemaObjectTable();
94                         elements = new XmlSchemaObjectTable();
95                         groups = new XmlSchemaObjectTable();
96                         notations = new XmlSchemaObjectTable();
97                         schemaTypes = new XmlSchemaObjectTable();
98                         idCollection = new Hashtable ();
99                         namedIdentities = new XmlSchemaObjectTable();
100                 }
101
102                 #region Properties
103
104                 [DefaultValue (XmlSchemaForm.None)]
105                 [System.Xml.Serialization.XmlAttribute ("attributeFormDefault")]
106                 public XmlSchemaForm AttributeFormDefault
107                 {
108                         get{ return attributeFormDefault; }
109                         set{ this.attributeFormDefault = value;}
110                 }
111
112                 [DefaultValue (XmlSchemaDerivationMethod.None)]
113                 [System.Xml.Serialization.XmlAttribute ("blockDefault")]
114                 public XmlSchemaDerivationMethod BlockDefault
115                 {
116                         get{ return blockDefault;}
117                         set{ blockDefault = value;}
118                 }
119
120                 [DefaultValue (XmlSchemaDerivationMethod.None)]
121                 [System.Xml.Serialization.XmlAttribute ("finalDefault")]
122                 public XmlSchemaDerivationMethod FinalDefault
123                 {
124                         get{ return finalDefault; }
125                         set{ finalDefault = value; }
126                 }
127
128                 [DefaultValue (XmlSchemaForm.None)]
129                 [System.Xml.Serialization.XmlAttribute ("elementFormDefault")]
130                 public XmlSchemaForm ElementFormDefault
131                 {
132                         get{ return elementFormDefault; }
133                         set{ elementFormDefault = value; }
134                 }
135
136                 [System.Xml.Serialization.XmlAttribute ("targetNamespace")]
137                 public string TargetNamespace
138                 {
139                         get{ return targetNamespace; }
140                         set{ targetNamespace = value; }
141                 }
142
143                 [System.Xml.Serialization.XmlAttribute ("version")]
144                 public string Version
145                 {
146                         get{ return version; }
147                         set{ version = value; }
148                 }
149
150                 [XmlElement ("include",typeof(XmlSchemaInclude), Namespace="http://www.w3.org/2001/XMLSchema")]
151                 [XmlElement ("import",typeof(XmlSchemaImport), Namespace="http://www.w3.org/2001/XMLSchema")]
152                 [XmlElement ("redefine",typeof(XmlSchemaRedefine), Namespace="http://www.w3.org/2001/XMLSchema")]
153                 public XmlSchemaObjectCollection Includes
154                 {
155                         get{ return includes;}
156                 }
157
158                 [XmlElement ("simpleType", typeof (XmlSchemaSimpleType), Namespace="http://www.w3.org/2001/XMLSchema")]
159                 [XmlElement ("complexType", typeof (XmlSchemaComplexType), Namespace="http://www.w3.org/2001/XMLSchema")]
160                 [XmlElement ("group", typeof (XmlSchemaGroup),Namespace="http://www.w3.org/2001/XMLSchema")]
161                         //Only Schema's attributeGroup has type XmlSchemaAttributeGroup.
162                         //Others (complextype, restrictions etc) must have XmlSchemaAttributeGroupRef
163                 [XmlElement ("attributeGroup", typeof (XmlSchemaAttributeGroup), Namespace="http://www.w3.org/2001/XMLSchema")]
164                 [XmlElement ("element", typeof (XmlSchemaElement), Namespace="http://www.w3.org/2001/XMLSchema")]
165                 [XmlElement ("attribute", typeof (XmlSchemaAttribute), Namespace="http://www.w3.org/2001/XMLSchema")]
166                 [XmlElement ("notation", typeof (XmlSchemaNotation), Namespace="http://www.w3.org/2001/XMLSchema")]
167                 [XmlElement ("annotation", typeof (XmlSchemaAnnotation), Namespace="http://www.w3.org/2001/XMLSchema")]
168                 public XmlSchemaObjectCollection Items
169                 {
170                         get{ return items; }
171                 }
172
173                 [XmlIgnore]
174                 public bool IsCompiled
175                 {
176                         get{ return this.CompilationId != Guid.Empty; }
177                 }
178
179                 [XmlIgnore]
180                 public XmlSchemaObjectTable Attributes
181                 {
182                         get{ return attributes; }
183                 }
184
185                 [XmlIgnore]
186                 public XmlSchemaObjectTable AttributeGroups
187                 {
188                         get{ return attributeGroups; }
189                 }
190
191                 [XmlIgnore]
192                 public XmlSchemaObjectTable SchemaTypes
193                 {
194                         get{ return schemaTypes; }
195                 }
196
197                 [XmlIgnore]
198                 public XmlSchemaObjectTable Elements
199                 {
200                         get{ return elements; }
201                 }
202
203                 [System.Xml.Serialization.XmlAttribute ("id")]
204                 public string Id
205                 {
206                         get{ return id; }
207                         set{ id = value; }
208                 }
209
210                 [XmlAnyAttribute]
211                 public XmlAttribute [] UnhandledAttributes
212                 {
213                         get {
214                                 if (unhandledAttributeList != null) {
215                                         unhandledAttributes = (XmlAttribute []) unhandledAttributeList.ToArray (typeof (XmlAttribute));
216                                         unhandledAttributeList = null;
217                                 }
218                                 return unhandledAttributes;
219                         }
220                         set {
221                                 unhandledAttributes = value;
222                                 unhandledAttributeList = null;
223                         }
224                 }
225
226                 [XmlIgnore]
227                 public XmlSchemaObjectTable Groups
228                 {
229                         get{ return groups; }
230                 }
231
232                 [XmlIgnore]
233                 public XmlSchemaObjectTable Notations
234                 {
235                         get{ return notations; }
236                 }
237
238                 internal Hashtable IDCollection
239                 {
240                         get { return idCollection; }
241                 }
242
243                 internal XmlSchemaObjectTable NamedIdentities
244                 {
245                         get { return namedIdentities; }
246                 }
247
248                 internal XmlSchemaSet Schemas
249                 {
250                         get { return schemas; }
251                 }
252                 #endregion
253
254                 #region Compile
255
256                 // Methods
257                 /// <summary>
258                 /// This compile method does two things:
259                 /// 1. It compiles and fills the PSVI dataset
260                 /// 2. Validates the schema by calling Validate method.
261                 /// Every XmlSchemaObject has a Compile Method which gets called.
262                 /// </summary>
263                 /// <remarks>
264                 ///             1. blockDefault must be one of #all | List of (extension | restriction | substitution)
265                 ///             2. finalDefault must be one of (#all | List of (extension | restriction| union| list))
266                 ///             3. id must be of type ID
267                 ///             4. targetNamespace should be any uri
268                 ///             5. version should be a normalizedString
269                 /// </remarks>
270                 public void Compile (ValidationEventHandler handler)
271                 {
272                         Compile (handler, new XmlUrlResolver ());
273                 }
274
275 #if NET_1_1
276                 public void Compile (ValidationEventHandler handler, XmlResolver resolver)
277 #else
278                 internal void Compile (ValidationEventHandler handler, XmlResolver resolver)
279 #endif
280                 {
281                         Compile (handler, new Stack (), this, null, resolver);
282                 }
283
284                 internal void Compile (ValidationEventHandler handler, XmlSchemaSet col, XmlResolver resolver)
285                 {
286                         Compile (handler, new Stack (), this, col, resolver);
287                 }
288
289                 private void Compile (ValidationEventHandler handler, Stack schemaLocationStack, XmlSchema rootSchema, XmlSchemaSet col, XmlResolver resolver)
290                 {
291                         if (rootSchema != this) {
292                                 CompilationId = rootSchema.CompilationId;
293                                 schemas = rootSchema.schemas;
294                         }
295                         else {
296                                 schemas = col;
297                                 if (schemas == null) {
298                                         schemas = new XmlSchemaSet ();
299                                         schemas.CompilationId = Guid.NewGuid ();
300                                 }
301                                 CompilationId = schemas.CompilationId;
302                                 this.idCollection.Clear ();
303                         }
304                         if (!schemas.Contains (this)) // e.g. xs:import
305                                 schemas.Add (this);
306
307                         attributeGroups.Clear ();
308                         attributes.Clear ();
309                         elements.Clear ();
310                         groups.Clear ();
311                         notations.Clear ();
312                         schemaTypes.Clear ();
313                         namedIdentities.Clear ();
314
315                         //1. Union and List are not allowed in block default
316                         if (BlockDefault != XmlSchemaDerivationMethod.All) {
317                                 if((BlockDefault & XmlSchemaDerivationMethod.List)!=0 )
318                                         error(handler, "list is not allowed in blockDefault attribute");
319                                 if((BlockDefault & XmlSchemaDerivationMethod.Union)!=0 )
320                                         error(handler, "union is not allowed in blockDefault attribute");
321                         }
322
323                         //2. Substitution is not allowed in finaldefault.
324                         if (FinalDefault != XmlSchemaDerivationMethod.All) {
325                                 if((FinalDefault & XmlSchemaDerivationMethod.Substitution)!=0 )
326                                         error(handler, "substitution is not allowed in finalDefault attribute");
327                         }
328
329                         //3. id must be of type ID
330                         XmlSchemaUtil.CompileID(Id, this, this.IDCollection, handler);
331
332                         //4. targetNamespace should be of type anyURI or absent
333                         if (TargetNamespace != null) {
334                                 if(!XmlSchemaUtil.CheckAnyUri (TargetNamespace))
335                                         error(handler, TargetNamespace+" is not a valid value for targetNamespace attribute of schema");
336                         }
337
338                         //5. version should be of type normalizedString
339                         if (!XmlSchemaUtil.CheckNormalizedString(Version))
340                                 error(handler, Version + "is not a valid value for version attribute of schema");
341
342                         // Compile the content of this schema
343
344                         compilationItems = new XmlSchemaObjectCollection ();
345                         for (int i = 0; i < Items.Count; i++) {
346 #if NET_2_0
347                                 Items [i].Parent = this;
348 #endif
349                                 compilationItems.Add (Items [i]);
350                         }
351                         if (this == rootSchema)
352                                 handledUris = new Hashtable ();
353
354                         // First, we run into inclusion schemas to collect 
355                         // compilation target items into compiledItems.
356                         for (int i = 0; i < Includes.Count; i++) {
357 #if NET_2_0
358                                 Includes [i].Parent = this;
359 #endif
360                                 XmlSchemaExternal ext = Includes [i] as XmlSchemaExternal;
361                                 if (ext == null) {
362                                         error (handler, String.Format ("Object of Type {0} is not valid in Includes Property of XmlSchema", Includes [i].GetType().Name));
363                                         continue;
364                                 }
365
366                                 if (ext.SchemaLocation == null) 
367                                         continue;
368
369                                 Stream stream = null;
370                                 string url = null;
371                                 if (resolver != null) {
372                                         url = GetResolvedUri (resolver, ext.SchemaLocation);
373                                         if (schemaLocationStack.Contains (url)) {
374                                                 // Just skip nested inclusion. 
375                                                 // The spec is "carefully written"
376                                                 // not to handle it as an error.
377 //                                              error (handler, "Nested inclusion was found: " + url);
378                                                 // must skip this inclusion
379                                                 continue;
380                                         }
381                                         if (rootSchema.handledUris.Contains (url))
382                                                 // This schema is already handled, so simply skip (otherwise, duplicate definition errrors occur.
383                                                 continue;
384                                         rootSchema.handledUris.Add (url, url);
385                                         try {
386                                                 stream = resolver.GetEntity (new Uri (url), null, typeof (Stream)) as Stream;
387                                         } catch (Exception) {
388                                         // LAMESPEC: This is not good way to handle errors, but since we cannot know what kind of XmlResolver will come, so there are no mean to avoid this ugly catch.
389                                                 warn (handler, "Could not resolve schema location URI: " + url);
390                                                 stream = null;
391                                         }
392                                 }
393
394                                 // Process redefinition children in advance.
395                                 XmlSchemaRedefine redefine = Includes [i] as XmlSchemaRedefine;
396                                 if (redefine != null) {
397                                         for (int j = 0; j < redefine.Items.Count; j++) {
398                                                 XmlSchemaObject redefinedObj = redefine.Items [j];
399                                                 redefinedObj.isRedefinedComponent = true;
400                                                 redefinedObj.isRedefineChild = true;
401                                                 if (redefinedObj is XmlSchemaType ||
402                                                         redefinedObj is XmlSchemaGroup ||
403                                                         redefinedObj is XmlSchemaAttributeGroup)
404                                                         compilationItems.Add (redefinedObj);
405                                                 else
406                                                         error (handler, "Redefinition is only allowed to simpleType, complexType, group and attributeGroup.");
407                                         }
408                                 }
409
410                                 XmlSchema includedSchema = null;
411                                 if (stream == null) {
412                                         // It is missing schema components.
413                                         missedSubComponents = true;
414                                         continue;
415                                 } else {
416                                         schemaLocationStack.Push (url);
417                                         XmlTextReader xtr = null;
418                                         try {
419                                                 xtr = new XmlTextReader (url, stream, nameTable);
420                                                 includedSchema = XmlSchema.Read (xtr, handler);
421                                         } finally {
422                                                 if (xtr != null)
423                                                         xtr.Close ();
424                                         }
425                                         includedSchema.schemas = schemas;
426                                 }
427
428                                 // Set - actual - target namespace for the included schema * before compilation*.
429                                 XmlSchemaImport import = ext as XmlSchemaImport;
430                                 if (import != null) {
431                                         if (TargetNamespace == includedSchema.TargetNamespace) {
432                                                 error (handler, "Target namespace must be different from that of included schema.");
433                                                 continue;
434                                         } else if (includedSchema.TargetNamespace != import.Namespace) {
435                                                 error (handler, "Attribute namespace and its importing schema's target namespace must be the same.");
436                                                 continue;
437                                         }
438                                 } else {
439                                         if (TargetNamespace == null && 
440                                                 includedSchema.TargetNamespace != null) {
441                                                 error (handler, "Target namespace is required to include a schema which has its own target namespace");
442                                                 continue;
443                                         }
444                                         else if (TargetNamespace != null && 
445                                                 includedSchema.TargetNamespace == null)
446                                                 includedSchema.TargetNamespace = TargetNamespace;
447                                 }
448
449                                 // Compile included schema.
450                                 includedSchema.idCollection = this.IDCollection;
451                                 includedSchema.Compile (handler, schemaLocationStack, rootSchema, col, resolver);
452                                 schemaLocationStack.Pop ();
453
454                                 if (import != null)
455                                         rootSchema.schemas.Add (includedSchema);
456
457                                 // Note that we use compiled items. Items
458                                 // may not exist in Items, since included
459                                 // schema also includes another schemas.
460                                 foreach (DictionaryEntry entry in includedSchema.Attributes)
461                                         compilationItems.Add ((XmlSchemaObject) entry.Value);
462                                 foreach (DictionaryEntry entry in includedSchema.Elements)
463                                         compilationItems.Add ((XmlSchemaObject) entry.Value);
464                                 foreach (DictionaryEntry entry in includedSchema.SchemaTypes)
465                                         compilationItems.Add ((XmlSchemaObject) entry.Value);
466                                 foreach (DictionaryEntry entry in includedSchema.AttributeGroups)
467                                         compilationItems.Add ((XmlSchemaObject) entry.Value);
468                                 foreach (DictionaryEntry entry in includedSchema.Groups)
469                                         compilationItems.Add ((XmlSchemaObject) entry.Value);
470                                 foreach (DictionaryEntry entry in includedSchema.Notations)
471                                         compilationItems.Add ((XmlSchemaObject) entry.Value);
472                         }
473
474                         // Compilation phase.
475                         // At least each Compile() must gives unique (qualified) name for each component.
476                         // It also checks self-resolvable properties correct.
477                         // Post compilation schema information contribution is not required here.
478                         // It should be done by Validate().
479                         for (int i = 0; i < compilationItems.Count; i++) {
480                                 XmlSchemaObject obj = compilationItems [i];
481                                 if(obj is XmlSchemaAnnotation) {
482                                         int numerr = ((XmlSchemaAnnotation)obj).Compile (handler, this);
483                                         errorCount += numerr;
484                                 } else if (obj is XmlSchemaAttribute) {
485                                         XmlSchemaAttribute attr = (XmlSchemaAttribute) obj;
486                                         attr.ParentIsSchema = true;
487                                         int numerr = attr.Compile (handler, this);
488                                         errorCount += numerr;
489                                         if(numerr == 0)
490                                         {
491                                                 XmlSchemaUtil.AddToTable (Attributes, attr, attr.QualifiedName, handler);
492                                         }
493                                 } else if (obj is XmlSchemaAttributeGroup) {
494                                         XmlSchemaAttributeGroup attrgrp = (XmlSchemaAttributeGroup) obj;
495                                         int numerr = attrgrp.Compile(handler, this);
496                                         errorCount += numerr;
497                                         if (numerr == 0)
498                                                 XmlSchemaUtil.AddToTable (
499                                                         AttributeGroups,
500                                                         attrgrp,
501                                                         attrgrp.QualifiedName,
502                                                         handler);
503                                 } else if (obj is XmlSchemaComplexType) {
504                                         XmlSchemaComplexType ctype = (XmlSchemaComplexType) obj;
505                                         ctype.ParentIsSchema = true;
506                                         int numerr = ctype.Compile (handler, this);
507                                         errorCount += numerr;
508                                         if (numerr == 0)
509                                                 XmlSchemaUtil.AddToTable (
510                                                         schemaTypes,
511                                                         ctype,
512                                                         ctype.QualifiedName,
513                                                         handler);
514                                 } else if (obj is XmlSchemaSimpleType) {
515                                         XmlSchemaSimpleType stype = (XmlSchemaSimpleType) obj;
516                                         stype.islocal = false; //This simple type is toplevel
517                                         int numerr = stype.Compile (handler, this);
518                                         errorCount += numerr;
519                                         if (numerr == 0)
520                                                 XmlSchemaUtil.AddToTable (
521                                                         SchemaTypes,
522                                                         stype,
523                                                         stype.QualifiedName,
524                                                         handler);
525                                 } else if (obj is XmlSchemaElement) {
526                                         XmlSchemaElement elem = (XmlSchemaElement) obj;
527                                         elem.parentIsSchema = true;
528                                         int numerr = elem.Compile (handler, this);
529                                         errorCount += numerr;
530                                         if (numerr == 0)
531                                                 XmlSchemaUtil.AddToTable (
532                                                         Elements,
533                                                         elem,
534                                                         elem.QualifiedName,
535                                                         handler);
536                                 } else if (obj is XmlSchemaGroup) {
537                                         XmlSchemaGroup grp = (XmlSchemaGroup) obj;
538                                         int numerr = grp.Compile (handler, this);
539                                         errorCount += numerr;
540                                         if (numerr == 0)
541                                                 XmlSchemaUtil.AddToTable (
542                                                         Groups,
543                                                         grp,
544                                                         grp.QualifiedName,
545                                                         handler);
546                                 } else if (obj is XmlSchemaNotation) {
547                                         XmlSchemaNotation ntn = (XmlSchemaNotation) obj;
548                                         int numerr = ntn.Compile (handler, this);
549                                         errorCount += numerr;
550                                         if (numerr == 0)
551                                                 XmlSchemaUtil.AddToTable (
552                                                         Notations,
553                                                         ntn,
554                                                         ntn.QualifiedName,
555                                                         handler);
556                                 } else {
557                                         ValidationHandler.RaiseValidationEvent (
558                                                 handler,
559                                                 null,
560                                                 String.Format ("Object of Type {0} is not valid in Item Property of Schema", obj.GetType ().Name),
561                                                 null,
562                                                 this,
563                                                 null,
564                                                 XmlSeverityType.Error);
565                                 }
566                         }
567
568                         if (rootSchema == this)
569                                 Validate(handler);
570
571                         if (errorCount == 0)
572                                 isCompiled = true;
573                         errorCount = 0;
574                 }
575
576                 private string GetResolvedUri (XmlResolver resolver, string relativeUri)
577                 {
578                         Uri baseUri = null;
579                         if (this.SourceUri != null && this.SourceUri != String.Empty)
580                                 baseUri = new Uri (this.SourceUri);
581                         return resolver.ResolveUri (baseUri, relativeUri).ToString ();
582                 }
583
584                 internal bool IsNamespaceAbsent (string ns)
585                 {
586                         return !schemas.Contains (ns);
587                 }
588
589                 #endregion
590
591                 private void Validate (ValidationEventHandler handler)
592                 {
593                         ValidationId = CompilationId;
594
595                         // Firstly Element needs to be filled their substitution group info
596                         foreach (XmlSchemaElement elem in Elements.Values)
597                                 elem.FillSubstitutionElementInfo ();
598
599                         // Validate
600                         foreach (XmlSchemaAttribute attr in Attributes.Values)
601                                 errorCount += attr.Validate (handler, this);
602                         foreach (XmlSchemaAttributeGroup attrgrp in AttributeGroups.Values)
603                                 errorCount += attrgrp.Validate (handler, this);
604                         foreach (XmlSchemaType type in SchemaTypes.Values)
605                                 errorCount += type.Validate (handler, this);
606                         foreach (XmlSchemaElement elem in Elements.Values)
607                                 errorCount += elem.Validate (handler, this);
608                         foreach (XmlSchemaGroup grp in Groups.Values)
609                                 errorCount += grp.Validate (handler, this);
610                         foreach (XmlSchemaNotation ntn in Notations.Values)
611                                 errorCount += ntn.Validate (handler, this);
612                 }
613
614                 #region Read
615
616                 // We cannot use xml deserialization, since it does not provide line info, qname context, and so on.
617                 public static XmlSchema Read (TextReader reader, ValidationEventHandler validationEventHandler)
618                 {
619                         return Read (new XmlTextReader (reader),validationEventHandler);
620                 }
621                 public static XmlSchema Read (Stream stream, ValidationEventHandler validationEventHandler)
622                 {
623                         return Read (new XmlTextReader (stream),validationEventHandler);
624                 }
625
626                 public static XmlSchema Read (XmlReader rdr, ValidationEventHandler validationEventHandler)
627                 {
628                         XmlSchemaReader reader = new XmlSchemaReader (rdr, validationEventHandler);
629
630                         if (reader.ReadState == ReadState.Initial)
631                                 reader.ReadNextElement ();
632
633                         int startDepth = reader.Depth;
634
635                         do
636                         {
637                                 switch(reader.NodeType)
638                                 {
639                                 case XmlNodeType.Element:
640                                         if(reader.LocalName == "schema")
641                                         {
642                                                 XmlSchema schema = new XmlSchema ();
643                                                 schema.nameTable = rdr.NameTable;
644
645                                                 schema.LineNumber = reader.LineNumber;
646                                                 schema.LinePosition = reader.LinePosition;
647                                                 schema.SourceUri = reader.BaseURI;
648
649                                                 ReadAttributes(schema, reader, validationEventHandler);
650                                                 //IsEmptyElement does not behave properly if reader is
651                                                 //positioned at an attribute.
652                                                 reader.MoveToElement();
653                                                 if(!reader.IsEmptyElement)
654                                                 {
655                                                         ReadContent(schema, reader, validationEventHandler);
656                                                 }
657                                                 else
658                                                         rdr.Skip ();
659
660                                                 if (rdr.NodeType == XmlNodeType.EndElement)
661                                                         rdr.Read ();
662                                                 return schema;
663                                         }
664                                         else
665                                                 //Schema can't be generated. Throw an exception
666                                                 error (validationEventHandler, "The root element must be schema", null);
667                                         break;
668                                 default:
669                                         error(validationEventHandler, "This should never happen. XmlSchema.Read 1 ",null);
670                                         break;
671                                 }
672                         } while(reader.Depth > startDepth && reader.ReadNextElement());
673
674                         // This is thrown regardless of ValidationEventHandler existence.
675                         throw new XmlSchemaException ("The top level schema must have namespace " + XmlSchema.Namespace, null);
676                 }
677
678                 private static void ReadAttributes(XmlSchema schema, XmlSchemaReader reader, ValidationEventHandler h)
679                 {
680                         Exception ex;
681
682                         reader.MoveToElement();
683                         while(reader.MoveToNextAttribute())
684                         {
685                                 switch(reader.Name)
686                                 {
687                                         case "attributeFormDefault" :
688                                                 schema.attributeFormDefault = XmlSchemaUtil.ReadFormAttribute(reader,out ex);
689                                                 if(ex != null)
690                                                         error(h, reader.Value + " is not a valid value for attributeFormDefault.", ex);
691                                                 break;
692                                         case "blockDefault" :
693                                                 schema.blockDefault = XmlSchemaUtil.ReadDerivationAttribute(reader,out ex, "blockDefault",
694                                                         XmlSchemaUtil.ElementBlockAllowed);
695                                                 if(ex != null)
696                                                         error (h, ex.Message, ex);
697                                                 break;
698                                         case "elementFormDefault":
699                                                 schema.elementFormDefault = XmlSchemaUtil.ReadFormAttribute(reader, out ex);
700                                                 if(ex != null)
701                                                         error(h, reader.Value + " is not a valid value for elementFormDefault.", ex);
702                                                 break;
703                                         case "finalDefault":
704                                                 schema.finalDefault = XmlSchemaUtil.ReadDerivationAttribute(reader, out ex, "finalDefault",
705                                                         XmlSchemaUtil.FinalAllowed);
706                                                 if(ex != null)
707                                                         error (h, ex.Message , ex);
708                                                 break;
709                                         case "id":
710                                                 schema.id = reader.Value;
711                                                 break;
712                                         case "targetNamespace":
713                                                 schema.targetNamespace = reader.Value;
714                                                 break;
715                                         case "version":
716                                                 schema.version = reader.Value;
717                                                 break;
718                                         default:
719                                                 if((reader.NamespaceURI == "" && reader.Name != "xmlns") || reader.NamespaceURI == XmlSchema.Namespace)
720                                                         error(h, reader.Name + " attribute is not allowed in schema element",null);
721                                                 else
722                                                 {
723                                                         XmlSchemaUtil.ReadUnhandledAttribute(reader,schema);
724                                                 }
725                                                 break;
726                                 }
727                         }
728                 }
729
730                 private static void ReadContent(XmlSchema schema, XmlSchemaReader reader, ValidationEventHandler h)
731                 {
732                         reader.MoveToElement();
733                         if(reader.LocalName != "schema" && reader.NamespaceURI != XmlSchema.Namespace && reader.NodeType != XmlNodeType.Element)
734                                 error(h, "UNREACHABLE CODE REACHED: Method: Schema.ReadContent, " + reader.LocalName + ", " + reader.NamespaceURI,null);
735
736                         //(include | import | redefine | annotation)*,
737                         //((simpleType | complexType | group | attributeGroup | element | attribute | notation | annotation)*
738                         int level = 1;
739                         while(reader.ReadNextElement())
740                         {
741                                 if(reader.NodeType == XmlNodeType.EndElement)
742                                 {
743                                         if(reader.LocalName != xmlname)
744                                                 error(h,"Should not happen :2: XmlSchema.Read, name="+reader.Name,null);
745                                         break;
746                                 }
747                                 if(level <= 1)
748                                 {
749                                         if(reader.LocalName == "include")
750                                         {
751                                                 XmlSchemaInclude include = XmlSchemaInclude.Read(reader,h);
752                                                 if(include != null)
753                                                         schema.includes.Add(include);
754                                                 continue;
755                                         }
756                                         if(reader.LocalName == "import")
757                                         {
758                                                 XmlSchemaImport import = XmlSchemaImport.Read(reader,h);
759                                                 if(import != null)
760                                                         schema.includes.Add(import);
761                                                 continue;
762                                         }
763                                         if(reader.LocalName == "redefine")
764                                         {
765                                                 XmlSchemaRedefine redefine = XmlSchemaRedefine.Read(reader,h);
766                                                 if(redefine != null)
767                                                         schema.includes.Add(redefine);
768                                                 continue;
769                                         }
770                                         if(reader.LocalName == "annotation")
771                                         {
772                                                 XmlSchemaAnnotation annotation = XmlSchemaAnnotation.Read(reader,h);
773                                                 if(annotation != null)
774                                                         schema.items.Add(annotation);
775                                                 continue;
776                                         }
777                                 }
778                                 if(level <=2)
779                                 {
780                                         level = 2;
781                                         if(reader.LocalName == "simpleType")
782                                         {
783                                                 XmlSchemaSimpleType stype = XmlSchemaSimpleType.Read(reader,h);
784                                                 if(stype != null)
785                                                         schema.items.Add(stype);
786                                                 continue;
787                                         }
788                                         if(reader.LocalName == "complexType")
789                                         {
790                                                 XmlSchemaComplexType ctype = XmlSchemaComplexType.Read(reader,h);
791                                                 if(ctype != null)
792                                                         schema.items.Add(ctype);
793                                                 continue;
794                                         }
795                                         if(reader.LocalName == "group")
796                                         {
797                                                 XmlSchemaGroup group = XmlSchemaGroup.Read(reader,h);
798                                                 if(group != null)
799                                                         schema.items.Add(group);
800                                                 continue;
801                                         }
802                                         if(reader.LocalName == "attributeGroup")
803                                         {
804                                                 XmlSchemaAttributeGroup attributeGroup = XmlSchemaAttributeGroup.Read(reader,h);
805                                                 if(attributeGroup != null)
806                                                         schema.items.Add(attributeGroup);
807                                                 continue;
808                                         }
809                                         if(reader.LocalName == "element")
810                                         {
811                                                 XmlSchemaElement element = XmlSchemaElement.Read(reader,h);
812                                                 if(element != null)
813                                                         schema.items.Add(element);
814                                                 continue;
815                                         }
816                                         if(reader.LocalName == "attribute")
817                                         {
818                                                 XmlSchemaAttribute attr = XmlSchemaAttribute.Read(reader,h);
819                                                 if(attr != null)
820                                                         schema.items.Add(attr);
821                                                 continue;
822                                         }
823                                         if(reader.LocalName == "notation")
824                                         {
825                                                 XmlSchemaNotation notation = XmlSchemaNotation.Read(reader,h);
826                                                 if(notation != null)
827                                                         schema.items.Add(notation);
828                                                 continue;
829                                         }
830                                         if(reader.LocalName == "annotation")
831                                         {
832                                                 XmlSchemaAnnotation annotation = XmlSchemaAnnotation.Read(reader,h);
833                                                 if(annotation != null)
834                                                         schema.items.Add(annotation);
835                                                 continue;
836                                         }
837                                 }
838                                 reader.RaiseInvalidElementError();
839                         }
840                 }
841                 #endregion
842
843                 #region write
844
845                 public void Write(System.IO.Stream stream)
846                 {
847                         Write(stream,null);
848                 }
849                 public void Write(System.IO.TextWriter writer)
850                 {
851                         Write(writer,null);
852                 }
853                 public void Write(System.Xml.XmlWriter writer)
854                 {
855                         Write(writer,null);
856                 }
857                 public void Write(System.IO.Stream stream, System.Xml.XmlNamespaceManager namespaceManager)
858                 {
859                         Write(new XmlTextWriter(stream,null),namespaceManager);
860                 }
861                 public void Write(System.IO.TextWriter writer, System.Xml.XmlNamespaceManager namespaceManager)
862                 {
863                         XmlTextWriter xwriter = new XmlTextWriter(writer);
864                         xwriter.Formatting = Formatting.Indented;
865                         Write(xwriter,namespaceManager);
866                 }
867
868                 public void Write (System.Xml.XmlWriter writer, System.Xml.XmlNamespaceManager namespaceManager)
869                 {
870                         XmlSerializerNamespaces nss = new XmlSerializerNamespaces ();
871
872                         if (namespaceManager != null) {
873                                 if (nss == null)
874                                         nss = new XmlSerializerNamespaces ();
875                                 foreach (string name in namespaceManager) {
876                                         //xml and xmlns namespaces are added by default in namespaceManager.
877                                         //So we should ignore them
878                                         if (name !="xml" && name != "xmlns")
879                                                 nss.Add (name, namespaceManager.LookupNamespace (name));
880                                 }
881                         }
882
883                         if (Namespaces != null && Namespaces.Count > 0) {
884                                 nss.Add (String.Empty, XmlSchema.Namespace);
885                                 foreach (XmlQualifiedName qn in Namespaces.ToArray ()) {
886                                         nss.Add (qn.Name, qn.Namespace);
887                                 }
888                         }
889
890                         if (nss.Count == 0) {
891                                 // Add the xml schema namespace. (It is done 
892                                 // only when no entry exists in Namespaces).
893                                 nss.Add ("xs", XmlSchema.Namespace);
894                                 if (TargetNamespace != null)
895                                         nss.Add ("tns", TargetNamespace);
896                         }
897
898                         XmlSchemaSerializer xser = new XmlSchemaSerializer ();
899                         xser.Serialize (writer, this, nss);
900                         writer.Flush();
901                 }
902                 #endregion
903         }
904
905         class XmlSchemaSerializer : XmlSerializer
906         {
907                 protected override void Serialize (object o, XmlSerializationWriter writer)
908                 {
909                         XmlSchemaSerializationWriter w = writer as XmlSchemaSerializationWriter;
910                         w.WriteRoot_XmlSchema ((XmlSchema) o);
911                 }
912
913                 protected override XmlSerializationWriter CreateWriter ()
914                 {
915                         return new XmlSchemaSerializationWriter ();
916                 }
917         }
918 }