Count the lines after grouping data in XSLT

回眸只為那壹抹淺笑 提交于 2020-02-07 02:35:25

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!