The Labs \ Source Viewer \ SSCLI \ System.Xml.Schema \ XmlSchemaSet

  1. //------------------------------------------------------------------------------
  2. // <copyright file="XmlSchemaSet.cs" company="Microsoft">
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. // </copyright>
  14. // <owner current="true" primary="true">priyal</owner>
  15. //------------------------------------------------------------------------------
  16. using System.Diagnostics;
  17. using System.Collections;
  18. using System.Threading;
  19. using System.Collections.Generic;
  20. namespace System.Xml.Schema
  21. {
  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.     {
  34.         XmlNameTable nameTable;
  35.         SchemaNames schemaNames;
  36.         SortedList schemas;
  37.         // List of source schemas
  38.         //Event handling
  39.         ValidationEventHandler internalEventHandler;
  40.         ValidationEventHandler eventHandler;
  41.        
  42.         bool isCompiled = false;
  43.        
  44.         //Dictionary<Uri, XmlSchema> schemaLocations;
  45.         //Dictionary<ChameleonKey, XmlSchema> chameleonSchemas;
  46.         Hashtable schemaLocations;
  47.         Hashtable chameleonSchemas;
  48.        
  49.         Hashtable targetNamespaces;
  50.         bool compileAll;
  51.        
  52.         //Cached Compiled Info
  53.         SchemaInfo cachedCompiledInfo;
  54.        
  55.         //Reader settings to parse schema
  56.         XmlReaderSettings readerSettings;
  57.         XmlSchema schemaForSchema;
  58.         //Only one schema for schema per set
  59.         //Schema compilation settings
  60.         XmlSchemaCompilationSettings compilationSettings;
  61.        
  62.         internal XmlSchemaObjectTable elements;
  63.         internal XmlSchemaObjectTable attributes;
  64.         internal XmlSchemaObjectTable schemaTypes;
  65.         internal XmlSchemaObjectTable substitutionGroups;
  66.         private XmlSchemaObjectTable typeExtensions;
  67.        
  68.         //Thread safety
  69.         private object internalSyncObject;
  70.         internal object InternalSyncObject {
  71.             get {
  72.                 if (internalSyncObject == null) {
  73.                     object o = new object();
  74.                     Interlocked.CompareExchange(ref internalSyncObject, o, null);
  75.                 }
  76.                 return internalSyncObject;
  77.             }
  78.         }
  79.        
  80.         //Constructors
  81.        
  82.         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.XmlSchemaSet"]/*' />
  83.         /// <devdoc>
  84.         /// <para>Construct a new empty schema schemas.</para>
  85.         /// </devdoc>
  86.         public XmlSchemaSet() : this(new NameTable())
  87.         {
  88.         }
  89.        
  90.         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.XmlSchemaSet1"]/*' />
  91.         /// <devdoc>
  92.         /// <para>Construct a new empty schema schemas with associated XmlNameTable.
  93.         /// The XmlNameTable is used when loading schemas</para>
  94.         /// </devdoc>
  95.         public XmlSchemaSet(XmlNameTable nameTable)
  96.         {
  97.             if (nameTable == null) {
  98.                 throw new ArgumentNullException("nameTable");
  99.             }
  100.             this.nameTable = nameTable;
  101.             schemas = new SortedList();
  102.            
  103.             /*schemaLocations = new Dictionary<Uri, XmlSchema>();
  104.             chameleonSchemas = new Dictionary<ChameleonKey, XmlSchema>();*/           
  105. schemaLocations = new Hashtable();
  106.             chameleonSchemas = new Hashtable();
  107.             targetNamespaces = new Hashtable();
  108.             internalEventHandler = new ValidationEventHandler(InternalValidationCallback);
  109.             eventHandler = internalEventHandler;
  110.            
  111.             readerSettings = new XmlReaderSettings();
  112.             readerSettings.NameTable = nameTable;
  113.             readerSettings.ProhibitDtd = true;
  114.            
  115.             compilationSettings = new XmlSchemaCompilationSettings();
  116.             cachedCompiledInfo = new SchemaInfo();
  117.             compileAll = true;
  118.         }
  119.        
  120.        
  121.         //Public Properties
  122.         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.NameTable"]/*' />
  123.         /// <devdoc>
  124.         /// <para>The default XmlNameTable used by the XmlSchemaSet when loading new schemas.</para>
  125.         /// </devdoc>
  126.         public XmlNameTable NameTable {
  127.             get { return nameTable; }
  128.         }
  129.        
  130.         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.ValidationEventHandler"]/*' />
  131.         public event ValidationEventHandler ValidationEventHandler {
  132.             add {
  133.                 eventHandler -= internalEventHandler;
  134.                 eventHandler += value;
  135.                 if (eventHandler == null) {
  136.                     eventHandler = internalEventHandler;
  137.                 }
  138.             }
  139.             remove {
  140.                 eventHandler -= value;
  141.                 if (eventHandler == null) {
  142.                     eventHandler = internalEventHandler;
  143.                 }
  144.             }
  145.         }
  146.        
  147.         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.IsCompiled"]/*' />
  148.         /// <devdoc>
  149.         /// <para>IsCompiled is true when the schema set is in compiled state</para>
  150.         /// </devdoc>
  151.         public bool IsCompiled {
  152.             get { return isCompiled; }
  153.         }
  154.        
  155.         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.XmlResolver"]/*' />
  156.         /// <devdoc>
  157.         /// <para></para>
  158.         /// </devdoc>
  159.         public XmlResolver XmlResolver {
  160.             set { readerSettings.XmlResolver = value; }
  161.         }
  162.        
  163.         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.CompilationSettings"]/*' />
  164.         /// <devdoc>
  165.         /// <para></para>
  166.         /// </devdoc>
  167.         public XmlSchemaCompilationSettings CompilationSettings {
  168.             get { return compilationSettings; }
  169.             set { compilationSettings = value; }
  170.         }
  171.        
  172.         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Count"]/*' />
  173.         /// <devdoc>
  174.         /// <para>Returns the count of schemas in the set</para>
  175.         /// </devdoc>
  176.         public int Count {
  177.             get { return schemas.Count; }
  178.         }
  179.         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.GlobalElements"]/*' />
  180.         /// <devdoc>
  181.         /// <para></para>
  182.         /// </devdoc>
  183.         public XmlSchemaObjectTable GlobalElements {
  184.             get {
  185.                 if (elements == null) {
  186.                     elements = new XmlSchemaObjectTable();
  187.                 }
  188.                 return elements;
  189.             }
  190.         }
  191.        
  192.         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.GlobalAttributes"]/*' />
  193.         /// <devdoc>
  194.         /// <para></para>
  195.         /// </devdoc>
  196.         public XmlSchemaObjectTable GlobalAttributes {
  197.             get {
  198.                 if (attributes == null) {
  199.                     attributes = new XmlSchemaObjectTable();
  200.                 }
  201.                 return attributes;
  202.             }
  203.         }
  204.        
  205.         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.GlobalTypes"]/*' />
  206.         /// <devdoc>
  207.         /// <para></para>
  208.         /// </devdoc>
  209.         public XmlSchemaObjectTable GlobalTypes {
  210.             get {
  211.                 if (schemaTypes == null) {
  212.                     schemaTypes = new XmlSchemaObjectTable();
  213.                 }
  214.                 return schemaTypes;
  215.             }
  216.         }
  217.        
  218.         internal XmlSchemaObjectTable SubstitutionGroups {
  219.             get {
  220.                 if (substitutionGroups == null) {
  221.                     substitutionGroups = new XmlSchemaObjectTable();
  222.                 }
  223.                 return substitutionGroups;
  224.             }
  225.         }
  226.        
  227.         /// <summary>
  228.         /// Table of all types extensions
  229.         /// </summary>
  230.         internal Hashtable SchemaLocations {
  231.             get { return schemaLocations; }
  232.         }
  233.        
  234.         /// <summary>
  235.         /// Table of all types extensions
  236.         /// </summary>
  237.         internal XmlSchemaObjectTable TypeExtensions {
  238.             get {
  239.                 if (typeExtensions == null) {
  240.                     typeExtensions = new XmlSchemaObjectTable();
  241.                 }
  242.                 return typeExtensions;
  243.             }
  244.         }
  245.         //Public Methods
  246.        
  247.         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Add1"]/*' />
  248.         /// <devdoc>
  249.         /// <para>Add the schema located by the given URL into the schema schemas.
  250.         /// If the given schema references other namespaces, the schemas for those other
  251.         /// namespaces are NOT automatically loaded.</para>
  252.         /// </devdoc>
  253.         public XmlSchema Add(string targetNamespace, string schemaUri)
  254.         {
  255.             if (schemaUri == null || schemaUri.Length == 0) {
  256.                 throw new ArgumentNullException("schemaUri");
  257.             }
  258.             if (targetNamespace != null) {
  259.                 targetNamespace = XmlComplianceUtil.CDataNormalize(targetNamespace);
  260.             }
  261.             XmlSchema schema = null;
  262.             lock (InternalSyncObject) {
  263.                 //Check if schema from url has already been added
  264.                 XmlResolver tempResolver = readerSettings.GetXmlResolver();
  265.                 if (tempResolver == null) {
  266.                     tempResolver = new XmlUrlResolver();
  267.                 }
  268.                 Uri tempSchemaUri = tempResolver.ResolveUri(null, schemaUri);
  269.                 if (IsSchemaLoaded(tempSchemaUri, targetNamespace, out schema)) {
  270.                     return schema;
  271.                 }
  272.                 else {
  273.                     //Url already not processed; Load SOM from url
  274.                     XmlReader reader = XmlReader.Create(schemaUri, readerSettings);
  275.                     try {
  276.                         schema = Add(targetNamespace, ParseSchema(targetNamespace, reader));
  277.                         //TODO can move parsing outside lock boundary
  278.                         while (reader.Read())
  279.                             ;
  280.                         // wellformness check;
  281.                     }
  282.                     finally {
  283.                         reader.Close();
  284.                     }
  285.                 }
  286.             }
  287.             return schema;
  288.         }
  289.        
  290.        
  291.         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Add4"]/*' />
  292.         /// <devdoc>
  293.         /// <para>Add the given schema into the schema schemas.
  294.         /// If the given schema references other namespaces, the schemas for those
  295.         /// other namespaces are NOT automatically loaded.</para>
  296.         /// </devdoc>
  297.         public XmlSchema Add(string targetNamespace, XmlReader schemaDocument)
  298.         {
  299.             if (schemaDocument == null) {
  300.                 throw new ArgumentNullException("schemaDocument");
  301.             }
  302.             if (targetNamespace != null) {
  303.                 targetNamespace = XmlComplianceUtil.CDataNormalize(targetNamespace);
  304.             }
  305.             lock (InternalSyncObject) {
  306.                 XmlSchema schema = null;
  307.                 Uri schemaUri = new Uri(schemaDocument.BaseURI, UriKind.RelativeOrAbsolute);
  308.                 if (IsSchemaLoaded(schemaUri, targetNamespace, out schema)) {
  309.                     return schema;
  310.                 }
  311.                 else {
  312.                     bool prohibitDtd = this.readerSettings.ProhibitDtd;
  313.                     SetProhibitDtd(schemaDocument);
  314.                     schema = Add(targetNamespace, ParseSchema(targetNamespace, schemaDocument));
  315.                     this.readerSettings.ProhibitDtd = prohibitDtd;
  316.                     //reset prohibitDTD flag
  317.                     return schema;
  318.                 }
  319.             }
  320.         }
  321.        
  322.        
  323.         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Add5"]/*' />
  324.         /// <devdoc>
  325.         /// <para>Adds all the namespaces defined in the given schemas
  326.         /// (including their associated schemas) to this schemas.</para>
  327.         /// </devdoc>
  328.         public void Add(XmlSchemaSet schemas)
  329.         {
  330.             if (schemas == null) {
  331.                 throw new ArgumentNullException("schemas");
  332.             }
  333.             if (this == schemas) {
  334.                 return;
  335.             }
  336.             bool lockObtained = false;
  337.             try {
  338.                 while (true) {
  339.                     if (Monitor.TryEnter(InternalSyncObject)) {
  340.                         if (Monitor.TryEnter(schemas.InternalSyncObject)) {
  341.                             lockObtained = true;
  342.                             break;
  343.                         }
  344.                         else {
  345.                             Monitor.Exit(InternalSyncObject);
  346.                             //Give up this lock and try both again
  347.                             continue;
  348.                         }
  349.                     }
  350.                 }
  351.                
  352.                 XmlSchema currentSchema;
  353.                 //TODO Need to copy chameleon Schemas and schemaLocations from other set
  354.                 if (schemas.IsCompiled) {
  355.                     CopyFromCompiledSet(schemas);
  356.                 }
  357.                 else {
  358.                     bool remove = false;
  359.                     string tns = null;
  360.                     foreach (XmlSchema schema in schemas.SortedSchemas.Values) {
  361.                         tns = schema.TargetNamespace;
  362.                         if (tns == null) {
  363.                             tns = string.Empty;
  364.                         }
  365.                         if (this.schemas.ContainsKey(schema.SchemaId) || FindSchemaByNSAndUrl(schema.BaseUri, tns, null) != null) {
  366.                             //Do not already existing url
  367.                             continue;
  368.                         }
  369.                         currentSchema = Add(schema.TargetNamespace, schema);
  370.                         if (currentSchema == null) {
  371.                             remove = true;
  372.                             break;
  373.                         }
  374.                     }
  375.                     //Remove all from the set if even one schema in the passed in set is not preprocessed.
  376.                     if (remove) {
  377.                         foreach (XmlSchema schema in schemas.SortedSchemas.Values) {
  378.                             //Remove all previously added schemas from the set
  379.                             this.schemas.Remove(schema.SchemaId);
  380.                             //Might remove schema that was already there and was not added thru this operation
  381.                             schemaLocations.Remove(schema.BaseUri);
  382.                         }
  383.                     }
  384.                 }
  385.             }
  386.             finally {
  387.                 //release locks on sets
  388.                 if (lockObtained) {
  389.                     Monitor.Exit(InternalSyncObject);
  390.                     Monitor.Exit(schemas.InternalSyncObject);
  391.                 }
  392.             }
  393.         }
  394.        
  395.         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Add6"]/*' />
  396.         public XmlSchema Add(XmlSchema schema)
  397.         {
  398.             if (schema == null) {
  399.                 throw new ArgumentNullException("schema");
  400.             }
  401.             lock (InternalSyncObject) {
  402.                 if (schemas.ContainsKey(schema.SchemaId)) {
  403.                     return schema;
  404.                 }
  405.                 return Add(schema.TargetNamespace, schema);
  406.             }
  407.         }
  408.        
  409.         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Remove"]/*' />
  410.         public XmlSchema Remove(XmlSchema schema)
  411.         {
  412.             return Remove(schema, true);
  413.         }
  414.        
  415.         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.RemoveRecursive"]/*' />
  416.         public bool RemoveRecursive(XmlSchema schemaToRemove)
  417.         {
  418.            
  419.             if (schemaToRemove == null) {
  420.                 throw new ArgumentNullException("schemaToRemove");
  421.             }
  422.             if (!schemas.ContainsKey(schemaToRemove.SchemaId)) {
  423.                 return false;
  424.             }
  425.            
  426.             lock (InternalSyncObject) {
  427.                 //Need to lock here so that remove cannot be called while the set is being compiled
  428.                 if (schemas.ContainsKey(schemaToRemove.SchemaId)) {
  429.                     //Need to check again
  430.                     //Build disallowedNamespaces list
  431.                     Hashtable disallowedNamespaces = new Hashtable();
  432.                     disallowedNamespaces.Add(GetTargetNamespace(schemaToRemove), schemaToRemove);
  433.                     string importedNS;
  434.                     for (int i = 0; i < schemaToRemove.ImportedNamespaces.Count; i++) {
  435.                         importedNS = (string)schemaToRemove.ImportedNamespaces[i];
  436.                         if (disallowedNamespaces[importedNS] == null) {
  437.                             disallowedNamespaces.Add(importedNS, importedNS);
  438.                         }
  439.                     }
  440.                    
  441.                     //Removal list is all schemas imported by this schema directly or indirectly
  442.                     //Need to check if other schemas in the set import schemaToRemove / any of its imports
  443.                     ArrayList needToCheckSchemaList = new ArrayList();
  444.                     XmlSchema mainSchema;
  445.                     for (int i = 0; i < schemas.Count; i++) {
  446.                         mainSchema = (XmlSchema)schemas.GetByIndex(i);
  447.                         if (mainSchema == schemaToRemove || schemaToRemove.ImportedSchemas.Contains(mainSchema)) {
  448.                             continue;
  449.                         }
  450.                         needToCheckSchemaList.Add(mainSchema);
  451.                     }
  452.                    
  453.                     mainSchema = null;
  454.                     for (int i = 0; i < needToCheckSchemaList.Count; i++) {
  455.                         //Perf: Not using nested foreach here
  456.                         mainSchema = (XmlSchema)needToCheckSchemaList[i];
  457.                        
  458.                         if (mainSchema.ImportedNamespaces.Count > 0) {
  459.                             foreach (string tns in disallowedNamespaces.Keys) {
  460.                                 if (mainSchema.ImportedNamespaces.Contains(tns)) {
  461.                                     SendValidationEvent(new XmlSchemaException(Res.Sch_SchemaNotRemoved, string.Empty), XmlSeverityType.Warning);
  462.                                     return false;
  463.                                 }
  464.                             }
  465.                         }
  466.                     }
  467.                    
  468.                     RemoveSchemaFromGlobalTables(schemaToRemove);
  469.                     Remove(schemaToRemove, false);
  470.                     foreach (XmlSchema impSchema in schemaToRemove.ImportedSchemas) {
  471.                         RemoveSchemaFromGlobalTables(impSchema);
  472.                         Remove(impSchema, false);
  473.                     }
  474.                     return true;
  475.                 }
  476.             }
  477.             return false;
  478.         }
  479.        
  480.         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Contains1"]/*' />
  481.         public bool Contains(string targetNamespace)
  482.         {
  483.             if (targetNamespace == null) {
  484.                 targetNamespace = string.Empty;
  485.             }
  486.             return targetNamespaces[targetNamespace] != null;
  487.         }
  488.        
  489.         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Contains2"]/*' />
  490.         public bool Contains(XmlSchema schema)
  491.         {
  492.             if (schema == null) {
  493.                 throw new ArgumentNullException("schema");
  494.             }
  495.             return schemas.ContainsValue(schema);
  496.         }
  497.        
  498.         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Compile"]/*' />
  499.         /// <devdoc>
  500.         /// <para>[To be supplied.]</para>
  501.         /// </devdoc>
  502.         public void Compile()
  503.         {
  504.             if (schemas.Count == 0) {
  505.                 ClearTables();
  506.                 //Clear any previously present compiled state left by calling just Remove() on the set
  507.                 return;
  508.             }
  509.             if (isCompiled) {
  510.                 return;
  511.             }
  512.             lock (InternalSyncObject) {
  513.                
  514.                 if (!isCompiled) {
  515.                     //Locking before checking isCompiled to avoid problems with double locking
  516.                     Compiler compiler = new Compiler(nameTable, eventHandler, schemaForSchema, compilationSettings);
  517.                     SchemaInfo newCompiledInfo = new SchemaInfo();
  518.                     int schemaIndex = 0;
  519.                     if (!compileAll) {
  520.                         //if we are not compiling everything again, Move the pre-compiled schemas to the compiler's tables
  521.                         compiler.ImportAllCompiledSchemas(this);
  522.                     }
  523.                     try {
  524.                         //First thing to do in the try block is to acquire locks since finally will try to release them.
  525.                         //If we dont accuire the locks first, and an exception occurs in the code before the locking code, then Threading.SynchronizationLockException will be thrown
  526.                         //when attempting to release it in the finally block
  527.                         XmlSchema currentSchema;
  528.                         XmlSchema xmlNSSchema = Preprocessor.GetBuildInSchema();
  529.                         for (schemaIndex = 0; schemaIndex < schemas.Count; schemaIndex++) {
  530.                             currentSchema = (XmlSchema)schemas.GetByIndex(schemaIndex);
  531.                            
  532.                             //Lock schema to be compiled
  533.                             Monitor.Enter(currentSchema);
  534.                             if (!currentSchema.IsPreprocessed) {
  535.                                 SendValidationEvent(new XmlSchemaException(Res.Sch_SchemaNotPreprocessed, string.Empty), XmlSeverityType.Error);
  536.                                 isCompiled = false;
  537.                                 return;
  538.                             }
  539.                             if (currentSchema.IsCompiledBySet) {
  540.                                 if (!compileAll) {
  541.                                     continue;
  542.                                 }
  543.                                 else if ((object)currentSchema == (object)xmlNSSchema) {
  544.                                     // prepare for xml namespace schema without cleanup
  545.                                     compiler.Prepare(currentSchema, false);
  546.                                     continue;
  547.                                 }
  548.                             }
  549.                             compiler.Prepare(currentSchema, true);
  550.                         }
  551.                        
  552.                         isCompiled = compiler.Execute(this, newCompiledInfo);
  553.                         if (isCompiled) {
  554.                             compileAll = false;
  555.                             newCompiledInfo.Add(cachedCompiledInfo, eventHandler);
  556.                             //Add all the items from the old to the new compiled object
  557.                             cachedCompiledInfo = newCompiledInfo;
  558.                             //Replace the compiled info in the set after successful compilation
  559.                         }
  560.                     }
  561.                     finally {
  562.                         //Release locks on all schemas
  563.                         XmlSchema currentSchema;
  564.                         if (schemaIndex == schemas.Count) {
  565.                             schemaIndex--;
  566.                         }
  567.                         for (int i = schemaIndex; i >= 0; i--) {
  568.                             currentSchema = (XmlSchema)schemas.GetByIndex(i);
  569.                             if (currentSchema == Preprocessor.GetBuildInSchema()) {
  570.                                 //dont re-set compiled flags for xml namespace schema
  571.                                 Monitor.Exit(currentSchema);
  572.                                 continue;
  573.                             }
  574.                             currentSchema.IsCompiledBySet = isCompiled;
  575.                             Monitor.Exit(currentSchema);
  576.                         }
  577.                     }
  578.                 }
  579.             }
  580.             return;
  581.         }
  582.        
  583.         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Reprocess"]/*' />
  584.         /// <devdoc>
  585.         /// <para>[To be supplied.]</para>
  586.         /// </devdoc>
  587.         public XmlSchema Reprocess(XmlSchema schema)
  588.         {
  589.             if (schema == null) {
  590.                 throw new ArgumentNullException("schema");
  591.             }
  592.             if (!schemas.ContainsKey(schema.SchemaId)) {
  593.                 throw new ArgumentException(Res.GetString(Res.Sch_SchemaDoesNotExist), "schema");
  594.             }
  595.             lock (InternalSyncObject) {
  596.                 //Lock set so that set cannot be compiled in another thread
  597.                 RemoveSchemaFromCaches(schema);
  598.                 PreprocessSchema(ref schema, schema.TargetNamespace);
  599.                 //TODO cd optimize to not process externals again
  600.                 foreach (XmlSchema s in schema.ImportedSchemas) {
  601.                     //Once preprocessed external schemas property is set
  602.                     if (!schemas.ContainsKey(s.SchemaId)) {
  603.                         schemas.Add(s.SchemaId, s);
  604.                     }
  605.                     string tns = GetTargetNamespace(s);
  606.                     if (targetNamespaces[tns] == null) {
  607.                         targetNamespaces.Add(tns, tns);
  608.                     }
  609.                 }
  610.                 isCompiled = false;
  611.             }
  612.             return schema;
  613.         }
  614.        
  615.         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.CopyTo"]/*' />
  616.         /// <devdoc>
  617.         /// <para>[To be supplied.]</para>
  618.         /// </devdoc>
  619.         public void CopyTo(XmlSchema[] schemas, int index)
  620.         {
  621.             if (schemas == null)
  622.                 throw new ArgumentNullException("schemas");
  623.             if (index < 0 || index > schemas.Length - 1)
  624.                 throw new ArgumentOutOfRangeException("index");
  625.             this.schemas.Values.CopyTo(schemas, index);
  626.         }
  627.        
  628.         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Schemas1"]/*' />
  629.         /// <devdoc>
  630.         /// <para>[To be supplied.]</para>
  631.         /// </devdoc>
  632.         public ICollection Schemas()
  633.         {
  634.             return schemas.Values;
  635.         }
  636.        
  637.         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Schemas1"]/*' />
  638.         /// <devdoc>
  639.         /// <para>[To be supplied.]</para>
  640.         /// </devdoc>
  641.         public ICollection Schemas(string targetNamespace)
  642.         {
  643.             ArrayList tnsSchemas = new ArrayList();
  644.             XmlSchema currentSchema;
  645.             if (targetNamespace == null) {
  646.                 targetNamespace = string.Empty;
  647.             }
  648.             for (int i = 0; i < schemas.Count; i++) {
  649.                 currentSchema = (XmlSchema)schemas.GetByIndex(i);
  650.                 if (GetTargetNamespace(currentSchema) == targetNamespace) {
  651.                     tnsSchemas.Add(currentSchema);
  652.                 }
  653.             }
  654.             return tnsSchemas;
  655.         }
  656.        
  657.         //Internal Methods
  658.        
  659.        
  660.         internal XmlSchema Add(string targetNamespace, XmlSchema schema)
  661.         {
  662.             if (schema == null || schema.ErrorCount != 0) {
  663.                 //Schema with parsing errors cannot be loaded
  664.                 return null;
  665.             }
  666.             if (PreprocessSchema(ref schema, targetNamespace)) {
  667.                 //No perf opt for already compiled schemas
  668.                 AddSchemaToSet(schema);
  669.                 isCompiled = false;
  670.                 return schema;
  671.             }
  672.             return null;
  673.         }
  674.        
  675.        
  676.         //For use by the validator when loading schemaLocations in the instance
  677.         internal void Add(string targetNamespace, XmlReader reader, Hashtable validatedNamespaces)
  678.         {
  679.             if (reader == null) {
  680.                 throw new ArgumentNullException("reader");
  681.             }
  682.             if (targetNamespace == null) {
  683.                 targetNamespace = string.Empty;
  684.             }
  685.             if (validatedNamespaces[targetNamespace] != null) {
  686.                 if (FindSchemaByNSAndUrl(new Uri(reader.BaseURI, UriKind.RelativeOrAbsolute), targetNamespace, null) != null) {
  687.                     return;
  688.                 }
  689.                 else {
  690.                     throw new XmlSchemaException(Res.Sch_ComponentAlreadySeenForNS, targetNamespace);
  691.                 }
  692.             }
  693.            
  694.             //Not locking set as this will not be accessible outside the validator
  695.             XmlSchema schema;
  696.             if (IsSchemaLoaded(new Uri(reader.BaseURI, UriKind.RelativeOrAbsolute), targetNamespace, out schema)) {
  697.                 return;
  698.             }
  699.             else {
  700.                 //top-level schema not present for same url
  701.                 schema = ParseSchema(targetNamespace, reader);
  702.                
  703.                 //Store the previous locations
  704.                 DictionaryEntry[] oldLocations = new DictionaryEntry[schemaLocations.Count];
  705.                 schemaLocations.CopyTo(oldLocations, 0);
  706.                
  707.                 //Add to set
  708.                 Add(targetNamespace, schema);
  709.                 if (schema.ImportedSchemas.Count > 0) {
  710.                     //Check imports
  711.                     string tns;
  712.                     foreach (XmlSchema impSchema in schema.ImportedSchemas) {
  713.                         tns = impSchema.TargetNamespace;
  714.                         if (tns == null) {
  715.                             tns = string.Empty;
  716.                         }
  717.                         if (validatedNamespaces[tns] != null && (FindSchemaByNSAndUrl(impSchema.BaseUri, tns, oldLocations) == null)) {
  718.                             RemoveRecursive(schema);
  719.                             throw new XmlSchemaException(Res.Sch_ComponentAlreadySeenForNS, tns);
  720.                         }
  721.                     }
  722.                 }
  723.             }
  724.         }
  725.        
  726.         internal XmlSchema FindSchemaByNSAndUrl(Uri schemaUri, string ns, DictionaryEntry[] locationsTable)
  727.         {
  728.             if (schemaUri == null || schemaUri.OriginalString.Length == 0) {
  729.                 return null;
  730.             }
  731.             XmlSchema schema = null;
  732.             if (locationsTable == null) {
  733.                 schema = (XmlSchema)schemaLocations[schemaUri];
  734.             }
  735.             else {
  736.                 for (int i = 0; i < locationsTable.Length; i++) {
  737.                     if (schemaUri.Equals(locationsTable[i].Key)) {
  738.                         schema = (XmlSchema)locationsTable[i].Value;
  739.                         break;
  740.                     }
  741.                 }
  742.             }
  743.             if (schema != null) {
  744.                 Debug.Assert(ns != null);
  745.                 string tns = schema.TargetNamespace == null ? string.Empty : schema.TargetNamespace;
  746.                 if (tns == ns) {
  747.                     return schema;
  748.                 }
  749.                 else if (tns == string.Empty) {
  750.                     //There could be a chameleon for same ns
  751.                     ChameleonKey cKey = new ChameleonKey(ns, schemaUri);
  752.                     schema = (XmlSchema)chameleonSchemas[cKey];
  753.                     //Need not clone if a schema for that namespace already exists
  754.                 }
  755.                 else {
  756.                     schema = null;
  757.                 }
  758.             }
  759.             return schema;
  760.         }
  761.        
  762.         private void SetProhibitDtd(XmlReader reader)
  763.         {
  764.             if (reader.Settings != null) {
  765.                 this.readerSettings.ProhibitDtd = reader.Settings.ProhibitDtd;
  766.             }
  767.             else {
  768.                 XmlTextReader v1Reader = reader as XmlTextReader;
  769.                 if (v1Reader != null) {
  770.                     this.readerSettings.ProhibitDtd = v1Reader.ProhibitDtd;
  771.                 }
  772.             }
  773.         }
  774.        
  775.         private void AddSchemaToSet(XmlSchema schema)
  776.         {
  777.             schemas.Add(schema.SchemaId, schema);
  778.             //Add to targetNamespaces table
  779.             string tns = GetTargetNamespace(schema);
  780.             if (targetNamespaces[tns] == null) {
  781.                 targetNamespaces.Add(tns, tns);
  782.             }
  783.             if (schemaForSchema == null && tns == XmlReservedNs.NsXs && schema.SchemaTypes[DatatypeImplementation.QnAnyType] != null) {
  784.                 //it has xs:anyType
  785.                 schemaForSchema = schema;
  786.             }
  787.             foreach (XmlSchema s in schema.ImportedSchemas) {
  788.                 //Once preprocessed external schemas property is set
  789.                 if (!schemas.ContainsKey(s.SchemaId)) {
  790.                     schemas.Add(s.SchemaId, s);
  791.                 }
  792.                 tns = GetTargetNamespace(s);
  793.                 if (targetNamespaces[tns] == null) {
  794.                     targetNamespaces.Add(tns, tns);
  795.                 }
  796.                 if (schemaForSchema == null && tns == XmlReservedNs.NsXs && schema.SchemaTypes[DatatypeImplementation.QnAnyType] != null) {
  797.                     //it has xs:anyType
  798.                     schemaForSchema = schema;
  799.                 }
  800.             }
  801.         }
  802.        
  803.         private void ProcessNewSubstitutionGroups(XmlSchemaObjectTable substitutionGroupsTable, bool resolve)
  804.         {
  805.             foreach (XmlSchemaSubstitutionGroup substGroup in substitutionGroupsTable.Values) {
  806.                 if (resolve) {
  807.                     //Resolve substitutionGroups within this schema
  808.                     ResolveSubstitutionGroup(substGroup, substitutionGroupsTable);
  809.                 }
  810.                
  811.                 //Add or Merge new substitutionGroups with those that already exist in the set
  812.                 XmlQualifiedName head = substGroup.Examplar;
  813.                 XmlSchemaSubstitutionGroup oldSubstGroup = (XmlSchemaSubstitutionGroup)substitutionGroups[head];
  814.                 if (oldSubstGroup != null) {
  815.                     foreach (XmlSchemaElement member in substGroup.Members) {
  816.                         if (!oldSubstGroup.Members.Contains(member)) {
  817.                             oldSubstGroup.Members.Add(member);
  818.                         }
  819.                     }
  820.                 }
  821.                 else {
  822.                     AddToTable(substitutionGroups, head, substGroup);
  823.                 }
  824.             }
  825.         }
  826.        
  827.         private void ResolveSubstitutionGroup(XmlSchemaSubstitutionGroup substitutionGroup, XmlSchemaObjectTable substTable)
  828.         {
  829.             ArrayList newMembers = null;
  830.             XmlSchemaElement headElement = (XmlSchemaElement)elements[substitutionGroup.Examplar];
  831.             if (substitutionGroup.Members.Contains(headElement)) {
  832.                 // already checked
  833.                 return;
  834.             }
  835.             foreach (XmlSchemaElement element in substitutionGroup.Members) {
  836.                 //Chain to other head's that are members of this head's substGroup
  837.                 XmlSchemaSubstitutionGroup g = (XmlSchemaSubstitutionGroup)substTable[element.QualifiedName];
  838.                 if (g != null) {
  839.                     ResolveSubstitutionGroup(g, substTable);
  840.                     foreach (XmlSchemaElement element1 in g.Members) {
  841.                         if (element1 != element) {
  842.                             //Exclude the head
  843.                             if (newMembers == null) {
  844.                                 newMembers = new ArrayList();
  845.                             }
  846.                             newMembers.Add(element1);
  847.                         }
  848.                     }
  849.                 }
  850.             }
  851.             if (newMembers != null) {
  852.                 foreach (XmlSchemaElement newMember in newMembers) {
  853.                     substitutionGroup.Members.Add(newMember);
  854.                 }
  855.             }
  856.             substitutionGroup.Members.Add(headElement);
  857.         }
  858.        
  859.         internal XmlSchema Remove(XmlSchema schema, bool forceCompile)
  860.         {
  861.             if (schema == null) {
  862.                 throw new ArgumentNullException("schema");
  863.             }
  864.             lock (InternalSyncObject) {
  865.                 //Need to lock here so that remove cannot be called while the set is being compiled
  866.                 if (schemas.ContainsKey(schema.SchemaId)) {
  867.                     schemas.Remove(schema.SchemaId);
  868.                     if (schema.BaseUri != null) {
  869.                         schemaLocations.Remove(schema.BaseUri);
  870.                     }
  871.                     string tns = GetTargetNamespace(schema);
  872.                     if (Schemas(tns).Count == 0) {
  873.                         //This is the only schema for that namespace
  874.                         targetNamespaces.Remove(tns);
  875.                     }
  876.                     if (forceCompile) {
  877.                         isCompiled = false;
  878.                         compileAll = true;
  879.                         //Force compilation of the whole set; This is when the set is not completely thread-safe
  880.                     }
  881.                     return schema;
  882.                 }
  883.             }
  884.             return null;
  885.         }
  886.        
  887.         private void ClearTables()
  888.         {
  889.             GlobalElements.Clear();
  890.             GlobalAttributes.Clear();
  891.             GlobalTypes.Clear();
  892.             SubstitutionGroups.Clear();
  893.             TypeExtensions.Clear();
  894.         }
  895.        
  896.         internal bool PreprocessSchema(ref XmlSchema schema, string targetNamespace)
  897.         {
  898.             Preprocessor prep = new Preprocessor(nameTable, GetSchemaNames(nameTable), eventHandler, compilationSettings);
  899.             prep.XmlResolver = readerSettings.GetXmlResolver();
  900.             prep.ReaderSettings = readerSettings;
  901.             prep.SchemaLocations = schemaLocations;
  902.             prep.ChameleonSchemas = chameleonSchemas;
  903.             bool hasErrors = prep.Execute(schema, targetNamespace, true);
  904.             schema = prep.RootSchema;
  905.             //For any root level chameleon cloned
  906.             return hasErrors;
  907.         }
  908.        
  909.         internal XmlSchema ParseSchema(string targetNamespace, XmlReader reader)
  910.         {
  911.             XmlNameTable readerNameTable = reader.NameTable;
  912.             SchemaNames schemaNames = GetSchemaNames(readerNameTable);
  913.             Parser parser = new Parser(SchemaType.XSD, readerNameTable, schemaNames, eventHandler);
  914.             parser.XmlResolver = readerSettings.GetXmlResolver();
  915.             SchemaType schemaType;
  916.             try {
  917.                 schemaType = parser.Parse(reader, targetNamespace);
  918.             }
  919.             catch (XmlSchemaException e) {
  920.                 SendValidationEvent(e, XmlSeverityType.Error);
  921.                 return null;
  922.             }
  923.             return parser.XmlSchema;
  924.         }
  925.        
  926.         internal void CopyFromCompiledSet(XmlSchemaSet otherSet)
  927.         {
  928.             XmlSchema currentSchema;
  929.             SortedList copyFromList = otherSet.SortedSchemas;
  930.             bool setIsCompiled = schemas.Count == 0 ? true : false;
  931.             ArrayList existingSchemas = new ArrayList();
  932.            
  933.             SchemaInfo newCompiledInfo = new SchemaInfo();
  934.             Uri baseUri;
  935.             for (int i = 0; i < copyFromList.Count; i++) {
  936.                 currentSchema = (XmlSchema)copyFromList.GetByIndex(i);
  937.                 baseUri = currentSchema.BaseUri;
  938.                 if (schemas.ContainsKey(currentSchema.SchemaId) || (baseUri != null && baseUri.OriginalString.Length != 0 && schemaLocations[baseUri] != null)) {
  939.                     existingSchemas.Add(currentSchema);
  940.                     continue;
  941.                 }
  942.                 schemas.Add(currentSchema.SchemaId, currentSchema);
  943.                 if (baseUri != null && baseUri.OriginalString.Length != 0) {
  944.                     schemaLocations.Add(baseUri, currentSchema);
  945.                 }
  946.                 string tns = GetTargetNamespace(currentSchema);
  947.                 if (targetNamespaces[tns] == null) {
  948.                     targetNamespaces.Add(tns, tns);
  949.                 }
  950.             }
  951.            
  952.             VerifyTables();
  953.             foreach (XmlSchemaElement element in otherSet.GlobalElements.Values) {
  954.                 if (!AddToTable(elements, element.QualifiedName, element)) {
  955.                     goto RemoveAll;
  956.                 }
  957.             }
  958.             foreach (XmlSchemaAttribute attribute in otherSet.GlobalAttributes.Values) {
  959.                 if (!AddToTable(attributes, attribute.QualifiedName, attribute)) {
  960.                     goto RemoveAll;
  961.                 }
  962.             }
  963.             foreach (XmlSchemaType schemaType in otherSet.GlobalTypes.Values) {
  964.                 if (!AddToTable(schemaTypes, schemaType.QualifiedName, schemaType)) {
  965.                     goto RemoveAll;
  966.                 }
  967.             }
  968.             //TODO get otherSet's substitutionGroups
  969.             ProcessNewSubstitutionGroups(otherSet.SubstitutionGroups, false);
  970.            
  971.             newCompiledInfo.Add(cachedCompiledInfo, eventHandler);
  972.             //Add all the items from the old to the new compiled object
  973.             newCompiledInfo.Add(otherSet.CompiledInfo, eventHandler);
  974.             //TODO: Throw error on conflicting types that are not from the same schema / baseUri
  975.             cachedCompiledInfo = newCompiledInfo;
  976.             //Replace the compiled info in the set after successful compilation
  977.             if (setIsCompiled) {
  978.                 isCompiled = true;
  979.                 compileAll = false;
  980.             }
  981.             return;
  982.             RemoveAll:
  983.            
  984.             foreach (XmlSchema schemaToRemove in copyFromList.Values) {
  985.                 if (!existingSchemas.Contains(schemaToRemove)) {
  986.                     Remove(schemaToRemove, false);
  987.                 }
  988.             }
  989.             foreach (XmlSchemaElement elementToRemove in otherSet.GlobalElements.Values) {
  990.                 if (!existingSchemas.Contains((XmlSchema)elementToRemove.Parent)) {
  991.                     elements.Remove(elementToRemove.QualifiedName);
  992.                 }
  993.             }
  994.             foreach (XmlSchemaAttribute attributeToRemove in otherSet.GlobalAttributes.Values) {
  995.                 if (!existingSchemas.Contains((XmlSchema)attributeToRemove.Parent)) {
  996.                     attributes.Remove(attributeToRemove.QualifiedName);
  997.                 }
  998.             }
  999.             foreach (XmlSchemaType schemaTypeToRemove in otherSet.GlobalTypes.Values) {
  1000.                 if (!existingSchemas.Contains((XmlSchema)schemaTypeToRemove.Parent)) {
  1001.                     schemaTypes.Remove(schemaTypeToRemove.QualifiedName);
  1002.                 }
  1003.             }
  1004.         }
  1005.        
  1006.         internal SchemaInfo CompiledInfo {
  1007.             get { return cachedCompiledInfo; }
  1008.         }
  1009.        
  1010.         internal XmlReaderSettings ReaderSettings {
  1011.             get { return readerSettings; }
  1012.         }
  1013.        
  1014.         internal XmlResolver GetResolver()
  1015.         {
  1016.             return readerSettings.GetXmlResolver();
  1017.         }
  1018.        
  1019.         internal ValidationEventHandler GetEventHandler()
  1020.         {
  1021.             return eventHandler;
  1022.         }
  1023.        
  1024.         internal SchemaNames GetSchemaNames(XmlNameTable nt)
  1025.         {
  1026.             if (nameTable != nt) {
  1027.                 return new SchemaNames(nt);
  1028.             }
  1029.             else {
  1030.                 if (schemaNames == null) {
  1031.                     schemaNames = new SchemaNames(nameTable);
  1032.                 }
  1033.                 return schemaNames;
  1034.             }
  1035.         }
  1036.        
  1037.         internal bool IsSchemaLoaded(Uri schemaUri, string targetNamespace, out XmlSchema schema)
  1038.         {
  1039.             schema = null;
  1040.             if (targetNamespace == null) {
  1041.                 targetNamespace = string.Empty;
  1042.             }
  1043.             if (GetSchemaByUri(schemaUri, out schema)) {
  1044.                 if (schemas.ContainsKey(schema.SchemaId) && (targetNamespace.Length == 0 || targetNamespace == schema.TargetNamespace)) {
  1045.                     //schema is present in set
  1046.                     return true;
  1047.                 }
  1048.                 else if (schema.TargetNamespace == null) {
  1049.                     //If schema not in set or namespace doesnt match, then it might be a chameleon
  1050.                     XmlSchema chameleonSchema = FindSchemaByNSAndUrl(schemaUri, targetNamespace, null);
  1051.                     if (chameleonSchema != null && schemas.ContainsKey(chameleonSchema.SchemaId)) {
  1052.                         schema = chameleonSchema;
  1053.                     }
  1054.                     else {
  1055.                         schema = Add(targetNamespace, schema);
  1056.                     }
  1057.                     return true;
  1058.                 }
  1059.                 else if (targetNamespace.Length != 0 && targetNamespace != schema.TargetNamespace) {
  1060.                     SendValidationEvent(new XmlSchemaException(Res.Sch_MismatchTargetNamespaceEx, new string[] {targetNamespace, schema.TargetNamespace}), XmlSeverityType.Error);
  1061.                 }
  1062.                 else {
  1063.                     //If here, schema not present in set but in loc and (s.TNS != null || tns == null)
  1064.                     Debug.Assert(false);
  1065.                 }
  1066.             }
  1067.             return false;
  1068.         }
  1069.        
  1070.         internal bool GetSchemaByUri(Uri schemaUri, out XmlSchema schema)
  1071.         {
  1072.             schema = null;
  1073.             if (schemaUri == null || schemaUri.OriginalString.Length == 0) {
  1074.                 return false;
  1075.             }
  1076.             schema = (XmlSchema)schemaLocations[schemaUri];
  1077.             if (schema != null) {
  1078.                 return true;
  1079.             }
  1080.             return false;
  1081.         }
  1082.        
  1083.         internal string GetTargetNamespace(XmlSchema schema)
  1084.         {
  1085.             return schema.TargetNamespace == null ? string.Empty : schema.TargetNamespace;
  1086.         }
  1087.        
  1088.        
  1089.         internal SortedList SortedSchemas {
  1090.             get { return schemas; }
  1091.         }
  1092.        
  1093.         internal bool CompileAll {
  1094.             get { return compileAll; }
  1095.         }
  1096.        
  1097.         //Private Methods
  1098.         private void RemoveSchemaFromCaches(XmlSchema schema)
  1099.         {
  1100.             //Remove From ChameleonSchemas and schemaLocations cache
  1101.             List<XmlSchema> reprocessList = new List<XmlSchema>();
  1102.             schema.GetExternalSchemasList(reprocessList, schema);
  1103.             foreach (XmlSchema reprocessSchema in reprocessList) {
  1104.                 //Remove schema from schemaLocations & chameleonSchemas tables
  1105.                 if (reprocessSchema.BaseUri != null && reprocessSchema.BaseUri.OriginalString.Length != 0) {
  1106.                     schemaLocations.Remove(reprocessSchema.BaseUri);
  1107.                 }
  1108.                 //Remove from chameleon table
  1109.                 ICollection chameleonKeys = chameleonSchemas.Keys;
  1110.                 ArrayList removalList = new ArrayList();
  1111.                 foreach (ChameleonKey cKey in chameleonKeys) {
  1112.                     if (cKey.chameleonLocation.Equals(reprocessSchema.BaseUri)) {
  1113.                         removalList.Add(cKey);
  1114.                     }
  1115.                 }
  1116.                 foreach (ChameleonKey cKey in removalList) {
  1117.                     chameleonSchemas.Remove(cKey);
  1118.                 }
  1119.             }
  1120.            
  1121.         }
  1122.        
  1123.         private void RemoveSchemaFromGlobalTables(XmlSchema schema)
  1124.         {
  1125.             if (schemas.Count == 0) {
  1126.                 return;
  1127.             }
  1128.             VerifyTables();
  1129.             foreach (XmlSchemaElement elementToRemove in schema.Elements.Values) {
  1130.                 XmlSchemaElement elem = (XmlSchemaElement)elements[elementToRemove.QualifiedName];
  1131.                 if (elem == elementToRemove) {
  1132.                     elements.Remove(elementToRemove.QualifiedName);
  1133.                 }
  1134.             }
  1135.             foreach (XmlSchemaAttribute attributeToRemove in schema.Attributes.Values) {
  1136.                 XmlSchemaAttribute attr = (XmlSchemaAttribute)attributes[attributeToRemove.QualifiedName];
  1137.                 if (attr == attributeToRemove) {
  1138.                     attributes.Remove(attributeToRemove.QualifiedName);
  1139.                 }
  1140.             }
  1141.             foreach (XmlSchemaType schemaTypeToRemove in schema.SchemaTypes.Values) {
  1142.                 XmlSchemaType schemaType = (XmlSchemaType)schemaTypes[schemaTypeToRemove.QualifiedName];
  1143.                 if (schemaType == schemaTypeToRemove) {
  1144.                     schemaTypes.Remove(schemaTypeToRemove.QualifiedName);
  1145.                 }
  1146.             }
  1147.         }
  1148.         private bool AddToTable(XmlSchemaObjectTable table, XmlQualifiedName qname, XmlSchemaObject item)
  1149.         {
  1150.             if (qname.Name.Length == 0) {
  1151.                 return true;
  1152.             }
  1153.             XmlSchemaObject existingObject = (XmlSchemaObject)table[qname];
  1154.             if (existingObject != null) {
  1155.                 if (existingObject == item || existingObject.SourceUri == item.SourceUri) {
  1156.                     return true;
  1157.                 }
  1158.                 string code = string.Empty;
  1159.                 if (item is XmlSchemaComplexType) {
  1160.                     code = Res.Sch_DupComplexType;
  1161.                 }
  1162.                 else if (item is XmlSchemaSimpleType) {
  1163.                     code = Res.Sch_DupSimpleType;
  1164.                 }
  1165.                 else if (item is XmlSchemaElement) {
  1166.                     code = Res.Sch_DupGlobalElement;
  1167.                 }
  1168.                 else if (item is XmlSchemaAttribute) {
  1169.                     if (qname.Namespace == XmlReservedNs.NsXml) {
  1170.                         XmlSchema schemaForXmlNS = Preprocessor.GetBuildInSchema();
  1171.                         XmlSchemaObject builtInAttribute = schemaForXmlNS.Attributes[qname];
  1172.                         if (existingObject == builtInAttribute) {
  1173.                             //replace built-in one
  1174.                             table.Insert(qname, item);
  1175.                             return true;
  1176.                         }
  1177.                         else if (item == builtInAttribute) {
  1178.                             //trying to overwrite customer's component with built-in, ignore built-in
  1179.                             return true;
  1180.                         }
  1181.                     }
  1182.                     code = Res.Sch_DupGlobalAttribute;
  1183.                 }
  1184.                 SendValidationEvent(new XmlSchemaException(code, qname.ToString()), XmlSeverityType.Error);
  1185.                 return false;
  1186.             }
  1187.             else {
  1188.                 table.Add(qname, item);
  1189.                 return true;
  1190.             }
  1191.         }
  1192.        
  1193.         private void VerifyTables()
  1194.         {
  1195.             if (elements == null) {
  1196.                 elements = new XmlSchemaObjectTable();
  1197.             }
  1198.             if (attributes == null) {
  1199.                 attributes = new XmlSchemaObjectTable();
  1200.             }
  1201.             if (schemaTypes == null) {
  1202.                 schemaTypes = new XmlSchemaObjectTable();
  1203.             }
  1204.             if (substitutionGroups == null) {
  1205.                 substitutionGroups = new XmlSchemaObjectTable();
  1206.             }
  1207.         }
  1208.        
  1209.         private void InternalValidationCallback(object sender, ValidationEventArgs e)
  1210.         {
  1211.             if (e.Severity == XmlSeverityType.Error) {
  1212.                 throw e.Exception;
  1213.             }
  1214.         }
  1215.        
  1216.         private void SendValidationEvent(XmlSchemaException e, XmlSeverityType severity)
  1217.         {
  1218.             if (eventHandler != null) {
  1219.                 eventHandler(this, new ValidationEventArgs(e, severity));
  1220.             }
  1221.             else {
  1222.                 throw e;
  1223.             }
  1224.         }
  1225.     }
  1226.    
  1227. }

Developer Fusion