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

C#序列化对象到XML:保留Name元素XML文本不转义

解决方案:动态控制Xml序列化时的字符转义

这个问题其实是Xml序列化里常见的「选择性不转义特殊字符」需求,默认的XmlSerializer会自动转义所有XML特殊字符(比如<、>、&),但我们可以通过两种方式实现你要的动态处理效果——既支持直接输出XML标签内容,也兼容普通文本的正常序列化。

方法1:实现IXmlSerializable接口自定义序列化逻辑

通过实现IXmlSerializable,我们可以完全掌控序列化/反序列化的过程,根据Name属性的内容动态决定是输出原始XML片段还是转义后的文本。

代码示例

using System.IO;
using System.Xml;
using System.Xml.Serialization;

public class ObjSer : IXmlSerializable
{
    public string Name { get; set; }

    // 实现IXmlSerializable的接口方法,返回null即可
    public XmlSchema GetSchema() => null;

    // 反序列化逻辑(如果需要支持从XML还原对象,可按需求实现)
    public void ReadXml(XmlReader reader)
    {
        reader.ReadStartElement();
        if (!reader.IsEmptyElement)
        {
            Name = reader.NodeType == XmlNodeType.Element 
                ? reader.ReadInnerXml() 
                : reader.ReadContentAsString();
        }
        reader.ReadEndElement();
    }

    // 核心:自定义序列化逻辑
    public void WriteXml(XmlWriter writer)
    {
        writer.WriteStartElement("Name");
        try
        {
            // 尝试把Name内容当作XML片段写入
            using var stringReader = new StringReader(Name);
            using var xmlReader = XmlReader.Create(stringReader, new XmlReaderSettings 
            { 
                ConformanceLevel = ConformanceLevel.Fragment 
            });
            writer.WriteNode(xmlReader, true);
        }
        catch (XmlException)
        {
            // 解析失败(说明是普通文本),则写入转义后的字符串
            writer.WriteString(Name);
        }
        writer.WriteEndElement();
    }
}

测试验证

// 场景1:带XML标签的内容
var objWithTags = new ObjSer { Name = "<tag1>Value</tag1>" };
using var sw1 = new StringWriter();
new XmlSerializer(typeof(ObjSer)).Serialize(sw1, objWithTags);
Console.WriteLine(sw1.ToString());
// 输出:<ObjSer><Name><tag1>Value</tag1></Name></ObjSer>

// 场景2:普通文本内容
var objPlainText = new ObjSer { Name = "Value" };
using var sw2 = new StringWriter();
new XmlSerializer(typeof(ObjSer)).Serialize(sw2, objPlainText);
Console.WriteLine(sw2.ToString());
// 输出:<ObjSer><Name>Value</Name></ObjSer>

方法2:使用辅助属性配合XmlAnyElement

如果不想修改整个类的序列化逻辑,可以用「忽略原属性+辅助XmlNode属性」的方式,只针对Name字段做特殊处理,代码更简洁。

代码示例

using System.Xml;
using System.Xml.Serialization;

public class ObjSer
{
    // 用XmlIgnore忽略原属性,不参与序列化
    [XmlIgnore]
    public string Name { get; set; }

    // 辅助属性,负责实际的序列化/反序列化
    [XmlElement("Name")]
    public XmlNode NameAsXml
    {
        get
        {
            if (string.IsNullOrEmpty(Name)) return null;
            
            try
            {
                // 尝试将Name解析为XML片段,返回对应的元素节点
                var doc = new XmlDocument();
                doc.LoadXml($"<temp>{Name}</temp>");
                return doc.DocumentElement.FirstChild;
            }
            catch (XmlException)
            {
                // 解析失败,返回文本节点(自动处理转义)
                var doc = new XmlDocument();
                return doc.CreateTextNode(Name);
            }
        }
        set
        {
            // 反序列化时还原Name属性
            if (value == null)
            {
                Name = null;
            }
            else if (value is XmlText textNode)
            {
                Name = textNode.Value;
            }
            else
            {
                Name = value.OuterXml;
            }
        }
    }
}

效果说明

这个方法的核心是利用XmlNode类型的特性:如果是元素节点,XmlSerializer会直接输出节点的原始XML内容;如果是文本节点,则会自动处理特殊字符转义,完美适配你的两种场景。

两种方法对比

  • 方法1:灵活性极高,适合需要对整个类的序列化做更多定制的场景,但需要自己实现完整的序列化/反序列化逻辑。
  • 方法2:代码更简洁,仅针对单个属性处理,侵入性低,适合只需要定制个别字段的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:23:47