XmlSchemaSet.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ FX-1434 / FX-1434 / 1.0 / untmp / whidbey / REDBITS / ndp / fx / src / Xml / System / Xml / schema / XmlSchemaSet.cs / 2 / XmlSchemaSet.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
//-----------------------------------------------------------------------------
using System.Diagnostics; 
using System.Collections; 
using System.Threading;
using System.Collections.Generic; 

namespace System.Xml.Schema {
    /// 
    ///  
    ///    The XmlSchemaSet contains a set of namespace URI's.
    ///       Each namespace also have an associated private data cache 
    ///       corresponding to the XML-Data Schema or W3C XML Schema. 
    ///       The XmlSchemaSet will able to load only XSD schemas,
    ///       and compile them into an internal "cooked schema representation". 
    ///       The Validate method then uses this internal representation for
    ///       efficient runtime validation of any given subtree.
    /// 
    public class XmlSchemaSet { 
        XmlNameTable nameTable;
        SchemaNames schemaNames; 
        SortedList schemas;              // List of source schemas 

        //Event handling 
        ValidationEventHandler internalEventHandler;
        ValidationEventHandler eventHandler;

        bool isCompiled = false; 

        //Dictionary schemaLocations; 
        //Dictionary chameleonSchemas; 
        Hashtable schemaLocations;
        Hashtable chameleonSchemas; 

        Hashtable targetNamespaces;
        bool compileAll;
 
        //Cached Compiled Info
        SchemaInfo cachedCompiledInfo; 
 
        //Reader settings to parse schema
        XmlReaderSettings readerSettings; 
        XmlSchema schemaForSchema;  //Only one schema for schema per set

        //Schema compilation settings
        XmlSchemaCompilationSettings compilationSettings; 

        internal XmlSchemaObjectTable elements; 
        internal XmlSchemaObjectTable attributes; 
        internal XmlSchemaObjectTable schemaTypes;
        internal XmlSchemaObjectTable substitutionGroups; 
        private XmlSchemaObjectTable typeExtensions;

        //Thread safety
        private Object internalSyncObject; 
        internal Object InternalSyncObject {
            get { 
                if (internalSyncObject == null) { 
                    Object o = new Object();
                    Interlocked.CompareExchange(ref internalSyncObject, o, null); 
                }
                return internalSyncObject;
            }
        } 

//Constructors 
 
        /// 
        ///  
        ///    Construct a new empty schema schemas.
        /// 
        public XmlSchemaSet() : this(new NameTable()) {
        } 

        ///  
        ///  
        ///    Construct a new empty schema schemas with associated XmlNameTable.
        ///       The XmlNameTable is used when loading schemas 
        /// 
        public XmlSchemaSet(XmlNameTable nameTable) {
            if (nameTable == null) {
                throw new ArgumentNullException("nameTable"); 
            }
            this.nameTable = nameTable; 
            schemas = new SortedList(); 

            /*schemaLocations = new Dictionary(); 
            chameleonSchemas = new Dictionary();*/
            schemaLocations = new Hashtable();
            chameleonSchemas = new Hashtable();
            targetNamespaces = new Hashtable(); 
            internalEventHandler = new ValidationEventHandler(InternalValidationCallback);
            eventHandler = internalEventHandler; 
 
            readerSettings = new XmlReaderSettings();
            readerSettings.NameTable = nameTable; 
            readerSettings.ProhibitDtd = true;

            compilationSettings = new XmlSchemaCompilationSettings();
            cachedCompiledInfo = new SchemaInfo(); 
            compileAll = true;
        } 
 

//Public Properties 
        /// 
        /// 
        ///    The default XmlNameTable used by the XmlSchemaSet when loading new schemas.
        ///  
        public XmlNameTable NameTable {
            get { return nameTable;} 
        } 

        ///  
        public  event ValidationEventHandler ValidationEventHandler {
            add {
                eventHandler -= internalEventHandler;
                eventHandler += value; 
                if (eventHandler == null) {
                    eventHandler = internalEventHandler; 
                } 
            }
            remove { 
                eventHandler -= value;
                if (eventHandler == null) {
                    eventHandler = internalEventHandler;
                } 
            }
        } 
 
        /// 
        ///  
        ///    IsCompiled is true when the schema set is in compiled state
        /// 
        public bool IsCompiled {
            get { 
                return isCompiled;
            } 
        } 

        ///  
        /// 
        ///    
        /// 
        public XmlResolver XmlResolver { 
            set {
                readerSettings.XmlResolver = value; 
            } 
        }
 
        /// 
        /// 
        ///    
        ///  
        public XmlSchemaCompilationSettings CompilationSettings {
            get { 
                return compilationSettings; 
            }
            set { 
               compilationSettings = value;
            }
        }
 
        /// 
        ///  
        ///    Returns the count of schemas in the set 
        /// 
        public int Count { 
            get {
                return schemas.Count;
            }
        } 
        /// 
        ///  
        ///     
        /// 
        public XmlSchemaObjectTable GlobalElements { 
            get {
                if (elements == null) {
                    elements = new XmlSchemaObjectTable();
                } 
                return elements;
            } 
        } 

        ///  
        /// 
        ///    
        /// 
        public XmlSchemaObjectTable GlobalAttributes { 
            get {
                if (attributes == null) { 
                    attributes = new XmlSchemaObjectTable(); 
                }
                return attributes; 
            }
        }

        ///  
        /// 
        ///     
        ///  
        public XmlSchemaObjectTable GlobalTypes {
            get { 
                if (schemaTypes == null) {
                    schemaTypes = new XmlSchemaObjectTable();
                }
                return schemaTypes; 
            }
        } 
 
