У меня есть входной файл XML, который выглядит следующим образом:
<?xml version='1.0' encoding='UTF-8'?>
<root>
<entry>
<ID>T-1149</ID>
<Item_ID>FM1</Item_ID>
<Item_Amount>
<Amount>20.00</Amount>
</Item_Amount>
</entry>
<entry>
<ID>T-1149</ID>
<Item_ID>FM1</Item_ID>
<Item_Amount>
<Amount>10.00</Amount>
</Item_Amount>
</entry>
<entry>
<ID>T-1142</ID>
<Item_ID>FM1</Item_ID>
<Item_Amount>
<Amount>10.00</Amount>
</Item_Amount>
</entry>
<entry>
<ID>T-1142</ID>
<Item_ID>FM2</Item_ID>
<Item_Amount>
<Amount>-50.00</Amount>
</Item_Amount>
</entry>
</root>
Требования:
Консолидация записи, если они имеют тот же ID и Item_ID, и суммировать общую сумму. Подсчитайте количество строк в выводе, включая заголовок и трейлер.
Получите общее значение Ха sh на основе идентификатора и суммы. Алгоритм:
(1) Определить позицию.
ID выровнен по правому краю с длиной поля Char (30)
Сумма выровнена по левому краю с длиной поля Sign (27)
(2) Преобразуйте каждый алфавитный символ c или значение знака в число. Ниже приведено примерное отображение символов.
T = 30, - = 42,. = 41, пробел = 40
(3) Разделить поле идентификатора на две части:
• Значение A (15 alphanumeri c value) - сложить преобразованные числа из позиции 1 - 15
• Значение B (15 alphanumeri c value) - сложить преобразованные числа из позиции 16 - 30
(4) Разделить поле Amount на две части:
• Value C (15 sign sign) - сложить преобразованные числа из позиции 1 - 15
• Значение D (12-значное значение) - сложите преобразованные числа из позиции 16 - 27
(5) Затем примените формулу: REMAINDER = mod (abs ((B + D)) - (A + C)), 13)
(6) итоговая сумма хэша = сумма всех REMAINDER.
Вывод с фиксированной шириной должен выглядеть следующим образом:
Header1
T-1149 FM1 30.00
T-1142 FM1 10.00
T-1142 FM2 -50.00
TRAILER 5 15
Где 5 - общее количество строк, вкл. заголовок и трейлер и 15 - это га sh всего.
Пример расчета для первой записи:
T-1149
VALUE A: 30+42+1+1+4+9+40*9 =447
VALUE B: 40*15 = 600
VALUE C: 40*15 = 600
VALUE D: 3+41+40*7= 324
REMAINDER=6
У меня есть следующий код:
<?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" xmlns:mf="http://example.com/mf"
exclude-result-prefixes="#all" version="3.0">
<xsl:output method="text"/>
<xsl:mode on-no-match="shallow-skip" use-accumulators="#all"/>
<xsl:accumulator name="A" as="xs:integer?" initial-value="()">
<xsl:accumulator-rule match="root/entry/ID" phase="end"
select="accumulator-after('values') => subsequence(1, 15) => sum()"/>
</xsl:accumulator>
<xsl:accumulator name="B" as="xs:integer?" initial-value="()">
<xsl:accumulator-rule match="root/entry/ID" phase="end"
select="accumulator-after('values') => subsequence(16, 27) => sum()"/>
</xsl:accumulator>
<xsl:accumulator name="C" as="xs:integer?" initial-value="()">
<xsl:accumulator-rule
match="root/entry/Item_Amomunt/Amount"
phase="end" select="accumulator-after('values') => subsequence(1, 15) => sum()"/>
</xsl:accumulator>
<xsl:accumulator name="D" as="xs:integer?" initial-value="()">
<xsl:accumulator-rule
match="root/entry/Item_Amomunt/Amount"
phase="end" select="accumulator-after('values') => subsequence(16, 27) => sum()"/>
</xsl:accumulator>
<xsl:accumulator name="values" as="xs:integer*" initial-value="()">
<xsl:accumulator-rule match="entry" select="()"/>
<xsl:accumulator-rule
match="entry/ID/text() | entry/Item_Amount/Amount/text()"
select="
analyze-string(., '.')//*:match ! (
if (. = '.')
then
41
else
if (. = ' ')
then
40
else
if (. = '-')
then
42
else
if (. = ',')
then
42
else
if (. = 'T')
then
30
else
xs:integer(.))"
/>
</xsl:accumulator>
<xsl:accumulator name="remainder" as="xs:integer?" initial-value="()">
<xsl:accumulator-rule match="root/entry" select="()"/>
<xsl:accumulator-rule
match="root/entry" phase="end"
select="
abs((accumulator-after('B') + accumulator-after('D')) -
(accumulator-after('A') + accumulator-after('C'))) mod 13"
/>
</xsl:accumulator>
<xsl:accumulator name="remainder-sum" as="xs:integer?" initial-value="()">
<xsl:accumulator-rule match="root" select="0"/>
<xsl:accumulator-rule match="root/entry"
select="$value + accumulator-after('remainder')"/>
</xsl:accumulator>
<xsl:variable name="count_invoice_line"
select="count(root/entry)"/>
<xsl:variable name="header_line">
<xsl:value-of select="1"/>
</xsl:variable>
<xsl:variable name="trailer_line">
<xsl:value-of select="1"/>
</xsl:variable>
<xsl:variable name="RightPadding"
select="'
'"/>
<xsl:variable name="LeftPadding"
select="'
'"/>
<xsl:function name="mf:PadLeft">
<xsl:param name="string"/>
<xsl:param name="length"/>
<xsl:variable name="leftPad">
<xsl:value-of
select="substring($LeftPadding, 1, $length - string-length(string($string)))"/>
</xsl:variable>
<xsl:sequence select="concat($leftPad, $string)"/>
</xsl:function>
<xsl:function name="mf:PadRight">
<xsl:param name="string"/>
<xsl:param name="length"/>
<xsl:sequence select="substring(concat($string, $RightPadding), 1, $length)"/>
</xsl:function>
<xsl:template match="/">
<xsl:apply-templates/>
<xsl:sequence
select="accumulator-after('remainder-sum')"/>
<Control_Header_Record>
<RowIdentifier>
<xsl:value-of select="mf:PadRight('HEADER', 6)"/>
</RowIdentifier>
</Control_Header_Record>
<Detail>
<xsl:for-each-group select="root/entry"
group-by="concat(ID, ' ', Item_ID)">
<ID><xsl:value-of select="mf:PadRight(ID, 30)"/></ID>
<Item_ID><xsl:value-of select="mf:PadRight(Item_ID, 3)"/>
<xsl:value-of select="mf:PadLeft(Amount, 27)"/>
</Row_Indentifier>
</Detail>
<Trailer_Record>
<xsl:variable name="total_feed_line">
<xsl:value-of select="$count_invoice_line + $header_line + $trailer_line"/>
</xsl:variable>
<RowIdentifier><xsl:value-of select="mf:PadRight('TRAILER',8)"/></RowIdentifier>
<Total_Feed_Line><xsl:value-of select="mf:PadRight($total_feed_line,2)"/></Total_Feed_Line>
<Hash_Total_Value><xsl:value-of select="mf:PadRight($remainder-sum,15)"/></Hash_Total_Value>
</Trailer_Record>
</xsl:template>
Проблема с кодами:
1. Не получается получить правильные итоговые строки в трейлере. Когда две строки объединены в одну строку, он все равно считает элемент как две, поскольку он основан на xpath «root / entry». Я попытался создать переменную и присвоить ей номер внутри l oop, но она не добавляется должным образом. Примерно так:
<xsl:variable name="counter"/> <-- Global variable
<xsl:value-of select="$counter + 1"> <-- inside the loop
<xsl:value-of select=$counter> <-- added in the trailer
Значение ha sh не добавляет «пробел» для вычислений. Например, если у меня есть T-1149, он суммирует числа, но не пробел от позиции 7 до 15.
T-1149 ЗНАЧЕНИЕ A: 30 + 42 + 1 + 1 + 4 + 9 = 89 ЗНАЧЕНИЕ B: 0 ЗНАЧЕНИЕ C: 0 ЗНАЧЕНИЕ D: 3 + 41 = 44 REMAINDER = 6
Я попытался создать переменную и поместить ее в аккумулятор вместо узла, но это не работает Например,
<xsl:variable name="var1" select="1149 "/>
<xsl:variable name="var2" select=" 12.00"/>
<xsl:accumulator name="A" as="xs:integer?" initial-value="()">
<xsl:accumulator-rule match="$var1" phase="end"
select="accumulator-after('values') => subsequence(1, 15) => sum()"/>
</xsl:accumulator>
Я планирую сначала преобразовать входной файл (из другой таблицы стилей), отформатировать и добавить пространство и ввести его в основную таблицу стилей, но проблема заключается в том, как поместить переменную внутри правила аккумулятора вместо узла. Можно ли сделать ту же таблицу стилей и в XSLT2.0? Я не знаком с XSLT3. Спасибо за помощь.