Updates referencesource to .NET 4.7
[mono-project.git] / mcs / class / referencesource / System.Xml / System / Xml / Schema / XmlSchemaSet.cs
blob978f3679308377e35346220ee5ad5826da003396
1 //------------------------------------------------------------------------------
2 // <copyright file="XmlSchemaSet.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
4 // </copyright>
5 // <owner current="true" primary="true">Microsoft</owner>
6 //------------------------------------------------------------------------------
7 using System.Diagnostics;
8 using System.Collections;
9 using System.Threading;
10 using System.Collections.Generic;
11 using System.Runtime.Versioning;
13 namespace System.Xml.Schema {
14 #if SILVERLIGHT
15 public class XmlSchemaSet
17 //Empty XmlSchemaSet class to enable backward compatibility of XmlSchemaProvideAttribute
18 //Add private ctor to prevent constructing of this class
19 XmlSchemaSet() { }
21 #else
22 /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet"]/*' />
23 /// <devdoc>
24 /// <para>The XmlSchemaSet contains a set of namespace URI's.
25 /// Each namespace also have an associated private data cache
26 /// corresponding to the XML-Data Schema or W3C XML Schema.
27 /// The XmlSchemaSet will able to load only XSD schemas,
28 /// and compile them into an internal "cooked schema representation".
29 /// The Validate method then uses this internal representation for
30 /// efficient runtime validation of any given subtree.</para>
31 /// </devdoc>
32 public class XmlSchemaSet {
33 XmlNameTable nameTable;
34 SchemaNames schemaNames;
35 SortedList schemas; // List of source schemas
37 //Event handling
38 ValidationEventHandler internalEventHandler;
39 ValidationEventHandler eventHandler;
41 bool isCompiled = false;
43 //Dictionary<Uri, XmlSchema> schemaLocations;
44 //Dictionary<ChameleonKey, XmlSchema> chameleonSchemas;
45 Hashtable schemaLocations;
46 Hashtable chameleonSchemas;
48 Hashtable targetNamespaces;
49 bool compileAll;
51 //Cached Compiled Info
52 SchemaInfo cachedCompiledInfo;
54 //Reader settings to parse schema
55 XmlReaderSettings readerSettings;
56 XmlSchema schemaForSchema; //Only one schema for schema per set
58 //Schema compilation settings
59 XmlSchemaCompilationSettings compilationSettings;
61 internal XmlSchemaObjectTable elements;
62 internal XmlSchemaObjectTable attributes;
63 internal XmlSchemaObjectTable schemaTypes;
64 internal XmlSchemaObjectTable substitutionGroups;
65 private XmlSchemaObjectTable typeExtensions;
67 //Thread safety
68 private Object internalSyncObject;
69 internal Object InternalSyncObject {
70 get {
71 if (internalSyncObject == null) {
72 Object o = new Object();
73 Interlocked.CompareExchange<Object>(ref internalSyncObject, o, null);
75 return internalSyncObject;
79 //Constructors
81 /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.XmlSchemaSet"]/*' />
82 /// <devdoc>
83 /// <para>Construct a new empty schema schemas.</para>
84 /// </devdoc>
85 public XmlSchemaSet() : this(new NameTable()) {
88 /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.XmlSchemaSet1"]/*' />
89 /// <devdoc>
90 /// <para>Construct a new empty schema schemas with associated XmlNameTable.
91 /// The XmlNameTable is used when loading schemas</para>
92 /// </devdoc>
93 public XmlSchemaSet(XmlNameTable nameTable) {
94 if (nameTable == null) {
95 throw new ArgumentNullException("nameTable");
97 this.nameTable = nameTable;
98 schemas = new SortedList();
100 /*schemaLocations = new Dictionary<Uri, XmlSchema>();
101 chameleonSchemas = new Dictionary<ChameleonKey, XmlSchema>();*/
102 schemaLocations = new Hashtable();
103 chameleonSchemas = new Hashtable();
104 targetNamespaces = new Hashtable();
105 internalEventHandler = new ValidationEventHandler(InternalValidationCallback);
106 eventHandler = internalEventHandler;
108 readerSettings = new XmlReaderSettings();
110 // we don't have to check XmlReaderSettings.EnableLegacyXmlSettings() here because the following
111 // code will return same result either we are running on v4.5 or later
112 if (readerSettings.GetXmlResolver() == null)
114 // The created resolver will be used in the schema validation only
115 readerSettings.XmlResolver = new XmlUrlResolver();
116 readerSettings.IsXmlResolverSet = false;
119 readerSettings.NameTable = nameTable;
120 readerSettings.DtdProcessing = DtdProcessing.Prohibit;
122 compilationSettings = new XmlSchemaCompilationSettings();
123 cachedCompiledInfo = new SchemaInfo();
124 compileAll = true;
128 //Public Properties
129 /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.NameTable"]/*' />
130 /// <devdoc>
131 /// <para>The default XmlNameTable used by the XmlSchemaSet when loading new schemas.</para>
132 /// </devdoc>
133 public XmlNameTable NameTable {
134 get { return nameTable;}
137 /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.ValidationEventHandler"]/*' />
138 public event ValidationEventHandler ValidationEventHandler {
139 add {
140 eventHandler -= internalEventHandler;
141 eventHandler += value;
142 if (eventHandler == null) {
143 eventHandler = internalEventHandler;
146 remove {
147 eventHandler -= value;
148 if (eventHandler == null) {
149 eventHandler = internalEventHandler;
154 /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.IsCompiled"]/*' />
155 /// <devdoc>
156 /// <para>IsCompiled is true when the schema set is in compiled state</para>
157 /// </devdoc>
158 public bool IsCompiled {
159 get {
160 return isCompiled;
164 /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.XmlResolver"]/*' />
165 /// <devdoc>
166 /// <para></para>
167 /// </devdoc>
168 public XmlResolver XmlResolver {
169 set {
170 readerSettings.XmlResolver = value;
174 /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.CompilationSettings"]/*' />
175 /// <devdoc>
176 /// <para></para>
177 /// </devdoc>
178 public XmlSchemaCompilationSettings CompilationSettings {
179 get {
180 return compilationSettings;
182 set {
183 compilationSettings = value;
187 /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Count"]/*' />
188 /// <devdoc>
189 /// <para>Returns the count of schemas in the set</para>
190 /// </devdoc>
191 public int Count {
192 get {
193 return schemas.Count;
196 /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.GlobalElements"]/*' />
197 /// <devdoc>
198 /// <para></para>
199 /// </devdoc>
200 public XmlSchemaObjectTable GlobalElements {
201 get {
202 if (elements == null) {
203 elements = new XmlSchemaObjectTable();
205 return elements;
209 /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.GlobalAttributes"]/*' />
210 /// <devdoc>
211 /// <para></para>
212 /// </devdoc>
213 public XmlSchemaObjectTable GlobalAttributes {
214 get {
215 if (attributes == null) {
216 attributes = new XmlSchemaObjectTable();
218 return attributes;
222 /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.GlobalTypes"]/*' />
223 /// <devdoc>
224 /// <para></para>
225 /// </devdoc>
226 public XmlSchemaObjectTable GlobalTypes {
227 get {
228 if (schemaTypes == null) {
229 schemaTypes = new XmlSchemaObjectTable();
231 return schemaTypes;
235 /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.SubstitutionGroups"]/*' />
236 /// <devdoc>
237 /// <para></para>
238 /// </devdoc>
239 ///
240 internal XmlSchemaObjectTable SubstitutionGroups {
241 get {
242 if (substitutionGroups == null) {
243 substitutionGroups = new XmlSchemaObjectTable();
245 return substitutionGroups;
249 /// <summary>
250 /// Table of all types extensions
251 /// </summary>
252 internal Hashtable SchemaLocations {
253 get {
254 return schemaLocations;
258 /// <summary>
259 /// Table of all types extensions
260 /// </summary>
261 internal XmlSchemaObjectTable TypeExtensions {
262 get {
263 if (typeExtensions == null) {
264 typeExtensions = new XmlSchemaObjectTable();
266 return typeExtensions;
269 //Public Methods
271 /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Add1"]/*' />
272 /// <devdoc>
273 /// <para>Add the schema located by the given URL into the schema schemas.
274 /// If the given schema references other namespaces, the schemas for those other
275 /// namespaces are NOT automatically loaded.</para>
276 /// </devdoc>
277 [ResourceConsumption(ResourceScope.Machine)]
278 [ResourceExposure(ResourceScope.Machine)]
279 public XmlSchema Add(String targetNamespace, String schemaUri) {
280 if (schemaUri == null || schemaUri.Length == 0) {
281 throw new ArgumentNullException("schemaUri");
283 if (targetNamespace != null) {
284 targetNamespace = XmlComplianceUtil.CDataNormalize(targetNamespace);
286 XmlSchema schema = null;
287 lock (InternalSyncObject) {
288 //Check if schema from url has already been added
289 XmlResolver tempResolver = readerSettings.GetXmlResolver();
290 if ( tempResolver == null ) {
291 tempResolver = new XmlUrlResolver();
293 Uri tempSchemaUri = tempResolver.ResolveUri(null, schemaUri);
294 if (IsSchemaLoaded(tempSchemaUri, targetNamespace, out schema)) {
295 return schema;
297 else {
298 //Url already not processed; Load SOM from url
299 XmlReader reader = XmlReader.Create(schemaUri, readerSettings);
300 try {
301 schema = Add(targetNamespace, ParseSchema(targetNamespace, reader)); //
302 while(reader.Read());// wellformness check;
304 finally {
305 reader.Close();
309 return schema;
313 /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Add4"]/*' />
314 /// <devdoc>
315 /// <para>Add the given schema into the schema schemas.
316 /// If the given schema references other namespaces, the schemas for those
317 /// other namespaces are NOT automatically loaded.</para>
318 /// </devdoc>
319 public XmlSchema Add(String targetNamespace, XmlReader schemaDocument) {
320 if (schemaDocument == null) {
321 throw new ArgumentNullException("schemaDocument");
323 if (targetNamespace != null) {
324 targetNamespace = XmlComplianceUtil.CDataNormalize(targetNamespace);
326 lock (InternalSyncObject) {
327 XmlSchema schema = null;
328 Uri schemaUri = new Uri(schemaDocument.BaseURI, UriKind.RelativeOrAbsolute);
329 if (IsSchemaLoaded(schemaUri, targetNamespace, out schema)) {
330 return schema;
332 else {
333 DtdProcessing dtdProcessing = this.readerSettings.DtdProcessing;
334 SetDtdProcessing(schemaDocument);
335 schema = Add(targetNamespace, ParseSchema(targetNamespace, schemaDocument));
336 this.readerSettings.DtdProcessing = dtdProcessing; //reset dtdProcessing setting
337 return schema;
343 /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Add5"]/*' />
344 /// <devdoc>
345 /// <para>Adds all the namespaces defined in the given schemas
346 /// (including their associated schemas) to this schemas.</para>
347 /// </devdoc>
348 public void Add(XmlSchemaSet schemas) {
349 if (schemas == null) {
350 throw new ArgumentNullException("schemas");
352 if (this == schemas) {
353 return;
355 bool thisLockObtained = false;
356 bool schemasLockObtained = false;
357 try {
358 while(true) {
359 Monitor.TryEnter(InternalSyncObject, ref thisLockObtained);
360 if (thisLockObtained) {
361 Monitor.TryEnter(schemas.InternalSyncObject, ref schemasLockObtained);
362 if (schemasLockObtained) {
363 break;
365 else {
366 Monitor.Exit(InternalSyncObject); //Give up this lock and try both again
367 thisLockObtained = false;
368 Thread.Yield(); //Let the thread that holds the lock run
369 continue;
374 XmlSchema currentSchema;
376 if (schemas.IsCompiled) {
377 CopyFromCompiledSet(schemas);
379 else {
380 bool remove = false;
381 string tns = null;
382 foreach(XmlSchema schema in schemas.SortedSchemas.Values) {
383 tns = schema.TargetNamespace;
384 if (tns == null) {
385 tns = string.Empty;
387 if (this.schemas.ContainsKey(schema.SchemaId) || FindSchemaByNSAndUrl(schema.BaseUri, tns, null) != null) { //Do not already existing url
388 continue;
390 currentSchema = Add(schema.TargetNamespace, schema);
391 if(currentSchema == null) {
392 remove = true;
393 break;
396 //Remove all from the set if even one schema in the passed in set is not preprocessed.
397 if (remove) {
398 foreach(XmlSchema schema in schemas.SortedSchemas.Values) { //Remove all previously added schemas from the set
399 this.schemas.Remove(schema.SchemaId); //Might remove schema that was already there and was not added thru this operation
400 schemaLocations.Remove(schema.BaseUri);
405 finally { //release locks on sets
406 if (thisLockObtained) {
407 Monitor.Exit(InternalSyncObject);
409 if (schemasLockObtained) {
410 Monitor.Exit(schemas.InternalSyncObject);
415 /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Add6"]/*' />
416 public XmlSchema Add(XmlSchema schema) {
417 if (schema == null) {
418 throw new ArgumentNullException("schema");
420 lock (InternalSyncObject) {
421 if (schemas.ContainsKey(schema.SchemaId)) {
422 return schema;
424 return Add(schema.TargetNamespace, schema);
428 /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Remove"]/*' />
429 public XmlSchema Remove(XmlSchema schema) {
430 return Remove(schema, true);
433 /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.RemoveRecursive"]/*' />
434 public bool RemoveRecursive(XmlSchema schemaToRemove) {
436 if (schemaToRemove == null) {
437 throw new ArgumentNullException("schemaToRemove");
439 if (!schemas.ContainsKey(schemaToRemove.SchemaId)) {
440 return false;
443 lock (InternalSyncObject) { //Need to lock here so that remove cannot be called while the set is being compiled
444 if (schemas.ContainsKey(schemaToRemove.SchemaId)) { //Need to check again
446 //Build disallowedNamespaces list
447 Hashtable disallowedNamespaces = new Hashtable();
448 disallowedNamespaces.Add(GetTargetNamespace(schemaToRemove), schemaToRemove);
449 string importedNS;
450 for (int i = 0; i < schemaToRemove.ImportedNamespaces.Count; i++) {
451 importedNS = (string)schemaToRemove.ImportedNamespaces[i];
452 if (disallowedNamespaces[importedNS] == null) {
453 disallowedNamespaces.Add(importedNS, importedNS);
457 //Removal list is all schemas imported by this schema directly or indirectly
458 //Need to check if other schemas in the set import schemaToRemove / any of its imports
459 ArrayList needToCheckSchemaList = new ArrayList();
460 XmlSchema mainSchema;
461 for (int i =0; i < schemas.Count; i++) {
462 mainSchema = (XmlSchema)schemas.GetByIndex(i);
463 if (mainSchema == schemaToRemove ||
464 schemaToRemove.ImportedSchemas.Contains(mainSchema)) {
465 continue;
467 needToCheckSchemaList.Add(mainSchema);
470 mainSchema = null;
471 for (int i = 0; i < needToCheckSchemaList.Count; i++) { //Perf: Not using nested foreach here
472 mainSchema = (XmlSchema)needToCheckSchemaList[i];
474 if (mainSchema.ImportedNamespaces.Count > 0) {
475 foreach(string tns in disallowedNamespaces.Keys) {
476 if (mainSchema.ImportedNamespaces.Contains(tns)) {
477 SendValidationEvent(new XmlSchemaException(Res.Sch_SchemaNotRemoved, string.Empty), XmlSeverityType.Warning);
478 return false;
484 Remove(schemaToRemove, true);
485 for (int i = 0; i < schemaToRemove.ImportedSchemas.Count; ++i) {
486 XmlSchema impSchema = (XmlSchema)schemaToRemove.ImportedSchemas[i];
487 Remove(impSchema, true);
489 return true;
492 return false;
495 /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Contains1"]/*' />
496 public bool Contains(String targetNamespace) {
497 if (targetNamespace == null) {
498 targetNamespace = string.Empty;
500 return targetNamespaces[targetNamespace] != null;
503 /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Contains2"]/*' />
504 public bool Contains(XmlSchema schema) {
505 if (schema == null) {
506 throw new ArgumentNullException("schema");
508 return schemas.ContainsValue(schema);
511 /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Compile"]/*' />
512 /// <devdoc>
513 /// <para>[To be supplied.]</para>
514 /// </devdoc>
515 public void Compile() {
516 if (isCompiled) {
517 return;
519 if (schemas.Count == 0) {
520 ClearTables(); //Clear any previously present compiled state left by calling just Remove() on the set
521 cachedCompiledInfo = new SchemaInfo();
522 isCompiled = true;
523 compileAll = false;
524 return;
526 lock (InternalSyncObject) {
528 if (!isCompiled) { //Locking before checking isCompiled to avoid problems with double locking
529 Compiler compiler = new Compiler(nameTable, eventHandler, schemaForSchema, compilationSettings);
530 SchemaInfo newCompiledInfo = new SchemaInfo();
531 int schemaIndex = 0;
532 if (!compileAll) { //if we are not compiling everything again, Move the pre-compiled schemas to the compiler's tables
533 compiler.ImportAllCompiledSchemas(this);
535 try { //First thing to do in the try block is to acquire locks since finally will try to release them.
536 //If we dont accuire the locks first, and an exception occurs in the code before the locking code, then Threading.SynchronizationLockException will be thrown
537 //when attempting to release it in the finally block
538 XmlSchema currentSchema;
539 XmlSchema xmlNSSchema = Preprocessor.GetBuildInSchema();
540 for (schemaIndex = 0; schemaIndex < schemas.Count; schemaIndex++) {
541 currentSchema = (XmlSchema)schemas.GetByIndex(schemaIndex);
543 //Lock schema to be compiled
544 #pragma warning disable 0618
546 Monitor.Enter(currentSchema);
547 #pragma warning restore 0618
548 if (!currentSchema.IsPreprocessed)
550 SendValidationEvent(new XmlSchemaException(Res.Sch_SchemaNotPreprocessed, string.Empty), XmlSeverityType.Error);
551 isCompiled = false;
552 return;
554 if (currentSchema.IsCompiledBySet) {
555 if (!compileAll) {
556 continue;
558 else if ((object)currentSchema == (object)xmlNSSchema) { // prepare for xml namespace schema without cleanup
559 compiler.Prepare(currentSchema, false);
560 continue;
563 compiler.Prepare(currentSchema, true);
566 isCompiled = compiler.Execute(this, newCompiledInfo);
567 if (isCompiled) {
568 if (!compileAll) {
569 newCompiledInfo.Add(cachedCompiledInfo, eventHandler); //Add all the items from the old to the new compiled object
571 compileAll = false;
572 cachedCompiledInfo = newCompiledInfo; //Replace the compiled info in the set after successful compilation
575 finally {
576 //Release locks on all schemas
577 XmlSchema currentSchema;
578 if (schemaIndex == schemas.Count) {
579 schemaIndex--;
581 for (int i = schemaIndex; i >= 0; i--) {
582 currentSchema = (XmlSchema)schemas.GetByIndex(i);
583 if (currentSchema == Preprocessor.GetBuildInSchema()) { //dont re-set compiled flags for xml namespace schema
584 Monitor.Exit(currentSchema);
585 continue;
587 currentSchema.IsCompiledBySet = isCompiled;
588 Monitor.Exit(currentSchema);
593 return;
596 /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Reprocess"]/*' />
597 /// <devdoc>
598 /// <para>[To be supplied.]</para>
599 /// </devdoc>
600 public XmlSchema Reprocess(XmlSchema schema) {
601 // Due to bug 644477 - this method is tightly coupled (THE CODE IS BASICALLY COPIED) to Remove, Add and AddSchemaToSet
602 // methods. If you change anything here *make sure* to update Remove/Add/AddSchemaToSet method(s) accordingly.
603 // The only difference is that we don't touch .schemas collection here to not break a code like this:
604 // foreach(XmlSchema s in schemaset.schemas) { schemaset.Reprocess(s); }
605 // This is by purpose.
606 if (schema == null) {
607 throw new ArgumentNullException("schema");
609 if (!schemas.ContainsKey(schema.SchemaId)) {
610 throw new ArgumentException(Res.GetString(Res.Sch_SchemaDoesNotExist), "schema");
612 XmlSchema originalSchema = schema;
613 lock (InternalSyncObject) { //Lock set so that set cannot be compiled in another thread
615 // This code is copied from method:
616 // Remove(XmlSchema schema, bool forceCompile)
617 // If you changed anything here go and change the same in Remove(XmlSchema schema, bool forceCompile) method
618 #region Copied from Remove(XmlSchema schema, bool forceCompile)
620 RemoveSchemaFromGlobalTables(schema);
621 RemoveSchemaFromCaches(schema);
622 if (schema.BaseUri != null) {
623 schemaLocations.Remove(schema.BaseUri);
625 string tns = GetTargetNamespace(schema);
626 if (Schemas(tns).Count == 0) { //This is the only schema for that namespace
627 targetNamespaces.Remove(tns);
629 isCompiled = false;
630 compileAll = true; //Force compilation of the whole set; This is when the set is not completely thread-safe
632 #endregion //Copied from Remove(XmlSchema schema, bool forceCompile)
635 // This code is copied from method:
636 // Add(string targetNamespace, XmlSchema schema)
637 // If you changed anything here go and change the same in Add(string targetNamespace, XmlSchema schema) method
638 #region Copied from Add(string targetNamespace, XmlSchema schema)
640 if (schema.ErrorCount != 0) { //Schema with parsing errors cannot be loaded
641 return originalSchema;
643 if (PreprocessSchema(ref schema, schema.TargetNamespace)) { //No perf opt for already compiled schemas
645 // This code is copied from method:
646 // AddSchemaToSet(XmlSchema schema)
647 // If you changed anything here go and change the same in AddSchemaToSet(XmlSchema schema) method
648 #region Copied from AddSchemaToSet(XmlSchema schema)
650 //Add to targetNamespaces table
651 if (targetNamespaces[tns] == null) {
652 targetNamespaces.Add(tns, tns);
654 if (schemaForSchema == null && tns == XmlReservedNs.NsXs && schema.SchemaTypes[DatatypeImplementation.QnAnyType] != null) { //it has xs:anyType
655 schemaForSchema = schema;
657 for (int i = 0; i < schema.ImportedSchemas.Count; ++i) { //Once preprocessed external schemas property is set
658 XmlSchema s = (XmlSchema)schema.ImportedSchemas[i];
659 if (!schemas.ContainsKey(s.SchemaId)) {
660 schemas.Add(s.SchemaId, s);
662 tns = GetTargetNamespace(s);
663 if (targetNamespaces[tns] == null) {
664 targetNamespaces.Add(tns, tns);
666 if (schemaForSchema == null && tns == XmlReservedNs.NsXs && schema.SchemaTypes[DatatypeImplementation.QnAnyType] != null) { //it has xs:anyType
667 schemaForSchema = schema;
670 #endregion //Copied from AddSchemaToSet(XmlSchema schema)
671 return schema;
673 #endregion // Copied from Add(string targetNamespace, XmlSchema schema)
675 return originalSchema;
679 /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.CopyTo"]/*' />
680 /// <devdoc>
681 /// <para>[To be supplied.]</para>
682 /// </devdoc>
683 public void CopyTo(XmlSchema[] schemas, int index) {
684 if (schemas == null)
685 throw new ArgumentNullException("schemas");
686 if (index < 0 || index > schemas.Length -1 )
687 throw new ArgumentOutOfRangeException("index");
688 this.schemas.Values.CopyTo(schemas, index);
691 /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Schemas1"]/*' />
692 /// <devdoc>
693 /// <para>[To be supplied.]</para>
694 /// </devdoc>
695 public ICollection Schemas() {
696 return schemas.Values;
699 /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Schemas1"]/*' />
700 /// <devdoc>
701 /// <para>[To be supplied.]</para>
702 /// </devdoc>
703 public ICollection Schemas(String targetNamespace) {
704 ArrayList tnsSchemas = new ArrayList();
705 XmlSchema currentSchema;
706 if (targetNamespace == null) {
707 targetNamespace = string.Empty;
709 for (int i=0; i < schemas.Count; i++) {
710 currentSchema = (XmlSchema)schemas.GetByIndex(i);
711 if (GetTargetNamespace(currentSchema) == targetNamespace) {
712 tnsSchemas.Add(currentSchema);
715 return tnsSchemas;
718 //Internal Methods
720 private XmlSchema Add(string targetNamespace, XmlSchema schema) {
721 // Due to bug 644477 - this method is tightly coupled (THE CODE IS BASICALLY COPIED) to Reprocess
722 // method. If you change anything here *make sure* to update Reprocess method accordingly.
724 if (schema == null || schema.ErrorCount != 0) { //Schema with parsing errors cannot be loaded
725 return null;
728 // This code is copied to method:
729 // Reprocess(XmlSchema schema)
730 // If you changed anything here go and change the same in Reprocess(XmlSchema schema) method
731 if (PreprocessSchema(ref schema, targetNamespace)) { //No perf opt for already compiled schemas
732 AddSchemaToSet(schema);
733 isCompiled = false;
734 return schema;
736 return null;
739 #if TRUST_COMPILE_STATE
740 private void AddCompiledSchema(XmlSchema schema) {
741 if (schema.IsCompiledBySet ) { //trust compiled state always if it is not a chameleon schema
742 VerifyTables();
743 SchemaInfo newCompiledInfo = new SchemaInfo();
744 XmlSchemaObjectTable substitutionGroupsTable = null;
745 if (!AddToCompiledInfo(schema, newCompiledInfo, ref substitutionGroupsTable)) { //Error while adding main schema
746 return null;
748 foreach (XmlSchema impSchema in schema.ImportedSchemas) {
749 if (!AddToCompiledInfo(impSchema, newCompiledInfo, ref substitutionGroupsTable)) { //Error while adding imports
750 return null;
753 newCompiledInfo.Add(cachedCompiledInfo, eventHandler); //Add existing compiled info
754 cachedCompiledInfo = newCompiledInfo;
755 if (substitutionGroupsTable != null) {
756 ProcessNewSubstitutionGroups(substitutionGroupsTable, true);
758 if (schemas.Count == 0) { //If its the first compiled schema being added, then set doesnt need to be compiled
759 isCompiled = true;
760 compileAll = false;
762 AddSchemaToSet(schema);
763 return schema;
767 private bool AddToCompiledInfo(XmlSchema schema, SchemaInfo newCompiledInfo, ref XmlSchemaObjectTable substTable) {
768 //Add schema's compiled tables to the set
769 if (schema.BaseUri != null && schemaLocations[schema.BaseUri] == null) { //Update schemaLocations table
770 schemaLocations.Add(schema.BaseUri, schema);
773 foreach (XmlSchemaElement element in schema.Elements.Values) {
774 if(!AddToTable(elements, element.QualifiedName, element)) {
775 RemoveSchemaFromGlobalTables(schema);
776 return false;
778 XmlQualifiedName head = element.SubstitutionGroup;
779 if (!head.IsEmpty) {
780 if (substTable == null) {
781 substTable = new XmlSchemaObjectTable();
783 XmlSchemaSubstitutionGroup substitutionGroup = (XmlSchemaSubstitutionGroup)substTable[head];
784 if (substitutionGroup == null) {
785 substitutionGroup = new XmlSchemaSubstitutionGroup();
786 substitutionGroup.Examplar = head;
787 substTable.Add(head, substitutionGroup);
789 ArrayList members = substitutionGroup.Members;
790 if (!members.Contains(element)) { //Members might contain element if the same schema is included and imported through different paths. Imp, hence will be added to set directly
791 members.Add(element);
795 foreach (XmlSchemaAttribute attribute in schema.Attributes.Values) {
796 if (!AddToTable(attributes, attribute.QualifiedName, attribute)) {
797 RemoveSchemaFromGlobalTables(schema);
798 return false;
801 foreach (XmlSchemaType schemaType in schema.SchemaTypes.Values) {
802 if (!AddToTable(schemaTypes, schemaType.QualifiedName, schemaType)) {
803 RemoveSchemaFromGlobalTables(schema);
804 return false;
807 schema.AddCompiledInfo(newCompiledInfo);
809 return true;
811 #endif
813 //For use by the validator when loading schemaLocations in the instance
814 internal void Add(String targetNamespace, XmlReader reader, Hashtable validatedNamespaces) {
815 if (reader == null) {
816 throw new ArgumentNullException("reader");
818 if (targetNamespace == null) {
819 targetNamespace = string.Empty;
821 if (validatedNamespaces[targetNamespace] != null) {
822 if (FindSchemaByNSAndUrl(new Uri(reader.BaseURI, UriKind.RelativeOrAbsolute), targetNamespace, null) != null) {
823 return;
825 else {
826 throw new XmlSchemaException(Res.Sch_ComponentAlreadySeenForNS, targetNamespace);
830 //Not locking set as this will not be accessible outside the validator
831 XmlSchema schema;
832 if (IsSchemaLoaded(new Uri(reader.BaseURI, UriKind.RelativeOrAbsolute), targetNamespace, out schema)) {
833 return;
835 else { //top-level schema not present for same url
836 schema = ParseSchema(targetNamespace, reader);
838 //Store the previous locations
839 DictionaryEntry[] oldLocations = new DictionaryEntry[schemaLocations.Count];
840 schemaLocations.CopyTo(oldLocations, 0);
842 //Add to set
843 Add(targetNamespace, schema);
844 if (schema.ImportedSchemas.Count > 0) { //Check imports
845 string tns;
846 for (int i = 0; i < schema.ImportedSchemas.Count; ++i) {
847 XmlSchema impSchema = (XmlSchema)schema.ImportedSchemas[i];
848 tns = impSchema.TargetNamespace;
849 if (tns == null) {
850 tns = string.Empty;
852 if (validatedNamespaces[tns] != null && (FindSchemaByNSAndUrl(impSchema.BaseUri, tns, oldLocations) == null) ) {
853 RemoveRecursive(schema);
854 throw new XmlSchemaException(Res.Sch_ComponentAlreadySeenForNS, tns);
861 internal XmlSchema FindSchemaByNSAndUrl(Uri schemaUri, string ns, DictionaryEntry[] locationsTable) {
862 if (schemaUri == null || schemaUri.OriginalString.Length == 0) {
863 return null;
865 XmlSchema schema = null;
866 if (locationsTable == null) {
867 schema = (XmlSchema)schemaLocations[schemaUri];
869 else {
870 for (int i = 0; i < locationsTable.Length; i++) {
871 if (schemaUri.Equals(locationsTable[i].Key)) {
872 schema = (XmlSchema)locationsTable[i].Value;
873 break;
877 if (schema != null) {
878 Debug.Assert(ns != null);
879 string tns = schema.TargetNamespace == null ? string.Empty : schema.TargetNamespace;
880 if (tns == ns) {
881 return schema;
883 else if (tns == string.Empty) { //There could be a chameleon for same ns
884 // It is OK to pass in the schema we have found so far, since it must have the schemaUri we're looking for
885 // (we found it that way above) and it must be the original chameleon schema (the one without target ns)
886 // as we don't add the chameleon copies into the locations tables above.
887 Debug.Assert(schema.BaseUri.Equals(schemaUri));
888 ChameleonKey cKey = new ChameleonKey(ns, schema);
889 schema = (XmlSchema)chameleonSchemas[cKey]; //Need not clone if a schema for that namespace already exists
891 else {
892 schema = null;
895 return schema;
898 private void SetDtdProcessing(XmlReader reader) {
899 if (reader.Settings != null) {
900 this.readerSettings.DtdProcessing = reader.Settings.DtdProcessing;
902 else {
903 XmlTextReader v1Reader = reader as XmlTextReader;
904 if (v1Reader != null) {
905 this.readerSettings.DtdProcessing = v1Reader.DtdProcessing;
910 private void AddSchemaToSet(XmlSchema schema) {
911 // Due to bug 644477 - this method is tightly coupled (THE CODE IS BASICALLY COPIED) to Reprocess
912 // method. If you change anything here *make sure* to update Reprocess method accordingly.
914 schemas.Add(schema.SchemaId, schema);
915 //Add to targetNamespaces table
917 // This code is copied to method:
918 // Reprocess(XmlSchema schema)
919 // If you changed anything here go and change the same in Reprocess(XmlSchema schema) method
920 #region This code is copied to Reprocess(XmlSchema schema) method
922 string tns = GetTargetNamespace(schema);
923 if (targetNamespaces[tns] == null) {
924 targetNamespaces.Add(tns, tns);
926 if (schemaForSchema == null && tns == XmlReservedNs.NsXs && schema.SchemaTypes[DatatypeImplementation.QnAnyType] != null) { //it has xs:anyType
927 schemaForSchema = schema;
929 for (int i = 0; i < schema.ImportedSchemas.Count; ++i) { //Once preprocessed external schemas property is set
930 XmlSchema s = (XmlSchema)schema.ImportedSchemas[i];
931 if (!schemas.ContainsKey(s.SchemaId)) {
932 schemas.Add(s.SchemaId, s);
934 tns = GetTargetNamespace(s);
935 if (targetNamespaces[tns] == null) {
936 targetNamespaces.Add(tns, tns);
938 if (schemaForSchema == null && tns == XmlReservedNs.NsXs && schema.SchemaTypes[DatatypeImplementation.QnAnyType] != null) { //it has xs:anyType
939 schemaForSchema = schema;
943 #endregion // This code is copied to Reprocess(XmlSchema schema) method
946 private void ProcessNewSubstitutionGroups(XmlSchemaObjectTable substitutionGroupsTable, bool resolve) {
947 foreach(XmlSchemaSubstitutionGroup substGroup in substitutionGroupsTable.Values) {
948 if (resolve) { //Resolve substitutionGroups within this schema
949 ResolveSubstitutionGroup(substGroup, substitutionGroupsTable);
952 //Add or Merge new substitutionGroups with those that already exist in the set
953 XmlQualifiedName head = substGroup.Examplar;
954 XmlSchemaSubstitutionGroup oldSubstGroup = (XmlSchemaSubstitutionGroup)substitutionGroups[head];
955 if (oldSubstGroup != null) {
956 for (int i = 0; i < substGroup.Members.Count; ++i) {
957 if (!oldSubstGroup.Members.Contains(substGroup.Members[i])) {
958 oldSubstGroup.Members.Add(substGroup.Members[i]);
962 else {
963 AddToTable(substitutionGroups, head, substGroup);
968 private void ResolveSubstitutionGroup(XmlSchemaSubstitutionGroup substitutionGroup, XmlSchemaObjectTable substTable) {
969 List<XmlSchemaElement> newMembers = null;
970 XmlSchemaElement headElement = (XmlSchemaElement)elements[substitutionGroup.Examplar];
971 if (substitutionGroup.Members.Contains(headElement)) {// already checked
972 return;
974 for (int i = 0; i < substitutionGroup.Members.Count; ++i) {
975 XmlSchemaElement element = (XmlSchemaElement)substitutionGroup.Members[i];
977 //Chain to other head's that are members of this head's substGroup
978 XmlSchemaSubstitutionGroup g = (XmlSchemaSubstitutionGroup)substTable[element.QualifiedName];
979 if (g != null) {
980 ResolveSubstitutionGroup(g, substTable);
981 for (int j = 0; j < g.Members.Count; ++j) {
982 XmlSchemaElement element1 = (XmlSchemaElement)g.Members[j];
983 if (element1 != element) { //Exclude the head
984 if (newMembers == null) {
985 newMembers = new List<XmlSchemaElement>();
987 newMembers.Add(element1);
992 if (newMembers != null) {
993 for (int i = 0; i < newMembers.Count; ++i) {
994 substitutionGroup.Members.Add(newMembers[i]);
997 substitutionGroup.Members.Add(headElement);
1000 internal XmlSchema Remove(XmlSchema schema, bool forceCompile) {
1001 // Due to bug 644477 - this method is tightly coupled (THE CODE IS BASICALLY COPIED) to Reprocess
1002 // method. If you change anything here *make sure* to update Reprocess method accordingly.
1003 if (schema == null) {
1004 throw new ArgumentNullException("schema");
1006 lock (InternalSyncObject) { //Need to lock here so that remove cannot be called while the set is being compiled
1007 if (schemas.ContainsKey(schema.SchemaId)) {
1009 // This code is copied to method:
1010 // Reprocess(XmlSchema schema)
1011 // If you changed anything here go and change the same in Reprocess(XmlSchema schema) method
1012 #region This code is copied to Reprocess(XmlSchema schema) method
1014 if (forceCompile) {
1015 RemoveSchemaFromGlobalTables(schema);
1016 RemoveSchemaFromCaches(schema);
1018 schemas.Remove(schema.SchemaId);
1019 if (schema.BaseUri != null) {
1020 schemaLocations.Remove(schema.BaseUri);
1022 string tns = GetTargetNamespace(schema);
1023 if (Schemas(tns).Count == 0) { //This is the only schema for that namespace
1024 targetNamespaces.Remove(tns);
1026 if (forceCompile) {
1027 isCompiled = false;
1028 compileAll = true; //Force compilation of the whole set; This is when the set is not completely thread-safe
1030 return schema;
1032 #endregion // This code is copied to Reprocess(XmlSchema schema) method
1035 return null;
1038 private void ClearTables() {
1039 GlobalElements.Clear();
1040 GlobalAttributes.Clear();
1041 GlobalTypes.Clear();
1042 SubstitutionGroups.Clear();
1043 TypeExtensions.Clear();
1046 internal bool PreprocessSchema(ref XmlSchema schema, string targetNamespace) {
1047 Preprocessor prep = new Preprocessor(nameTable, GetSchemaNames(nameTable), eventHandler, compilationSettings);
1048 prep.XmlResolver = readerSettings.GetXmlResolver_CheckConfig();
1049 prep.ReaderSettings = readerSettings;
1050 prep.SchemaLocations = schemaLocations;
1051 prep.ChameleonSchemas = chameleonSchemas;
1052 bool hasErrors = prep.Execute(schema, targetNamespace, true);
1053 schema = prep.RootSchema; //For any root level chameleon cloned
1054 return hasErrors;
1057 internal XmlSchema ParseSchema(string targetNamespace, XmlReader reader) {
1058 XmlNameTable readerNameTable = reader.NameTable;
1059 SchemaNames schemaNames = GetSchemaNames(readerNameTable);
1060 Parser parser = new Parser(SchemaType.XSD, readerNameTable, schemaNames, eventHandler);
1061 parser.XmlResolver = readerSettings.GetXmlResolver_CheckConfig();
1062 SchemaType schemaType;
1063 try {
1064 schemaType = parser.Parse(reader, targetNamespace);
1066 catch(XmlSchemaException e) {
1067 SendValidationEvent(e, XmlSeverityType.Error);
1068 return null;
1070 return parser.XmlSchema;
1073 internal void CopyFromCompiledSet(XmlSchemaSet otherSet) {
1074 XmlSchema currentSchema;
1075 SortedList copyFromList = otherSet.SortedSchemas;
1076 bool setIsCompiled = schemas.Count == 0 ? true : false;
1077 ArrayList existingSchemas = new ArrayList();
1079 SchemaInfo newCompiledInfo = new SchemaInfo();
1080 Uri baseUri;
1081 for(int i=0; i < copyFromList.Count; i++) {
1082 currentSchema = (XmlSchema)copyFromList.GetByIndex(i);
1083 baseUri = currentSchema.BaseUri;
1084 if (schemas.ContainsKey(currentSchema.SchemaId) || (baseUri != null && baseUri.OriginalString.Length != 0 && schemaLocations[baseUri] != null)) {
1085 existingSchemas.Add(currentSchema);
1086 continue;
1088 schemas.Add(currentSchema.SchemaId, currentSchema);
1089 if (baseUri != null && baseUri.OriginalString.Length != 0) {
1090 schemaLocations.Add(baseUri, currentSchema);
1092 string tns = GetTargetNamespace(currentSchema);
1093 if (targetNamespaces[tns] == null) {
1094 targetNamespaces.Add(tns, tns);
1098 VerifyTables();
1099 foreach (XmlSchemaElement element in otherSet.GlobalElements.Values) {
1100 if(!AddToTable(elements, element.QualifiedName, element)) {
1101 goto RemoveAll;
1104 foreach (XmlSchemaAttribute attribute in otherSet.GlobalAttributes.Values) {
1105 if (!AddToTable(attributes, attribute.QualifiedName, attribute)) {
1106 goto RemoveAll;
1109 foreach (XmlSchemaType schemaType in otherSet.GlobalTypes.Values) {
1110 if (!AddToTable(schemaTypes, schemaType.QualifiedName, schemaType)) {
1111 goto RemoveAll;
1115 ProcessNewSubstitutionGroups(otherSet.SubstitutionGroups, false);
1117 newCompiledInfo.Add(cachedCompiledInfo, eventHandler); //Add all the items from the old to the new compiled object
1118 newCompiledInfo.Add(otherSet.CompiledInfo,eventHandler); //
1119 cachedCompiledInfo = newCompiledInfo; //Replace the compiled info in the set after successful compilation
1120 if (setIsCompiled) {
1121 isCompiled = true;
1122 compileAll = false;
1124 return;
1126 RemoveAll:
1127 foreach (XmlSchema schemaToRemove in copyFromList.Values) {
1128 if (!existingSchemas.Contains(schemaToRemove)) {
1129 Remove(schemaToRemove, false);
1132 foreach (XmlSchemaElement elementToRemove in otherSet.GlobalElements.Values) {
1133 if(!existingSchemas.Contains((XmlSchema)elementToRemove.Parent)) {
1134 elements.Remove(elementToRemove.QualifiedName);
1137 foreach (XmlSchemaAttribute attributeToRemove in otherSet.GlobalAttributes.Values) {
1138 if(!existingSchemas.Contains((XmlSchema)attributeToRemove.Parent)) {
1139 attributes.Remove(attributeToRemove.QualifiedName);
1142 foreach (XmlSchemaType schemaTypeToRemove in otherSet.GlobalTypes.Values) {
1143 if(!existingSchemas.Contains((XmlSchema)schemaTypeToRemove.Parent)) {
1144 schemaTypes.Remove(schemaTypeToRemove.QualifiedName);
1149 internal SchemaInfo CompiledInfo {
1150 get {
1151 return cachedCompiledInfo;
1155 internal XmlReaderSettings ReaderSettings {
1156 get {
1157 return readerSettings;
1161 internal XmlResolver GetResolver() {
1162 return readerSettings.GetXmlResolver_CheckConfig();
1165 internal ValidationEventHandler GetEventHandler() {
1166 return eventHandler;
1169 internal SchemaNames GetSchemaNames(XmlNameTable nt) {
1170 if (nameTable != nt) {
1171 return new SchemaNames(nt);
1173 else {
1174 if (schemaNames == null) {
1175 schemaNames = new SchemaNames( nameTable );
1177 return schemaNames;
1181 internal bool IsSchemaLoaded(Uri schemaUri, string targetNamespace, out XmlSchema schema) {
1182 schema = null;
1183 if (targetNamespace == null) {
1184 targetNamespace = string.Empty;
1186 if (GetSchemaByUri(schemaUri, out schema)) {
1187 if (schemas.ContainsKey(schema.SchemaId) && (targetNamespace.Length == 0 || targetNamespace == schema.TargetNamespace)) { //schema is present in set
1188 //Schema found
1190 else if (schema.TargetNamespace == null) { //If schema not in set or namespace doesnt match, then it might be a chameleon
1191 XmlSchema chameleonSchema = FindSchemaByNSAndUrl(schemaUri, targetNamespace, null);
1192 if (chameleonSchema != null && schemas.ContainsKey(chameleonSchema.SchemaId)) {
1193 schema = chameleonSchema;
1195 else {
1196 schema = Add(targetNamespace, schema);
1199 else if (targetNamespace.Length != 0 && targetNamespace != schema.TargetNamespace) {
1200 SendValidationEvent(new XmlSchemaException(Res.Sch_MismatchTargetNamespaceEx, new string[] { targetNamespace, schema.TargetNamespace }), XmlSeverityType.Error);
1201 schema = null;
1203 else {
1204 //If here, schema not present in set but in loc and might be added in loc through an earlier include
1205 //S.TNS != null && ( tns == null or tns == s.TNS)
1206 AddSchemaToSet(schema);
1208 return true; //Schema Found
1210 return false;
1213 internal bool GetSchemaByUri(Uri schemaUri, out XmlSchema schema) {
1214 schema = null;
1215 if (schemaUri == null || schemaUri.OriginalString.Length == 0) {
1216 return false;
1218 schema = (XmlSchema)schemaLocations[schemaUri];
1219 if (schema != null) {
1220 return true;
1222 return false;
1225 internal string GetTargetNamespace(XmlSchema schema) {
1226 return schema.TargetNamespace == null ? string.Empty : schema.TargetNamespace;
1230 internal SortedList SortedSchemas {
1231 get {
1232 return schemas;
1236 internal bool CompileAll {
1237 get {
1238 return compileAll;
1242 //Private Methods
1243 private void RemoveSchemaFromCaches(XmlSchema schema) {
1244 //Remove From ChameleonSchemas and schemaLocations cache
1245 List<XmlSchema> reprocessList = new List<XmlSchema>();
1246 schema.GetExternalSchemasList(reprocessList, schema);
1247 for (int i = 0; i < reprocessList.Count; ++i) { //Remove schema from schemaLocations & chameleonSchemas tables
1248 if (reprocessList[i].BaseUri != null && reprocessList[i].BaseUri.OriginalString.Length != 0) {
1249 schemaLocations.Remove(reprocessList[i].BaseUri);
1251 //Remove from chameleon table
1252 ICollection chameleonKeys = chameleonSchemas.Keys;
1253 ArrayList removalList = new ArrayList();
1254 foreach(ChameleonKey cKey in chameleonKeys) {
1255 if (cKey.chameleonLocation.Equals(reprocessList[i].BaseUri)) {
1256 // The key will have the originalSchema set to null if the location was not empty
1257 // otherwise we need to care about it as there may be more chameleon schemas without
1258 // a base URI and we want to remove only those which were created as a clone of the one
1259 // we're removing.
1260 if (cKey.originalSchema == null || Ref.ReferenceEquals(cKey.originalSchema, reprocessList[i])) {
1261 removalList.Add(cKey);
1265 for (int j = 0; j < removalList.Count; ++j) {
1266 chameleonSchemas.Remove(removalList[j]);
1271 private void RemoveSchemaFromGlobalTables(XmlSchema schema) {
1272 if (schemas.Count == 0) {
1273 return;
1275 VerifyTables();
1276 foreach (XmlSchemaElement elementToRemove in schema.Elements.Values) {
1277 XmlSchemaElement elem = (XmlSchemaElement)elements[elementToRemove.QualifiedName];
1278 if (elem == elementToRemove) {
1279 elements.Remove(elementToRemove.QualifiedName);
1282 foreach (XmlSchemaAttribute attributeToRemove in schema.Attributes.Values) {
1283 XmlSchemaAttribute attr = (XmlSchemaAttribute)attributes[attributeToRemove.QualifiedName];
1284 if (attr == attributeToRemove) {
1285 attributes.Remove(attributeToRemove.QualifiedName);
1288 foreach (XmlSchemaType schemaTypeToRemove in schema.SchemaTypes.Values) {
1289 XmlSchemaType schemaType = (XmlSchemaType)schemaTypes[schemaTypeToRemove.QualifiedName];
1290 if (schemaType == schemaTypeToRemove) {
1291 schemaTypes.Remove(schemaTypeToRemove.QualifiedName);
1295 private bool AddToTable(XmlSchemaObjectTable table, XmlQualifiedName qname, XmlSchemaObject item) {
1296 if (qname.Name.Length == 0) {
1297 return true;
1299 XmlSchemaObject existingObject = (XmlSchemaObject)table[qname];
1300 if (existingObject != null) {
1301 if (existingObject == item || existingObject.SourceUri == item.SourceUri) {
1302 return true;
1304 string code = string.Empty;
1305 if (item is XmlSchemaComplexType) {
1306 code = Res.Sch_DupComplexType;
1308 else if (item is XmlSchemaSimpleType) {
1309 code = Res.Sch_DupSimpleType;
1311 else if (item is XmlSchemaElement) {
1312 code = Res.Sch_DupGlobalElement;
1314 else if (item is XmlSchemaAttribute) {
1315 if (qname.Namespace == XmlReservedNs.NsXml) {
1316 XmlSchema schemaForXmlNS = Preprocessor.GetBuildInSchema();
1317 XmlSchemaObject builtInAttribute = schemaForXmlNS.Attributes[qname];
1318 if (existingObject == builtInAttribute) { //replace built-in one
1319 table.Insert(qname, item);
1320 return true;
1322 else if (item == builtInAttribute) { //trying to overwrite customer's component with built-in, ignore built-in
1323 return true;
1326 code = Res.Sch_DupGlobalAttribute;
1328 SendValidationEvent(new XmlSchemaException(code,qname.ToString()), XmlSeverityType.Error);
1329 return false;
1331 else {
1332 table.Add(qname, item);
1333 return true;
1337 private void VerifyTables() {
1338 if (elements == null) {
1339 elements = new XmlSchemaObjectTable();
1341 if (attributes == null) {
1342 attributes = new XmlSchemaObjectTable();
1344 if (schemaTypes == null) {
1345 schemaTypes = new XmlSchemaObjectTable();
1347 if (substitutionGroups == null) {
1348 substitutionGroups = new XmlSchemaObjectTable();
1352 private void InternalValidationCallback(object sender, ValidationEventArgs e ) {
1353 if (e.Severity == XmlSeverityType.Error) {
1354 throw e.Exception;
1358 private void SendValidationEvent(XmlSchemaException e, XmlSeverityType severity) {
1359 if (eventHandler != null) {
1360 eventHandler(this, new ValidationEventArgs(e, severity));
1362 else {
1363 throw e;
1367 #endif