        /// 
        ///  
        ///    
        /// 
        ///
        internal XmlSchemaObjectTable SubstitutionGroups { 
            get {
                if (substitutionGroups == null) { 
                    substitutionGroups = new XmlSchemaObjectTable(); 
                }
                return substitutionGroups; 
            }
        }

        ///  
        /// Table of all types extensions
        ///  
        internal Hashtable SchemaLocations { 
            get {
                return schemaLocations; 
            }
        }

        ///  
        /// Table of all types extensions
        ///  
        internal XmlSchemaObjectTable TypeExtensions { 
            get {
                if (typeExtensions == null) { 
                    typeExtensions = new XmlSchemaObjectTable();
                }
                return typeExtensions;
            } 
        }
//Public Methods 
 
        /// 
        ///  
        ///    Add the schema located by the given URL into the schema schemas.
        ///       If the given schema references other namespaces, the schemas for those other
        ///       namespaces are NOT automatically loaded.
        ///  
        public XmlSchema Add(String targetNamespace, String schemaUri) {
            if (schemaUri == null || schemaUri.Length == 0) { 
                throw new ArgumentNullException("schemaUri"); 
            }
            if (targetNamespace != null) { 
                targetNamespace = XmlComplianceUtil.CDataNormalize(targetNamespace);
            }
            XmlSchema schema = null;
            lock (InternalSyncObject) { 
                //Check if schema from url has already been added
                XmlResolver tempResolver = readerSettings.GetXmlResolver(); 
                if ( tempResolver == null ) { 
                    tempResolver = new XmlUrlResolver();
                } 
                Uri tempSchemaUri = tempResolver.ResolveUri(null, schemaUri);
                if (IsSchemaLoaded(tempSchemaUri, targetNamespace, out schema)) {
                    return schema;
                } 
                else {
                    //Url already not processed; Load SOM from url 
                    XmlReader reader = XmlReader.Create(schemaUri, readerSettings); 
                    try {
                        schema = Add(targetNamespace, ParseSchema(targetNamespace, reader)); // 
                        while(reader.Read());// wellformness check;
                    }
                    finally {
                        reader.Close(); 
                    }
                } 
            } 
            return schema;
        } 


        /// 
        ///  
        ///    Add the given schema into the schema schemas.
        ///       If the given schema references other namespaces, the schemas for those 
        ///       other namespaces are NOT automatically loaded. 
        /// 
        public XmlSchema Add(String targetNamespace, XmlReader schemaDocument) { 
            if (schemaDocument == null) {
                throw new ArgumentNullException("schemaDocument");
            }
            if (targetNamespace != null) { 
                targetNamespace = XmlComplianceUtil.CDataNormalize(targetNamespace);
            } 
            lock (InternalSyncObject) { 
                XmlSchema schema = null;
                Uri schemaUri = new Uri(schemaDocument.BaseURI, UriKind.RelativeOrAbsolute); 
                if (IsSchemaLoaded(schemaUri, targetNamespace, out schema)) {
                    return schema;
                }
                else { 
                    bool prohibitDtd = this.readerSettings.ProhibitDtd;
                    SetProhibitDtd(schemaDocument); 
                    schema = Add(targetNamespace, ParseSchema(targetNamespace, schemaDocument)); 
                    this.readerSettings.ProhibitDtd = prohibitDtd; //reset prohibitDTD flag
                    return schema; 
                }
            }
        }
 

        ///  
        ///  
        ///    Adds all the namespaces defined in the given schemas
        ///       (including their associated schemas) to this schemas. 
        /// 
        public void Add(XmlSchemaSet schemas) {
            if (schemas == null) {
                throw new ArgumentNullException("schemas"); 
            }
            if (this == schemas) { 
                return; 
            }
            bool lockObtained = false; 
            try {
                while(true) {
                    if (Monitor.TryEnter(InternalSyncObject)) {
                        if (Monitor.TryEnter(schemas.InternalSyncObject)) { 
                            lockObtained = true;
                            break; 
                        } 
                        else {
                            Monitor.Exit(InternalSyncObject); //Give up this lock and try both again 
                            continue;
                        }
                    }
                } 

                XmlSchema currentSchema; 
                // 
                if (schemas.IsCompiled) {
                    CopyFromCompiledSet(schemas); 
                }
                else {
                    bool remove = false;
                    string tns = null; 
                    foreach(XmlSchema schema in schemas.SortedSchemas.Values) {
                        tns = schema.TargetNamespace; 
                        if (tns == null) { 
                            tns = string.Empty;
                        } 
                        if (this.schemas.ContainsKey(schema.SchemaId) || FindSchemaByNSAndUrl(schema.BaseUri, tns, null) != null) { //Do not already existing url
                            continue;
                        }
                        currentSchema = Add(schema.TargetNamespace, schema); 
                        if(currentSchema == null) {
                            remove = true; 
                            break; 
                        }
                    } 
                    //Remove all from the set if even one schema in the passed in set is not preprocessed.
                    if (remove) {
                        foreach(XmlSchema schema in schemas.SortedSchemas.Values) { //Remove all previously added schemas from the set
                            this.schemas.Remove(schema.SchemaId); //Might remove schema that was already there and was not added thru this operation 
                            schemaLocations.Remove(schema.BaseUri);
                        } 
                    } 
                }
            } 
            finally { //release locks on sets
                if (lockObtained) {
                    Monitor.Exit(InternalSyncObject);
                    Monitor.Exit(schemas.InternalSyncObject); 
                }
            } 
        } 

