Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / ndp / fx / src / xsp / System / Web / Extensions / Compilation / WCFModel / SchemaMerger.cs / 1 / SchemaMerger.cs
//------------------------------------------------------------------------------ //// Copyright (C) Microsoft Corporation. All Rights Reserved. // //----------------------------------------------------------------------------- using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Globalization; using System.Reflection; using System.Web.Services.Description; using System.Xml; using System.Xml.Schema; #if WEB_EXTENSIONS_CODE using System.Web.Resources; #else using Microsoft.VSDesigner.Resources.Microsoft.VSDesigner; #endif #if WEB_EXTENSIONS_CODE namespace System.Web.Compilation.WCFModel #else namespace Microsoft.VSDesigner.WCFModel #endif { ////// a utility class to merge schema files, and remove duplicated part /// internal class SchemaMerger { // xml serializable attributes private static Type[] xmlSerializationAttributes = new Type[] { typeof(System.Xml.Serialization.XmlElementAttribute), typeof(System.Xml.Serialization.XmlAttributeAttribute), typeof(System.Xml.Serialization.XmlAnyAttributeAttribute), typeof(System.Xml.Serialization.XmlAnyElementAttribute), typeof(System.Xml.Serialization.XmlTextAttribute), }; // elements in the schema (we don't process annotation node) private static SchemaTopLevelItemType[] schemaTopLevelItemTypes = new SchemaTopLevelItemType[] { new SchemaTopLevelItemType(typeof(XmlSchemaType), "type"), new SchemaTopLevelItemType(typeof(XmlSchemaElement), "element"), new SchemaTopLevelItemType(typeof(XmlSchemaAttribute), "attribute"), new SchemaTopLevelItemType(typeof(XmlSchemaGroup), "group"), new SchemaTopLevelItemType(typeof(XmlSchemaAttributeGroup), "attributeGroup"), }; // when properties defined in those types are different, we only report warnings, but not error messages private static Type[] ignorablePropertyTypes = new Type[] { typeof(XmlAttribute[]), typeof(XmlElement[]), typeof(XmlNode[]), typeof(XmlSchemaAnnotation), }; private readonly static XmlAttribute[] emptyXmlAttributeCollection = new XmlAttribute[0]; private readonly static object[] emptyCollection = new object[0]; ////// Merge and remove duplicated part from the schema list /// /// schemas with names /// error messages /// error messages ///internal static void MergeSchemas(IEnumerable schemaList, IList importErrors, out IEnumerable duplicatedSchemas) { if (schemaList == null) { throw new ArgumentNullException("schemaList"); } if (importErrors == null) { throw new ArgumentNullException("importErrors"); } List duplicatedSchemaList = new List (); duplicatedSchemas = duplicatedSchemaList; // types, elements, groups have their own name space Dictionary [] knownItemTables = new Dictionary [schemaTopLevelItemTypes.Length]; for (int i = 0; i < schemaTopLevelItemTypes.Length; i++) { knownItemTables[i] = new Dictionary (); } foreach (XmlSchema schema in schemaList) { bool hasNewDefinedItems = false; List duplicatedItems = new List (); for (int i = 0; i < schemaTopLevelItemTypes.Length; i++) { Dictionary knownItemTable = knownItemTables[i]; int knownItemCount = knownItemTable.Count; FindDuplicatedItems(schema, schemaTopLevelItemTypes[i].ItemType, schemaTopLevelItemTypes[i].Name, knownItemTable, duplicatedItems, importErrors); if (knownItemTable.Count > knownItemCount) { hasNewDefinedItems = true; } } if (duplicatedItems.Count > 0) { if (!hasNewDefinedItems) { // remove the whole schema... duplicatedSchemaList.Add(schema); } else { // remove duplicated items only foreach (XmlSchemaObject item in duplicatedItems) { schema.Items.Remove(item); } } } } } /// /// Find duplicated items in a schema /// ///private static void FindDuplicatedItems( XmlSchema schema, Type itemType, string itemTypeName, Dictionary knownItemTable, List duplicatedItems, IList importErrors) { string targetNamespace = schema.TargetNamespace; if (String.IsNullOrEmpty(targetNamespace)) { targetNamespace = String.Empty; } foreach (XmlSchemaObject item in schema.Items) { if (itemType.IsInstanceOfType(item)) { XmlQualifiedName combinedName = new XmlQualifiedName(GetSchemaItemName(item), targetNamespace); XmlSchemaObject originalItem = null; if (knownItemTable.TryGetValue(combinedName, out originalItem)) { string differentLocation; if (!AreSchemaObjectsEquivalent(originalItem, item, out differentLocation)) { differentLocation = CombinePath(".", differentLocation); importErrors.Add( new ProxyGenerationError( ProxyGenerationError.GeneratorState.MergeMetadata, String.Empty, new InvalidOperationException( String.Format(CultureInfo.CurrentCulture, WCFModelStrings.ReferenceGroup_DuplicatedSchemaItems, itemTypeName, combinedName.ToString(), schema.SourceUri, originalItem.SourceUri, differentLocation) ) ) ); } else if (!String.IsNullOrEmpty(differentLocation)) { // warning: ignorable difference found differentLocation = CombinePath(".", differentLocation); importErrors.Add( new ProxyGenerationError( ProxyGenerationError.GeneratorState.MergeMetadata, String.Empty, new InvalidOperationException( String.Format(CultureInfo.CurrentCulture, WCFModelStrings.ReferenceGroup_DuplicatedSchemaItemsIgnored, itemTypeName, combinedName.ToString(), schema.SourceUri, originalItem.SourceUri, differentLocation) ), true // isWarning = true ) ); } duplicatedItems.Add(item); } else { item.SourceUri = schema.SourceUri; knownItemTable.Add(combinedName, item); } } } } /// /// Compare two schema objects /// ////// /// For all those functions, we follow the same pattern: /// return false: find not-ignorable difference between them. differentLocation will contain the path /// return true, with empty differentLocation -- no difference found /// return true, with non-empty differentLocation -- ignorable difference found under that location /// private static bool AreSchemaObjectsEquivalent(XmlSchemaObject originalItem, XmlSchemaObject item, out string differentLocation) { differentLocation = String.Empty; Type itemType = originalItem.GetType(); if (itemType != item.GetType()) { return false; } string ignorableDifferenceLocation = String.Empty; PropertyInfo[] properties = itemType.GetProperties(); foreach (PropertyInfo property in properties) { if (IsPersistedProperty(property)) { bool ignorableProperty = ShouldIgnoreSchemaProperty(property); object originalValue = property.GetValue(originalItem, new object[] {}); object newValue = property.GetValue(item, new object[] {}); if (!CompareSchemaPropertyValues(property, originalValue, newValue, out differentLocation) && !ignorableProperty) { return false; } if (String.IsNullOrEmpty(ignorableDifferenceLocation)) { ignorableDifferenceLocation = differentLocation; } } } differentLocation = ignorableDifferenceLocation; return true; } ////// Compare two property of a schema object /// ///true: if the value are same ///private static bool CompareSchemaPropertyValues(PropertyInfo propertyInfo, object originalValue, object newValue, out string differentLocation) { differentLocation = String.Empty; if (originalValue == null && newValue == null) { return true; } // we create empty collection so a meaningful differentLocation could be generated if (typeof(XmlAttribute[]) == propertyInfo.PropertyType) { if (originalValue == null) { originalValue = emptyXmlAttributeCollection; } if (newValue == null) { newValue = emptyXmlAttributeCollection; } XmlAttribute differentAttribute1, differentAttribute2; if (!CompareXmlAttributeCollections((XmlAttribute[])originalValue, (XmlAttribute[])newValue, out differentAttribute1, out differentAttribute2)) { differentLocation = GetSchemaPropertyNameInXml(propertyInfo, differentAttribute1, differentAttribute2); return false; } return true; } if (typeof(System.Collections.ICollection).IsAssignableFrom(propertyInfo.PropertyType)) { if (originalValue == null) { originalValue = emptyCollection; } if (newValue == null) { newValue = emptyCollection; } object differentItem1, differentItem2; if (!CompareSchemaCollections((System.Collections.ICollection)originalValue, (System.Collections.ICollection)newValue, out differentItem1, out differentItem2, out differentLocation)) { differentLocation = CombinePath(GetSchemaPropertyNameInXml(propertyInfo, differentItem1, differentItem2), differentLocation); return false; } else { if (!String.IsNullOrEmpty(differentLocation)) { // ignorable difference... differentLocation = CombinePath(GetSchemaPropertyNameInXml(propertyInfo, differentItem1, differentItem2), differentLocation); } return true; } } if (originalValue == null || newValue == null) { differentLocation = CombinePath(GetSchemaPropertyNameInXml(propertyInfo, originalValue, newValue), differentLocation); return false; } if (originalValue.GetType() != newValue.GetType()) { differentLocation = CombinePath(GetSchemaPropertyNameInXml(propertyInfo, originalValue, newValue), differentLocation); return false; } if (!CompareSchemaValues(originalValue, newValue, out differentLocation)) { differentLocation = CombinePath(GetSchemaPropertyNameInXml(propertyInfo, originalValue, newValue), differentLocation); return false; } else { // ignorable difference... if (!String.IsNullOrEmpty(differentLocation)) { differentLocation = CombinePath(GetSchemaPropertyNameInXml(propertyInfo, originalValue, newValue), differentLocation); } return true; } } /// /// Compare two schema values /// ////// private static bool CompareSchemaValues(object originalValue, object newValue, out string differentLocation) { differentLocation = String.Empty; if (originalValue == null || newValue == null) { return (originalValue == null && newValue == null); } if (originalValue.GetType() != newValue.GetType()) { return false; } if (originalValue is XmlSchemaObject) { return AreSchemaObjectsEquivalent((XmlSchemaObject)originalValue, (XmlSchemaObject)newValue, out differentLocation); } if (originalValue is XmlAttribute) { return CompareXmlAttributes((XmlAttribute)originalValue, (XmlAttribute)newValue); } if (originalValue is XmlElement) { return CompareXmlElements((XmlElement)originalValue, (XmlElement)newValue, out differentLocation); } if (originalValue is XmlText) { return CompareXmlTexts((XmlText)originalValue, (XmlText)newValue); } return originalValue.Equals(newValue); } /// /// Compare two collections of items /// ////// private static bool CompareSchemaCollections(System.Collections.IEnumerable originalCollection, System.Collections.IEnumerable newCollection, out object differentItem1, out object differentItem2, out string differentLocation) { differentLocation = String.Empty; System.Collections.IEnumerator list1 = originalCollection.GetEnumerator(); System.Collections.IEnumerator list2 = newCollection.GetEnumerator(); string ignorableDifferenceLocation = String.Empty; object ignorableDifferenceItem1 = null; object ignorableDifferenceItem2 = null; do { differentItem1 = list1.MoveNext() ? list1.Current : null; differentItem2 = list2.MoveNext() ? list2.Current : null; if (!CompareSchemaValues(differentItem1, differentItem2, out differentLocation)) { return false; } if (String.IsNullOrEmpty(ignorableDifferenceLocation)) { ignorableDifferenceItem1 = differentItem1; ignorableDifferenceItem2 = differentItem2; ignorableDifferenceLocation = differentLocation; } } while (differentItem1 != null && differentItem2 != null); Debug.Assert(differentItem1 == null && differentItem2 == null); differentLocation = ignorableDifferenceLocation; differentItem1 = ignorableDifferenceItem1; differentItem2 = ignorableDifferenceItem2; return true; } /// /// Compare two attributes /// ////// private static bool CompareXmlAttributes(XmlAttribute attribute1, XmlAttribute attribute2) { return String.Equals(attribute1.LocalName, attribute2.LocalName, StringComparison.Ordinal) && String.Equals(attribute1.NamespaceURI, attribute2.NamespaceURI, StringComparison.Ordinal) && String.Equals(attribute1.Value, attribute2.Value, StringComparison.Ordinal); } /// /// Compare two attribute collections /// ////// private static bool CompareXmlAttributeCollections(System.Collections.ICollection attributeCollection1, System.Collections.ICollection attributeCollection2, out XmlAttribute differentAttribute1, out XmlAttribute differentAttribute2) { differentAttribute1 = null; differentAttribute2 = null; XmlAttribute[] attributeArray1 = GetSortedAttributeArray(attributeCollection1); XmlAttribute[] attributeArray2 = GetSortedAttributeArray(attributeCollection2); object differentItem1, differentItem2; string differentLocation; if (!CompareSchemaCollections(attributeArray1, attributeArray2, out differentItem1, out differentItem2, out differentLocation)) { differentAttribute1 = (XmlAttribute)differentItem1; differentAttribute2 = (XmlAttribute)differentItem2; return false; } return true; } /// /// sort XmlAttribute array, so we can compare two collections without being affected by the order /// ////// private static XmlAttribute[] GetSortedAttributeArray(System.Collections.ICollection attributeCollection) { XmlAttribute[] attributeArray = new XmlAttribute[attributeCollection.Count]; int index = 0; foreach (XmlAttribute attribute in attributeCollection) { attributeArray[index++] = attribute; } Array.Sort(attributeArray, new AttributeComparer()); return attributeArray; } /// /// Compare two elements /// ////// private static bool CompareXmlElements(XmlElement element1, XmlElement element2, out string differentLocation) { differentLocation = String.Empty; if (!String.Equals(element1.LocalName, element2.LocalName, StringComparison.Ordinal) || !String.Equals(element1.NamespaceURI, element2.NamespaceURI, StringComparison.Ordinal)) { return false; } XmlAttribute differentAttribute1, differentAttribute2; if (!CompareXmlAttributeCollections(element1.Attributes, element2.Attributes, out differentAttribute1, out differentAttribute2)) { string attributeName1 = differentAttribute1 != null ? "@" + differentAttribute1.LocalName : String.Empty; string attributeName2 = differentAttribute2 != null ? "@" + differentAttribute2.LocalName : String.Empty; differentLocation = CombineTwoNames(attributeName1, attributeName2); return false; } object differentChild1, differentChild2; if (!CompareSchemaCollections(element1.ChildNodes, element2.ChildNodes, out differentChild1, out differentChild2, out differentLocation)) { string child1Name = differentChild1 != null ? ((XmlNode)differentChild1).LocalName : String.Empty; string child2Name = differentChild2 != null ? ((XmlNode)differentChild2).LocalName : String.Empty; differentLocation = CombinePath(CombineTwoNames(child1Name, child2Name), differentLocation); return false; } return true; } /// /// Compare two text nodes /// ////// private static bool CompareXmlTexts(XmlText text1, XmlText text2) { return String.Equals(text1.Value, text2.Value, StringComparison.Ordinal); } /// /// Combine two path (similar to xpath) in error messages /// ////// private static string CombinePath(string path1, string path2) { if (String.IsNullOrEmpty(path1)) { return path2; } else if (String.IsNullOrEmpty(path2)) { return path1; } return path1 + "/" + path2; } /// /// Get Name of a top level schema item /// /// ////// private static string GetSchemaItemName(XmlSchemaObject item) { if (item == null) { throw new ArgumentNullException("item"); } Type itemType = item.GetType(); PropertyInfo nameProperty = itemType.GetProperty("Name"); if (nameProperty != null) { object nameValue = nameProperty.GetValue(item, new object[]{}); if (nameValue is string) { return (string)nameValue; } return String.Empty; } return String.Empty; } /// /// Generate end-user unstandable property name -- we will use name in the schema file, but not name in object model /// ////// private static string GetSchemaPropertyNameInXml(PropertyInfo property, object value1, object value2) { object[] propertyAttributes = property.GetCustomAttributes(true); string name = String.Empty; if (propertyAttributes != null) { string name1 = GetSchemaPropertyNameInXmlHelper(propertyAttributes, value1); string name2 = GetSchemaPropertyNameInXmlHelper(propertyAttributes, value2); name = CombineTwoNames(name1, name2); } if (String.IsNullOrEmpty(name)) { Debug.Fail("Why we didn't get a property name with normal routine?"); name = property.Name; } return name; } /// /// Combine names of two properties in error messages /// ///private static string CombineTwoNames(string name1, string name2) { string name = String.Empty; if (name1.Length > 0) { if (name2.Length > 0) { if (String.Equals(name1, name2, StringComparison.Ordinal)) { name = name1; } else { name = name1 + "|" + name2; } } else { name = name1; } } else if (name2.Length > 0) { name = name2; } return name; } /// /// a helper function to generate names /// ///private static string GetSchemaPropertyNameInXmlHelper(object[] propertyAttributes, object value) { if (value != null) { foreach (object attribute in propertyAttributes) { if (attribute is System.Xml.Serialization.XmlAttributeAttribute) { return "@" + ((System.Xml.Serialization.XmlAttributeAttribute)attribute).AttributeName; } if (attribute is System.Xml.Serialization.XmlElementAttribute) { System.Xml.Serialization.XmlElementAttribute elementAttribute = (System.Xml.Serialization.XmlElementAttribute)attribute; Type elementType = elementAttribute.Type; if (elementType == null || elementType.IsInstanceOfType(value)) { if (value is XmlSchemaObject) { string itemName = GetSchemaItemName((XmlSchemaObject)value); if (itemName.Length > 0) { return String.Format(System.Globalization.CultureInfo.InvariantCulture, "{0}[@name='{1}']", elementAttribute.ElementName, itemName); } } return elementAttribute.ElementName; } } if (attribute is System.Xml.Serialization.XmlAnyAttributeAttribute) { if (value is XmlAttribute) { return "@" + ((XmlAttribute)value).LocalName; } } if (attribute is System.Xml.Serialization.XmlAnyElementAttribute) { if (value is XmlElement) { return ((XmlElement)value).LocalName; } } if (attribute is System.Xml.Serialization.XmlTextAttribute) { if (value is XmlText) { return ((XmlText)value).Name; } } } } return String.Empty; } /// /// Check whether a property is persisted with XmlSerialization /// /// ////// private static bool IsPersistedProperty(PropertyInfo property) { object[] propertyAttributes = property.GetCustomAttributes(true); if (propertyAttributes != null) { foreach (object attribute in propertyAttributes) { foreach (Type serializationAttibuteType in xmlSerializationAttributes) { if (serializationAttibuteType.IsInstanceOfType(attribute)) { return true; } } } } return false; } /// /// check whether we should report warning but not error messages, when the property is different /// ///private static bool ShouldIgnoreSchemaProperty(PropertyInfo property) { Type propertyType = property.PropertyType; foreach (Type ignoreableType in ignorablePropertyTypes) { if (propertyType == ignoreableType || propertyType.IsSubclassOf(ignoreableType)) { return true; } } // special case constraints... if (String.Equals(property.Name, "Constraints", StringComparison.Ordinal)) { return true; } return false; } /// /// a helper structure to hold top level items we want to scan /// ///private struct SchemaTopLevelItemType { public Type ItemType; public string Name; public SchemaTopLevelItemType(Type itemType, string name) { this.ItemType = itemType; this.Name = name; } }; /// /// Helper class to compare two XmlAttributes /// ///private class AttributeComparer : System.Collections.Generic.IComparer { public int Compare(System.Xml.XmlAttribute x, System.Xml.XmlAttribute y) { int namespaceResult = String.Compare(x.NamespaceURI, y.NamespaceURI, StringComparison.Ordinal); if (namespaceResult != 0) { return namespaceResult; } return String.Compare(x.Name, y.Name, StringComparison.Ordinal); } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. //------------------------------------------------------------------------------ // // Copyright (C) Microsoft Corporation. All Rights Reserved. // //----------------------------------------------------------------------------- using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Globalization; using System.Reflection; using System.Web.Services.Description; using System.Xml; using System.Xml.Schema; #if WEB_EXTENSIONS_CODE using System.Web.Resources; #else using Microsoft.VSDesigner.Resources.Microsoft.VSDesigner; #endif #if WEB_EXTENSIONS_CODE namespace System.Web.Compilation.WCFModel #else namespace Microsoft.VSDesigner.WCFModel #endif { ////// a utility class to merge schema files, and remove duplicated part /// internal class SchemaMerger { // xml serializable attributes private static Type[] xmlSerializationAttributes = new Type[] { typeof(System.Xml.Serialization.XmlElementAttribute), typeof(System.Xml.Serialization.XmlAttributeAttribute), typeof(System.Xml.Serialization.XmlAnyAttributeAttribute), typeof(System.Xml.Serialization.XmlAnyElementAttribute), typeof(System.Xml.Serialization.XmlTextAttribute), }; // elements in the schema (we don't process annotation node) private static SchemaTopLevelItemType[] schemaTopLevelItemTypes = new SchemaTopLevelItemType[] { new SchemaTopLevelItemType(typeof(XmlSchemaType), "type"), new SchemaTopLevelItemType(typeof(XmlSchemaElement), "element"), new SchemaTopLevelItemType(typeof(XmlSchemaAttribute), "attribute"), new SchemaTopLevelItemType(typeof(XmlSchemaGroup), "group"), new SchemaTopLevelItemType(typeof(XmlSchemaAttributeGroup), "attributeGroup"), }; // when properties defined in those types are different, we only report warnings, but not error messages private static Type[] ignorablePropertyTypes = new Type[] { typeof(XmlAttribute[]), typeof(XmlElement[]), typeof(XmlNode[]), typeof(XmlSchemaAnnotation), }; private readonly static XmlAttribute[] emptyXmlAttributeCollection = new XmlAttribute[0]; private readonly static object[] emptyCollection = new object[0]; ////// Merge and remove duplicated part from the schema list /// /// schemas with names /// error messages /// error messages ///internal static void MergeSchemas(IEnumerable schemaList, IList importErrors, out IEnumerable duplicatedSchemas) { if (schemaList == null) { throw new ArgumentNullException("schemaList"); } if (importErrors == null) { throw new ArgumentNullException("importErrors"); } List duplicatedSchemaList = new List (); duplicatedSchemas = duplicatedSchemaList; // types, elements, groups have their own name space Dictionary [] knownItemTables = new Dictionary [schemaTopLevelItemTypes.Length]; for (int i = 0; i < schemaTopLevelItemTypes.Length; i++) { knownItemTables[i] = new Dictionary (); } foreach (XmlSchema schema in schemaList) { bool hasNewDefinedItems = false; List duplicatedItems = new List (); for (int i = 0; i < schemaTopLevelItemTypes.Length; i++) { Dictionary knownItemTable = knownItemTables[i]; int knownItemCount = knownItemTable.Count; FindDuplicatedItems(schema, schemaTopLevelItemTypes[i].ItemType, schemaTopLevelItemTypes[i].Name, knownItemTable, duplicatedItems, importErrors); if (knownItemTable.Count > knownItemCount) { hasNewDefinedItems = true; } } if (duplicatedItems.Count > 0) { if (!hasNewDefinedItems) { // remove the whole schema... duplicatedSchemaList.Add(schema); } else { // remove duplicated items only foreach (XmlSchemaObject item in duplicatedItems) { schema.Items.Remove(item); } } } } } /// /// Find duplicated items in a schema /// ///private static void FindDuplicatedItems( XmlSchema schema, Type itemType, string itemTypeName, Dictionary knownItemTable, List duplicatedItems, IList importErrors) { string targetNamespace = schema.TargetNamespace; if (String.IsNullOrEmpty(targetNamespace)) { targetNamespace = String.Empty; } foreach (XmlSchemaObject item in schema.Items) { if (itemType.IsInstanceOfType(item)) { XmlQualifiedName combinedName = new XmlQualifiedName(GetSchemaItemName(item), targetNamespace); XmlSchemaObject originalItem = null; if (knownItemTable.TryGetValue(combinedName, out originalItem)) { string differentLocation; if (!AreSchemaObjectsEquivalent(originalItem, item, out differentLocation)) { differentLocation = CombinePath(".", differentLocation); importErrors.Add( new ProxyGenerationError( ProxyGenerationError.GeneratorState.MergeMetadata, String.Empty, new InvalidOperationException( String.Format(CultureInfo.CurrentCulture, WCFModelStrings.ReferenceGroup_DuplicatedSchemaItems, itemTypeName, combinedName.ToString(), schema.SourceUri, originalItem.SourceUri, differentLocation) ) ) ); } else if (!String.IsNullOrEmpty(differentLocation)) { // warning: ignorable difference found differentLocation = CombinePath(".", differentLocation); importErrors.Add( new ProxyGenerationError( ProxyGenerationError.GeneratorState.MergeMetadata, String.Empty, new InvalidOperationException( String.Format(CultureInfo.CurrentCulture, WCFModelStrings.ReferenceGroup_DuplicatedSchemaItemsIgnored, itemTypeName, combinedName.ToString(), schema.SourceUri, originalItem.SourceUri, differentLocation) ), true // isWarning = true ) ); } duplicatedItems.Add(item); } else { item.SourceUri = schema.SourceUri; knownItemTable.Add(combinedName, item); } } } } /// /// Compare two schema objects /// ////// /// For all those functions, we follow the same pattern: /// return false: find not-ignorable difference between them. differentLocation will contain the path /// return true, with empty differentLocation -- no difference found /// return true, with non-empty differentLocation -- ignorable difference found under that location /// private static bool AreSchemaObjectsEquivalent(XmlSchemaObject originalItem, XmlSchemaObject item, out string differentLocation) { differentLocation = String.Empty; Type itemType = originalItem.GetType(); if (itemType != item.GetType()) { return false; } string ignorableDifferenceLocation = String.Empty; PropertyInfo[] properties = itemType.GetProperties(); foreach (PropertyInfo property in properties) { if (IsPersistedProperty(property)) { bool ignorableProperty = ShouldIgnoreSchemaProperty(property); object originalValue = property.GetValue(originalItem, new object[] {}); object newValue = property.GetValue(item, new object[] {}); if (!CompareSchemaPropertyValues(property, originalValue, newValue, out differentLocation) && !ignorableProperty) { return false; } if (String.IsNullOrEmpty(ignorableDifferenceLocation)) { ignorableDifferenceLocation = differentLocation; } } } differentLocation = ignorableDifferenceLocation; return true; } ////// Compare two property of a schema object /// ///true: if the value are same ///private static bool CompareSchemaPropertyValues(PropertyInfo propertyInfo, object originalValue, object newValue, out string differentLocation) { differentLocation = String.Empty; if (originalValue == null && newValue == null) { return true; } // we create empty collection so a meaningful differentLocation could be generated if (typeof(XmlAttribute[]) == propertyInfo.PropertyType) { if (originalValue == null) { originalValue = emptyXmlAttributeCollection; } if (newValue == null) { newValue = emptyXmlAttributeCollection; } XmlAttribute differentAttribute1, differentAttribute2; if (!CompareXmlAttributeCollections((XmlAttribute[])originalValue, (XmlAttribute[])newValue, out differentAttribute1, out differentAttribute2)) { differentLocation = GetSchemaPropertyNameInXml(propertyInfo, differentAttribute1, differentAttribute2); return false; } return true; } if (typeof(System.Collections.ICollection).IsAssignableFrom(propertyInfo.PropertyType)) { if (originalValue == null) { originalValue = emptyCollection; } if (newValue == null) { newValue = emptyCollection; } object differentItem1, differentItem2; if (!CompareSchemaCollections((System.Collections.ICollection)originalValue, (System.Collections.ICollection)newValue, out differentItem1, out differentItem2, out differentLocation)) { differentLocation = CombinePath(GetSchemaPropertyNameInXml(propertyInfo, differentItem1, differentItem2), differentLocation); return false; } else { if (!String.IsNullOrEmpty(differentLocation)) { // ignorable difference... differentLocation = CombinePath(GetSchemaPropertyNameInXml(propertyInfo, differentItem1, differentItem2), differentLocation); } return true; } } if (originalValue == null || newValue == null) { differentLocation = CombinePath(GetSchemaPropertyNameInXml(propertyInfo, originalValue, newValue), differentLocation); return false; } if (originalValue.GetType() != newValue.GetType()) { differentLocation = CombinePath(GetSchemaPropertyNameInXml(propertyInfo, originalValue, newValue), differentLocation); return false; } if (!CompareSchemaValues(originalValue, newValue, out differentLocation)) { differentLocation = CombinePath(GetSchemaPropertyNameInXml(propertyInfo, originalValue, newValue), differentLocation); return false; } else { // ignorable difference... if (!String.IsNullOrEmpty(differentLocation)) { differentLocation = CombinePath(GetSchemaPropertyNameInXml(propertyInfo, originalValue, newValue), differentLocation); } return true; } } /// /// Compare two schema values /// ////// private static bool CompareSchemaValues(object originalValue, object newValue, out string differentLocation) { differentLocation = String.Empty; if (originalValue == null || newValue == null) { return (originalValue == null && newValue == null); } if (originalValue.GetType() != newValue.GetType()) { return false; } if (originalValue is XmlSchemaObject) { return AreSchemaObjectsEquivalent((XmlSchemaObject)originalValue, (XmlSchemaObject)newValue, out differentLocation); } if (originalValue is XmlAttribute) { return CompareXmlAttributes((XmlAttribute)originalValue, (XmlAttribute)newValue); } if (originalValue is XmlElement) { return CompareXmlElements((XmlElement)originalValue, (XmlElement)newValue, out differentLocation); } if (originalValue is XmlText) { return CompareXmlTexts((XmlText)originalValue, (XmlText)newValue); } return originalValue.Equals(newValue); } /// /// Compare two collections of items /// ////// private static bool CompareSchemaCollections(System.Collections.IEnumerable originalCollection, System.Collections.IEnumerable newCollection, out object differentItem1, out object differentItem2, out string differentLocation) { differentLocation = String.Empty; System.Collections.IEnumerator list1 = originalCollection.GetEnumerator(); System.Collections.IEnumerator list2 = newCollection.GetEnumerator(); string ignorableDifferenceLocation = String.Empty; object ignorableDifferenceItem1 = null; object ignorableDifferenceItem2 = null; do { differentItem1 = list1.MoveNext() ? list1.Current : null; differentItem2 = list2.MoveNext() ? list2.Current : null; if (!CompareSchemaValues(differentItem1, differentItem2, out differentLocation)) { return false; } if (String.IsNullOrEmpty(ignorableDifferenceLocation)) { ignorableDifferenceItem1 = differentItem1; ignorableDifferenceItem2 = differentItem2; ignorableDifferenceLocation = differentLocation; } } while (differentItem1 != null && differentItem2 != null); Debug.Assert(differentItem1 == null && differentItem2 == null); differentLocation = ignorableDifferenceLocation; differentItem1 = ignorableDifferenceItem1; differentItem2 = ignorableDifferenceItem2; return true; } /// /// Compare two attributes /// ////// private static bool CompareXmlAttributes(XmlAttribute attribute1, XmlAttribute attribute2) { return String.Equals(attribute1.LocalName, attribute2.LocalName, StringComparison.Ordinal) && String.Equals(attribute1.NamespaceURI, attribute2.NamespaceURI, StringComparison.Ordinal) && String.Equals(attribute1.Value, attribute2.Value, StringComparison.Ordinal); } /// /// Compare two attribute collections /// ////// private static bool CompareXmlAttributeCollections(System.Collections.ICollection attributeCollection1, System.Collections.ICollection attributeCollection2, out XmlAttribute differentAttribute1, out XmlAttribute differentAttribute2) { differentAttribute1 = null; differentAttribute2 = null; XmlAttribute[] attributeArray1 = GetSortedAttributeArray(attributeCollection1); XmlAttribute[] attributeArray2 = GetSortedAttributeArray(attributeCollection2); object differentItem1, differentItem2; string differentLocation; if (!CompareSchemaCollections(attributeArray1, attributeArray2, out differentItem1, out differentItem2, out differentLocation)) { differentAttribute1 = (XmlAttribute)differentItem1; differentAttribute2 = (XmlAttribute)differentItem2; return false; } return true; } /// /// sort XmlAttribute array, so we can compare two collections without being affected by the order /// ////// private static XmlAttribute[] GetSortedAttributeArray(System.Collections.ICollection attributeCollection) { XmlAttribute[] attributeArray = new XmlAttribute[attributeCollection.Count]; int index = 0; foreach (XmlAttribute attribute in attributeCollection) { attributeArray[index++] = attribute; } Array.Sort(attributeArray, new AttributeComparer()); return attributeArray; } /// /// Compare two elements /// ////// private static bool CompareXmlElements(XmlElement element1, XmlElement element2, out string differentLocation) { differentLocation = String.Empty; if (!String.Equals(element1.LocalName, element2.LocalName, StringComparison.Ordinal) || !String.Equals(element1.NamespaceURI, element2.NamespaceURI, StringComparison.Ordinal)) { return false; } XmlAttribute differentAttribute1, differentAttribute2; if (!CompareXmlAttributeCollections(element1.Attributes, element2.Attributes, out differentAttribute1, out differentAttribute2)) { string attributeName1 = differentAttribute1 != null ? "@" + differentAttribute1.LocalName : String.Empty; string attributeName2 = differentAttribute2 != null ? "@" + differentAttribute2.LocalName : String.Empty; differentLocation = CombineTwoNames(attributeName1, attributeName2); return false; } object differentChild1, differentChild2; if (!CompareSchemaCollections(element1.ChildNodes, element2.ChildNodes, out differentChild1, out differentChild2, out differentLocation)) { string child1Name = differentChild1 != null ? ((XmlNode)differentChild1).LocalName : String.Empty; string child2Name = differentChild2 != null ? ((XmlNode)differentChild2).LocalName : String.Empty; differentLocation = CombinePath(CombineTwoNames(child1Name, child2Name), differentLocation); return false; } return true; } /// /// Compare two text nodes /// ////// private static bool CompareXmlTexts(XmlText text1, XmlText text2) { return String.Equals(text1.Value, text2.Value, StringComparison.Ordinal); } /// /// Combine two path (similar to xpath) in error messages /// ////// private static string CombinePath(string path1, string path2) { if (String.IsNullOrEmpty(path1)) { return path2; } else if (String.IsNullOrEmpty(path2)) { return path1; } return path1 + "/" + path2; } /// /// Get Name of a top level schema item /// /// ////// private static string GetSchemaItemName(XmlSchemaObject item) { if (item == null) { throw new ArgumentNullException("item"); } Type itemType = item.GetType(); PropertyInfo nameProperty = itemType.GetProperty("Name"); if (nameProperty != null) { object nameValue = nameProperty.GetValue(item, new object[]{}); if (nameValue is string) { return (string)nameValue; } return String.Empty; } return String.Empty; } /// /// Generate end-user unstandable property name -- we will use name in the schema file, but not name in object model /// ////// private static string GetSchemaPropertyNameInXml(PropertyInfo property, object value1, object value2) { object[] propertyAttributes = property.GetCustomAttributes(true); string name = String.Empty; if (propertyAttributes != null) { string name1 = GetSchemaPropertyNameInXmlHelper(propertyAttributes, value1); string name2 = GetSchemaPropertyNameInXmlHelper(propertyAttributes, value2); name = CombineTwoNames(name1, name2); } if (String.IsNullOrEmpty(name)) { Debug.Fail("Why we didn't get a property name with normal routine?"); name = property.Name; } return name; } /// /// Combine names of two properties in error messages /// ///private static string CombineTwoNames(string name1, string name2) { string name = String.Empty; if (name1.Length > 0) { if (name2.Length > 0) { if (String.Equals(name1, name2, StringComparison.Ordinal)) { name = name1; } else { name = name1 + "|" + name2; } } else { name = name1; } } else if (name2.Length > 0) { name = name2; } return name; } /// /// a helper function to generate names /// ///private static string GetSchemaPropertyNameInXmlHelper(object[] propertyAttributes, object value) { if (value != null) { foreach (object attribute in propertyAttributes) { if (attribute is System.Xml.Serialization.XmlAttributeAttribute) { return "@" + ((System.Xml.Serialization.XmlAttributeAttribute)attribute).AttributeName; } if (attribute is System.Xml.Serialization.XmlElementAttribute) { System.Xml.Serialization.XmlElementAttribute elementAttribute = (System.Xml.Serialization.XmlElementAttribute)attribute; Type elementType = elementAttribute.Type; if (elementType == null || elementType.IsInstanceOfType(value)) { if (value is XmlSchemaObject) { string itemName = GetSchemaItemName((XmlSchemaObject)value); if (itemName.Length > 0) { return String.Format(System.Globalization.CultureInfo.InvariantCulture, "{0}[@name='{1}']", elementAttribute.ElementName, itemName); } } return elementAttribute.ElementName; } } if (attribute is System.Xml.Serialization.XmlAnyAttributeAttribute) { if (value is XmlAttribute) { return "@" + ((XmlAttribute)value).LocalName; } } if (attribute is System.Xml.Serialization.XmlAnyElementAttribute) { if (value is XmlElement) { return ((XmlElement)value).LocalName; } } if (attribute is System.Xml.Serialization.XmlTextAttribute) { if (value is XmlText) { return ((XmlText)value).Name; } } } } return String.Empty; } /// /// Check whether a property is persisted with XmlSerialization /// /// ////// private static bool IsPersistedProperty(PropertyInfo property) { object[] propertyAttributes = property.GetCustomAttributes(true); if (propertyAttributes != null) { foreach (object attribute in propertyAttributes) { foreach (Type serializationAttibuteType in xmlSerializationAttributes) { if (serializationAttibuteType.IsInstanceOfType(attribute)) { return true; } } } } return false; } /// /// check whether we should report warning but not error messages, when the property is different /// ///private static bool ShouldIgnoreSchemaProperty(PropertyInfo property) { Type propertyType = property.PropertyType; foreach (Type ignoreableType in ignorablePropertyTypes) { if (propertyType == ignoreableType || propertyType.IsSubclassOf(ignoreableType)) { return true; } } // special case constraints... if (String.Equals(property.Name, "Constraints", StringComparison.Ordinal)) { return true; } return false; } /// /// a helper structure to hold top level items we want to scan /// ///private struct SchemaTopLevelItemType { public Type ItemType; public string Name; public SchemaTopLevelItemType(Type itemType, string name) { this.ItemType = itemType; this.Name = name; } }; /// /// Helper class to compare two XmlAttributes /// ///private class AttributeComparer : System.Collections.Generic.IComparer { public int Compare(System.Xml.XmlAttribute x, System.Xml.XmlAttribute y) { int namespaceResult = String.Compare(x.NamespaceURI, y.NamespaceURI, StringComparison.Ordinal); if (namespaceResult != 0) { return namespaceResult; } return String.Compare(x.Name, y.Name, StringComparison.Ordinal); } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- NoPersistHandle.cs
- GeneralTransform.cs
- ToolStripScrollButton.cs
- WindowsListViewGroupSubsetLink.cs
- WinEventWrap.cs
- EventToken.cs
- QueryAccessibilityHelpEvent.cs
- GroupLabel.cs
- TrackingProfile.cs
- Rect3D.cs
- BezierSegment.cs
- SqlBulkCopy.cs
- XmlSchemaSubstitutionGroup.cs
- InvalidAsynchronousStateException.cs
- HMACSHA384.cs
- xdrvalidator.cs
- IMembershipProvider.cs
- ImageField.cs
- EventManager.cs
- AssemblyName.cs
- VectorCollection.cs
- CapacityStreamGeometryContext.cs
- Descriptor.cs
- Renderer.cs
- RadialGradientBrush.cs
- EdmSchemaError.cs
- TrackingStringDictionary.cs
- UriExt.cs
- CodeNamespaceCollection.cs
- As.cs
- Peer.cs
- Matrix3D.cs
- SwitchAttribute.cs
- DecoderReplacementFallback.cs
- AuthenticationModuleElementCollection.cs
- WebPartDisplayModeCancelEventArgs.cs
- ComponentResourceManager.cs
- TemplateControlCodeDomTreeGenerator.cs
- SynchronousChannel.cs
- DbConnectionClosed.cs
- UserPreferenceChangedEventArgs.cs
- TextParagraphView.cs
- TypeForwardedToAttribute.cs
- TraceRecord.cs
- BufferedReadStream.cs
- ProgressiveCrcCalculatingStream.cs
- ExpressionCopier.cs
- DictionaryContent.cs
- DoubleAnimation.cs
- Binding.cs
- StylusPointDescription.cs
- SubMenuStyle.cs
- nulltextnavigator.cs
- XmlObjectSerializerContext.cs
- InsufficientMemoryException.cs
- BindingContext.cs
- DbParameterHelper.cs
- TableAdapterManagerHelper.cs
- ExecutionContext.cs
- SQLInt16Storage.cs
- Image.cs
- _AuthenticationState.cs
- ProviderConnectionPoint.cs
- SignatureToken.cs
- TimelineCollection.cs
- ZoneIdentityPermission.cs
- FunctionParameter.cs
- TemplateManager.cs
- StrokeCollection.cs
- DragAssistanceManager.cs
- QueryGeneratorBase.cs
- NestPullup.cs
- EnumUnknown.cs
- InlineUIContainer.cs
- ProtocolsConfiguration.cs
- StylusPoint.cs
- ProfileBuildProvider.cs
- CompositionDesigner.cs
- TextStore.cs
- DocumentReferenceCollection.cs
- basenumberconverter.cs
- DrawingAttributes.cs
- File.cs
- EncoderReplacementFallback.cs
- TextSelection.cs
- ResizingMessageFilter.cs
- TraceProvider.cs
- Publisher.cs
- LostFocusEventManager.cs
- SettingsAttributes.cs
- DataGridRow.cs
- AutomationProperties.cs
- VersionPair.cs
- TextSearch.cs
- StringComparer.cs
- RenderDataDrawingContext.cs
- DateTimeFormat.cs
- BindingCollection.cs
- FilteredDataSetHelper.cs
- XmlWellformedWriter.cs