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

XSLT3.0累加器Map仅返回最后元素问题排查求助

问题

使用XSLT 3.0的accumulator map时,无论匹配情况如何,查询总是仅返回最后一个元素。预期行为是:针对cal:timeoff节点,将其中的cal:person元素值与wd:Report_Data节点下wd:Report_Entry中的wd:Person_Id和wd:Wiser_ID映射关联,返回对应的Wiser_ID。

输入XML

<?xml version="1.0" encoding="utf-8"?>
<AggregatedData xmlns:wkd="urn:Workday_timeoff_Extract" xmlns:cal="urn:calabrio"
   xmlns:wd="urn:com.workday.report/CR_Calabrio_TO_Eligible_Worker_Report">
   <wd:Report_Data>
      <wd:Report_Entry>
         <wd:Person_Id>473937f5922241879d30afe000c44702</wd:Person_Id>
         <wd:Wiser_ID>10636</wd:Wiser_ID>
      </wd:Report_Entry>
      <wd:Report_Entry>
         <wd:Person_Id/>
         <wd:Wiser_ID>EE1111</wd:Wiser_ID>
      </wd:Report_Entry>
   </wd:Report_Data>
   <cal:stack>
      <cal:timeoff>
         <cal:person>473937f5922241879d30afe000c44702</cal:person>
         <cal:key>20241101USAABS002450</cal:key>
         <cal:date>2024-11-01</cal:date>
         <cal:timeofftype>USA_ABS002</cal:timeofftype>
         <cal:hours>4.50</cal:hours>
      </cal:timeoff>
   </cal:stack>
   <wkd:TimeOff-Stack>
      <wkd:TimeOff-Entry>
         <wkd:WiserID>10636</wkd:WiserID>
         <wkd:wd-key>20241107USAABS002800</wkd:wd-key>
         <wkd:Date>2024-11-07</wkd:Date>
         <wkd:Timeoff>USA_ABS002</wkd:Timeoff>
         <wkd:Hours>8.00</wkd:Hours>
         <wkd:EntryID>TIME_OFF_ENTRY-6-1136743</wkd:EntryID>
      </wkd:TimeOff-Entry>
   </wkd:TimeOff-Stack>
</AggregatedData>

现有XSLT代码

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="3.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:wkd="urn:Workday_timeoff_Extract"
    xmlns:map="http://www.w3.org/2005/xpath-functions/map"
    xmlns:cal="urn:calabrio"
    xmlns:wd="urn:com.workday.report/CR_Calabrio_TO_Eligible_Worker_Report"
    exclude-result-prefixes="#all">
    <xsl:output method="xml" indent = "yes"  />
    <xsl:mode streamable="no" on-no-match="shallow-copy" use-accumulators="calpersonids idmap"/>
    
    <xsl:accumulator name="calpersonids" as="xs:string" initial-value="''"  streamable="no">
        <xsl:accumulator-rule match="wd:Person_Id/text()" select="normalize-space()"/>
    </xsl:accumulator>
    <xsl:accumulator name="idmap" as="map(xs:string,xs:string)" initial-value="map{}"  streamable="no">
        <xsl:accumulator-rule match="wd:Wiser_ID/text()" select="map:put($value, accumulator-before('calpersonids'),normalize-space())"/>
    </xsl:accumulator>
    
    <xsl:template match="AggregatedData">
        <xsl:apply-templates select="copy-of(cal:stack/cal:timeoff)"/>
    </xsl:template>
    
    <xsl:template match="cal:timeoff">
            <cal:timeoff>
                <cal:wiserid><xsl:value-of select="accumulator-before('idmap')(cal:person)"/></cal:wiserid>
                <cal:personid><xsl:value-of select="cal:person"/></cal:personid>
                <cal:key><xsl:value-of select="cal:key"/></cal:key>
                <cal:date><xsl:value-of select="cal:date"/></cal:date>
                <cal:timeofftype><xsl:value-of select="cal:timeofftype"/></cal:timeofftype>
                <cal:hours><xsl:value-of select="cal:hours"/></cal:hours>    
            </cal:timeoff> 
    </xsl:template>
    
</xsl:stylesheet>

当前输出

