Multiple schemas in wsdl could share same SourceUri, so check more identity.
[mono.git] / mcs / class / System.XML / System.Xml.Schema / XmlSchemaSet.cs
1 //
2 // XmlSchemaSet.cs
3 //
4 // Author:
5 //      Atsushi Enomoto <ginga@kit.hi-ho.ne.jp>
6 //
7 // (C)2003 Atsushi Enomoto
8 // (C)2004 Novell Inc.
9 //
10
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31 using System;
32 using System.Collections;
33 using System.Collections.Generic;
34 using System.Collections.Specialized;
35 using System.ComponentModel;
36 using System.IO;
37 using System.Security.Policy;
38 using System.Xml.Schema;
39 using System.Xml.XPath;
40
41 namespace System.Xml.Schema
42 {
43 #if NET_2_0
44         public class XmlSchemaSet
45 #else
46         internal sealed class XmlSchemaSet
47 #endif
48         {
49                 XmlNameTable nameTable;
50                 XmlResolver xmlResolver = new XmlUrlResolver ();
51
52                 ArrayList schemas;
53                 XmlSchemaObjectTable attributes;
54                 XmlSchemaObjectTable elements;
55                 XmlSchemaObjectTable types;
56 //              XmlSchemaObjectTable attributeGroups;
57 //              XmlSchemaObjectTable groups;
58                 Hashtable idCollection;
59                 XmlSchemaObjectTable namedIdentities;
60
61                 XmlSchemaCompilationSettings settings =
62                         new XmlSchemaCompilationSettings ();
63
64                 bool isCompiled;
65
66                 internal Guid CompilationId { get; private set; }
67
68                 public XmlSchemaSet ()
69                         : this (new NameTable ())
70                 {
71                 }
72
73                 public XmlSchemaSet (XmlNameTable nameTable)
74                 {
75                         if (nameTable == null)
76                                 throw new ArgumentNullException ("nameTable");
77
78                         this.nameTable = nameTable;
79                         schemas = new ArrayList ();
80                         CompilationId = Guid.NewGuid ();
81                 }
82
83                 public event ValidationEventHandler ValidationEventHandler;
84
85                 public int Count {
86                         get { return schemas.Count; }
87                 }
88
89                 public XmlSchemaObjectTable GlobalAttributes {
90                         get {
91                                 if (attributes == null)
92                                         attributes = new XmlSchemaObjectTable ();
93                                 return attributes;
94                         }
95                 }
96
97                 public XmlSchemaObjectTable GlobalElements {
98                         get {
99                                 if (elements == null)
100                                         elements = new XmlSchemaObjectTable ();
101                                 return elements;
102                         }
103                 }
104
105                 public XmlSchemaObjectTable GlobalTypes { 
106                         get {
107                                 if (types == null)
108                                         types = new XmlSchemaObjectTable ();
109                                 return types;
110                         }
111                 }
112
113                 public bool IsCompiled { 
114                         get { return isCompiled; }
115                 }
116
117                 public XmlNameTable NameTable { 
118                         get { return nameTable; }
119                 }
120
121                 public XmlSchemaCompilationSettings CompilationSettings {
122                         get { return settings; }
123                         set { settings = value; }
124                 }
125
126                 public XmlResolver XmlResolver {
127                         set { xmlResolver = value; }
128 #if NET_2_0
129                         internal get { return xmlResolver; }
130 #else
131                         get { return xmlResolver; }
132 #endif
133                 }
134
135                 internal Hashtable IDCollection {
136                         get {
137                                 if (idCollection == null)
138                                         idCollection = new Hashtable ();
139                                 return idCollection;
140                         }
141                 }
142
143                 internal XmlSchemaObjectTable NamedIdentities {
144                         get {
145                                 if (namedIdentities == null)
146                                         namedIdentities = new XmlSchemaObjectTable();
147                                 return namedIdentities;
148                         }
149                 }
150
151                 public XmlSchema Add (string targetNamespace, string url)
152                 {
153                         XmlTextReader r = null;
154                         try {
155                                 r = new XmlTextReader (url, nameTable);
156                                 return Add (targetNamespace, r);
157                         } finally {
158                                 if (r != null)
159                                         r.Close ();
160                         }
161                 }
162
163                 public XmlSchema Add (string targetNamespace, XmlReader reader)
164                 {
165                         XmlSchema schema = XmlSchema.Read (reader, ValidationEventHandler);
166                         if (schema.TargetNamespace == null)
167                                 schema.TargetNamespace = targetNamespace == String.Empty ? null : targetNamespace; // this weirdness is due to bug #571660.
168                         else if (targetNamespace != null && schema.TargetNamespace != targetNamespace)
169                                 throw new XmlSchemaException ("The actual targetNamespace in the schema does not match the parameter.");
170                         Add (schema);
171                         return schema;
172                 }
173
174                 [MonoTODO]
175                 // FIXME: Check the exact behavior when namespaces are in conflict (but it would be preferable to wait for 2.0 RTM)
176                 public void Add (XmlSchemaSet schemaSet)
177                 {
178                         ArrayList al = new ArrayList ();
179                         foreach (XmlSchema schema in schemaSet.schemas) {
180                                 if (!schemas.Contains (schema))
181                                         al.Add (schema);
182                         }
183                         foreach (XmlSchema schema in al)
184                                 Add (schema);
185                 }
186
187                 public XmlSchema Add (XmlSchema schema)
188                 {
189                         schemas.Add (schema);
190                         ResetCompile ();
191                         return schema;
192                 }
193
194                 // FIXME: It should be the actual compilation engine.
195                 public void Compile ()
196                 {
197                         ClearGlobalComponents ();
198                         ArrayList al = new ArrayList ();
199                         al.AddRange (schemas);
200                         IDCollection.Clear ();
201                         NamedIdentities.Clear ();
202
203                         var handledUris = new List<CompiledSchemaMemo> ();
204                         foreach (XmlSchema schema in al)
205                                 if (!schema.IsCompiled)
206                                         schema.CompileSubset (ValidationEventHandler, this, xmlResolver, handledUris);
207
208                         // Process substitutionGroup first, as this process
209                         // involves both substituted and substituting elements
210                         // and hence it needs to be done before actual
211                         // validation (by current design of conformance checker).
212                         foreach (XmlSchema schema in al)
213                                 foreach (XmlSchemaElement elem in schema.Elements.Values)
214                                         elem.FillSubstitutionElementInfo ();
215
216
217                         foreach (XmlSchema schema in al)
218                                 schema.Validate (ValidationEventHandler);
219
220                         foreach (XmlSchema schema in al)
221                                 AddGlobalComponents (schema);
222
223                         isCompiled = true;
224                 }
225
226                 private void ClearGlobalComponents ()
227                 {
228                         GlobalElements.Clear ();
229                         GlobalAttributes.Clear ();
230                         GlobalTypes.Clear ();
231                         // GlobalAttributeGroups.Clear ();
232                         // GlobalGroups.Clear ();
233                 }
234
235                 private void AddGlobalComponents (XmlSchema schema)
236                 {
237                         foreach (XmlSchemaElement el in schema.Elements.Values)
238                                 GlobalElements.Add (el.QualifiedName, el);
239                         foreach (XmlSchemaAttribute a in schema.Attributes.Values)
240                                 GlobalAttributes.Add (a.QualifiedName, a);
241                         foreach (XmlSchemaType t in schema.SchemaTypes.Values)
242                                 GlobalTypes.Add (t.QualifiedName, t);
243                 }
244
245                 public bool Contains (string targetNamespace)
246                 {
247                         targetNamespace = GetSafeNs (targetNamespace);
248                         foreach (XmlSchema schema in schemas)
249                                 if (GetSafeNs (schema.TargetNamespace) == targetNamespace)
250                                         return true;
251                         return false;
252                 }
253
254                 public bool Contains (XmlSchema targetNamespace)
255                 {
256                         foreach (XmlSchema schema in schemas)
257                                 if (schema == targetNamespace)
258                                         return true;
259                         return false;
260                 }
261
262                 public void CopyTo (XmlSchema [] array, int index)
263                 {
264                         schemas.CopyTo (array, index);
265                 }
266
267                 internal void CopyTo (Array array, int index)
268                 {
269                         schemas.CopyTo (array, index);
270                 }
271
272                 string GetSafeNs (string ns)
273                 {
274                         return ns == null ? "" : ns;
275                 }
276
277                 [MonoTODO]
278                 // FIXME: Check exact behavior
279                 public XmlSchema Remove (XmlSchema schema)
280                 {
281                         if (schema == null)
282                                 throw new ArgumentNullException ("schema");
283                         ArrayList al = new ArrayList ();
284                         al.AddRange (schemas);
285                         if (!al.Contains (schema))
286                                 return null;
287                         // FIXME: I have no idea why Remove() might throw
288                         // XmlSchemaException, except for the case it compiles.
289                         if (!schema.IsCompiled)
290                                 schema.CompileSubset (ValidationEventHandler, this, xmlResolver);
291                         schemas.Remove (schema);
292                         ResetCompile ();
293                         return schema;
294                 }
295
296                 void ResetCompile ()
297                 {
298                         isCompiled = false;
299                         ClearGlobalComponents ();
300                 }
301
302                 public bool RemoveRecursive (XmlSchema schema)
303                 {
304                         if (schema == null)
305                                 throw new ArgumentNullException ("schema");
306                         ArrayList al = new ArrayList ();
307                         al.AddRange (schemas);
308                         if (!al.Contains (schema))
309                                 return false;
310                         al.Remove (schema);
311                         schemas.Remove (schema);
312
313                         if (!IsCompiled)
314                                 return true;
315
316                         ClearGlobalComponents ();
317                         foreach (XmlSchema s in al) {
318                                 if (s.IsCompiled)
319                                         AddGlobalComponents (schema);
320                         }
321                         return true;
322                 }
323
324                 public XmlSchema Reprocess (XmlSchema schema)
325                 {
326                         if (schema == null)
327                                 throw new ArgumentNullException ("schema");
328                         ArrayList al = new ArrayList ();
329                         al.AddRange (schemas);
330                         if (!al.Contains (schema))
331                                 throw new ArgumentException ("Target schema is not contained in the schema set.");
332                         ClearGlobalComponents ();
333                         foreach (XmlSchema s in al) {
334                                 if (schema == s)
335                                         schema.CompileSubset (ValidationEventHandler, this, xmlResolver);
336                                 if (s.IsCompiled)
337                                         AddGlobalComponents (schema);
338                         }
339                         return schema.IsCompiled ? schema : null;
340                 }
341
342                 public ICollection Schemas ()
343                 {
344                         return schemas;
345                 }
346
347                 public ICollection Schemas (string targetNamespace)
348                 {
349                         targetNamespace = GetSafeNs (targetNamespace);
350                         ArrayList al = new ArrayList ();
351                         foreach (XmlSchema schema in schemas)
352                                 if (GetSafeNs (schema.TargetNamespace) == targetNamespace)
353                                         al.Add (schema);
354                         return al;
355                 }
356
357                 internal bool MissedSubComponents (string targetNamespace)
358                 {
359                         foreach (XmlSchema s in Schemas (targetNamespace))
360                                 if (s.missedSubComponents)
361                                         return true;
362                         return false;
363                 }
364         }
365 }