Thevagabond
Thevagabond

Reputation: 323

Addind values over loop in FOP with XSL and XML

I have this XML and XSL example:

XML:

<mastercount>
  <sourceval>
    <attm>50</attm>
    <fh>6500</fh>
    <id>1</id>
  </sourceval>
  <sourceval>
    <attm>15</attm>
    <fh>2300</fh>
    <id>2</id>
  </sourceval>
  <sourceval>
    <attm>4</attm>
    <fh>280</fh>
    <id>3</id>
  </sourceval>
  <sourceval>
    <attm>20</attm>
    <fh>2700</fh>
    <id>4</id>
  </sourceval>
</mastercount>

XSL:

<xsl:variable name="var_idx">
  <xsl:value-of select="position()" />
</xsl:variable>
<xsl:variable name="var_sum_attm" />
<xsl:variable name="var_sum_fh" />
<fo:table-row>
    <xsl:for-each select="/mastercount">
        <fo:table-cell padding="3pt" border-style="solid" width="12mm" border-width="1pt" text-align="right">
            <fo:block>
                <xsl:value-of select="sourceval[position()=$var_idx]/attm" />               
            </fo:block>     
        </fo:table-cell>

        <fo:table-cell padding="3pt" border-style="solid" width="12mm" border-width="1pt" text-align="right">
            <fo:block>
                <xsl:value-of select="sourceval[position()=$var_idx]/fh" />
            </fo:block>
        </fo:table-cell>
    </xsl:for-each>
</fo:table-row>

This part of the source works great and I get

         attm  fh   attm    fh
 Val2     50 6500    0    6500 
 Val1     15 2300    0    2300 
 Val3    280    0  280       0 
 Val4     20 2700    0    2700 

(I skipped the name part above in the source)

However I now need a sum of those 2 fields:

         attm  fh   attm    fh
 Val2     50 6500    0    6500 
 Val1     15 2300    0    2300 
 Val3    280    0  280       0 
 Val4     20 2700    0    2700
        sum   sum  sum     sum

How can I get this to work?

Any ideas?

Thanks for your help. TheVagabond

UPDATE:

Thanks to RT72 here is an answer:

<xsl:for-each select="/mastercount">
    <fo:table-cell padding="3pt" border-style="solid" width="12mm" border-width="1pt" text-align="right">
      <fo:block>
        <xsl:value-of select="sum(sourceval/attm)"/>                                            
      </fo:block>                                       
    </fo:table-cell>
    <fo:table-cell padding="3pt" border-style="solid" width="12mm" border-width="1pt" text-align="right">
      <fo:block>
        <xsl:value-of select="sum(sourceval/fh)" />
      </fo:block>
    </fo:table-cell>
</xsl:for-each>

Upvotes: 0

Views: 1247

Answers (3)

Tony Graham
Tony Graham

Reputation: 8068

It can be simpler to use xsl:templates that reflect the structure of your source and let the XSLT processor work out what to process. The example below does the summing in the template for mastercount, and the templates for sourceval and both attm and fh generate their respective FOs:

<xsl:attribute-set name="table-cell">
    <xsl:attribute name="padding">3pt</xsl:attribute>
    <xsl:attribute name="border-style">solid</xsl:attribute>
    <xsl:attribute name="width">12mm</xsl:attribute>
    <xsl:attribute name="border-width">1pt</xsl:attribute>
    <xsl:attribute name="text-align">right</xsl:attribute>
</xsl:attribute-set>

<xsl:template match="mastercount">
    <fo:table>
        <fo:table-body>
            <xsl:apply-templates />
            <fo:table-row>
                <fo:table-cell xsl:use-attribute-sets="table-cell">
                    <fo:block>
                        <xsl:value-of select="sum(sourceval/attm)" />
                    </fo:block>
                </fo:table-cell>
                <fo:table-cell xsl:use-attribute-sets="table-cell">
                    <fo:block>
                        <xsl:value-of select="sum(sourceval/fh)" />
                    </fo:block>
                </fo:table-cell>
            </fo:table-row>
        </fo:table-body>
    </fo:table>
</xsl:template>

<xsl:template match="sourceval">
    <fo:table-row>
        <xsl:apply-templates select="attm | fh"/>
    </fo:table-row>
</xsl:template>

<xsl:template match="attm | fh">
    <fo:table-cell xsl:use-attribute-sets="table-cell">
        <fo:block>
            <xsl:apply-templates />
        </fo:block>
    </fo:table-cell>
</xsl:template>

If you wanted to only have one template that generates an fo:table-cell with your desired properties, you could change the templates for mastercount and attm and fh to:

<xsl:template match="mastercount">
    <fo:table>
        <fo:table-body>
            <xsl:apply-templates />
            <fo:table-row>
                <xsl:call-template name="table-cell">
                    <xsl:with-param name="value" select="sum(sourceval/attm)" />
                </xsl:call-template>
                <xsl:call-template name="table-cell">
                    <xsl:with-param name="value" select="sum(sourceval/fh)" />
                </xsl:call-template>
            </fo:table-row>
        </fo:table-body>
    </fo:table>
</xsl:template>

<xsl:template match="attm | fh" name="table-cell">
    <xsl:param name="value" select="." />

    <fo:table-cell xsl:use-attribute-sets="table-cell">
        <fo:block>
            <xsl:value-of select="$value" />
        </fo:block>
    </fo:table-cell>
</xsl:template>

Upvotes: 1

RT72
RT72

Reputation: 191

The following should work for you:

 <xsl:variable name="var_sum_attm" select="sum(/mastercount/sourceval/attm)"/>
 <xsl:variable name="var_sum_fh" select="sum(/mastercount/sourceval/fh)"/>

Updated after OP edited question

try this

<xsl:for-each select="/mastercount/sourceval">
<fo:table-row>                              
    <fo:table-cell padding="3pt" border-style="solid" width="12mm" border-width="1pt" text-align="right"> 
        <fo:block>
            <xsl:value-of select="attm" />
        </fo:block>
    </fo:table-cell>
    <fo:table-cell padding="3pt" border-style="solid" width="12mm" border-width="1pt" text-align="right"> 
        <fo:block>
            <xsl:value-of select="fh" />
         </fo:block>
     </fo:table-cell>
</fo:table-row>

<fo:table-row>                              
<fo:table-cell padding="3pt" border-style="solid" width="12mm" border-width="1pt" text-align="right"> 
    <fo:block>
         <xsl:value-of select="sum(/mastercount/sourceval/attm)" />
    </fo:block>
</fo:table-cell>
<fo:table-cell padding="3pt" border-style="solid" width="12mm" border-width="1pt" text-align="right"> 
    <fo:block>
        <xsl:value-of select="sum(/mastercount/sourceval/fh)" />
     </fo:block>
 </fo:table-cell>
</fo:table-row>

Upvotes: 1

Rupesh_Kr
Rupesh_Kr

Reputation: 3445

you can also use this

    <xsl:value-of select="sum(for $i in //attm return $i)"/>
    <xsl:value-of select="sum(for $i in //fh return $i)"/>

Upvotes: 0

Related Questions