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