Saxon 中的 BaseUri 在尝试编译 xslt 内容时导致问题

Posted

技术标签:

【中文标题】Saxon 中的 BaseUri 在尝试编译 xslt 内容时导致问题【英文标题】:BaseUri in Saxon causing problems when trying to compile xslt content 【发布时间】:2020-02-08 02:29:57 【问题描述】:

这是我的代码:

static void Main(string[] args)

    string xml = File.ReadAllText("C:/Users/Davíð/source/Saxon/Saxon/data.xml");
    string xslt = File.ReadAllText("C:/Users/Davíð/source/Saxon/Saxon/dataXslt.xsl");
    string xmlCopy = File.ReadAllText("C:/Users/Davíð/source/Saxon/Saxon/data.xml");

    TransformData(xml, xmlCopy, xslt);


static public void TransformData(string data, string xmlCopy, string xslt)

    // Create a Processor instance.
    Processor processor = new Processor();

    // Create a compiled stylesheet
    processor.NewXsltCompiler().BaseUri = new Uri("C:/Users/Davíð/source/Saxon/Saxon");
    XsltExecutable templates = processor.NewXsltCompiler().Compile(new XmlTextReader(new StringReader(xslt)));

    // Note: we could actually use the same Xslt30Transformer in this case.
    // But in principle, the two transformations could be done in parallel in separate threads.

    // Do the first transformation
    Console.WriteLine("\n\n----- transform of " + data + " -----");
    Xslt30Transformer transformer1 = templates.Load30();
    XdmNode input1 = processor.NewDocumentBuilder().Build(new XmlTextReader(new StringReader(data)));
    transformer1.ApplyTemplates(input1, processor.NewSerializer(Console.Out));     // default destination is Console.Out

    // Do the second transformation
    Console.WriteLine("\n\n----- transform of " + xmlCopy + " -----");
    Xslt30Transformer transformer2 = templates.Load30();
    XdmNode input2 = processor.NewDocumentBuilder().Build(new XmlTextReader(new StringReader(xmlCopy)));
    transformer2.ApplyTemplates(input2, processor.NewSerializer(Console.Out));     // default destination is Console.Out

无论我是否删除 BaseUri,这都是我不断收到的错误。

未处理的异常:System.ArgumentNullException:值不能为空。 参数名称:BaseUri 在 Saxon.Api.XsltCompiler.Compile(XmlReader 阅读器) 在 C:\Users\Davíð\source\Saxon\Saxon\Program.cs:line 33 中的 Saxon.Program.TransformData(String data, String xmlCopy, String xslt) 在 C:\Users\Davíð\source\Saxon\Saxon\Program.cs:line 22 中的 Saxon.Program.Main(String[] args) 处


基于 cmets,固定 & 工作代码如下:

static void Main(string[] args)


    string xml = File.ReadAllText("C:/Users/Davíð/source/Saxon/Saxon/data.xml");
    string xslt = File.ReadAllText("C:/Users/Davíð/source/Saxon/Saxon/dataXslt.xsl");

    TransformData(xml, xml, xslt);


static public void TransformData(string data, string xmlCopy, string xslt)

    // Create a Processor instance.
    Processor processor = new Processor();

    // Create a compiled stylesheet
    var compiler = processor.NewXsltCompiler();
    compiler.BaseUri = new Uri("C:/Users/Davíð/source/Saxon/Saxon");
    XsltExecutable templates = compiler.Compile(XmlReader.Create(new StringReader(xslt)));

    // Note: we could actually use the same Xslt30Transformer in this case.
    // But in principle, the two transformations could be done in parallel in separate threads.

    // Do the first transformation
    Console.WriteLine("\n\n----- transform of " + data + " -----");
    Xslt30Transformer transformer1 = templates.Load30();
    XdmNode input1 = processor.NewDocumentBuilder().Build(XmlReader.Create(new StringReader(data)));
    transformer1.ApplyTemplates(input1, processor.NewSerializer(Console.Out));     // default destination is Console.Out

    // Do the second transformation
    Console.WriteLine("\n\n----- transform of " + xmlCopy + " -----");
    Xslt30Transformer transformer2 = templates.Load30();
    XdmNode input2 = processor.NewDocumentBuilder().Build(new XmlTextReader(new StringReader(xmlCopy)));
    transformer2.ApplyTemplates(input2, processor.NewSerializer(Console.Out));     // default destination is Console.Out

【问题讨论】:

