5 // Atsushi Enomoto <ginga@kit.hi-ho.ne.jp>
7 // (C)2003 Atsushi Enomoto
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:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
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.
32 using System.Collections;
33 using System.Collections.Generic;
34 using System.Collections.Specialized;
35 using System.ComponentModel;
37 using System.Security.Policy;
38 using System.Xml.Schema;
39 using System.Xml.XPath;
41 namespace System.Xml.Schema
44 public class XmlSchemaSet
46 internal sealed class XmlSchemaSet
49 XmlNameTable nameTable;
50 XmlResolver xmlResolver = new XmlUrlResolver ();
53 XmlSchemaObjectTable attributes;
54 XmlSchemaObjectTable elements;
55 XmlSchemaObjectTable types;
56 // XmlSchemaObjectTable attributeGroups;
57 // XmlSchemaObjectTable groups;
58 Hashtable idCollection;
59 XmlSchemaObjectTable namedIdentities;
61 XmlSchemaCompilationSettings settings =
62 new XmlSchemaCompilationSettings ();
66 internal Guid CompilationId { get; private set; }
68 public XmlSchemaSet ()
69 : this (new NameTable ())
73 public XmlSchemaSet (XmlNameTable nameTable)
75 if (nameTable == null)
76 throw new ArgumentNullException ("nameTable");
78 this.nameTable = nameTable;
79 schemas = new ArrayList ();
80 CompilationId = Guid.NewGuid ();
83 public event ValidationEventHandler ValidationEventHandler;
86 get { return schemas.Count; }
89 public XmlSchemaObjectTable GlobalAttributes {
91 if (attributes == null)
92 attributes = new XmlSchemaObjectTable ();
97 public XmlSchemaObjectTable GlobalElements {
100 elements = new XmlSchemaObjectTable ();
105 public XmlSchemaObjectTable GlobalTypes {
108 types = new XmlSchemaObjectTable ();
113 public bool IsCompiled {
114 get { return isCompiled; }
117 public XmlNameTable NameTable {
118 get { return nameTable; }
121 public XmlSchemaCompilationSettings CompilationSettings {
122 get { return settings; }
123 set { settings = value; }
126 public XmlResolver XmlResolver {
127 set { xmlResolver = value; }
129 internal get { return xmlResolver; }
131 get { return xmlResolver; }
135 internal Hashtable IDCollection {
137 if (idCollection == null)
138 idCollection = new Hashtable ();
143 internal XmlSchemaObjectTable NamedIdentities {
145 if (namedIdentities == null)
146 namedIdentities = new XmlSchemaObjectTable();
147 return namedIdentities;
151 public XmlSchema Add (string targetNamespace, string url)
153 XmlTextReader r = null;
155 r = new XmlTextReader (url, nameTable);
156 return Add (targetNamespace, r);
163 public XmlSchema Add (string targetNamespace, XmlReader reader)
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.");
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)
178 ArrayList al = new ArrayList ();
179 foreach (XmlSchema schema in schemaSet.schemas) {
180 if (!schemas.Contains (schema))
183 foreach (XmlSchema schema in al)
187 public XmlSchema Add (XmlSchema schema)
189 schemas.Add (schema);
194 // FIXME: It should be the actual compilation engine.
195 public void Compile ()
197 ClearGlobalComponents ();
198 ArrayList al = new ArrayList ();
199 al.AddRange (schemas);
200 IDCollection.Clear ();
201 NamedIdentities.Clear ();
203 var handledUris = new List<CompiledSchemaMemo> ();
204 foreach (XmlSchema schema in al)
205 if (!schema.IsCompiled)
206 schema.CompileSubset (ValidationEventHandler, this, xmlResolver, handledUris);
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 ();
217 foreach (XmlSchema schema in al)
218 schema.Validate (ValidationEventHandler);
220 foreach (XmlSchema schema in al)
221 AddGlobalComponents (schema);
226 private void ClearGlobalComponents ()
228 GlobalElements.Clear ();
229 GlobalAttributes.Clear ();
230 GlobalTypes.Clear ();
231 // GlobalAttributeGroups.Clear ();
232 // GlobalGroups.Clear ();
235 private void AddGlobalComponents (XmlSchema schema)
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);
245 public bool Contains (string targetNamespace)
247 targetNamespace = GetSafeNs (targetNamespace);
248 foreach (XmlSchema schema in schemas)
249 if (GetSafeNs (schema.TargetNamespace) == targetNamespace)
254 public bool Contains (XmlSchema targetNamespace)
256 foreach (XmlSchema schema in schemas)
257 if (schema == targetNamespace)
262 public void CopyTo (XmlSchema [] array, int index)
264 schemas.CopyTo (array, index);
267 internal void CopyTo (Array array, int index)
269 schemas.CopyTo (array, index);
272 string GetSafeNs (string ns)
274 return ns == null ? "" : ns;
278 // FIXME: Check exact behavior
279 public XmlSchema Remove (XmlSchema schema)
282 throw new ArgumentNullException ("schema");
283 ArrayList al = new ArrayList ();
284 al.AddRange (schemas);
285 if (!al.Contains (schema))
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);
299 ClearGlobalComponents ();
302 public bool RemoveRecursive (XmlSchema schema)
305 throw new ArgumentNullException ("schema");
306 ArrayList al = new ArrayList ();
307 al.AddRange (schemas);
308 if (!al.Contains (schema))
311 schemas.Remove (schema);
316 ClearGlobalComponents ();
317 foreach (XmlSchema s in al) {
319 AddGlobalComponents (schema);
324 public XmlSchema Reprocess (XmlSchema schema)
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) {
335 schema.CompileSubset (ValidationEventHandler, this, xmlResolver);
337 AddGlobalComponents (schema);
339 return schema.IsCompiled ? schema : null;
342 public ICollection Schemas ()
347 public ICollection Schemas (string targetNamespace)
349 targetNamespace = GetSafeNs (targetNamespace);
350 ArrayList al = new ArrayList ();
351 foreach (XmlSchema schema in schemas)
352 if (GetSafeNs (schema.TargetNamespace) == targetNamespace)
357 internal bool MissedSubComponents (string targetNamespace)
359 foreach (XmlSchema s in Schemas (targetNamespace))
360 if (s.missedSubComponents)