2006-11-22 Atsushi Enomoto <atsushi@ximian.com>
[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.Specialized;
34 using System.ComponentModel;
35 using System.IO;
36 using System.Security.Policy;
37 using System.Xml.Schema;
38 using System.Xml.XPath;
39
40 namespace System.Xml.Schema
41 {
42 #if NET_2_0
43         public class XmlSchemaSet
44 #else
45         internal sealed class XmlSchemaSet
46 #endif
47         {
48                 XmlNameTable nameTable;
49                 XmlResolver xmlResolver = new XmlUrlResolver ();
50
51                 ArrayList schemas;
52                 XmlSchemaObjectTable attributes;
53                 XmlSchemaObjectTable elements;
54                 XmlSchemaObjectTable types;
55 //              XmlSchemaObjectTable attributeGroups;
56 //              XmlSchemaObjectTable groups;
57                 Hashtable idCollection;
58                 XmlSchemaObjectTable namedIdentities;
59
60                 XmlSchemaCompilationSettings settings =
61                         new XmlSchemaCompilationSettings ();
62
63                 bool isCompiled;
64
65                 internal Guid CompilationId;
66
67                 public XmlSchemaSet ()
68                         : this (new NameTable ())
69                 {
70                 }
71
72                 public XmlSchemaSet (XmlNameTable nameTable)
73                 {
74                         if (nameTable == null)
75                                 throw new ArgumentNullException ("nameTable");
76
77                         this.nameTable = nameTable;
78                         schemas = new ArrayList ();
79                         CompilationId = Guid.NewGuid ();
80                 }
81
82                 public event ValidationEventHandler ValidationEventHandler;
83
84                 public int Count {
85                         get { return schemas.Count; }
86                 }
87
88                 public XmlSchemaObjectTable GlobalAttributes {
89                         get {
90                                 if (attributes == null)
91                                         attributes = new XmlSchemaObjectTable ();
92                                 return attributes;
93                         }
94                 }
95
96                 public XmlSchemaObjectTable GlobalElements {
97                         get {
98                                 if (elements == null)
99                                         elements = new XmlSchemaObjectTable ();
100                                 return elements;
101                         }
102                 }
103
104                 public XmlSchemaObjectTable GlobalTypes { 
105                         get {
106                                 if (types == null)
107                                         types = new XmlSchemaObjectTable ();
108                                 return types;
109                         }
110                 }
111
112                 public bool IsCompiled { 
113                         get { return isCompiled; }
114                 }
115
116                 public XmlNameTable NameTable { 
117                         get { return nameTable; }
118                 }
119
120                 public XmlSchemaCompilationSettings CompilationSettings {
121                         get { return settings; }
122                         set { settings = value; }
123                 }
124
125                 public XmlResolver XmlResolver {
126                         set { xmlResolver = value; }
127 #if NET_2_0
128                         internal get { return xmlResolver; }
129 #else
130                         get { return xmlResolver; }
131 #endif
132                 }
133
134                 internal Hashtable IDCollection {
135                         get {
136                                 if (idCollection == null)
137                                         idCollection = new Hashtable ();
138                                 return idCollection;
139                         }
140                 }
141
142                 internal XmlSchemaObjectTable NamedIdentities {
143                         get {
144                                 if (namedIdentities == null)
145                                         namedIdentities = new XmlSchemaObjectTable();
146                                 return namedIdentities;
147                         }
148                 }
149
150                 public XmlSchema Add (string targetNamespace, string url)
151                 {
152                         XmlTextReader r = null;
153                         try {
154                                 r = new XmlTextReader (url, nameTable);
155                                 return Add (targetNamespace, r);
156                         } finally {
157                                 if (r != null)
158                                         r.Close ();
159                         }
160                 }
161
162                 public XmlSchema Add (string targetNamespace, XmlReader reader)
163                 {
164                         XmlSchema schema = XmlSchema.Read (reader, ValidationEventHandler);
165                         if (schema.TargetNamespace == null)
166                                 schema.TargetNamespace = targetNamespace;
167                         else if (targetNamespace != null && schema.TargetNamespace != targetNamespace)
168                                 throw new XmlSchemaException ("The actual targetNamespace in the schema does not match the parameter.");
169                         Add (schema);
170                         return schema;
171                 }
172
173                 [MonoTODO]
174                 // FIXME: Check the exact behavior when namespaces are in conflict (but it would be preferable to wait for 2.0 RTM)
175                 public void Add (XmlSchemaSet schemaSet)
176                 {
177                         ArrayList al = new ArrayList ();
178                         foreach (XmlSchema schema in schemaSet.schemas) {
179                                 if (!schemas.Contains (schema))
180                                         al.Add (schema);
181                         }
182                         foreach (XmlSchema schema in al)
183                                 Add (schema);
184                 }
185
186                 public XmlSchema Add (XmlSchema schema)
187                 {
188                         schemas.Add (schema);
189                         ResetCompile ();
190                         return schema;
191                 }
192
193                 // FIXME: It should be the actual compilation engine.
194                 public void Compile ()
195                 {
196                         ClearGlobalComponents ();
197                         ArrayList al = new ArrayList ();
198                         al.AddRange (schemas);
199                         IDCollection.Clear ();
200                         NamedIdentities.Clear ();
201
202                         foreach (XmlSchema schema in al)
203                                 if (!schema.IsCompiled)
204                                         schema.CompileSubset (ValidationEventHandler, this, xmlResolver);
205                         foreach (XmlSchema schema in al)
206                                 schema.Validate (ValidationEventHandler);
207
208                         foreach (XmlSchema schema in al)
209                                 AddGlobalComponents (schema);
210
211                         isCompiled = true;
212                 }
213
214                 private void ClearGlobalComponents ()
215                 {
216                         GlobalElements.Clear ();
217                         GlobalAttributes.Clear ();
218                         GlobalTypes.Clear ();
219                         // GlobalAttributeGroups.Clear ();
220                         // GlobalGroups.Clear ();
221                 }
222
223                 private void AddGlobalComponents (XmlSchema schema)
224                 {
225                         foreach (XmlSchemaElement el in schema.Elements.Values)
226                                 GlobalElements.Add (el.QualifiedName, el);
227                         foreach (XmlSchemaAttribute a in schema.Attributes.Values)
228                                 GlobalAttributes.Add (a.QualifiedName, a);
229                         foreach (XmlSchemaType t in schema.SchemaTypes.Values)
230                                 GlobalTypes.Add (t.QualifiedName, t);
231                 }
232
233                 public bool Contains (string targetNamespace)
234                 {
235                         targetNamespace = GetSafeNs (targetNamespace);
236                         foreach (XmlSchema schema in schemas)
237                                 if (GetSafeNs (schema.TargetNamespace) == targetNamespace)
238                                         return true;
239                         return false;
240                 }
241
242                 public bool Contains (XmlSchema targetNamespace)
243                 {
244                         foreach (XmlSchema schema in schemas)
245                                 if (schema == targetNamespace)
246                                         return true;
247                         return false;
248                 }
249
250                 public void CopyTo (XmlSchema [] array, int index)
251                 {
252                         schemas.CopyTo (array, index);
253                 }
254
255                 internal void CopyTo (Array array, int index)
256                 {
257                         schemas.CopyTo (array, index);
258                 }
259
260                 string GetSafeNs (string ns)
261                 {
262                         return ns == null ? "" : ns;
263                 }
264
265                 [MonoTODO]
266                 // FIXME: Check exact behavior
267                 public XmlSchema Remove (XmlSchema schema)
268                 {
269                         if (schema == null)
270                                 throw new ArgumentNullException ("schema");
271                         ArrayList al = new ArrayList ();
272                         al.AddRange (schemas);
273                         if (!al.Contains (schema))
274                                 return null;
275                         // FIXME: I have no idea why Remove() might throw
276                         // XmlSchemaException, except for the case it compiles.
277                         if (!schema.IsCompiled)
278                                 schema.CompileSubset (ValidationEventHandler, this, xmlResolver);
279                         schemas.Remove (schema);
280                         ResetCompile ();
281                         return schema;
282                 }
283
284                 void ResetCompile ()
285                 {
286                         isCompiled = false;
287                         ClearGlobalComponents ();
288                 }
289
290                 public bool RemoveRecursive (XmlSchema schema)
291                 {
292                         if (schema == null)
293                                 throw new ArgumentNullException ("schema");
294                         ArrayList al = new ArrayList ();
295                         al.AddRange (schemas);
296                         if (!al.Contains (schema))
297                                 return false;
298                         al.Remove (schema);
299                         schemas.Remove (schema);
300
301                         if (!IsCompiled)
302                                 return true;
303
304                         ClearGlobalComponents ();
305                         foreach (XmlSchema s in al) {
306                                 if (s.IsCompiled)
307                                         AddGlobalComponents (schema);
308                         }
309                         return true;
310                 }
311
312                 public XmlSchema Reprocess (XmlSchema schema)
313                 {
314                         if (schema == null)
315                                 throw new ArgumentNullException ("schema");
316                         ArrayList al = new ArrayList ();
317                         al.AddRange (schemas);
318                         if (!al.Contains (schema))
319                                 throw new ArgumentException ("Target schema is not contained in the schema set.");
320                         ClearGlobalComponents ();
321                         foreach (XmlSchema s in al) {
322                                 if (schema == s)
323                                         schema.CompileSubset (ValidationEventHandler, this, xmlResolver);
324                                 if (s.IsCompiled)
325                                         AddGlobalComponents (schema);
326                         }
327                         return schema.IsCompiled ? schema : null;
328                 }
329
330                 public ICollection Schemas ()
331                 {
332                         return schemas;
333                 }
334
335                 public ICollection Schemas (string targetNamespace)
336                 {
337                         targetNamespace = GetSafeNs (targetNamespace);
338                         ArrayList al = new ArrayList ();
339                         foreach (XmlSchema schema in schemas)
340                                 if (GetSafeNs (schema.TargetNamespace) == targetNamespace)
341                                         al.Add (schema);
342                         return al;
343                 }
344
345                 internal bool MissedSubComponents (string targetNamespace)
346                 {
347                         foreach (XmlSchema s in Schemas (targetNamespace))
348                                 if (s.missedSubComponents)
349                                         return true;
350                         return false;
351                 }
352         }
353 }