        ///  
        public XmlSchema Add(XmlSchema schema) {
            if (schema == null) {
                throw new ArgumentNullException("schema");
            } 
            lock (InternalSyncObject) {
                if (schemas.ContainsKey(schema.SchemaId)) { 
                    return schema; 
                }
                return Add(schema.TargetNamespace, schema); 
            }
        }

        ///  
        public XmlSchema Remove(XmlSchema schema) {
            return Remove(schema, true); 
        } 

        ///  
        public bool RemoveRecursive(XmlSchema schemaToRemove) {

            if (schemaToRemove == null) {
                throw new ArgumentNullException("schemaToRemove"); 
            }
            if (!schemas.ContainsKey(schemaToRemove.SchemaId)) { 
                return false; 
            }
 
            lock (InternalSyncObject) { //Need to lock here so that remove cannot be called while the set is being compiled
                if (schemas.ContainsKey(schemaToRemove.SchemaId)) { //Need to check again

                    //Build disallowedNamespaces list 
                    Hashtable disallowedNamespaces = new Hashtable();
                    disallowedNamespaces.Add(GetTargetNamespace(schemaToRemove), schemaToRemove); 
                    string importedNS; 
                    for (int i = 0; i < schemaToRemove.ImportedNamespaces.Count; i++) {
                        importedNS = (string)schemaToRemove.ImportedNamespaces[i]; 
                        if (disallowedNamespaces[importedNS] == null) {
                            disallowedNamespaces.Add(importedNS, importedNS);
                        }
                    } 

                    //Removal list is all schemas imported by this schema directly or indirectly 
                    //Need to check if other schemas in the set import schemaToRemove / any of its imports 
                    ArrayList needToCheckSchemaList = new ArrayList();
                    XmlSchema mainSchema; 
                    for (int i =0; i < schemas.Count; i++) {
                        mainSchema = (XmlSchema)schemas.GetByIndex(i);
                        if (mainSchema == schemaToRemove ||
                            schemaToRemove.ImportedSchemas.Contains(mainSchema)) { 
                            continue;
                        } 
                        needToCheckSchemaList.Add(mainSchema); 
                    }
 
                    mainSchema = null;
                    for (int i = 0; i < needToCheckSchemaList.Count; i++) { //Perf: Not using nested foreach here
                        mainSchema = (XmlSchema)needToCheckSchemaList[i];
 
                        if (mainSchema.ImportedNamespaces.Count > 0) {
                            foreach(string tns in disallowedNamespaces.Keys) { 
                                if (mainSchema.ImportedNamespaces.Contains(tns)) { 
                                    SendValidationEvent(new XmlSchemaException(Res.Sch_SchemaNotRemoved, string.Empty), XmlSeverityType.Warning);
                                    return false; 
                                }
                            }
                        }
                    } 

                    RemoveSchemaFromGlobalTables(schemaToRemove); 
                    Remove(schemaToRemove, false); 
                    foreach(XmlSchema impSchema in schemaToRemove.ImportedSchemas) {
                        RemoveSchemaFromGlobalTables(impSchema); 
                        Remove(impSchema, false);
                    }
                    return true;
                } 
            }
            return false; 
        } 

        ///  
        public bool Contains(String targetNamespace) {
           if (targetNamespace == null) {
               targetNamespace = string.Empty;
           } 
           return targetNamespaces[targetNamespace] != null;
        } 
 
        /// 
        public bool Contains(XmlSchema schema) { 
            if (schema == null) {
                throw new ArgumentNullException("schema");
            }
            return schemas.ContainsValue(schema); 
        }
 
        ///  
        /// 
        ///    [To be supplied.] 
        /// 
        public void Compile() {
            if (schemas.Count == 0) {
                ClearTables(); //Clear any previously present compiled state left by calling just Remove() on the set 
                return;
            } 
            if (isCompiled) { 
                return;
            } 
            lock (InternalSyncObject) {

                if (!isCompiled) { //Locking before checking isCompiled to avoid problems with double locking
                    Compiler compiler = new Compiler(nameTable, eventHandler, schemaForSchema, compilationSettings); 
                    SchemaInfo newCompiledInfo = new SchemaInfo();
                    int schemaIndex = 0; 
                    if (!compileAll) { //if we are not compiling everything again, Move the pre-compiled schemas to the compiler's tables 
                        compiler.ImportAllCompiledSchemas(this);
                    } 
                    try { //First thing to do in the try block is to acquire locks since finally will try to release them.
                        //If we dont accuire the locks first, and an exception occurs in the code before the locking code, then Threading.SynchronizationLockException will be thrown
                        //when attempting to release it in the finally block
                        XmlSchema currentSchema; 
                        XmlSchema xmlNSSchema = Preprocessor.GetBuildInSchema();
                        for (schemaIndex = 0; schemaIndex < schemas.Count; schemaIndex++) { 
                            currentSchema = (XmlSchema)schemas.GetByIndex(schemaIndex); 

                            //Lock schema to be compiled 
                            Monitor.Enter(currentSchema);
                            if (!currentSchema.IsPreprocessed) {
                                SendValidationEvent(new XmlSchemaException(Res.Sch_SchemaNotPreprocessed, string.Empty), XmlSeverityType.Error);
                                isCompiled = false; 
                                return;
                            } 
                            if (currentSchema.IsCompiledBySet) { 
                                if (!compileAll) {
                                    continue; 
                                }
                                else if ((object)currentSchema == (object)xmlNSSchema) { // prepare for xml namespace schema without cleanup
                                    compiler.Prepare(currentSchema, false);
                                    continue; 
                                }
                            } 
                            compiler.Prepare(currentSchema, true); 
                        }
 
                        isCompiled = compiler.Execute(this, newCompiledInfo);
                        if (isCompiled) {
                            compileAll = false;
                            newCompiledInfo.Add(cachedCompiledInfo, eventHandler); //Add all the items from the old to the new compiled object 
                            cachedCompiledInfo = newCompiledInfo; //Replace the compiled info in the set after successful compilation
                        } 
                    } 
                    finally {
                        //Release locks on all schemas 
                        XmlSchema currentSchema;
                        if (schemaIndex == schemas.Count) {
                            schemaIndex--;
                        } 
                        for (int i = schemaIndex; i >= 0; i--) {
                            currentSchema = (XmlSchema)schemas.GetByIndex(i); 
                            if (currentSchema == Preprocessor.GetBuildInSchema()) { //dont re-set compiled flags for xml namespace schema 
                                Monitor.Exit(currentSchema);
                                continue; 
                            }
                            currentSchema.IsCompiledBySet = isCompiled;
                            Monitor.Exit(currentSchema);
                        } 
                    }
                } 
            } 
            return;
        } 

