2004-11-25 Atsushi Enomoto <atsushi@ximian.com>
[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                                 compilationItems.Add (Items [i]);
347                         if (this == rootSchema)
348                                 handledUris = new Hashtable ();
349
350                         // First, we run into inclusion schemas to collect 
351                         // compilation target items into compiledItems.
352                         for (int i = 0; i < Includes.Count; i++) {
353                                 XmlSchemaExternal ext = Includes [i] as XmlSchemaExternal;
354                                 if (ext == null) {
355                                         error (handler, String.Format ("Object of Type {0} is not valid in Includes Property of XmlSchema", Includes [i].GetType().Name));
356                                         continue;
357                                 }
358
359                                 if (ext.SchemaLocation == null) 
360                                         continue;
361
362                                 Stream stream = null;
363                                 string url = null;
364                                 if (resolver != null) {
365                                         url = GetResolvedUri (resolver, ext.SchemaLocation);
366                                         if (schemaLocationStack.Contains (url)) {
367                                                 // Just skip nested inclusion. 
368                                                 // The spec is "carefully written"
369                                                 // not to handle it as an error.
370 //                                              error (handler, "Nested inclusion was found: " + url);
371                                                 // must skip this inclusion
372                                                 continue;
373                                         }
374                                         if (rootSchema.handledUris.Contains (url))
375                                                 // This schema is already handled, so simply skip (otherwise, duplicate definition errrors occur.
376                                                 continue;
377                                         rootSchema.handledUris.Add (url, url);
378                                         try {
379                                                 stream = resolver.GetEntity (new Uri (url), null, typeof (Stream)) as Stream;
380                                         } catch (Exception) {
381                                         // 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.
382                                                 warn (handler, "Could not resolve schema location URI: " + url);
383                                                 stream = null;
384                                         }
385                                 }
386
387                                 // Process redefinition children in advance.
388                                 XmlSchemaRedefine redefine = Includes [i] as XmlSchemaRedefine;
389                                 if (redefine != null) {
390                                         for (int j = 0; j < redefine.Items.Count; j++) {
391                                                 XmlSchemaObject redefinedObj = redefine.Items [j];
392                                                 redefinedObj.isRedefinedComponent = true;
393                                                 redefinedObj.isRedefineChild = true;
394                                                 if (redefinedObj is XmlSchemaType ||
395                                                         redefinedObj is XmlSchemaGroup ||
396                                                         redefinedObj is XmlSchemaAttributeGroup)
397                                                         compilationItems.Add (redefinedObj);
398                                                 else
399                                                         error (handler, "Redefinition is only allowed to simpleType, complexType, group and attributeGroup.");
400                                         }
401                                 }
402
403                                 XmlSchema includedSchema = null;
404                                 if (stream == null) {
405                                         // It is missing schema components.
406                                         missedSubComponents = true;
407                                         continue;
408                                 } else {
409                                         schemaLocationStack.Push (url);
410                                         XmlTextReader xtr = null;
411                                         try {
412                                                 xtr = new XmlTextReader (url, stream, nameTable);
413                                                 includedSchema = XmlSchema.Read (xtr, handler);
414                                         } finally {
415                                                 if (xtr != null)
416                                                         xtr.Close ();
417                                         }
418                                         includedSchema.schemas = schemas;
419                                 }
420
421                                 // Set - actual - target namespace for the included schema * before compilation*.
422                                 XmlSchemaImport import = ext as XmlSchemaImport;
423                                 if (import != null) {
424                                         if (TargetNamespace == includedSchema.TargetNamespace) {
425                                                 error (handler, "Target namespace must be different from that of included schema.");
426                                                 continue;
427                                         } else if (includedSchema.TargetNamespace != import.Namespace) {
428                                                 error (handler, "Attribute namespace and its importing schema's target namespace must be the same.");
429                                                 continue;
430                                         }
431                                 } else {
432                                         if (TargetNamespace == null && 
433                                                 includedSchema.TargetNamespace != null) {
434                                                 error (handler, "Target namespace is required to include a schema which has its own target namespace");
435                                                 continue;
436                                         }
437                                         else if (TargetNamespace != null && 
438                                                 includedSchema.TargetNamespace == null)
439                                                 includedSchema.TargetNamespace = TargetNamespace;
440                                 }
441
442                                 // Compile included schema.
443                                 includedSchema.idCollection = this.IDCollection;
444                                 includedSchema.Compile (handler, schemaLocationStack, rootSchema, col, resolver);
445                                 schemaLocationStack.Pop ();
446
447                                 if (import != null)
448                                         rootSchema.schemas.Add (includedSchema);
449
450                                 // Note that we use compiled items. Items
451                                 // may not exist in Items, since included
452                                 // schema also includes another schemas.
453                                 foreach (DictionaryEntry entry in includedSchema.Attributes)
454                                         compilationItems.Add ((XmlSchemaObject) entry.Value);
455                                 foreach (DictionaryEntry entry in includedSchema.Elements)
456                                         compilationItems.Add ((XmlSchemaObject) entry.Value);
457                                 foreach (DictionaryEntry entry in includedSchema.SchemaTypes)
458                                         compilationItems.Add ((XmlSchemaObject) entry.Value);
459                                 foreach (DictionaryEntry entry in includedSchema.AttributeGroups)
460                                         compilationItems.Add ((XmlSchemaObject) entry.Value);
461                                 foreach (DictionaryEntry entry in includedSchema.Groups)
462                                         compilationItems.Add ((XmlSchemaObject) entry.Value);
463                                 foreach (DictionaryEntry entry in includedSchema.Notations)
464                                         compilationItems.Add ((XmlSchemaObject) entry.Value);
465                         }
466
467                         // Compilation phase.
468                         // At least each Compile() must gives unique (qualified) name for each component.
469                         // It also checks self-resolvable properties correct.
470                         // Post compilation schema information contribution is not required here.
471                         // It should be done by Validate().
472                         for (int i = 0; i < compilationItems.Count; i++) {
473                                 XmlSchemaObject obj = compilationItems [i];
474                                 if(obj is XmlSchemaAnnotation) {
475                                         int numerr = ((XmlSchemaAnnotation)obj).Compile (handler, this);
476                                         errorCount += numerr;
477                                 } else if (obj is XmlSchemaAttribute) {
478                                         XmlSchemaAttribute attr = (XmlSchemaAttribute) obj;
479                                         attr.ParentIsSchema = true;
480                                         int numerr = attr.Compile (handler, this);
481                                         errorCount += numerr;
482                                         if(numerr == 0)
483                                         {
484                                                 XmlSchemaUtil.AddToTable (Attributes, attr, attr.QualifiedName, handler);
485                                         }
486                                 } else if (obj is XmlSchemaAttributeGroup) {
487                                         XmlSchemaAttributeGroup attrgrp = (XmlSchemaAttributeGroup) obj;
488                                         int numerr = attrgrp.Compile(handler, this);
489                                         errorCount += numerr;
490                                         if (numerr == 0)
491                                                 XmlSchemaUtil.AddToTable (
492                                                         AttributeGroups,
493                                                         attrgrp,
494                                                         attrgrp.QualifiedName,
495                                                         handler);
496                                 } else if (obj is XmlSchemaComplexType) {
497                                         XmlSchemaComplexType ctype = (XmlSchemaComplexType) obj;
498                                         ctype.ParentIsSchema = true;
499                                         int numerr = ctype.Compile (handler, this);
500                                         errorCount += numerr;
501                                         if (numerr == 0)
502                                                 XmlSchemaUtil.AddToTable (
503                                                         schemaTypes,
504                                                         ctype,
505                                                         ctype.QualifiedName,
506                                                         handler);
507                                 } else if (obj is XmlSchemaSimpleType) {
508                                         XmlSchemaSimpleType stype = (XmlSchemaSimpleType) obj;
509                                         stype.islocal = false; //This simple type is toplevel
510                                         int numerr = stype.Compile (handler, this);
511                                         errorCount += numerr;
512                                         if (numerr == 0)
513                                                 XmlSchemaUtil.AddToTable (
514                                                         SchemaTypes,
515                                                         stype,
516                                                         stype.QualifiedName,
517                                                         handler);
518                                 } else if (obj is XmlSchemaElement) {
519                                         XmlSchemaElement elem = (XmlSchemaElement) obj;
520                                         elem.parentIsSchema = true;
521                                         int numerr = elem.Compile (handler, this);
522                                         errorCount += numerr;
523                                         if (numerr == 0)
524                                                 XmlSchemaUtil.AddToTable (
525                                                         Elements,
526                                                         elem,
527                                                         elem.QualifiedName,
528                                                         handler);
529                                 } else if (obj is XmlSchemaGroup) {
530                                         XmlSchemaGroup grp = (XmlSchemaGroup) obj;
531                                         int numerr = grp.Compile (handler, this);
532                                         errorCount += numerr;
533                                         if (numerr == 0)
534                                                 XmlSchemaUtil.AddToTable (
535                                                         Groups,
536                                                         grp,
537                                                         grp.QualifiedName,
538                                                         handler);
539                                 } else if (obj is XmlSchemaNotation) {
540                                         XmlSchemaNotation ntn = (XmlSchemaNotation) obj;
541                                         int numerr = ntn.Compile (handler, this);
542                                         errorCount += numerr;
543                                         if (numerr == 0)
544                                                 XmlSchemaUtil.AddToTable (
545                                                         Notations,
546                                                         ntn,
547                                                         ntn.QualifiedName,
548                                                         handler);
549                                 } else {
550                                         ValidationHandler.RaiseValidationEvent (
551                                                 handler,
552                                                 null,
553                                                 String.Format ("Object of Type {0} is not valid in Item Property of Schema", obj.GetType ().Name),
554                                                 null,
555                                                 this,
556                                                 null,
557                                                 XmlSeverityType.Error);
558                                 }
559                         }
560
561                         if (rootSchema == this)
562                                 Validate(handler);
563
564                         if (errorCount == 0)
565                                 isCompiled = true;
566                         errorCount = 0;
567                 }
568
569                 private string GetResolvedUri (XmlResolver resolver, string relativeUri)
570                 {
571                         Uri baseUri = null;
572                         if (this.SourceUri != null && this.SourceUri != String.Empty)
573                                 baseUri = new Uri (this.SourceUri);
574                         return resolver.ResolveUri (baseUri, relativeUri).ToString ();
575                 }
576
577                 internal bool IsNamespaceAbsent (string ns)
578                 {
579                         return !schemas.Contains (ns);
580                 }
581
582                 #endregion
583
584                 private void Validate (ValidationEventHandler handler)
585                 {
586                         ValidationId = CompilationId;
587
588                         // Firstly Element needs to be filled their substitution group info
589                         foreach (XmlSchemaElement elem in Elements.Values)
590                                 elem.FillSubstitutionElementInfo ();
591
592                         // Validate
593                         foreach (XmlSchemaAttribute attr in Attributes.Values)
594                                 errorCount += attr.Validate (handler, this);
595                         foreach (XmlSchemaAttributeGroup attrgrp in AttributeGroups.Values)
596                                 errorCount += attrgrp.Validate (handler, this);
597                         foreach (XmlSchemaType type in SchemaTypes.Values)
598                                 errorCount += type.Validate (handler, this);
599                         foreach (XmlSchemaElement elem in Elements.Values)
600                                 errorCount += elem.Validate (handler, this);
601                         foreach (XmlSchemaGroup grp in Groups.Values)
602                                 errorCount += grp.Validate (handler, this);
603                         foreach (XmlSchemaNotation ntn in Notations.Values)
604                                 errorCount += ntn.Validate (handler, this);
605                 }
606
607                 #region Read
608
609                 // We cannot use xml deserialization, since it does not provide line info, qname context, and so on.
610                 public static XmlSchema Read (TextReader reader, ValidationEventHandler validationEventHandler)
611                 {
612                         return Read (new XmlTextReader (reader),validationEventHandler);
613                 }
614                 public static XmlSchema Read (Stream stream, ValidationEventHandler validationEventHandler)
615                 {
616                         return Read (new XmlTextReader (stream),validationEventHandler);
617                 }
618
619                 public static XmlSchema Read (XmlReader rdr, ValidationEventHandler validationEventHandler)
620                 {
621                         XmlSchemaReader reader = new XmlSchemaReader (rdr, validationEventHandler);
622
623                         if (reader.ReadState == ReadState.Initial)
624                                 reader.ReadNextElement ();
625
626                         int startDepth = reader.Depth;
627
628                         do
629                         {
630                                 switch(reader.NodeType)
631                                 {
632                                 case XmlNodeType.Element:
633                                         if(reader.LocalName == "schema")
634                                         {
635                                                 XmlSchema schema = new XmlSchema ();
636                                                 schema.nameTable = rdr.NameTable;
637
638                                                 schema.LineNumber = reader.LineNumber;
639                                                 schema.LinePosition = reader.LinePosition;
640                                                 schema.SourceUri = reader.BaseURI;
641
642                                                 ReadAttributes(schema, reader, validationEventHandler);
643                                                 //IsEmptyElement does not behave properly if reader is
644                                                 //positioned at an attribute.
645                                                 reader.MoveToElement();
646                                                 if(!reader.IsEmptyElement)
647                                                 {
648                                                         ReadContent(schema, reader, validationEventHandler);
649                                                 }
650                                                 else
651                                                         rdr.Skip ();
652
653                                                 if (rdr.NodeType == XmlNodeType.EndElement)
654                                                         rdr.Read ();
655                                                 return schema;
656                                         }
657                                         else
658                                                 //Schema can't be generated. Throw an exception
659                                                 error (validationEventHandler, "The root element must be schema", null);
660                                         break;
661                                 default:
662                                         error(validationEventHandler, "This should never happen. XmlSchema.Read 1 ",null);
663                                         break;
664                                 }
665                         } while(reader.Depth > startDepth && reader.ReadNextElement());
666
667                         // This is thrown regardless of ValidationEventHandler existence.
668                         throw new XmlSchemaException ("The top level schema must have namespace " + XmlSchema.Namespace, null);
669                 }
670
671                 private static void ReadAttributes(XmlSchema schema, XmlSchemaReader reader, ValidationEventHandler h)
672                 {
673                         Exception ex;
674
675                         reader.MoveToElement();
676                         while(reader.MoveToNextAttribute())
677                         {
678                                 switch(reader.Name)
679                                 {
680                                         case "attributeFormDefault" :
681                                                 schema.attributeFormDefault = XmlSchemaUtil.ReadFormAttribute(reader,out ex);
682                                                 if(ex != null)
683                                                         error(h, reader.Value + " is not a valid value for attributeFormDefault.", ex);
684                                                 break;
685                                         case "blockDefault" :
686                                                 schema.blockDefault = XmlSchemaUtil.ReadDerivationAttribute(reader,out ex, "blockDefault",
687                                                         XmlSchemaUtil.ElementBlockAllowed);
688                                                 if(ex != null)
689                                                         error (h, ex.Message, ex);
690                                                 break;
691                                         case "elementFormDefault":
692                                                 schema.elementFormDefault = XmlSchemaUtil.ReadFormAttribute(reader, out ex);
693                                                 if(ex != null)
694                                                         error(h, reader.Value + " is not a valid value for elementFormDefault.", ex);
695                                                 break;
696                                         case "finalDefault":
697                                                 schema.finalDefault = XmlSchemaUtil.ReadDerivationAttribute(reader, out ex, "finalDefault",
698                                                         XmlSchemaUtil.FinalAllowed);
699                                                 if(ex != null)
700                                                         error (h, ex.Message , ex);
701                                                 break;
702                                         case "id":
703                                                 schema.id = reader.Value;
704                                                 break;
705                                         case "targetNamespace":
706                                                 schema.targetNamespace = reader.Value;
707                                                 break;
708                                         case "version":
709                                                 schema.version = reader.Value;
710                                                 break;
711                                         default:
712                                                 if((reader.NamespaceURI == "" && reader.Name != "xmlns") || reader.NamespaceURI == XmlSchema.Namespace)
713                                                         error(h, reader.Name + " attribute is not allowed in schema element",null);
714                                                 else
715                                                 {
716                                                         XmlSchemaUtil.ReadUnhandledAttribute(reader,schema);
717                                                 }
718                                                 break;
719                                 }
720                         }
721                 }
722
723                 private static void ReadContent(XmlSchema schema, XmlSchemaReader reader, ValidationEventHandler h)
724                 {
725                         reader.MoveToElement();
726                         if(reader.LocalName != "schema" && reader.NamespaceURI != XmlSchema.Namespace && reader.NodeType != XmlNodeType.Element)
727                                 error(h, "UNREACHABLE CODE REACHED: Method: Schema.ReadContent, " + reader.LocalName + ", " + reader.NamespaceURI,null);
728
729                         //(include | import | redefine | annotation)*,
730                         //((simpleType | complexType | group | attributeGroup | element | attribute | notation | annotation)*
731                         int level = 1;
732                         while(reader.ReadNextElement())
733                         {
734                                 if(reader.NodeType == XmlNodeType.EndElement)
735                                 {
736                                         if(reader.LocalName != xmlname)
737                                                 error(h,"Should not happen :2: XmlSchema.Read, name="+reader.Name,null);
738                                         break;
739                                 }
740                                 if(level <= 1)
741                                 {
742                                         if(reader.LocalName == "include")
743                                         {
744                                                 XmlSchemaInclude include = XmlSchemaInclude.Read(reader,h);
745                                                 if(include != null)
746                                                         schema.includes.Add(include);
747                                                 continue;
748                                         }
749                                         if(reader.LocalName == "import")
750                                         {
751                                                 XmlSchemaImport import = XmlSchemaImport.Read(reader,h);
752                                                 if(import != null)
753                                                         schema.includes.Add(import);
754                                                 continue;
755                                         }
756                                         if(reader.LocalName == "redefine")
757                                         {
758                                                 XmlSchemaRedefine redefine = XmlSchemaRedefine.Read(reader,h);
759                                                 if(redefine != null)
760                                                         schema.includes.Add(redefine);
761                                                 continue;
762                                         }
763                                         if(reader.LocalName == "annotation")
764                                         {
765                                                 XmlSchemaAnnotation annotation = XmlSchemaAnnotation.Read(reader,h);
766                                                 if(annotation != null)
767                                                         schema.items.Add(annotation);
768                                                 continue;
769                                         }
770                                 }
771                                 if(level <=2)
772                                 {
773                                         level = 2;
774                                         if(reader.LocalName == "simpleType")
775                                         {
776                                                 XmlSchemaSimpleType stype = XmlSchemaSimpleType.Read(reader,h);
777                                                 if(stype != null)
778                                                         schema.items.Add(stype);
779                                                 continue;
780                                         }
781                                         if(reader.LocalName == "complexType")
782                                         {
783                                                 XmlSchemaComplexType ctype = XmlSchemaComplexType.Read(reader,h);
784                                                 if(ctype != null)
785                                                         schema.items.Add(ctype);
786                                                 continue;
787                                         }
788                                         if(reader.LocalName == "group")
789                                         {
790                                                 XmlSchemaGroup group = XmlSchemaGroup.Read(reader,h);
791                                                 if(group != null)
792                                                         schema.items.Add(group);
793                                                 continue;
794                                         }
795                                         if(reader.LocalName == "attributeGroup")
796                                         {
797                                                 XmlSchemaAttributeGroup attributeGroup = XmlSchemaAttributeGroup.Read(reader,h);
798                                                 if(attributeGroup != null)
799                                                         schema.items.Add(attributeGroup);
800                                                 continue;
801                                         }
802                                         if(reader.LocalName == "element")
803                                         {
804                                                 XmlSchemaElement element = XmlSchemaElement.Read(reader,h);
805                                                 if(element != null)
806                                                         schema.items.Add(element);
807                                                 continue;
808                                         }
809                                         if(reader.LocalName == "attribute")
810                                         {
811                                                 XmlSchemaAttribute attr = XmlSchemaAttribute.Read(reader,h);
812                                                 if(attr != null)
813                                                         schema.items.Add(attr);
814                                                 continue;
815                                         }
816                                         if(reader.LocalName == "notation")
817                                         {
818                                                 XmlSchemaNotation notation = XmlSchemaNotation.Read(reader,h);
819                                                 if(notation != null)
820                                                         schema.items.Add(notation);
821                                                 continue;
822                                         }
823                                         if(reader.LocalName == "annotation")
824                                         {
825                                                 XmlSchemaAnnotation annotation = XmlSchemaAnnotation.Read(reader,h);
826                                                 if(annotation != null)
827                                                         schema.items.Add(annotation);
828                                                 continue;
829                                         }
830                                 }
831                                 reader.RaiseInvalidElementError();
832                         }
833                 }
834                 #endregion
835
836                 #region write
837
838                 public void Write(System.IO.Stream stream)
839                 {
840                         Write(stream,null);
841                 }
842                 public void Write(System.IO.TextWriter writer)
843                 {
844                         Write(writer,null);
845                 }
846                 public void Write(System.Xml.XmlWriter writer)
847                 {
848                         Write(writer,null);
849                 }
850                 public void Write(System.IO.Stream stream, System.Xml.XmlNamespaceManager namespaceManager)
851                 {
852                         Write(new XmlTextWriter(stream,null),namespaceManager);
853                 }
854                 public void Write(System.IO.TextWriter writer, System.Xml.XmlNamespaceManager namespaceManager)
855                 {
856                         XmlTextWriter xwriter = new XmlTextWriter(writer);
857                         xwriter.Formatting = Formatting.Indented;
858                         Write(xwriter,namespaceManager);
859                 }
860
861                 public void Write (System.Xml.XmlWriter writer, System.Xml.XmlNamespaceManager namespaceManager)
862                 {
863                         XmlSerializerNamespaces nss = new XmlSerializerNamespaces ();
864
865                         if (namespaceManager != null) {
866                                 if (nss == null)
867                                         nss = new XmlSerializerNamespaces ();
868                                 foreach (string name in namespaceManager) {
869                                         //xml and xmlns namespaces are added by default in namespaceManager.
870                                         //So we should ignore them
871                                         if (name !="xml" && name != "xmlns")
872                                                 nss.Add (name, namespaceManager.LookupNamespace (name));
873                                 }
874                         }
875
876                         if (Namespaces != null && Namespaces.Count > 0) {
877                                 nss.Add (String.Empty, XmlSchema.Namespace);
878                                 foreach (XmlQualifiedName qn in Namespaces.ToArray ()) {
879                                         nss.Add (qn.Name, qn.Namespace);
880                                 }
881                         }
882
883                         if (nss.Count == 0) {
884                                 // Add the xml schema namespace. (It is done 
885                                 // only when no entry exists in Namespaces).
886                                 nss.Add ("xs", XmlSchema.Namespace);
887                                 if (TargetNamespace != null)
888                                         nss.Add ("tns", TargetNamespace);
889                         }
890
891                         XmlSchemaSerializer xser = new XmlSchemaSerializer ();
892                         xser.Serialize (writer, this, nss);
893                         writer.Flush();
894                 }
895                 #endregion
896         }
897
898         class XmlSchemaSerializer : XmlSerializer
899         {
900                 protected override void Serialize (object o, XmlSerializationWriter writer)
901                 {
902                         XmlSchemaSerializationWriter w = writer as XmlSchemaSerializationWriter;
903                         w.WriteRoot_XmlSchema ((XmlSchema) o);
904                 }
905
906                 protected override XmlSerializationWriter CreateWriter ()
907                 {
908                         return new XmlSchemaSerializationWriter ();
909                 }
910         }
911 }