Как получить количество строк и общую сумму значений полей через XSLT? - PullRequest
0 голосов
/ 24 июня 2019

У меня есть следующие требования к формату файла, где мне нужно получить количество строк и общую сумму поля.В этом примере есть три строки со столбцом, который имеет значения суммы, а в четвертой строке мне понадобится общее количество строк и сумма сумм для заполнения.

Alex, Scot              10091978       90.00
Brad, Ander             23061976       40.00
Rodney, Philips         04091983       35.00
03 165.00

XML Input

 <wd:Report_Data 
 xmlns:wd="urn:com.workday.report/INT001_Test_Reward_Report">
 <wd:Report_Entry>
 <wd:Worker_group>
 <wd:Employee_ID>12344</wd:Employee_ID>
 <wd:dateOfBirth>1975-05-06</wd:dateOfBirth>
 <wd:lastName>Alex</wd:lastName>
 <wd:firstName>Scot</wd:firstName>
 <wd:Pay_Frequency>M1</wd:Pay_Frequency>
 </wd:Worker_group>
 <wd:Payroll_Result_group>
 <wd:Payment_Date>2019-04-02</wd:Payment_Date>
 </wd:Payroll_Result_group>
 <wd:Payroll_Result_Line_group>
 <wd:Result_Line_Amount>40</wd:Result_Line_Amount>
 </wd:Payroll_Result_Line_group>
 </wd:Report_Entry>
 <wd:Report_Entry>
 <wd:Worker_group>
 <wd:Employee_ID>12355</wd:Employee_ID>
 <wd:dateOfBirth>1958-05-06</wd:dateOfBirth>
 <wd:lastName>Hyrus</wd:lastName>
 <wd:firstName>Marike</wd:firstName>
 <wd:Pay_Frequency>M1</wd:Pay_Frequency>
 </wd:Worker_group>
 <wd:Payroll_Result_group>
 <wd:Payment_Date>2019-04-04</wd:Payment_Date>
 </wd:Payroll_Result_group>
 <wd:Payroll_Result_Line_group>
 <wd:Result_Line_Amount>10</wd:Result_Line_Amount>
 </wd:Payroll_Result_Line_group>
 </wd:Report_Entry>
 <wd:Report_Entry>
 <wd:Worker_group>
 <wd:Employee_ID>12366</wd:Employee_ID>
 <wd:dateOfBirth>1986-09-10</wd:dateOfBirth>
 <wd:lastName>Elite</wd:lastName>
 <wd:firstName>Samsung</wd:firstName>
 <wd:Pay_Frequency>M1</wd:Pay_Frequency>
 </wd:Worker_group>
 <wd:Payroll_Result_group>
 <wd:Payment_Date>2019-04-02</wd:Payment_Date>
 </wd:Payroll_Result_group>
 <wd:Payroll_Result_Line_group>
 <wd:Result_Line_Amount>30</wd:Result_Line_Amount>
 </wd:Payroll_Result_Line_group>
 </wd:Report_Entry>
 </wd:Report_Data>

   XSLT I have tried so far

 <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:wd="urn:com.workday.report/INT001_Test_Reward_Report"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:this="urn:this-stylesheet"
version="2.0" exclude-result-prefixes="xs this">

<!--**************************************************************************************-->
<!--    Date           XSLT Attachment Design                                             -->
<!--    06-17-2019     Transformation to transform file format from xml to .txt(fixed )   -->
<!--**************************************************************************************-->
<!--    06-17-2019     Initial Version                                                    -->
<!--**************************************************************************************-->

<!--The final output file will be text formatted with an encoding of *NA*-->
<xsl:output encoding="UTF-8" method="text" use-character-maps="custom-char-filter" />

<!--declare global variables here such as delimiter and linefeed-->
    <xsl:variable name="vDelimiter" select="''"/>
<xsl:variable name="linefeed" select="'&#13;&#10;'" />
    <xsl:variable name="linefeed2" select="'
    '"/>
    <xsl:variable name="vWrapQuotes" select="false()"/>
    <xsl:variable name="vDateFormat" select="'[Y0001][M01][D01]'"/>
    <xsl:variable name="vDateTimeFormat" select="'[D01]-[MN,*-3]-[Y0001]T[H01]:[m01]:[s01]'"/>
    <xsl:variable name="pDateValue" select="current-date()"/>
    <xsl:variable name="SumAmount" select="0"/>
     <xsl:variable name="i" select="0"/>

<!--Root Template-->
<xsl:template match="wd:Report_Data">

    <!--declare root variables here such as current datetime or other repeating values-->


    <xsl:value-of select="this:setOutput(this:formatDate($pDateValue))" />
    <xsl:value-of select="$linefeed"/>

    <!--Process detail records-->
    <xsl:apply-templates select="wd:Report_Entry" />

    <xsl:text>T</xsl:text>
    <xsl:value-of select="$i"/>
    <xsl:value-of select="$SumAmount"/>