        /// 
        /// 
        ///    [To be supplied.] 
        /// 
        public XmlSchema Reprocess(XmlSchema schema) { 
            if (schema == null) { 
                throw new ArgumentNullException("schema");
            } 
            if (!schemas.ContainsKey(schema.SchemaId)) {
                throw new ArgumentException(Res.GetString(Res.Sch_SchemaDoesNotExist), "schema");
            }
            lock (InternalSyncObject) { //Lock set so that set cannot be compiled in another thread 
                RemoveSchemaFromCaches(schema);
                PreprocessSchema(ref schema, schema.TargetNamespace); // 
                foreach (XmlSchema s in schema.ImportedSchemas) { //Once preprocessed external schemas property is set 
                    if (!schemas.ContainsKey(s.SchemaId)) {
                        schemas.Add(s.SchemaId, s); 
                    }
                    string tns = GetTargetNamespace(s);
                    if (targetNamespaces[tns] == null) {
                        targetNamespaces.Add(tns, tns); 
                    }
                } 
                isCompiled = false; 
            }
            return schema; 
        }

        /// 
        ///  
        ///    [To be supplied.]
        ///  
        public void CopyTo(XmlSchema[] schemas, int index) { 
            if (schemas == null)
                throw new ArgumentNullException("schemas"); 
            if (index < 0 || index > schemas.Length -1 )
                throw new ArgumentOutOfRangeException("index");
            this.schemas.Values.CopyTo(schemas, index);
        } 

        ///  
        ///  
        ///    [To be supplied.]
        ///  
        public ICollection Schemas() {
            return schemas.Values;
        }
 
        /// 
        ///  
        ///    [To be supplied.] 
        /// 
        public ICollection Schemas(String targetNamespace) { 
            ArrayList tnsSchemas = new ArrayList();
            XmlSchema currentSchema;
            if (targetNamespace == null) {
                targetNamespace = string.Empty; 
            }
            for (int i=0; i < schemas.Count; i++) { 
                currentSchema = (XmlSchema)schemas.GetByIndex(i); 
                if (GetTargetNamespace(currentSchema) == targetNamespace) {
                    tnsSchemas.Add(currentSchema); 
                }
            }
            return tnsSchemas;
        } 

//Internal Methods 
 

        internal XmlSchema Add(string targetNamespace, XmlSchema schema) { 
            if (schema == null || schema.ErrorCount != 0) { //Schema with parsing errors cannot be loaded
                return null;
            }
            if (PreprocessSchema(ref schema, targetNamespace)) { //No perf opt for already compiled schemas 
                AddSchemaToSet(schema);
                isCompiled = false; 
                return schema; 
            }
            return null; 
        }

#if TRUST_COMPILE_STATE
        private void AddCompiledSchema(XmlSchema schema) { 
            if (schema.IsCompiledBySet ) { //trust compiled state always if it is not a chameleon schema
                VerifyTables(); 
                SchemaInfo newCompiledInfo = new SchemaInfo(); 
                XmlSchemaObjectTable substitutionGroupsTable = null;
                if (!AddToCompiledInfo(schema, newCompiledInfo, ref substitutionGroupsTable)) { //Error while adding main schema 
                    return null;
                }
                foreach (XmlSchema impSchema in schema.ImportedSchemas) {
                    if (!AddToCompiledInfo(impSchema, newCompiledInfo, ref substitutionGroupsTable)) { //Error while adding imports 
                        return null;
                    } 
                } 
                newCompiledInfo.Add(cachedCompiledInfo, eventHandler); //Add existing compiled info
                cachedCompiledInfo = newCompiledInfo; 
                if (substitutionGroupsTable != null) {
                    ProcessNewSubstitutionGroups(substitutionGroupsTable, true);
                }
                if (schemas.Count == 0) { //If its the first compiled schema being added, then set doesnt need to be compiled 
                    isCompiled = true;
                    compileAll = false; 
                } 
                AddSchemaToSet(schema);
                return schema; 
            }
        }

