You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 14:25:44