我有几个XSLT转换。它们都包含相同的模板,看起来像这样(它的实现和功能无关紧要):
<xsl:template match="firstField| secondField | thirdField">
<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文件的函数一样,并指定一个参数列表,这些是要以这种方式修改的字段的名称。
我可以使用XSLT吗?
答案 0 :(得分:2)
更新,我可能误解了您的问题并重新审视了您的模板(有关解决方案说明的更一般说明,请参阅下文)。
您写道:
<xsl:template match="firstField| secondField | thirdField"> <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文件并指定一个参数列表,这些是要以这种方式修改的字段的名称。
如果用&#34;这种方式&#34;你的意思是说:
xsl:copy
就足够了)然后你可以通过以下方式做到这一点。但是,只有当您的要求像您所说的那样一般适用于您的用例时,这才有效。
按如下方式编写模板:
<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:import
导入此文件,您现在唯一需要做的就是覆盖xsl:variable
。
XSLT 2.0和3.0中有更多通用和简单的方法,但此版本适用于XSLT 1.0。
免责声明:未经测试,可能包含错误,当然也可以根据您的需求进行调整;)
是的,你可以这样做。不同的XSLT版本具有不同的抽象级别:
您可以创建命名模板(只需为其命名)。如果使用xsl:call-template
调用命名模板,则当前上下文项将用作模板内的上下文项。这将使用模板匹配中的字段名称解决您的问题。
您可以将其放在一个单独的文件中,然后使用xsl:import
将其导入,以便在必要时覆盖它,或者xsl:include
,它不允许覆盖,如果是,则会引发错误命名冲突出现了。
您可以在XSLT 2.0中创建一个可以作为任何其他函数调用的函数。函数可以包含您在上面显示的模板。
在XSLT 2.0中,您还可以使用import和include。
您可以执行与以前版本相同的操作,但现在可以将它们放在(预编译)包中,这样可以更轻松地重用,重新分发和调用它们。
此外,XSLT 3.0在覆盖和接受/暴露已使用软件包的组件方面有一个大大改进的系统。
您可能有一个当前使用xsl:apply-templates
的地方。如果您想阻止重复声明匹配的xsl:template
,可以通过创建通用来解决此问题:
<xsl:template match="node()" mode="special">
<xsl:call-template name="yourNamedTemplate" />
</xsl:template>
然后&#34;叫&#34;使用:
<xsl:apply-templates select="firstField | secondField | thirdField" mode="special" />
如果可重用性很重要,那么您的&#34;库样式表&#34; (在XSLT 3.0中,官方术语&#34;库包&#34;弹出),您应该在命名空间中创建模式的名称。实际上,可重用样式表中的任何命名组件(命名模板,模式,函数,累加器,键)都应位于其自己的命名空间中。这可以防止冲突,如果用户想要覆盖它们,则必须明确地这样做。
您可以创建&#34;继承链&#34;。如果A导入B导入C,那么最高优先级将给予A中的命名组件,然后是B,然后是C.对于冲突的匹配模板也是如此。这通常不允许在你的主样式表中(因此设置优先级),但是A可以具有与B相同的匹配模板,或者作为C.在这种情况下,A超过B超过C。
答案 1 :(得分:1)
指定参数列表,这些参数是要包含的字段的名称 以这种方式修改。
问题的问题的答案是否定的:您无法告诉模板将自身应用于参数中提供的节点列表。调用命名模板或函数时,上下文不会更改。
但是,一旦建立了上下文,可以调用命名模板(或XSLT 2.0中的函数) - 如Justin的答案所示。
答案 2 :(得分:0)
排序。
您可以做的是创建一个包含您想要重复使用的实现的命名模板,如下所示:
<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>
(这是未经测试的,因此语法可能有点偏离)