Merge pull request #347 from JamesB7/master
[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
57                 XmlSchemaCompilationSettings settings =
58                         new XmlSchemaCompilationSettings ();
59
60                 bool isCompiled;
61
62                 internal Guid CompilationId { get; private set; }
63
64                 public XmlSchemaSet ()
65                         : this (new NameTable ())
66                 {
67                 }
68
69                 public XmlSchemaSet (XmlNameTable nameTable)
70                 {
71                         if (nameTable == null)
72                                 throw new ArgumentNullException ("nameTable");
73
74                         this.nameTable = nameTable;
75                         schemas = new ArrayList ();
76                         CompilationId = Guid.NewGuid ();
77                 }
78
79                 public event ValidationEventHandler ValidationEventHandler;
80
81                 public int Count {
82                         get { return schemas.Count; }
83                 }
84
85                 public XmlSchemaObjectTable GlobalAttributes {
86                         get {
87                                 if (attributes == null)
88                                         attributes = new XmlSchemaObjectTable ();
89                                 return attributes;
90                         }
91                 }
92
93                 public XmlSchemaObjectTable GlobalElements {
94                         get {
95                                 if (elements == null)
96                                         elements = new XmlSchemaObjectTable ();
97                                 return elements;
98                         }
99                 }
100
101                 public XmlSchemaObjectTable GlobalTypes { 
102                         get {
103                                 if (types == null)
104                                         types = new XmlSchemaObjectTable ();
105                                 return types;
106                         }
107                 }
108
109                 public bool IsCompiled { 
110                         get { return isCompiled; }
111                 }
112
113                 public XmlNameTable NameTable { 
114                         get { return nameTable; }
115                 }
116
117                 public XmlSchemaCompilationSettings CompilationSettings {
118                         get { return settings; }
119                         set { settings = value; }
120                 }
121
122                 public XmlResolver XmlResolver {
123                         set { xmlResolver = value; }
124 #if NET_2_0
125                         internal get { return xmlResolver; }
126 #else
127                         get { return xmlResolver; }
128 #endif
129                 }
130
131                 public XmlSchema Add (string targetNamespace, string schemaUri)
132                 {
133                         XmlTextReader r = null;
134                         try {
135                                 r = new XmlTextReader (schemaUri, nameTable);
136                                 return Add (targetNamespace, r);
137                         } finally {
138                                 if (r != null)
139                                         r.Close ();
140                         }
141                 }
142
143                 public XmlSchema Add (string targetNamespace, XmlReader schemaDocument)
144                 {
145                         XmlSchema schema = XmlSchema.Read (schemaDocument, ValidationEventHandler);
146                         if (schema.TargetNamespace == null)
147                                 schema.TargetNamespace = targetNamespace == String.Empty ? null : targetNamespace; // this weirdness is due to bug #571660.
148                         else if (targetNamespace != null && schema.TargetNamespace != targetNamespace)
149                                 throw new XmlSchemaException ("The actual targetNamespace in the schema does not match the parameter.");
150                         Add (schema);
151                         return schema;
152                 }
153
154                 [MonoTODO]
155                 // FIXME: Check the exact behavior when namespaces are in conflict (but it would be preferable to wait for 2.0 RTM)
156                 public void Add (XmlSchemaSet schemas)
157                 {
158                         ArrayList al = new ArrayList ();
159                         foreach (XmlSchema schema in schemas.schemas) {
160                                 if (!this.schemas.Contains (schema))
161                                         al.Add (schema);
162                         }
163                         foreach (XmlSchema schema in al)
164                                 Add (schema);
165                 }
166
167                 public XmlSchema Add (XmlSchema schema)
168                 {
169                         schemas.Add (schema);
170                         ResetCompile ();
171                         return schema;
172                 }
173
174                 // FIXME: It should be the actual compilation engine.
175                 public void Compile ()
176                 {
177                         ClearGlobalComponents ();
178                         ArrayList al = new ArrayList ();
179                         al.AddRange (schemas);
180
181                         var handledUris = new List<CompiledSchemaMemo> ();
182                         foreach (XmlSchema schema in al)
183                                 if (!schema.IsCompiled)
184                                         schema.CompileSubset (ValidationEventHandler, this, xmlResolver, handledUris);
185
186                         // Process substitutionGroup first, as this process
187                         // involves both substituted and substituting elements
188                         // and hence it needs to be done before actual
189                         // validation (by current design of conformance checker).
190                         foreach (XmlSchema schema in al)
191                                 foreach (XmlSchemaElement elem in schema.Elements.Values)
192                                         elem.FillSubstitutionElementInfo ();
193
194
195                         foreach (XmlSchema schema in al)
196                                 schema.Validate (ValidationEventHandler);
197
198                         foreach (XmlSchema schema in al)
199                                 AddGlobalComponents (schema);
200
201                         isCompiled = true;
202                 }
203
204                 private void ClearGlobalComponents ()
205                 {
206                         GlobalElements.Clear ();
207                         GlobalAttributes.Clear ();
208                         GlobalTypes.Clear ();
209                         global_attribute_groups.Clear ();
210                         global_groups.Clear ();
211                         global_notations.Clear ();
212                         global_ids.Clear ();
213                         global_identity_constraints.Clear ();
214                 }
215                 
216                 XmlSchemaObjectTable global_attribute_groups = new XmlSchemaObjectTable ();
217                 XmlSchemaObjectTable global_groups = new XmlSchemaObjectTable ();
218                 XmlSchemaObjectTable global_notations = new XmlSchemaObjectTable ();
219                 XmlSchemaObjectTable global_identity_constraints = new XmlSchemaObjectTable ();
220                 Hashtable global_ids = new Hashtable ();
221
222                 private void AddGlobalComponents (XmlSchema schema)
223                 {
224                         foreach (XmlSchemaElement el in schema.Elements.Values)
225                                 GlobalElements.Add (el.QualifiedName, el);
226                         foreach (XmlSchemaAttribute a in schema.Attributes.Values)
227                                 GlobalAttributes.Add (a.QualifiedName, a);
228                         foreach (XmlSchemaType t in schema.SchemaTypes.Values)
229                                 GlobalTypes.Add (t.QualifiedName, t);
230                         foreach (XmlSchemaAttributeGroup g in schema.AttributeGroups.Values)
231                                 global_attribute_groups.Add (g.QualifiedName, g);
232                         foreach (XmlSchemaGroup g in schema.Groups.Values)
233                                 global_groups.Add (g.QualifiedName, g);
234                         foreach (DictionaryEntry pair in schema.IDCollection)
235                                 global_ids.Add (pair.Key, pair.Value);
236                         foreach (XmlSchemaIdentityConstraint ic in schema.NamedIdentities.Values)
237                                 global_identity_constraints.Add (ic.QualifiedName, ic);
238                 }
239
240                 public bool Contains (string targetNamespace)
241                 {
242                         targetNamespace = GetSafeNs (targetNamespace);
243                         foreach (XmlSchema schema in schemas)
244                                 if (GetSafeNs (schema.TargetNamespace) == targetNamespace)
245                                         return true;
246                         return false;
247                 }
248
249                 public bool Contains (XmlSchema schema)
250                 {
251                         foreach (XmlSchema s in schemas)
252                                 if (s == schema)
253                                         return true;
254                         return false;
255                 }
256
257                 public void CopyTo (XmlSchema [] schemas, int index)
258                 {
259                         this.schemas.CopyTo (schemas, index);
260                 }
261
262                 internal void CopyTo (Array array, int index)
263                 {
264                         schemas.CopyTo (array, index);
265                 }
266
267                 string GetSafeNs (string ns)
268                 {
269                         return ns == null ? "" : ns;
270                 }
271
272                 [MonoTODO]
273                 // FIXME: Check exact behavior
274                 public XmlSchema Remove (XmlSchema schema)
275                 {
276                         if (schema == null)
277                                 throw new ArgumentNullException ("schema");
278                         ArrayList al = new ArrayList ();
279                         al.AddRange (schemas);
280                         if (!al.Contains (schema))
281                                 return null;
282                         // FIXME: I have no idea why Remove() might throw
283                         // XmlSchemaException, except for the case it compiles.
284                         if (!schema.IsCompiled)
285                                 schema.CompileSubset (ValidationEventHandler, this, xmlResolver);
286                         schemas.Remove (schema);
287                         ResetCompile ();
288                         return schema;
289                 }
290
291                 void ResetCompile ()
292                 {
293                         isCompiled = false;
294                         ClearGlobalComponents ();
295                 }
296
297                 public bool RemoveRecursive (XmlSchema schemaToRemove)
298                 {
299                         if (schemaToRemove == null)
300                                 throw new ArgumentNullException ("schema");
301                         ArrayList al = new ArrayList ();
302                         al.AddRange (schemas);
303                         if (!al.Contains (schemaToRemove))
304                                 return false;
305                         al.Remove (schemaToRemove);
306                         schemas.Remove (schemaToRemove);
307
308                         if (!IsCompiled)
309                                 return true;
310
311                         ClearGlobalComponents ();
312                         foreach (XmlSchema s in al) {
313                                 if (s.IsCompiled)
314                                         AddGlobalComponents (schemaToRemove);
315                         }
316                         return true;
317                 }
318
319                 public XmlSchema Reprocess (XmlSchema schema)
320                 {
321                         if (schema == null)
322                                 throw new ArgumentNullException ("schema");
323                         ArrayList al = new ArrayList ();
324                         al.AddRange (schemas);
325                         if (!al.Contains (schema))
326                                 throw new ArgumentException ("Target schema is not contained in the schema set.");
327                         ClearGlobalComponents ();
328                         foreach (XmlSchema s in al) {
329                                 if (schema == s)
330                                         schema.CompileSubset (ValidationEventHandler, this, xmlResolver);
331                                 if (s.IsCompiled)
332                                         AddGlobalComponents (schema);
333                         }
334                         return schema.IsCompiled ? schema : null;
335                 }
336
337                 public ICollection Schemas ()
338                 {
339                         return schemas;
340                 }
341
342                 public ICollection Schemas (string targetNamespace)
343                 {
344                         targetNamespace = GetSafeNs (targetNamespace);
345                         ArrayList al = new ArrayList ();
346                         foreach (XmlSchema schema in schemas)
347                                 if (GetSafeNs (schema.TargetNamespace) == targetNamespace)
348                                         al.Add (schema);
349                         return al;
350                 }
351
352                 internal bool MissedSubComponents (string targetNamespace)
353                 {
354                         foreach (XmlSchema s in Schemas (targetNamespace))
355                                 if (s.missedSubComponents)
356                                         return true;
357                         return false;
358                 }
359         }
360 }