How to use XSLT 3.0 using Saxon-HE 9.8 in .NET

拜拜、爱过 提交于 2021-01-27 07:04:03

问题


I'm using Win7 and set my VSC# project to .NETFramework4. Then download SaxonHE9-8-0-7N-setup.exe and install. Then reference saxon9he-api.dll to C# project and using Saxon.Api; And here's my program.cs:

static void Main(string[] args)
{
    var xslt = new FileInfo(Path.GetFullPath(Path.Combine(Environment.CurrentDirectory.ToString(), @"..\..\..")) + @"\TEST.xslt");
    var input = new FileInfo(Path.GetFullPath(Path.Combine(Environment.CurrentDirectory.ToString(), @"..\..\..")) + @"\TEST.xml");
    var output = new FileInfo(Path.GetFullPath(Path.Combine(Environment.CurrentDirectory.ToString(), @"..\..\..")) + @"\result.txt");

    var processor = new Processor();
    var compiler = processor.NewXsltCompiler();
    var executable = compiler.Compile(new Uri(xslt.FullName));
    var transformer = executable.Load();
    var serializer = new Serializer();

    FileStream outStream = new FileStream(output.ToString(), FileMode.Create, FileAccess.Write);
    serializer.SetOutputStream(outStream);

    using (var inputStream = input.OpenRead())
    {
        transformer.SetInputStream(inputStream, new Uri(Path.GetTempPath()));
        transformer.SetParameter(new QName("password"), new XdmAtomicValue("secret"));
        transformer.Run(serializer);
        outStream.Close();
    }
}

here's my TEST.xslt:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:math="http://www.w3.org/2005/xpath-functions/math"
    xmlns:map="http://www.w3.org/2005/xpath-functions/map"
    xmlns:array="http://www.w3.org/2005/xpath-functions/array"
    exclude-result-prefixes="xs math map array"
    version="3.0">

  <xsl:output method="json" indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:template match="root">
    <xsl:map>
      <xsl:map-entry key="local-name()">
        <xsl:apply-templates/>
      </xsl:map-entry>
    </xsl:map>
  </xsl:template>

  <xsl:template match="items">
    <xsl:variable name="items" as="item()*">
      <xsl:apply-templates/>
    </xsl:variable>
    <xsl:sequence select="map { local-name() : array { $items }}"/>
  </xsl:template>

  <xsl:template match="item">
    <xsl:sequence select="map { 'foo' : xs:integer(foo), 'bar' : string(bar) }"/>
  </xsl:template>

</xsl:stylesheet>

Before runing I receive two error message:

The element 'template' in namespace 'http://www.w3.org/1999/XSL/Transform' has invalid child element 'map'

and

The 'as' attribute is not declared.

When running I receive one error message:

Error in xsl:map-entry/@key TEST.xslt:FOTY0013: Cannot write a function item to an XML tree in built-in template rule for /root in the unnamed mode**

So what should I do to run this code without error?


回答1:


Change the line to create a Transformer to create an Xslt30Transformer

        var transformer = executable.Load30();

to use XSLT 3 and its various, different and more flexible input and output options and then to run the stylesheet use

        using (var inputStream = input.OpenRead())
        {
            transformer.ApplyTemplates(inputStream, serializer);
            outStream.Close();
        }

That way the XSLT code I posted earlier and you used as an example runs fine (I had to adapt the file paths but that obviously depends on how/where the files are in relation to the C# project).

Note that in general with XSLT 3 the initial match selection and the global context item to initialize global variables can be different, the sample stylesheet does not have any global variables or parameters, but if it had them you would also need to set the GlobalContextItem (https://www.saxonica.com/html/documentation/dotnetdoc/Saxon/Api/Xslt30Transformer.html#GlobalContextItem) to an XdmValue.

As for the various editor warnings or error messages you get when editing XSLT 3 in Visual Studio, well, simply installing an XSLT 3 processor on your system does not convert VS into an XSLT 3 editor, you will need to check whether/how you can set up Visual Studio to use the XSLT 3 schema, the XSLT 3 spec has one linked at https://www.w3.org/TR/xslt-30/schema-for-xslt30.xsd but I think it uses the schema language 1.1 while Microsoft only supports the schema language version 1.0 so it might be a bit difficult to find and install a schema for VS that makes it recognize and support XSLT 3 editing.




回答2:


Because I had problem with translating this solution to HE-9.9, here is my solution - with caveat that it works for 9.9 and not for 9.8:

using System;
using System.IO;
using Saxon.Api;

namespace Project1
{
    public static class ClassMain
    {
        public static string TransformXml(string xmlData, string xslData)
        {
            var xsltProcessor = new Processor();
            var documentBuilder = xsltProcessor.NewDocumentBuilder();
            documentBuilder.BaseUri = new Uri("file://");
            var xdmNode = documentBuilder.Build(new StringReader(xmlData));

            var xsltCompiler = xsltProcessor.NewXsltCompiler();
            var xsltExecutable = xsltCompiler.Compile(new StringReader(xslData));
            var xsltTransformer = xsltExecutable.Load();
            xsltTransformer.InitialContextNode = xdmNode;

            var results = new XdmDestination();

            xsltTransformer.Run(results);
            return results.XdmNode.OuterXml;
        }

        public static void Main()
        {
            var xmlData = File.ReadAllText("a.xml");
            var xslData = File.ReadAllText("a.xsl");

            var data = TransformXml(xmlData, xslData);
            Console.WriteLine(data);
            Console.ReadKey();
        }
    }
}



回答3:


for 9.9 use var serializer = processor.NewSerializer();



来源:https://stackoverflow.com/questions/48055282/how-to-use-xslt-3-0-using-saxon-he-9-8-in-net

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!