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

如何使用XSLT按特定日期范围对XML元素分组?

问题描述

现有如下XML数据,需通过XSLT按特定日期范围重新分组元素。每个<cust_MDFCostDistribution_child>元素包含cust_startdate和cust_EndDate日期范围,仅保留对应日期范围内的元素;当元素到期后,剩余元素从次日起重新分组,effectiveDate为cust_EndDate + xs:dayTimeDuration('P1D')。尝试过group-starting-with和group-ending-with函数但未解决问题,寻求解决方案。

输入XML

<cust_CD>
   <user>
      <userId>50298867</userId>
      <cust_MDFCostDistribution_child>
         <cust_EndDate>2023-05-31T00:00:00.000</cust_EndDate>
         <cust_startdate>2023-01-01T00:00:00.000</cust_startdate>
         <cust_percentage>20</cust_percentage>
         <cust_costCenter>N3020050</cust_costCenter>
         <cust_MDFCostDistribution_Parent_usersSysId>50298867</cust_MDFCostDistribution_Parent_usersSysId>
      </cust_MDFCostDistribution_child>
      <cust_MDFCostDistribution_child>
         <cust_EndDate>2023-02-28T00:00:00.000</cust_EndDate>
         <cust_startdate>2023-01-01T00:00:00.000</cust_startdate>
         <cust_percentage>40</cust_percentage>
         <cust_costCenter>NT7000003</cust_costCenter>
         <cust_MDFCostDistribution_Parent_usersSysId>50298867</cust_MDFCostDistribution_Parent_usersSysId>
      </cust_MDFCostDistribution_child>
      <cust_MDFCostDistribution_child>
         <cust_EndDate>2023-01-31T00:00:00.000</cust_EndDate>
         <cust_startdate>2023-01-01T00:00:00.000</cust_startdate>
         <cust_percentage>40</cust_percentage>
         <cust_costCenter>N2030020</cust_costCenter>
         <cust_MDFCostDistribution_Parent_usersSysId>50298867</cust_MDFCostDistribution_Parent_usersSysId>
      </cust_MDFCostDistribution_child>
   </user>
</cust_CD>

期望输出XML

<group>
   <date>
      <effectiveDate>2023-01-01T00:00:00.000</effectiveDate>
      <cust_MDFCostDistribution_child>
         <cust_EndDate>2023-05-31T00:00:00.000</cust_EndDate>
         <cust_startdate>2023-01-01T00:00:00.000</cust_startdate>
         <cust_percentage>20</cust_percentage>
         <cust_costCenter>N3020050</cust_costCenter>
         <cust_MDFCostDistribution_Parent_usersSysId>50298867</cust_MDFCostDistribution_Parent_usersSysId>
      </cust_MDFCostDistribution_child>
      <cust_MDFCostDistribution_child>
         <cust_EndDate>2023-02-28T00:00:00.000</cust_EndDate>
         <cust_startdate>2023-01-01T00:00:00.000</cust_startdate>
         <cust_percentage>40</cust_percentage>
         <cust_costCenter>NT7000003</cust_costCenter>
         <cust_MDFCostDistribution_Parent_usersSysId>50298867</cust_MDFCostDistribution_Parent_usersSysId>
      </cust_MDFCostDistribution_child>
      <cust_MDFCostDistribution_child>
         <cust_EndDate>2023-01-31T00:00:00.000</cust_EndDate>
         <cust_startdate>2023-01-01T00:00:00.000</cust_startdate>
         <cust_percentage>40</cust_percentage>
         <cust_costCenter>N2030020</cust_costCenter>
         <cust_MDFCostDistribution_Parent_usersSysId>50298867</cust_MDFCostDistribution_Parent_usersSysId>
      </cust_MDFCostDistribution_child>
   </date>
   <date>
      <effectiveDate>2023-02-01T00:00:00.000</effectiveDate>
      <cust_MDFCostDistribution_child>
         <cust_EndDate>2023-05-31T00:00:00.000</cust_EndDate>
         <cust_startdate>2023-01-01T00:00:00.000</cust_startdate>
         <cust_percentage>20</cust_percentage>
         <cust_costCenter>N3020050</cust_costCenter>
         <cust_MDFCostDistribution_Parent_usersSysId>50298867</cust_MDFCostDistribution_Parent_usersSysId>
      </cust_MDFCostDistribution_child>
      <cust_MDFCostDistribution_child>
         <cust_EndDate>2023-02-28T00:00:00.000</cust_EndDate>
         <cust_startdate>2023-01-01T00:00:00.000</cust_startdate>
         <cust_percentage>40</cust_percentage>
         <cust_costCenter>NT7000003</cust_costCenter>
         <cust_MDFCostDistribution_Parent_usersSysId>50298867</cust_MDFCostDistribution_Parent_usersSysId>
      </cust_MDFCostDistribution_child>
   </date>
   <date>
      <effectiveDate>2023-03-01T00:00:00.000</effectiveDate>
      <cust_MDFCostDistribution_child>
         <cust_EndDate>2023-05-31T00:00:00.000</cust_EndDate>
         <cust_startdate>2023-01-01T00:00:00.000</cust_startdate>
         <cust_percentage>20</cust_percentage>
         <cust_costCenter>N3020050</cust_costCenter>
         <cust_MDFCostDistribution_Parent_usersSysId>50298867</cust_MDFCostDistribution_Parent_usersSysId>
      </cust_MDFCostDistribution_child>
   </date>
   <date>
      <effectiveDate>2023-06-01T00:00:00.000</effectiveDate>
   </date>
