Справка XSLT. Сохраните сопоставление полей в переменной и сгруппируйте входную полезную нагрузку на основе этого сопоставления.

У меня есть файл XML, который необходимо преобразовать в текстовый файл с разделителями каналов. Кроме того, XML-файл содержит устаревшие коды оплаты, которые необходимо преобразовать в коды будущих состояний в выходном файле. Сопоставление между этими кодами либо 1:1, либо М:1. Например, если 4 строки входных данных с разными кодами соответствуют одному коду в будущем состоянии, на выходе должна быть одна строка с суммированными суммами. Вот пример,

XML:

<?xml version="1.0" encoding="UTF-8"?>
<wd:Report_Data xmlns:wd="urn:com.workday.report/ERP-PAY-CR_PAYROLL_BALANCES_-_CX">
<wd:Report_Entry>
<wd:Legal_Entity_Name wd:Descriptor="Wayne Enterprises">
<wd:ID wd:type="WID">66b06c2b4ec001df7d2d7875ea020e52</wd:ID>
<wd:ID wd:type="Organization_Reference_ID">G01A</wd:ID>
<wd:ID wd:type="Company_Reference_ID">G01A</wd:ID>
</wd:Legal_Entity_Name>
<wd:Person_Number>2100003</wd:Person_Number>
<wd:Calendar_Quarter wd:Descriptor="2019-Q1">
<wd:ID wd:type="WID">da9970b23fce10001102e89a634e0024</wd:ID>
<wd:ID wd:type="Calendar_Quarter">2019-Q1</wd:ID>
</wd:Calendar_Quarter>
<wd:Pay_Component_Code>102</wd:Pay_Component_Code>
<wd:Result_Line_Amount>14326.91</wd:Result_Line_Amount>
</wd:Report_Entry>
<wd:Report_Entry>
<wd:Legal_Entity_Name wd:Descriptor="Wayne Enterprises">
<wd:ID wd:type="WID">66b06c2b4ec001df7d2d7875ea020e52</wd:ID>
<wd:ID wd:type="Organization_Reference_ID">G01A</wd:ID>
<wd:ID wd:type="Company_Reference_ID">G01A</wd:ID>
</wd:Legal_Entity_Name>
<wd:Person_Number>2100003</wd:Person_Number>
<wd:Calendar_Quarter wd:Descriptor="2019-Q1">
<wd:ID wd:type="WID">da9970b23fce10001102e89a634e0024</wd:ID>
<wd:ID wd:type="Calendar_Quarter">2019-Q1</wd:ID>
</wd:Calendar_Quarter>
<wd:Pay_Component_Code>123</wd:Pay_Component_Code>
<wd:Result_Line_Amount>1175.56</wd:Result_Line_Amount>
</wd:Report_Entry>
<wd:Report_Entry>
<wd:Legal_Entity_Name wd:Descriptor="Wayne Enterprises">
<wd:ID wd:type="WID">66b06c2b4ec001df7d2d7875ea020e52</wd:ID>
<wd:ID wd:type="Organization_Reference_ID">G01A</wd:ID>
<wd:ID wd:type="Company_Reference_ID">G01A</wd:ID>
</wd:Legal_Entity_Name>
<wd:Person_Number>2100003</wd:Person_Number>
<wd:Calendar_Quarter wd:Descriptor="2019-Q1">
<wd:ID wd:type="WID">da9970b23fce10001102e89a634e0024</wd:ID>
<wd:ID wd:type="Calendar_Quarter">2019-Q1</wd:ID>
</wd:Calendar_Quarter>
<wd:Pay_Component_Code>126</wd:Pay_Component_Code>
<wd:Result_Line_Amount>2350.74</wd:Result_Line_Amount>
</wd:Report_Entry>
<wd:Report_Entry>
<wd:Legal_Entity_Name wd:Descriptor="Wayne Enterprises">
<wd:ID wd:type="WID">66b06c2b4ec001df7d2d7875ea020e52</wd:ID>
<wd:ID wd:type="Organization_Reference_ID">G01A</wd:ID>
<wd:ID wd:type="Company_Reference_ID">G01A</wd:ID>
</wd:Legal_Entity_Name>
<wd:Person_Number>2100003</wd:Person_Number>
<wd:Calendar_Quarter wd:Descriptor="2019-Q1">
<wd:ID wd:type="WID">da9970b23fce10001102e89a634e0024</wd:ID>
<wd:ID wd:type="Calendar_Quarter">2019-Q1</wd:ID>
</wd:Calendar_Quarter>
<wd:Pay_Component_Code>217</wd:Pay_Component_Code>
<wd:Result_Line_Amount>0.85</wd:Result_Line_Amount>
</wd:Report_Entry>
<wd:Report_Entry>
<wd:Legal_Entity_Name wd:Descriptor="Wayne Enterprises">
<wd:ID wd:type="WID">66b06c2b4ec001df7d2d7875ea020e52</wd:ID>
<wd:ID wd:type="Organization_Reference_ID">G01A</wd:ID>
<wd:ID wd:type="Company_Reference_ID">G01A</wd:ID>
</wd:Legal_Entity_Name>
<wd:Person_Number>2100003</wd:Person_Number>
<wd:Calendar_Quarter wd:Descriptor="2019-Q1">
<wd:ID wd:type="WID">da9970b23fce10001102e89a634e0024</wd:ID>
<wd:ID wd:type="Calendar_Quarter">2019-Q1</wd:ID>
</wd:Calendar_Quarter>
<wd:Pay_Component_Code>225</wd:Pay_Component_Code>
<wd:Result_Line_Amount>1.03</wd:Result_Line_Amount>
</wd:Report_Entry>
<wd:Report_Entry>
<wd:Legal_Entity_Name wd:Descriptor="Wayne Enterprises">
<wd:ID wd:type="WID">66b06c2b4ec001df7d2d7875ea020e52</wd:ID>
<wd:ID wd:type="Organization_Reference_ID">G01A</wd:ID>
<wd:ID wd:type="Company_Reference_ID">G01A</wd:ID>
</wd:Legal_Entity_Name>
<wd:Person_Number>2100003</wd:Person_Number>
<wd:Calendar_Quarter wd:Descriptor="2019-Q1">
<wd:ID wd:type="WID">da9970b23fce10001102e89a634e0024</wd:ID>
<wd:ID wd:type="Calendar_Quarter">2019-Q1</wd:ID>
</wd:Calendar_Quarter>
<wd:Pay_Component_Code>353</wd:Pay_Component_Code>
<wd:Result_Line_Amount>21.84</wd:Result_Line_Amount>
</wd:Report_Entry>
<wd:Report_Entry>
<wd:Legal_Entity_Name wd:Descriptor="Wayne Enterprises">
<wd:ID wd:type="WID">66b06c2b4ec001df7d2d7875ea020e52</wd:ID>
<wd:ID wd:type="Organization_Reference_ID">G01A</wd:ID>
<wd:ID wd:type="Company_Reference_ID">G01A</wd:ID>
</wd:Legal_Entity_Name>
<wd:Person_Number>2100003</wd:Person_Number>
<wd:Calendar_Quarter wd:Descriptor="2019-Q1">
<wd:ID wd:type="WID">da9970b23fce10001102e89a634e0024</wd:ID>
<wd:ID wd:type="Calendar_Quarter">2019-Q1</wd:ID>
</wd:Calendar_Quarter>
<wd:Pay_Component_Code>420</wd:Pay_Component_Code>
<wd:Result_Line_Amount>1632.61</wd:Result_Line_Amount>
</wd:Report_Entry>

