如何在XSLT中使用外部参数动态设置template match的匹配元素?
动态设置XSLT模板匹配元素的实现方案
问题背景
需要通过外部参数对XML进行动态过滤:指定过滤字段filterAt、过滤值filterVal,同时希望将需要过滤的目标元素(如示例中的row)也通过参数rowName动态配置。直接在xsl:template的match属性中使用参数$rowName会导致解析错误,因为XSLT的模板匹配模式属于静态编译逻辑,无法直接引用运行时参数。
原始XML示例
<root> <row id="1"> <order>4711</order> <customer>a</customer> </row> <row id="3"> <order>4712</order> <customer>a</customer> </row> <row id="4"> <order>4713</order> <customer>b</customer> </row> <row id="5"> <order>4714</order> <customer>c</customer> </row> </root>
预期过滤结果(按customer=a过滤)
<root> <row id="1"> <order>4711</order> <customer>a</customer> </row> <row id="3"> <order>4712</order> <customer>a</customer> </row> </root>
可行实现方案
方案一:通用适配型(保留身份模板)
通过新增匹配所有元素的模板,在模板内部判断元素名是否匹配参数rowName,再执行过滤逻辑,同时保留身份模板的通用性,适配任意XML结构:
<?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:param name="filterVal"/> <xsl:param name="filterAt"/> <xsl:param name="rowName" select="'row'"/> <!-- 设置默认值为row,可选 --> <xsl:output method="xml" indent="yes"/> <!-- 身份模板:默认复制所有节点和属性 --> <xsl:template match="node()|@*"> <xsl:copy> <xsl:apply-templates select="node()|@*"/> </xsl:copy> </xsl:template> <!-- 匹配所有元素,动态判断是否为目标过滤元素 --> <xsl:template match="*"> <xsl:choose> <xsl:when test="local-name() = $rowName"> <!-- 仅保留符合过滤条件的目标元素 --> <xsl:if test="*[local-name()=$filterAt]=$filterVal"> <xsl:copy-of select="."/> </xsl:if> </xsl:when> <xsl:otherwise> <!-- 非目标元素按身份模板规则处理 --> <xsl:copy> <xsl:apply-templates select="node()|@*"/> </xsl:copy> </xsl:otherwise> </xsl:choose> </xsl:template> </xsl:stylesheet>
方案二:简洁定向型(针对固定根结构)
如果XML结构固定(如根节点为root),可以直接在根节点模板中通过动态XPath选择符合条件的元素,代码更简洁:
<?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:param name="filterVal"/> <xsl:param name="filterAt"/> <xsl:param name="rowName" select="'row'"/> <xsl:output method="xml" indent="yes"/> <xsl:template match="root"> <root> <!-- 动态选择目标元素并过滤:匹配元素名=rowName,且指定字段值=filterVal --> <xsl:copy-of select="*[local-name()=$rowName and *[local-name()=$filterAt]=$filterVal]"/> </root> </xsl:template> </xsl:stylesheet>
说明
两种方案均基于XSLT 2.0规范,XMLSpy只要开启XSLT 2.0解析模式即可正常运行。参数rowName可外部传入(如rowName=entry),实现对不同元素的动态过滤。
内容的提问来源于stack exchange,提问作者user2886121
相关产品推荐
相关产品推荐

