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

使用C# Saxon API校验XML与XSD时无法捕获全部验证错误

解决Saxon API一次性捕获所有XML验证错误的问题

核心原因

Saxon默认错误处理机制会在遇到第一个严重错误时终止验证流程,想要收集全部错误,需要自定义错误监听器来接管错误处理逻辑,避免验证中断。

解决方案步骤

1. 自定义错误监听器

实现IErrorListener接口,将所有验证错误(包括警告、普通错误、致命错误)存储到列表中,关键是不要在错误处理方法中抛出异常,否则会中断验证:

using Saxon.Api;
using System.Collections.Generic;

public class CollectingErrorListener : IErrorListener
{
    public List<XmlValidationIssue> Issues { get; } = new List<XmlValidationIssue>();

    public void Error(StaticError error)
    {
        Issues.Add(new XmlValidationIssue(error.Message, error.LineNumber, error.ColumnNumber, error.ErrorCode, IssueType.Error));
    }

    public void FatalError(StaticError error)
    {
        Issues.Add(new XmlValidationIssue(error.Message, error.LineNumber, error.ColumnNumber, error.ErrorCode, IssueType.FatalError));
    }

    public void Warning(StaticError error)
    {
        Issues.Add(new XmlValidationIssue(error.Message, error.LineNumber, error.ColumnNumber, error.ErrorCode, IssueType.Warning));
    }
}

public enum IssueType
{
    Warning,
    Error,
    FatalError
}

public class XmlValidationIssue
{
    public string Message { get; }
    public int LineNumber { get; }
    public int ColumnNumber { get; }
    public string ErrorCode { get; }
    public IssueType Type { get; }

    public XmlValidationIssue(string message, int lineNumber, int columnNumber, string errorCode, IssueType type)
    {
        Message = message;
        LineNumber = lineNumber;
        ColumnNumber = columnNumber;
        ErrorCode = errorCode;
        Type = type;
    }
}

2. 修改校验代码,接入自定义监听器

在创建SchemaValidator后,替换默认的错误监听器为自定义实现,执行验证后即可获取所有错误:

using Saxon.Api;
using System.IO;

public void ValidateXml(string xmlFilePath, string xsdFilePath)
{
    // 初始化Saxon处理器
    var processor = new Processor();
    var schemaManager = processor.SchemaManager;

    // 加载XSD Schema
    using var xsdStream = File.OpenRead(xsdFilePath);
    schemaManager.Load(new XmlTextReader(xsdStream));

    // 创建验证器并绑定自定义错误监听器
    var validator = schemaManager.NewSchemaValidator();
    var errorCollector = new CollectingErrorListener();
    validator.ErrorListener = errorCollector;

    // 加载待验证的XML
    using var xmlStream = File.OpenRead(xmlFilePath);
    var xmlReader = processor.NewXmlReader(xmlStream);
    validator.SetSource(xmlReader);

    // 执行验证(不会因错误中断)
    validator.Run();

    // 处理收集到的所有问题
    if (errorCollector.Issues.Count > 0)
    {
        foreach (var issue in errorCollector.Issues)
        {
            Console.WriteLine($"[{issue.Type}] 行{issue.LineNumber}, 列{issue.ColumnNumber}: {issue.Message} (错误码: {issue.ErrorCode})");
        }
        // 可根据业务需求抛出汇总异常,或返回错误列表
        throw new InvalidOperationException($"XML验证失败,共检测到{errorCollector.Issues.Count}个问题");
    }
    else
    {
        Console.WriteLine("XML验证通过");
    }
}

3. 关键注意事项

  • 自定义监听器的Error和FatalError方法绝对不能抛出异常,否则Saxon会立刻终止验证,无法收集后续错误。
  • 可通过IssueType区分问题级别,按需过滤或处理不同类型的验证问题。
  • 确保使用的Saxon版本支持自定义ErrorListener(HE/PE/EE版本均支持,建议使用较新的稳定版本)。

示例测试文件

示例XSD(test.xsd)

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="Root">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="Name" type="xs:string" minOccurs="1"/>
                <xs:element name="Age" type="xs:int" minOccurs="1"/>
                <xs:element name="Email" type="xs:anyURI" minOccurs="1"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>

示例XML(test.xml,含多个错误)

<?xml version="1.0" encoding="UTF-8"?>
<Root>
    <Age>abc</Age> <!-- 数据类型错误 -->
    <!-- 缺少Name元素 -->
    <Email>invalid-email</Email> <!-- URI格式错误 -->
    <ExtraElement>多余内容</ExtraElement> <!-- 未定义元素 -->
</Root>

运行校验代码后,会一次性捕获全部4个验证问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 06:45:30