//------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // // Microsoft //------------------------------------------------------------------------------ namespace System.Xml.Schema { using System.Collections; using System.IO; using System.Threading; using System.Diagnostics; using System.Collections.Generic; using System.Runtime.Versioning; internal enum Compositor { Root, Include, Import, Redefine }; class RedefineEntry { internal XmlSchemaRedefine redefine; internal XmlSchema schemaToUpdate; public RedefineEntry(XmlSchemaRedefine external, XmlSchema schema) { redefine = external; schemaToUpdate = schema; } } internal sealed class Preprocessor : BaseProcessor { string Xmlns; string NsXsi; string targetNamespace; XmlSchema rootSchema; XmlSchema currentSchema; XmlSchemaForm elementFormDefault; XmlSchemaForm attributeFormDefault; XmlSchemaDerivationMethod blockDefault; XmlSchemaDerivationMethod finalDefault; /*Dictionary schemaLocations; Dictionary chameleonSchemas;*/ Hashtable schemaLocations; Hashtable chameleonSchemas; Hashtable referenceNamespaces; Hashtable processedExternals; SortedList lockList; XmlReaderSettings readerSettings; //For redefines XmlSchema rootSchemaForRedefine = null; ArrayList redefinedList; static XmlSchema builtInSchemaForXmlNS; const XmlSchemaDerivationMethod schemaBlockDefaultAllowed = XmlSchemaDerivationMethod.Restriction | XmlSchemaDerivationMethod.Extension | XmlSchemaDerivationMethod.Substitution; const XmlSchemaDerivationMethod schemaFinalDefaultAllowed = XmlSchemaDerivationMethod.Restriction | XmlSchemaDerivationMethod.Extension | XmlSchemaDerivationMethod.List | XmlSchemaDerivationMethod.Union; const XmlSchemaDerivationMethod elementBlockAllowed = XmlSchemaDerivationMethod.Restriction | XmlSchemaDerivationMethod.Extension | XmlSchemaDerivationMethod.Substitution; const XmlSchemaDerivationMethod elementFinalAllowed = XmlSchemaDerivationMethod.Restriction | XmlSchemaDerivationMethod.Extension; const XmlSchemaDerivationMethod simpleTypeFinalAllowed = XmlSchemaDerivationMethod.Restriction | XmlSchemaDerivationMethod.Extension | XmlSchemaDerivationMethod.List | XmlSchemaDerivationMethod.Union; const XmlSchemaDerivationMethod complexTypeBlockAllowed = XmlSchemaDerivationMethod.Restriction | XmlSchemaDerivationMethod.Extension; const XmlSchemaDerivationMethod complexTypeFinalAllowed = XmlSchemaDerivationMethod.Restriction | XmlSchemaDerivationMethod.Extension; private XmlResolver xmlResolver = null; public Preprocessor(XmlNameTable nameTable, SchemaNames schemaNames, ValidationEventHandler eventHandler) : this(nameTable, schemaNames, eventHandler, new XmlSchemaCompilationSettings()){} public Preprocessor(XmlNameTable nameTable, SchemaNames schemaNames, ValidationEventHandler eventHandler, XmlSchemaCompilationSettings compilationSettings) : base(nameTable, schemaNames, eventHandler, compilationSettings) { referenceNamespaces = new Hashtable(); processedExternals = new Hashtable(); lockList = new SortedList(); } public bool Execute(XmlSchema schema, string targetNamespace, bool loadExternals) { rootSchema = schema; //Need to lock main schema here Xmlns = NameTable.Add("xmlns"); NsXsi = NameTable.Add(XmlReservedNs.NsXsi); rootSchema.ImportedSchemas.Clear(); rootSchema.ImportedNamespaces.Clear(); //Add root schema to the schemaLocations table if (rootSchema.BaseUri != null) { if (schemaLocations[rootSchema.BaseUri] == null) { schemaLocations.Add(rootSchema.BaseUri, rootSchema); } } //Check targetNamespace for rootSchema if (rootSchema.TargetNamespace != null) { if (targetNamespace == null) { targetNamespace = rootSchema.TargetNamespace; } else if (targetNamespace != rootSchema.TargetNamespace) { SendValidationEvent(Res.Sch_MismatchTargetNamespaceEx, targetNamespace, rootSchema.TargetNamespace, rootSchema); } } else if (targetNamespace != null && targetNamespace.Length != 0) { //if schema.TargetNamespace == null & targetNamespace != null, we will force the schema components into targetNamespace rootSchema = GetChameleonSchema(targetNamespace, rootSchema); //Chameleon include at top-level } if (loadExternals && xmlResolver != null) { LoadExternals(rootSchema); } BuildSchemaList(rootSchema); int schemaIndex = 0; XmlSchema listSchema; try { //Accquire locks on all schema objects; Need to lock only on pre-created schemas and not parsed schemas for (schemaIndex = 0; schemaIndex < lockList.Count; schemaIndex++) { listSchema = (XmlSchema)lockList.GetByIndex(schemaIndex); #pragma warning disable 0618 //@ Monitor.Enter(listSchema); #pragma warning restore 0618 listSchema.IsProcessing = false; //Reset processing flag from LoadExternals } //Preprocess rootSchemaForRedefine = rootSchema; Preprocess(rootSchema, targetNamespace, rootSchema.ImportedSchemas); if (redefinedList != null) { //If there were redefines for (int i = 0; i < redefinedList.Count; ++i) { PreprocessRedefine((RedefineEntry)redefinedList[i]); } } } finally { //Releasing locks in finally block if (schemaIndex == lockList.Count) { schemaIndex--; } for (int i = schemaIndex; schemaIndex >= 0; schemaIndex--) { listSchema = (XmlSchema)lockList.GetByIndex(schemaIndex); listSchema.IsProcessing = false; //Reset processing flag from Preprocess if (listSchema == Preprocessor.GetBuildInSchema()) { //dont re-set compiled flags for xml namespace schema Monitor.Exit(listSchema); continue; } listSchema.IsCompiledBySet = false; listSchema.IsPreprocessed = !HasErrors; Monitor.Exit(listSchema); //Release locks on all schema objects } } rootSchema.IsPreprocessed = !HasErrors; //For chameleon at top-level return !HasErrors; } private void Cleanup(XmlSchema schema) { if (schema == Preprocessor.GetBuildInSchema()) { return; } schema.Attributes.Clear(); schema.AttributeGroups.Clear(); schema.SchemaTypes.Clear(); schema.Elements.Clear(); schema.Groups.Clear(); schema.Notations.Clear(); schema.Ids.Clear(); schema.IdentityConstraints.Clear(); schema.IsRedefined = false; schema.IsCompiledBySet = false; } private void CleanupRedefine(XmlSchemaExternal include) { XmlSchemaRedefine rdef = include as XmlSchemaRedefine; rdef.AttributeGroups.Clear(); rdef.Groups.Clear(); rdef.SchemaTypes.Clear(); } internal XmlResolver XmlResolver { set { xmlResolver = value; } } internal XmlReaderSettings ReaderSettings { get { if (readerSettings == null) { readerSettings = new XmlReaderSettings(); readerSettings.DtdProcessing = DtdProcessing.Prohibit; } return readerSettings; } set { readerSettings = value; } } //internal Dictionary SchemaLocations { internal Hashtable SchemaLocations { set { schemaLocations = value; } } //internal Dictionary ChameleonSchemas { internal Hashtable ChameleonSchemas { set { chameleonSchemas = value; } } internal XmlSchema RootSchema { get { return rootSchema; //This is required to get back a cloned chameleon } } private void BuildSchemaList(XmlSchema schema) { if (lockList.Contains(schema.SchemaId)) { return; } lockList.Add(schema.SchemaId, schema); for (int i = 0; i < schema.Includes.Count; ++i) { XmlSchemaExternal ext = (XmlSchemaExternal)schema.Includes[i]; if (ext.Schema != null) { BuildSchemaList(ext.Schema); } } } // SxS: This method uses resource names read from source document and does not expose any resources to the caller. // It's OK to suppress the SxS warning. [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] [ResourceExposure(ResourceScope.None)] private void LoadExternals(XmlSchema schema) { if (schema.IsProcessing) { return; } schema.IsProcessing = true; for (int i = 0; i < schema.Includes.Count; ++i) { Uri includeLocation = null; //CASE 1: If the Schema object of the include has been set XmlSchemaExternal include = (XmlSchemaExternal)schema.Includes[i]; XmlSchema includedSchema = include.Schema; if (includedSchema != null) { // already loaded includeLocation = includedSchema.BaseUri; if (includeLocation != null && schemaLocations[includeLocation] == null) { schemaLocations.Add(includeLocation, includedSchema); } LoadExternals(includedSchema); continue; } //CASE 2: Try & Parse schema from the provided location string schemaLocation = include.SchemaLocation; Uri ruri = null; Exception innerException = null; if (schemaLocation != null) { try { ruri = ResolveSchemaLocationUri(schema, schemaLocation); } catch(Exception e) { ruri = null; innerException = e; } } if (include.Compositor == Compositor.Import) { XmlSchemaImport import = include as XmlSchemaImport; Debug.Assert(import != null); string importNS = import.Namespace != null ? import.Namespace : string.Empty; if (!schema.ImportedNamespaces.Contains(importNS)) { schema.ImportedNamespaces.Add(importNS); } //CASE 2.1: If the imported namespace is the XML namespace, // If the parent schemaSet already has schema for XML ns loaded, use that // Else if the location is null use the built-in one // else go through regular processing of parsing from location if (importNS == XmlReservedNs.NsXml) { if (ruri == null) { //Resolved location is null, hence get the built-in one include.Schema = Preprocessor.GetBuildInSchema(); continue; } } } //CASE 3: Parse schema from the provided location if (ruri == null) { if (schemaLocation != null) { SendValidationEvent(new XmlSchemaException(Res.Sch_InvalidIncludeLocation, null, innerException, include.SourceUri, include.LineNumber, include.LinePosition, include), XmlSeverityType.Warning); } continue; } if (schemaLocations[ruri] == null) { // Only if location already not processed object obj = null; try { obj = GetSchemaEntity(ruri); } catch(Exception eInner) { innerException = eInner; obj = null; } if (obj != null) { include.BaseUri = ruri; Type returnType = obj.GetType(); if (typeof(XmlSchema).IsAssignableFrom(returnType)) { //To handle XmlSchema and all its derived types include.Schema = (XmlSchema)obj; schemaLocations.Add(ruri, include.Schema); LoadExternals(include.Schema); } else { XmlReader reader = null; if (returnType.IsSubclassOf(typeof(Stream)) ) { readerSettings.CloseInput = true; readerSettings.XmlResolver = xmlResolver; reader = XmlReader.Create((Stream)obj, readerSettings, ruri.ToString() ); } else if (returnType.IsSubclassOf(typeof(XmlReader)) ) { reader = (XmlReader)obj; } else if (returnType.IsSubclassOf(typeof(TextReader))) { readerSettings.CloseInput = true; readerSettings.XmlResolver = xmlResolver; reader = XmlReader.Create((TextReader)obj, readerSettings, ruri.ToString() ); } if (reader == null) { SendValidationEvent(Res.Sch_InvalidIncludeLocation, include, XmlSeverityType.Warning); continue; } try { Parser parser = new Parser(SchemaType.XSD, NameTable, SchemaNames, EventHandler); parser.Parse(reader, null); while(reader.Read());// wellformness check includedSchema = parser.XmlSchema; include.Schema = includedSchema; schemaLocations.Add(ruri, includedSchema); LoadExternals(includedSchema); } catch(XmlSchemaException e) { SendValidationEvent(Res.Sch_CannotLoadSchemaLocation, schemaLocation, e.Message, e.SourceUri, e.LineNumber, e.LinePosition); } catch(Exception eInner) { SendValidationEvent(new XmlSchemaException(Res.Sch_InvalidIncludeLocation, null, eInner, include.SourceUri, include.LineNumber, include.LinePosition, include), XmlSeverityType.Warning); } finally { reader.Close(); } } } else { SendValidationEvent(new XmlSchemaException(Res.Sch_InvalidIncludeLocation, null, innerException, include.SourceUri, include.LineNumber, include.LinePosition, include), XmlSeverityType.Warning); } } else { //Location already in table and now seeing duplicate import / include include.Schema = (XmlSchema)schemaLocations[ruri]; //Set schema object even for duplicates } } } internal static XmlSchema GetBuildInSchema() { if (builtInSchemaForXmlNS == null) { XmlSchema tempSchema = new XmlSchema(); tempSchema.TargetNamespace = XmlReservedNs.NsXml; tempSchema.Namespaces.Add("xml", XmlReservedNs.NsXml); XmlSchemaAttribute lang = new XmlSchemaAttribute(); lang.Name = "lang"; lang.SchemaTypeName = new XmlQualifiedName("language", XmlReservedNs.NsXs); tempSchema.Items.Add(lang); XmlSchemaAttribute xmlbase = new XmlSchemaAttribute(); xmlbase.Name = "base"; xmlbase.SchemaTypeName = new XmlQualifiedName("anyURI", XmlReservedNs.NsXs); tempSchema.Items.Add(xmlbase); XmlSchemaAttribute space = new XmlSchemaAttribute(); space.Name = "space"; XmlSchemaSimpleType type = new XmlSchemaSimpleType(); XmlSchemaSimpleTypeRestriction r = new XmlSchemaSimpleTypeRestriction(); r.BaseTypeName = new XmlQualifiedName("NCName", XmlReservedNs.NsXs); XmlSchemaEnumerationFacet space_default = new XmlSchemaEnumerationFacet(); space_default.Value = "default"; r.Facets.Add(space_default); XmlSchemaEnumerationFacet space_preserve = new XmlSchemaEnumerationFacet(); space_preserve.Value = "preserve"; r.Facets.Add(space_preserve); type.Content = r; space.SchemaType = type; space.DefaultValue = "preserve"; tempSchema.Items.Add(space); XmlSchemaAttributeGroup attributeGroup = new XmlSchemaAttributeGroup(); attributeGroup.Name = "specialAttrs"; XmlSchemaAttribute langRef = new XmlSchemaAttribute(); langRef.RefName = new XmlQualifiedName("lang", XmlReservedNs.NsXml); attributeGroup.Attributes.Add(langRef); XmlSchemaAttribute spaceRef = new XmlSchemaAttribute(); spaceRef.RefName = new XmlQualifiedName("space", XmlReservedNs.NsXml); attributeGroup.Attributes.Add(spaceRef); XmlSchemaAttribute baseRef = new XmlSchemaAttribute(); baseRef.RefName = new XmlQualifiedName("base", XmlReservedNs.NsXml); attributeGroup.Attributes.Add(baseRef); tempSchema.Items.Add(attributeGroup); tempSchema.IsPreprocessed = true; tempSchema.CompileSchemaInSet(new NameTable(), null, null); //compile built-in schema Interlocked.CompareExchange(ref builtInSchemaForXmlNS, tempSchema, null); } return builtInSchemaForXmlNS; } private void BuildRefNamespaces(XmlSchema schema) { referenceNamespaces.Clear(); XmlSchemaImport import; string ns; //Add XSD namespace referenceNamespaces.Add(XmlReservedNs.NsXs,XmlReservedNs.NsXs); for (int i = 0; i < schema.Includes.Count; ++i) { XmlSchemaExternal include = (XmlSchemaExternal)schema.Includes[i]; if(include is XmlSchemaImport) { import = include as XmlSchemaImport; ns = import.Namespace; if (ns == null) { ns = string.Empty; } if(referenceNamespaces[ns] == null) referenceNamespaces.Add(ns,ns); } } //Add the schema's targetnamespace string tns = schema.TargetNamespace; if (tns == null) { tns = string.Empty; } if(referenceNamespaces[tns] == null) { referenceNamespaces.Add(tns,tns); } } private void ParseUri(string uri, string code, XmlSchemaObject sourceSchemaObject) { try { XmlConvert.ToUri(uri); // can throw } catch (FormatException eInner) { SendValidationEvent(code, new string[] { uri }, eInner, sourceSchemaObject); } } private void Preprocess(XmlSchema schema, string targetNamespace, ArrayList imports) { XmlSchema prevRootSchemaForRedefine = null; if (schema.IsProcessing) { return; } schema.IsProcessing = true; string tns = schema.TargetNamespace; if (tns != null) { schema.TargetNamespace = tns = NameTable.Add(tns); if (tns.Length == 0) { SendValidationEvent(Res.Sch_InvalidTargetNamespaceAttribute, schema); } else { ParseUri(tns, Res.Sch_InvalidNamespace, schema); } } if (schema.Version != null) { XmlSchemaDatatype tokenDt = DatatypeImplementation.GetSimpleTypeFromTypeCode(XmlTypeCode.Token).Datatype; object version; Exception exception = tokenDt.TryParseValue(schema.Version, null, null, out version); if (exception != null) { SendValidationEvent(Res.Sch_AttributeValueDataTypeDetailed, new string[] { "version", schema.Version, tokenDt.TypeCodeString, exception.Message }, exception, schema); } else { schema.Version = (string)version; } } //Begin processing the schema after checking targetNamespace and verifying chameleon Cleanup(schema); for (int i = 0; i < schema.Includes.Count; ++i) { XmlSchemaExternal include = (XmlSchemaExternal)schema.Includes[i]; XmlSchema externalSchema = include.Schema; SetParent(include, schema); PreprocessAnnotation(include); string loc = include.SchemaLocation; if (loc != null) { ParseUri(loc, Res.Sch_InvalidSchemaLocation, include); } else if ((include.Compositor == Compositor.Include || include.Compositor == Compositor.Redefine) && externalSchema == null){ SendValidationEvent(Res.Sch_MissRequiredAttribute, "schemaLocation", include); } switch (include.Compositor) { case Compositor.Import: XmlSchemaImport import = include as XmlSchemaImport; string importNS = import.Namespace; if (importNS == schema.TargetNamespace) { SendValidationEvent(Res.Sch_ImportTargetNamespace, include); } if (externalSchema != null) { if (importNS != externalSchema.TargetNamespace) { SendValidationEvent(Res.Sch_MismatchTargetNamespaceImport, importNS, externalSchema.TargetNamespace, import); } //SetParent(externalSchema, import); prevRootSchemaForRedefine = rootSchemaForRedefine; rootSchemaForRedefine = externalSchema; //Make the imported schema the root schema for redefines Preprocess(externalSchema, importNS, imports); rootSchemaForRedefine = prevRootSchemaForRedefine; //Reset the root schema for redefines } else { if (importNS != null) { if (importNS.Length == 0) { SendValidationEvent(Res.Sch_InvalidNamespaceAttribute, importNS, include); } else { ParseUri(importNS, Res.Sch_InvalidNamespace, include); } } } break; case Compositor.Include: XmlSchema includedSchema = include.Schema; if (includedSchema != null) { //SetParent(includedSchema, include); goto default; } break; case Compositor.Redefine: if (externalSchema != null) { //SetParent(externalSchema, include); CleanupRedefine(include); goto default; } break; default: //For include, redefine common case if (externalSchema.TargetNamespace != null) { if (schema.TargetNamespace != externalSchema.TargetNamespace) { //namespaces for includes should be the same SendValidationEvent(Res.Sch_MismatchTargetNamespaceInclude, externalSchema.TargetNamespace, schema.TargetNamespace, include); } } else if (targetNamespace != null && targetNamespace.Length != 0) { //Chameleon redefine externalSchema = GetChameleonSchema(targetNamespace, externalSchema); include.Schema = externalSchema; //Reset the schema property to the cloned schema } Preprocess(externalSchema, schema.TargetNamespace, imports); break; } } //Begin processing the current schema passed to preprocess //Build the namespaces that can be referenced in the current schema this.currentSchema = schema; BuildRefNamespaces(schema); ValidateIdAttribute(schema); this.targetNamespace = targetNamespace == null ? string.Empty : targetNamespace; SetSchemaDefaults(schema); processedExternals.Clear(); XmlSchemaExternal external; for (int i = 0; i < schema.Includes.Count; i++) { external = (XmlSchemaExternal) schema.Includes[i]; XmlSchema includedSchema = external.Schema; if (includedSchema != null) { switch (external.Compositor) { case Compositor.Include: if (processedExternals[includedSchema] != null) { continue; //Already processed this included schema; } processedExternals.Add(includedSchema, external); CopyIncludedComponents(includedSchema, schema); break; case Compositor.Redefine: if (redefinedList == null) { redefinedList = new ArrayList(); } redefinedList.Add(new RedefineEntry(external as XmlSchemaRedefine, rootSchemaForRedefine)); if (processedExternals[includedSchema] != null) { continue; //Already processed this included schema; } processedExternals.Add(includedSchema, external); CopyIncludedComponents(includedSchema, schema); break; case Compositor.Import: if (includedSchema != rootSchema) { XmlSchemaImport import = external as XmlSchemaImport; string importNS = import.Namespace != null ? import.Namespace : string.Empty; if (!imports.Contains(includedSchema)) { // imports.Add(includedSchema); } if (!rootSchema.ImportedNamespaces.Contains(importNS)) { rootSchema.ImportedNamespaces.Add(importNS); } } break; default: Debug.Assert(false); break; } } else if (external.Compositor == Compositor.Redefine) { XmlSchemaRedefine redefine = external as XmlSchemaRedefine; if (redefine.BaseUri == null) { for (int j = 0; j < redefine.Items.Count; ++j) { if (!(redefine.Items[j] is XmlSchemaAnnotation)) { SendValidationEvent(Res.Sch_RedefineNoSchema, redefine); break; } } } } ValidateIdAttribute(external); } List removeItemsList = new List(); XmlSchemaObjectCollection schemaItems = schema.Items; for (int i = 0; i < schemaItems.Count; ++i) { SetParent(schemaItems[i], schema); XmlSchemaAttribute attribute = schemaItems[i] as XmlSchemaAttribute; if (attribute != null) { PreprocessAttribute(attribute); AddToTable(schema.Attributes, attribute.QualifiedName, attribute); } else if (schemaItems[i] is XmlSchemaAttributeGroup) { XmlSchemaAttributeGroup attributeGroup = (XmlSchemaAttributeGroup)schemaItems[i]; PreprocessAttributeGroup(attributeGroup); AddToTable(schema.AttributeGroups, attributeGroup.QualifiedName, attributeGroup); } else if (schemaItems[i] is XmlSchemaComplexType) { XmlSchemaComplexType complexType = (XmlSchemaComplexType)schemaItems[i]; PreprocessComplexType(complexType, false); AddToTable(schema.SchemaTypes, complexType.QualifiedName, complexType); } else if (schemaItems[i] is XmlSchemaSimpleType) { XmlSchemaSimpleType simpleType = (XmlSchemaSimpleType)schemaItems[i]; PreprocessSimpleType(simpleType, false); AddToTable(schema.SchemaTypes, simpleType.QualifiedName, simpleType); } else if (schemaItems[i] is XmlSchemaElement) { XmlSchemaElement element = (XmlSchemaElement)schemaItems[i]; PreprocessElement(element); AddToTable(schema.Elements, element.QualifiedName, element); } else if (schemaItems[i] is XmlSchemaGroup) { XmlSchemaGroup group = (XmlSchemaGroup)schemaItems[i]; PreprocessGroup(group); AddToTable(schema.Groups, group.QualifiedName, group); } else if (schemaItems[i] is XmlSchemaNotation) { XmlSchemaNotation notation = (XmlSchemaNotation)schemaItems[i]; PreprocessNotation(notation); AddToTable(schema.Notations, notation.QualifiedName, notation); } else if (schemaItems[i] is XmlSchemaAnnotation) { PreprocessAnnotation(schemaItems[i] as XmlSchemaAnnotation); } else { SendValidationEvent(Res.Sch_InvalidCollection,(XmlSchemaObject)schemaItems[i]); removeItemsList.Add(schemaItems[i]); } } for (int i = 0; i < removeItemsList.Count; ++i) { schema.Items.Remove(removeItemsList[i]); } } private void CopyIncludedComponents(XmlSchema includedSchema, XmlSchema schema) { foreach (XmlSchemaElement element in includedSchema.Elements.Values) { AddToTable(schema.Elements, element.QualifiedName, element); } foreach (XmlSchemaAttribute attribute in includedSchema.Attributes.Values) { AddToTable(schema.Attributes, attribute.QualifiedName, attribute); } foreach (XmlSchemaGroup group in includedSchema.Groups.Values) { AddToTable(schema.Groups, group.QualifiedName, group); } foreach (XmlSchemaAttributeGroup attributeGroup in includedSchema.AttributeGroups.Values) { AddToTable(schema.AttributeGroups, attributeGroup.QualifiedName, attributeGroup); } foreach (XmlSchemaType type in includedSchema.SchemaTypes.Values) { AddToTable(schema.SchemaTypes, type.QualifiedName, type); } foreach (XmlSchemaNotation notation in includedSchema.Notations.Values) { AddToTable(schema.Notations, notation.QualifiedName, notation); } } private void PreprocessRedefine(RedefineEntry redefineEntry) { XmlSchemaRedefine redefine = redefineEntry.redefine; XmlSchema originalSchema = redefine.Schema; currentSchema = GetParentSchema(redefine); //Set this for correct schema context in ValidateIdAttribute & ValidateQNameAttribute for redefines Debug.Assert(currentSchema != null); SetSchemaDefaults(currentSchema); if (originalSchema.IsRedefined) { SendValidationEvent(Res.Sch_MultipleRedefine, redefine, XmlSeverityType.Warning); return; } originalSchema.IsRedefined = true; XmlSchema schemaToUpdate = redefineEntry.schemaToUpdate; ArrayList includesOfRedefine = new ArrayList(); GetIncludedSet(originalSchema, includesOfRedefine); string targetNS = schemaToUpdate.TargetNamespace == null ? string.Empty : schemaToUpdate.TargetNamespace; XmlSchemaObjectCollection items = redefine.Items; for (int i = 0; i < items.Count; ++i) { SetParent(items[i], redefine); XmlSchemaGroup group = items[i] as XmlSchemaGroup; if (group != null) { PreprocessGroup(group); group.QualifiedName.SetNamespace(targetNS); //Since PreprocessGroup will use this.targetNamespace and that will be that of the root schema's if (redefine.Groups[group.QualifiedName] != null) { SendValidationEvent(Res.Sch_GroupDoubleRedefine, group); } else { AddToTable(redefine.Groups, group.QualifiedName, group); XmlSchemaGroup originalGroup = (XmlSchemaGroup)schemaToUpdate.Groups[group.QualifiedName]; XmlSchema parentSchema = GetParentSchema(originalGroup); if (originalGroup == null || (parentSchema != originalSchema && !includesOfRedefine.Contains(parentSchema)) ) { SendValidationEvent(Res.Sch_ComponentRedefineNotFound, "", group.QualifiedName.ToString(), group); } else { group.Redefined = originalGroup; schemaToUpdate.Groups.Insert(group.QualifiedName, group); CheckRefinedGroup(group); } } } else if (items[i] is XmlSchemaAttributeGroup) { XmlSchemaAttributeGroup attributeGroup = (XmlSchemaAttributeGroup)items[i]; PreprocessAttributeGroup(attributeGroup); attributeGroup.QualifiedName.SetNamespace(targetNS); //Since PreprocessAttributeGroup will use this.targetNamespace and that will be that of the root schema's if (redefine.AttributeGroups[attributeGroup.QualifiedName] != null) { SendValidationEvent(Res.Sch_AttrGroupDoubleRedefine, attributeGroup); } else { AddToTable(redefine.AttributeGroups, attributeGroup.QualifiedName, attributeGroup); XmlSchemaAttributeGroup originalAttrGroup = (XmlSchemaAttributeGroup)schemaToUpdate.AttributeGroups[attributeGroup.QualifiedName]; XmlSchema parentSchema = GetParentSchema(originalAttrGroup); if (originalAttrGroup == null || (parentSchema != originalSchema && !includesOfRedefine.Contains(parentSchema)) ) { SendValidationEvent(Res.Sch_ComponentRedefineNotFound, "", attributeGroup.QualifiedName.ToString(), attributeGroup); } else { attributeGroup.Redefined = originalAttrGroup; schemaToUpdate.AttributeGroups.Insert(attributeGroup.QualifiedName, attributeGroup); CheckRefinedAttributeGroup(attributeGroup); } } } else if (items[i] is XmlSchemaComplexType) { XmlSchemaComplexType complexType = (XmlSchemaComplexType)items[i]; PreprocessComplexType(complexType, false); complexType.QualifiedName.SetNamespace(targetNS); //Since PreprocessComplexType will use this.targetNamespace and that will be that of the root schema's if (redefine.SchemaTypes[complexType.QualifiedName] != null) { SendValidationEvent(Res.Sch_ComplexTypeDoubleRedefine, complexType); } else { AddToTable(redefine.SchemaTypes, complexType.QualifiedName, complexType); XmlSchemaType originalType = (XmlSchemaType)schemaToUpdate.SchemaTypes[complexType.QualifiedName]; XmlSchema parentSchema = GetParentSchema(originalType); if (originalType == null || (parentSchema != originalSchema && !includesOfRedefine.Contains(parentSchema)) ) { SendValidationEvent(Res.Sch_ComponentRedefineNotFound, "", complexType.QualifiedName.ToString(), complexType); } else if (originalType is XmlSchemaComplexType) { complexType.Redefined = originalType; schemaToUpdate.SchemaTypes.Insert(complexType.QualifiedName, complexType); CheckRefinedComplexType(complexType); } else { SendValidationEvent(Res.Sch_SimpleToComplexTypeRedefine, complexType); } } } else if (items[i] is XmlSchemaSimpleType) { XmlSchemaSimpleType simpleType = (XmlSchemaSimpleType)items[i]; PreprocessSimpleType(simpleType, false); simpleType.QualifiedName.SetNamespace(targetNS); //Since PreprocessSimpleType will use this.targetNamespace and that will be that of the root schema's if (redefine.SchemaTypes[simpleType.QualifiedName] != null) { SendValidationEvent(Res.Sch_SimpleTypeDoubleRedefine, simpleType); } else { AddToTable(redefine.SchemaTypes, simpleType.QualifiedName, simpleType); XmlSchemaType originalType = (XmlSchemaType)schemaToUpdate.SchemaTypes[simpleType.QualifiedName]; XmlSchema parentSchema = GetParentSchema(originalType); if (originalType == null || (parentSchema != originalSchema && !includesOfRedefine.Contains(parentSchema)) ) { SendValidationEvent(Res.Sch_ComponentRedefineNotFound, "", simpleType.QualifiedName.ToString(), simpleType); } else if (originalType is XmlSchemaSimpleType) { simpleType.Redefined = originalType; schemaToUpdate.SchemaTypes.Insert(simpleType.QualifiedName, simpleType); CheckRefinedSimpleType(simpleType); } else { SendValidationEvent(Res.Sch_ComplexToSimpleTypeRedefine, simpleType); } } } } } private void GetIncludedSet(XmlSchema schema, ArrayList includesList) { if (includesList.Contains(schema)) { return; } includesList.Add(schema); for (int i = 0; i < schema.Includes.Count; ++i) { XmlSchemaExternal external = (XmlSchemaExternal)schema.Includes[i]; if (external.Compositor == Compositor.Include || external.Compositor == Compositor.Redefine) { if (external.Schema != null) { GetIncludedSet(external.Schema, includesList); } } } } internal static XmlSchema GetParentSchema(XmlSchemaObject currentSchemaObject) { XmlSchema parentSchema = null; Debug.Assert((currentSchemaObject as XmlSchema) == null); //The current object should not be schema while(parentSchema == null && currentSchemaObject != null) { currentSchemaObject = currentSchemaObject.Parent; parentSchema = currentSchemaObject as XmlSchema; } return parentSchema; } private void SetSchemaDefaults(XmlSchema schema) { if (schema.BlockDefault == XmlSchemaDerivationMethod.All) { this.blockDefault = XmlSchemaDerivationMethod.All; } else if (schema.BlockDefault == XmlSchemaDerivationMethod.None) { this.blockDefault = XmlSchemaDerivationMethod.Empty; } else { if ((schema.BlockDefault & ~schemaBlockDefaultAllowed) != 0) { SendValidationEvent(Res.Sch_InvalidBlockDefaultValue, schema); } this.blockDefault = schema.BlockDefault & schemaBlockDefaultAllowed; } if (schema.FinalDefault == XmlSchemaDerivationMethod.All) { this.finalDefault = XmlSchemaDerivationMethod.All; } else if (schema.FinalDefault == XmlSchemaDerivationMethod.None) { this.finalDefault = XmlSchemaDerivationMethod.Empty; } else { if ((schema.FinalDefault & ~schemaFinalDefaultAllowed) != 0) { SendValidationEvent(Res.Sch_InvalidFinalDefaultValue, schema); } this.finalDefault = schema.FinalDefault & schemaFinalDefaultAllowed; } this.elementFormDefault = schema.ElementFormDefault; if (this.elementFormDefault == XmlSchemaForm.None) { this.elementFormDefault = XmlSchemaForm.Unqualified; } this.attributeFormDefault = schema.AttributeFormDefault; if (this.attributeFormDefault == XmlSchemaForm.None) { this.attributeFormDefault = XmlSchemaForm.Unqualified; } } private int CountGroupSelfReference(XmlSchemaObjectCollection items, XmlQualifiedName name, XmlSchemaGroup redefined) { int count = 0; for (int i = 0; i < items.Count; ++i) { XmlSchemaGroupRef groupRef = items[i] as XmlSchemaGroupRef; if (groupRef != null) { if (groupRef.RefName == name) { groupRef.Redefined = redefined; if (groupRef.MinOccurs != decimal.One || groupRef.MaxOccurs != decimal.One) { SendValidationEvent(Res.Sch_MinMaxGroupRedefine, groupRef); } count ++; } } else if (items[i] is XmlSchemaGroupBase) { count += CountGroupSelfReference(((XmlSchemaGroupBase)items[i]).Items, name, redefined); } if (count > 1) { break; } } return count; } private void CheckRefinedGroup(XmlSchemaGroup group) { int count = 0; if (group.Particle != null) { count = CountGroupSelfReference(group.Particle.Items, group.QualifiedName, group.Redefined); } if (count > 1) { SendValidationEvent(Res.Sch_MultipleGroupSelfRef, group); } group.SelfReferenceCount = count; } private void CheckRefinedAttributeGroup(XmlSchemaAttributeGroup attributeGroup) { int count = 0; for (int i = 0; i < attributeGroup.Attributes.Count; ++i) { XmlSchemaAttributeGroupRef attrGroupRef = attributeGroup.Attributes[i] as XmlSchemaAttributeGroupRef; if (attrGroupRef != null && attrGroupRef.RefName == attributeGroup.QualifiedName) { count++; } } if (count > 1) { SendValidationEvent(Res.Sch_MultipleAttrGroupSelfRef, attributeGroup); } attributeGroup.SelfReferenceCount = count; } private void CheckRefinedSimpleType(XmlSchemaSimpleType stype) { if (stype.Content != null && stype.Content is XmlSchemaSimpleTypeRestriction) { XmlSchemaSimpleTypeRestriction restriction = (XmlSchemaSimpleTypeRestriction)stype.Content; if (restriction.BaseTypeName == stype.QualifiedName) { return; } } SendValidationEvent(Res.Sch_InvalidTypeRedefine, stype); } private void CheckRefinedComplexType(XmlSchemaComplexType ctype) { if (ctype.ContentModel != null) { XmlQualifiedName baseName; if (ctype.ContentModel is XmlSchemaComplexContent) { XmlSchemaComplexContent content = (XmlSchemaComplexContent)ctype.ContentModel; if (content.Content is XmlSchemaComplexContentRestriction) { baseName = ((XmlSchemaComplexContentRestriction)content.Content).BaseTypeName; } else { baseName = ((XmlSchemaComplexContentExtension)content.Content).BaseTypeName; } } else { XmlSchemaSimpleContent content = (XmlSchemaSimpleContent)ctype.ContentModel; if (content.Content is XmlSchemaSimpleContentRestriction) { baseName = ((XmlSchemaSimpleContentRestriction)content.Content).BaseTypeName; } else { baseName = ((XmlSchemaSimpleContentExtension)content.Content).BaseTypeName; } } if (baseName == ctype.QualifiedName) { return; } } SendValidationEvent(Res.Sch_InvalidTypeRedefine, ctype); } private void PreprocessAttribute(XmlSchemaAttribute attribute) { if (attribute.Name != null) { ValidateNameAttribute(attribute); attribute.SetQualifiedName(new XmlQualifiedName(attribute.Name, this.targetNamespace)); } else { SendValidationEvent(Res.Sch_MissRequiredAttribute, "name", attribute); } if (attribute.Use != XmlSchemaUse.None) { SendValidationEvent(Res.Sch_ForbiddenAttribute, "use", attribute); } if (attribute.Form != XmlSchemaForm.None) { SendValidationEvent(Res.Sch_ForbiddenAttribute, "form", attribute); } PreprocessAttributeContent(attribute); ValidateIdAttribute(attribute); } private void PreprocessLocalAttribute(XmlSchemaAttribute attribute) { if (attribute.Name != null) { // name ValidateNameAttribute(attribute); PreprocessAttributeContent(attribute); attribute.SetQualifiedName(new XmlQualifiedName(attribute.Name, (attribute.Form == XmlSchemaForm.Qualified || (attribute.Form == XmlSchemaForm.None && this.attributeFormDefault == XmlSchemaForm.Qualified)) ? this.targetNamespace : null)); } else { // ref PreprocessAnnotation(attribute); //set parent of annotation child of ref if (attribute.RefName.IsEmpty) { SendValidationEvent(Res.Sch_AttributeNameRef, "???", attribute); } else { ValidateQNameAttribute(attribute, "ref", attribute.RefName); } if (!attribute.SchemaTypeName.IsEmpty || attribute.SchemaType != null || attribute.Form != XmlSchemaForm.None /*|| attribute.DefaultValue != null || attribute.FixedValue != null*/ ) { SendValidationEvent(Res.Sch_InvalidAttributeRef, attribute); } attribute.SetQualifiedName(attribute.RefName); } ValidateIdAttribute(attribute); } private void PreprocessAttributeContent(XmlSchemaAttribute attribute) { PreprocessAnnotation(attribute); if (Ref.Equal(currentSchema.TargetNamespace, NsXsi)) { SendValidationEvent(Res.Sch_TargetNamespaceXsi, attribute); } if (!attribute.RefName.IsEmpty) { SendValidationEvent(Res.Sch_ForbiddenAttribute, "ref", attribute); } if (attribute.DefaultValue != null && attribute.FixedValue != null) { SendValidationEvent(Res.Sch_DefaultFixedAttributes, attribute); } if (attribute.DefaultValue != null && attribute.Use != XmlSchemaUse.Optional && attribute.Use != XmlSchemaUse.None) { SendValidationEvent(Res.Sch_OptionalDefaultAttribute, attribute); } if (attribute.Name == Xmlns) { SendValidationEvent(Res.Sch_XmlNsAttribute, attribute); } if (attribute.SchemaType != null) { SetParent(attribute.SchemaType, attribute); if (!attribute.SchemaTypeName.IsEmpty) { SendValidationEvent(Res.Sch_TypeMutualExclusive, attribute); } PreprocessSimpleType(attribute.SchemaType, true); } if (!attribute.SchemaTypeName.IsEmpty) { ValidateQNameAttribute(attribute, "type", attribute.SchemaTypeName); } } private void PreprocessAttributeGroup(XmlSchemaAttributeGroup attributeGroup) { if (attributeGroup.Name != null) { ValidateNameAttribute(attributeGroup); attributeGroup.SetQualifiedName(new XmlQualifiedName(attributeGroup.Name, this.targetNamespace)); } else { SendValidationEvent(Res.Sch_MissRequiredAttribute, "name", attributeGroup); } PreprocessAttributes(attributeGroup.Attributes, attributeGroup.AnyAttribute, attributeGroup); PreprocessAnnotation(attributeGroup); ValidateIdAttribute(attributeGroup); } private void PreprocessElement(XmlSchemaElement element) { if (element.Name != null) { ValidateNameAttribute(element); element.SetQualifiedName(new XmlQualifiedName(element.Name, this.targetNamespace)); } else { SendValidationEvent(Res.Sch_MissRequiredAttribute, "name", element); } PreprocessElementContent(element); if (element.Final == XmlSchemaDerivationMethod.All) { element.SetFinalResolved(XmlSchemaDerivationMethod.All); } else if (element.Final == XmlSchemaDerivationMethod.None) { if (this.finalDefault == XmlSchemaDerivationMethod.All) { element.SetFinalResolved(XmlSchemaDerivationMethod.All); } else { element.SetFinalResolved(this.finalDefault & elementFinalAllowed); } } else { if ((element.Final & ~elementFinalAllowed) != 0) { SendValidationEvent(Res.Sch_InvalidElementFinalValue, element); } element.SetFinalResolved(element.Final & elementFinalAllowed); } if (element.Form != XmlSchemaForm.None) { SendValidationEvent(Res.Sch_ForbiddenAttribute, "form", element); } if (element.MinOccursString != null) { SendValidationEvent(Res.Sch_ForbiddenAttribute, "minOccurs", element); } if (element.MaxOccursString != null) { SendValidationEvent(Res.Sch_ForbiddenAttribute, "maxOccurs", element); } if (!element.SubstitutionGroup.IsEmpty) { ValidateQNameAttribute(element, "type", element.SubstitutionGroup); } ValidateIdAttribute(element); } private void PreprocessLocalElement(XmlSchemaElement element) { if (element.Name != null) { // name ValidateNameAttribute(element); PreprocessElementContent(element); element.SetQualifiedName(new XmlQualifiedName(element.Name, (element.Form == XmlSchemaForm.Qualified || (element.Form == XmlSchemaForm.None && this.elementFormDefault == XmlSchemaForm.Qualified))? this.targetNamespace : null)); } else { // ref PreprocessAnnotation(element); //Check annotation child for ref and set parent if (element.RefName.IsEmpty) { SendValidationEvent(Res.Sch_ElementNameRef, element); } else { ValidateQNameAttribute(element, "ref", element.RefName); } if (!element.SchemaTypeName.IsEmpty || element.HasAbstractAttribute || element.Block != XmlSchemaDerivationMethod.None || element.SchemaType != null || element.HasConstraints || element.DefaultValue != null || element.Form != XmlSchemaForm.None || element.FixedValue != null || element.HasNillableAttribute) { SendValidationEvent(Res.Sch_InvalidElementRef, element); } if (element.DefaultValue != null && element.FixedValue != null) { SendValidationEvent(Res.Sch_DefaultFixedAttributes, element); } element.SetQualifiedName(element.RefName); } if (element.MinOccurs > element.MaxOccurs) { element.MinOccurs = decimal.Zero; SendValidationEvent(Res.Sch_MinGtMax, element); } if(element.HasAbstractAttribute) { SendValidationEvent(Res.Sch_ForbiddenAttribute, "abstract", element); } if (element.Final != XmlSchemaDerivationMethod.None) { SendValidationEvent(Res.Sch_ForbiddenAttribute, "final", element); } if (!element.SubstitutionGroup.IsEmpty) { SendValidationEvent(Res.Sch_ForbiddenAttribute, "substitutionGroup", element); } ValidateIdAttribute(element); } private void PreprocessElementContent(XmlSchemaElement element) { PreprocessAnnotation(element); //Set parent for Annotation child of element if (!element.RefName.IsEmpty) { SendValidationEvent(Res.Sch_ForbiddenAttribute, "ref", element); } if (element.Block == XmlSchemaDerivationMethod.All) { element.SetBlockResolved(XmlSchemaDerivationMethod.All); } else if (element.Block == XmlSchemaDerivationMethod.None) { if (this.blockDefault == XmlSchemaDerivationMethod.All) { element.SetBlockResolved(XmlSchemaDerivationMethod.All); } else { element.SetBlockResolved(this.blockDefault & elementBlockAllowed); } } else { if ((element.Block & ~elementBlockAllowed) != 0) { SendValidationEvent(Res.Sch_InvalidElementBlockValue, element); } element.SetBlockResolved(element.Block & elementBlockAllowed); } if (element.SchemaType != null) { SetParent(element.SchemaType, element); //Set parent for simple / complex type child of element if (!element.SchemaTypeName.IsEmpty) { SendValidationEvent(Res.Sch_TypeMutualExclusive, element); } if (element.SchemaType is XmlSchemaComplexType) { PreprocessComplexType((XmlSchemaComplexType)element.SchemaType, true); } else { PreprocessSimpleType((XmlSchemaSimpleType)element.SchemaType, true); } } if (!element.SchemaTypeName.IsEmpty) { ValidateQNameAttribute(element, "type", element.SchemaTypeName); } if (element.DefaultValue != null && element.FixedValue != null) { SendValidationEvent(Res.Sch_DefaultFixedAttributes, element); } for (int i = 0; i < element.Constraints.Count; ++i) { XmlSchemaIdentityConstraint identityConstraint = (XmlSchemaIdentityConstraint)element.Constraints[i]; SetParent(identityConstraint, element); PreprocessIdentityConstraint(identityConstraint); } } private void PreprocessIdentityConstraint(XmlSchemaIdentityConstraint constraint) { bool valid = true; PreprocessAnnotation(constraint); //Set parent of annotation child of key/keyref/unique if (constraint.Name != null) { ValidateNameAttribute(constraint); constraint.SetQualifiedName(new XmlQualifiedName(constraint.Name, this.targetNamespace)); } else { SendValidationEvent(Res.Sch_MissRequiredAttribute, "name", constraint); valid = false; } if (rootSchema.IdentityConstraints[constraint.QualifiedName] != null) { SendValidationEvent(Res.Sch_DupIdentityConstraint, constraint.QualifiedName.ToString(), constraint); valid = false; } else { rootSchema.IdentityConstraints.Add(constraint.QualifiedName, constraint); } if (constraint.Selector == null) { SendValidationEvent(Res.Sch_IdConstraintNoSelector, constraint); valid = false; } if (constraint.Fields.Count == 0) { SendValidationEvent(Res.Sch_IdConstraintNoFields, constraint); valid = false; } if (constraint is XmlSchemaKeyref) { XmlSchemaKeyref keyref = (XmlSchemaKeyref)constraint; if (keyref.Refer.IsEmpty) { SendValidationEvent(Res.Sch_IdConstraintNoRefer, constraint); valid = false; } else { ValidateQNameAttribute(keyref, "refer", keyref.Refer); } } if (valid) { ValidateIdAttribute(constraint); ValidateIdAttribute(constraint.Selector); SetParent(constraint.Selector, constraint); for (int i = 0; i < constraint.Fields.Count; ++i) { SetParent(constraint.Fields[i], constraint); ValidateIdAttribute(constraint.Fields[i]); } } } private void PreprocessSimpleType(XmlSchemaSimpleType simpleType, bool local) { if (local) { if (simpleType.Name != null) { SendValidationEvent(Res.Sch_ForbiddenAttribute, "name", simpleType); } } else { if (simpleType.Name != null) { ValidateNameAttribute(simpleType); simpleType.SetQualifiedName(new XmlQualifiedName(simpleType.Name, this.targetNamespace)); } else { SendValidationEvent(Res.Sch_MissRequiredAttribute, "name", simpleType); } if (simpleType.Final == XmlSchemaDerivationMethod.All) { simpleType.SetFinalResolved(XmlSchemaDerivationMethod.All); } else if (simpleType.Final == XmlSchemaDerivationMethod.None) { if (this.finalDefault == XmlSchemaDerivationMethod.All) { simpleType.SetFinalResolved(XmlSchemaDerivationMethod.All); } else { simpleType.SetFinalResolved(this.finalDefault & simpleTypeFinalAllowed); } } else { if ((simpleType.Final & ~simpleTypeFinalAllowed) != 0) { SendValidationEvent(Res.Sch_InvalidSimpleTypeFinalValue, simpleType); } simpleType.SetFinalResolved(simpleType.Final & simpleTypeFinalAllowed); } } if (simpleType.Content == null) { SendValidationEvent(Res.Sch_NoSimpleTypeContent, simpleType); } else if (simpleType.Content is XmlSchemaSimpleTypeRestriction) { XmlSchemaSimpleTypeRestriction restriction = (XmlSchemaSimpleTypeRestriction)simpleType.Content; //SetParent SetParent(restriction, simpleType); for (int i = 0; i < restriction.Facets.Count; ++i) { SetParent(restriction.Facets[i], restriction); } if (restriction.BaseType != null) { if (!restriction.BaseTypeName.IsEmpty) { SendValidationEvent(Res.Sch_SimpleTypeRestRefBase, restriction); } PreprocessSimpleType(restriction.BaseType, true); } else { if (restriction.BaseTypeName.IsEmpty) { SendValidationEvent(Res.Sch_SimpleTypeRestRefBaseNone, restriction); } else { ValidateQNameAttribute(restriction, "base", restriction.BaseTypeName); } } PreprocessAnnotation(restriction); //set parent of annotation child of simple type restriction ValidateIdAttribute(restriction); } else if (simpleType.Content is XmlSchemaSimpleTypeList) { XmlSchemaSimpleTypeList list = (XmlSchemaSimpleTypeList)simpleType.Content; SetParent(list, simpleType); if (list.ItemType != null) { if (!list.ItemTypeName.IsEmpty) { SendValidationEvent(Res.Sch_SimpleTypeListRefBase, list); } SetParent(list.ItemType, list); PreprocessSimpleType(list.ItemType, true); } else { if (list.ItemTypeName.IsEmpty) { SendValidationEvent(Res.Sch_SimpleTypeListRefBaseNone, list); } else { ValidateQNameAttribute(list, "itemType", list.ItemTypeName); } } PreprocessAnnotation(list); //set parent of annotation child of simple type list ValidateIdAttribute(list); } else { // union XmlSchemaSimpleTypeUnion union1 = (XmlSchemaSimpleTypeUnion)simpleType.Content; SetParent(union1, simpleType); int baseTypeCount = union1.BaseTypes.Count; if (union1.MemberTypes != null) { baseTypeCount += union1.MemberTypes.Length; XmlQualifiedName[] qNames = union1.MemberTypes; for (int i = 0; i < qNames.Length; ++i) { ValidateQNameAttribute(union1, "memberTypes", qNames[i]); } } if (baseTypeCount == 0) { SendValidationEvent(Res.Sch_SimpleTypeUnionNoBase, union1); } for (int i = 0; i < union1.BaseTypes.Count; ++i) { XmlSchemaSimpleType type = (XmlSchemaSimpleType)union1.BaseTypes[i]; SetParent(type, union1); PreprocessSimpleType(type, true); } PreprocessAnnotation(union1); //set parent of annotation child of simple type union ValidateIdAttribute(union1); } ValidateIdAttribute(simpleType); } private void PreprocessComplexType(XmlSchemaComplexType complexType, bool local) { if (local) { if (complexType.Name != null) { SendValidationEvent(Res.Sch_ForbiddenAttribute, "name", complexType); } } else { if (complexType.Name != null) { ValidateNameAttribute(complexType); complexType.SetQualifiedName(new XmlQualifiedName(complexType.Name, this.targetNamespace)); } else { SendValidationEvent(Res.Sch_MissRequiredAttribute, "name", complexType); } if (complexType.Block == XmlSchemaDerivationMethod.All) { complexType.SetBlockResolved(XmlSchemaDerivationMethod.All); } else if (complexType.Block == XmlSchemaDerivationMethod.None) { complexType.SetBlockResolved(this.blockDefault & complexTypeBlockAllowed); } else { if ((complexType.Block & ~complexTypeBlockAllowed) != 0) { SendValidationEvent(Res.Sch_InvalidComplexTypeBlockValue, complexType); } complexType.SetBlockResolved(complexType.Block & complexTypeBlockAllowed); } if (complexType.Final == XmlSchemaDerivationMethod.All) { complexType.SetFinalResolved(XmlSchemaDerivationMethod.All); } else if (complexType.Final == XmlSchemaDerivationMethod.None) { if (this.finalDefault == XmlSchemaDerivationMethod.All) { complexType.SetFinalResolved(XmlSchemaDerivationMethod.All); } else { complexType.SetFinalResolved(this.finalDefault & complexTypeFinalAllowed); } } else { if ((complexType.Final & ~complexTypeFinalAllowed) != 0) { SendValidationEvent(Res.Sch_InvalidComplexTypeFinalValue, complexType); } complexType.SetFinalResolved(complexType.Final & complexTypeFinalAllowed); } } if (complexType.ContentModel != null) { SetParent(complexType.ContentModel, complexType); //SimpleContent / complexCotent PreprocessAnnotation(complexType.ContentModel); if (complexType.Particle != null || complexType.Attributes != null) { // this is illigal } if (complexType.ContentModel is XmlSchemaSimpleContent) { XmlSchemaSimpleContent content = (XmlSchemaSimpleContent)complexType.ContentModel; if (content.Content == null) { if (complexType.QualifiedName == XmlQualifiedName.Empty) { SendValidationEvent(Res.Sch_NoRestOrExt, complexType); } else { SendValidationEvent(Res.Sch_NoRestOrExtQName, complexType.QualifiedName.Name, complexType.QualifiedName.Namespace, complexType); } } else { SetParent(content.Content, content); //simplecontent extension / restriction PreprocessAnnotation(content.Content); //annotation child of simple extension / restriction if (content.Content is XmlSchemaSimpleContentExtension) { XmlSchemaSimpleContentExtension contentExtension = (XmlSchemaSimpleContentExtension)content.Content; if (contentExtension.BaseTypeName.IsEmpty) { SendValidationEvent(Res.Sch_MissAttribute, "base", contentExtension); } else { ValidateQNameAttribute(contentExtension, "base", contentExtension.BaseTypeName); } PreprocessAttributes(contentExtension.Attributes, contentExtension.AnyAttribute, contentExtension); ValidateIdAttribute(contentExtension); } else { //XmlSchemaSimpleContentRestriction XmlSchemaSimpleContentRestriction contentRestriction = (XmlSchemaSimpleContentRestriction)content.Content; if (contentRestriction.BaseTypeName.IsEmpty) { SendValidationEvent(Res.Sch_MissAttribute, "base", contentRestriction); } else { ValidateQNameAttribute(contentRestriction, "base", contentRestriction.BaseTypeName); } if (contentRestriction.BaseType != null) { SetParent(contentRestriction.BaseType, contentRestriction); PreprocessSimpleType(contentRestriction.BaseType, true); } PreprocessAttributes(contentRestriction.Attributes, contentRestriction.AnyAttribute, contentRestriction); ValidateIdAttribute(contentRestriction); } } ValidateIdAttribute(content); } else { // XmlSchemaComplexContent XmlSchemaComplexContent content = (XmlSchemaComplexContent)complexType.ContentModel; if (content.Content == null) { if (complexType.QualifiedName == XmlQualifiedName.Empty) { SendValidationEvent(Res.Sch_NoRestOrExt, complexType); } else { SendValidationEvent(Res.Sch_NoRestOrExtQName, complexType.QualifiedName.Name, complexType.QualifiedName.Namespace, complexType); } } else { if ( !content.HasMixedAttribute && complexType.IsMixed) { content.IsMixed = true; // fixup } SetParent(content.Content, content); //complexcontent extension / restriction PreprocessAnnotation(content.Content); //Annotation child of extension / restriction if (content.Content is XmlSchemaComplexContentExtension) { XmlSchemaComplexContentExtension contentExtension = (XmlSchemaComplexContentExtension)content.Content; if (contentExtension.BaseTypeName.IsEmpty) { SendValidationEvent(Res.Sch_MissAttribute, "base", contentExtension); } else { ValidateQNameAttribute(contentExtension, "base", contentExtension.BaseTypeName); } if (contentExtension.Particle != null) { SetParent(contentExtension.Particle, contentExtension); //Group / all / choice / sequence PreprocessParticle(contentExtension.Particle); } PreprocessAttributes(contentExtension.Attributes, contentExtension.AnyAttribute, contentExtension); ValidateIdAttribute(contentExtension); } else { // XmlSchemaComplexContentRestriction XmlSchemaComplexContentRestriction contentRestriction = (XmlSchemaComplexContentRestriction)content.Content; if (contentRestriction.BaseTypeName.IsEmpty) { SendValidationEvent(Res.Sch_MissAttribute, "base", contentRestriction); } else { ValidateQNameAttribute(contentRestriction, "base", contentRestriction.BaseTypeName); } if (contentRestriction.Particle != null) { SetParent(contentRestriction.Particle, contentRestriction); //Group / all / choice / sequence PreprocessParticle(contentRestriction.Particle); } PreprocessAttributes(contentRestriction.Attributes, contentRestriction.AnyAttribute, contentRestriction); ValidateIdAttribute(contentRestriction); } ValidateIdAttribute(content); } } } else { if (complexType.Particle != null) { SetParent(complexType.Particle, complexType); PreprocessParticle(complexType.Particle); } PreprocessAttributes(complexType.Attributes, complexType.AnyAttribute, complexType); } ValidateIdAttribute(complexType); } private void PreprocessGroup(XmlSchemaGroup group) { if (group.Name != null) { ValidateNameAttribute(group); group.SetQualifiedName(new XmlQualifiedName(group.Name, this.targetNamespace)); } else { SendValidationEvent(Res.Sch_MissRequiredAttribute, "name", group); } if (group.Particle == null) { SendValidationEvent(Res.Sch_NoGroupParticle, group); return; } if (group.Particle.MinOccursString != null) { SendValidationEvent(Res.Sch_ForbiddenAttribute, "minOccurs", group.Particle); } if (group.Particle.MaxOccursString != null) { SendValidationEvent(Res.Sch_ForbiddenAttribute, "maxOccurs", group.Particle); } PreprocessParticle(group.Particle); PreprocessAnnotation(group); //Set parent of annotation child of group ValidateIdAttribute(group); } private void PreprocessNotation(XmlSchemaNotation notation) { if (notation.Name != null) { ValidateNameAttribute(notation); notation.QualifiedName = new XmlQualifiedName(notation.Name, this.targetNamespace); } else { SendValidationEvent(Res.Sch_MissRequiredAttribute, "name", notation); } if (notation.Public == null && notation.System == null) { SendValidationEvent(Res.Sch_MissingPublicSystemAttribute, notation); } else { if (notation.Public != null) { try { XmlConvert.VerifyTOKEN(notation.Public); // can throw } catch(XmlException eInner) { SendValidationEvent(Res.Sch_InvalidPublicAttribute, new string[] { notation.Public} , eInner, notation); } } if (notation.System != null) { ParseUri(notation.System, Res.Sch_InvalidSystemAttribute, notation); } } PreprocessAnnotation(notation); //Set parent of annotation child of notation ValidateIdAttribute(notation); } private void PreprocessParticle(XmlSchemaParticle particle) { XmlSchemaObjectCollection items; if (particle is XmlSchemaAll) { if (particle.MinOccurs != decimal.Zero && particle.MinOccurs != decimal.One) { particle.MinOccurs = decimal.One; SendValidationEvent(Res.Sch_InvalidAllMin, particle); } if (particle.MaxOccurs != decimal.One) { particle.MaxOccurs = decimal.One; SendValidationEvent(Res.Sch_InvalidAllMax, particle); } items = ((XmlSchemaAll) particle).Items; for (int i = 0; i < items.Count; ++i) { XmlSchemaElement element = (XmlSchemaElement)items[i]; if (element.MaxOccurs != decimal.Zero && element.MaxOccurs != decimal.One) { element.MaxOccurs = decimal.One; SendValidationEvent(Res.Sch_InvalidAllElementMax, element); } SetParent(element, particle); PreprocessLocalElement(element); } } else { if (particle.MinOccurs > particle.MaxOccurs) { particle.MinOccurs = particle.MaxOccurs; SendValidationEvent(Res.Sch_MinGtMax, particle); } if (particle is XmlSchemaChoice) { items = ((XmlSchemaChoice)particle).Items; for (int i = 0; i < items.Count; ++i) { SetParent(items[i], particle); XmlSchemaElement element = items[i] as XmlSchemaElement; if (element != null) { PreprocessLocalElement(element); } else { PreprocessParticle((XmlSchemaParticle)items[i]); } } } else if (particle is XmlSchemaSequence) { items = ((XmlSchemaSequence)particle).Items; for (int i = 0; i < items.Count; ++i) { SetParent(items[i], particle); XmlSchemaElement element = items[i] as XmlSchemaElement; if (element != null) { PreprocessLocalElement(element); } else { PreprocessParticle((XmlSchemaParticle)items[i]); } } } else if (particle is XmlSchemaGroupRef) { XmlSchemaGroupRef groupRef = (XmlSchemaGroupRef)particle; if (groupRef.RefName.IsEmpty) { SendValidationEvent(Res.Sch_MissAttribute, "ref", groupRef); } else { ValidateQNameAttribute(groupRef, "ref", groupRef.RefName); } } else if (particle is XmlSchemaAny) { try { ((XmlSchemaAny)particle).BuildNamespaceList(this.targetNamespace); } catch(FormatException fe) { SendValidationEvent(Res.Sch_InvalidAnyDetailed, new string[] {fe.Message}, fe, particle); } } } PreprocessAnnotation(particle); //set parent of annotation child of group / all/ choice / sequence ValidateIdAttribute(particle); } private void PreprocessAttributes(XmlSchemaObjectCollection attributes, XmlSchemaAnyAttribute anyAttribute, XmlSchemaObject parent) { for (int i = 0; i < attributes.Count; ++i) { SetParent(attributes[i], parent); XmlSchemaAttribute attr = attributes[i] as XmlSchemaAttribute; if (attr != null) { PreprocessLocalAttribute(attr); } else { // XmlSchemaAttributeGroupRef XmlSchemaAttributeGroupRef attributeGroupRef = (XmlSchemaAttributeGroupRef)attributes[i]; if (attributeGroupRef.RefName.IsEmpty) { SendValidationEvent(Res.Sch_MissAttribute, "ref", attributeGroupRef); } else { ValidateQNameAttribute(attributeGroupRef, "ref", attributeGroupRef.RefName); } PreprocessAnnotation(attributes[i]); //set parent of annotation child of attributeGroupRef ValidateIdAttribute(attributes[i]); } } if (anyAttribute != null) { try { SetParent(anyAttribute, parent); PreprocessAnnotation(anyAttribute); //set parent of annotation child of any attribute anyAttribute.BuildNamespaceList(this.targetNamespace); } catch(FormatException fe) { SendValidationEvent(Res.Sch_InvalidAnyDetailed, new string[] {fe.Message}, fe, anyAttribute); } ValidateIdAttribute(anyAttribute); } } private void ValidateIdAttribute(XmlSchemaObject xso) { if (xso.IdAttribute != null) { try { xso.IdAttribute = NameTable.Add(XmlConvert.VerifyNCName(xso.IdAttribute)); } catch(XmlException ex) { SendValidationEvent(Res.Sch_InvalidIdAttribute, new string [] {ex.Message}, ex, xso); return; } catch(ArgumentNullException) { SendValidationEvent(Res.Sch_InvalidIdAttribute, Res.GetString(Res.Sch_NullValue), xso); return; } try { currentSchema.Ids.Add(xso.IdAttribute, xso); } catch (ArgumentException) { SendValidationEvent(Res.Sch_DupIdAttribute, xso); } } } private void ValidateNameAttribute(XmlSchemaObject xso) { string name = xso.NameAttribute; if (name == null || name.Length == 0) { SendValidationEvent(Res.Sch_InvalidNameAttributeEx, null, Res.GetString(Res.Sch_NullValue), xso); } //Normalize whitespace since NCName has whitespace facet="collapse" name = XmlComplianceUtil.NonCDataNormalize(name); int len = ValidateNames.ParseNCName(name, 0); if (len != name.Length) { // If the string is not a valid NCName, then throw or return false string[] invCharArgs = XmlException.BuildCharExceptionArgs(name, len); string innerStr = Res.GetString(Res.Xml_BadNameCharWithPos, invCharArgs[0], invCharArgs[1], len); SendValidationEvent(Res.Sch_InvalidNameAttributeEx, name, innerStr, xso); } else { xso.NameAttribute = NameTable.Add(name); } } private void ValidateQNameAttribute(XmlSchemaObject xso, string attributeName, XmlQualifiedName value) { try { value.Verify(); value.Atomize(NameTable); if (currentSchema.IsChameleon && value.Namespace.Length == 0) { value.SetNamespace(currentSchema.TargetNamespace); //chameleon schemas are clones that have correct targetNamespace set } if(referenceNamespaces[value.Namespace] == null) { SendValidationEvent(Res.Sch_UnrefNS, value.Namespace, xso, XmlSeverityType.Warning); } } catch(FormatException fx) { SendValidationEvent(Res.Sch_InvalidAttribute, new string[] {attributeName, fx.Message}, fx, xso); } catch(XmlException ex) { SendValidationEvent(Res.Sch_InvalidAttribute, new string[] {attributeName, ex.Message}, ex, xso); } } [ResourceConsumption(ResourceScope.Machine)] [ResourceExposure(ResourceScope.Machine)] private Uri ResolveSchemaLocationUri(XmlSchema enclosingSchema, string location) { if (location.Length == 0) { return null; } return xmlResolver.ResolveUri( enclosingSchema.BaseUri, location); } private object GetSchemaEntity(Uri ruri) { return xmlResolver.GetEntity(ruri, null, null); } private XmlSchema GetChameleonSchema(string targetNamespace, XmlSchema schema) { ChameleonKey cKey = new ChameleonKey(targetNamespace, schema); XmlSchema chameleonSchema = (XmlSchema)chameleonSchemas[cKey]; //Need not clone if a schema for that namespace already exists if (chameleonSchema == null) { chameleonSchema = schema.DeepClone(); //It is ok that we dont lock the clone since no one else has access to it yet chameleonSchema.IsChameleon = true; chameleonSchema.TargetNamespace = targetNamespace; chameleonSchemas.Add(cKey, chameleonSchema); chameleonSchema.SourceUri = schema.SourceUri; //Handle the original schema that was added to lockList before cloning occurred schema.IsProcessing = false; //Since we cloned it for the chameleon } return chameleonSchema; } private void SetParent(XmlSchemaObject child, XmlSchemaObject parent) { child.Parent = parent; } private void PreprocessAnnotation(XmlSchemaObject schemaObject) { XmlSchemaAnnotation annotation; if (schemaObject is XmlSchemaAnnotated) { XmlSchemaAnnotated annotated = schemaObject as XmlSchemaAnnotated; annotation = annotated.Annotation; if (annotation != null) { PreprocessAnnotation(annotation); annotation.Parent = schemaObject; } } } private void PreprocessAnnotation(XmlSchemaAnnotation annotation) { ValidateIdAttribute(annotation); for (int i = 0; i < annotation.Items.Count; ++i) { annotation.Items[i].Parent = annotation; //Can be documentation or appInfo } } }; } // namespace System.Xml