XRechnung Visualizer 和 Saxon-HE for .NET 的自闭合 DIV 标签存在问题

问题描述 投票:0回答:4

我想通过使用 itplr-kosit 的 xrechnung-visualization 来使用 .NET/C# 实现 XRechnung 可视化工具,将 XRechnung 转换为 HTML。作为处理器,我使用 Saxonica 的 Saxon-HE。现在,我正在努力以自动关闭 DIV 的形式输出无效的 HTML。

转换代码如下:

public static string TransformXml(string xmlData, string xslData)
{
    var xsltProcessor = new Saxon.Api.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 Saxon.Api.XdmDestination();
    xsltTransformer.Run(results);

    return results.XdmNode.OuterXml;
}

    

来电:

var xmlData = File.ReadAllText(Path.Combine(Directory.GetCurrentDirectory(), "xrechnung.xml"));
var xslDataToXR = File.ReadAllText(Path.Combine(Directory.GetCurrentDirectory(), "cii-xr.xsl"));
var xslDataToHTML = File.ReadAllText(Path.Combine(Directory.GetCurrentDirectory(), "xrechnung-html.xsl"));

var xrXMLData = TransformXml(xmlData, xslDataToXR);
var htmlData = TransformXml(xrXMLData, xslDataToHTML);

File.WriteAllText(Path.Combine(Directory.GetCurrentDirectory(), "result.html"), htmlData);

有效...解决问题,在生成的 HTML 中,所有未填充的字段都转换为 自闭合 DIV 标签

例如,以下片段来自

xrechnung-html.xsl
...

<div class="boxzeile">
  <div class="boxdaten legende">Postfach:</div>
  <div id="BT-51" title="BT-51" class="boxdaten wert"><xsl:value-of select="xr:BUYER_POSTAL_ADDRESS/xr:Buyer_address_line_2"/></div>
</div>

...将呈现为以下 HTML,因为 xml 没有提供

Buyer_address_line_2
:

的值
<div class="boxzeile">
  <div class="boxdaten legende">Postfach:</div>
  <div id="BT-51" title="BT-51" class="boxdaten wert"/>
</div>

浏览器将自关闭 DIV 解释为开放标签,完整视图被破坏。

有什么想法吗?

html xslt transform saxon
4个回答
1
投票

确保将结果序列化为 HTML(或 XHTML)而不是 XML。

您当前正在将结果发送到内存中的树,然后使用

OuterXML
属性对其进行序列化,这为您提供了 XML 序列化。

相反,将输出发送到序列化器,然后使用样式表中的

<xsl:output>
或通过设置
Serializer
对象的属性来选择序列化方法 HTML。


0
投票

如果您让 Saxon 不使用 XdmDestination 而是使用 Serializer 直接写入文件或流或字符串编写器来进行序列化,那么我确信它遵循 HTML 序列化规则。在 XML 和 XSLT 的上下文中,我建议让 XML 解析器和 XSLT 处理器尽可能地处理输入解析和输出序列化,而不是使用文件 API 从文件中读取字符串或将字符串写入文件。

因为你似乎想链接两个转换,我想使用

  var xslt1 = xsltExecutable1.Load30();
  var xslt2 = xsltExecutable2.Load30();
  
  using (var inputStream  = File.OpenRead(Path.Combine(Directory.GetCurrentDirectory(), "xrechnung.xml")) {
    using (var resultStream = File.OpenWrite(Path.Combine(Directory.GetCurrentDirectory(), "result.html") {
      xslt1.Transform(inputStream , xslt2.AsDocumentDestination(xslt2.NewSerializer(resultStream)));
    }
  }

是一个可行的方法。

当然,也可以直接在 XSLT 3 中更改两个样式表:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="#all"
    version="3.0">

  <xsl:param name="step1-uri" as="xs:string">https://github.com/itplr-kosit/xrechnung-visualization/raw/master/src/xsl/ubl-invoice-xr.xsl</xsl:param>
  <xsl:param name="step2-uri" as="xs:string">https://github.com/itplr-kosit/xrechnung-visualization/raw/master/src/xsl/xrechnung-html.xsl</xsl:param>

  <xsl:output method="html" indent="yes" html-version="5"/>

  <xsl:template match="/">
      <xsl:sequence
         select="transform(map {
                   'source-node' : .,
                   'stylesheet-location' : $step1-uri
                 })?output ! transform(map { 
                               'source-node' : ., 
                               'stylesheet-location' : $step2-uri 
                             })?output"/>
  </xsl:template>
  
</xsl:stylesheet>

一般来说,可以使用

fold-left
链接一系列样式表:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="#all"
    version="3.0">

  <xsl:param name="step1-uri" as="xs:string">https://github.com/itplr-kosit/xrechnung-visualization/raw/master/src/xsl/ubl-invoice-xr.xsl</xsl:param>
  <xsl:param name="step2-uri" as="xs:string">https://github.com/itplr-kosit/xrechnung-visualization/raw/master/src/xsl/xrechnung-html.xsl</xsl:param>

  <xsl:param name="xslt-locations" as="xs:string*" select="$step1-uri, $step2-uri"/>

  <xsl:output method="html" indent="yes" html-version="5"/>

  <xsl:template match="/">
      <xsl:sequence
         select="fold-left(
                   $xslt-locations,
                   .,
                   function($doc, $xslt-location) { 
                     transform(map { 'source-node' : $doc, 'stylesheet-location' : $xslt-location })?output
                   }
                )"/>
  </xsl:template>
  
</xsl:stylesheet>

0
投票

感谢马丁的回答。我能弄清楚。这是一个完整的功能。

public static string XmlToHtmlWithSaxon(byte[] xmlData, byte[] xslData)
{
    Processor processor = new Processor();
    XsltCompiler xsltCompiler = processor.NewXsltCompiler();
    XmlReaderSettings readerSettings = new XmlReaderSettings();
    readerSettings.DtdProcessing = DtdProcessing.Parse;
    string htmlResult = null;
    using (MemoryStream msXslt = new MemoryStream(xslData))
    {
         using (XmlReader reader = XmlReader.Create(msXslt, readerSettings))
         {
             xsltCompiler.BaseUri = new Uri("file://");
             XsltExecutable xsltExecutable = xsltCompiler.Compile(reader);
             var xsltTransformer = xsltExecutable.Load30();
             using (MemoryStream inputStream = new MemoryStream(xmlData))
             {
                 using (MemoryStream outputStream = new MemoryStream())
                 {
                     xsltTransformer.Transform(inputStream, processor.NewSerializer(outputStream));
                     htmlResult = System.Text.Encoding.UTF8.GetString(outputStream.ToArray());
                  }
             }
         }
      }
     return htmlResult;
}

0
投票

@Kristof 你能生成 PDF 吗? 如果是的话你能告诉我怎么做吗?

© www.soinside.com 2019 - 2024. All rights reserved.