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

.NET XmlReader处理cXML时DTD验证报错,如何配置XmlReaderSettings?

问题描述

在.NET 4.8、6、7中处理cXML文件时,使用XmlReader开启DTD验证会抛出以下异常:

Unhandled exception. System.Xml.Schema.XmlSchemaException: The parameter entity replacement text must nest properly within markup declarations.

示例cXML输入:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE cXML SYSTEM "http://xml.cxml.org/schemas/cXML/1.2.041/cXML.dtd">
<cXML payloadID="donkeys@example.com" timestamp="2023-02-13T01:01:01Z">
  <Header>
  </Header>
  <Request deploymentMode="production">
  </Request>
</cXML>

示例应用代码:

using System.Xml;
using System.Xml.Linq;

namespace Donkeys
{
    internal class Program
    {
        static void Main()
        {
            XmlReaderSettings settings = new()
            {
                XmlResolver = new XmlUrlResolver(),
                DtdProcessing = DtdProcessing.Parse,
                ValidationType = ValidationType.DTD,
            };

            FileStream fs = File.OpenRead("test.xml"); // 上述示例cXML文件
            XmlReader reader = XmlReader.Create(fs, settings);

            XDocument.Load(reader); // 此处抛出异常
        }
    }
}

目前的情况是:希望通过XmlUrlResolver缓存DTD,但开启DTD验证就会触发上述错误。尝试过不同验证标志,仅当ValidationType = ValidationType.DTD时会验证并报错。XmlUrlResolver工作正常,子类化后能正确返回MemoryStream形式的DTD。

临时解决方案是通过添加验证事件处理程序忽略该错误,但这种方式不够稳妥:

using System.Xml;
using System.Xml.Linq;

namespace Donkeys
{
    internal class Program
    {
        static void Main()
        {
            XmlReaderSettings settings = new()
            {
                XmlResolver = new XmlUrlResolver(),
                DtdProcessing = DtdProcessing.Parse,
                ValidationType = ValidationType.DTD,
                IgnoreComments = true
            };

            settings.ValidationEventHandler += Settings_ValidationEventHandler;

            FileStream fs = File.OpenRead("test.xml");
            XmlReader reader = XmlReader.Create(fs, settings);

            XDocument dogs = XDocument.Load(reader);
         }

        private static void Settings_ValidationEventHandler(object? sender, System.Xml.Schema.ValidationEventArgs e)
        {
            // 这种匹配消息的方式很脆弱
            if (e.Message.Equals("The parameter entity replacement text must nest properly within markup declarations.", StringComparison.OrdinalIgnoreCase))
                return;

            throw e.Exception;
        }
    }
}

请问是否可以通过配置XmlReaderSettings的某些参数,让.NET原生处理这类cXML而不抛出异常?


解决方案

这个问题的根源在于,cXML的DTD使用了一些不符合.NET XmlReader严格DTD验证规则的语法(具体是参数实体的嵌套方式不满足.NET的解析要求),而.NET的XmlReader对DTD的兼容性比部分其他XML解析器更严格。

目前没有直接通过XmlReaderSettings配置就能完全解决的方案,不过可以参考以下更稳健的处理方式:

1. 优化验证事件处理逻辑

如果必须保留DTD验证,不要直接匹配错误消息文本(容易因语言、版本更新失效),可以通过异常的类型和HResult来判断:

private static void Settings_ValidationEventHandler(object? sender, System.Xml.Schema.ValidationEventArgs e)
{
    if (e.Exception is XmlSchemaException schemaEx 
        && schemaEx.HResult == -2146232000) // 对应该特定DTD验证错误的HResult
    {
        return;
    }
    throw e.Exception;
}

注:HResult值需要提前确认是否在你的.NET版本中稳定对应该错误。

2. 预加载并修正DTD

如果有权限或能力,可以预先下载cXML的DTD,修改其中不符合.NET验证规则的参数实体嵌套部分,然后通过自定义XmlResolver返回修改后的本地DTD。这种方式能从根源解决验证错误,但需要维护DTD的同步更新。

3. 关闭DTD验证但保留实体解析

如果业务场景中不需要严格的DTD验证,仅需要解析XML中的实体引用,可以将ValidationType设为ValidationType.None,同时保留DtdProcessing = DtdProcessing.Parse:

XmlReaderSettings settings = new()
{
    XmlResolver = new XmlUrlResolver(),
    DtdProcessing = DtdProcessing.Parse,
    ValidationType = ValidationType.None, // 关闭验证
};

这种方式不会触发验证错误,同时仍能解析DTD中的实体,也能通过XmlUrlResolver缓存DTD。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 16:00:59