</wd:Report_Data>

Справочник по сопоставлению:

Legacy Codes   Future State Values
102            Regular
123            Regular
126            Regular
217            Diff Shift Prod
225            Diff Shift Prod
353            PTO Donation
420            PTO Donation

Ожидаемый результат:

Legal Entity Name|Person Number|Calendar Quarter|Pay Component Code|Result Line Amount
Wayne Enterprises|2100003|2019-Q1|Regular|17853.21
Wayne Enterprises|2100003|2019-Q1|Diff Shift Prod|1.88
Wayne Enterprises|2100003|2019-Q1|PTO Donation|1654.45

По сути, я бы хотел создать переменную сопоставления, и я могу жестко кодировать все сопоставления в своем коде и группировать суммы на основе нового кода. Прикрепляю свой xsl-код, если он чем-то поможет. Любая помощь приветствуется.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    xmlns:wd="urn:com.workday.report/ERP-PAY-CR_PAYROLL_BALANCES_-_CX"
    version="2.0">
    <xsl:output method="text"/>
    <xsl:variable name="linefeed" select="'&#xD;&#xA;'"/>
    <xsl:variable name="pipe" select="'|'"/>
    <xsl:variable name="EffectiveStartDate" select="'1951-01-01'"/>
    <xsl:variable name="EffectiveEndDate" select="'4712-12-31'"/>

    <xsl:param name="quote">"</xsl:param>
    <xsl:template match="/">
        <!--  File Header Record  -->
        <!-- ERP1 -->
        <xsl:call-template name="Write-Header-Record0"/>
        <!--  File Detail Layout  -->
        <xsl:for-each
            select="wd:Report_Data/wd:Report_Entry">

                <xsl:call-template name="Write-Detail-Record"/>

        </xsl:for-each>
    </xsl:template>

    <!-- File Header Record 0-->
    <xsl:template name="Write-Header-Record0">

        <xsl:text>Legal Entity Name|Person Number|Calendar Quarter|Pay Component Code|Result Line Amount</xsl:text>

        <xsl:value-of select="$linefeed"/>
    </xsl:template>

    <xsl:template name="Write-Detail-Record">

        <xsl:value-of select="wd:Legal_Entity_Name/@wd:Descriptor"/>
        <xsl:value-of select="$pipe"/>

        <xsl:value-of select="wd:Person_Number"/>
        <xsl:value-of select="$pipe"/>

        <xsl:value-of select="wd:Calendar_Quarter/@wd:Descriptor"/>
        <xsl:value-of select="$pipe"/>

        <xsl:value-of select="wd:Pay_Component_Code"/>
        <xsl:value-of select="$pipe"/>

        <xsl:value-of select="wd:Result_Line_Amount"/>



        <xsl:value-of select="$linefeed"/>


    </xsl:template>

