从 Saxon 9.4he 中的嵌入式资源加载 xml 和 xslt

Posted

技术标签:

【中文标题】从 Saxon 9.4he 中的嵌入式资源加载 xml 和 xslt【英文标题】:Load xml and xslt from embedded resource in Saxon 9.4he 【发布时间】:2013-04-12 15:29:54 【问题描述】:

我正在使用 Saxon 9.4 家庭版 (Saxon-HE 9.4 .NET) 来获得对 XSLT 2.0 和 XPath 2.0 以及 .NET 中的 XQuery 1.0 的支持。当我加载没有 URI 的文件时,我的代码崩溃了。

    是否可以在没有与所加载文档相关的 URI 的情况下加载 xml/xsl 文档? 如果没有,有没有办法为嵌入在 dll 文件中的元素定义 URI?

任何其他解决方案也将不胜感激,我唯一的说法是文件必须从 dll 文件中加载。

只要我从文件中加载 xml/xsl,我的代码就可以完美运行:

const string sourcePath = @"C:\test\TestInvoiceWithError.xml";
const string xsltpath = @"C:\test\UBL-T10-BiiRules.xsl";

当我尝试从嵌入式资源加载时,代码会抛出异常声明'未提供基本 URI'

Stream sourceStream = GetEmbeddedResource("TestProject1.testfiles.TestInvoice.xml");
Stream xsltStream = GetEmbeddedResource("TestProject1.testfiles.UBL-T10-BiiRules.xsl");

我还为具有引发异常的相对路径的资源创建了 Uri。'相对 URI 不支持此操作。'

Uri sourceUri = new Uri("/TestProject1;component/testfiles/TestInvoice.xml",     UriKind.Relative);
Uri xsltUri = new Uri("/TestProject1;component/testfiles/UBL-T10-BiiRules.xsl.xml", UriKind.Relative);

这是我的代码:

using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text;
using System.Xml;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Saxon.Api;


namespace TestProject1

    [TestClass]
    public class XsltTest
    
        [TestMethod]
        public void SaxonTest()
        
            Stream sourceStream = GetEmbeddedResource("TestProject1.testfiles.TestInvoice.xml");
            Stream xsltStream = GetEmbeddedResource("TestProject1.testfiles.UBL-T10-BiiRules.xsl");

            Uri sourceUri = new Uri("/TestProject1;component/testfiles/TestInvoice.xml", UriKind.Relative);
            Uri xsltUri = new Uri("/TestProject1;component/testfiles/UBL-T10-BiiRules.xsl.xml", UriKind.Relative);

            const string sourcePath = @"C:\test\TestInvoiceWithError.xml";
            const string xsltpath = @"C:\test\UBL-T10-BiiRules.xsl";

            Processor processor = new Processor();
            XdmNode input = processor.NewDocumentBuilder().Build(new Uri(sourcePath));

            XsltTransformer transformer = processor.NewXsltCompiler().Compile(new Uri(xsltpath)).Load();

            transformer.InitialContextNode = input;

            Serializer serializer = new Serializer();
            StringBuilder sb = new StringBuilder();
            TextWriter writer = new StringWriter(sb);
            serializer.SetOutputWriter(writer);

            transformer.Run(serializer);

            XmlDocument xmlDocOut = new XmlDocument();
            xmlDocOut.LoadXml(sb.ToString());
            XmlNodeList failedAsserts = xmlDocOut.SelectNodes("/svrl:schematron-output/svrl:failed-assert",XmlInvoiceNamespaceManager());

            if (failedAsserts == null)
                return;

            foreach (XmlNode failedAssert in failedAsserts)
            
                if (failedAssert.Attributes == null)
                    continue;

                XmlAttribute typeOfError = failedAssert.Attributes["flag"];

                if (typeOfError.Value.Equals("warning"))
                /*Log something*/
                else if (typeOfError.Value.Equals("fatal"))
                /*Log something*/
            
        

        private XmlNamespaceManager XmlInvoiceNamespaceManager()
        
            IDictionary<string, string> list = new Dictionary<string, string>
                                                   
                                                       "xml", "http://www.w3.org/XML/1998/namespace",
                                                       "xsi", "http://www.w3.org/2001/XMLSchema-instance",
                                                       "xsd", "http://www.w3.org/2001/XMLSchema",
                                                       "udt","urn:un:unece:uncefact:data:specification:UnqualifiedDataTypesSchemaModule:2",
                                                       "qdt","urn:oasis:names:specification:ubl:schema:xsd:QualifiedDatatypes-2",
                                                       "ext","urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2",
                                                       "ccts", "urn:un:unece:uncefact:documentation:2",
                                                       "cbc","urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2",
                                                       "cac","urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2",
                                                       "inv", "urn:oasis:names:specification:ubl:schema:xsd:Invoice-2",
                                                       "svrl", "http://purl.oclc.org/dsdl/svrl"
                                                   ;

            XmlNameTable xmlNameTable = new NameTable();

            XmlNamespaceManager xmlInvoiceNamespaceManager = new XmlNamespaceManager(xmlNameTable);

            foreach (KeyValuePair<string, string> ns in list)
            
                xmlInvoiceNamespaceManager.AddNamespace(ns.Key, ns.Value);
            
            return xmlInvoiceNamespaceManager;
        

        protected static Stream GetEmbeddedResource(string path)
        
            Assembly asm = Assembly.GetExecutingAssembly();
            Stream stream = asm.GetManifestResourceStream(path);
            return stream;
        
    

