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

如何在XML中按不同层级标签分组?求XSL实现方案指导

问题描述

现有如下源XML,包含一个头部层级标签<Tran>,其下包含行层级标签<Line>:

<Tran>
    <Company>ABC corp</Company>
    <Country>IN</Country>
    <Line>
        <No>1</No>
        <Type>Item</Type>
        <Amount>100</Amount>
    </Line>
    <Line>
        <No>2</No>
        <Type>Item</Type>
        <Amount>200</Amount>
    </Line>
    <Line>
        <No>3</No>
        <Type>Freight</Type>
        <Amount>50</Amount>
    </Line>
    <Line>
        <No>4</No>
        <Type>Freight</Type>
        <Amount>60</Amount>
    </Line>
    <Line>
        <No>5</No>
        <Type>Tax</Type>
        <Amount>100</Amount>
    </Line>
</Tran>

需要按头部层级的<Company>和行层级的<Type>进行分组,生成如下预期结果:

<Pmtheader>
    <Comp>ABC corp</Comp>
    <Type>Item</Type>
    <CountLine>2</CountLine>
    <TotalAmt>300</TotalAmt>
    <Pmtline>
        <No>1</No>
        <Amt>100</Amt>
    </Pmtline>
    <Pmtline>
        <No>2</No>
        <Amt>200</Amt>
    </Pmtline>
</Pmtheader>
<Pmtheader>
    <Comp>ABC corp</Comp>
    <Type>Freight</Type>
    <CountLine>2</CountLine>  
    <TotalAmt>110</TotalAmt>
    <Pmtline>
        <No>3</No>
        <Amt>50</Amt>
    </Pmtline>
    <Pmtline>
        <No>4</No>
        <Amt>60</Amt>
    </Pmtline>
</Pmtheader>
<Pmtheader>
    <Comp>ABC corp</Comp>
    <Type>Tax</Type>
    <CountLine>1</CountLine>  
    <TotalAmt>100</TotalAmt>
    <Pmtline>
        <No>5</No>
        <Amt>100</Amt>
    </Pmtline>
</Pmtheader>

从未使用过xsl:for-each-group和for-each函数,不知如何实现分组。

解决方案

可以使用XSLT 2.0及以上版本的xsl:for-each-group来实现按<Company>和<Type>分组,以下是完整的XSLT代码:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes"/>

    <!-- 匹配根节点,处理每个Tran元素 -->
    <xsl:template match="/">
        <xsl:apply-templates select="Tran"/>
    </xsl:template>

    <xsl:template match="Tran">
        <!-- 按Line下的Type分组,同时保留Company信息 -->
        <xsl:for-each-group select="Line" group-by="Type">
            <Pmtheader>
                <!-- 输出Company信息 -->
                <Comp><xsl:value-of select="../Company"/></Comp>
                <!-- 输出当前分组的Type -->
                <Type><xsl:value-of select="current-grouping-key()"/></Type>
                <!-- 统计当前分组的行数 -->
                <CountLine><xsl:value-of select="count(current-group())"/></CountLine>
                <!-- 计算当前分组的金额总和 -->
                <TotalAmt><xsl:value-of select="sum(current-group()/Amount)"/></TotalAmt>
                <!-- 遍历分组内的每个Line,生成Pmtline -->
                <xsl:for-each select="current-group()">
                    <Pmtline>
                        <No><xsl:value-of select="No"/></No>
                        <Amt><xsl:value-of select="Amount"/></Amt>
                    </Pmtline>
                </xsl:for-each>
            </Pmtheader>
        </xsl:for-each-group>
    </xsl:template>
</xsl:stylesheet>

关键代码解释

  • <xsl:for-each-group select="Line" group-by="Type">:选中所有<Line>元素,按<Type>的值进行分组。current-grouping-key()可获取当前分组的Type值。
  • current-group():代表当前分组内的所有<Line>元素集合,用它可以统计行数count(current-group())和计算金额总和sum(current-group()/Amount)。
  • <xsl:for-each select="current-group()">:遍历当前分组内的每个<Line>,生成对应的<Pmtline>元素。
  • ../Company:因为当前上下文是<Line>,通过../回到父节点<Tran>,获取<Company>的值。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 18:15:26