</xsl:stylesheet>

person abishek rao    schedule 16.03.2020    source источник
comment
В вашем примере все записи имеют одно и то же имя юридического лица, номер лица и календарный квартал. Всегда ли так будет? Если нет, то что должна представлять каждая строка вывода?   -  person michael.hor257k    schedule 16.03.2020
comment
Спасибо Михаил за ваш ответ. Это отлично сработало для моих образцов данных. Отличный вопрос! Сумма должна быть сгруппирована на основе кодов оплаты для уникальной комбинации Номер лица › Юридический работодатель › Календарный квартал. Нужно ли обновлять значение группировки, чтобы включить эти три атрибута? Кроме того, не могли бы вы помочь мне понять синтаксис: group-by=key('paycode', wd:Pay_Component_Code, $payCodes), так как мне, возможно, придется его улучшить.   -  person abishek rao    schedule 16.03.2020
comment
Я считаю, что вам нужно сначала сгруппировать по комбинации этих трех свойств, а затем выполнить группировку, показанную в моем ответе, в каждой внешней группе. -- Не уверен, какая часть синтаксиса нуждается в пояснении. Ключ выбирает payCode на legacyCode, поэтому вызов ключа с любым из его устаревших кодов выбирает правильный payCode. Дополнительную информацию см. на странице w3.org/TR/xslt20/#key.   -  person michael.hor257k    schedule 16.03.2020
comment
Благодарю вас! Очень помог. Я столкнулся с другой проблемой. Во входном xml есть некоторые устаревшие коды, которые не отображаются в XSLT. В этих случаях я хотел бы, чтобы программа печатала одну строку для каждого устаревшего кода с именем компонента устаревшей оплаты и соответствующей суммой. Прямо сейчас программа группирует все неопознанные устаревшие коды и печатает одну строку с суммой суммы. Возможно ли это сделать? Пожалуйста, дайте мне знать, если это должно быть еще одно сообщение.   -  person abishek rao    schedule 05.04.2020
comment
Попробуйте разветвить обработку каждой группы на основе существования current-grouping-key().   -  person michael.hor257k    schedule 05.04.2020
comment
Благодарю вас! Как вы сказали, я применил условие для печати, только если существует совпадение в ключе. Я запустил программу для одной компании, и она работала нормально. Когда я запускаю его для другой компании, я получаю следующую ошибку: последовательность из более чем одного элемента не допускается в качестве первого аргумента concat() (‹payCode/›, ‹payCode/›) Line: 1786 Column: 11 Я понимаю это происходит, когда узел в контексте имеет несколько дочерних элементов. Не могли бы вы объяснить, где может быть проблема? Редактор Oxygen выделяет весь XML-файл, указывая на предупреждение. Входной XML-файл слишком длинный для анализа проблемы. Размещение моего xslt в моем следующем комментарии.   -  person abishek rao    schedule 29.04.2020
comment
Я не знаю. Я предлагаю вам опубликовать новый вопрос с минимально воспроизводимым примером, показывающим текущую проблему.   -  person michael.hor257k    schedule 29.04.2020
comment
Без проблем. Здесь размещен новый вопрос: stackoverflow.com/questions/61490430/ Любое руководство очень полезно.   -  person abishek rao    schedule 29.04.2020


