在使用 XSLT 分组和转置数据方面需要帮助

Need help in grouping and transposing data using XSLT

我在条件分组和转置 XML 数据方面需要帮助。

  1. 我需要使用月份中的星期几、工作人员 ID 和 Rate_Category_Code 对数据进行分组和转置。需要在适当的周内报告 Hours_Worked。其他一周的时间都是空白的。 XML 中的数据永远不会超过一个月。
  2. 如果报告了加班时间(由 Rate_Category_Code 标识为加班),那么我需要为报告加班时间的那一周创建单独的行。

下面是 XML 数据 -

``

<?xml version="1.0" encoding="UTF-8"?>
<wd:Report_Data xmlns:wd="urn:com.workday.report/INT1120_CR_HR_Fieldglass_Daily_Timesheet">
    <wd:Report_Entry>
        <wd:Worker_ID>FNRAWK00001743</wd:Worker_ID>
        <wd:Task_Code>01</wd:Task_Code>
        <wd:GL_Account_Code>Default</wd:GL_Account_Code>
        <wd:Rate_Category_Code>ST</wd:Rate_Category_Code>
        <wd:UOM>HR</wd:UOM>
        <wd:Hours_Worked>8</wd:Hours_Worked>
        <wd:Reported_Date>2019-06-10</wd:Reported_Date>
    </wd:Report_Entry>
    <wd:Report_Entry>
        <wd:Worker_ID>FNRAWK00001743</wd:Worker_ID>
        <wd:Task_Code>01</wd:Task_Code>
        <wd:GL_Account_Code>Default</wd:GL_Account_Code>
        <wd:Rate_Category_Code>ST</wd:Rate_Category_Code>
        <wd:UOM>HR</wd:UOM>
        <wd:Hours_Worked>8</wd:Hours_Worked>
        <wd:Reported_Date>2019-06-18</wd:Reported_Date>
    </wd:Report_Entry>
    <wd:Report_Entry>
        <wd:Worker_ID>FNRAWK00001743</wd:Worker_ID>
        <wd:Task_Code>01</wd:Task_Code>
        <wd:GL_Account_Code>Default</wd:GL_Account_Code>
        <wd:Rate_Category_Code>OT</wd:Rate_Category_Code>
        <wd:UOM>HR</wd:UOM>
        <wd:Hours_Worked>1</wd:Hours_Worked>
        <wd:Reported_Date>2019-06-10</wd:Reported_Date>
    </wd:Report_Entry>
    <wd:Report_Entry>
        <wd:Worker_ID>FNRAWK00001742</wd:Worker_ID>
        <wd:Task_Code>01</wd:Task_Code>
        <wd:GL_Account_Code>Default</wd:GL_Account_Code>
        <wd:Rate_Category_Code>ST</wd:Rate_Category_Code>
        <wd:UOM>HR</wd:UOM>
        <wd:Hours_Worked>9</wd:Hours_Worked>
        <wd:Reported_Date>2019-06-20</wd:Reported_Date>
    </wd:Report_Entry>
</wd:Report_Data>

``

期望的输出 -

``

Type=Upload Full Time Sheet with Revision
Transaction=True
Approval Required=True
Messaging Required=False
Language=English (United States)
Number Format=#,##9.99 (Example: 1,234,567.99)
Date Format=MM/DD/YYYY
Submit=FALSE
Buyer=FNRA
Supplier Review=False
Comments=

Worker_ID|Month_Start_Date|First_Monday|Cost_Center_Code|Task_Code|GL_Account_Code|Rate_Category_Code|UOM|Mon_Hrs|Tue_Hrs|Wed_Hrs|Thu_Hrs|Fri_Hrs|Sat_Hrs|Sun_Hrs
FNRAWK00001743|06/01/2019|05/27/2019||01|Default|ST|HR||||||||
FNRAWK00001743|06/01/2019|06/03/2019||01|Default|ST|HR||||||||
FNRAWK00001743|06/01/2019|06/10/2019||01|Default|ST|HR|8|||||||
FNRAWK00001743|06/01/2019|06/10/2019||01|Default|OT|HR|1|||||||
FNRAWK00001743|06/01/2019|06/17/2019||01|Default|ST|HR||8||||||
FNRAWK00001743|06/01/2019|06/24/2019||01|Default|ST|HR||||||||
FNRAWK00001742|06/01/2019|05/27/2019||01|Default|ST|HR||||||||
FNRAWK00001742|06/01/2019|06/03/2019||01|Default|ST|HR||||||||
FNRAWK00001742|06/01/2019|06/10/2019||01|Default|ST|HR||||||||
FNRAWK00001742|06/01/2019|06/10/2019||01|Default|OT|HR||||||||
FNRAWK00001742|06/01/2019|06/17/2019||01|Default|ST|HR||||9||||
FNRAWK00001742|06/01/2019|06/24/2019||01|Default|ST|HR||||||||

