2016-08-03 10:59:49 +00:00
//------------------------------------------------------------------------------
// <copyright file="XmlSchemaSet.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
2017-08-21 15:34:15 +00:00
// <owner current="true" primary="true">Microsoft</owner>
2016-08-03 10:59:49 +00:00
//------------------------------------------------------------------------------
using System.Diagnostics ;
using System.Collections ;
using System.Threading ;
using System.Collections.Generic ;
using System.Runtime.Versioning ;
namespace System.Xml.Schema {
#if SILVERLIGHT
public class XmlSchemaSet
{
//Empty XmlSchemaSet class to enable backward compatibility of XmlSchemaProvideAttribute
//Add private ctor to prevent constructing of this class
XmlSchemaSet ( ) { }
}
#else
/// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet"]/*' />
/// <devdoc>
/// <para>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.</para>
/// </devdoc>
public class XmlSchemaSet {
XmlNameTable nameTable ;
SchemaNames schemaNames ;
SortedList schemas ; // List of source schemas
//Event handling
ValidationEventHandler internalEventHandler ;
ValidationEventHandler eventHandler ;
bool isCompiled = false ;
//Dictionary<Uri, XmlSchema> schemaLocations;
//Dictionary<ChameleonKey, XmlSchema> 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 < Object > ( ref internalSyncObject , o , null ) ;
}
return internalSyncObject ;
}
}
//Constructors
/// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.XmlSchemaSet"]/*' />
/// <devdoc>
/// <para>Construct a new empty schema schemas.</para>
/// </devdoc>
public XmlSchemaSet ( ) : this ( new NameTable ( ) ) {
}
/// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.XmlSchemaSet1"]/*' />
/// <devdoc>
/// <para>Construct a new empty schema schemas with associated XmlNameTable.
/// The XmlNameTable is used when loading schemas</para>
/// </devdoc>
public XmlSchemaSet ( XmlNameTable nameTable ) {
if ( nameTable = = null ) {
throw new ArgumentNullException ( "nameTable" ) ;
}
this . nameTable = nameTable ;
schemas = new SortedList ( ) ;
/ * schemaLocations = new Dictionary < Uri , XmlSchema > ( ) ;
chameleonSchemas = new Dictionary < ChameleonKey , XmlSchema > ( ) ; * /
schemaLocations = new Hashtable ( ) ;
chameleonSchemas = new Hashtable ( ) ;
targetNamespaces = new Hashtable ( ) ;
internalEventHandler = new ValidationEventHandler ( InternalValidationCallback ) ;
eventHandler = internalEventHandler ;
readerSettings = new XmlReaderSettings ( ) ;
// we don't have to check XmlReaderSettings.EnableLegacyXmlSettings() here because the following
// code will return same result either we are running on v4.5 or later
if ( readerSettings . GetXmlResolver ( ) = = null )
{
// The created resolver will be used in the schema validation only
readerSettings . XmlResolver = new XmlUrlResolver ( ) ;
readerSettings . IsXmlResolverSet = false ;
}
readerSettings . NameTable = nameTable ;
readerSettings . DtdProcessing = DtdProcessing . Prohibit ;
compilationSettings = new XmlSchemaCompilationSettings ( ) ;
cachedCompiledInfo = new SchemaInfo ( ) ;
compileAll = true ;
}
//Public Properties
/// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.NameTable"]/*' />
/// <devdoc>
/// <para>The default XmlNameTable used by the XmlSchemaSet when loading new schemas.</para>
/// </devdoc>
public XmlNameTable NameTable {
get { return nameTable ; }
}
/// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.ValidationEventHandler"]/*' />
public event ValidationEventHandler ValidationEventHandler {
add {
eventHandler - = internalEventHandler ;
eventHandler + = value ;
if ( eventHandler = = null ) {
eventHandler = internalEventHandler ;
}
}
remove {
eventHandler - = value ;
if ( eventHandler = = null ) {
eventHandler = internalEventHandler ;
}
}
}
/// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.IsCompiled"]/*' />
/// <devdoc>
/// <para>IsCompiled is true when the schema set is in compiled state</para>
/// </devdoc>
public bool IsCompiled {
get {
return isCompiled ;
}
}
/// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.XmlResolver"]/*' />
/// <devdoc>
/// <para></para>
/// </devdoc>
public XmlResolver XmlResolver {
set {
readerSettings . XmlResolver = value ;
}
}
/// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.CompilationSettings"]/*' />
/// <devdoc>
/// <para></para>
/// </devdoc>
public XmlSchemaCompilationSettings CompilationSettings {
get {
return compilationSettings ;
}
set {
compilationSettings = value ;
}
}
/// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Count"]/*' />
/// <devdoc>
/// <para>Returns the count of schemas in the set</para>
/// </devdoc>
public int Count {
get {
return schemas . Count ;
}
}
/// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.GlobalElements"]/*' />
/// <devdoc>
/// <para></para>
/// </devdoc>
public XmlSchemaObjectTable GlobalElements {
get {
if ( elements = = null ) {
elements = new XmlSchemaObjectTable ( ) ;
}
return elements ;
}
}
/// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.GlobalAttributes"]/*' />
/// <devdoc>
/// <para></para>
/// </devdoc>
public XmlSchemaObjectTable GlobalAttributes {
get {
if ( attributes = = null ) {
attributes = new XmlSchemaObjectTable ( ) ;
}
return attributes ;
}
}
/// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.GlobalTypes"]/*' />
/// <devdoc>
/// <para></para>
/// </devdoc>
public XmlSchemaObjectTable GlobalTypes {
get {
if ( schemaTypes = = null ) {
schemaTypes = new XmlSchemaObjectTable ( ) ;
}
return schemaTypes ;
}
}
/// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.SubstitutionGroups"]/*' />
/// <devdoc>
/// <para></para>
/// </devdoc>
///
internal XmlSchemaObjectTable SubstitutionGroups {
get {
if ( substitutionGroups = = null ) {
substitutionGroups = new XmlSchemaObjectTable ( ) ;
}
return substitutionGroups ;
}
}
/// <summary>
/// Table of all types extensions
/// </summary>
internal Hashtable SchemaLocations {
get {
return schemaLocations ;
}
}
/// <summary>
/// Table of all types extensions
/// </summary>
internal XmlSchemaObjectTable TypeExtensions {
get {
if ( typeExtensions = = null ) {
typeExtensions = new XmlSchemaObjectTable ( ) ;
}
return typeExtensions ;
}
}
//Public Methods
/// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Add1"]/*' />
/// <devdoc>
/// <para>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.</para>
/// </devdoc>
[ResourceConsumption(ResourceScope.Machine)]
[ResourceExposure(ResourceScope.Machine)]
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 ;
}
/// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Add4"]/*' />
/// <devdoc>
/// <para>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.</para>
/// </devdoc>
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 {
DtdProcessing dtdProcessing = this . readerSettings . DtdProcessing ;
SetDtdProcessing ( schemaDocument ) ;
schema = Add ( targetNamespace , ParseSchema ( targetNamespace , schemaDocument ) ) ;
this . readerSettings . DtdProcessing = dtdProcessing ; //reset dtdProcessing setting
return schema ;
}
}
}
/// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Add5"]/*' />
/// <devdoc>
/// <para>Adds all the namespaces defined in the given schemas
/// (including their associated schemas) to this schemas.</para>
/// </devdoc>
public void Add ( XmlSchemaSet schemas ) {
if ( schemas = = null ) {
throw new ArgumentNullException ( "schemas" ) ;
}
if ( this = = schemas ) {
return ;
}
bool thisLockObtained = false ;
bool schemasLockObtained = false ;
try {
while ( true ) {
Monitor . TryEnter ( InternalSyncObject , ref thisLockObtained ) ;
if ( thisLockObtained ) {
Monitor . TryEnter ( schemas . InternalSyncObject , ref schemasLockObtained ) ;
if ( schemasLockObtained ) {
break ;
}
else {
Monitor . Exit ( InternalSyncObject ) ; //Give up this lock and try both again
thisLockObtained = false ;
Thread . Yield ( ) ; //Let the thread that holds the lock run
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 ( thisLockObtained ) {
Monitor . Exit ( InternalSyncObject ) ;
}
if ( schemasLockObtained ) {
Monitor . Exit ( schemas . InternalSyncObject ) ;
}
}
}
/// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Add6"]/*' />
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 ) ;
}
}
/// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Remove"]/*' />
public XmlSchema Remove ( XmlSchema schema ) {
return Remove ( schema , true ) ;
}
/// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.RemoveRecursive"]/*' />
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 ;
}
}
}
}
Remove ( schemaToRemove , true ) ;
for ( int i = 0 ; i < schemaToRemove . ImportedSchemas . Count ; + + i ) {
XmlSchema impSchema = ( XmlSchema ) schemaToRemove . ImportedSchemas [ i ] ;
Remove ( impSchema , true ) ;
}
return true ;
}
}
return false ;
}
/// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Contains1"]/*' />
public bool Contains ( String targetNamespace ) {
if ( targetNamespace = = null ) {
targetNamespace = string . Empty ;
}
return targetNamespaces [ targetNamespace ] ! = null ;
}
/// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Contains2"]/*' />
public bool Contains ( XmlSchema schema ) {
if ( schema = = null ) {
throw new ArgumentNullException ( "schema" ) ;
}
return schemas . ContainsValue ( schema ) ;
}
/// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Compile"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public void Compile ( ) {
if ( isCompiled ) {
return ;
}
if ( schemas . Count = = 0 ) {
ClearTables ( ) ; //Clear any previously present compiled state left by calling just Remove() on the set
cachedCompiledInfo = new SchemaInfo ( ) ;
isCompiled = true ;
compileAll = false ;
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
#pragma warning disable 0618
//@
Monitor . Enter ( currentSchema ) ;
#pragma warning restore 0618
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 ) {
if ( ! compileAll ) {
newCompiledInfo . Add ( cachedCompiledInfo , eventHandler ) ; //Add all the items from the old to the new compiled object
}
compileAll = false ;
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 ;
}
/// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Reprocess"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public XmlSchema Reprocess ( XmlSchema schema ) {
// Due to bug 644477 - this method is tightly coupled (THE CODE IS BASICALLY COPIED) to Remove, Add and AddSchemaToSet
// methods. If you change anything here *make sure* to update Remove/Add/AddSchemaToSet method(s) accordingly.
// The only difference is that we don't touch .schemas collection here to not break a code like this:
// foreach(XmlSchema s in schemaset.schemas) { schemaset.Reprocess(s); }
// This is by purpose.
if ( schema = = null ) {
throw new ArgumentNullException ( "schema" ) ;
}
if ( ! schemas . ContainsKey ( schema . SchemaId ) ) {
throw new ArgumentException ( Res . GetString ( Res . Sch_SchemaDoesNotExist ) , "schema" ) ;
}
XmlSchema originalSchema = schema ;
lock ( InternalSyncObject ) { //Lock set so that set cannot be compiled in another thread
// This code is copied from method:
// Remove(XmlSchema schema, bool forceCompile)
// If you changed anything here go and change the same in Remove(XmlSchema schema, bool forceCompile) method
#region Copied from Remove ( XmlSchema schema , bool forceCompile )
RemoveSchemaFromGlobalTables ( schema ) ;
RemoveSchemaFromCaches ( schema ) ;
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 ) ;
}
isCompiled = false ;
compileAll = true ; //Force compilation of the whole set; This is when the set is not completely thread-safe
#endregion //Copied from Remove(XmlSchema schema, bool forceCompile)
// This code is copied from method:
// Add(string targetNamespace, XmlSchema schema)
// If you changed anything here go and change the same in Add(string targetNamespace, XmlSchema schema) method
#region Copied from Add ( string targetNamespace , XmlSchema schema )
if ( schema . ErrorCount ! = 0 ) { //Schema with parsing errors cannot be loaded
return originalSchema ;
}
if ( PreprocessSchema ( ref schema , schema . TargetNamespace ) ) { //No perf opt for already compiled schemas
// This code is copied from method:
// AddSchemaToSet(XmlSchema schema)
// If you changed anything here go and change the same in AddSchemaToSet(XmlSchema schema) method
#region Copied from AddSchemaToSet ( XmlSchema schema )
//Add to targetNamespaces table
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 ;
}
for ( int i = 0 ; i < schema . ImportedSchemas . Count ; + + i ) { //Once preprocessed external schemas property is set
XmlSchema s = ( XmlSchema ) schema . ImportedSchemas [ i ] ;
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 ;
}
}
#endregion //Copied from AddSchemaToSet(XmlSchema schema)
return schema ;
}
#endregion // Copied from Add(string targetNamespace, XmlSchema schema)
return originalSchema ;
}
}
/// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.CopyTo"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
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 ) ;
}
/// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Schemas1"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public ICollection Schemas ( ) {
return schemas . Values ;
}
/// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Schemas1"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
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
private XmlSchema Add ( string targetNamespace , XmlSchema schema ) {
// Due to bug 644477 - this method is tightly coupled (THE CODE IS BASICALLY COPIED) to Reprocess
// method. If you change anything here *make sure* to update Reprocess method accordingly.
if ( schema = = null | | schema . ErrorCount ! = 0 ) { //Schema with parsing errors cannot be loaded
return null ;
}
// This code is copied to method:
// Reprocess(XmlSchema schema)
// If you changed anything here go and change the same in Reprocess(XmlSchema schema) method
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 ;
for ( int i = 0 ; i < schema . ImportedSchemas . Count ; + + i ) {
XmlSchema impSchema = ( XmlSchema ) schema . ImportedSchemas [ i ] ;
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
// It is OK to pass in the schema we have found so far, since it must have the schemaUri we're looking for
// (we found it that way above) and it must be the original chameleon schema (the one without target ns)
// as we don't add the chameleon copies into the locations tables above.
Debug . Assert ( schema . BaseUri . Equals ( schemaUri ) ) ;
ChameleonKey cKey = new ChameleonKey ( ns , schema ) ;
schema = ( XmlSchema ) chameleonSchemas [ cKey ] ; //Need not clone if a schema for that namespace already exists
}
else {
schema = null ;
}
}
return schema ;
}
private void SetDtdProcessing ( XmlReader reader ) {
if ( reader . Settings ! = null ) {
this . readerSettings . DtdProcessing = reader . Settings . DtdProcessing ;
}
else {
XmlTextReader v1Reader = reader as XmlTextReader ;
if ( v1Reader ! = null ) {
this . readerSettings . DtdProcessing = v1Reader . DtdProcessing ;
}
}
}
private void AddSchemaToSet ( XmlSchema schema ) {
// Due to bug 644477 - this method is tightly coupled (THE CODE IS BASICALLY COPIED) to Reprocess
// method. If you change anything here *make sure* to update Reprocess method accordingly.
schemas . Add ( schema . SchemaId , schema ) ;
//Add to targetNamespaces table
// This code is copied to method:
// Reprocess(XmlSchema schema)
// If you changed anything here go and change the same in Reprocess(XmlSchema schema) method
#region This code is copied to Reprocess ( XmlSchema schema ) method
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 ;
}
for ( int i = 0 ; i < schema . ImportedSchemas . Count ; + + i ) { //Once preprocessed external schemas property is set
XmlSchema s = ( XmlSchema ) schema . ImportedSchemas [ i ] ;
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 ;
}
}
#endregion // This code is copied to Reprocess(XmlSchema schema) method
}
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 ) {
for ( int i = 0 ; i < substGroup . Members . Count ; + + i ) {
if ( ! oldSubstGroup . Members . Contains ( substGroup . Members [ i ] ) ) {
oldSubstGroup . Members . Add ( substGroup . Members [ i ] ) ;
}
}
}
else {
AddToTable ( substitutionGroups , head , substGroup ) ;
}
}
}
private void ResolveSubstitutionGroup ( XmlSchemaSubstitutionGroup substitutionGroup , XmlSchemaObjectTable substTable ) {
List < XmlSchemaElement > newMembers = null ;
XmlSchemaElement headElement = ( XmlSchemaElement ) elements [ substitutionGroup . Examplar ] ;
if ( substitutionGroup . Members . Contains ( headElement ) ) { // already checked
return ;
}
for ( int i = 0 ; i < substitutionGroup . Members . Count ; + + i ) {
XmlSchemaElement element = ( XmlSchemaElement ) substitutionGroup . Members [ i ] ;
//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 ) ;
for ( int j = 0 ; j < g . Members . Count ; + + j ) {
XmlSchemaElement element1 = ( XmlSchemaElement ) g . Members [ j ] ;
if ( element1 ! = element ) { //Exclude the head
if ( newMembers = = null ) {
newMembers = new List < XmlSchemaElement > ( ) ;
}
newMembers . Add ( element1 ) ;
}
}
}
}
if ( newMembers ! = null ) {
for ( int i = 0 ; i < newMembers . Count ; + + i ) {
substitutionGroup . Members . Add ( newMembers [ i ] ) ;
}
}
substitutionGroup . Members . Add ( headElement ) ;
}
internal XmlSchema Remove ( XmlSchema schema , bool forceCompile ) {
// Due to bug 644477 - this method is tightly coupled (THE CODE IS BASICALLY COPIED) to Reprocess
// method. If you change anything here *make sure* to update Reprocess method accordingly.
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 ) ) {
// This code is copied to method:
// Reprocess(XmlSchema schema)
// If you changed anything here go and change the same in Reprocess(XmlSchema schema) method
#region This code is copied to Reprocess ( XmlSchema schema ) method
if ( forceCompile ) {
RemoveSchemaFromGlobalTables ( schema ) ;
RemoveSchemaFromCaches ( schema ) ;
}
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 ;
#endregion // This code is copied to Reprocess(XmlSchema schema) method
}
}
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_CheckConfig ( ) ;
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_CheckConfig ( ) ;
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_CheckConfig ( ) ;
}
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 < XmlSchema > reprocessList = new List < XmlSchema > ( ) ;
schema . GetExternalSchemasList ( reprocessList , schema ) ;
for ( int i = 0 ; i < reprocessList . Count ; + + i ) { //Remove schema from schemaLocations & chameleonSchemas tables
if ( reprocessList [ i ] . BaseUri ! = null & & reprocessList [ i ] . BaseUri . OriginalString . Length ! = 0 ) {
schemaLocations . Remove ( reprocessList [ i ] . BaseUri ) ;
}
//Remove from chameleon table
ICollection chameleonKeys = chameleonSchemas . Keys ;
ArrayList removalList = new ArrayList ( ) ;
foreach ( ChameleonKey cKey in chameleonKeys ) {
if ( cKey . chameleonLocation . Equals ( reprocessList [ i ] . BaseUri ) ) {
// The key will have the originalSchema set to null if the location was not empty
// otherwise we need to care about it as there may be more chameleon schemas without
// a base URI and we want to remove only those which were created as a clone of the one
// we're removing.
if ( cKey . originalSchema = = null | | Ref . ReferenceEquals ( cKey . originalSchema , reprocessList [ i ] ) ) {
removalList . Add ( cKey ) ;
}
}
}
for ( int j = 0 ; j < removalList . Count ; + + j ) {
chameleonSchemas . Remove ( removalList [ j ] ) ;
}
}
}
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 ;
}
}
} ;
#endif
}