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