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; 12 13 namespace System.Xml.Schema { 14 #if SILVERLIGHT 15 public class XmlSchemaSet 16 { 17 //Empty XmlSchemaSet class to enable backward compatibility of XmlSchemaProvideAttribute 18 //Add private ctor to prevent constructing of this class XmlSchemaSet()19 XmlSchemaSet() { } 20 } 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 36 37 //Event handling 38 ValidationEventHandler internalEventHandler; 39 ValidationEventHandler eventHandler; 40 41 bool isCompiled = false; 42 43 //Dictionary<Uri, XmlSchema> schemaLocations; 44 //Dictionary<ChameleonKey, XmlSchema> chameleonSchemas; 45 Hashtable schemaLocations; 46 Hashtable chameleonSchemas; 47 48 Hashtable targetNamespaces; 49 bool compileAll; 50 51 //Cached Compiled Info 52 SchemaInfo cachedCompiledInfo; 53 54 //Reader settings to parse schema 55 XmlReaderSettings readerSettings; 56 XmlSchema schemaForSchema; //Only one schema for schema per set 57 58 //Schema compilation settings 59 XmlSchemaCompilationSettings compilationSettings; 60 61 internal XmlSchemaObjectTable elements; 62 internal XmlSchemaObjectTable attributes; 63 internal XmlSchemaObjectTable schemaTypes; 64 internal XmlSchemaObjectTable substitutionGroups; 65 private XmlSchemaObjectTable typeExtensions; 66 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); 74 } 75 return internalSyncObject; 76 } 77 } 78 79 //Constructors 80 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()) { 86 } 87 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"); 96 } 97 this.nameTable = nameTable; 98 schemas = new SortedList(); 99 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; 107 108 readerSettings = new XmlReaderSettings(); 109 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) 113 { 114 // The created resolver will be used in the schema validation only 115 readerSettings.XmlResolver = new XmlUrlResolver(); 116 readerSettings.IsXmlResolverSet = false; 117 } 118 119 readerSettings.NameTable = nameTable; 120 readerSettings.DtdProcessing = DtdProcessing.Prohibit; 121 122 compilationSettings = new XmlSchemaCompilationSettings(); 123 cachedCompiledInfo = new SchemaInfo(); 124 compileAll = true; 125 } 126 127 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;} 135 } 136 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; 144 } 145 } 146 remove { 147 eventHandler -= value; 148 if (eventHandler == null) { 149 eventHandler = internalEventHandler; 150 } 151 } 152 } 153 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; 161 } 162 } 163 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; 171 } 172 } 173 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; 181 } 182 set { 183 compilationSettings = value; 184 } 185 } 186 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; 194 } 195 } 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(); 204 } 205 return elements; 206 } 207 } 208 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(); 217 } 218 return attributes; 219 } 220 } 221 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(); 230 } 231 return schemaTypes; 232 } 233 } 234 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(); 244 } 245 return substitutionGroups; 246 } 247 } 248 249 /// <summary> 250 /// Table of all types extensions 251 /// </summary> 252 internal Hashtable SchemaLocations { 253 get { 254 return schemaLocations; 255 } 256 } 257 258 /// <summary> 259 /// Table of all types extensions 260 /// </summary> 261 internal XmlSchemaObjectTable TypeExtensions { 262 get { 263 if (typeExtensions == null) { 264 typeExtensions = new XmlSchemaObjectTable(); 265 } 266 return typeExtensions; 267 } 268 } 269 //Public Methods 270 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"); 282 } 283 if (targetNamespace != null) { 284 targetNamespace = XmlComplianceUtil.CDataNormalize(targetNamespace); 285 } 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(); 292 } 293 Uri tempSchemaUri = tempResolver.ResolveUri(null, schemaUri); 294 if (IsSchemaLoaded(tempSchemaUri, targetNamespace, out schema)) { 295 return schema; 296 } 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; 303 } 304 finally { 305 reader.Close(); 306 } 307 } 308 } 309 return schema; 310 } 311 312 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"); 322 } 323 if (targetNamespace != null) { 324 targetNamespace = XmlComplianceUtil.CDataNormalize(targetNamespace); 325 } 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; 331 } 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; 338 } 339 } 340 } 341 342 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"); 351 } 352 if (this == schemas) { 353 return; 354 } 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; 364 } 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; 370 } 371 } 372 } 373 374 XmlSchema currentSchema; 375 // 376 if (schemas.IsCompiled) { 377 CopyFromCompiledSet(schemas); 378 } 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; 386 } 387 if (this.schemas.ContainsKey(schema.SchemaId) || FindSchemaByNSAndUrl(schema.BaseUri, tns, null) != null) { //Do not already existing url 388 continue; 389 } 390 currentSchema = Add(schema.TargetNamespace, schema); 391 if(currentSchema == null) { 392 remove = true; 393 break; 394 } 395 } 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); 401 } 402 } 403 } 404 } 405 finally { //release locks on sets 406 if (thisLockObtained) { 407 Monitor.Exit(InternalSyncObject); 408 } 409 if (schemasLockObtained) { 410 Monitor.Exit(schemas.InternalSyncObject); 411 } 412 } 413 } 414 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"); 419 } 420 lock (InternalSyncObject) { 421 if (schemas.ContainsKey(schema.SchemaId)) { 422 return schema; 423 } 424 return Add(schema.TargetNamespace, schema); 425 } 426 } 427 428 /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Remove"]/*' /> 429 public XmlSchema Remove(XmlSchema schema) { 430 return Remove(schema, true); 431 } 432 433 /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.RemoveRecursive"]/*' /> 434 public bool RemoveRecursive(XmlSchema schemaToRemove) { 435 436 if (schemaToRemove == null) { 437 throw new ArgumentNullException("schemaToRemove"); 438 } 439 if (!schemas.ContainsKey(schemaToRemove.SchemaId)) { 440 return false; 441 } 442 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 445 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); 454 } 455 } 456 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; 466 } 467 needToCheckSchemaList.Add(mainSchema); 468 } 469 470 mainSchema = null; 471 for (int i = 0; i < needToCheckSchemaList.Count; i++) { //Perf: Not using nested foreach here 472 mainSchema = (XmlSchema)needToCheckSchemaList[i]; 473 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; 479 } 480 } 481 } 482 } 483 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); 488 } 489 return true; 490 } 491 } 492 return false; 493 } 494 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; 499 } 500 return targetNamespaces[targetNamespace] != null; 501 } 502 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"); 507 } 508 return schemas.ContainsValue(schema); 509 } 510 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; 518 } 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; 525 } 526 lock (InternalSyncObject) { 527 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); 534 } 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); 542 543 //Lock schema to be compiled 544 #pragma warning disable 0618 545 //@ 546 Monitor.Enter(currentSchema); 547 #pragma warning restore 0618 548 if (!currentSchema.IsPreprocessed) 549 { 550 SendValidationEvent(new XmlSchemaException(Res.Sch_SchemaNotPreprocessed, string.Empty), XmlSeverityType.Error); 551 isCompiled = false; 552 return; 553 } 554 if (currentSchema.IsCompiledBySet) { 555 if (!compileAll) { 556 continue; 557 } 558 else if ((object)currentSchema == (object)xmlNSSchema) { // prepare for xml namespace schema without cleanup 559 compiler.Prepare(currentSchema, false); 560 continue; 561 } 562 } 563 compiler.Prepare(currentSchema, true); 564 } 565 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 570 } 571 compileAll = false; 572 cachedCompiledInfo = newCompiledInfo; //Replace the compiled info in the set after successful compilation 573 } 574 } 575 finally { 576 //Release locks on all schemas 577 XmlSchema currentSchema; 578 if (schemaIndex == schemas.Count) { 579 schemaIndex--; 580 } 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; 586 } 587 currentSchema.IsCompiledBySet = isCompiled; 588 Monitor.Exit(currentSchema); 589 } 590 } 591 } 592 } 593 return; 594 } 595 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"); 608 } 609 if (!schemas.ContainsKey(schema.SchemaId)) { 610 throw new ArgumentException(Res.GetString(Res.Sch_SchemaDoesNotExist), "schema"); 611 } 612 XmlSchema originalSchema = schema; 613 lock (InternalSyncObject) { //Lock set so that set cannot be compiled in another thread 614 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) 619 620 RemoveSchemaFromGlobalTables(schema); 621 RemoveSchemaFromCaches(schema); 622 if (schema.BaseUri != null) { 623 schemaLocations.Remove(schema.BaseUri); 624 } 625 string tns = GetTargetNamespace(schema); 626 if (Schemas(tns).Count == 0) { //This is the only schema for that namespace 627 targetNamespaces.Remove(tns); 628 } 629 isCompiled = false; 630 compileAll = true; //Force compilation of the whole set; This is when the set is not completely thread-safe 631 632 #endregion //Copied from Remove(XmlSchema schema, bool forceCompile) 633 634 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) 639 640 if (schema.ErrorCount != 0) { //Schema with parsing errors cannot be loaded 641 return originalSchema; 642 } 643 if (PreprocessSchema(ref schema, schema.TargetNamespace)) { //No perf opt for already compiled schemas 644 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) 649 650 //Add to targetNamespaces table 651 if (targetNamespaces[tns] == null) { 652 targetNamespaces.Add(tns, tns); 653 } 654 if (schemaForSchema == null && tns == XmlReservedNs.NsXs && schema.SchemaTypes[DatatypeImplementation.QnAnyType] != null) { //it has xs:anyType 655 schemaForSchema = schema; 656 } 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); 661 } 662 tns = GetTargetNamespace(s); 663 if (targetNamespaces[tns] == null) { 664 targetNamespaces.Add(tns, tns); 665 } 666 if (schemaForSchema == null && tns == XmlReservedNs.NsXs && schema.SchemaTypes[DatatypeImplementation.QnAnyType] != null) { //it has xs:anyType 667 schemaForSchema = schema; 668 } 669 } 670 #endregion //Copied from AddSchemaToSet(XmlSchema schema) 671 return schema; 672 } 673 #endregion // Copied from Add(string targetNamespace, XmlSchema schema) 674 675 return originalSchema; 676 } 677 } 678 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); 689 } 690 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; 697 } 698 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; 708 } 709 for (int i=0; i < schemas.Count; i++) { 710 currentSchema = (XmlSchema)schemas.GetByIndex(i); 711 if (GetTargetNamespace(currentSchema) == targetNamespace) { 712 tnsSchemas.Add(currentSchema); 713 } 714 } 715 return tnsSchemas; 716 } 717 718 //Internal Methods 719 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. 723 724 if (schema == null || schema.ErrorCount != 0) { //Schema with parsing errors cannot be loaded 725 return null; 726 } 727 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; 735 } 736 return null; 737 } 738 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; 747 } 748 foreach (XmlSchema impSchema in schema.ImportedSchemas) { 749 if (!AddToCompiledInfo(impSchema, newCompiledInfo, ref substitutionGroupsTable)) { //Error while adding imports 750 return null; 751 } 752 } 753 newCompiledInfo.Add(cachedCompiledInfo, eventHandler); //Add existing compiled info 754 cachedCompiledInfo = newCompiledInfo; 755 if (substitutionGroupsTable != null) { 756 ProcessNewSubstitutionGroups(substitutionGroupsTable, true); 757 } 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; 761 } 762 AddSchemaToSet(schema); 763 return schema; 764 } 765 } 766 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); 771 } 772 773 foreach (XmlSchemaElement element in schema.Elements.Values) { 774 if(!AddToTable(elements, element.QualifiedName, element)) { 775 RemoveSchemaFromGlobalTables(schema); 776 return false; 777 } 778 XmlQualifiedName head = element.SubstitutionGroup; 779 if (!head.IsEmpty) { 780 if (substTable == null) { 781 substTable = new XmlSchemaObjectTable(); 782 } 783 XmlSchemaSubstitutionGroup substitutionGroup = (XmlSchemaSubstitutionGroup)substTable[head]; 784 if (substitutionGroup == null) { 785 substitutionGroup = new XmlSchemaSubstitutionGroup(); 786 substitutionGroup.Examplar = head; 787 substTable.Add(head, substitutionGroup); 788 } 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); 792 } 793 } 794 } 795 foreach (XmlSchemaAttribute attribute in schema.Attributes.Values) { 796 if (!AddToTable(attributes, attribute.QualifiedName, attribute)) { 797 RemoveSchemaFromGlobalTables(schema); 798 return false; 799 } 800 } 801 foreach (XmlSchemaType schemaType in schema.SchemaTypes.Values) { 802 if (!AddToTable(schemaTypes, schemaType.QualifiedName, schemaType)) { 803 RemoveSchemaFromGlobalTables(schema); 804 return false; 805 } 806 } 807 schema.AddCompiledInfo(newCompiledInfo); 808 809 return true; 810 } 811 #endif 812 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"); 817 } 818 if (targetNamespace == null) { 819 targetNamespace = string.Empty; 820 } 821 if (validatedNamespaces[targetNamespace] != null) { 822 if (FindSchemaByNSAndUrl(new Uri(reader.BaseURI, UriKind.RelativeOrAbsolute), targetNamespace, null) != null) { 823 return; 824 } 825 else { 826 throw new XmlSchemaException(Res.Sch_ComponentAlreadySeenForNS, targetNamespace); 827 } 828 } 829 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; 834 } 835 else { //top-level schema not present for same url 836 schema = ParseSchema(targetNamespace, reader); 837 838 //Store the previous locations 839 DictionaryEntry[] oldLocations = new DictionaryEntry[schemaLocations.Count]; 840 schemaLocations.CopyTo(oldLocations, 0); 841 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; 851 } 852 if (validatedNamespaces[tns] != null && (FindSchemaByNSAndUrl(impSchema.BaseUri, tns, oldLocations) == null) ) { 853 RemoveRecursive(schema); 854 throw new XmlSchemaException(Res.Sch_ComponentAlreadySeenForNS, tns); 855 } 856 } 857 } 858 } 859 } 860 861 internal XmlSchema FindSchemaByNSAndUrl(Uri schemaUri, string ns, DictionaryEntry[] locationsTable) { 862 if (schemaUri == null || schemaUri.OriginalString.Length == 0) { 863 return null; 864 } 865 XmlSchema schema = null; 866 if (locationsTable == null) { 867 schema = (XmlSchema)schemaLocations[schemaUri]; 868 } 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; 874 } 875 } 876 } 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; 882 } 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 890 } 891 else { 892 schema = null; 893 } 894 } 895 return schema; 896 } 897 898 private void SetDtdProcessing(XmlReader reader) { 899 if (reader.Settings != null) { 900 this.readerSettings.DtdProcessing = reader.Settings.DtdProcessing; 901 } 902 else { 903 XmlTextReader v1Reader = reader as XmlTextReader; 904 if (v1Reader != null) { 905 this.readerSettings.DtdProcessing = v1Reader.DtdProcessing; 906 } 907 } 908 } 909 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. 913 914 schemas.Add(schema.SchemaId, schema); 915 //Add to targetNamespaces table 916 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 921 922 string tns = GetTargetNamespace(schema); 923 if (targetNamespaces[tns] == null) { 924 targetNamespaces.Add(tns, tns); 925 } 926 if (schemaForSchema == null && tns == XmlReservedNs.NsXs && schema.SchemaTypes[DatatypeImplementation.QnAnyType] != null) { //it has xs:anyType 927 schemaForSchema = schema; 928 } 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); 933 } 934 tns = GetTargetNamespace(s); 935 if (targetNamespaces[tns] == null) { 936 targetNamespaces.Add(tns, tns); 937 } 938 if (schemaForSchema == null && tns == XmlReservedNs.NsXs && schema.SchemaTypes[DatatypeImplementation.QnAnyType] != null) { //it has xs:anyType 939 schemaForSchema = schema; 940 } 941 } 942 943 #endregion // This code is copied to Reprocess(XmlSchema schema) method 944 } 945 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); 950 } 951 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]); 959 } 960 } 961 } 962 else { 963 AddToTable(substitutionGroups, head, substGroup); 964 } 965 } 966 } 967 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; 973 } 974 for (int i = 0; i < substitutionGroup.Members.Count; ++i) { 975 XmlSchemaElement element = (XmlSchemaElement)substitutionGroup.Members[i]; 976 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>(); 986 } 987 newMembers.Add(element1); 988 } 989 } 990 } 991 } 992 if (newMembers != null) { 993 for (int i = 0; i < newMembers.Count; ++i) { 994 substitutionGroup.Members.Add(newMembers[i]); 995 } 996 } 997 substitutionGroup.Members.Add(headElement); 998 } 999 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"); 1005 } 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)) { 1008 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 1013 1014 if (forceCompile) { 1015 RemoveSchemaFromGlobalTables(schema); 1016 RemoveSchemaFromCaches(schema); 1017 } 1018 schemas.Remove(schema.SchemaId); 1019 if (schema.BaseUri != null) { 1020 schemaLocations.Remove(schema.BaseUri); 1021 } 1022 string tns = GetTargetNamespace(schema); 1023 if (Schemas(tns).Count == 0) { //This is the only schema for that namespace 1024 targetNamespaces.Remove(tns); 1025 } 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 1029 } 1030 return schema; 1031 1032 #endregion // This code is copied to Reprocess(XmlSchema schema) method 1033 } 1034 } 1035 return null; 1036 } 1037 1038 private void ClearTables() { 1039 GlobalElements.Clear(); 1040 GlobalAttributes.Clear(); 1041 GlobalTypes.Clear(); 1042 SubstitutionGroups.Clear(); 1043 TypeExtensions.Clear(); 1044 } 1045 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; 1055 } 1056 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); 1065 } 1066 catch(XmlSchemaException e) { 1067 SendValidationEvent(e, XmlSeverityType.Error); 1068 return null; 1069 } 1070 return parser.XmlSchema; 1071 } 1072 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(); 1078 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; 1087 } 1088 schemas.Add(currentSchema.SchemaId, currentSchema); 1089 if (baseUri != null && baseUri.OriginalString.Length != 0) { 1090 schemaLocations.Add(baseUri, currentSchema); 1091 } 1092 string tns = GetTargetNamespace(currentSchema); 1093 if (targetNamespaces[tns] == null) { 1094 targetNamespaces.Add(tns, tns); 1095 } 1096 } 1097 1098 VerifyTables(); 1099 foreach (XmlSchemaElement element in otherSet.GlobalElements.Values) { 1100 if(!AddToTable(elements, element.QualifiedName, element)) { 1101 goto RemoveAll; 1102 } 1103 } 1104 foreach (XmlSchemaAttribute attribute in otherSet.GlobalAttributes.Values) { 1105 if (!AddToTable(attributes, attribute.QualifiedName, attribute)) { 1106 goto RemoveAll; 1107 } 1108 } 1109 foreach (XmlSchemaType schemaType in otherSet.GlobalTypes.Values) { 1110 if (!AddToTable(schemaTypes, schemaType.QualifiedName, schemaType)) { 1111 goto RemoveAll; 1112 } 1113 } 1114 // 1115 ProcessNewSubstitutionGroups(otherSet.SubstitutionGroups, false); 1116 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; 1123 } 1124 return; 1125 1126 RemoveAll: 1127 foreach (XmlSchema schemaToRemove in copyFromList.Values) { 1128 if (!existingSchemas.Contains(schemaToRemove)) { 1129 Remove(schemaToRemove, false); 1130 } 1131 } 1132 foreach (XmlSchemaElement elementToRemove in otherSet.GlobalElements.Values) { 1133 if(!existingSchemas.Contains((XmlSchema)elementToRemove.Parent)) { 1134 elements.Remove(elementToRemove.QualifiedName); 1135 } 1136 } 1137 foreach (XmlSchemaAttribute attributeToRemove in otherSet.GlobalAttributes.Values) { 1138 if(!existingSchemas.Contains((XmlSchema)attributeToRemove.Parent)) { 1139 attributes.Remove(attributeToRemove.QualifiedName); 1140 } 1141 } 1142 foreach (XmlSchemaType schemaTypeToRemove in otherSet.GlobalTypes.Values) { 1143 if(!existingSchemas.Contains((XmlSchema)schemaTypeToRemove.Parent)) { 1144 schemaTypes.Remove(schemaTypeToRemove.QualifiedName); 1145 } 1146 } 1147 } 1148 1149 internal SchemaInfo CompiledInfo { 1150 get { 1151 return cachedCompiledInfo; 1152 } 1153 } 1154 1155 internal XmlReaderSettings ReaderSettings { 1156 get { 1157 return readerSettings; 1158 } 1159 } 1160 1161 internal XmlResolver GetResolver() { 1162 return readerSettings.GetXmlResolver_CheckConfig(); 1163 } 1164 1165 internal ValidationEventHandler GetEventHandler() { 1166 return eventHandler; 1167 } 1168 1169 internal SchemaNames GetSchemaNames(XmlNameTable nt) { 1170 if (nameTable != nt) { 1171 return new SchemaNames(nt); 1172 } 1173 else { 1174 if (schemaNames == null) { 1175 schemaNames = new SchemaNames( nameTable ); 1176 } 1177 return schemaNames; 1178 } 1179 } 1180 1181 internal bool IsSchemaLoaded(Uri schemaUri, string targetNamespace, out XmlSchema schema) { 1182 schema = null; 1183 if (targetNamespace == null) { 1184 targetNamespace = string.Empty; 1185 } 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 1189 } 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; 1194 } 1195 else { 1196 schema = Add(targetNamespace, schema); 1197 } 1198 } 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; 1202 } 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); 1207 } 1208 return true; //Schema Found 1209 } 1210 return false; 1211 } 1212 1213 internal bool GetSchemaByUri(Uri schemaUri, out XmlSchema schema) { 1214 schema = null; 1215 if (schemaUri == null || schemaUri.OriginalString.Length == 0) { 1216 return false; 1217 } 1218 schema = (XmlSchema)schemaLocations[schemaUri]; 1219 if (schema != null) { 1220 return true; 1221 } 1222 return false; 1223 } 1224 1225 internal string GetTargetNamespace(XmlSchema schema) { 1226 return schema.TargetNamespace == null ? string.Empty : schema.TargetNamespace; 1227 } 1228 1229 1230 internal SortedList SortedSchemas { 1231 get { 1232 return schemas; 1233 } 1234 } 1235 1236 internal bool CompileAll { 1237 get { 1238 return compileAll; 1239 } 1240 } 1241 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); 1250 } 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); 1262 } 1263 } 1264 } 1265 for (int j = 0; j < removalList.Count; ++j) { 1266 chameleonSchemas.Remove(removalList[j]); 1267 } 1268 } 1269 } 1270 1271 private void RemoveSchemaFromGlobalTables(XmlSchema schema) { 1272 if (schemas.Count == 0) { 1273 return; 1274 } 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); 1280 } 1281 } 1282 foreach (XmlSchemaAttribute attributeToRemove in schema.Attributes.Values) { 1283 XmlSchemaAttribute attr = (XmlSchemaAttribute)attributes[attributeToRemove.QualifiedName]; 1284 if (attr == attributeToRemove) { 1285 attributes.Remove(attributeToRemove.QualifiedName); 1286 } 1287 } 1288 foreach (XmlSchemaType schemaTypeToRemove in schema.SchemaTypes.Values) { 1289 XmlSchemaType schemaType = (XmlSchemaType)schemaTypes[schemaTypeToRemove.QualifiedName]; 1290 if (schemaType == schemaTypeToRemove) { 1291 schemaTypes.Remove(schemaTypeToRemove.QualifiedName); 1292 } 1293 } 1294 } 1295 private bool AddToTable(XmlSchemaObjectTable table, XmlQualifiedName qname, XmlSchemaObject item) { 1296 if (qname.Name.Length == 0) { 1297 return true; 1298 } 1299 XmlSchemaObject existingObject = (XmlSchemaObject)table[qname]; 1300 if (existingObject != null) { 1301 if (existingObject == item || existingObject.SourceUri == item.SourceUri) { 1302 return true; 1303 } 1304 string code = string.Empty; 1305 if (item is XmlSchemaComplexType) { 1306 code = Res.Sch_DupComplexType; 1307 } 1308 else if (item is XmlSchemaSimpleType) { 1309 code = Res.Sch_DupSimpleType; 1310 } 1311 else if (item is XmlSchemaElement) { 1312 code = Res.Sch_DupGlobalElement; 1313 } 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; 1321 } 1322 else if (item == builtInAttribute) { //trying to overwrite customer's component with built-in, ignore built-in 1323 return true; 1324 } 1325 } 1326 code = Res.Sch_DupGlobalAttribute; 1327 } 1328 SendValidationEvent(new XmlSchemaException(code,qname.ToString()), XmlSeverityType.Error); 1329 return false; 1330 } 1331 else { 1332 table.Add(qname, item); 1333 return true; 1334 } 1335 } 1336 1337 private void VerifyTables() { 1338 if (elements == null) { 1339 elements = new XmlSchemaObjectTable(); 1340 } 1341 if (attributes == null) { 1342 attributes = new XmlSchemaObjectTable(); 1343 } 1344 if (schemaTypes == null) { 1345 schemaTypes = new XmlSchemaObjectTable(); 1346 } 1347 if (substitutionGroups == null) { 1348 substitutionGroups = new XmlSchemaObjectTable(); 1349 } 1350 } 1351 1352 private void InternalValidationCallback(object sender, ValidationEventArgs e ) { 1353 if (e.Severity == XmlSeverityType.Error) { 1354 throw e.Exception; 1355 } 1356 } 1357 1358 private void SendValidationEvent(XmlSchemaException e, XmlSeverityType severity) { 1359 if (eventHandler != null) { 1360 eventHandler(this, new ValidationEventArgs(e, severity)); 1361 } 1362 else { 1363 throw e; 1364 } 1365 } 1366 }; 1367 #endif 1368 } 1369