You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

XSLT同一路径多匹配模板问题:如何让节点应用所有匹配模板

嘿,这个问题我太熟了!XSLT的模板匹配规则默认就是只会选一个最匹配的模板执行,而不是所有匹配的都跑一遍——如果多个模板优先级相同,就选XSL文件里最后出现的那个,这就是你遇到的“看顺序”问题。

本质上,XSLT的模板匹配是“竞争式”的:处理器会给每个匹配的模板打分(优先级),然后挑最高分的执行;分数一样的话,就选定义靠后的。默认不会自动触发多个模板,得你手动告诉它要继续执行其他匹配的模板。

方案1:XSLT 2.0及以上(推荐,更简洁)

用<xsl:next-match/>指令,它能让处理器在当前模板执行完后,继续应用下一个匹配的模板。比如针对你的示例:

先看你的XML源:

<a>
  <b url="foo">
    <text>1</text>
    <text>2</text>
  </b>
</a>

然后写XSLT:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <!-- 第一个模板:输出所有text子节点的内容 -->
  <xsl:template match="//*[text]">
    <xsl:for-each select="text">
      <xsl:value-of select="."/>
    </xsl:for-each>
    <!-- 关键:告诉处理器继续找下一个匹配的模板执行 -->
    <xsl:next-match/>
  </xsl:template>

  <!-- 第二个模板:处理带url属性的节点 -->
  <xsl:template match="//*[@url]">
    <xsl:text> (URL: </xsl:text>
    <xsl:value-of select="@url"/>
    <xsl:text>)</xsl:text>
  </xsl:template>

  <!-- 必须保留的默认模板:确保递归处理整个节点树 -->
  <xsl:template match="@*|node()">
    <xsl:apply-templates select="@*|node()"/>
  </xsl:template>
</xsl:stylesheet>

运行后会输出:12 (URL: foo),两个模板的逻辑都执行了。

方案2:XSLT 1.0(兼容旧环境)

XSLT 1.0没有<xsl:next-match/>,那我们可以把要执行的逻辑拆成命名模板,然后在主匹配模板里逐个调用:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <!-- 主匹配模板:负责调用所有需要的逻辑模板 -->
  <xsl:template match="//*[text]">
    <!-- 调用输出text内容的模板 -->
    <xsl:call-template name="output-text-content"/>
    <!-- 如果节点有url属性,调用输出url的模板 -->
    <xsl:if test="@url">
      <xsl:call-template name="output-url-attribute"/>
    </xsl:if>
  </xsl:template>

  <!-- 命名模板1:输出text子节点内容 -->
  <xsl:template name="output-text-content">
    <xsl:for-each select="text">
      <xsl:value-of select="."/>
    </xsl:for-each>
  </xsl:template>

  <!-- 命名模板2:输出url属性 -->
  <xsl:template name="output-url-attribute">
    <xsl:text> (URL: </xsl:text>
    <xsl:value-of select="@url"/>
    <xsl:text>)</xsl:text>
  </xsl:template>

  <!-- 默认模板:递归处理节点树 -->
  <xsl:template match="@*|node()">
    <xsl:apply-templates select="@*|node()"/>
  </xsl:template>
</xsl:stylesheet>

额外提醒

别忘了保留那个默认的match="@*|node()"模板——它会递归处理XML里的所有节点和属性,不然处理器可能只会处理你明确匹配的节点,忽略其他部分。

内容的提问来源于stack exchange,提问作者Maroš Beťko

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 07:28:53