        private bool AddToCompiledInfo(XmlSchema schema, SchemaInfo newCompiledInfo, ref XmlSchemaObjectTable substTable) { 
            //Add schema's compiled tables to the set
            if (schema.BaseUri != null && schemaLocations[schema.BaseUri] == null) { //Update schemaLocations table 
                schemaLocations.Add(schema.BaseUri, schema); 
            }
 
            foreach (XmlSchemaElement element in schema.Elements.Values) {
                if(!AddToTable(elements, element.QualifiedName, element)) {
                    RemoveSchemaFromGlobalTables(schema);
                    return false; 
                }
                XmlQualifiedName head = element.SubstitutionGroup; 
                if (!head.IsEmpty) { 
                    if (substTable == null) {
                        substTable = new XmlSchemaObjectTable(); 
                    }
                    XmlSchemaSubstitutionGroup substitutionGroup = (XmlSchemaSubstitutionGroup)substTable[head];
                    if (substitutionGroup == null) {
                        substitutionGroup = new XmlSchemaSubstitutionGroup(); 
                        substitutionGroup.Examplar = head;
                        substTable.Add(head, substitutionGroup); 
                    } 
                    ArrayList members = substitutionGroup.Members;
                    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 
                        members.Add(element);
                    }
                }
            } 
            foreach (XmlSchemaAttribute attribute in schema.Attributes.Values) {
                if (!AddToTable(attributes, attribute.QualifiedName, attribute)) { 
                    RemoveSchemaFromGlobalTables(schema); 
                    return false;
                } 
            }
            foreach (XmlSchemaType schemaType in schema.SchemaTypes.Values) {
                if (!AddToTable(schemaTypes, schemaType.QualifiedName, schemaType)) {
                    RemoveSchemaFromGlobalTables(schema); 
                    return false;
                } 
            } 
            schema.AddCompiledInfo(newCompiledInfo);
 
            return true;
        }
#endif
 
        //For use by the validator when loading schemaLocations in the instance
        internal void Add(String targetNamespace, XmlReader reader, Hashtable validatedNamespaces) { 
            if (reader == null) { 
                throw new ArgumentNullException("reader");
            } 
            if (targetNamespace == null) {
                targetNamespace = string.Empty;
            }
            if (validatedNamespaces[targetNamespace] != null) { 
                if (FindSchemaByNSAndUrl(new Uri(reader.BaseURI, UriKind.RelativeOrAbsolute), targetNamespace, null) != null) {
                    return; 
                } 
                else {
                    throw new XmlSchemaException(Res.Sch_ComponentAlreadySeenForNS, targetNamespace); 
                }
            }

            //Not locking set as this will not be accessible outside the validator 
            XmlSchema schema;
            if (IsSchemaLoaded(new Uri(reader.BaseURI, UriKind.RelativeOrAbsolute), targetNamespace, out schema)) { 
                return; 
            }
            else { //top-level schema not present for same url 
                schema = ParseSchema(targetNamespace, reader);

                //Store the previous locations
                DictionaryEntry[] oldLocations = new DictionaryEntry[schemaLocations.Count]; 
                schemaLocations.CopyTo(oldLocations, 0);
 
                //Add to set 
                Add(targetNamespace, schema);
                if (schema.ImportedSchemas.Count > 0) { //Check imports 
                    string tns;
                    foreach(XmlSchema impSchema in schema.ImportedSchemas) {
                        tns = impSchema.TargetNamespace;
                        if (tns == null) { 
                            tns = string.Empty;
                        } 
                        if (validatedNamespaces[tns] != null && (FindSchemaByNSAndUrl(impSchema.BaseUri, tns, oldLocations) == null) ) { 
                            RemoveRecursive(schema);
                            throw new XmlSchemaException(Res.Sch_ComponentAlreadySeenForNS, tns); 
                        }
                    }
                 }
            } 
        }
 
        internal XmlSchema FindSchemaByNSAndUrl(Uri schemaUri, string ns, DictionaryEntry[] locationsTable) { 
            if (schemaUri == null || schemaUri.OriginalString.Length == 0) {
                return null; 
            }
            XmlSchema schema = null;
            if (locationsTable == null) {
                schema = (XmlSchema)schemaLocations[schemaUri]; 
            }
            else { 
                for (int i = 0; i < locationsTable.Length; i++) { 
                    if (schemaUri.Equals(locationsTable[i].Key)) {
                        schema = (XmlSchema)locationsTable[i].Value; 
                        break;
                    }
                }
            } 
            if (schema != null) {
                Debug.Assert(ns != null); 
                string tns = schema.TargetNamespace == null ? string.Empty : schema.TargetNamespace; 
                if (tns == ns) {
                    return schema; 
                }
                else if (tns == string.Empty) { //There could be a chameleon for same ns
                    ChameleonKey cKey = new ChameleonKey(ns, schemaUri);
                    schema = (XmlSchema)chameleonSchemas[cKey]; //Need not clone if a schema for that namespace already exists 
                }
                else { 
                    schema = null; 
                }
            } 
            return schema;
        }

        private void SetProhibitDtd(XmlReader reader) { 
            if (reader.Settings != null) {
                this.readerSettings.ProhibitDtd = reader.Settings.ProhibitDtd; 
            } 
            else {
                XmlTextReader v1Reader = reader as XmlTextReader; 
                if (v1Reader != null) {
                   this.readerSettings.ProhibitDtd = v1Reader.ProhibitDtd;
                }
            } 
        }
 
