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