Search code examples
xmlvariablesxsltexpressionevaluate

XSL evaluate attribute with variables


I would like to use an xsl file to show and evaluate an xml file. The XML file contains an amount of parts which have a title, description, image and an amount. But this amount is dependant on some variables that I will declare in the XSL file. But in this case I have to calculate the expression from within the XML in the XSL file. Is there a way to this?

See example: (the expressions in @amount should be evaluated with the variables from the XML)

XML:

<partslist>         
<part value="1" amount="$variable1" visible="true">     
    <title> 
        <nl>Onderdeel 1</nl>
        <fr>Partie 1</fr>
        <en>Part 1</en>
        <de>Teil 1</de>
    </title>    
    <image src="images/partslist/part1.jpg"/>   
</part>     
<part value="2" amount="$variable1 * $variable2" visible="true">        
    <title> 
        <nl>Onderdeel 2</nl>
        <fr>Partie 2</fr>
        <en>Part 2</en>
        <de>Teil 2</de>
    </title>    
    <image src="images/partslist/part2.jpg"/>   
</part> 
<part value="3" amount="$variable3" visible="true">     
    <title> 
        <nl>Onderdeel 3</nl>
        <fr>Partie 3</fr>
        <en>Part 3</en>
        <de>Teil 3</de>
    </title>    
    <image src="images/partslist/part3.jpg"/>   
</part> 
<part value="4" amount="$variable1 + $variable3" visible="true">        
    <title> 
        <nl>Onderdeel 4</nl>
        <fr>Partie 4</fr>
        <en>Part 4</en>
        <de>Teil 4</de>
    </title>    
    <image src="images/partslist/part4.jpg"/>   
</part> 
</partslist>            

XSL:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<xsl:template match="/">
    <html>
        <head>
            <link rel="stylesheet" href="style.css" type="text/css"/>
        </head>
        <body>
            <xsl:variable name="variable1" select="1" />
            <xsl:variable name="variable2" select="2" />
            <xsl:variable name="variable3" select="3" />

            <div class="np">
                <H2>Parts List</H2>
                <table border ="1">
                    <tr>
                        <th style="width:15%;">ID</th>
                        <th style="width:15%;">Amount</th>
                        <th style="width:40%;">Description</th>
                        <th style="width:30%;">Image</th>
                    </tr>
                    <xsl:for-each select="partslist/part">
                        <tr>
                            <td><xsl:value-of select="@value" /></td>
                            <td><xsl:value-of select="@amount"/></td>
                            <td><xsl:value-of select="title/nl"/></td>
                            <td><img style="width:100%;" src="{image/@src}"/></td>
                        </tr>
                    </xsl:for-each>
                </table>
            </div>
        </body>
    </html>
</xsl:template>
</xsl:stylesheet>

Thanks in advance


Solution

  • If you use an XSLT processor like Xalan interpreter which supports the EXSLT dyn:evaluate function (http://exslt.org/dyn/functions/evaluate/index.html) then you can use

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      xmlns:dyn="http://exslt.org/dynamic" exclude-result-prefixes="dyn">
    <xsl:template match="/">
        <html>
            <head>
                <link rel="stylesheet" href="style.css" type="text/css"/>
            </head>
            <body>
                <xsl:variable name="variable1" select="1" />
                <xsl:variable name="variable2" select="2" />
                <xsl:variable name="variable3" select="3" />
    
                <div class="np">
                    <H2>Parts List</H2>
                    <table border ="1">
                        <tr>
                            <th style="width:15%;">ID</th>
                            <th style="width:15%;">Amount</th>
                            <th style="width:40%;">Description</th>
                            <th style="width:30%;">Image</th>
                        </tr>
                        <xsl:for-each select="partslist/part">
                            <tr>
                                <td><xsl:value-of select="@value" /></td>
                                <td><xsl:value-of select="dyn:evaluate(@amount)"/></td>
                                <td><xsl:value-of select="title/nl"/></td>
                                <td><img style="width:100%;" src="{image/@src}"/></td>
                            </tr>
                        </xsl:for-each>
                    </table>
                </div>
            </body>
        </html>
    </xsl:template>
    </xsl:stylesheet>
    

    http://xsltransform.hikmatu.com/948Fn5d.

    Depending on your XSLT processor, even is there is no support for dyn:evaluate, you might be able to implement the functionality with an extension function.

    Or move to an XSLT 3 processor that supports xsl:evaluate:

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        xmlns:math="http://www.w3.org/2005/xpath-functions/math" exclude-result-prefixes="xs math"
        version="3.0">
    
        <xsl:template match="/">
            <html>
                <head>
                    <link rel="stylesheet" href="style.css" type="text/css"/>
                </head>
                <body>
                    <xsl:variable name="variable1" select="1"/>
                    <xsl:variable name="variable2" select="2"/>
                    <xsl:variable name="variable3" select="3"/>
    
                    <div class="np">
                        <H2>Parts List</H2>
                        <table border="1">
                            <tr>
                                <th style="width:15%;">ID</th>
                                <th style="width:15%;">Amount</th>
                                <th style="width:40%;">Description</th>
                                <th style="width:30%;">Image</th>
                            </tr>
                            <xsl:for-each select="partslist/part">
                                <tr>
                                    <td>
                                        <xsl:value-of select="@value"/>
                                    </td>
                                    <td>
                                        <xsl:evaluate xpath="@amount" context-item="."
                                            with-params="
                                                map {
                                                    xs:QName('variable1'): $variable1,
                                                    xs:QName('variable2'): $variable2,
                                                    xs:QName('variable3'): $variable3
                                                }"
                                        />
                                    </td>
                                    <td>
                                        <xsl:value-of select="title/nl"/>
                                    </td>
                                    <td>
                                        <img style="width:100%;" src="{image/@src}"/>
                                    </td>
                                </tr>
                            </xsl:for-each>
                        </table>
                    </div>
                </body>
            </html>
        </xsl:template>
    
    </xsl:stylesheet>