XSL按Byordnum和Num分组计算小计问题求助
XML分组小计问题解决方案
问题描述
需要基于Byordnum和Num两个字段对XML中的<Line>元素分组,计算Delqua字段的小计,但当前XSL代码未生效,输出与输入完全一致。
输入XML
<DeliHomeBasic_DesAdv> <InboundDlvNumber/> <ExternalDlvNumber>WSP0059837_SCU0000001_1</ExternalDlvNumber> <DeliveryDate>2023-01-16</DeliveryDate> <SupplierName>Weekamp Doors SRO</SupplierName> <Cpss> <Cps> <Line>1</Line> <Subline>0</Subline> <Pacs> <Pac> <Qua>1</Qua> </Pac> </Pacs> </Cps> <Cps> <Line>2</Line> <Subline>1</Subline> <Pacs> <Pac> <Qua>1</Qua> <Iso>2</Iso> <Sscc>WPA0135955</Sscc> <Sscc2>80689</Sscc2> </Pac> </Pacs> <Lines> <Line> <Num>00960</Num> <Byart>WK_RA_UITZET</Byart> <Desc>Top hang window, 895x1370x54 FSCHW</Desc> <Delqua>1</Delqua> <Byordnum>4500428486</Byordnum> </Line> <Line> <Num>00960</Num> <Byart>WK_RA_UITZET</Byart> <Desc>Top hang window, 895x1370x54 FSCHW</Desc> <Delqua>1</Delqua> <Byordnum>4500428486</Byordnum> </Line> <Line> <Num>00960</Num> <Byart>WK_RA_UITZET</Byart> <Desc>Top hang window, 895x1370x54 FSCHW</Desc> <Delqua>1</Delqua> <Byordnum>4500428486</Byordnum> </Line> <Line> <Num>00970</Num> <Byart>WK_RA_UITZET</Byart> <Desc>Top hang window, 895x1495x54 FSCHW</Desc> <Delqua>1</Delqua> <Byordnum>4500428486</Byordnum> </Line> <Line> <Num>00970</Num> <Byart>WK_RA_UITZET</Byart> <Desc>Top hang window, 895x1495x54 FSCHW</Desc> <Delqua>1</Delqua> <Byordnum>4500428486</Byordnum> </Line> <Line> <Num>00990</Num> <Gtin/> <Byart>WK_TB_DEUR</Byart> <Desc>WK046, 830x2120x38 FSC® cert. Premium Hardwood</Desc> <Delqua>1</Delqua> <Byordnum>4500428486</Byordnum> <Suordnum>SOR0061481</Suordnum> </Line> </Lines> </Cps> </Cpss> </DeliHomeBasic_DesAdv>
现有XSL代码
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:strip-space elements="*"/> <xsl:output indent="yes"/> <xsl:key name="k1" match="/Line" use="concat(Byordnum, '|', Num, '|', generate-id(..))"/> <!-- identity transform --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <xsl:template match="/Lines"> <xsl:copy> <xsl:for-each select="/Lines[generate-id()=generate-id(key('k1', concat(Byordnum,'|',Num, '|', generate-id(..)))[1])]"> <xsl:copy> <xsl:copy-of select="Num"/> <xsl:copy-of select="Gtin"/> <xsl:copy-of select="Byart"/> <Delqua> <xsl:value-of select="sum(key('k1', concat(Byordnum,'|',Num, '|', generate-id(..)))/Delqua)" /> </Delqua> <xsl:copy-of select="Byordnum"/> <xsl:copy-of select="Suordnum"/> </xsl:copy> </xsl:for-each> </xsl:copy> </xsl:template> </xsl:stylesheet>
期望输出
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <DeliHomeBasic_DesAdv> <InboundDlvNumber/> <ExternalDlvNumber>WSP0059837_SCU0000001_1</ExternalDlvNumber> <DeliveryDate>2023-01-16</DeliveryDate> <SupplierName>Weekamp Doors SRO</SupplierName> <Cpss> <Cps> <Line>1</Line> <Subline>0</Subline> <Pacs> <Pac> <Qua>1</Qua> </Pac> </Pacs> </Cps> <Cps> <Line>2</Line> <Subline>1</Subline> <Pacs> <Pac> <Qua>1</Qua> <Iso>2</Iso> <Sscc>WPA0135955</Sscc> <Sscc2>80689</Sscc2> </Pac> </Pacs> <Lines> <Line> <Num>00960</Num> <Byart>WK_RA_UITZET</Byart> <Desc>Top hang window, 895x1370x54 FSCHW</Desc> <Delqua>3</Delqua> <Byordnum>4500428486</Byordnum> </Line> <Line> <Num>00970</Num> <Byart>WK_RA_UITZET</Byart> <Desc>Top hang window, 895x1495x54 FSCHW</Desc> <Delqua>2</Delqua> <Byordnum>4500428486</Byordnum> </Line> <Line> <Num>00990</Num> <Gtin/> <Byart>WK_TB_DEUR</Byart> <Desc>WK046, 830x2120x38 FSC® cert. Premium Hardwood</Desc> <Delqua>1</Delqua> <Byordnum>4500428486</Byordnum> <Suordnum>SOR0061481</Suordnum> </Line> </Lines> </Cps> </Cpss> </DeliHomeBasic_DesAdv>
问题原因及修正方案
问题分析
- 节点匹配路径错误:
xsl:key中match="/Line"试图匹配根节点下的<Line>,但实际<Line>嵌套在<Lines>内部,应改为相对路径match="Line"。- 模板
match="/Lines"同样错误,根节点下无直接的<Lines>,需改为match="Lines"以匹配所有嵌套的<Lines>节点。
- 分组逻辑错误:
xsl:for-each选择的是<Lines>节点而非<Line>节点,无法实现按<Line>分组。- 分组键多余加入了父节点ID
generate-id(..),导致相同Byordnum+Num的<Line>被错误拆分。
- 节点遗漏:原代码未复制
<Desc>节点,无法匹配期望输出中的该字段。
修正后的XSL代码
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:strip-space elements="*"/> <xsl:output indent="yes"/> <!-- 按Byordnum和Num的组合作为分组键 --> <xsl:key name="k1" match="Line" use="concat(Byordnum, '|', Num)"/> <!-- 身份转换模板:复制未被特殊处理的节点 --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <!-- 处理Lines节点,生成分组后的Line元素 --> <xsl:template match="Lines"> <xsl:copy> <!-- 选择每个分组中的第一个Line节点,作为分组代表 --> <xsl:for-each select="Line[generate-id() = generate-id(key('k1', concat(Byordnum, '|', Num))[1])]"> <xsl:copy> <!-- 复制Line下除Delqua外的所有必要子节点 --> <xsl:copy-of select="Num|Gtin|Byart|Desc|Byordnum|Suordnum"/> <!-- 计算当前分组的Delqua总和 --> <Delqua> <xsl:value-of select="sum(key('k1', concat(Byordnum, '|', Num))/Delqua)"/> </Delqua> </xsl:copy> </xsl:for-each> </xsl:copy> </xsl:template> </xsl:stylesheet>
修正说明
- 简化分组键:仅使用
Byordnum和Num的组合,确保相同属性的<Line>被归为一组。 - 修正匹配路径:确保能正确定位到所有
<Line>和<Lines>节点。 - 补全节点复制:加入
<Desc>节点的复制,符合期望输出要求。 - 正确分组选择:通过
generate-id()筛选每个分组的第一个<Line>,实现分组去重并计算小计。
内容的提问来源于stack exchange,提问作者Mike Dole
相关产品推荐
相关产品推荐