</xsl:template>

<!--Detail Record Template-->
<xsl:template match="wd:Report_Entry">

    <!--
    Detail Record


    -->

    <!--Record Type - -->
    <xsl:text>D</xsl:text>
    <xsl:value-of select="this:setOutput(this:fixedWidth(wd:Worker_group/wd:Employee_ID, ' ', 8, 'left'))" />
    <xsl:value-of select="this:setOutput(this:fixedWidth((this:formatDate(wd:Worker_group/wd:dateOfBirth)), ' ', 8, 'left'))" />
    <xsl:value-of select="this:setOutput(this:fixedWidth(wd:Worker_group/wd:lastName, ' ', 40,'left'))" />
    <xsl:value-of select="this:setOutput(this:fixedWidth(wd:Worker_group/wd:firstName, ' ', 40, 'left'))" />
    <xsl:value-of select="this:setOutput(this:fixedWidth(wd:Payroll_Result_Line_group/wd:Result_Line_Amount, ' ', 9, 'left'))" />
    <xsl:value-of select="this:setOutput(this:fixedWidth(wd:Worker_group/wd:Pay_Frequency, ' ', 2, 'left'))" />
    <xsl:value-of select="this:setOutput(this:fixedWidth((this:formatDate(wd:Payroll_Result_group/wd:Payment_Date)), ' ', 8, 'left'))" />
    <xsl:variable name="Amount" select="this:setOutput(wd:Payroll_Result_Line_group/wd:Result_Line_Amount)"/>
    <xsl:value-of select="$Amount"/>
    <xsl:variable name="i" select="position()"/>
    <xsl:value-of select="$i"/>
    <xsl:variable name="SumAmount" select="$SumAmount + $Amount"/>
    <xsl:value-of select="$linefeed" />     

    </xsl:template>
    <!--********************************************************************************************  -->
    <!--This function returns the input value followed by a delmiter                                  -->
    <!--********************************************************************************************  -->
    <xsl:function name="this:setOutput">
    <xsl:param name="value" />

    <xsl:value-of select="this:setOutput($value,false())"/>
    </xsl:function>

    <!--********************************************************************************************  -->
    <!--This function returns the input value followed by a delmiter                                  -->
    <!--********************************************************************************************  -->
    <xsl:function name="this:setOutput">
    <xsl:param name="value" />
    <xsl:param name="finalValue" as="xs:boolean"/>

    <xsl:variable name="vWrappedValue">
        <xsl:value-of select="if($vWrapQuotes = false()) then $value else this:wrapQuotes($value)"/>            
    </xsl:variable>

    <xsl:value-of select="if ($finalValue = false()) then concat(string($vWrappedValue),$vDelimiter) else $vWrappedValue"/>

    </xsl:function>

    <!--********************************************************************************************  -->
    <!--This function is designed to wrap a string in quotes if required                              -->
    <!--********************************************************************************************  -->  
    <xsl:function name="this:wrapQuotes">
    <xsl:param name="field"/>
    <xsl:value-of select="'&quot;'"/>
    <xsl:value-of select="replace($field,'&quot;','&quot;&quot;')"/>
    <xsl:value-of select="'&quot;'"/>
    </xsl:function>

    <!--********************************************************************************************  -->
    <!--This function is designed to pad a string to the left or right to a fixed number of characters-->
    <!--    str: a string input                                                                       -->
    <!--    chr: a character used for padding                                                         -->
    <!--    len: a number of defining the total length of the output                                  -->
    <!--    dir: the direction of the alignment default is left; right if specified)                  -->
    <!--         Note: if something is aligned left it will be padded on the right and vice versa     --> 
    <!--********************************************************************************************  -->
    <xsl:function name="this:padString">
    <xsl:param name="str" />
    <xsl:param name="chr" />
    <xsl:param name="len" />
    <xsl:param name="dir" />

    <xsl:variable name="padLength">
        <xsl:value-of select="$len - string-length($str)" />
    </xsl:variable>

    <xsl:variable name="pad">
        <xsl:for-each select="1 to $padLength">
            <xsl:value-of select="$chr" />
        </xsl:for-each>
    </xsl:variable>

    <xsl:value-of select="if ($dir = 'right') then concat($str,$pad) else concat($pad,$str)" />

    </xsl:function>

    <!--********************************************************************************************    -->
    <!--This function is designed to align a string to the left or right to a fixed number of characters-->
    <!--    str: a string input                                                                         -->
    <!--    chr: a character used for padding                                                           -->
    <!--    len: a number of defining the total length of the output                                    -->
    <!--    dir: the direction of the alignment default is left; right if specified)                    -->
    <!--         Note: if something is aligned left it will be padded on the right and vice versa       -->    
    <!--********************************************************************************************    -->
    <xsl:function name="this:fixedWidth">
    <xsl:param name="str" />
    <xsl:param name="chr" />
    <xsl:param name="len" />
    <xsl:param name="dir" />        

    <xsl:variable name="padLength">
        <xsl:value-of select="$len - string-length($str)" />
    </xsl:variable>

    <xsl:variable name="pad">
        <xsl:for-each select="1 to $padLength">
            <xsl:value-of select="$chr" />
        </xsl:for-each>
    </xsl:variable>

    <xsl:value-of select="if ($dir = 'right') then substring(concat($pad,$str),1,$len) else substring(concat($str,$pad),1,$len)" />

    </xsl:function>

    <!--********************************************************************************************  -->
    <!--This function can be modified as needed for the appropriate date format                       -->
    <!--********************************************************************************************  -->    
    <xsl:function name="this:formatDate">
    <xsl:param name="pDateValue" />

    <xsl:value-of select="if (xs:string($pDateValue) = '') then '' else format-date(xs:date($pDateValue), $vDateFormat)" />

    </xsl:function>

    <xsl:function name="this:formatDateTime">
    <xsl:param name="pDateTimeValue" />

    <xsl:value-of select="if ($pDateTimeValue = '') then '' else format-dateTime(xs:dateTime($pDateTimeValue),$vDateTimeFormat )" />
    </xsl:function>

