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