C#中复用类反序列化不同元素名XML文件的问题求助
解决方案:复用类实现不同XML结构的反序列化
XmlSerializer不支持为单个属性重复应用[XmlElement]特性,因此你原代码中的写法无法同时识别两种前缀的XML元素。以下是两种可行的解决方案:
方法一:使用XmlAttributeOverrides动态配置序列化规则
通过动态生成序列化规则,根据XML类型(MR/RESP)创建对应元素名的XmlSerializer实例,复用同一个TransferDoctorXml类。
实现代码
public static class TransferXmlSerializerFactory { // 缓存Serializer实例,避免重复创建影响性能 private static readonly Dictionary<string, XmlSerializer> _serializerCache = new Dictionary<string, XmlSerializer>(); public static XmlSerializer GetSerializer(string parentNodeName, string elementPrefix) { string cacheKey = $"{parentNodeName}_{elementPrefix}"; if (_serializerCache.TryGetValue(cacheKey, out var serializer)) { return serializer; } // 配置TransferXml的父节点映射 var transferOverrides = new XmlAttributeOverrides(); var transferAttributes = new XmlAttributes(); transferAttributes.XmlElements.Add(new XmlElementAttribute(parentNodeName)); transferOverrides.Add(typeof(TransferXml), nameof(TransferXml.TR_DOCTOR_MR), transferAttributes); // 配置TransferDoctorXml的元素前缀映射 var doctorOverrides = new XmlAttributeOverrides(); foreach (var prop in typeof(TransferDoctorXml).GetProperties()) { var elementAttr = new XmlElementAttribute($"{elementPrefix}{prop.Name.ToUpper()}"); var attrs = new XmlAttributes(); attrs.XmlElements.Add(elementAttr); doctorOverrides.Add(typeof(TransferDoctorXml), prop.Name, attrs); } // 合并配置并创建Serializer var combinedOverrides = new XmlAttributeOverrides(); foreach (var kvp in transferOverrides) combinedOverrides.Add(kvp.Key, kvp.Value); foreach (var kvp in doctorOverrides) combinedOverrides.Add(kvp.Key, kvp.Value); serializer = new XmlSerializer(typeof(TransferXml), combinedOverrides); _serializerCache.Add(cacheKey, serializer); return serializer; } } // 反序列化调用示例 string doctorMrXml = File.ReadAllText(@"C:\TEMP\TransferDoctorMr.xml"); using (var reader = new StringReader(doctorMrXml)) { var serializer = TransferXmlSerializerFactory.GetSerializer("TR_DOCTOR_MR", "REFDOC_"); var drXml = (TransferXml)serializer.Deserialize(reader); } string doctorRespXml = File.ReadAllText(@"C:\TEMP\TransferDoctorResp.xml"); using (var reader = new StringReader(doctorRespXml)) { var serializer = TransferXmlSerializerFactory.GetSerializer("TR_DOCTOR_RESP", "ATDOC_"); var drXml = (TransferXml)serializer.Deserialize(reader); }
方法二:自定义XmlReader替换元素前缀
通过包装默认XmlReader,在读取XML时自动将带前缀的元素名转换为统一的无前缀名称,简化TransferDoctorXml类的属性标记。
实现代码
// 自定义XmlReader,用于替换元素前缀 public class PrefixReplacingXmlReader : XmlReaderWrapper { private readonly string _oldPrefix; public PrefixReplacingXmlReader(XmlReader innerReader, string oldPrefix) : base(innerReader) { _oldPrefix = oldPrefix; } public override string LocalName { get { var localName = base.LocalName; return localName.StartsWith(_oldPrefix) ? localName.Substring(_oldPrefix.Length) : localName; } } } // XmlReader包装基类,转发所有方法到内部Reader public abstract class XmlReaderWrapper : XmlReader { protected readonly XmlReader InnerReader; protected XmlReaderWrapper(XmlReader innerReader) { InnerReader = innerReader ?? throw new ArgumentNullException(nameof(innerReader)); } public override XmlNodeType NodeType => InnerReader.NodeType; public override string Name => InnerReader.Name; public override string NamespaceURI => InnerReader.NamespaceURI; public override string Prefix => InnerReader.Prefix; public override bool HasValue => InnerReader.HasValue; public override string Value => InnerReader.Value; public override int Depth => InnerReader.Depth; public override string BaseURI => InnerReader.BaseURI; public override bool IsEmptyElement => InnerReader.IsEmptyElement; public override int AttributeCount => InnerReader.AttributeCount; public override bool EOF => InnerReader.EOF; public override ReadState ReadState => InnerReader.ReadState; public override XmlNameTable NameTable => InnerReader.NameTable; public override string GetAttribute(string name) => InnerReader.GetAttribute(name); public override string GetAttribute(string name, string namespaceURI) => InnerReader.GetAttribute(name, namespaceURI); public override string GetAttribute(int i) => InnerReader.GetAttribute(i); public override bool MoveToAttribute(string name) => InnerReader.MoveToAttribute(name); public override bool MoveToAttribute(string name, string ns) => InnerReader.MoveToAttribute(name, ns); public override bool MoveToFirstAttribute() => InnerReader.MoveToFirstAttribute(); public override bool MoveToNextAttribute() => InnerReader.MoveToNextAttribute(); public override bool MoveToElement() => InnerReader.MoveToElement(); public override bool Read() => InnerReader.Read(); public override bool ReadAttributeValue() => InnerReader.ReadAttributeValue(); public override void Close() => InnerReader.Close(); public override string LookupNamespace(string prefix) => InnerReader.LookupNamespace(prefix); public override void ResolveEntity() => InnerReader.ResolveEntity(); } // 修改后的TransferDoctorXml类,使用无前缀元素名 public class TransferDoctorXml { [XmlElement("CODE")] public string Code { get; set; } [XmlElement("HOSPITALKEY")] public string HospitalKey { get; set; } [XmlElement("RIZIV")] public string Riziv { get; set; } [XmlElement("NAME")] public string LastName { get; set; } [XmlElement("FNAME")] public string FirstName { get; set; } [XmlElement("TITLE")] public string Title { get; set; } [XmlElement("INITIALS")] public string Initials { get; set; } [XmlElement("FREEFIELD1")] public string FreeField1 { get; set; } [XmlElement("FREEFIELD2")] public string FreeField2 { get; set; } [XmlElement("FREEFIELD3")] public string FreeField3 { get; set; } } // 修改后的TransferXml类,支持两种父节点 [XmlRoot("TRANSFERS")] public class TransferXml { [XmlElement("TR_DOCTOR_MR", Type = typeof(TransferDoctorXml))] [XmlElement("TR_DOCTOR_RESP", Type = typeof(TransferDoctorXml))] public TransferDoctorXml Doctor { get; set; } } // 反序列化调用示例 string doctorMrXml = File.ReadAllText(@"C:\TEMP\TransferDoctorMr.xml"); using (var stringReader = new StringReader(doctorMrXml)) using (var xmlReader = XmlReader.Create(stringReader)) using (var prefixReader = new PrefixReplacingXmlReader(xmlReader, "REFDOC_")) { var serializer = new XmlSerializer(typeof(TransferXml)); var drXml = (TransferXml)serializer.Deserialize(prefixReader); } string doctorRespXml = File.ReadAllText(@"C:\TEMP\TransferDoctorResp.xml"); using (var stringReader = new StringReader(doctorRespXml)) using (var xmlReader = XmlReader.Create(stringReader)) using (var prefixReader = new PrefixReplacingXmlReader(xmlReader, "ATDOC_")) { var serializer = new XmlSerializer(typeof(TransferXml)); var drXml = (TransferXml)serializer.Deserialize(prefixReader); }
内容的提问来源于stack exchange,提问作者Prashant Desai
相关产品推荐
相关产品推荐

