如何使用包含图案的XSLT变量在模板匹配表达式
问题描述:
<xsl:variable name="myPattern" select="node1|node2"/>
<xsl:template match="$myPattern">
...
</xsl:template>
<xsl:template match="/">
...
<xsl:for-each select="distinct-values(//$myPattern/name/text()">
...
</xsl:for-each>
</xsl:template>
我用XSLT版本2.0和3.0无济于事尝试这样做。任何提示?
原因:该模式有点复杂,我想在几个地方使用它,而不仅仅是这场比赛。
编辑:
我解决我的问题,现在通过接受一个事实,即该变量不包含字符串/模式,但结果节点。如果我将其修改为
<xsl:variable name="myNodes" select="//(node1|node2)"/>
<xsl:template match="$myNodes">
...
</xsl:template>
<xsl:template match="/">
...
<xsl:for-each select="distinct-values($myNodes/name/text()">
...
</xsl:for-each>
</xsl:template>
它工作正常。
我仍然想知道为什么不能简单地将字符串存储在变量中,并在允许字符串的任何位置使用它。
答
至于文本替换,使用XSLT 3.0,您可以使用使用静态参数有一个字符串值,然后所谓的阴影属性(https://www.w3.org/TR/xslt-30/#shadow-attributes):
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:math="http://www.w3.org/2005/xpath-functions/math" exclude-result-prefixes="xs math"
version="3.0">
<xsl:param name="myPattern" static="yes" as="xs:string" select="'node1|node2'"/>
<xsl:template _match="{$myPattern}">
<matched name="{node-name()}">
<xsl:apply-templates/>
</matched>
</xsl:template>
<xsl:template match="/*">
<xsl:copy>
<xsl:for-each _select="distinct-values(//{$myPattern}/text())">
<value>
<xsl:value-of select="."/>
</value>
</xsl:for-each>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
这转变
<root>
<node1>a</node1>
<node2>1</node2>
<node1>a</node1>
</root>
into
<root><value>a</value><value>1</value>
<matched name="node1">a</matched>
<matched name="node2">1</matched>
<matched name="node1">a</matched>
</root>
在XSLT 3.0 y您可以使用模板的match
模式的变量或参数引用,但它不是发生的文本替换,而是“$ xyz匹配变量$ xyz的值中存在的任何节点”(https://www.w3.org/TR/xslt-30/#pattern-examples)。
于是用XSLT是
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:param name="delete" select="//*[contains-token(@class, 'foo')]"/>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template match="$delete"/>
</xsl:stylesheet>
和XML输入是
<html>
<head>
<title>test</title>
</head>
<body>
<p class="foobar bar">Paragraph 1.</p>
<p class="foo bar">Paragraph 2.</p>
<p class="bar">Paragraph 3.</p>
<p class="foo">Paragraph 4.</p>
</body>
</html>
相符的XSLT 3.0处理器等撒克逊9.7 EE输出
<html>
<head>
<title>test</title>
</head>
<body>
<p class="foobar bar">Paragraph 1.</p>
<p class="bar">Paragraph 3.</p>
</body>
</html>
答
我建议使用一个功能而不是变量:
<xsl:function name="_:myPattern" as="xs:boolean">
<xsl:param name="node" as="node()"/>
<xsl:sequence select="self::node1() | self::node2()"/>
</xsl:function>
<xsl:template match="node()[_:myPattern(.)]">
...
</xsl:template>
XSLT 3.0允许您使用例如'match =“$ xyz”'并解释“$ xyz匹配变量$ xyz的值中存在的任何节点”。因此,您需要向我们展示一个最小但完整的XML,XSLT样本,您期望的输出,输出或错误,以及有关使用的XSLT处理器的信息,以便我们能够分辨出哪些是错误的。显然,我希望你的变量声明看起来像例如' ',除非你正在寻找的元素真的是根元素。 –
@MartinHonnen:你说得对。我希望在短时间内让其他人在搜索答案时节省时间。我认为你的评论比你的回答更好,因为这是我解决它的方法:' '。 –
mdr
@mdr您将不得不使用某种'evaluate()'函数将字符串转换为XPath表达式(如果这就是您的意思)。 –