2006-02-20 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
58                 XmlSchemaCompilationSettings settings =
59                         new XmlSchemaCompilationSettings ();
60
61                 XmlSchemaCollection col;
62                 ValidationEventHandler handler;
63
64                 bool isCompiled;
65
66                 internal Guid CompilationId;
67
68                 public XmlSchemaSet ()
69                         : this (new NameTable ())
70                 {
71                         handler = new ValidationEventHandler (this.OnValidationError);
72                 }
73
74                 public XmlSchemaSet (XmlNameTable nameTable)
75                 {
76                         if (nameTable == null)
77                                 throw new ArgumentNullException ("nameTable");
78
79                         this.nameTable = nameTable;
80                         schemas = new ArrayList ();
81                         CompilationId = Guid.NewGuid ();
82                 }
83
84                 public event ValidationEventHandler ValidationEventHandler;
85
86                 public int Count {
87                         get { return schemas.Count; }
88                 }
89
90                 public XmlSchemaObjectTable GlobalAttributes {
91                         get {
92                                 if (attributes == null)
93                                         attributes = new XmlSchemaObjectTable ();
94                                 return attributes;
95                         }
96                 }
97
98                 public XmlSchemaObjectTable GlobalElements {
99                         get {
100                                 if (elements == null)
101                                         elements = new XmlSchemaObjectTable ();
102                                 return elements;
103                         }
104                 }
105
106                 public XmlSchemaObjectTable GlobalTypes { 
107                         get {
108                                 if (types == null)
109                                         types = new XmlSchemaObjectTable ();
110                                 return types;
111                         }
112                 }
113
114                 public bool IsCompiled { 
115                         get { return isCompiled; }
116                 }
117
118                 public XmlNameTable NameTable { 
119                         get { return nameTable; }
120                 }
121
122                 public XmlSchemaCompilationSettings CompilationSettings {
123                         get { return settings; }
124                         set { settings = value; }
125                 }
126
127                 // This is mainly used for event delegating
128                 internal XmlSchemaCollection SchemaCollection {
129                         get {
130                                 if (col == null) {
131                                         lock (this) {
132                                                 col = new XmlSchemaCollection ();
133                                                 foreach (XmlSchema s in schemas)
134                                                         col.Add (s);
135                                         }
136                                 }
137                                 return col;
138                         }
139                 }
140
141                 public XmlResolver XmlResolver {
142                         set { xmlResolver = value; }
143 #if NET_2_0
144                         internal get { return xmlResolver; }
145 #endif
146                 }
147
148                 public XmlSchema Add (string targetNamespace, string url)
149                 {
150                         targetNamespace = GetSafeNs (targetNamespace);
151                         XmlTextReader r = null;
152                         try {
153                                 r = new XmlTextReader (url, nameTable);
154                                 return Add (targetNamespace, r);
155                         } finally {
156                                 if (r != null)
157                                         r.Close ();
158                         }
159                 }
160
161                 [MonoTODO ("It has weird namespace duplication check that is different from Add(XmlSchema).")]
162                 public XmlSchema Add (string targetNamespace, XmlReader reader)
163                 {
164                         XmlSchema schema = XmlSchema.Read (reader, handler);
165                         if (targetNamespace != null
166                                 && targetNamespace.Length > 0)
167                                 schema.TargetNamespace = targetNamespace;
168                         Add (schema);
169                         return schema;
170                 }
171
172                 [MonoTODO ("Check the exact behavior when namespaces are in conflict (but it would be preferable to wait for 2.0 RTM).")]
173                 public void Add (XmlSchemaSet schemaSet)
174                 {
175                         ArrayList al = new ArrayList ();
176                         foreach (XmlSchema schema in schemaSet.schemas) {
177                                 if (!schemas.Contains (schema))
178                                         al.Add (schema);
179                         }
180                         foreach (XmlSchema schema in al)
181                                 Add (schema);
182                 }
183
184                 public XmlSchema Add (XmlSchema schema)
185                 {
186                         schemas.Add (schema);
187                         ResetCompile ();
188                         return schema;
189                 }
190
191                 [MonoTODO ("It should be the actual compilation engine.")]
192                 public void Compile ()
193                 {
194                         ClearGlobalComponents ();
195                         ArrayList al = new ArrayList ();
196                         al.AddRange (schemas);
197                         foreach (XmlSchema schema in al) {
198                                 if (!schema.IsCompiled)
199                                         schema.Compile (handler, this, xmlResolver);
200                                 AddGlobalComponents (schema);
201                         }
202                         isCompiled = true;
203                 }
204
205                 private void ClearGlobalComponents ()
206                 {
207                         GlobalElements.Clear ();
208                         GlobalAttributes.Clear ();
209                         GlobalTypes.Clear ();
210                         // GlobalAttributeGroups.Clear ();
211                         // GlobalGroups.Clear ();
212                 }
213
214                 private void AddGlobalComponents (XmlSchema schema)
215                 {
216                         foreach (XmlSchemaElement el in schema.Elements.Values)
217                                 GlobalElements.Add (el.QualifiedName, el);
218                         foreach (XmlSchemaAttribute a in schema.Attributes.Values)
219                                 GlobalAttributes.Add (a.QualifiedName, a);
220                         foreach (XmlSchemaType t in schema.SchemaTypes.Values)
221                                 GlobalTypes.Add (t.QualifiedName, t);
222                 }
223
224                 public bool Contains (string targetNamespace)
225                 {
226                         targetNamespace = GetSafeNs (targetNamespace);
227                         foreach (XmlSchema schema in schemas)
228                                 if (GetSafeNs (schema.TargetNamespace) == targetNamespace)
229                                         return true;
230                         return false;
231                 }
232
233                 public bool Contains (XmlSchema targetNamespace)
234                 {
235                         foreach (XmlSchema schema in schemas)
236                                 if (schema == targetNamespace)
237                                         return true;
238                         return false;
239                 }
240
241                 public void CopyTo (XmlSchema [] array, int index)
242                 {
243                         schemas.CopyTo (array, index);
244                 }
245
246                 internal void CopyTo (Array array, int index)
247                 {
248                         schemas.CopyTo (array, index);
249                 }
250
251                 string GetSafeNs (string ns)
252                 {
253                         return ns == null ? "" : ns;
254                 }
255
256                 internal void OnValidationError (object o, ValidationEventArgs e)
257                 {
258                         if (col != null)
259                                 col.OnValidationError (o, e);
260                         if (ValidationEventHandler != null)
261                                 ValidationEventHandler (o, e);
262                         else if (e.Severity == XmlSeverityType.Error)
263                                 throw e.Exception;
264                 }
265
266                 [MonoTODO ("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.Compile (handler, 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.Compile (handler, 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                 [MonoTODO]
336                 public ICollection Schemas (string targetNamespace)
337                 {
338                         targetNamespace = GetSafeNs (targetNamespace);
339                         ArrayList al = new ArrayList ();
340                         foreach (XmlSchema schema in schemas)
341                                 if (GetSafeNs (schema.TargetNamespace) == targetNamespace)
342                                         al.Add (schema);
343                         return al;
344                 }
345
346                 internal bool MissedSubComponents (string targetNamespace)
347                 {
348                         foreach (XmlSchema s in Schemas (targetNamespace))
349                                 if (s.missedSubComponents)
350                                         return true;
351                         return false;
352                 }
353         }
354 }