e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
772 lines
30 KiB
C#
772 lines
30 KiB
C#
#region Copyright (c) Microsoft Corporation
|
|
/// <copyright company='Microsoft Corporation'>
|
|
/// Copyright (c) Microsoft Corporation. All Rights Reserved.
|
|
/// Information Contained Herein is Proprietary and Confidential.
|
|
/// </copyright>
|
|
#endregion
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.Globalization;
|
|
using System.Reflection;
|
|
using System.Xml;
|
|
using System.Xml.Schema;
|
|
|
|
#if WEB_EXTENSIONS_CODE
|
|
using System.Web.Resources;
|
|
#else
|
|
using Microsoft.VSDesigner.WCF.Resources;
|
|
#endif
|
|
|
|
#if WEB_EXTENSIONS_CODE
|
|
namespace System.Web.Compilation.WCFModel
|
|
#else
|
|
namespace Microsoft.VSDesigner.WCFModel
|
|
#endif
|
|
{
|
|
/// <summary>
|
|
/// a utility class to merge schema files, and remove duplicated part
|
|
/// </summary>
|
|
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];
|
|
|
|
/// <summary>
|
|
/// Merge and remove duplicated part from the schema list
|
|
/// </summary>
|
|
/// <param name="schemaList">schemas with names</param>
|
|
/// <param name="importErrors">error messages</param>
|
|
/// <param name="duplicatedSchemas">error messages</param>
|
|
/// <remarks></remarks>
|
|
internal static void MergeSchemas(IEnumerable<XmlSchema> schemaList, IList<ProxyGenerationError> importErrors, out IEnumerable<XmlSchema> duplicatedSchemas)
|
|
{
|
|
if (schemaList == null)
|
|
{
|
|
throw new ArgumentNullException("schemaList");
|
|
}
|
|
if (importErrors == null)
|
|
{
|
|
throw new ArgumentNullException("importErrors");
|
|
}
|
|
|
|
List<XmlSchema> duplicatedSchemaList = new List<XmlSchema>();
|
|
duplicatedSchemas = duplicatedSchemaList;
|
|
|
|
// types, elements, groups have their own name space
|
|
Dictionary<XmlQualifiedName, XmlSchemaObject>[] knownItemTables = new Dictionary<XmlQualifiedName, XmlSchemaObject>[schemaTopLevelItemTypes.Length];
|
|
for (int i = 0; i < schemaTopLevelItemTypes.Length; i++)
|
|
{
|
|
knownItemTables[i] = new Dictionary<XmlQualifiedName, XmlSchemaObject>();
|
|
}
|
|
|
|
foreach (XmlSchema schema in schemaList)
|
|
{
|
|
|
|
bool hasNewDefinedItems = false;
|
|
List<XmlSchemaObject> duplicatedItems = new List<XmlSchemaObject>();
|
|
|
|
for (int i = 0; i < schemaTopLevelItemTypes.Length; i++)
|
|
{
|
|
Dictionary<XmlQualifiedName, XmlSchemaObject> 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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Find duplicated items in a schema
|
|
/// </summary>
|
|
/// <remarks></remarks>
|
|
private static void FindDuplicatedItems(
|
|
XmlSchema schema,
|
|
Type itemType,
|
|
string itemTypeName,
|
|
Dictionary<XmlQualifiedName, XmlSchemaObject> knownItemTable,
|
|
List<XmlSchemaObject> duplicatedItems,
|
|
IList<ProxyGenerationError> 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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Compare two schema objects
|
|
/// </summary>
|
|
/// <return></return>
|
|
/// <remarks>
|
|
/// 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
|
|
/// </remarks>
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Compare two property of a schema object
|
|
/// </summary>
|
|
/// <return>true: if the value are same</return>
|
|
/// <remarks></remarks>
|
|
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;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Compare two schema values
|
|
/// </summary>
|
|
/// <return></return>
|
|
/// <remarks></remarks>
|
|
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);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Compare two collections of items
|
|
/// </summary>
|
|
/// <return></return>
|
|
/// <remarks></remarks>
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Compare two attributes
|
|
/// </summary>
|
|
/// <return></return>
|
|
/// <remarks></remarks>
|
|
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);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Compare two attribute collections
|
|
/// </summary>
|
|
/// <return></return>
|
|
/// <remarks></remarks>
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// sort XmlAttribute array, so we can compare two collections without being affected by the order
|
|
/// </summary>
|
|
/// <return></return>
|
|
/// <remarks></remarks>
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Compare two elements
|
|
/// </summary>
|
|
/// <return></return>
|
|
/// <remarks></remarks>
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Compare two text nodes
|
|
/// </summary>
|
|
/// <return></return>
|
|
/// <remarks></remarks>
|
|
private static bool CompareXmlTexts(XmlText text1, XmlText text2)
|
|
{
|
|
return String.Equals(text1.Value, text2.Value, StringComparison.Ordinal);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Combine two path (similar to xpath) in error messages
|
|
/// </summary>
|
|
/// <return></return>
|
|
/// <remarks></remarks>
|
|
private static string CombinePath(string path1, string path2)
|
|
{
|
|
if (String.IsNullOrEmpty(path1))
|
|
{
|
|
return path2;
|
|
}
|
|
else if (String.IsNullOrEmpty(path2))
|
|
{
|
|
return path1;
|
|
}
|
|
|
|
return path1 + "/" + path2;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get Name of a top level schema item
|
|
/// </summary>
|
|
/// <param name="item"></param>
|
|
/// <return></return>
|
|
/// <remarks></remarks>
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Generate end-user unstandable property name -- we will use name in the schema file, but not name in object model
|
|
/// </summary>
|
|
/// <return></return>
|
|
/// <remarks></remarks>
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Combine names of two properties in error messages
|
|
/// </summary>
|
|
/// <remarks></remarks>
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// a helper function to generate names
|
|
/// </summary>
|
|
/// <remarks></remarks>
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Check whether a property is persisted with XmlSerialization
|
|
/// </summary>
|
|
/// <param name="property"></param>
|
|
/// <return></return>
|
|
/// <remarks></remarks>
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// check whether we should report warning but not error messages, when the property is different
|
|
/// </summary>
|
|
/// <remarks></remarks>
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// a helper structure to hold top level items we want to scan
|
|
/// </summary>
|
|
/// <remarks></remarks>
|
|
private struct SchemaTopLevelItemType
|
|
{
|
|
public Type ItemType;
|
|
public string Name;
|
|
|
|
public SchemaTopLevelItemType(Type itemType, string name)
|
|
{
|
|
this.ItemType = itemType;
|
|
this.Name = name;
|
|
}
|
|
};
|
|
|
|
/// <summary>
|
|
/// Helper class to compare two XmlAttributes
|
|
/// </summary>
|
|
/// <remarks></remarks>
|
|
private class AttributeComparer : System.Collections.Generic.IComparer<XmlAttribute>
|
|
{
|
|
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|