Search code examples
xsl-fo

Math. Minus one child from anotehr in the next parent item XSLT 1.0


I need to loop through nodes and have math functions on parent and children nodes.

I have played around with parent:: ancestor:: etc but I cannot get what I need.

I have simplified the XML and XSL for this example of what I need. `

<bookstore>
<book>
    <title lang="en">Harry Potter</title>
    <price>29.99</price>
</book>
<book>
    <title lang="en">Learning XML</title>
    <price>39.95</price>
</book>
<book>
    <title lang="en">Lord Of The Rings</title>
    <price>32.99</price>
</book>

I need the output to be in a table (xsl:fo)

Harry Potter       29.99  29.99
Learning XML       39.95  -9.96
Lord Of The Rings  32.99  -6.96

So basically what this is showing is title, price, sum(price of current node - price of previous node) So that last cell from row 2 is (39.95 - 29.99) Row 3 would be (32.99 - 39.95) I have the first two columns but I don't know how to do the last column within a loop.

Here is a snippet for a table that I am trying to create

<xsl:for-each select="/bookstore">
<fo:table-row border-top="0.5pt solid black">
    <fo:table-cell <!--%var-cell-padding%-->>
        <fo:block>
            <xsl:value-of select="title" />
        </fo:block>
    </fo:table-cell>
    <fo:table-cell <!--%var-cell-padding%--> text-align="left">
        <fo:block>
            <xsl:value-of select="price"/>
        </fo:block>
    </fo:table-cell>
    <fo:table-cell <!--%var-cell-padding%--> text-align="center">
        <fo:block>
            <xsl:value-of select="currentprice-previousItemInLoopPrice"/>
        </fo:block>
    </fo:table-cell>
</fo:table-row>


Solution

  • Your data seems wrong for your expectations, but here is a simple example with all the remainder of the XSL FO required to render a page:

    Given this input:

    <bookstore>
        <book>
            <title lang="en">Harry Potter</title>
            <price>29.99</price>
        </book>
        <book>
            <title lang="en">Learning XML</title>
            <price>39.95</price>
        </book>
        <book>
            <title lang="en">Lord Of The Rings</title>
            <price>32.99</price>
        </book>
    </bookstore>
    

    And this XSL (which is one of 100 ways to do it):

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" version="1.0">
        <xsl:template match="bookstore">
            <fo:table>
                <xsl:apply-templates/>
            </fo:table>
        </xsl:template>
        <xsl:template match="book">
            <fo:table-row>
                <fo:table-cell>
                    <fo:block>
                        <xsl:value-of select="title"/>
                    </fo:block>
                </fo:table-cell>
                <fo:table-cell>
                    <fo:block>
                        <xsl:value-of select="format-number(price,'#.00')"/>
                    </fo:block>
                </fo:table-cell>
                <fo:table-cell>
                    <fo:block>
                        <xsl:choose>
                            <xsl:when test="not(preceding-sibling::book)">
                                <xsl:text>0.00</xsl:text>
                            </xsl:when>
                            <xsl:otherwise>
                                <xsl:value-of select="format-number(number(price) - number(preceding-sibling::book[1]/price), '#.00')"/>
                            </xsl:otherwise>
                        </xsl:choose>
                    </fo:block>
                </fo:table-cell>
            </fo:table-row>
        </xsl:template>
    </xsl:stylesheet>
    

    The output is:

    <fo:table xmlns:fo="http://www.w3.org/1999/XSL/Format">
    <fo:table-row><fo:table-cell><fo:block>Harry Potter</fo:block></fo:table-cell><fo:table-cell><fo:block>29.99</fo:block></fo:table-cell><fo:table-cell><fo:block>0.00</fo:block></fo:table-cell></fo:table-row>
    <fo:table-row><fo:table-cell><fo:block>Learning XML</fo:block></fo:table-cell><fo:table-cell><fo:block>39.95</fo:block></fo:table-cell><fo:table-cell><fo:block>9.96</fo:block></fo:table-cell></fo:table-row>
    <fo:table-row><fo:table-cell><fo:block>Lord Of The Rings</fo:block></fo:table-cell><fo:table-cell><fo:block>32.99</fo:block></fo:table-cell><fo:table-cell><fo:block>-6.96</fo:block></fo:table-cell></fo:table-row>
    </fo:table