XSLT XPath:如果更新了一个子节点,则从不同的子节点获取数据(对于同一工作人员)-如何处理?

XSLT XPath: If one child node is updated, take data from different child node (for the same worker) - how to handle?

这是我的XML(见下面的问题):

<?xml version="1.0" encoding="UTF-8"?>
<Worker_Effective_Stack_Aggregate>
<Pay_Group Name="Exempt">
    <Worker>
        <Summary>
            <Employee_ID>12345</Employee_ID>
        </Summary>
        <Effective_Change>
            <Derived_Event_Code>PGO</Derived_Event_Code>
            <Position isUpdated="1">
                <Business_Title>Test Worker</Business_Title>
                <Position_End_Date isAdded="1">6/30/2021</Position_End_Date>
            </Position>
        </Effective_Change>
    </Worker>
</Pay_Group>
<Pay_Group Name="Non-Exempt">
    <Worker>
        <Summary>
            <Employee_ID>11111</Employee_ID>
        </Summary>
        <Effective_Change>
            <Derived_Event_Code>PGI</Derived_Event_Code>
            <Position isAdded="1">
                <Business_Title>Wrong Test Worker</Business_Title>
            </Position>
        </Effective_Change>
    </Worker>
    <Worker>
        <Summary>
            <Employee_ID>12345</Employee_ID>
        </Summary>
        <Effective_Change>
            <Derived_Event_Code>PGI</Derived_Event_Code>
            <Position isAdded="1">
                <Business_Title>Senior Test Worker</Business_Title>
            </Position>
        </Effective_Change>
    </Worker>
</Pay_Group>
</Worker_Effective_Stack_Aggregate>

问题:你知道如何编写代码来遵循这个场景:'如果事件代码是'PGO'并且工人的位置更新为结束日期,在整个文件中查找与发生 'PGO' 事件的工人 ID 相同的工人的 'PGI' 事件 并提供 值,在本例中为 'Senior Test Worker'.

这是我的 XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xtt="urn:com.workday/xtt" version="2.0">
                
<xsl:output method="xml" indent="yes"/>

<xsl:variable name="SEPARATOR" select="','" as="xs:string"/>
<xsl:variable name="NEWLINE" select="'&#xD;&#xA;'" as="xs:string"/>

<xsl:template match="/">
    <File>
        <Header xtt:endTag="{$NEWLINE}" xtt:separator="{$SEPARATOR}">
            <Business_Title>Business Title</Business_Title>
        </Header>
        <xsl:apply-templates select="Worker_Effective_Stack_Aggregate/Pay_Group/Worker"/>
    </File>
</xsl:template>

<xsl:template match="Worker">
    <Employee xtt:endTag="{$NEWLINE}" xtt:separator="{$SEPARATOR}" xtt:quotes="never">
    
        <Business_Title>
            <xsl:choose>
                <xsl:when test="Effective_Change/Derived_Event_Code = 'PGO'">
                    <xsl:value-of select="../../../Worker_Effective_Stack_Aggregate/Pay_Group/Worker [Effective_Change/Derived_Event_Code = 'PGI' and Summary/Employee_ID = '12345']/Effective_Change/Position/Business_Title"/>
                </xsl:when>
            </xsl:choose>
        </Business_Title>

    </Employee>
</xsl:template>

</xsl:stylesheet>

如果您需要上述所有内容的背景知识:在我们的 HCM 系统中 'Workday',每当有人更改薪酬组和职位时,Workday 都会为他们创建两个事件,一个称为 'PGO'(支付组出站),第二个称为 'PGI'(支付组入站)。如果位置发生变化,新的只会反映在 'PGI' 事件中,我需要以某种方式将其带入 'PGO' 事件详细信息中。

预期输出:

<?xml version="1.0"?>
<File xmlns:xtt="urn:com.workday/xtt">
  <Header xtt:endTag="&#13;&#10;" xtt:separator=",">
    <Business_Title>Business Title</Business_Title>
  </Header>
  <Employee xtt:endTag="&#13;&#10;" xtt:separator="," xtt:quotes="never">
    <Business_Title>Senior Test Worker</Business_Title>
  </Employee>
  <Employee xtt:endTag="&#13;&#10;" xtt:separator="," xtt:quotes="never">
    <Business_Title/>
  </Employee>
  <Employee xtt:endTag="&#13;&#10;" xtt:separator="," xtt:quotes="never">
    <Business_Title/>
  </Employee>
</File>

使用基于键和模板的匹配,您可以使用

从相关元素中提取标题
  <xsl:key name="bus-title-by-id"
           match="Worker/Effective_Change[Derived_Event_Code = 'PGI']/Position/Business_Title" 
           use="ancestor::Worker/Summary/Employee_ID"/>
  
  <xsl:template match="Worker/Effective_Change[Derived_Event_Code = 'PGO']/Position[@isUpdated = 1][Position_End_Date]/Business_Title[key('bus-title-by-id', ancestor::Worker/Summary/Employee_ID)]">
    <xsl:sequence select="key('bus-title-by-id', ancestor::Worker/Summary/Employee_ID)"/>
  </xsl:template>

如果文档的其余部分需要原封不动地复制,请使用身份转换模板进行处理

<xsl:template match="@* | node()">
  <xsl:copy>
    <xsl:apply-templates select="@* | node()"/>
  </xsl:copy>
</xsl:template>

至于你自己的代码,现在添加,使用current()比较两个元素(即一个与你查找的另一个匹配):

<xsl:template match="Worker">
    <Employee xtt:endTag="{$NEWLINE}" xtt:separator="{$SEPARATOR}" xtt:quotes="never">
    
        <Business_Title>
            <xsl:choose>
                <xsl:when test="Effective_Change/Derived_Event_Code = 'PGO'">
                    <xsl:value-of select="../../../Worker_Effective_Stack_Aggregate/Pay_Group/Worker [Effective_Change/Derived_Event_Code = 'PGI' and Summary/Employee_ID = current()/Summary/Employee_ID]/Effective_Change/Position/Business_Title"/>
                </xsl:when>
            </xsl:choose>
        </Business_Title>

    </Employee>
</xsl:template>

最后,密钥的使用使此类查找更快更有效:

<xsl:template match="Worker">
    <Employee xtt:endTag="{$NEWLINE}" xtt:separator="{$SEPARATOR}" xtt:quotes="never">
    
        <Business_Title>
            <xsl:choose>
                <xsl:when test="Effective_Change/Derived_Event_Code = 'PGO'">
                    <xsl:value-of select="key('bus-title-by-id', Summary/Employee_ID)"/>
                </xsl:when>
            </xsl:choose>
        </Business_Title>

    </Employee>
</xsl:template>

<xsl:key name="bus-title-by-id"
           match="Worker/Effective_Change[Derived_Event_Code = 'PGI']/Position/Business_Title" 
           use="ancestor::Worker/Summary/Employee_ID"/>

在最后两个示例中,xsl:choose/when 似乎不必要地复杂,一个简单的 xsl:if 就足够了。