Come definire più nomi per il campo XmlElement?

Ho un documento XML fornito dalle applicazioni client alla mia applicazione C #. Ecco come un client invia il file XML:

  2380983   

E una class C # che supporta la deserializzazione XML:

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

Ma ci sono alcuni client il cui sistema invia l’XML in questo modo (notare la lettera maiuscola in LeParentId ):

   2380983   

Come posso rendere questo campo (e altri) per supportare entrambi i nomi XML parentId e LeParentId ?

Questo è il metodo che sto attualmente utilizzando per la deserializzazione 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); } } 

Ho provato ad aggiungere [XmlElement] due volte nel campo, uno per nome di elemento, ma non ha funzionato.

Prendi 2 – implementiamo noi stessi usando l’evento di gestione dell’elemento sconosciuto (vedi comunque i commenti per alcune limitazioni):

 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); } } } 

E ora il codice effettivo della class sarebbe:

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

Per deserializzare, usa semplicemente XmlSynonymDeserializer invece del normale XmlSerializer . Questo dovrebbe funzionare per la maggior parte dei bisogni di base.

Limitazioni note:

  • Questa implementazione supporta solo elementi con più nomi; estenderlo per gli attributi dovrebbe essere banale
  • Supporto per la gestione di proprietà / campi nei casi in cui le quadro ereditano l’una dall’altra non viene testato
  • Questa implementazione non controlla i bug di programmazione (con l’attributo su read-only / campo costante / proprietà, più membri con gli stessi sinonimi e così via)

So che questo è un vecchio post, ma forse questo aiuterà chiunque abbia lo stesso problema. Quello che potresti usare per questo problema è 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 } 

Ora se hai una nuova versione xml e un nuovo nome XmlElement devi solo aggiungere quel nome all’enumerazione ItemChoiceType e un nuovo XmlElement alla proprietà.

Se hai bisogno solo di un altro nome, ecco una soluzione rapida (e piuttosto brutta) che abbiamo implementato in diversi casi nel mio lavoro quando dovevamo solo leggere XML (questo sarà problematico per la serializzazione di un XML), perché è il più semplice e facile da capire:

 [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... }