XSLT遍历对象列表:匹配终止处理,无匹配则执行文档处理
嘿,这个问题其实是XSLT新手常遇到的坑——毕竟它是声明式语言,和你熟悉的命令式语言逻辑不一样,没法用「布尔变量+for循环」那套思路。咱们一步步来解决:
问题根源分析
你现有代码的问题在于 contains($url, exsl:node-set($exclude)/exclude/@block) 只会取第一个 exclude/@block 的值(也就是999),没法遍历整个列表检查所有项。要实现「只要有一个匹配就终止,否则处理文档」的逻辑,关键是用XPath判断是否存在任何一个exclude项匹配URL,而不是逐个遍历。
XSLT 1.0 解决方案(兼容多数旧处理器)
因为你用到了 exsl:node-set,说明是在XSLT 1.0环境下(1.0中变量里的节点是「结果树片段」,需要转成节点集才能遍历),完整代码如下:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exsl="http://exslt.org/common" exclude-result-prefixes="exsl"> <!-- 定义排除列表 --> <xsl:variable name="exclude"> <exclude block="999" /> <exclude block="111" /> </xsl:variable> <!-- 身份模板:默认复制所有节点和属性 --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()" /> </xsl:copy> </xsl:template> <!-- 根节点控制模板 --> <xsl:template match="/"> <!-- 判断是否存在匹配的exclude项 --> <xsl:variable name="has-match" select="boolean(exsl:node-set($exclude)/exclude[contains($url, @block)])"/> <!-- 无匹配时才执行文档处理 --> <xsl:if test="not($has-match)"> <xsl:apply-templates select="." /> </xsl:if> <!-- 有匹配则什么都不输出,相当于终止处理 --> </xsl:template> </xsl:stylesheet>
代码说明:
- 声明
exsl命名空间并设置exclude-result-prefixes,避免它污染输出结果 $has-match变量通过boolean()把节点集转成布尔值:如果存在任何一个exclude节点的block值包含在$url中,就返回true,否则false- 根模板只有在无匹配时才调用身份模板执行文档复制,达到「匹配则终止」的效果
XSLT 2.0+ 简化版本(推荐)
如果你的处理器支持XSLT 2.0或更高版本,就不需要 exsl:node-set 了,代码会更简洁:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:variable name="exclude"> <exclude block="999" /> <exclude block="111" /> </xsl:variable> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()" /> </xsl:copy> </xsl:template> <xsl:template match="/"> <xsl:if test="not(exists($exclude/exclude[contains($url, @block)]))"> <xsl:apply-templates select="." /> </xsl:if> </xsl:template> </xsl:stylesheet>
核心思路总结
XSLT的本质是「描述要做什么」,而不是「描述怎么做」。你不需要手动写循环,只要用XPath告诉处理器「我要找满足XX条件的节点」,它会自动帮你遍历节点集完成判断——这就是声明式语言的优势啦。
内容的提问来源于stack exchange,提问作者Joshua Hedges
相关产品推荐
相关产品推荐

