如何在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
相关产品推荐
相关产品推荐

