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