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

解析修改保存XML时如何保留属性值中>字符不被自动转义

解决方案

.NET 内置的 XmlDocument、XDocument 搭配默认 XmlWriter 输出时,确实会无条件转义属性和文本中的>字符,这个行为是默认输出逻辑写死的,没有公开的配置开关可以直接关闭,但可以通过以下两种合规的方式实现需求,且不会遗漏必须转义的场景:

  • 方案1:自定义XmlWriter实现标准兼容的转义逻辑(生产环境推荐)
    这个方案完全遵循XML 2.4节的转义要求,仅在确实需要转义>的场景(即]]>序列末尾)才输出实体引用,其余场景直接保留原始>字符,不会破坏XML合法性,也不会误改需要保留的格式:

    1. 继承XmlWriter类,将除WriteString之外的所有抽象成员全部转发给内部包装的原生XmlWriter实例
    2. 重写WriteString方法时,对强制转义字符&、<、"、'正常输出对应实体引用
    3. 针对>字符维护一个长度为2的滑动窗口,检查当前字符前两个紧邻的字符是否为]]:如果是则转义为&gt;,否则直接输出原始>字符
    4. 保存XML时,将自定义Writer实例传入Save方法即可,你对XML文档做的所有结构修改都会正常保留。

    核心实现示例:

    public class StandardCompliantXmlWriter : XmlWriter
    {
        private readonly XmlWriter _inner;
        private readonly char[] _slidingBuffer = new char[2];
        private int _bufIndex = 0;
    
        public StandardCompliantXmlWriter(XmlWriter innerWriter) => _inner = innerWriter;
        public override WriteState WriteState => _inner.WriteState;
        public override void Flush() => _inner.Flush();
        public override void WriteStartElement(string prefix, string localName, string ns) => _inner.WriteStartElement(prefix, localName, string ns);
        public override void WriteEndElement() => _inner.WriteEndElement();
        public override void WriteFullEndElement() => _inner.WriteFullEndElement();
        public override void WriteStartAttribute(string prefix, string localName, string ns) => _inner.WriteStartAttribute(prefix, localName, ns);
        public override void WriteEndAttribute() => _inner.WriteEndAttribute();
    
        public override void WriteString(string text)
        {
            if (string.IsNullOrEmpty(text)) return;
            foreach (var c in text)
            {
                switch (c)
                {
                    case '&': _inner.WriteEntityRef("amp"); break;
                    case '<': _inner.WriteEntityRef("lt"); break;
                    case '"': _inner.WriteEntityRef("quot"); break;
                    case '\'': _inner.WriteEntityRef("apos"); break;
                    case '>':
                        if (_bufIndex >=2 && _slidingBuffer[0] == ']' && _slidingBuffer[1] == ']')
                            _inner.WriteEntityRef("gt");
                        else
                            _inner.WriteRaw(">");
                        break;
                    default: _inner.WriteChar(c); break;
                }
                _slidingBuffer[_bufIndex % 2] = c;
                _bufIndex++;
            }
        }
    }
    

    调用方式:

    var doc = XDocument.Load("yourfile.xml");
    // 在此处执行你需要的XML修改逻辑
    using var fs = File.Create("output.xml");
    using var baseWriter = XmlWriter.Create(fs, new XmlWriterSettings { Indent = true, Encoding = Encoding.UTF8 });
    using var writer = new StandardCompliantXmlWriter(baseWriter);
    doc.Save(writer);
    

    输出结果中示例里的Name="a->b"会原样保留,仅当碰到]]>这类必须转义的序列时才会转义对应的>,完全符合XML标准,也不会出现后处理方案的误替换问题。

  • 方案2:反射修改内置XmlWriter的私有开关(仅适合固定.NET版本场景)
    .NET的原生XmlWriter内部存在一个名为DoNotEscapeRightAngleBracket的私有配置字段,将其设置为true后,原生Writer也会停止非必要的>转义。但这个字段是非公开成员,在不同.NET版本(.NET Framework、.NET Core、.NET 5+)中可能存在命名、位置变化,升级框架时需要重新校验兼容性,不推荐在对稳定性要求高的生产环境使用。

不建议使用输出后替换的方案:全局替换&gt;为>会破坏必须转义的场景,而基于正则的上下文判断本质上是在重新实现XML解析逻辑,很容易漏掉边界场景引入错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 14:33:17