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

XSLT 2.0 for-each-group按索引计算修改EndDate元素值问题

问题诊断

两个核心错误导致第二个Person的EndDate为空:

  • 你在xsl:for-each-group的分组上下文中直接调用following-sibling::StartDate,获取的是原始Start_Dates节点下未分组去重的后续节点,而非当前分组后排序的节点列表,following-sibling::StartDate[$i+1]在第二个分组中无匹配节点,因此输出空值。
  • 你未对分组后的StartDate做显式排序,若原始StartDate顺序紊乱会直接导致EndDate计算逻辑完全失效。
修复思路
  1. 先将分组去重后的StartDate按日期升序排序,存入变量获得固定顺序的节点列表,直接通过位置索引获取下一个StartDate
  2. 拆分独立模板实现不同功能:
    • 根节点处理模板:负责构造输出XML的根结构
    • CompoundEmployee节点处理模板:负责提取去重排序后的日期列表
    • Person节点生成模板:负责生成每个Person节点的基础结构
    • EndDate计算模板:负责根据当前节点位置计算对应EndDate
    • 关联信息拷贝模板:负责拷贝当前日期对应的人员、职位等关联信息,可直接扩展你注释的逻辑
完整修复后的XSLT代码
<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" version="1.0" encoding="UTF-8" indent="yes"/>

<!-- 根节点处理模板 -->
<xsl:template match="/queryCompoundEmployeeResponse">
    <queryCompoundEmployeeResponse>
        <xsl:apply-templates select="CompoundEmployee"/>
    </queryCompoundEmployeeResponse>
</xsl:template>

<!-- CompoundEmployee节点处理模板 -->
<xsl:template match="CompoundEmployee">
    <xsl:copy>
        <xsl:variable name="person" select="person" />
        <!-- 提取去重排序后的StartDate列表 -->
        <xsl:variable name="sortedStartDates" as="xs:date*">
            <xsl:for-each-group select="Start_Dates/StartDate" group-by=".">
                <xsl:sort select="xs:date(.)" order="ascending"/>
                <xsl:sequence select="xs:date(.)"/>
            </xsl:for-each-group>
        </xsl:variable>
        <!-- 遍历生成每个Person节点 -->
        <xsl:for-each select="$sortedStartDates">
            <xsl:call-template name="generatePerson">
                <xsl:with-param name="currentStartDate" select="."/>
                <xsl:with-param name="position" select="position()"/>
                <xsl:with-param name="totalCount" select="count($sortedStartDates)"/>
                <xsl:with-param name="sortedStartDates" select="$sortedStartDates"/>
                <xsl:with-param name="lastEndDate" select="End_Dates/EndDate[last()]"/>
                <xsl:with-param name="personNode" select="$person"/>
            </xsl:call-template>
        </xsl:for-each>
    </xsl:copy>
</xsl:template>

<!-- Person节点生成模板 -->
<xsl:template name="generatePerson">
    <xsl:param name="currentStartDate" as="xs:date"/>
    <xsl:param name="position" as="xs:integer"/>
    <xsl:param name="totalCount" as="xs:integer"/>
    <xsl:param name="sortedStartDates" as="xs:date*"/>
    <xsl:param name="lastEndDate"/>
    <xsl:param name="personNode"/>
    <Person>
        <StartDate><xsl:value-of select="$currentStartDate"/></StartDate>
        <!-- 调用EndDate计算模板 -->
        <xsl:call-template name="calculateEndDate">
            <xsl:with-param name="position" select="$position"/>
            <xsl:with-param name="totalCount" select="$totalCount"/>
            <xsl:with-param name="sortedStartDates" select="$sortedStartDates"/>
            <xsl:with-param name="lastEndDate" select="$lastEndDate"/>
        </xsl:call-template>
        <!-- 调用关联信息拷贝模板 你注释的代码可以在这里实现 -->
        <xsl:call-template name="copyRelatedInfo">
            <xsl:with-param name="currentStartDate" select="$currentStartDate"/>
            <xsl:with-param name="personNode" select="$personNode"/>
        </xsl:call-template>
    </Person>
</xsl:template>

<!-- EndDate计算模板 -->
<xsl:template name="calculateEndDate">
    <xsl:param name="position" as="xs:integer"/>
    <xsl:param name="totalCount" as="xs:integer"/>
    <xsl:param name="sortedStartDates" as="xs:date*"/>
    <xsl:param name="lastEndDate"/>
    <EndDate>
        <xsl:choose>
            <!-- 最后一个节点用输入的最后一个EndDate -->
            <xsl:when test="$position = $totalCount">
                <xsl:value-of select="$lastEndDate"/>
            </xsl:when>
            <!-- 其他节点取下一个StartDate的前一天 -->
            <xsl:otherwise>
                <xsl:variable name="nextStart" select="$sortedStartDates[$position + 1]"/>
                <xsl:value-of select="$nextStart - xs:dayTimeDuration('P1D')"/>
            </xsl:otherwise>
        </xsl:choose>
    </EndDate>
</xsl:template>

<!-- 关联信息拷贝模板 可扩展你需要的拷贝逻辑 -->
<xsl:template name="copyRelatedInfo">
    <xsl:param name="currentStartDate" as="xs:date"/>
    <xsl:param name="personNode"/>
    <!-- 你注释的代码可以在此处实现 示例:
    <xsl:copy-of select="$personNode/* except $personNode/(personal_information | phone_information | email_information | employment_information)"/>
    <xsl:copy-of select="$personNode/personal_information[xs:date(start_date) le $currentStartDate and $currentStartDate le xs:date(end_date)]"/>
    <xsl:copy-of select="$personNode/employment_information[xs:date(start_date) le $currentStartDate and $currentStartDate le xs:date(end_date)]"/>
    <xsl:copy-of select="$personNode/employment_information/job_information[xs:date(start_date) le $currentStartDate and $currentStartDate le xs:date(end_date)]"/> 
    -->
</xsl:template>

</xsl:stylesheet>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 04:57:01