如何为XmlElement字段定义多个名称?

我有一个客户端应用程序提供给我的C#应用​​程序的XML文档。 这是客户端发送XML文件的方式:

  2380983   

还有一个支持XML反序列化的C#类:

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

但是有一些客户端的系统以这种方式发送XML(请注意LeParentId中的LeParentId ):

   2380983   

如何使此字段(和其他字段)支持XML名称parentIdLeParentId

这是我目前用于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); } } 

我试图在字段中添加两次[XmlElement] ,每个元素名称一个,但这不起作用。

Take 2 – 让我们自己使用未知元素处理事件来实现它(尽管有一些限制,请参阅下面的注释):

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

而现在该类的实际代码将是:

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

要反序列化,只需使用XmlSynonymDeserializer而不是常规的XmlSerializer 。 这应该适用于大多数基本需求。

已知限制:

  • 此实现仅支持具有多个名称的元素; 为属性扩展它应该是微不足道的
  • 不测试在实体彼此inheritance的情况下处理属性/字段的支持
  • 此实现不检查编程错误(具有只读/常量字段/属性的属性,具有相同同义词的多个成员等)

我知道这是一个旧post,但也许这会帮助其他人遇到同样的问题。 您可以用于此问题的是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 } 

现在,如果您有一个新的xml版本和一个新的XmlElement名称,您只需将该名称添加到ItemChoiceType枚举中,并将新的XmlElement添加到该属性中。

如果你只需要一个名字,这里有一个快速(而且相当丑陋)的解决方案,当我们只读取XML时,我们在工作中的几个案例中部署了这个(这对于序列化回到XML会有问题),因为它是最简单易懂:

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