Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

XSL Conditional Totalling

Is it possible to perform conditional totalling in xsl?

I have the following xml sample:

<?xml version="1.0" encoding="utf-8"?>
<export>
<stats set="1">
  <columns>
    <column id="0">
      <sum>100</sum>
    </column>
    <column id="1">
      <sum>102</sum>
    </column>
    <column id="2">
      <sum>12</sum>
    </column>
  </columns>
</stats>
  <stats set="2">
    <columns>
      <column id="0">
        <sum>100</sum>
      </column>
      <column id="1">
        <sum>101</sum>
      </column>
      <column id="2">
        <sum>19</sum>
      </column>
    </columns>
  </stats>
</export>

Is it possible to compute the total of all columns in each stat set where they are not equal to one another? So it would output the following:

               Set 1       Set 2       Diff(Set 1 - Set 2)
Total (Diff)   114         120           -6
column 2       102         101            1  
column 3       12          19            -7 

So in the output column 1 would be omitted as the sum in the two stat sets is the same.

I can get my xsl to output the columns that are different but unsure how to total these up and put in the total row.

Many thanks,

Andez

like image 458
Andez Avatar asked Sep 01 '26 20:09

Andez


1 Answers

This transformation (64 lines):

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="text"/>
 <xsl:key name="kColByPosAndVal" match="column"
  use="concat(count(preceding-sibling::*),
              '+',
              sum)"/>
 <xsl:key name="kIdByVal" match="column/@id"
  use="."/>

 <xsl:template match="/*">
  <xsl:variable name="vsum1" select=
   "sum(stats[@set=1]/*/column
                  [not(key('kColByPosAndVal',
                            concat(count(preceding-sibling::*),
                                  '+',
                                   sum)
                           )[2]
                       )])"/>
  <xsl:variable name="vsum2" select=
   "sum(stats[@set=2]/*/column
                  [not(key('kColByPosAndVal',
                            concat(count(preceding-sibling::*),
                                  '+',
                                   sum)
                           )[2]
                       )])"/>

                 Set 1          Set 2       Diff(Set 1 - Set 2)
  Total (Diff)   <xsl:text/>
  <xsl:value-of select="$vsum1"/>
  <xsl:text>             </xsl:text>
  <xsl:value-of select="$vsum2"/>
  <xsl:text>             </xsl:text>
  <xsl:value-of select="$vsum1 -$vsum2"/>
  <xsl:text>&#xA;</xsl:text>

  <xsl:for-each select=
   "*/*/column/@id
       [generate-id()
       = generate-id(key('kIdByVal',.)[1])
       ]
       [not(key('kColByPosAndVal',
                concat(count(../preceding-sibling::*),
                       '+',
                       ../sum)
                )[2]
            )]">
    <xsl:variable name="vcolSet1" select=
     "/*/stats[@set=1]/*/column[@id=current()]/sum"/>

    <xsl:variable name="vcolSet2" select=
     "/*/stats[@set=2]/*/column[@id=current()]/sum"/>
  Column <xsl:value-of select=".+1"/><xsl:text/>
    <xsl:text>       </xsl:text>
    <xsl:value-of select="$vcolSet1"/>
    <xsl:text>             </xsl:text>
    <xsl:value-of select="$vcolSet2"/>
    <xsl:text>             </xsl:text>
    <xsl:value-of select="$vcolSet1 -$vcolSet2"/>
    <xsl:text>&#xA;</xsl:text>
  </xsl:for-each>
 </xsl:template>
</xsl:stylesheet>

when applied on the provided XML document:

<export>
<stats set="1">
  <columns>
    <column id="0">
      <sum>100</sum>
    </column>
    <column id="1">
      <sum>102</sum>
    </column>
    <column id="2">
      <sum>12</sum>
    </column>
  </columns>
</stats>
  <stats set="2">
    <columns>
      <column id="0">
        <sum>100</sum>
      </column>
      <column id="1">
        <sum>101</sum>
      </column>
      <column id="2">
        <sum>19</sum>
      </column>
    </columns>
  </stats>
</export>

produces the wanted, correct result:

                 Set 1          Set 2       Diff(Set 1 - Set 2)
  Total (Diff)   114             120             -6

  Column 2       102             101             1

  Column 3       12             19             -7

Explanation:

  1. The key named kColByPosAndVal is used to select all columns that have a given position (among all column siblings) and a given value for their sum child-element.

  2. The key named kIdByVal is used in Muenchian grouping to find all different values for the id attribute.

  3. The two totals are calculated summing only those columns, whose kColByPosAndVal key selects only one column element (if it selects two column elements, they both are at the same position and have the same sum).

  4. The rest should be easy to understand.

like image 97
Dimitre Novatchev Avatar answered Sep 05 '26 11:09

Dimitre Novatchev



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!