``

XSLT -

``

 <?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" xmlns:wd="urn:com.workday.report/INT1120_CR_HR_Fieldglass_Daily_Timesheet" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:my="http://www.example.com/my" xmlns:functx="http://www.functx.com" exclude-result-prefixes="xs my functx">
        <xsl:output method="text" version="1.0" encoding="UTF-8" indent="no"/>
        <xsl:variable name="Linefeed" select="'&#13;&#10;'"/>
        <xsl:variable name="Delimiter" select=" '|' "/>
        <xsl:function name="functx:repeat-string" as="xs:string">
            <xsl:param name="stringToRepeat" as="xs:string?"/>
            <xsl:param name="count" as="xs:integer"/>
            <xsl:sequence select="string-join((for $i in 1 to $count return $stringToRepeat),'')"/>
        </xsl:function>
        <xsl:function name="functx:pad-integer-to-length" as="xs:string">
            <xsl:param name="integerToPad" as="xs:anyAtomicType?"/>
            <xsl:param name="length" as="xs:integer"/>
            <xsl:sequence select="if ($length &lt; string-length(string($integerToPad))) then error(xs:QName('functx:Integer_Longer_Than_Length')) else concat (functx:repeat-string('0',$length - string-length(string($integerToPad))),string($integerToPad))"/>
        </xsl:function>
        <xsl:function name="functx:date" as="xs:date">
            <xsl:param name="year" as="xs:anyAtomicType"/>
            <xsl:param name="month" as="xs:anyAtomicType"/>
            <xsl:param name="day" as="xs:anyAtomicType"/>
            <xsl:sequence select="xs:date(concat(functx:pad-integer-to-length(xs:integer($year),4),'-',functx:pad-integer-to-length(xs:integer($month),2),'-',functx:pad-integer-to-length(xs:integer($day),2)))"/>
        </xsl:function>
        <!--Function which accepts date as input and returns the date for first day of the month (Input Date)-->
        <xsl:function name="functx:first-day-of-month" as="xs:date?">
            <xsl:param name="date" as="xs:anyAtomicType?"/>
            <xsl:sequence select="functx:date(year-from-date(xs:date($date)),month-from-date(xs:date($date)),1)"/>
        </xsl:function>
        <!--Function which accepts date as input and returns the date for first day of the week-->
        <xsl:function name="my:thisMonday">
            <xsl:param name="date"/>
            <xsl:variable name="epoch" select="xs:date('0001-01-01')"/>
            <xsl:variable name="dayNumber" select="fn:days-from-duration($date - $epoch)"/>
            <xsl:variable name="dayOfWeek" select="$dayNumber mod 7"/>
            <xsl:value-of select="$date - xs:dayTimeDuration(concat('P', $dayOfWeek, 'D' ))"/>
        </xsl:function>
        <xsl:template match="wd:Report_Data">
            <File>
                <Header>
                    <xsl:text>Type=Upload Full Time Sheet with Revision</xsl:text>
                    <xsl:value-of select="$Linefeed"/>
                    <xsl:text>Transaction=True</xsl:text>
                    <xsl:value-of select="$Linefeed"/>
                    <xsl:text>Approval Required=True</xsl:text>
                    <xsl:value-of select="$Linefeed"/>
                    <xsl:text>Messaging Required=False</xsl:text>
                    <xsl:value-of select="$Linefeed"/>
                    <xsl:text>Language=English (United States)</xsl:text>
                    <xsl:value-of select="$Linefeed"/>
                    <xsl:text>Number Format=#,##9.99 (Example: 1,234,567.99)</xsl:text>
                    <xsl:value-of select="$Linefeed"/>
                    <xsl:text>Date Format=MM/DD/YYYY</xsl:text>
                    <xsl:value-of select="$Linefeed"/>
                    <xsl:text>Submit=FALSE</xsl:text>
                    <xsl:value-of select="$Linefeed"/>
                    <xsl:text>Buyer=FNRA</xsl:text>
                    <xsl:value-of select="$Linefeed"/>
                    <xsl:text>Supplier Review=False</xsl:text>
                    <xsl:value-of select="$Linefeed"/>
                    <xsl:text>Comments=</xsl:text>
                    <xsl:value-of select="$Linefeed"/>
                </Header>
                <xsl:value-of select="$Linefeed"/>
                <Header>
                    <xsl:text>Worker_ID|Date|Week_Start_Date|Cost_Center_Code|Task_Code|GL_Account_Code|Rate_Category_Code|UOM|Mon_Hrs|Tue_Hrs|Wed_Hrs|Thu_Hrs|Fri_Hrs|Sat_Hrs|Sun_Hrs</xsl:text>
                    <xsl:value-of select="$Linefeed"/>
                </Header>
                <xsl:for-each select="wd:Report_Entry">
                    <xsl:call-template name="Write_Rows"/>
                </xsl:for-each>
            </File>
        </xsl:template>
        <xsl:template name="Write_Rows">
            <Record>
                <Worker_ID>
                    <xsl:value-of select="wd:Worker_ID"/>
                </Worker_ID>
                <xsl:value-of select="$Delimiter"/>
                <Date>
                    <!--<xsl:value-of select="concat(substring(wd:Date,6, 2),'/',substring(wd:Date, 9, 2),'/',substring(wd:Date, 1, 4))"/>-->
                    <!--Pass date in YYYY-MM-DD format to custom function and format the return value to 'MM/DD/YYYY'-->
                    <xsl:variable name="StartDateOfMonth" select="string(functx:first-day-of-month(xs:date(concat(substring(wd:Reported_Date, 1, 4),'-', substring(wd:Reported_Date,6, 2),'-',substring(wd:Reported_Date, 9, 2)))))"/>
                    <xsl:value-of select="concat(substring($StartDateOfMonth,6,2),'/',substring($StartDateOfMonth,9,2),'/',substring($StartDateOfMonth,1,4))"/>
                </Date>
                <xsl:value-of select="$Delimiter"/>
                <Week_Start_Date>
                    <!--<xsl:variable name="WeekStartDate" select="my:thisMonday(xs:date('2019-06-01'))"/>-->
                    <!--Format the return value to 'MM/DD/YYYY'-->
                    <xsl:variable name="WeekStartDate" select="my:thisMonday(xs:date(wd:Reported_Date))"/>
                    <xsl:value-of select="concat(substring($WeekStartDate,6,2),'/',substring($WeekStartDate,9,2),'/',substring($WeekStartDate,1,4))"/>
                </Week_Start_Date>
                <xsl:value-of select="$Delimiter"/>
                <Cost_Center_Code>
                    <xsl:value-of select="wd:Cost_Center_Code"/>
                </Cost_Center_Code>
                <xsl:value-of select="$Delimiter"/>
                <Task_Code>
                    <xsl:value-of select="wd:Task_Code"/>
                </Task_Code>
                <xsl:value-of select="$Delimiter"/>
                <GL_Account_Code>
                    <xsl:value-of select="wd:GL_Account_Code"/>
                </GL_Account_Code>
                <xsl:value-of select="$Delimiter"/>
                <Rate_Category_Code>
                    <xsl:value-of select="wd:Rate_Category_Code"/>
                </Rate_Category_Code>
                <xsl:value-of select="$Delimiter"/>
                <UOM>
                    <xsl:value-of select="wd:UOM"/>
                </UOM>
                <xsl:value-of select="$Delimiter"/>
                <Hours_Worked>
                    <xsl:value-of select="wd:Hours_Worked"/>
                </Hours_Worked>
                <xsl:value-of select="$Delimiter"/>
                <Overtime>
                    <xsl:value-of select="wd:Overtime"/>
                </Overtime>
                <xsl:value-of select="$Linefeed"/>
            </Record>
        </xsl:template>
    </xsl:stylesheet>

``

我认为部分任务是使用复合键进行分组,例如在 XSLT 3 中:

<xsl:for-each-group select="wd:Report_Entry" composite="yes" group-by="wd:Worker_ID, wd:Rate_Category_Code, my:thisMonday(xs:date(wd:Reported_Date))">
    <xsl:value-of select="current-grouping-key(), sum(current-group()/wd:Hours_Worked)" separator="|"/>
    <xsl:text>&#10;</xsl:text>
</xsl:for-each-group>

即给出现有数据:

FNRAWK00001743|ST|2019-06-10|8
FNRAWK00001743|ST|2019-06-17|8
FNRAWK00001743|OT|2019-06-10|1
FNRAWK00001742|ST|2019-06-17|9

您将需要添加逻辑以输出没有数据的周的空行。