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

如何在XSLT 2.0中对XML的连续Time_Off_Date分组生成CSV?

当然可以!用XSLT 2.0轻松实现无递归的连续日期分组转CSV

刚接触XSLT的话,你可能还没意识到——XSLT 2.0的xsl:for-each-group配合group-adjacent属性,简直是处理这类连续序列分组问题的神器,完全不需要写递归函数。我给你一步步拆解怎么实现:

先假设你的XML结构(如果和实际有出入,调整XPath就行)

比如常见的请假记录XML大概是这样:

<TimeOffRecords>
  <Record>
    <EmployeeID>EMP001</EmployeeID>
    <Time_Off_Date>2024-05-01</Time_Off_Date>
    <Reason>Vacation</Reason>
  </Record>
  <Record>
    <EmployeeID>EMP001</EmployeeID>
    <Time_Off_Date>2024-05-02</Time_Off_Date>
    <Reason>Vacation</Reason>
  </Record>
  <Record>
    <EmployeeID>EMP001</EmployeeID>
    <Time_Off_Date>2024-05-04</Time_Off_Date>
    <Reason>Sick Leave</Reason>
  </Record>
  <Record>
    <EmployeeID>EMP002</EmployeeID>
    <Time_Off_Date>2024-05-01</Time_Off_Date>
    <Reason>Vacation</Reason>
  </Record>
</TimeOffRecords>

对应的XSLT 2.0代码

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:xs="http://www.w3.org/2001/XMLSchema"
                exclude-result-prefixes="xs">

  <!-- 输出纯文本格式的CSV,禁用缩进,确保换行正确 -->
  <xsl:output method="text" encoding="UTF-8" indent="no"/>

  <!-- 先输出CSV表头 -->
  <xsl:template match="/">
    <xsl:text>EmployeeID,StartDate,EndDate,Reason&#10;</xsl:text>
    <xsl:apply-templates select="TimeOffRecords/Record"/>
  </xsl:template>

  <!-- 核心分组逻辑:先按员工ID分组,再在每组内按连续日期分组 -->
  <xsl:template match="Record">
    <!-- 第一步:把同一个员工的记录归为一组 -->
    <xsl:for-each-group select="." group-by="EmployeeID">
      <!-- 第二步:在员工组内,把连续的日期归为一组 -->
      <xsl:for-each-group select="current-group()" 
                          group-adjacent="xs:date(Time_Off_Date) - xs:dayTimeDuration('P' || position() - 1 || 'D')">
        <!-- 输出当前连续日期组的CSV行 -->
        <xsl:value-of select="current-group()[1]/EmployeeID"/>
        <xsl:text>,</xsl:text>
        <xsl:value-of select="current-group()[1]/Time_Off_Date"/> <!-- 连续日期的起始 -->
        <xsl:text>,</xsl:text>
        <xsl:value-of select="current-group()[last()]/Time_Off_Date"/> <!-- 连续日期的结束 -->
        <xsl:text>,</xsl:text>
        <xsl:value-of select="current-group()[1]/Reason"/> <!-- 假设同一连续组的原因一致,取第一个 -->
        <xsl:text>&#10;</xsl:text> <!-- 换行 -->
      </xsl:for-each-group>
    </xsl:for-each-group>
  </xsl:template>

</xsl:stylesheet>

关键逻辑解释

  • 双重分组:先按EmployeeID分组,避免不同员工的日期被错误合并;再在每个员工的记录里处理连续日期。
  • 连续日期分组的核心:group-adjacent="xs:date(Time_Off_Date) - xs:dayTimeDuration('P' || position() - 1 || 'D')"
    这个表达式的作用是:把每个日期转换成xs:date类型,然后减去它在当前员工组内的位置对应的天数(比如第1条记录减0天,第2条减1天,以此类推)。连续的日期会得到同一个基准日期,比如2024-05-01减0天是2024-05-01,2024-05-02减1天也是2024-05-01,所以这两个会被分到同一组;而2024-05-04减2天是2024-05-02,和前面的基准不同,就会单独成组。
  • CSV输出:每组连续日期输出一行,包含员工ID、起始日期、结束日期、请假原因,用逗号分隔,每行末尾加换行符。

调整提示

如果你的XML字段名、结构和示例不一样,只需要修改对应的XPath即可:

  • 比如如果Time_Off_Date在别的节点下,就把Time_Off_Date改成完整路径,比如LeaveDetails/Time_Off_Date
  • 如果需要输出更多字段,在CSV行里添加对应的<xsl:value-of>和分隔符就行

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 07:38:01