如何用XSLT实现按日期分组聚合及取最后值的XML转换?
用XSLT实现XML分组聚合转换需求
需要将给定XML转换为指定的CSV格式,每条输出记录包含:
- 员工姓名
- 职位
- 日期(同一日期仅出现一次)
- 该日期下最后一条
In_Time(无则留空) - 该日期下最后一条
Out_Time(无则留空) - 当日所有
Hours的总和
此前尝试先按ID分组,再按Details/Date分组,但未能成功将同日期的记录归为一组。
示例输出
Bill,President,2025-07-01-07:00,2025-07-01T08:00:00-04:00,2025-07-01T12:00:00-04:00,4 Scott,Vice President,2025-07-03-07:00,,8 Scott,Vice President,2025-07-07-07:00,,8 Scott,Vice President,2025-07-08-07:00,,8
示例XML
<Data> <Entry> <ID>1</ID> <Name>Bill</Name> <Title>President</Title> <Details> <Date>2025-07-01-07:00</Date> <In_Time>2025-07-01T08:00:00-04:00</In_Time> <Out_Time>2025-07-01T12:00:00-04:00</Out_Time> <Hours>4</Hours> <Type>PTO</Type> </Details> <Details> <Date>2025-07-01-07:00</Date> <In_Time>2025-07-01T08:00:00-04:00</In_Time> <Out_Time>2025-07-01T15:00:00-04:00</Out_Time> <Hours>2</Hours> <Type>PTO</Type> </Details> <Details> <Date>2025-07-01-07:00</Date> <In_Time>2025-07-01T08:00:00-04:00</In_Time> <Out_Time>2025-07-01T12:00:00-04:00</Out_Time> <Hours>-2</Hours> <Type>PTO</Type> </Details> </Entry> <Entry> <ID>2</ID> <Name>Scott</Name> <Title>Vice President</Title> <Details> <Date>2025-07-03-07:00</Date> <Hours>8</Hours> <Type>Holiday</Type> </Details> <Details> <Date>2025-07-07-07:00</Date> <Hours>8</Hours> <Type>Holiday</Type> </Details> <Details> <Date>2025-07-08-07:00</Date> <Hours>8</Hours> <Type>PTO</Type> </Details> </Entry> </Data>
解决方案XSLT代码
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text" encoding="UTF-8"/> <!-- 按员工ID分组 --> <xsl:for-each-group select="/Data/Entry" group-by="ID"> <!-- 在员工组内按日期分组 --> <xsl:for-each-group select="current-group()/Details" group-by="Date"> <xsl:value-of select="ancestor::Entry/Name"/> <xsl:text>,</xsl:text> <xsl:value-of select="ancestor::Entry/Title"/> <xsl:text>,</xsl:text> <xsl:value-of select="current-grouping-key()"/> <xsl:text>,</xsl:text> <!-- 取当日最后一条记录的In_Time --> <xsl:value-of select="current-group()[last()]/In_Time"/> <xsl:text>,</xsl:text> <!-- 取当日最后一条记录的Out_Time --> <xsl:value-of select="current-group()[last()]/Out_Time"/> <xsl:text>,</xsl:text> <!-- 计算当日Hours总和 --> <xsl:value-of select="sum(current-group()/Hours)"/> <xsl:text> </xsl:text> </xsl:for-each-group> </xsl:for-each-group> </xsl:stylesheet>
实现思路
- 利用XSLT 2.0的分组功能,先按
Entry/ID分组,确保同一员工的记录归为一组; - 在每个员工组内,再按
Details/Date分组,聚合同一日期的所有详情记录; - 对每个日期组:
- 提取员工姓名和职位信息;
- 输出分组日期;
- 取该组最后一条记录的
In_Time和Out_Time(无对应节点则自动留空); - 使用
sum()函数计算当日所有Hours的总和;
- 输出格式为CSV,用逗号分隔字段,换行符分隔每条记录。
内容的提问来源于stack exchange,提问作者BryanG
相关产品推荐
相关产品推荐

