首页 > 解决方案 > 从导入的 .xsl 文件中显式调用命名模板

问题描述

我有以下情况:
我正在使用第 3 方 xsl 模板系统 ( kosit XRechnung ),它允许通过将您自己的 .xsl 文件指定为处理入口点来配置自定义适配。

这是过程:

+--------+                                         
|        |                                         
|        |                                         
|        |                                         
| in.xml |                                         
|        |                                         
+--------+                                         
    |                                              
    |                                              
    |                                              
    V                                              
+--------+                                         
|        |                                         
|        |  import   +--------+                    
| my.xsl | <-------- |        |                    
|        |           | adapt  |  import +---------+
|        |           |  .xsl  | <-------|         |
+--------+           |        |         | default |
    |                |        |         |  .xsl   |
   -|                +--------+         |         |
    |                                   |         |
    V                                   +---------+
+--------+                                         
|        |                                         
|        |                                         
|   out  |                                         
|  .xml  |                                         
|        |                                         
+--------+                                         

my.xsl是由我提供的一些 .xml 数据的处理入口点,它 adapt.xsl是一种改编,它提供了一个命名模板,该模板在某些时候调用,通过
default.xsl它做很多事情来创建最终的输出 XML 文档。

默认.xsl:

<!-- ... -->
        <xsl:when test="s:scenario">
          <rep:scenarioMatched>
            <xsl:apply-templates select="s:scenario" mode="copy" />
            <xsl:call-template name="documentData" />
            <xsl:sequence select="$validationStepResults" />
          </rep:scenarioMatched>
        </xsl:when>
<!-- ... -->

适应.xsl:

<!-- Overwritten (default.xsl) -->
<xsl:template name="documentData">
    <rep:documentData>
        <xsl:for-each select="
            $input-document/*/cac:AccountingSupplierParty/cac:Party/cac:PartyLegalEntity/cbc:RegistrationName, 
            $input-document/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeAgreement/ram:SellerTradeParty/ram:Name">
            <seller>
                <xsl:value-of select="."/>
            </seller>
        </xsl:for-each>
        
        <xsl:for-each select="
            $input-document/*/cbc:ID,
            $input-document/rsm:CrossIndustryInvoice/rsm:ExchangedDocument/ram:ID">
            <id>
                <xsl:value-of select="."/>
            </id>
        </xsl:for-each>
        
        <xsl:for-each select="$input-document/*/cbc:IssueDate,
            $input-document/rsm:CrossIndustryInvoice/rsm:ExchangedDocument/ram:IssueDateTime/udt:DateTimeString">
            <issueDate>
                <xsl:value-of select="."/>
            </issueDate>
        </xsl:for-each>
    </rep:documentData>
</xsl:template>

现在在我的顶级 .xsl 中,我可以再次覆盖在以下位置调用的命名模板default.xsl

我的.xsl:

<?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:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:rep="http://www.xoev.de/de/validator/varl/1"
    xmlns:s="http://www.xoev.de/de/validator/framework/1/scenarios" 
    xmlns:in="http://www.xoev.de/de/validator/framework/1/createreportinput"
    xmlns:svrl="http://purl.oclc.org/dsdl/svrl"
    xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl"
    xmlns:html="http://www.w3.org/1999/xhtml"
    xmlns:ubl="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"
    xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" 
    xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"
    xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100"
    xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100"
    xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100"
    xmlns:myns="urn:mycompany:xrechnung:data:enhancements"
    exclude-result-prefixes="xs"
    version="2.0">

    <xsl:import href="./adapt.xsl"/>

    <xsl:output method="xml" indent="yes"/>

    <!-- Overwritten (default.xsl) -->
    <xsl:template name="documentData">
        <rep:documentData>
            <myns:MyContainer>
                <myns:MyElement>
                   <!-- Enhanced stuff -->
                </myns:MyElement>
            </myns:MyContainer>
            <!-- xsl:call-template name="documentData"/-->
        </rep:documentData>
    </xsl:template>
</xsl:stylesheet>

问题是:

如何在adapt.xsl不复制documentData命名模板的 xsl 代码的情况下应用定义的内容(不更改default.xslor adapt.xsl)?

标签: xsltimportxslt-2.0saxon

解决方案


在 XSLT 3 包的上下文中,这是可能的,请参阅https://www.w3.org/TR/xslt-30/#re​​fer -to-overridden :

在作为 xsl:override 的子项出现的命名模板中,名称 xsl:original可能显示为 xsl:call-template 的 name 属性的值:例如,<xsl:call-template name="xsl:original"/>.

Saxon 9.8 及更高版本通过包支持 XSLT 3。

对于具体示例,我认为您需要使用第四个文件(例如adapt-package-wrapper.xsl),它是一个命名包导入,adapt.xsl例如

<xsl:package xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0"
    name="http://example.com/adapt1" package-version="1.0">
    
    <xsl:expose component="template" names="documentData" visibility="public"/>
    
    <xsl:import href="adapt.xsl"/>
    
</xsl:package>

然后my.xsl你需要声明覆盖:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0">
    
    <xsl:use-package name="http://example.com/adapt1" version="1.0">
        <xsl:override>
          <xsl:template name="documentData">
            <rep:documentData>
              <myns:MyContainer>
                <myns:MyElement>
                   <!-- Enhanced stuff -->
                </myns:MyElement>
              </myns:MyContainer>
              <!-- xsl:call-template name="documentData"/-->
              <xsl:call-template name="xsl:original"/>
             </rep:documentData>
          </xsl:template>
        </xsl:override>
    </xsl:use-package>
    
    ...

</xsl:stylesheet>

然后主要问题是让 Saxon 知道如何在http://example.com/adapt1您将使用的命令行上将包名称映射到包文件,例如-lib:adapt-package-wrapper.xsl. 或者,您可以使用配置文件。不确定您是否可以在您的环境中执行此操作。


推荐阅读