在XML数据转换任务中,我们经常遇到这样的情形:同一个父节点下的子元素,需要根据不同的属性值、文本内容或位置关系,输出完全不同的HTML结构或文本格式。XSLT作为专门负责XML转换的语言,并没有传统编程语言里的if-else代码块写法,而是通过一组声明式的指令元素来完成多条件选择。理解这些元素的行为差异,能够帮助我们在样式表中表达复杂的业务分支,而不必把逻辑拆散到大量零散的模板里。

使用xsl:choose构建分支逻辑
xsl:choose是XSLT中最接近switch-case的多条件选择结构。它必须包含一个或多个xsl:when子元素,以及可选的一个xsl:otherwise收尾元素。处理器会自上而下依次计算xsl:when上的test属性表达式,一旦某个表达式结果为真,就执行该分支内部的指令,然后直接跳出整个xsl:choose,后续分支不再评估。这种顺序敏感的特性要求我们将更精确、更狭窄的条件写在前面,把兜底规则放在xsl:otherwise中。
下面示例展示如何根据商品库存状态输出不同提示。当status为out时显示缺货,limited时显示紧张,其余情况显示有货。注意test表达式里使用了等号和逻辑函数,XSLT的XPath引擎会自动完成字符串比较与节点集判断。
<xsl:template match="product">
<div class="product">
<xsl:choose>
<xsl:when test="@status = 'out'">
<span class="sold-out">暂时缺货</span>
</xsl:when>
<xsl:when test="@status = 'limited'">
<span class="limited">库存紧张</span>
</xsl:when>
<xsl:otherwise>
<span class="in-stock">现货充足</span>
</xsl:otherwise>
</xsl:choose>
</div>
</xsl:template>
如果我们在上述例子中把xsl:otherwise写成一个test="@status != 'out'"的xsl:when并放在第一位,那么limited状态也会被它提前捕获,导致永远走不到第二个分支。这就是顺序评估带来的隐藏陷阱。因此在设计多条件选择时,应先列出所有互斥且具体的情形,再考虑通用兜底。
结合xsl:if与嵌套choose处理复合条件
当只需要判断单个布尔条件而不存在多种互斥输出时,xsl:if更为轻量。它不像xsl:choose那样提供else分支,若条件不成立就什么都不做。但在真实项目中,条件往往是多维的:比如先按地区分流,地区内部再按用户等级显示不同价格。此时可以在xsl:when分支内部再嵌套一层xsl:choose,或者用xsl:if配合多个并列判断。
以下代码先在顶层用xsl:if确认文档语言,再在内部用嵌套xsl:choose处理货币符号。这种结构比把全部条件拍平为长串or表达式更易读,也方便后续维护者单独修改某个地区的规则。
<xsl:template match="price">
<xsl:if test="../@region = 'cn'">
<p>
<xsl:text>¥</xsl:text>
<xsl:choose>
<xsl:when test="@level = 'vip'">
<xsl:value-of select=". * 0.8"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="."/>
</xsl:otherwise>
</xsl:choose>
</p>
</xsl:if>
</xsl:template>
需要注意,嵌套层次过深会让样式表难以调试。如果复合条件超过三层,建议把内层逻辑抽取成独立模板,通过xsl:apply-templates传递参数,或者利用xsl:variable先计算出中间状态,再用单层xsl:choose做最终选择。这样既能保留多条件选择的清晰性,又避免标签嵌套如同迷宫。
借助XPath表达式简化多条件判断
很多初学者习惯写一大堆xsl:when来列举所有可能值,其实XPath本身支持丰富的运算符与函数,可以把多个条件压缩进一个test里。例如使用and、or连接判断,或用contains、starts-with做模糊匹配,甚至用count()配合节点集比较。合理运用这些表达式,能减少分支数量,让多条件选择更紧凑。
假设我们要过滤掉无效订单:金额小于零,或状态为cancel,或备注含test字样。与其写三个xsl:when,不如在父级用一个xsl:if统统一并拦截,剩下的正常订单再走xsl:choose细分物流方式。示例代码如下,其中test属性内联了复合布尔逻辑。
<xsl:template match="order">
<xsl:if test="not(amount < 0 or @state = 'cancel' or contains(note, 'test'))">
<div class="order">
<xsl:choose>
<xsl:when test="@ship = 'express'">
<span>顺丰速运</span>
</xsl:when>
<xsl:when test="@ship = 'normal'">
<span>标准快递</span>
</xsl:when>
<xsl:otherwise>
<span>尚未安排</span>
</xsl:otherwise>
</xsl:choose>
</div>
</xsl:if>
</xsl:template>
在XPath 2.0及以上版本中,还可以使用if-then-else表达式直接写在select或test中,例如select="if (@a > 10) then 'high' else 'low'",这进一步模糊了xsl:choose与语言内置条件的边界。不过为了样式表在旧环境或简单处理器中通用,仍推荐以xsl:choose作为多条件选择的主干,把复杂判断交给XPath做前置筛选。掌握这种分工,才能写出既高效又兼容的转换脚本。
XSLT多条件选择xsl_choose修改时间:2026-08-17 01:46:36