<!--*************************************************************************************************  -->
<!--Character Maps can be used to replace special and/or foreign characters where appropriate          -->
<!--The big avantage is that these don't have to be called explicitly, the processor will handle this  -->
<!--while writing the output.                                                                          -->
<!--*************************************************************************************************  -->
<xsl:character-map name="custom-char-filter">

    <xsl:output-character character="*" string="" />
    <xsl:output-character character=":" string="" />
    <xsl:output-character character="^" string="" />
    <xsl:output-character character="~" string="" />
</xsl:character-map>

    </xsl:stylesheet>

Я также пробовал использовать несколько функций xslt (Общее количество, общее количество строк), но, похоже, ничего не работает.

Спасибо, Джитендра.

1 Ответ

0 голосов
/ 24 июня 2019

Рассмотрим следующий упрощенный пример:

XML

<wd:Report_Data xmlns:wd="urn:com.workday.report/INT001_Test_Reward_Report">
    <wd:Report_Entry>
        <wd:Worker_group>
            <wd:lastName>Alex</wd:lastName>
            <wd:firstName>Scot</wd:firstName>
        </wd:Worker_group>
        <wd:Payroll_Result_Line_group>
            <wd:Result_Line_Amount>90</wd:Result_Line_Amount>
        </wd:Payroll_Result_Line_group>
    </wd:Report_Entry>
    <wd:Report_Entry>
        <wd:Worker_group>
            <wd:lastName>Brad</wd:lastName>
            <wd:firstName>Ander</wd:firstName>
        </wd:Worker_group>
        <wd:Payroll_Result_Line_group>
            <wd:Result_Line_Amount>40</wd:Result_Line_Amount>
        </wd:Payroll_Result_Line_group>
    </wd:Report_Entry>
    <wd:Report_Entry>
        <wd:Worker_group>
            <wd:lastName>Rodney</wd:lastName>
            <wd:firstName>Philips</wd:firstName>
        </wd:Worker_group>
        <wd:Payroll_Result_Line_group>
            <wd:Result_Line_Amount>35</wd:Result_Line_Amount>
        </wd:Payroll_Result_Line_group>
    </wd:Report_Entry>
</wd:Report_Data>

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:wd="urn:com.workday.report/INT001_Test_Reward_Report">
<xsl:output method="text" encoding="UTF-8" />

<xsl:template match="/wd:Report_Data">
    <!-- records -->
    <xsl:for-each select="wd:Report_Entry">
        <xsl:value-of select="wd:Worker_group/wd:lastName"/>
        <xsl:text>, </xsl:text>
        <xsl:value-of select="wd:Worker_group/wd:firstName"/>
        <xsl:text>&#9;</xsl:text>
        <xsl:value-of select="wd:Payroll_Result_Line_group/wd:Result_Line_Amount"/>
        <xsl:text>&#10;</xsl:text>
    </xsl:for-each>
    <!-- summary -->
    <xsl:value-of select="count(wd:Report_Entry)"/>
    <xsl:text>&#9;</xsl:text>
    <xsl:value-of select="sum(wd:Report_Entry/wd:Payroll_Result_Line_group/wd:Result_Line_Amount)"/>
</xsl:template>

</xsl:stylesheet>

Результат

Alex, Scot  90
Brad, Ander 40
Rodney, Philips 35
3   165
...