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