我对xsl:apply-templates:
进行了相当复杂的调用<xsl:apply-templates select="columnval[@id
and not(@id='_Name_')
and not(@id='Group')
and not(@id='_Count_')]"/>
表达式在其他地方重复使用:
<xsl:apply-templates select="someothernode[@id
and not(@id='_Name_')
and not(@id='Group')
and not(@id='_Count_')]"/>
我想以某种方式概括它,所以我可以定义一次并在其他地方重用它。但是,这似乎不起作用:
<xsl:variable name="x">@id and not(@id='_Name_') and not(@id='Group') and not(@id='_Count_')</xsl:variable>
<xsl:apply-templates select="columnval[$x]"/>
<xsl:apply-templates select="someothernode[$x]"/>
有更好/不同的方式吗?我想要的是在多个不同的xsl:apply-templates调用中重用xpath表达式(其中一些从不同的子节点中选择)。
这将在客户端应用程序中使用,因此我不能使用任何扩展或切换到XSLT 2。 :(
感谢。
答案 0 :(得分:5)
您无法在XSLT中动态构建XPath(至少不是XSLT 1.0)。但是你可以使用模板模式轻松完成你想要做的事情:
<xsl:apply-templates select="columnval" mode="filter"/>
<xsl:apply-template select="someothernode" mode="filter"/>
...
<!-- this guarantees that elements that don't match the filter don't get output -->
<xsl:template match="*" mode="filter"/>
<xsl:template match="*[@id and not(@id='_Name_') and not(@id='Group') and not(@id='_Count_')]" mode="filter">
<xsl:apply-templates select="." mode="filtered"/>
</xsl:template>
<xsl:template match="columnval" mode="filtered">
<!-- this will only be applied to the columnval elements that pass the filter -->
</xsl:template>
<xsl:template match="someothernode" mode="filtered">
<!-- this will only be applied to the someothernode elements that pass the filter -->
</xsl:template>
答案 1 :(得分:2)
重构@Robert Rossney和@Tomalak
<xsl:apply-templates select="columnval" mode="filter"/>
<xsl:apply-templates select="someothernode" mode="filter"/>
<xsl:template match="*" mode="filter">
<xsl:param name="pFilter" select="'_Name_|Group|_Count_'"/>
<xsl:apply-templates select="self::*
[not(contains(
concat('|',$pFilter,'|'),
concat('|',@id,'|')))
and @id]"/>
</xsl:template>
答案 2 :(得分:1)
我会看一下使用xslt的扩展名。我不认为你可以用“标准”xslt。
来做此扩展程序可以执行您想要的操作:http://www.exslt.org/dyn/functions/evaluate/index.html
答案 3 :(得分:1)
使用扩展名exsl:nodeset,您可以创建一个接受节点集$ x的命名模板,并根据您的静态谓词返回已过滤的节点集。
您还可以在XSLT 2.0中定义一个函数。
答案 4 :(得分:1)
怎么样:
<xsl:variable name="filter" select="_Name_|Group|_Count_" />
<xsl:apply-templates select="columnval" mode="filtered" />
<xsl:apply-templates select="someothernode" mode="filtered" />
<xsl:template match="someothernode|columnval" mode="filtered">
<xsl:if test="not(contains(
concat('|', $filter,'|'),
concat('|', @id,'|'),
))">
<!-- whatever -->
</xsl:if>
</xsl:template>
你可以让$filter
成为一个参数,然后从外面传递它。
你不能做的事(正如你所注意到的)是使用变量来存储XPath表达式。
答案 5 :(得分:1)
XSLT 1.0和XSLT 2.0都不支持动态评估。
执行此操作的一种方法是在XSLT 2.0中使用<xsl:function>
或在XSLT 1.0中使用<xsl:call-template>
。
<xsl:function name="my:test" as="xs:boolean">
<xsl:param name="pNode" as="element()"/>
<xsl:variable name="vid" select="$pNode/@id"/>
<xsl:sequence select=
"$vid and not($vid=('_Name_','Group','_Count_')"/>
</xsl:function>
然后您可以使用此功能:
<xsl:apply-templates select="columnval[my:test(.)]"/>
当然,您可以按照罗伯特·罗斯尼建议的特定匹配模式指定测试,这可能是最佳方式。
如果您需要动态定义要使用的过滤功能,一个强大的工具是 FXSL 库,它实现了高阶函数( HOF)在XSLT中。 HOF是接受其他函数作为参数的函数,可以返回函数作为结果。
使用此方法,您可以动态确定并将my:test()
作为参数传递给执行测试的函数。