在 XSLT3 中使用累加器进行键匹配

Key Match using accumulators in XSLT3

我希望在下面的 xslt3 中使用累加器,并且只处理不匹配的键而忽略其他键。

我想遍历每个 All_Time_Offs/Time_Off,如果 Time_Off_Key 出现在 Payroll_Input/Input_Key -> 则不处理。否则处理记录

<?xml version="1.0" encoding="UTF-8"?>
<Aggregated_TimeOffs>
    <All_Payroll_Inputs>
        <Payroll_Input>
            <RefID>PAYROLL_INPUT-6-122898</RefID>
            <Emp_ID>101058</Emp_ID>
            <Earning>101D</Earning>
            <Start_Date/>
            <Adjustment>0</Adjustment>
            <Hours>4</Hours>
            <Input_Key>PAYROLL_INPUT-6-122898101D4</Input_Key>
        </Payroll_Input>
        <Payroll_Input>
            <RefID>PAYROLL_INPUT-6-122898</RefID>
            <Emp_ID>101058</Emp_ID>
            <Earning>101D</Earning>
            <Start_Date/>
            <Adjustment>0</Adjustment>
            <Hours>4</Hours>
            <Input_Key>PAYROLL_INPUT-6-122898101D9</Input_Key>
        </Payroll_Input>
    </All_Payroll_Inputs>
    <All_Time_Offs>
        <Time_Off>
            <RefID/>
            <Emp_ID>29519</Emp_ID>
            <Earning/>
            <Date>2020-09-10</Date>
            <Adjustment/>
            <Hours>7</Hours>
            <Cost_Center/>
            <Week>Week_2</Week>
            <Time_Off_Key>PAYROLL_INPUT-6-122898101D4</Time_Off_Key>
        </Time_Off>
        <Time_Off>
            <RefID/>
            <Emp_ID>68413</Emp_ID>
            <Earning/>
            <Date>2020-09-09</Date>
            <Adjustment/>
            <Hours>8</Hours>
            <Cost_Center/>
            <Week>Week_2</Week>
            <Time_Off_Key>INT024_PAYROLL_INPUT_2020-09-098</Time_Off_Key>
        </Time_Off>
    </All_Time_Offs>    
</Aggregated_TimeOffs> 

下面是我正在尝试但无法正常工作的 XSLT。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:map="http://www.w3.org/2005/xpath-functions/map"
    xmlns:err="http://www.w3.org/2005/xqt-errors"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:ext="urn:SomeExternalSource"
    xmlns:xtt="urn:com.workday/xtt"
    xmlns:wd="urn:com.workday/bsvc"
    xmlns:this="urn:com.workday/this"
    exclude-result-prefixes="xs ext map wd xtt this"
    version="3.0">
    
    <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"></xsl:output>
    
    <xsl:mode streamable="yes" on-no-match="shallow-skip" use-accumulators="Time_Off_Key Payroll_Input_lookup emp.id"/>
    
    <xsl:accumulator name="Payroll_Input_lookup" as="xs:string" initial-value="''" streamable="yes">
        <xsl:accumulator-rule match="Input_Key/text()" select="."/>
    </xsl:accumulator>
    
    <xsl:accumulator name="Time_Off_Key" as="map(xs:string,xs:string)" initial-value="map{}" streamable="yes">
        <xsl:accumulator-rule match="Time_Off_Key/text()" select="map:put($value, string(.), accumulator-before('Payroll_Input_lookup'))"/>
    </xsl:accumulator>
    
    <xsl:accumulator name="emp.id" streamable="yes" as="xs:string" initial-value="''">
        <xsl:accumulator-rule match="Emp_ID/text()" select="."/>
    </xsl:accumulator>
    
    <xsl:template match="Aggregated_TimeOffs">
        
        <xsl:for-each select="All_Time_Offs/Time_Off/copy-of()">
            
            <xsl:variable name="input_exists">
                <xsl:value-of select="accumulator-before('Time_Off_Key')(normalize-space(Time_Off_Key))"/>
            </xsl:variable>
            
            <xsl:if test="string-length($input_exists) &lt; 0">
                <xsl:copy-of select="."/>
            </xsl:if>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

如果您只想比较 Payroll_Input/Input_Key 值的“较早”解析期间出现的单个值 Time_Off_Key,那么单个 xs:string*,即基于字符串序列的累加器就足够了:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="3.0"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  exclude-result-prefixes="#all"
  expand-text="yes">

    <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
    
    <xsl:mode streamable="yes" on-no-match="shallow-skip" use-accumulators="Payroll_Input_Input_Keys"/>
    
    <xsl:accumulator name="Payroll_Input_Input_Keys" as="xs:string*" initial-value="()" streamable="yes">
        <xsl:accumulator-rule match="Payroll_Input/Input_Key/text()" select="., $value"/>
    </xsl:accumulator>
    
    <xsl:template match="Time_Off[copy-of()[not(Time_Off_Key = accumulator-before('Payroll_Input_Input_Keys'))]]">
      <xsl:copy-of select="."/>
    </xsl:template>
    
</xsl:stylesheet>

它可能不是流式的,但是,因为在模式的谓词中使用 copy-of() 打破了流式模式的无运动要求:所以我们需要写

<xsl:template match="Time_Off">
    <xsl:copy-of select="copy-of()[not(Time_Off_Key = accumulator-before('Payroll_Input_Input_Keys'))]"/>
</xsl:template>

而不是让该代码与流媒体一起工作。