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