问题
I need to get the number of rows in the output after the data have been grouped.
XML input file looks like this:
<?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>
The output which is a fixed width will look like this:
Header1
T-1149 FM1 30.00
T-1142 FM1 10.00
T-1142 FM2 -50.00
TRAILER 5 15
The number 5 in the trailer is the count of lines including header and trailer.
I have this code but this counts all the entries in the XML file:
<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>
The output of this code is
Header1
T-1149 FM1 30.00
T-1142 FM1 10.00
T-1142 FM2 -50.00
TRAILER 6 15
Since the T-1149 from the input file has two entries, it is counted as 2 thats why it's getting 6. I just the need total number of lines in the output. I tried putting the grouping result in a variable and call the variable for the count:
<Detail>
<xsl:variable="row">
<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>
</xsl:variable>
</Detail>
<xsl:value-of select="count($rows)"/>
but I'm getting complilation error saying a variable (rows) with no following sibling instructions has no effect and then variable $rows has not been declared. I'm using oxygen to test this and not sure if it is simpler to be done in XSLT2.0 than 3.0. but I need to get this along with my other code here Count of consolidated lines and Hash value - getting the remainder in XSLT which is an issue about getting the hash total value
Thank you.
回答1:
You get the first error because the variable declaration with xsl:variable
is done inside of the Details
literal result element but your attempt to use the variable is not a sibling of that variable declaration, i.e. also inside of the Details
element, but outside of it.
So that is a necessary and easy fix you can make.
Other than that your code is not clear (there is a stray </Row_Indentifier>
), nor is your wanted result, if your aim is to group the entry
elements then I would expect some content inside of the xsl:for-each-group
to either create "group" wrapper element for each group or to merge the "entry" elements belonging to a group by accumulating amout or other data.
So you will need to elaborate on which result structure you want for the variable content, which elements or items you want to count, which result you are looking for for the count.
To give you an example, the code
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
version="3.0">
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template match="root">
<xsl:variable name="grouped-entries" as="element(entry)*">
<xsl:for-each-group select="entry" composite="yes" group-by="ID, Item_ID">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:for-each-group>
</xsl:variable>
<xsl:sequence select="count($grouped-entries), $grouped-entries"/>
</xsl:template>
<xsl:template match="Item_Amount/Amount">
<xsl:copy>
<xsl:value-of select="sum(current-group()/Item_Amount/Amount)"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
groups the entry
elements of the same ID
and Item_ID
into one where the Amount
is summed for all entries in the group, so for your example you then have 3
entry elements in the variable and you have the sums you seem to want to output (https://xsltfiddle.liberty-development.net/pPJ9hE9)
Transforming that grouping result into another format is a different step but should rather easy once you have understood the type and structure of the grouping result and have a clear understanding on how to create the format you need.
来源:https://stackoverflow.com/questions/59925295/count-the-lines-after-grouping-data-in-xslt