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

SaxonCS捕获XSLT转换错误疑问——Schematron校验失败断言未进入自定义错误列表

SaxonCS捕获XSLT转换错误疑问——Schematron校验失败断言未进入自定义错误列表

兄弟,我完全懂你的困惑!你现在遇到的核心问题是:Schematron的svrl:failed-assert属于校验结果的正常输出,并不是Saxon认定的「XSLT转换错误」,所以你的ErrorReporter根本不会捕获到这些内容。

为什么会这样?

Saxon的ErrorReporter负责捕获的是XSLT执行过程中出现的运行时异常——比如XSLT语法错误、节点查找失败、类型转换错误这类会中断或影响转换流程的问题。而Schematron的工作逻辑是:把校验规则编译成XSLT,然后通过转换XML生成包含failed-assert的SVRL报告,这整个过程是完全正常的XSLT转换,没有触发任何错误,自然不会被ErrorReporter记录。

怎么解决你的需求?

你要的是判断XML是否符合Schematron规则,其实不需要依赖ErrorReporter,直接处理转换出来的SVRL报告就可以了,这里给你两种实用方案:

方案一:解析SVRL输出文件,检查失败断言

这是最直接的方式,转换完成后读取生成的SVRL文件,用XPath查询是否存在svrl:failed-assert元素:

public static bool Validate(string schematronFilePath, string xmlFilePath)
{
    Processor processor = new();
    var compiler = processor.NewXsltCompiler();
    Xslt30Transformer transformer = compiler.Compile(new Uri(schematronFilePath)).Load30();
    transformer.SchemaValidationMode = SchemaValidationMode.Strict;

    XdmNode input = processor.NewDocumentBuilder().Build(new Uri(xmlFilePath));
    transformer.GlobalContextItem = input;

    string svrlOutputPath = @"pathToOuputFile";
    var outputFileStream = File.OpenWrite(svrlOutputPath);
    Serializer serializer = processor.NewSerializer(outputFileStream);
    transformer.ApplyTemplates(input, serializer);
    outputFileStream.Close();

    // 加载SVRL输出文件并检查失败断言
    XdmNode svrlDoc = processor.NewDocumentBuilder().Build(new Uri(svrlOutputPath));
    XPathCompiler xpathCompiler = processor.NewXPathCompiler();
    xpathCompiler.DeclareNamespace("svrl", "http://purl.oclc.org/dsdl/svrl");
    XPathSelector failedAssertSelector = xpathCompiler.Compile("//svrl:failed-assert").Load();
    failedAssertSelector.ContextItem = svrlDoc;

    // 如果存在失败断言,返回true(表示校验不通过)
    return failedAssertSelector.MoveNext();
}

方案二:修改Schematron编译后的XSLT,让失败断言触发错误

如果你希望把Schematron的失败断言当成Saxon的错误来捕获,可以修改Schematron生成的XSLT模板,让它在生成failed-assert的同时抛出错误。比如找到生成svrl:failed-assert的模板,添加saxon:error函数(需要引入Saxon命名空间):

<xsl:template match="..." mode="schematron-failed-assert">
    <!-- 原有的生成failed-assert的代码 -->
    <svrl:failed-assert ...>
        ...
    </svrl:failed-assert>
    <!-- 添加这行,抛出错误 -->
    <saxon:error message="{svrl:text}" terminate="no"/>
</xsl:template>

这样一来,每次生成failed-assert时,Saxon就会触发ErrorReporter,你的transformerErrorList就能捕获到对应的错误信息了。不过这种方式需要你能修改Schematron编译后的XSLT,或者自定义Schematron的编译规则。

总结

回到你的问题:你的代码本身没毛病,只是对Saxon的错误机制和Schematron的工作逻辑理解有偏差。最推荐用方案一,因为它更符合Schematron的原生设计,也不需要修改原有XSLT代码。

备注:内容来源于stack exchange,提问作者GrowNarko

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.23 08:44:10