Xml XSLT:我可以创建一个函数库,它本身就是一个模板吗?

Xml XSLT:我可以创建一个函数库,它本身就是一个模板吗?,xml,xslt,xslt-2.0,Xml,Xslt,Xslt 2.0,我有几个XSLT转换。它们都包含相同的模板,如下所示(其实现和功能无关紧要): 缺席的 如您所见,我列出了要在模板匹配中应用此模板的字段 但事实上,我想在我所有的转换中使用这个模板,当然是使用不同的字段名。换句话说,我想把它当作一个可以插入任何.xsl文件并指定参数列表的函数来使用,这些参数是以这种方式修改的字段的名称 我可以用XSLT吗?有点像 您可以创建一个命名模板,其中包含要重用的实现,如下所示: <xsl:template name="MyTemplate"> &

我有几个XSLT转换。它们都包含相同的模板,如下所示(其实现和功能无关紧要):


缺席的
如您所见,我列出了要在模板匹配中应用此模板的字段

但事实上,我想在我所有的转换中使用这个模板,当然是使用不同的字段名。换句话说,我想把它当作一个可以插入任何.xsl文件并指定参数列表的函数来使用,这些参数是以这种方式修改的字段的名称

我可以用XSLT吗?

有点像

您可以创建一个命名模板,其中包含要重用的实现,如下所示:

<xsl:template name="MyTemplate">
    <xsl:element name="{local-name(.)}">    
    <xsl:choose>
        <xsl:when test="string-length(.)!=0"><xsl:value-of select="."/></xsl:when>  
        <xsl:otherwise>ABSENT</xsl:otherwise>   
    </xsl:choose>   
    </xsl:element>
</xsl:template>

缺席的
然后可以调用此模板来创建匹配不同元素的模板,而无需重复模板主体

<xsl:template match="firstField | secondField | thirdField">
    <xsl:call-template name="MyTemplate" />
</xsl:template>


(这是未经测试的,因此语法可能有点不正确)

更新,我可能误解了您的问题,并再次查看了您的模板(有关解决方案说明的更一般描述,请参阅下文)

你写道:

将上面的代码放在一个单独的文件中,除了变量之外,您应该将其放在那里,但保留为空。使用
xsl:import
导入此文件,现在只需覆盖
xsl:variable

XSLT2.0和3.0中有比这更通用和更简单的方法,但此版本适用于XSLT1.0

免责声明:未经测试,可能包含错误,当然,根据您的需要进行调整;)

更好的/通用的方法 是的,你能做到。不同的XSLT版本具有不同的抽象级别:

XSLT1.0 您可以创建一个命名模板(只需给它一个名称)。如果使用
xsl:call template
调用命名模板,则当前上下文项将用作模板内的上下文项。这将解决模板匹配中字段名称的问题

您可以将其放置在一个单独的文件中,并使用
xsl:import
(允许您在必要时覆盖它)或
xsl:include
(不允许覆盖)导入它,如果出现命名冲突,将引发错误

XSLT2.0 您可以在XSLT2.0中创建一个函数,该函数可以作为任何其他函数调用。函数可以包含上面显示的模板

在XSLT2.0中,还可以使用导入和包含

XSLT3.0 您可以执行与以前版本相同的操作,但现在可以将它们放在(预编译)包中,这使得重用、重新分发和调用它们变得更加容易

此外,XSLT 3.0在覆盖和接受/公开所用包的组件方面有了很大的改进

所有版本 您可能有一个地方当前正在使用
xsl:apply-templates
。如果要防止重复声明匹配的
xsl:template
,可以通过创建泛型:

<xsl:template match="node()" mode="special">
    <xsl:call-template name="yourNamedTemplate" />
</xsl:template>

然后通过使用以下命令“调用”该命令:

<xsl:apply-templates select="firstField | secondField | thirdField" mode="special" />

提示 如果重用性很重要,那么您的“库样式表”(在XSLT 3.0中,会弹出官方术语“库包”),您应该在名称空间中创建模式名称。事实上,可重用样式表中的任何命名组件(命名模板、模式、函数、累加器、键)都应该位于它们自己的名称空间中。这可以防止冲突,如果用户想要覆盖冲突,他们必须显式地这样做

您可以创建一个“继承链”。如果A导入B导入C,则A、B、C中的命名组件的优先级最高。冲突的匹配模板也是如此。这(通常)在您的主样式表中是不允许的(因此设置了优先级),但A可以与B或C具有相同的匹配模板。在这种情况下,A超过B超过C

指定参数列表,这些参数是要删除的字段的名称 这样修改的

问题的答案是否定的:您不能告诉模板将自身应用于参数中提供的节点列表。调用命名模板或函数时,上下文不会更改


但是,一旦建立了上下文,您就可以调用命名模板(或XSLT 2.0中的函数),如Justin的回答所示。

请指出XSLT 1.0或2.0。当我阅读您的回答时,我再次阅读了他的陈述,我不确定这是否是不可能的,如果所示模板如其描述所示一般适用。但是,同样需要OP的评论才能确定。@Abel OP声明“模板的实现和功能不重要”。OP没有说明样式表可能有哪些其他模板。不,这就是为什么在我的回答中我建议使用其他模式。如果他的模板内容使用应用模板,我建议的方法将不起作用。@Abel按照我的理解,OP希望此模板覆盖任何(未知)模板,否则这些模板将应用于相关节点。当节点列表作为参数传递时,我认为这是不可能的。如果他必须坚持匹配模板,并希望在给定参数的情况下此行为,则不可能,因为参数将超出匹配模式的范围。XSLT3.0中有一个显著的例外,您可以使用
xsl:acculator
模拟这种行为,但我猜这对于一个简单的需求来说太高级了。
<xsl:variable name="names">
    <names>
        <n>firstField</n>
        <n>secondField</n>
        <n>thirdField</n>
    </names>
</xsl:variable>

<xsl:template match="*" mode="by-name">
   <xsl:element name="{local-name(.)}">
      <xsl:apply-templates select="self::node()" mode="text" />
   </xsl:element>
</xsl:template>

<xsl:template match="node()" mode="by-name" />

<xsl:template match="*[text()]" mode="text">
    <xsl:copy />
</xsl:template>

<xsl:template match="*[not(text())]" mode="text">
    <xsl:text>ABSENT</xsl:text>
</xsl:template>

<xsl:template match="/">
    <xsl:apply-templates select="your/current/whatever" />
</xsl:template>

<xsl:template match="*">
    <xsl:for-each select="exslt:node-set($names)/names/n/text()">
        <xsl:apply-templates select="self::*[name() = .]" mode="by-name" />
    </xsl:for-each>
</xsl:template>
<xsl:template match="node()" mode="special">
    <xsl:call-template name="yourNamedTemplate" />
</xsl:template>
<xsl:apply-templates select="firstField | secondField | thirdField" mode="special" />