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

7
我正在使用 Saxon 9.4 Home Edition (Saxon-HE 9.4 .NET) 来支持在 .NET 中使用 XSLT 2.0,XPath 2.0 和 XQuery 1.0 技术。当我加载没有 URI 的文件时,我的代码会崩溃。
以下是需要翻译的问题:
  1. 是否可以加载没有与所加载文档相关的 URI 的 xml/xsl 文档?
  2. 如果不行,是否有任何方法来为嵌入到 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,但这会抛出异常'This operation is not supported for a relative 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;
        }
    }
}
2个回答

5

我认为你可以在Saxon中使用流加载,但是你需要先设置一个基本URI,以便加载任何引用资源(比如XML文档中的DTD或者包含或导入的样式表模块)。如果你确定没有这个需求,可以尝试以下操作:

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

XdmNode input = db.Build(xsltStream);

如果您需要在XSLT中解析相对URI,这些URI也将作为嵌入式资源加载,那么需要更多的工作:您需要设置XmlResolver为一个支持从嵌入式资源加载资源的类,并使用XSLT中的URI方案来指示解析器需要从资源加载。我认为.NET框架没有提供这种类型的XmlResolver,Uri类也不支持自定义模式。


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

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;
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接