【问题讨论】:

【参考方案1】:

最近,我遇到了这个问题。这是我的解决方案。

private void test() 
        Stream xsltStream = GetEmbeddedResource("TestSaxon.Resources.test.xsl");

        Processor processor = new Processor();

        DocumentBuilder db = processor.NewDocumentBuilder();
        XmlDocument xmlDocument = new XmlDocument();
        xmlDocument.Load(xsltStream);

        XdmNode xdmNode = db.Build(xmlDocument);

        XsltTransformer transformer = processor.NewXsltCompiler().Compile(xdmNode).Load();
        var path = AppDomain.CurrentDomain.BaseDirectory;
        var input = new FileInfo(path + @"\input.xml");
        var output = new FileInfo(path + @"\result.xml");
        var destination = new DomDestination();
        using (var inputStream = input.OpenRead())
        
            transformer.SetInputStream(inputStream, new Uri(input.DirectoryName));
            transformer.Run(destination);
        
        destination.XmlDocument.Save(output.FullName);
    

    protected static Stream GetEmbeddedResource(string path)
    
        Assembly asm = Assembly.GetExecutingAssembly();
        Stream stream = asm.GetManifestResourceStream(path);
        return stream;
    

【讨论】:

【参考方案2】:

我认为您可以使用 Saxon 从流中加载,但您需要先设置一个基本 URI,以允许加载任何引用资源(例如 XML 文档中的 DTD 或包含或导入的样式表模块)。如果您确定没有,那么只需尝试例如

DocumentBuilder db = processor.NewDocumentBuilder();
db.BaseUri = new Uri("file:///C:/");

XdmNode input = db.Build(xsltStream);

显然,如果您需要解析 XSLT 中也将作为嵌入式资源加载的相对 URI,则需要做更多工作:您需要将 XmlResolver 设置为支持从嵌入式资源加载资源的类,与 XSLT 中的 URI 方案一起向解析器指示您需要从资源加载。我不认为 .NET 框架提供了这样一种 XmlResolver 并且 Uri 类也不支持自定义架构。

【讨论】:

谢谢!没有意识到 BaseUri 指的是参考资源而不是实际文档。 我们尝试编写代码,以便没有基本 URI 只会在某些实际需要基本 URI 时引起问题。但令人惊讶的是它确实用于了多少事情,因此最好设置一个,并且最好使其成为有效的绝对 URI。如果您想不出任何明智的设置,请在错误消息中使用可识别的内容,例如文件:/invented.base.uri/ 对我来说使用 new Uri("file://") 似乎就足够了。还是有人对此有问题? 不要忘记将流的位置设置为0。

以上是关于从 Saxon 9.4he 中的嵌入式资源加载 xml 和 xslt的主要内容,如果未能解决你的问题,请参考以下文章

如何从命令行运行 Saxon

XSLT 函数返回不同的结果 [Saxon-EE vs Saxon-HE/PE]

Saxon-HE 集成扩展功能 |如何以及在哪里?

如何在 Saxon-HE 中获得 EXSLT 支持?

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

如何在 .NET 中使用 Saxon-HE 9.8 使用 XSLT 3.0