UBL XML的Schematron验证:ISO XSL与SVRL XSL选型及实现咨询
针对Schematron转XSL后验证XML的解决方案
首先,先帮你理清ISO XSL和SVRL XSL的区别,再结合你的代码给出具体调整建议:
一、ISO Schematron XSL vs SVRL XSL
- ISO Schematron XSL:是直接把Schematron规则转换成通用XSLT,运行时会直接对XML进行验证并抛出错误(或自定义处理逻辑),不会生成标准化的验证报告。
- SVRL XSL:转换后的XSL会生成符合Schematron Validation Report Language规范的XML报告,报告里包含
<svrl:failed-assert>、<svrl:text>这类标准化错误节点——这正是你的代码里在读取的内容,所以你现在用的应该是SVRL类型的XSL(Oxygen默认转换选项一般就是生成SVRL)。
二、你的代码问题与优化建议
1. 替换过时的API
XmlTextReader已被标记为过时,建议改用XmlReader.Create来避免潜在的兼容性问题。
2. 处理命名空间的ID查找
你代码里用document.GetElementsByTagName("cbc:ID")可能会因为命名空间前缀不匹配找不到元素,因为cbc只是前缀,实际XML里对应的命名空间URI才是关键。建议改用XPath查询来处理命名空间:
XmlNamespaceManager nsManager = new XmlNamespaceManager(document.NameTable); nsManager.AddNamespace("cbc", "http://你的cbc命名空间URI"); // 替换成XML中cbc前缀对应的实际URI XmlElement elementId = document.SelectSingleNode("//cbc:ID", nsManager) as XmlElement;
3. 优化验证流程
不需要把XmlDocument转成StringReader再用XmlTextReader加载,可以直接从XmlDocument构建Saxon输入节点,减少冗余转换。
调整后的完整代码示例
转换方法(优化版)
using Saxon.Api; using System.IO; using System.Xml; public static Stream Transform(XmlDocument xmlDoc) { try { var processor = new Processor(); // 直接从XmlDocument构建Saxon的XdmNode var docBuilder = processor.NewDocumentBuilder(); docBuilder.BaseUri = new Uri("file:///"); // 设置基础URI避免路径问题 var input = docBuilder.Build(xmlDoc); var compiler = processor.NewXsltCompiler(); // 用XmlReader.Create替换过时的XmlTextReader using var xslReader = XmlReader.Create(@"C:\Tools\Schematron\Schematron.xsl"); var transformer = compiler.Compile(xslReader).Load(); transformer.InitialContextNode = input; var resultStream = new MemoryStream(); var serializer = processor.NewSerializer(resultStream); transformer.Run(serializer); resultStream.Position = 0; return resultStream; } catch (Exception ex) { // 添加详细错误信息方便调试 throw new InvalidOperationException("XSLT转换失败", ex); } }
验证方法(优化版)
using System.Collections.Generic; using System.Linq; using System.Xml; public class ValidationResult { public List<string> ErrorMessageList { get; set; } = new List<string>(); public bool IsValid { get; set; } } public static ValidationResult SchematronValidateXml(List<XmlDocument> xmlList) { var result = new ValidationResult(); // 提前定义命名空间管理器,避免重复创建 XmlNamespaceManager nsManager = new XmlNamespaceManager(new NameTable()); nsManager.AddNamespace("cbc", "http://你的cbc命名空间URI"); // 替换为实际URI nsManager.AddNamespace("svrl", "http://purl.oclc.org/dsdl/svrl"); // SVRL标准命名空间 foreach (var document in xmlList) { using var resultStream = Transform(document); using var xmlReader = XmlReader.Create(resultStream); // 加载SVRL报告文档,用XPath批量查询错误 XmlDocument svrlReport = new XmlDocument(); svrlReport.Load(xmlReader); var errorNodes = svrlReport.SelectNodes("//svrl:text", nsManager); if (errorNodes != null && errorNodes.Count > 0) { // 获取当前XML的ID string id = "无ID"; XmlElement elementId = document.SelectSingleNode("//cbc:ID", nsManager) as XmlElement; if (elementId != null) id = elementId.InnerText; foreach (XmlNode errorNode in errorNodes) { result.ErrorMessageList.Add($"Schematron ({id}) : {errorNode.InnerText}"); } } } result.IsValid = !result.ErrorMessageList.Any(); return result; }
三、后续操作步骤
- 确认XSL类型:打开Oxygen的Schematron转换设置,确保选择的是"Generate SVRL"(或类似选项),这样转换后的XSL才会输出你代码依赖的SVRL格式报告。
- 替换命名空间URI:把代码里的
http://你的cbc命名空间URI替换成你XML中cbc前缀对应的实际命名空间(可查看XML根元素的xmlns:cbc属性值)。 - 测试验证逻辑:分别用合格和不合格的XML测试,检查
ErrorMessageList是否正确捕获错误,IsValid是否准确反映验证结果。 - 增强错误处理:建议添加日志记录,方便调试转换或验证过程中出现的异常。
内容的提问来源于stack exchange,提问作者Tester3
相关产品推荐
相关产品推荐

