¿Cómo se definen varios nombres para el campo XmlElement?

Tengo un documento XML proporcionado por aplicaciones cliente para mi aplicación C #. Así es como un cliente envía el archivo XML:

  2380983   

Y una clase C # que admite la deserialización XML:

 [XmlRoot] public class SomeAccount { [XmlElement("parentId")] public long ParentId { get; set; } //rest of fields... } 

Pero hay algunos clientes cuyo sistema envía el XML de esta manera (observe la mayúscula en LeParentId ):

   2380983   

¿Cómo puedo hacer que este campo (y otros) sean compatibles con los nombres XML parentId y LeParentId ?

Este es el método que estoy usando actualmente para la deserialización XML:

 public sealed class XmlSerializationUtil { public static T Deserialize(string xml) { if (xml == null) return default(T); XmlSerializer serializer = new XmlSerializer(typeof(T)); StringReader stringReader = new StringReader(xml); return (T)serializer.Deserialize(stringReader); } } 

Traté de agregar [XmlElement] dos veces en el campo, uno por nombre de elemento, pero eso no funcionó.

    Tome 2: impleméntelo nosotros mismos usando el evento de manejo de elementos desconocido (sin embargo, a pesar de algunas limitaciones, consulte los comentarios a continuación):

     public class XmlSynonymDeserializer : XmlSerializer { public class SynonymsAttribute : Attribute { public readonly ISet Names; public SynonymsAttribute(params string[] names) { this.Names = new HashSet(names); } public static MemberInfo GetMember(object obj, string name) { Type type = obj.GetType(); var result = type.GetProperty(name); if (result != null) return result; foreach (MemberInfo member in type.GetProperties().Cast().Union(type.GetFields())) foreach (var attr in member.GetCustomAttributes(typeof(SynonymsAttribute), true)) if (attr is SynonymsAttribute && ((SynonymsAttribute)attr).Names.Contains(name)) return member; return null; } } public XmlSynonymDeserializer(Type type) : base(type) { this.UnknownElement += this.SynonymHandler; } public XmlSynonymDeserializer(Type type, XmlRootAttribute root) : base(type, root) { this.UnknownElement += this.SynonymHandler; } protected void SynonymHandler(object sender, XmlElementEventArgs e) { var member = SynonymsAttribute.GetMember(e.ObjectBeingDeserialized, e.Element.Name); Type memberType; if (member != null && member is FieldInfo) memberType = ((FieldInfo)member).FieldType; else if (member != null && member is PropertyInfo) memberType = ((PropertyInfo)member).PropertyType; else return; if (member != null) { object value; XmlSynonymDeserializer serializer = new XmlSynonymDeserializer(memberType, new XmlRootAttribute(e.Element.Name)); using (System.IO.StringReader reader = new System.IO.StringReader(e.Element.OuterXml)) value = serializer.Deserialize(reader); if (member is FieldInfo) ((FieldInfo)member).SetValue(e.ObjectBeingDeserialized, value); else if (member is PropertyInfo) ((PropertyInfo)member).SetValue(e.ObjectBeingDeserialized, value); } } } 

    Y ahora el código real de la clase sería:

     [XmlRoot] public class SomeAccount { [XmlElement("parentId")] [XmlSynonymDeserializer.Synonyms("LeParentId", "AnotherGreatName")] public long ParentId { get; set; } //rest of fields... } 

    Para deserializar, simplemente use XmlSynonymDeserializer lugar del XmlSerializer regular. Esto debería funcionar para la mayoría de las necesidades básicas.

    Limitaciones conocidas

    • Esta implementación solo admite elementos con múltiples nombres; extenderlo por atributos debe ser trivial
    • No se prueba el soporte para el manejo de propiedades / campos en casos en que las entidades heredan entre sí
    • Esta implementación no verifica errores de progtwigción (teniendo el atributo en campo / propiedades de solo lectura / constantes, miembros múltiples con los mismos sinónimos, etc.)

    Sé que esta es una publicación anterior, pero tal vez esto ayude a cualquier persona que tenga el mismo problema. Lo que podrías usar para este problema es XmlChoiceIdentifier.

     [XmlRoot] public class SomeAccount { [XmlIgnore] public ItemChoiceType EnumType; [XmlChoiceIdentifier("EnumType")] [XmlElement("LeParentId")] [XmlElement("parentId")] public long ParentId { get; set; } //rest of fields... } [XmlType(IncludeInSchema = false)] public enum ItemChoiceType { LeParentId, parentId } 

    Ahora, si tiene una nueva versión xml y un nuevo nombre XmlElement, simplemente agregue ese nombre a la enumeración ItemChoiceType y un nuevo XmlElement a la propiedad.

    Si solo necesita un nombre más, aquí hay una solución rápida (y bastante fea) que implementamos en varios casos en mi trabajo cuando solo teníamos que leer XML (esto será problemático para la serialización en un XML), porque es el lo más simple y fácil de entender:

     [XmlRoot] public class SomeAccount { [XmlElement("parentId")] public long ParentId { get; set; } [XmlElement("LeParentId")] public long LeParentId { get { return this.ParentId; } set { this.ParentId = value; } } //rest of fields... }