        private void AddSchemaToSet(XmlSchema schema) { 
            schemas.Add(schema.SchemaId, schema);
            //Add to targetNamespaces table 
            string tns = GetTargetNamespace(schema);
            if (targetNamespaces[tns] == null) {
                targetNamespaces.Add(tns, tns);
            } 
            if (schemaForSchema == null && tns == XmlReservedNs.NsXs && schema.SchemaTypes[DatatypeImplementation.QnAnyType] != null) { //it has xs:anyType
                schemaForSchema = schema; 
            } 
            foreach (XmlSchema s in schema.ImportedSchemas) { //Once preprocessed external schemas property is set
                if (!schemas.ContainsKey(s.SchemaId)) { 
                    schemas.Add(s.SchemaId, s);
                }
                tns = GetTargetNamespace(s);
                if (targetNamespaces[tns] == null) { 
                    targetNamespaces.Add(tns, tns);
                } 
                if (schemaForSchema == null && tns == XmlReservedNs.NsXs && schema.SchemaTypes[DatatypeImplementation.QnAnyType] != null) { //it has xs:anyType 
                    schemaForSchema = schema;
                } 
            }
        }

        private void ProcessNewSubstitutionGroups(XmlSchemaObjectTable substitutionGroupsTable, bool resolve) { 
            foreach(XmlSchemaSubstitutionGroup substGroup in substitutionGroupsTable.Values) {
                if (resolve) { //Resolve substitutionGroups within this schema 
                    ResolveSubstitutionGroup(substGroup, substitutionGroupsTable); 
                }
 
                //Add or Merge new substitutionGroups with those that already exist in the set
                XmlQualifiedName head = substGroup.Examplar;
                XmlSchemaSubstitutionGroup oldSubstGroup = (XmlSchemaSubstitutionGroup)substitutionGroups[head];
                if (oldSubstGroup != null) { 
                    foreach(XmlSchemaElement member in substGroup.Members) {
                        if (!oldSubstGroup.Members.Contains(member)) { 
                            oldSubstGroup.Members.Add(member); 
                        }
                    } 
                }
                else {
                    AddToTable(substitutionGroups, head, substGroup);
                } 
            }
        } 
 
        private void ResolveSubstitutionGroup(XmlSchemaSubstitutionGroup substitutionGroup, XmlSchemaObjectTable substTable) {
            ArrayList newMembers = null; 
            XmlSchemaElement headElement = (XmlSchemaElement)elements[substitutionGroup.Examplar];
            if (substitutionGroup.Members.Contains(headElement)) {// already checked
                return;
            } 
            foreach (XmlSchemaElement element in substitutionGroup.Members) {
                //Chain to other head's that are members of this head's substGroup 
                XmlSchemaSubstitutionGroup g = (XmlSchemaSubstitutionGroup)substTable[element.QualifiedName]; 
                if (g != null) {
                    ResolveSubstitutionGroup(g, substTable); 
                    foreach (XmlSchemaElement element1 in g.Members) {
                        if (element1 != element) { //Exclude the head
                            if (newMembers == null) {
                                newMembers = new ArrayList(); 
                            }
                            newMembers.Add(element1); 
                        } 
                    }
                } 
            }
            if (newMembers != null) {
                foreach (XmlSchemaElement newMember in newMembers) {
                    substitutionGroup.Members.Add(newMember); 
                }
            } 
            substitutionGroup.Members.Add(headElement); 
        }
 
        internal XmlSchema Remove(XmlSchema schema, bool forceCompile) {
            if (schema == null) {
                throw new ArgumentNullException("schema");
            } 
            lock (InternalSyncObject) { //Need to lock here so that remove cannot be called while the set is being compiled
                if (schemas.ContainsKey(schema.SchemaId)) { 
                    schemas.Remove(schema.SchemaId); 
                    if (schema.BaseUri != null) {
                        schemaLocations.Remove(schema.BaseUri); 
                    }
                    string tns = GetTargetNamespace(schema);
                    if (Schemas(tns).Count == 0) { //This is the only schema for that namespace
                        targetNamespaces.Remove(tns); 
                    }
                    if (forceCompile) { 
                        isCompiled = false; 
                        compileAll = true; //Force compilation of the whole set; This is when the set is not completely thread-safe
                    } 
                    return schema;
                }
            }
            return null; 
        }
 
        private void ClearTables() { 
            GlobalElements.Clear();
            GlobalAttributes.Clear(); 
            GlobalTypes.Clear();
            SubstitutionGroups.Clear();
            TypeExtensions.Clear();
        } 

        internal bool PreprocessSchema(ref XmlSchema schema, string targetNamespace) { 
            Preprocessor prep = new Preprocessor(nameTable, GetSchemaNames(nameTable), eventHandler, compilationSettings); 
            prep.XmlResolver = readerSettings.GetXmlResolver();
            prep.ReaderSettings = readerSettings; 
            prep.SchemaLocations = schemaLocations;
            prep.ChameleonSchemas = chameleonSchemas;
            bool hasErrors = prep.Execute(schema, targetNamespace, true);
            schema = prep.RootSchema; //For any root level chameleon cloned 
            return hasErrors;
        } 
 
        internal XmlSchema ParseSchema(string targetNamespace, XmlReader reader) {
            XmlNameTable readerNameTable = reader.NameTable; 
            SchemaNames schemaNames = GetSchemaNames(readerNameTable);
            Parser parser = new Parser(SchemaType.XSD, readerNameTable, schemaNames, eventHandler);
            parser.XmlResolver = readerSettings.GetXmlResolver();
            SchemaType schemaType; 
            try {
                schemaType = parser.Parse(reader, targetNamespace); 
            } 
            catch(XmlSchemaException e) {
                SendValidationEvent(e, XmlSeverityType.Error); 
                return null;
            }
            return parser.XmlSchema;
        } 

