在C#中使用XSL文件进行Schematron XML验证报错求助
首先,咱们拆解你遇到的两个核心问题:一是validator.Validate(xmlStream)报错的原因,二是微软文档为何侧重XSD而非Schematron的疑问。
一、分析“Operation is not allowed”错误的可能原因
你用的第三方Schematron库出现这个报错,大概率是以下两个细节没处理到位:
- 内存流位置未重置:当你把字符串转成
MemoryStream后,流的指针默认停在末尾,库加载时会读不到任何内容。 - 输入的XSL文件类型不对:有些Schematron库要求输入的是编译后的XSLT文件(由原始
.schSchematron schema转换而来),而不是直接用.sch源文件。
修复现有代码的小调整
先试试给内存流加上位置重置,修改你的代码:
public static bool SchemaTronValidation(string xml, string xsl) { // 创建XSL流并重置位置 var xslBytes = Encoding.UTF8.GetBytes(xsl ?? ""); var xslStream = new MemoryStream(xslBytes); xslStream.Position = 0; // 关键:重置流指针到开头 Schema schematronSchema = new Schema(); schematronSchema.Load(xslStream); Validator validator = new Validator(); validator.AddSchema(schematronSchema); // 创建XML流并重置位置 var xmlBytes = Encoding.UTF8.GetBytes(xml ?? ""); var xmlStream = new MemoryStream(xmlBytes); xmlStream.Position = 0; // 同样重置指针 var res = validator.Validate(xmlStream); return res.IsValid; // 注意:应该返回验证结果的IsValid,而非固定true }
如果还是报错,检查你的xsl参数是不是编译后的XSLT——如果是原始.sch文件,需要先把它转换成XSLT格式(后面会讲转换方法)。
二、微软文档为何用XSD而非Schematron?
这个疑问很合理:.NET原生完全支持XSD(XML Schema Definition),因为XSD是W3C标准的XML结构验证方案,适合校验元素、属性的类型、结构、必填性等基础规则。而Schematron是基于XSLT的规则型验证,可以实现更灵活的自定义逻辑(比如跨节点的关联校验),但.NET并没有原生提供Schematron的API,所以微软文档里主要讲解原生支持的XSD用法。
三、更可靠的C# Schematron实现方案:用XslCompiledTransform手动实现
第三方库可能存在版本兼容问题,用.NET自带的XslCompiledTransform实现Schematron验证反而更可控——本质上Schematron验证就是把.sch文件转换成XSLT,再用XSLT处理XML生成验证报告。
步骤1:编译Schematron Schema到XSLT
首先需要用ISO官方的Schematron骨架样式表(比如iso_schematron_skeleton_for_xslt1.xsl)把你的.sch文件转换成XSLT。你可以把这个骨架文件嵌入到项目中,然后用代码动态转换:
// 把Schematron(.sch)编译成XSLT public static string CompileSchematronToXslt(string schematronContent) { using var schematronStream = new MemoryStream(Encoding.UTF8.GetBytes(schematronContent)); var xsltTransform = new XslCompiledTransform(); // 加载ISO Schematron骨架样式表(确保文件路径正确) xsltTransform.Load("iso_schematron_skeleton_for_xslt1.xsl"); using var outputStream = new MemoryStream(); xsltTransform.Transform(schematronStream, null, outputStream); outputStream.Position = 0; using var reader = new StreamReader(outputStream); return reader.ReadToEnd(); }
步骤2:用XSLT执行验证并解析结果
拿到编译后的XSLT后,就可以用它处理XML,生成验证报告,然后解析报告判断是否验证通过:
// 定义Schematron结果的命名空间 private static readonly XNamespace SchematronNs = "http://purl.oclc.org/dsdl/schematron"; public static bool ValidateXmlWithSchematron(string xmlContent, string compiledXslt) { using var xmlStream = new MemoryStream(Encoding.UTF8.GetBytes(xmlContent)); using var xsltStream = new MemoryStream(Encoding.UTF8.GetBytes(compiledXslt)); var xsltTransform = new XslCompiledTransform(); xsltTransform.Load(xsltStream); using var resultStream = new MemoryStream(); xsltTransform.Transform(xmlStream, null, resultStream); resultStream.Position = 0; // 加载验证结果文档 var resultDoc = XDocument.Load(resultStream); // 检查是否有失败的断言或报告 var failedAsserts = resultDoc.Descendants(SchematronNs + "failed-assert"); var errorReports = resultDoc.Descendants(SchematronNs + "report"); // 没有失败项则验证通过 return !failedAsserts.Any() && !errorReports.Any(); }
使用示例
// 读取Schematron schema文件内容 var schematronContent = File.ReadAllText("your-schema.sch"); // 编译成XSLT var compiledXslt = CompileSchematronToXslt(schematronContent); // 读取要验证的XML var xmlContent = File.ReadAllText("your-document.xml"); // 执行验证 bool isValid = ValidateXmlWithSchematron(xmlContent, compiledXslt);
这种实现方式完全依赖.NET原生API,没有第三方库的兼容问题,可控性也更强。
内容的提问来源于stack exchange,提问作者Joseph

