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

如何用XmlSerializer序列化含派生类集合并移除xmlns引用

解决序列化抽象类List时移除XML xmlns引用的问题

需要序列化包含不同子类的List<AbstractTable>集合,生成不含xmlns引用的XML。当前代码生成的XML中每个<Tables>元素都带有xmlns:p2="http://www.w3.org/2001/XMLSchema-instance"命名空间声明,以及p2:type属性,需要移除这些内容。


方案一:自定义XmlWriter移除命名空间和前缀

通过自定义XmlWriter拦截并处理xsi相关的命名空间声明和属性,直接生成无命名空间的XML。

自定义XmlWriter代码

public class NoNamespaceXmlWriter : XmlTextWriter
{
    public NoNamespaceXmlWriter(TextWriter writer) : base(writer) { }

    public override void WriteStartElement(string prefix, string localName, string ns)
    {
        // 忽略元素的命名空间和前缀
        base.WriteStartElement("", localName, "");
    }

    public override void WriteStartAttribute(string prefix, string localName, string ns)
    {
        // 将xsi:type转换为无前缀的type属性
        if (prefix == "p2" && localName == "type" && ns == "http://www.w3.org/2001/XMLSchema-instance")
        {
            base.WriteStartAttribute("", "type", "");
        }
        else
        {
            base.WriteStartAttribute("", localName, "");
        }
    }

    public override void WriteAttributeString(string prefix, string localName, string ns, string value)
    {
        // 忽略所有xmlns相关的属性声明
        if (prefix == "xmlns" || (localName == "xmlns" && prefix == ""))
        {
            return;
        }
        // 处理xsi:type属性,转换为无命名空间的type
        if (prefix == "p2" && localName == "type" && ns == "http://www.w3.org/2001/XMLSchema-instance")
        {
            base.WriteAttributeString("", "type", "", value);
        }
        else
        {
            base.WriteAttributeString("", localName, "", value);
        }
    }
}

修改序列化方法

替换原有的SerializeToString方法,使用自定义的NoNamespaceXmlWriter:

public static string SerializeToString<T>(T value)
{
    var serializer = new XmlSerializer(value.GetType());
    using (var stream = new StringWriter())
    using (var writer = new NoNamespaceXmlWriter(stream))
    {
        writer.Formatting = Formatting.Indented;
        serializer.Serialize(writer, value);
        return stream.ToString();
    }
}

生成的XML效果

<Root>
  <Tables type="TableType1" TableName="TableType1" ValueA="AAA" />
  <Tables type="TableType2" TableName="TableType2" ValueB="BBB" />
</Root>

方案二:使用XmlChoiceIdentifier替代xsi:type

利用XmlChoiceIdentifierAttribute通过已有TableName属性(或自定义枚举)标识子类类型,彻底移除xsi相关内容。

步骤1:定义类型枚举

public enum TableType
{
    TableType1,
    TableType2
}

步骤2:修改Root类

添加XmlChoiceIdentifier属性和对应的枚举集合:

[Serializable]
public class Root
{
    [XmlElement("Tables", Type = typeof(TableType1))]
    [XmlElement("Tables", Type = typeof(TableType2))]
    [XmlChoiceIdentifier("TableTypeIdentifier")]
    public List<AbstractTable> Tables { get; set; } = new List<AbstractTable>();

    [XmlIgnore]
    public List<TableType> TableTypeIdentifier { get; set; } = new List<TableType>();
}

步骤3:修改序列化前的赋值逻辑

添加子类时同步设置对应的枚举值:

var allegato = new Root();

var tableType1 = new TableType1();
tableType1.ValueA = "AAA";
allegato.Tables.Add(tableType1);
allegato.TableTypeIdentifier.Add(TableType.TableType1);

var tableType2 = new TableType2();
tableType2.ValueB = "BBB";
allegato.Tables.Add(tableType2);
allegato.TableTypeIdentifier.Add(TableType.TableType2);

生成的XML效果

<Root>
  <Tables TableName="TableType1" ValueA="AAA" />
  <Tables TableName="TableType2" ValueB="BBB" />
</Root>

内容的提问来源于stack exchange,提问作者Gabriele

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 22:47:13