        internal void CopyFromCompiledSet(XmlSchemaSet otherSet) { 
            XmlSchema currentSchema; 
            SortedList copyFromList = otherSet.SortedSchemas;
            bool setIsCompiled = schemas.Count == 0 ? true : false; 
            ArrayList existingSchemas = new ArrayList();

            SchemaInfo newCompiledInfo = new SchemaInfo();
            Uri baseUri; 
            for(int i=0; i < copyFromList.Count; i++) {
                currentSchema = (XmlSchema)copyFromList.GetByIndex(i); 
                baseUri = currentSchema.BaseUri; 
                if (schemas.ContainsKey(currentSchema.SchemaId) || (baseUri != null && baseUri.OriginalString.Length != 0 && schemaLocations[baseUri] != null)) {
                    existingSchemas.Add(currentSchema); 
                    continue;
                }
                schemas.Add(currentSchema.SchemaId, currentSchema);
                if (baseUri != null && baseUri.OriginalString.Length != 0) { 
                    schemaLocations.Add(baseUri, currentSchema);
                } 
                string tns = GetTargetNamespace(currentSchema); 
                if (targetNamespaces[tns] == null) {
                    targetNamespaces.Add(tns, tns); 
                }
            }

            VerifyTables(); 
            foreach (XmlSchemaElement element in otherSet.GlobalElements.Values) {
                if(!AddToTable(elements, element.QualifiedName, element)) { 
                    goto RemoveAll; 
                }
            } 
            foreach (XmlSchemaAttribute attribute in otherSet.GlobalAttributes.Values) {
                if (!AddToTable(attributes, attribute.QualifiedName, attribute)) {
                    goto RemoveAll;
                } 
            }
            foreach (XmlSchemaType schemaType in otherSet.GlobalTypes.Values) { 
                if (!AddToTable(schemaTypes, schemaType.QualifiedName, schemaType)) { 
                    goto RemoveAll;
                } 
            }
            //
            ProcessNewSubstitutionGroups(otherSet.SubstitutionGroups, false);
 
            newCompiledInfo.Add(cachedCompiledInfo, eventHandler); //Add all the items from the old to the new compiled object
            newCompiledInfo.Add(otherSet.CompiledInfo,eventHandler); // 
            cachedCompiledInfo = newCompiledInfo; //Replace the compiled info in the set after successful compilation 
            if (setIsCompiled) {
                isCompiled = true; 
                compileAll = false;
            }
            return;
 
            RemoveAll:
                foreach (XmlSchema schemaToRemove in copyFromList.Values) { 
                    if (!existingSchemas.Contains(schemaToRemove)) { 
                        Remove(schemaToRemove, false);
                    } 
                }
                foreach (XmlSchemaElement elementToRemove in otherSet.GlobalElements.Values) {
                    if(!existingSchemas.Contains((XmlSchema)elementToRemove.Parent)) {
                        elements.Remove(elementToRemove.QualifiedName); 
                    }
                } 
                foreach (XmlSchemaAttribute attributeToRemove in otherSet.GlobalAttributes.Values) { 
                    if(!existingSchemas.Contains((XmlSchema)attributeToRemove.Parent)) {
                        attributes.Remove(attributeToRemove.QualifiedName); 
                    }
                }
                foreach (XmlSchemaType schemaTypeToRemove in otherSet.GlobalTypes.Values) {
                    if(!existingSchemas.Contains((XmlSchema)schemaTypeToRemove.Parent)) { 
                        schemaTypes.Remove(schemaTypeToRemove.QualifiedName);
                    } 
                } 
        }
 
        internal SchemaInfo CompiledInfo {
            get {
                return cachedCompiledInfo;
            } 
        }
 
        internal XmlReaderSettings ReaderSettings { 
            get {
                return readerSettings; 
            }
        }

        internal XmlResolver GetResolver() { 
            return readerSettings.GetXmlResolver();
        } 
 
        internal ValidationEventHandler GetEventHandler() {
            return eventHandler; 
        }

        internal SchemaNames GetSchemaNames(XmlNameTable nt) {
            if (nameTable != nt) { 
                return new SchemaNames(nt);
            } 
            else { 
                if (schemaNames == null) {
                    schemaNames = new SchemaNames( nameTable ); 
                }
                return schemaNames;
            }
        } 

        internal bool IsSchemaLoaded(Uri schemaUri, string targetNamespace, out XmlSchema schema) { 
            schema = null; 
            if (targetNamespace == null) {
                targetNamespace = string.Empty; 
            }
            if (GetSchemaByUri(schemaUri, out schema)) {
                if (schemas.ContainsKey(schema.SchemaId) && (targetNamespace.Length == 0 || targetNamespace == schema.TargetNamespace)) { //schema is present in set
                    //Schema found 
                }
                else if (schema.TargetNamespace == null) { //If schema not in set or namespace doesnt match, then it might be a chameleon 
                    XmlSchema chameleonSchema = FindSchemaByNSAndUrl(schemaUri, targetNamespace, null); 
                    if (chameleonSchema != null && schemas.ContainsKey(chameleonSchema.SchemaId)) {
                        schema = chameleonSchema; 
                    }
                    else {
                        schema = Add(targetNamespace, schema);
                    } 
                }
                else if (targetNamespace.Length != 0 && targetNamespace != schema.TargetNamespace) { 
                    SendValidationEvent(new XmlSchemaException(Res.Sch_MismatchTargetNamespaceEx, new string[] { targetNamespace, schema.TargetNamespace }), XmlSeverityType.Error); 
                    schema = null;
                } 
                else {
                    //If here, schema not present in set but in loc and might be added in loc through an earlier include
                    //S.TNS != null && ( tns == null or tns == s.TNS)
                    AddSchemaToSet(schema); 
                }
                return true; //Schema Found 
           } 
           return false;
        } 