Ответы (1)


Попробуйте это в качестве отправной точки:

XSLT 2.0

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:wd="urn:com.workday.report/ERP-PAY-CR_PAYROLL_BALANCES_-_CX">
<xsl:output method="text"/>

<xsl:variable name="payCodes">
    <payCode name="Regular">
        <legacyCode>102</legacyCode>
        <legacyCode>123</legacyCode>
        <legacyCode>126</legacyCode>
    </payCode>
    <payCode name="Diff Shift Prod">
        <legacyCode>217</legacyCode>
        <legacyCode>225</legacyCode>
    </payCode>
    <payCode name="PTO Donation">
        <legacyCode>353</legacyCode>
        <legacyCode>420</legacyCode>
    </payCode>
</xsl:variable>

<xsl:key name="paycode" match="payCode" use="legacyCode" />

<xsl:template match="/wd:Report_Data">
    <xsl:variable name="common">
        <xsl:value-of select="wd:Report_Entry[1]/wd:Legal_Entity_Name/@wd:Descriptor"/>
        <xsl:text>|</xsl:text>
        <xsl:value-of select="wd:Report_Entry[1]/wd:Person_Number"/>
        <xsl:text>|</xsl:text>
        <xsl:value-of select="wd:Report_Entry[1]/wd:Calendar_Quarter/@wd:Descriptor"/>
        <xsl:text>|</xsl:text>
    </xsl:variable>
    <!-- HEADER -->
    <xsl:text>Legal Entity Name|Person Number|Calendar Quarter|Pay Component Code|Result Line Amount&#xD;&#xA;</xsl:text>
    <!-- DATA -->
    <xsl:for-each-group select="wd:Report_Entry" group-by="key('paycode', wd:Pay_Component_Code, $payCodes)">
        <xsl:value-of select="$common"/>
        <xsl:value-of select="key('paycode', wd:Pay_Component_Code, $payCodes)/@name"/>
        <xsl:text>|</xsl:text>
        <xsl:value-of select="sum(current-group()/wd:Result_Line_Amount)"/>
        <xsl:text>&#xD;&#xA;</xsl:text>
    </xsl:for-each-group>
</xsl:template>

</xsl:stylesheet>

Демо: https://xsltfiddle.liberty-development.net/6pS26mw

person michael.hor257k    schedule 16.03.2020
comment
Упрощение: <xsl:value-of select="wd:Report_Entry[1]/(wd:Legal_Entity_Name/@wd:Descriptor, wd:Person_Number, wd:Calendar_Quarter/@wd:Descriptor)" separator="|"/> - person Michael Kay; 16.03.2020