Schxslt与SaxonCS编译Schematron时base-uri()返回空值问题
问题描述
我有一份XML文件和对应的.sch校验文件,校验规则中包含<xsl:param name="dosyaAdi" select="base-uri()"/>,但base-uri()函数返回空值,导致依赖该函数的校验规则全部失效。
我已通过Schxslt的compile-for-svrl.xsl编译.sch文件,再将XML与生成的XSLT传入Saxon进行转换,转换过程正常,但推测Sch中的base-uri()返回空值,致使2条相关校验规则失败。代码示例如下:
string schxsltSvrlXsltResource = @"SchematronSchxsltSaxonCSValidator/schxslt195/compile-for-svrl.xsl"; var schxsltResourceUri = UriUtils.GetLocationUri(schxsltSvrlXsltResource, Assembly.GetExecutingAssembly()); var resolver = new Resolver(); var settings = new XmlReaderSettings() { XmlResolver = resolver }; var processor = new Processor(true); var xsltCompiler = processor.NewXsltCompiler(); using var schxsltReader = XmlReader.Create(schxsltResourceUri.AbsoluteUri, settings); var transformer = xsltCompiler.Compile(schxsltReader).Load30(); //var compiledSchxslt = xsltCompiler.Compile(schxsltReader).Load30(); var compiledSchematron = new XdmDestination(); compiledSchematron.BaseUri = new Uri(new FileInfo(inputSch).FullName); using var schemaStream = File.OpenRead(inputSch); transformer.Transform(schemaStream, compiledSchematron); var xsltCompiler2 = processor.NewXsltCompiler(); var schematronValidator = xsltCompiler2.Compile(compiledSchematron.XdmNode).Load30(); var svrlResult = new XdmDestination(); using var instanceStream = File.OpenRead(inputXml); //schematronValidator.Run(svrlResult); schematronValidator.Transform(instanceStream, svrlResult); XmlDocument doc = new XmlDocument(); doc.LoadXml(svrlResult.XdmNode.OuterXml); var failedNodes = doc.GetElementsByTagName("svrl:failed-assert"); foreach (System.Xml.XmlNode node in failedNodes) { }
解决方案
原因分析
使用File.OpenRead读取文件流时,Saxon无法获取文件的Base URI元数据,导致base-uri()函数返回空值。无论是编译.sch还是校验XML阶段,仅传递流都会丢失文件的原始路径信息。
修复方案
方案1:传递文件URI而非流
直接基于文件URI创建节点,保留完整的Base URI信息:
- 编译.sch文件时:
// 替换原schemaStream相关代码 var schUri = new Uri(new FileInfo(inputSch).FullName); transformer.Transform(new UriXdmNode(processor, schUri), compiledSchematron); - 校验XML文件时:
// 替换原instanceStream相关代码 var xmlUri = new Uri(new FileInfo(inputXml).FullName); schematronValidator.Transform(new UriXdmNode(processor, xmlUri), svrlResult);
方案2:手动传递参数
如果必须使用流,可以直接向校验XSLT传递dosyaAdi参数,绕过base-uri()函数:
// 在调用Transform前添加参数设置 schematronValidator.SetParameter(new QName("", "", "dosyaAdi"), new XdmAtomicValue(new FileInfo(inputXml).FullName));
关键提示
base-uri()的返回值完全依赖节点是否携带URI信息,流模式读取会丢失该元数据。- 使用
UriXdmNode是最贴合Schxslt设计的解决方案,能完整保留文件的URI上下文。 - 手动传参适合无法直接获取文件URI的场景,比如处理内存中的XML内容。
内容的提问来源于stack exchange,提问作者Cemal Çelik
相关产品推荐
相关产品推荐