        internal bool GetSchemaByUri(Uri schemaUri, out XmlSchema schema) {
            schema = null;
            if (schemaUri == null || schemaUri.OriginalString.Length == 0) { 
                return false;
            } 
            schema = (XmlSchema)schemaLocations[schemaUri]; 
            if (schema != null) {
                return true; 
            }
            return false;
        }
 
        internal string GetTargetNamespace(XmlSchema schema) {
            return schema.TargetNamespace == null ? string.Empty : schema.TargetNamespace; 
        } 

 
        internal SortedList SortedSchemas {
            get {
                return schemas;
            } 
        }
 
        internal bool CompileAll { 
            get {
                return compileAll; 
            }
        }

//Private Methods 
        private void RemoveSchemaFromCaches(XmlSchema schema) {
            //Remove From ChameleonSchemas and schemaLocations cache 
            List reprocessList = new List(); 
            schema.GetExternalSchemasList(reprocessList, schema);
            foreach(XmlSchema reprocessSchema in reprocessList) { //Remove schema from schemaLocations & chameleonSchemas tables 
                if (reprocessSchema.BaseUri != null && reprocessSchema.BaseUri.OriginalString.Length != 0) {
                    schemaLocations.Remove(reprocessSchema.BaseUri);
                }
                //Remove from chameleon table 
                ICollection chameleonKeys = chameleonSchemas.Keys;
                ArrayList removalList = new ArrayList(); 
                foreach(ChameleonKey cKey in chameleonKeys) { 
                    if (cKey.chameleonLocation.Equals(reprocessSchema.BaseUri)) {
                        removalList.Add(cKey); 
                    }
                }
                foreach(ChameleonKey cKey in removalList) {
                    chameleonSchemas.Remove(cKey); 
                }
            } 
 
        }
 
        private void RemoveSchemaFromGlobalTables(XmlSchema schema) {
            if (schemas.Count == 0) {
                return;
            } 
            VerifyTables();
            foreach (XmlSchemaElement elementToRemove in schema.Elements.Values) { 
                XmlSchemaElement elem = (XmlSchemaElement)elements[elementToRemove.QualifiedName]; 
                if (elem == elementToRemove) {
                    elements.Remove(elementToRemove.QualifiedName); 
                }
            }
            foreach (XmlSchemaAttribute attributeToRemove in schema.Attributes.Values) {
                XmlSchemaAttribute attr = (XmlSchemaAttribute)attributes[attributeToRemove.QualifiedName]; 
                if (attr == attributeToRemove) {
                    attributes.Remove(attributeToRemove.QualifiedName); 
                } 
            }
            foreach (XmlSchemaType schemaTypeToRemove in schema.SchemaTypes.Values) { 
                XmlSchemaType schemaType = (XmlSchemaType)schemaTypes[schemaTypeToRemove.QualifiedName];
                if (schemaType == schemaTypeToRemove) {
                    schemaTypes.Remove(schemaTypeToRemove.QualifiedName);
                } 
            }
        } 
        private bool AddToTable(XmlSchemaObjectTable table, XmlQualifiedName qname, XmlSchemaObject item) { 
            if (qname.Name.Length == 0) {
                return true; 
            }
            XmlSchemaObject existingObject = (XmlSchemaObject)table[qname];
            if (existingObject != null) {
                if (existingObject == item || existingObject.SourceUri == item.SourceUri) { 
                    return true;
                } 
                string code = string.Empty; 
                if (item is XmlSchemaComplexType) {
                    code = Res.Sch_DupComplexType; 
                }
                else if (item is XmlSchemaSimpleType) {
                    code = Res.Sch_DupSimpleType;
                } 
                else if (item is XmlSchemaElement) {
                    code = Res.Sch_DupGlobalElement; 
                } 
                else if (item is XmlSchemaAttribute) {
                    if (qname.Namespace == XmlReservedNs.NsXml) { 
                        XmlSchema schemaForXmlNS = Preprocessor.GetBuildInSchema();
                        XmlSchemaObject builtInAttribute = schemaForXmlNS.Attributes[qname];
                        if (existingObject == builtInAttribute) { //replace built-in one
                            table.Insert(qname, item); 
                            return true;
                        } 
                        else if (item == builtInAttribute) { //trying to overwrite customer's component with built-in, ignore built-in 
                            return true;
                        } 
                    }
                    code = Res.Sch_DupGlobalAttribute;
                }
                SendValidationEvent(new XmlSchemaException(code,qname.ToString()), XmlSeverityType.Error); 
                return false;
            } 
            else { 
                table.Add(qname, item);
                return true; 
            }
        }

        private void VerifyTables() { 
            if (elements == null) {
                elements = new XmlSchemaObjectTable(); 
            } 
            if (attributes == null) {
                attributes = new XmlSchemaObjectTable(); 
            }
            if (schemaTypes == null) {
                schemaTypes = new XmlSchemaObjectTable();
            } 
            if (substitutionGroups == null) {
                substitutionGroups = new XmlSchemaObjectTable(); 
            } 
        }
 
        private void InternalValidationCallback(object sender, ValidationEventArgs e ) {
            if (e.Severity == XmlSeverityType.Error) {
                throw e.Exception;
            } 
        }
 
        private void SendValidationEvent(XmlSchemaException e, XmlSeverityType severity) { 
            if (eventHandler != null) {
                eventHandler(this, new ValidationEventArgs(e, severity)); 
            }
            else {
                throw e;
            } 
        }
    }; 
 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK