使用XRechnung Visualizer和.NET的Saxon-HE自动关闭DIV标签的问题

问题描述

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

转换代码如下:

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(或XHTML)而不是XML。

您当前正在将结果发送到内存树中,然后使用OuterXML属性对其进行序列化,该属性将为您提供XML序列化。

相反,将输出发送到序列化器,然后使用样式表中的<xsl:output>或通过在Serializer对象上设置属性来选择序列化方法HTML。

,

如果让Saxon通过不使用XdmDestination而不是通过使用Serializer直接写入文件或流或字符串编写器来进行序列化,那么我相信它遵循HTML序列化规则。在XML和XSLT的上下文中,我建议让XML解析器和XSLT处理器尽可能多地处理输入解析和输出序列化,而不是从文件中读取字符串或使用File 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>

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...