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

如何使用XSLT mode属性实现XML分组后仅输出文本结果

解决XSLT多模板组合时的输出问题

问题说明

尽管有不少帖子讲解同一XSLT文件中多模板的使用,但仍未找到解决自身问题的方案。希望对XML文件执行两次转换:首先按ID进行分组,然后进行去除特殊字符的处理。单独使用两个模板时均能正常工作,但将它们组合后,输出同时包含XML和文本内容。目标是仅保留文本输出,将XML部分作为中间步骤即可,期望实现类似如下结构的逻辑:

<xsl:template match="">
     <xsl:apply-templates select="XML_Part"/> ---> 不输出到最终结果
     <xsl:apply-templates select="Text_Part"/>
</xsl:template>

<xsl:template match="" mode="XML_Part">
</xsl:template>

<xsl:template match="" mode="Text_Part">
</xsl:template>

输入XML文件

<?xml version="1.0" encoding="UTF-8"?>
<wd:Report_Data xmlns:wd="http://www.workday.org/">
  <wd:Report_Entry>
    <wd:id>1000</wd:id>
    <wd:name>Call-of-Duty</wd:name>
    <wd:price>50.12</wd:price>
    <wd:copy>0</wd:copy>
  </wd:Report_Entry>
  <wd:Report_Entry>
    <wd:id>1000</wd:id>
    <wd:name>Call-of-Duty</wd:name>
    <wd:price>60.0</wd:price>
    <wd:copy>1</wd:copy>
  </wd:Report_Entry>
  <wd:Report_Entry>
    <wd:id>2000</wd:id>
    <wd:name>Metal Slug</wd:name>
    <wd:price>75.00</wd:price>
    <wd:copy>0</wd:copy>
  </wd:Report_Entry>
  <wd:Report_Entry>
    <wd:id>3000</wd:id>
    <wd:name>Need For Speed</wd:name>
    <wd:price>40.00</wd:price>
    <wd:copy>0</wd:copy>
  </wd:Report_Entry>
</wd:Report_Data>

分组用XSLT模板(单独正常工作)

<xsl:template match="/wd:Report_Data">
    <xsl:copy>
        <xsl:for-each-group select="wd:Report_Entry" group-by="wd:id">
            <xsl:copy>
                <xsl:copy-of select="wd:id"/>
                <xsl:copy-of select="wd:name"/>
                    <wd:price>
                        <xsl:value-of select="sum(current-group()/wd:price)" />
                    </wd:price>                 
                <xsl:copy-of select="wd:copy"/>
            </xsl:copy>
        </xsl:for-each-group>
    </xsl:copy>
</xsl:template>

去除特殊字符并显示文本的XSLT模板(单独正常工作)

<xsl:template match="wd:Report_Data/wd:Report_Entry">
    
    <xsl:value-of select="wd:id"/>
    <xsl:text>|</xsl:text>
    <xsl:value-of select="translate(wd:name,'-',' ')"/>
    <xsl:text>|</xsl:text>
    <xsl:value-of select="wd:price"/>
    <xsl:text>|</xsl:text>
    <xsl:value-of select="wd:copy"/>
  
</xsl:template>

当前输出

<wd:Report_Data xmlns:wd="http://www.workday.org/">
   <wd:Report_Entry>
      <wd:id>1000</wd:id>
      <wd:name>Call of Duty</wd:name>
      <wd:price>110.12</wd:price>
      <wd:copy>0</wd:copy>
   </wd:Report_Entry>
   <wd:Report_Entry>
      <wd:id>2000</wd:id>
      <wd:name>Metal Slug</wd:name>
      <wd:price>75</wd:price>
      <wd:copy>0</wd:copy>
   </wd:Report_Entry>
   <wd:Report_Entry>
      <wd:id>3000</wd:id>
      <wd:name>Need For Speed</wd:name>
      <wd:price>40</wd:price>
      <wd:copy>0</wd:copy>
   </wd:Report_Entry>
</wd:Report_Data>
1000|Call of Duty|110.12|0
2000|Metal Slug|75.00|0
3000|Need For Speed|40.00|0

期望输出

1000|Call of Duty|110.12|0
2000|Metal Slug|75.00|0
3000|Need For Speed|40.00|0

解决方案

方案一:一步完成分组与文本转换

核心是直接在分组逻辑中调用文本输出模板,跳过中间XML的输出环节:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:wd="http://www.workday.org/">
    <!-- 主模板:触发分组并直接生成文本 -->
    <xsl:template match="/wd:Report_Data">
        <xsl:for-each-group select="wd:Report_Entry" group-by="wd:id">
            <xsl:apply-templates select="." mode="text-output"/>
            <xsl:text>&#10;</xsl:text> <!-- 添加换行符 -->
        </xsl:for-each-group>
    </xsl:template>

    <!-- 文本输出模板:处理分组后的条目 -->
    <xsl:template match="wd:Report_Entry" mode="text-output">
        <xsl:value-of select="wd:id"/>
        <xsl:text>|</xsl:text>
        <xsl:value-of select="translate(wd:name,'-',' ')"/>
        <xsl:text>|</xsl:text>
        <xsl:value-of select="sum(current-group()/wd:price)"/>
        <xsl:text>|</xsl:text>
        <xsl:value-of select="wd:copy"/>
    </xsl:template>

    <!-- 抑制默认模板,避免多余内容输出 -->
    <xsl:template match="text()|@*"/>
</xsl:stylesheet>

方案二:保留中间XML步骤

如果严格需要先生成分组后的XML再转换为文本,可通过变量存储中间结果:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:wd="http://www.workday.org/">
    <xsl:template match="/wd:Report_Data">
        <!-- 第一步:生成分组后的XML并存储 -->
        <xsl:variable name="grouped-data">
            <xsl:copy>
                <xsl:for-each-group select="wd:Report_Entry" group-by="wd:id">
                    <xsl:copy>
                        <xsl:copy-of select="wd:id"/>
                        <xsl:copy-of select="wd:name"/>
                        <wd:price>
                            <xsl:value-of select="sum(current-group()/wd:price)" />
                        </wd:price>                 
                        <xsl:copy-of select="wd:copy"/>
                    </xsl:copy>
                </xsl:for-each-group>
            </xsl:copy>
        </xsl:variable>

        <!-- 第二步:对中间XML应用文本输出模板 -->
        <xsl:apply-templates select="$grouped-data/wd:Report_Data/wd:Report_Entry"/>
    </xsl:template>

    <!-- 文本输出模板 -->
    <xsl:template match="wd:Report_Entry">
        <xsl:value-of select="wd:id"/>
        <xsl:text>|</xsl:text>
        <xsl:value-of select="translate(wd:name,'-',' ')"/>
        <xsl:text>|</xsl:text>
        <xsl:value-of select="wd:price"/>
        <xsl:text>|</xsl:text>
        <xsl:value-of select="wd:copy"/>
        <xsl:text>&#10;</xsl:text>
    </xsl:template>

    <!-- 抑制默认模板 -->
    <xsl:template match="text()|@*"/>
</xsl:stylesheet>

关键说明

  • mode属性用于区分不同处理逻辑,避免模板冲突;
  • 抑制默认模板(match="text()|@*")可防止原始XML的多余内容被输出;
  • 添加<xsl:text>&#10;</xsl:text>确保每条结果单独占一行,匹配期望格式。

内容的提问来源于stack exchange,提问作者David Edgar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 11:39:53