revert mono-specific XmlSchemas changes that is not necessary anymore.
[mono.git] / mcs / class / referencesource / System.Xml / System / Xml / Serialization / XmlSchemas.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="XmlSchemas.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 // <owner current="true" primary="true">[....]</owner>                                                                
6 //------------------------------------------------------------------------------
7
8 namespace System.Xml.Serialization {
9
10     using System.Collections;
11     using System.Collections.Generic;
12     using System.IO;
13     using System;
14     using System.Globalization;
15     using System.ComponentModel;
16     using System.Xml.Serialization;
17     using System.Xml.Schema;
18     using System.Diagnostics;
19     using System.Threading;
20     using System.Security.Permissions;
21     using System.Security.Policy;
22     using System.Security;
23     using System.Net;
24
25     /// <include file='doc\XmlSchemas.uex' path='docs/doc[@for="XmlSchemas"]/*' />
26     /// <internalonly/>
27     /// <devdoc>
28     ///    <para>[To be supplied.]</para>
29     /// </devdoc>
30     public class XmlSchemas : CollectionBase, IEnumerable<XmlSchema> {
31         XmlSchemaSet schemaSet;
32         Hashtable references;
33         SchemaObjectCache cache; // cached schema top-level items
34         bool shareTypes;
35         Hashtable mergedSchemas;
36         internal Hashtable delayedSchemas = new Hashtable();
37         bool isCompiled = false;
38         static volatile XmlSchema xsd;
39         static volatile XmlSchema xml;
40
41         /// <include file='doc\XmlSchemas.uex' path='docs/doc[@for="XmlSchemas.this"]/*' />
42         /// <devdoc>
43         ///    <para>[To be supplied.]</para>
44         /// </devdoc>
45         public XmlSchema this[int index] {
46             get { return (XmlSchema)List[index]; }
47             set { List[index] = value; }
48         }
49
50         /// <include file='doc\XmlSchemas.uex' path='docs/doc[@for="XmlSchemas.this1"]/*' />
51         /// <devdoc>
52         ///    <para>[To be supplied.]</para>
53         /// </devdoc>
54         public XmlSchema this[string ns] {
55             get {
56                 IList values = (IList)SchemaSet.Schemas(ns);
57                 if (values.Count == 0)
58                     return null;
59                 if (values.Count == 1)
60                     return (XmlSchema)values[0];
61
62                 throw new InvalidOperationException(Res.GetString(Res.XmlSchemaDuplicateNamespace, ns));
63             }
64         }
65
66         /// <include file='doc\XmlSchemas.uex' path='docs/doc[@for="XmlSchemas.GetSchemas"]/*' />
67         /// <devdoc>
68         ///    <para>[To be supplied.]</para>
69         /// </devdoc>
70         public IList GetSchemas(string ns) {
71             return (IList)SchemaSet.Schemas(ns);
72         }
73
74         internal SchemaObjectCache Cache {
75             get {
76                 if (cache == null)
77                     cache = new SchemaObjectCache();
78                 return cache; 
79             }
80         }
81
82         internal Hashtable MergedSchemas {
83             get {
84                 if (mergedSchemas == null)
85                     mergedSchemas = new Hashtable();
86                 return mergedSchemas;
87             }
88         }
89
90         internal Hashtable References {
91             get { 
92                 if (references == null)
93                     references = new Hashtable();
94                 return references;
95             }
96         }
97
98         internal XmlSchemaSet SchemaSet {
99             get { 
100                 if (schemaSet == null) {
101                     schemaSet = new XmlSchemaSet();
102                     schemaSet.XmlResolver = null;
103                     schemaSet.ValidationEventHandler += new ValidationEventHandler(IgnoreCompileErrors);
104                 }
105                 return schemaSet;
106             }
107         }
108         internal int Add(XmlSchema schema, bool delay) {
109             if (delay) {
110                 if (delayedSchemas[schema] == null)
111                     delayedSchemas.Add(schema, schema);
112                 return -1;
113             }
114             else {
115                 return Add(schema);
116             }
117         }
118
119         /// <include file='doc\XmlSchemas.uex' path='docs/doc[@for="XmlSchemas.Add"]/*' />
120         /// <devdoc>
121         ///    <para>[To be supplied.]</para>
122         /// </devdoc>
123         public int Add(XmlSchema schema) {
124             if (List.Contains(schema))
125                 return List.IndexOf(schema);
126             return List.Add(schema);
127         }
128
129         /// <include file='doc\XmlSchemas.uex' path='docs/doc[@for="XmlSchemas.Add"]/*' />
130         /// <devdoc>
131         ///    <para>[To be supplied.]</para>
132         /// </devdoc>
133         public int Add(XmlSchema schema, Uri baseUri) {
134             if (List.Contains(schema))
135                 return List.IndexOf(schema);
136             if (baseUri != null)
137                 schema.BaseUri = baseUri;
138             return List.Add(schema);
139         }
140
141         /// <include file='doc\XmlSchemas.uex' path='docs/doc[@for="XmlSchemas.Add1"]/*' />
142         /// <devdoc>
143         ///    <para>[To be supplied.]</para>
144         /// </devdoc>
145         public void Add(XmlSchemas schemas) {
146             foreach (XmlSchema schema in schemas) {
147                 Add(schema);
148             }
149         }
150
151         /// <include file='doc\XmlSchemas.uex' path='docs/doc[@for="XmlSchemas.AddReference"]/*' />
152         /// <devdoc>
153         ///    <para>[To be supplied.]</para>
154         /// </devdoc>
155         public void AddReference(XmlSchema schema) {
156             References[schema] = schema;
157         }
158
159         /// <include file='doc\XmlSchemas.uex' path='docs/doc[@for="XmlSchemas.Insert"]/*' />
160         /// <devdoc>
161         ///    <para>[To be supplied.]</para>
162         /// </devdoc>
163         public void Insert(int index, XmlSchema schema) {
164             List.Insert(index, schema);
165         }
166
167         /// <include file='doc\XmlSchemas.uex' path='docs/doc[@for="XmlSchemas.IndexOf"]/*' />
168         /// <devdoc>
169         ///    <para>[To be supplied.]</para>
170         /// </devdoc>
171         public int IndexOf(XmlSchema schema) {
172             return List.IndexOf(schema);
173         }
174         
175         /// <include file='doc\XmlSchemas.uex' path='docs/doc[@for="XmlSchemas.Contains"]/*' />
176         /// <devdoc>
177         ///    <para>[To be supplied.]</para>
178         /// </devdoc>
179         public bool Contains(XmlSchema schema) {
180             return List.Contains(schema);
181         }
182
183         /// <include file='doc\XmlSchemas.uex' path='docs/doc[@for="XmlSchemas.Contains1"]/*' />
184         /// <devdoc>
185         ///    <para>[To be supplied.]</para>
186         /// </devdoc>
187         public bool Contains(string targetNamespace) {
188             return SchemaSet.Contains(targetNamespace);
189         }
190         
191         /// <include file='doc\XmlSchemas.uex' path='docs/doc[@for="XmlSchemas.Remove"]/*' />
192         /// <devdoc>
193         ///    <para>[To be supplied.]</para>
194         /// </devdoc>
195         public void Remove(XmlSchema schema) {
196             List.Remove(schema);
197         }
198         
199         /// <include file='doc\XmlSchemas.uex' path='docs/doc[@for="XmlSchemas.CopyTo"]/*' />
200         /// <devdoc>
201         ///    <para>[To be supplied.]</para>
202         /// </devdoc>
203         public void CopyTo(XmlSchema[] array, int index) {
204             List.CopyTo(array, index);
205         }
206
207         /// <include file='doc\XmlSchemas.uex' path='docs/doc[@for="XmlSchemas.OnInsert"]/*' />
208         /// <devdoc>
209         ///    <para>[To be supplied.]</para>
210         /// </devdoc>
211         protected override void OnInsert(int index, object value) {
212             AddName((XmlSchema)value);
213         }
214
215         /// <include file='doc\XmlSchemas.uex' path='docs/doc[@for="XmlSchemas.OnRemove"]/*' />
216         /// <devdoc>
217         ///    <para>[To be supplied.]</para>
218         /// </devdoc>
219         protected override void OnRemove(int index, object value) {
220             RemoveName((XmlSchema)value);
221         }
222
223         /// <include file='doc\XmlSchemas.uex' path='docs/doc[@for="XmlSchemas.OnClear"]/*' />
224         /// <devdoc>
225         ///    <para>[To be supplied.]</para>
226         /// </devdoc>
227         protected override void OnClear() {
228             schemaSet = null;
229         }
230
231         /// <include file='doc\XmlSchemas.uex' path='docs/doc[@for="XmlSchemas.OnSet"]/*' />
232         /// <devdoc>
233         ///    <para>[To be supplied.]</para>
234         /// </devdoc>
235         protected override void OnSet(int index, object oldValue, object newValue) {
236             RemoveName((XmlSchema)oldValue);
237             AddName((XmlSchema)newValue);
238         }
239
240         void AddName(XmlSchema schema) {
241             if (isCompiled) throw new InvalidOperationException(Res.GetString(Res.XmlSchemaCompiled));
242             if (SchemaSet.Contains(schema))
243                 SchemaSet.Reprocess(schema);
244             else {
245                 Prepare(schema);
246                 SchemaSet.Add(schema);
247             }
248         }
249
250         void Prepare(XmlSchema schema) {
251             // need to remove illegal <import> externals;
252             ArrayList removes = new ArrayList();
253             string ns = schema.TargetNamespace;
254             foreach (XmlSchemaExternal external in schema.Includes) {
255                 if (external is XmlSchemaImport) {
256                     if (ns == ((XmlSchemaImport)external).Namespace) {
257                         removes.Add(external);
258                     }
259                 }
260             }
261             foreach(XmlSchemaObject o in removes) {
262                 schema.Includes.Remove(o);
263             }
264         }
265
266         void RemoveName(XmlSchema schema) {
267             SchemaSet.Remove(schema);
268         }
269
270         /// <include file='doc\XmlSchemas.uex' path='docs/doc[@for="XmlSchemas.Find"]/*' />
271         /// <devdoc>
272         ///    <para>[To be supplied.]</para>
273         /// </devdoc>
274         public object Find(XmlQualifiedName name, Type type) {
275             return Find(name, type, true);
276         }
277         internal object Find(XmlQualifiedName name, Type type, bool checkCache) {
278             if (!IsCompiled) {
279                  foreach (XmlSchema schema in List) {
280                     Preprocess(schema);
281                 }
282             }
283             IList values = (IList)SchemaSet.Schemas(name.Namespace);
284             if (values == null) return null;
285
286             foreach (XmlSchema schema in values) {
287                 Preprocess(schema);
288
289                 XmlSchemaObject ret = null;
290                 if (typeof(XmlSchemaType).IsAssignableFrom(type)) {
291                     ret = schema.SchemaTypes[name];
292                     if (ret == null || !type.IsAssignableFrom(ret.GetType())) {
293                         continue;
294                     }
295                 }
296                 else if (type == typeof(XmlSchemaGroup)) {
297                     ret = schema.Groups[name];
298                 }
299                 else if (type == typeof(XmlSchemaAttributeGroup)) {
300                     ret = schema.AttributeGroups[name];
301                 }
302                 else if (type == typeof(XmlSchemaElement)) {
303                     ret = schema.Elements[name];
304                 }
305                 else if (type == typeof(XmlSchemaAttribute)) {
306                     ret = schema.Attributes[name];
307                 }
308                 else if (type == typeof(XmlSchemaNotation)) {
309                     ret = schema.Notations[name];
310                 }
311 #if DEBUG
312             else {
313                 // use exception in the place of Debug.Assert to avoid throwing asserts from a server process such as aspnet_ewp.exe
314                 throw new InvalidOperationException(Res.GetString(Res.XmlInternalErrorDetails, "XmlSchemas.Find: Invalid object type " + type.FullName));
315             }
316 #endif
317
318                 if (ret != null && shareTypes && checkCache && !IsReference(ret))
319                     ret = Cache.AddItem(ret, name, this);
320                 if (ret != null) {
321                     return ret;
322                 }
323             }
324             return null;
325         }
326
327         IEnumerator<XmlSchema> IEnumerable<XmlSchema>.GetEnumerator() {
328             return new XmlSchemaEnumerator(this);
329         }
330
331         internal static void Preprocess(XmlSchema schema) {
332             if (!schema.IsPreprocessed) {
333                 try {
334                     XmlNameTable nameTable = new System.Xml.NameTable();
335                     Preprocessor prep = new Preprocessor(nameTable, new SchemaNames(nameTable), null);
336                     prep.SchemaLocations = new Hashtable();
337                     prep.Execute(schema, schema.TargetNamespace, false);
338                 }
339                 catch(XmlSchemaException e) {
340                     throw CreateValidationException(e, e.Message);
341                 }
342             }
343         }
344
345         /// <include file='doc\XmlSchemas.uex' path='docs/doc[@for="XmlSchemas.IsDataSet"]/*' />
346         /// <devdoc>
347         ///    <para>[To be supplied.]</para>
348         /// </devdoc>
349         public static bool IsDataSet(XmlSchema schema) {
350             foreach (XmlSchemaObject o in schema.Items) {
351                 if (o is XmlSchemaElement) {
352                     XmlSchemaElement e = (XmlSchemaElement)o;
353                     if (e.UnhandledAttributes != null) {
354                         foreach (XmlAttribute a in e.UnhandledAttributes) {
355                             if (a.LocalName == "IsDataSet" && a.NamespaceURI == "urn:schemas-microsoft-com:xml-msdata") {
356                                 // currently the msdata:IsDataSet uses its own format for the boolean values
357                                 if (a.Value == "True" || a.Value == "true" || a.Value == "1") return true;
358                             }
359                         }
360                     }
361                 }
362             }
363             return false;
364         }
365
366         void Merge(XmlSchema schema) {
367             if (MergedSchemas[schema] != null)
368                 return;
369             IList originals = (IList)SchemaSet.Schemas(schema.TargetNamespace);
370             if (originals != null && originals.Count > 0) {
371                 MergedSchemas.Add(schema, schema);
372                 Merge(originals, schema);
373             }
374             else {
375                 Add(schema); 
376                 MergedSchemas.Add(schema, schema);
377             }
378         }
379
380         void AddImport(IList schemas, string ns) {
381             foreach(XmlSchema s in schemas) {
382                 bool add = true;
383                 foreach (XmlSchemaExternal external in s.Includes) {
384                     if (external is XmlSchemaImport && ((XmlSchemaImport)external).Namespace == ns) {
385                         add = false;
386                         break;
387                     }
388                 }
389                 if (add) {
390                     XmlSchemaImport import = new XmlSchemaImport();
391                     import.Namespace = ns;
392                     s.Includes.Add(import);
393                 }
394             }
395         }
396
397         void Merge(IList originals, XmlSchema schema) {
398             foreach (XmlSchema s in originals) {
399                 if (schema == s) {
400                     return;
401                 }
402             }
403
404             foreach (XmlSchemaExternal external in schema.Includes) {
405                 if (external is XmlSchemaImport) {
406                     external.SchemaLocation = null;
407                     if (external.Schema != null) {
408                         Merge(external.Schema);
409                     }
410                     else {
411                         AddImport(originals, ((XmlSchemaImport)external).Namespace);
412                     }
413                 }
414                 else {
415                     if (external.Schema == null) {
416                         // we do not process includes or redefines by the schemaLocation
417                         if (external.SchemaLocation != null) {
418                             throw new InvalidOperationException(Res.GetString(Res.XmlSchemaIncludeLocation, this.GetType().Name, external.SchemaLocation));
419                         }
420                     }
421                     else {
422                         external.SchemaLocation = null;
423                         Merge(originals, external.Schema);
424                     }
425                 }
426             }
427
428             // bring all included items to the parent schema;
429             bool[] matchedItems = new bool[schema.Items.Count];
430             int count = 0;
431             for (int i = 0; i < schema.Items.Count; i++) {
432                 XmlSchemaObject o  = schema.Items[i];
433                 XmlSchemaObject dest = Find(o, originals);
434                 if (dest != null) {
435                     if (!Cache.Match(dest, o, shareTypes)) {
436                         // 
437                         Debug.WriteLineIf(DiagnosticsSwitches.XmlSerialization.TraceVerbose, "XmlSerialization::Failed to Merge " + MergeFailedMessage(o, dest, schema.TargetNamespace)
438                             + "' Plase Compare hash:\r\n" + Cache.looks[dest] + "\r\n" + Cache.looks[o]);
439                         throw new InvalidOperationException(MergeFailedMessage(o, dest, schema.TargetNamespace));
440                     }
441                     matchedItems[i] = true;
442                     count++;
443                 }
444             }
445             if (count != schema.Items.Count) {
446                 XmlSchema destination = (XmlSchema)originals[0];
447                 for (int i = 0; i < schema.Items.Count; i++) {
448                     if (!matchedItems[i]) {
449                         destination.Items.Add(schema.Items[i]);
450                     }
451                 }
452                 destination.IsPreprocessed = false;
453                 Preprocess(destination);
454             }
455         }
456
457         static string ItemName(XmlSchemaObject o) {
458             if (o is XmlSchemaNotation) {
459                 return ((XmlSchemaNotation)o).Name;
460             }
461             else if (o is XmlSchemaGroup) {
462                 return ((XmlSchemaGroup)o).Name;
463             }
464             else if (o is XmlSchemaElement) {
465                 return ((XmlSchemaElement)o).Name;
466             }
467             else if (o is XmlSchemaType) {
468                 return ((XmlSchemaType)o).Name;
469             }
470             else if (o is XmlSchemaAttributeGroup) {
471                 return ((XmlSchemaAttributeGroup)o).Name;
472             }
473             else if (o is XmlSchemaAttribute) {
474                 return ((XmlSchemaAttribute)o).Name;
475             }
476             return null;
477         }
478
479         internal static XmlQualifiedName GetParentName(XmlSchemaObject item) {
480             while (item.Parent != null) {
481                 if (item.Parent is XmlSchemaType) {
482                     XmlSchemaType type = (XmlSchemaType)item.Parent;
483                     if (type.Name != null && type.Name.Length != 0) {
484                         return type.QualifiedName;
485                     }
486                 }
487                 item = item.Parent;
488             }
489             return XmlQualifiedName.Empty;
490         }
491
492         static string GetSchemaItem(XmlSchemaObject o, string ns, string details) {
493             if (o == null) {
494                 return null;
495             }
496             while (o.Parent != null && !(o.Parent is XmlSchema)) {
497                 o = o.Parent;
498             }
499             if (ns == null || ns.Length == 0) {
500                 XmlSchemaObject tmp = o;
501                 while (tmp.Parent != null) {
502                     tmp = tmp.Parent;
503                 }
504                 if (tmp is XmlSchema) {
505                     ns = ((XmlSchema)tmp).TargetNamespace;
506                 }
507             }
508             string item = null;
509             if (o is XmlSchemaNotation) {
510                 item = Res.GetString(Res.XmlSchemaNamedItem, ns, "notation", ((XmlSchemaNotation)o).Name, details);
511             }
512             else if (o is XmlSchemaGroup) {
513                 item = Res.GetString(Res.XmlSchemaNamedItem, ns, "group", ((XmlSchemaGroup)o).Name, details);
514             }
515             else if (o is XmlSchemaElement) {
516                 XmlSchemaElement e = ((XmlSchemaElement)o);
517                 if (e.Name == null || e.Name.Length == 0) {
518                     XmlQualifiedName parentName = XmlSchemas.GetParentName(o);
519                     // Element reference '{0}' declared in schema type '{1}' from namespace '{2}'
520                     item = Res.GetString(Res.XmlSchemaElementReference, e.RefName.ToString(), parentName.Name, parentName.Namespace);
521                 }
522                 else {
523                     item = Res.GetString(Res.XmlSchemaNamedItem, ns, "element", e.Name, details);
524                 }
525             }
526             else if (o is XmlSchemaType) {
527                 item = Res.GetString(Res.XmlSchemaNamedItem, ns, o.GetType() == typeof(XmlSchemaSimpleType) ? "simpleType" : "complexType", ((XmlSchemaType)o).Name, null);
528             }
529             else if (o is XmlSchemaAttributeGroup) {
530                 item = Res.GetString(Res.XmlSchemaNamedItem, ns, "attributeGroup", ((XmlSchemaAttributeGroup)o).Name, details);
531             }
532             else if (o is XmlSchemaAttribute) {
533                 XmlSchemaAttribute a = ((XmlSchemaAttribute)o);
534                 if (a.Name == null || a.Name.Length == 0) {
535                     XmlQualifiedName parentName = XmlSchemas.GetParentName(o);
536                     // Attribure reference '{0}' declared in schema type '{1}' from namespace '{2}'
537                     return Res.GetString(Res.XmlSchemaAttributeReference, a.RefName.ToString(), parentName.Name, parentName.Namespace);
538                 }
539                 else  {
540                     item = Res.GetString(Res.XmlSchemaNamedItem, ns, "attribute", a.Name, details);
541                 }
542
543             }
544             else if (o is XmlSchemaContent) {
545                 XmlQualifiedName parentName = XmlSchemas.GetParentName(o);
546                 // Check content definition of schema type '{0}' from namespace '{1}'. {2}
547                 item = Res.GetString(Res.XmlSchemaContentDef, parentName.Name, parentName.Namespace, null);
548             }
549             else if (o is XmlSchemaExternal) {
550                 string itemType = o is XmlSchemaImport ? "import" : o is XmlSchemaInclude ? "include" : o is XmlSchemaRedefine ? "redefine" : o.GetType().Name;
551                 item = Res.GetString(Res.XmlSchemaItem, ns, itemType, details);
552             }
553             else if (o is XmlSchema) {
554                 item = Res.GetString(Res.XmlSchema, ns, details);
555             }
556             else {
557                 item = Res.GetString(Res.XmlSchemaNamedItem, ns, o.GetType().Name, null, details);
558             }
559
560             return item;
561         }
562
563         static string Dump(XmlSchemaObject o) {
564             XmlWriterSettings settings = new XmlWriterSettings();
565             settings.OmitXmlDeclaration = true;
566             settings.Indent = true;
567             XmlSerializer s = new XmlSerializer(o.GetType());
568             StringWriter sw = new StringWriter(CultureInfo.InvariantCulture);
569             XmlWriter xmlWriter = XmlWriter.Create(sw, settings);
570             XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
571             ns.Add("xs", XmlSchema.Namespace);
572             s.Serialize(xmlWriter, o, ns);
573             return sw.ToString();
574         }
575         static string MergeFailedMessage(XmlSchemaObject src, XmlSchemaObject dest, string ns) {
576             string err = Res.GetString(Res.XmlSerializableMergeItem, ns, GetSchemaItem(src, ns, null));
577             err += "\r\n" + Dump(src);
578             err += "\r\n" + Dump(dest);
579             return err;
580         }
581
582         internal XmlSchemaObject Find(XmlSchemaObject o, IList originals) {
583             string name = ItemName(o);
584             if (name == null)
585                 return null;
586
587             Type type = o.GetType();
588
589             foreach (XmlSchema s in originals) {
590                 foreach(XmlSchemaObject item in s.Items) {
591                     if (item.GetType() == type && name == ItemName(item)) {
592                         return item;
593                     }
594                 }
595             }
596             return null;
597         }
598
599         /// <include file='doc\XmlSchemas.uex' path='docs/doc[@for="XmlSchemas.IsCompiled"]/*' />
600         public bool IsCompiled {
601             get { return isCompiled; }
602         }
603
604         /// <include file='doc\XmlSchemas.uex' path='docs/doc[@for="XmlSchemas.Compile"]/*' />
605         public void Compile(ValidationEventHandler handler, bool fullCompile) {
606             if (isCompiled)
607                 return;
608
609             foreach(XmlSchema s in delayedSchemas.Values)
610                 Merge(s);
611             delayedSchemas.Clear();
612
613             if (fullCompile) {
614                 schemaSet = new XmlSchemaSet();
615                 schemaSet.XmlResolver = null;
616                 schemaSet.ValidationEventHandler += handler;
617
618                 foreach (XmlSchema s in References.Values)
619                     schemaSet.Add(s);
620                 int schemaCount = schemaSet.Count;
621
622                 foreach (XmlSchema s in List) {
623                     if (!SchemaSet.Contains(s)) {
624                         schemaSet.Add(s);
625                         schemaCount++;
626                     }
627                 }
628
629                 if (!SchemaSet.Contains(XmlSchema.Namespace)) {
630                     AddReference(XsdSchema);
631                     schemaSet.Add(XsdSchema);
632                     schemaCount++;
633                 }
634
635                 if (!SchemaSet.Contains(XmlReservedNs.NsXml)) {
636                     AddReference(XmlSchema);
637                     schemaSet.Add(XmlSchema);
638                     schemaCount++;
639                 }
640                 schemaSet.Compile();
641                 schemaSet.ValidationEventHandler -= handler;
642                 isCompiled = schemaSet.IsCompiled && schemaCount == schemaSet.Count;
643             }
644             else {
645                 try {
646                     XmlNameTable nameTable = new System.Xml.NameTable();
647                     Preprocessor prep = new Preprocessor(nameTable, new SchemaNames(nameTable), null);
648                     prep.XmlResolver = null;
649                     prep.SchemaLocations = new Hashtable();
650                     prep.ChameleonSchemas = new Hashtable();
651                     foreach (XmlSchema schema in SchemaSet.Schemas()) {
652                         prep.Execute(schema, schema.TargetNamespace, true);
653                     }
654                 }
655                 catch(XmlSchemaException e) {
656                     throw CreateValidationException(e, e.Message);
657                 }
658             }
659         }
660
661         internal static Exception CreateValidationException(XmlSchemaException exception, string message) {
662             XmlSchemaObject source = exception.SourceSchemaObject;
663             if (exception.LineNumber == 0 && exception.LinePosition == 0) {
664                 throw new InvalidOperationException(GetSchemaItem(source, null, message), exception);
665             }
666             else {
667                 string ns = null;
668                 if (source != null) {
669                     while (source.Parent != null) {
670                         source = source.Parent;
671                     }
672                     if (source is XmlSchema) {
673                         ns = ((XmlSchema)source).TargetNamespace;
674                     }
675                 }
676                 throw new InvalidOperationException(Res.GetString(Res.XmlSchemaSyntaxErrorDetails, ns, message, exception.LineNumber, exception.LinePosition), exception);
677             }
678         }
679
680         internal static void IgnoreCompileErrors(object sender, ValidationEventArgs args) {
681             return;
682         }
683
684         internal static XmlSchema XsdSchema {
685             get {
686                 if (xsd == null) {
687                     xsd = CreateFakeXsdSchema(XmlSchema.Namespace, "schema");
688                 }
689                 return xsd;
690             }
691         }
692
693         internal static XmlSchema XmlSchema {
694             get {
695                 if (xml == null) {
696                     xml = XmlSchema.Read(new StringReader(xmlSchema), null);
697                 }
698                 return xml;
699             }
700         }
701
702         private static XmlSchema CreateFakeXsdSchema(string ns, string name) {
703             /* Create fake xsd schema to fool the XmlSchema.Compiler
704                 <xsd:schema targetNamespace="http://www.w3.org/2001/XMLSchema" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
705                   <xsd:element name="schema">
706                     <xsd:complexType />
707                   </xsd:element>
708                 </xsd:schema>
709             */
710             XmlSchema schema = new XmlSchema();
711             schema.TargetNamespace = ns;
712             XmlSchemaElement element = new XmlSchemaElement();
713             element.Name = name;
714             XmlSchemaComplexType type = new XmlSchemaComplexType();
715             element.SchemaType = type;
716             schema.Items.Add(element);
717             return schema;
718         }
719
720         internal void SetCache(SchemaObjectCache cache, bool shareTypes) {
721             this.shareTypes = shareTypes;
722             this.cache = cache;
723             if (shareTypes) {
724                 cache.GenerateSchemaGraph(this);
725             }
726         }
727
728         internal bool IsReference(XmlSchemaObject type) {
729             XmlSchemaObject parent = type;
730             while (parent.Parent != null) {
731                 parent = parent.Parent;
732             }
733             return References.Contains(parent);
734         }
735
736         internal const string xmlSchema = @"<?xml version='1.0' encoding='UTF-8' ?> 
737 <xs:schema targetNamespace='http://www.w3.org/XML/1998/namespace' xmlns:xs='http://www.w3.org/2001/XMLSchema' xml:lang='en'>
738  <xs:attribute name='lang' type='xs:language'/>
739  <xs:attribute name='space'>
740   <xs:simpleType>
741    <xs:restriction base='xs:NCName'>
742     <xs:enumeration value='default'/>
743     <xs:enumeration value='preserve'/>
744    </xs:restriction>
745   </xs:simpleType>
746  </xs:attribute>
747  <xs:attribute name='base' type='xs:anyURI'/>
748  <xs:attribute name='id' type='xs:ID' />
749  <xs:attributeGroup name='specialAttrs'>
750   <xs:attribute ref='xml:base'/>
751   <xs:attribute ref='xml:lang'/>
752   <xs:attribute ref='xml:space'/>
753  </xs:attributeGroup>
754 </xs:schema>";
755     }
756
757     public class XmlSchemaEnumerator : IEnumerator<XmlSchema>, System.Collections.IEnumerator {
758         private XmlSchemas list;
759         private int idx, end;
760
761         public XmlSchemaEnumerator(XmlSchemas list) {
762             this.list = list;
763             this.idx = -1;
764             this.end = list.Count - 1;
765         }
766
767         public void Dispose() {
768         }
769
770         public bool MoveNext() {
771             if (this.idx >= this.end)
772                 return false;
773
774             this.idx++;
775             return true;
776         }
777
778         public XmlSchema Current {
779             get { return this.list[this.idx]; }
780         }
781
782         object System.Collections.IEnumerator.Current {
783             get { return this.list[this.idx]; }
784         }
785
786         void System.Collections.IEnumerator.Reset() {
787             this.idx = -1;
788         }
789     }
790 }