</group>

逻辑说明

  • 仅保留落在对应日期范围内的元素
  • 元素到期后,剩余元素从次日起重新分组,effectiveDate为cust_EndDate + xs:dayTimeDuration('P1D')
  • 示例分组:
    • 2023-01-01至01-31:三个元素有效
    • 2023-02-01至02-28:两个元素有效
    • 2023-03-01至05-31:一个元素有效
    • 2023-06-01起:无有效元素
XSLT解决方案

使用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">
    <xsl:output method="xml" indent="yes"/>

    <!-- 获取所有关键日期:起始日期、所有到期日期+1天 -->
    <xsl:variable name="allDates">
        <xsl:variable name="startDate" select="xs:dateTime(/cust_CD/user/cust_MDFCostDistribution_child[1]/cust_startdate)"/>
        <date><xsl:value-of select="$startDate"/></date>
        <xsl:for-each select="/cust_CD/user/cust_MDFCostDistribution_child">
            <date><xsl:value-of select="xs:dateTime(cust_EndDate) + xs:dayTimeDuration('P1D')"/></date>
        </xsl:for-each>
    </xsl:variable>

    <!-- 去重并按日期排序 -->
    <xsl:variable name="sortedUniqueDates" select="distinct-values($allDates/date/xs:dateTime(.))" as="xs:dateTime*">
        <xsl:sort select="."/>
    </xsl:variable>

    <xsl:template match="/">
        <group>
            <xsl:for-each select="$sortedUniqueDates">
                <xsl:variable name="currentEffectiveDate" select="."/>
                <date>
                    <effectiveDate><xsl:value-of select="$currentEffectiveDate"/></effectiveDate>
                    <!-- 筛选当前生效日期范围内的元素 -->
                    <xsl:for-each select="/cust_CD/user/cust_MDFCostDistribution_child[
                        xs:dateTime(cust_startdate) le $currentEffectiveDate 
                        and $currentEffectiveDate le xs:dateTime(cust_EndDate)
                    ]">
                        <xsl:copy-of select="."/>
                    </xsl:for-each>
                </date>
            </xsl:for-each>
        </group>
    </xsl:template>
</xsl:stylesheet>
方案解释
  1. 提取关键日期:收集所有元素的起始日期、每个元素到期日期的次日,这些日期是分组的节点
  2. 去重排序:对收集到的日期去重并按时间顺序排序,确保分组按时间推进
  3. 生成分组:遍历每个关键日期,将其设为effectiveDate,筛选出所有在该日期仍有效的元素(起始日期≤当前生效日期≤结束日期),并复制到对应分组中
  4. 空分组处理:当某一关键日期没有有效元素时,自动生成仅包含effectiveDate的空<date>节点,符合输出要求

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 19:01:28