您能否编辑您的问题并提供您正在使用的 Saxon 的确切版本和版本?堆栈跟踪也会有所帮助。您是否真的需要像您的代码那样将 XML 解析为 .NET 字符串?与使用 ReadAllText 相比,使用文档构建器从文件/URI 简单地构建应该更容易和更好地处理不同的编码。 不知道这是否会导致您的问题,但XmlTextReader has been deprecated since .Net 2.0 over 10 years ago。相反,请使用XmlReader.Create(TextReader)。另外,请务必在事后处理掉它。 另外,请edit 您的问题包括以下内容:1) 异常的完整ToString() 输出,包括异常类型、消息、回溯和内部异常,如果任何。 2) minimal reproducible example 显示重现问题的最小示例 XML 和 XSL 文件?如果我们可以重现您的问题,我们更有可能解决您的问题。请参阅:How to Ask、tour 和 codeblog.jonskeet.uk/2010/08/29/writing-the-perfect-question processor.NewXsltCompiler() 每次调用都会返回一个新的XsltCompiler。你称之为两次:你在第一个上设置BaseUri,然后创建另一个来做你处理。你试过var compiler = processor.NewXsltCompiler(); compiler.BaseUri = new Uri("C:/Users/Davíð/source/Saxon/Saxon"); var templates = compiler.Compile( /* Remainder as before ... 吗? 顺便说一下,.Net 中的字符串是不可变的,因此没有理由像使用 @ 那样通过读取文件 两次 来深度克隆字符串987654338@. 【参考方案1】:

你有几个问题:

processor.NewXsltCompiler() 每次调用都会返回一个新的XsltCompiler。你称它两次

processor.NewXsltCompiler().BaseUri = new Uri("C:/Users/Davíð/source/Saxon/Saxon");
XsltExecutable templates = processor.NewXsltCompiler().Compile(new XmlTextReader(new StringReader(xslt)));

代码在第一个设置BaseUri,然后创建另一个进行编译。因此,BaseUri 永远不会设置在实际用于工作的 XsltCompiler 上。

这是异常的直接原因未处理的异常:System.ArgumentNullException:值不能为空。参数名称:BaseUri at Saxon.Api.XsltCompiler.Compile(XmlReader reader)

您应该只创建一个XsltCompiler

您使用的是 XmlTextReader,但 XmlTextReader has been deprecated since .Net 2.0 是 10 多年前的事了。相反,请使用XmlReader.Create(TextReader)。此外,请务必在之后处理它。

您将文件data.xml 内容的两个副本加载到内存中,分别加载到字符串xmlxmlCopy 中。但是 .Net 中的字符串是不可变的,所以没有必要这样做。

因此您的代码应如下所示:

public static void Main(string[] args)

    string xml = File.ReadAllText("C:/Users/Davíð/source/Saxon/Saxon/data.xml");
    string xslt = File.ReadAllText("C:/Users/Davíð/source/Saxon/Saxon/dataXslt.xsl");

    TransformData(xml, xml, xslt);


static public void TransformData(string xml1, string xml2, string xslt)

    // Create a Processor instance.
    var processor = new Processor();

    // Create a compiled stylesheet
    var compiler = processor.NewXsltCompiler();
    compiler.BaseUri = new Uri("C:/Users/Davíð/source/Saxon/Saxon");
    XsltExecutable templates;
    using (var reader = XmlReader.Create(new StringReader(xslt)))
        templates = compiler.Compile(reader);

    // Note: we could actually use the same Xslt30Transformer in this case.
    // But in principle, the two transformations could be done in parallel in separate threads.

    // Do the first transformation
    Console.WriteLine("\n\n----- transform of " + xml1 + " -----");
    TransformData(processor, templates, xml1, Console.Out);

    // Do the second transformation
    Console.WriteLine("\n\n----- transform of " + xml2 + " -----");
    TransformData(processor, templates, xml2, Console.Out);


private static void TransformData(Processor processor, XsltExecutable templates, string xml, TextWriter output)

    var transformer = templates.Load30();
    using (var reader = XmlReader.Create(new StringReader(xml)))
    
        var input = processor.NewDocumentBuilder().Build(reader);
        transformer.ApplyTemplates(input, processor.NewSerializer(output));
    

【讨论】:

以上是关于Saxon 中的 BaseUri 在尝试编译 xslt 内容时导致问题的主要内容,如果未能解决你的问题,请参考以下文章

Saxon-HE Java 扩展函数(问题配置)

编译样式表时的未知函数 saxon:parse-html

Saxon XSLT 2.0 和 RFC 822 日期格式

RAML中的多个baseUri?

Saxon 转换因 java.lang.OutOfMemoryError 失败:Java 堆空间错误

Saxon HE - XSLT 转换 - 尝试运行命令行代码时出错