<?xml version="1.0" encoding="UTF-8"?>
<cal:timeoff xmlns:cal="urn:calabrio">
   <cal:wiserid>EE1111</cal:wiserid>
   <cal:personid>473937f5922241879d30afe000c44702</cal:personid>
   <cal:key>20241101USAABS002450</cal:key>
   <cal:date>2024-11-01</cal:date>
   <cal:timeofftype>USA_ABS002</cal:timeofftype>
   <cal:hours>4.50</cal:hours>
</cal:timeoff>

期望输出

<?xml version="1.0" encoding="UTF-8"?>
<cal:timeoff xmlns:cal="urn:calabrio">
   <cal:wiserid>10636</cal:wiserid>
   <cal:key>20241101USAABS002450</cal:key>
   <cal:date>2024-11-01</cal:date>
   <cal:timeofftype>USA_ABS002</cal:timeofftype>
   <cal:hours>4.50</cal:hours>
</cal:timeoff>
解决方案

问题原因

  1. calpersonids累加器未重置:当前calpersonids仅在匹配到wd:Person_Id/text()时更新,但第二个wd:Report_Entry中的wd:Person_Id是空节点,无文本节点,导致累加器保留第一个Person_Id的值。处理第二个Wiser_ID时,会用该旧值覆盖map中对应条目,最终473937f5922241879d30afe000c44702对应的Wiser_ID被替换为EE1111。
  2. 空Person_Id处理缺失:未针对空wd:Person_Id节点重置calpersonids,导致无效映射被写入map。

修改后的XSLT代码

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="3.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:wkd="urn:Workday_timeoff_Extract"
    xmlns:map="http://www.w3.org/2005/xpath-functions/map"
    xmlns:cal="urn:calabrio"
    xmlns:wd="urn:com.workday.report/CR_Calabrio_TO_Eligible_Worker_Report"
    exclude-result-prefixes="#all">
    <xsl:output method="xml" indent = "yes"  />
    <xsl:mode streamable="no" on-no-match="shallow-copy" use-accumulators="calpersonids idmap"/>
    
    <xsl:accumulator name="calpersonids" as="xs:string?" initial-value="()"  streamable="no">
        <!-- 匹配wd:Person_Id节点,无论是否有文本都更新值 -->
        <xsl:accumulator-rule match="wd:Person_Id" select="normalize-space(.)"/>
        <!-- 每个wd:Report_Entry结束时重置累加器,避免影响下一条目 -->
        <xsl:accumulator-rule match="wd:Report_Entry" phase="end" select="()"/>
    </xsl:accumulator>
    
    <xsl:accumulator name="idmap" as="map(xs:string,xs:string)" initial-value="map{}"  streamable="no">
        <!-- 仅当calpersonids有有效值时,才写入map -->
        <xsl:accumulator-rule match="wd:Wiser_ID/text()" 
            select="if (exists(accumulator-before('calpersonids')) and accumulator-before('calpersonids') != '')
                    then map:put($value, accumulator-before('calpersonids'), normalize-space())
                    else $value"/>
    </xsl:accumulator>
    
    <xsl:template match="AggregatedData">
        <xsl:apply-templates select="copy-of(cal:stack/cal:timeoff)"/>
    </xsl:template>
    
    <xsl:template match="cal:timeoff">
        <cal:timeoff>
            <cal:wiserid><xsl:value-of select="accumulator-before('idmap')(cal:person)"/></cal:wiserid>
            <cal:key><xsl:value-of select="cal:key"/></cal:key>
            <cal:date><xsl:value-of select="cal:date"/></cal:date>
            <cal:timeofftype><xsl:value-of select="cal:timeofftype"/></cal:timeofftype>
            <cal:hours><xsl:value-of select="cal:hours"/></cal:hours>    
        </cal:timeoff> 
    </xsl:template>
    
</xsl:stylesheet>

修改说明

  1. 调整calpersonids累加器:
    • 类型改为xs:string?允许空值,初始值设为()(空序列);
    • 匹配wd:Person_Id节点而非文本节点,确保空节点也能获取空值;
    • 添加phase="end"规则,在每个wd:Report_Entry处理完成后重置累加器,避免条目间值复用。
  2. 优化idmap累加器:
    • 增加条件判断,仅当calpersonids存在且非空时,才将映射写入map,跳过空Person_Id的无效条目。
  3. 对齐期望输出:移除了多余的cal:personid节点。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 10:25:55