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

XSLT 1.0按@item首字母分组时Item求和异常,求修正方案

XSLT 1.0按Item首字母分组并统计单个Item的Area总和修正方案

使用XSLT 1.0处理XML文件时,需要按@item属性的首字母分组展示,同时统计每个独立Item对应的area总和。当前实现中,所有首字母相同的Item的area会被错误累加(如a1和a2的area总和均显示为4),但预期应为每个Item单独求和(a1为2,a2为2;b1为2,b2为1)。


相关代码

XML文件

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="test_1.xsl"?>
 <Features>
  <Feature item="a1" area="1"></Feature>
  <Feature item="a1" area="1"></Feature>
  <Feature item="a2" area="1"></Feature>
  <Feature item="a2" area="1"></Feature>
  <Feature item="b1" area="1"></Feature>
  <Feature item="b1" area="1"></Feature>
  <Feature item="b2" area="1"></Feature>
 </Features>

XSLT文件

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">     
<xsl:key name="KeyStyle" match="Feature" use="substring(@item,1,1)"/>
<xsl:key name="KeyItem" match="Feature" use="@item"/>
 <xsl:template match="Features">
  <html>
    <xsl:for-each select="Feature[generate-id() = generate-id(key('KeyStyle',substring(@item,1,1))[1])]">   
    <xsl:sort select="substring(@item,1,1)" order="ascending"/> 
     Table for style (<xsl:value-of select="substring(@item,1,1)"/>)
     <xsl:for-each select="key('KeyStyle',substring(@item,1,1))">
     <xsl:sort select="@item" order="ascending"/>
      <xsl:if test="not(preceding::*[@item = current()/@item])">
       <p>Style=<xsl:value-of select="substring(@item,1,1)"/></p>  
       <p>Item=<xsl:value-of select="@item"/></p>  
       <p>TotalAreaOf_Items (<xsl:value-of select="@item"/>)=<xsl:value-of select="sum(key('KeyItem',@item)/@area)"/></p> 
       </xsl:if>
      </xsl:for-each> ----------
      <br/><br/>
    </xsl:for-each>
  </html>
 </xsl:template>
</xsl:stylesheet>

当前错误输出

<html> 
 Table for style (a)
  <p>Item=a1</p>
  <p>TotalAreaOf_Items (a1)=4</p>
  <p>Item=a2</p>
  <p>TotalAreaOf_Items (a2)=4</p>
  -----------------
 Table for style (b)
  <p>Item=b1</p>
  <p>TotalAreaOf_Items (b1)=3</p>
  <p>Item=b2</p>
  <p>TotalAreaOf_Items (b2)=3</p>
</html>

预期输出

<html> 
 Table for style (a)
  <p>Style=a</p>
  <p>Item=a1</p>
  <p>TotalAreaOf_Items (a1)=2</p>
  <p>Style=a</p>
  <p>Item=a2</p>
  <p>TotalAreaOf_Items (a2)=2</p>
  -----------------
 Table for style (b)
  <p>Style=b</p>
  <p>Item=b1</p>
  <p>TotalAreaOf_Items (b1)=2</p>
  <p>Style=b</p>
  <p>Item=b2</p>
  <p>TotalAreaOf_Items (b2)=1</p>
</html>

修正方案

问题出在内部xsl:for-each中使用preceding::*[@item = current()/@item]的判断逻辑——这个轴会扫描整个文档中之前的所有节点,而非当前首字母分组内的节点,导致求和上下文出错。正确做法是在首字母分组内,再次按@item进行分组,用generate-id()获取每个Item的唯一实例。

修改后的XSLT代码如下:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">     
    <xsl:key name="KeyStyle" match="Feature" use="substring(@item,1,1)"/>
    <xsl:key name="KeyItem" match="Feature" use="@item"/>

    <xsl:template match="Features">
        <html>
            <!-- 按首字母分组 -->
            <xsl:for-each select="Feature[generate-id() = generate-id(key('KeyStyle',substring(@item,1,1))[1])]">   
                <xsl:sort select="substring(@item,1,1)" order="ascending"/> 
                Table for style (<xsl:value-of select="substring(@item,1,1)"/>)
                <!-- 存储当前首字母分组下的所有Feature节点 -->
                <xsl:variable name="currentStyleFeatures" select="key('KeyStyle',substring(@item,1,1))"/>
                <!-- 在当前分组内按@item二次分组 -->
                <xsl:for-each select="$currentStyleFeatures[generate-id() = generate-id(key('KeyItem',@item)[1])]">
                    <xsl:sort select="@item" order="ascending"/>
                    <p>Style=<xsl:value-of select="substring(@item,1,1)"/></p>  
                    <p>Item=<xsl:value-of select="@item"/></p>  
                    <p>TotalAreaOf_Items (<xsl:value-of select="@item"/>)=<xsl:value-of select="sum(key('KeyItem',@item)/@area)"/></p> 
                </xsl:for-each>
                ----------
                <br/><br/>
            </xsl:for-each>
        </html>
    </xsl:template>
</xsl:stylesheet>

修正说明

  1. 新增变量currentStyleFeatures限定后续分组的范围,仅处理当前首字母分组内的节点。
  2. 内部循环改用generate-id()判断每个@item的唯一实例,替代preceding::*的全局扫描,避免跨分组的节点干扰。
  3. 修正后sum(key('KeyItem',@item)/@area)可准确计算每个独立Item的area总和,不会出现首字母相同的Item累加错误。

内容的提问来源于stack exchange,提问作者kapopoulos john

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 21:55:53