0
votes

This is my xslt:

<?xml version="1.0" encoding="UTF-8"?>
   <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xhtml" encoding="UTF-8" indent="yes"/>

    <xsl:output doctype-public="-//W3C//DTD XHTML 1.1//EN"
                doctype-system="http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd" />

    <xsl:template match="/">
        <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="pt">
            <head>
                <title>teste</title>
            </head>
            <body>
                <xsl:apply-templates select="//produtos"/>


            </body>
        </html>
    </xsl:template>


    <xsl:template match="produto">

        <xsl:variable name="id" select="@id"/>

        <xsl:variable name="nr" select="count(//avaliacao[@produto = $id])"/>

        <xsl:variable name="stars" select="sum(//avaliacao[@produto = $id]/@stars)"/>

        <xsl:variable name="media" select="$stars div $nr"/>

        <xsl:if test="$media &gt; 2">

            <xsl:for-each select="//produto[@id = $id]">
                <xsl:sort select="string($media)" data-type="number" order="ascending"/>

                <xsl:value-of select="$media"/>

            </xsl:for-each>
        </xsl:if>


        </xsl:template>



        </xsl:stylesheet>

And this is my XML (it's a bit large):

        <produtos>

        <produto id="P01">
            <nome>Powerbank</nome>
            <descricao>Nova.</descricao>
            <caracteristicas nome="Powerbank" valor="19,99"/>
            <preco>19.99</preco>
            <data_ins>2017/10/16</data_ins>
            <transportadora empresa="CTT"/>
            <transportadora empresa="SEUR"/>
            <links_f href="https://ae01.alicdn.com/kf/HTB1YGZkLXXXXXb8XFXXq6xXFXXXr/Original-DOCA-font-b-Power-b-font-font-b-Ban-b-font-Real-5000Mah-Li-polymer.jpg"/>              
            <vendedor id="U07"/>
        </produto>

                <avaliacoes>

            <avaliacao produto="P04" autor="U02" stars="5"/>
            <avaliacao produto="P03" autor="U02" stars="4"/>
            <avaliacao produto="P01" autor="U01" stars="5"/>
            <avaliacao produto="P07" autor="U03" stars="5"/>
            <avaliacao produto="P08" autor="U01" stars="4"/>
            <avaliacao produto="P09" autor="U01" stars="2"/>

        </avaliacoes>

This is just a sample of my XML, the original is 400 lines large.

Basically my problem is that I'm trying to make an average of the stars given to a certain product and then sort the products with an average greater than 2 stars.

Right now my XHTML output is:

5 3 5 5 4 

instead of:

5 5 5 4 3

What is wrong with my XSLT?

1

1 Answers

1
votes

Your xsl:for-each is in a template matching produto but all it is going to do is select the exact same (single) product, so there is nothing to sort.

To do the sorting, you should do so in the code that selects produto in the first place. (Which you don't actually have)

But to make things simpler, consider using a key to look up the avaliacao elements.

<xsl:key name="avaliacao" match="avaliacao" use="@produto" />

Then you can have an xsl:apply-templates to select produto that can do both the sort, and the filtering...

<xsl:apply-templates select="//produto[sum(key('avaliacao', @id)/@stars) div count(key('avaliacao', @id)) gt 2]">
    <xsl:sort select="sum(key('avaliacao', @id)/@stars) div count(key('avaliacao', @id))" order="descending" />
</xsl:apply-templates>

Try this XSLT

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xhtml" encoding="UTF-8" indent="yes"
            doctype-public="-//W3C//DTD XHTML 1.1//EN"
            doctype-system="http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd" />

    <xsl:key name="avaliacao" match="avaliacao" use="@produto" />

    <xsl:template match="/">
        <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="pt">
            <head>
                <title>teste</title>
            </head>
            <body>
                <xsl:apply-templates select="//produto[sum(key('avaliacao', @id)/@stars) div count(key('avaliacao', @id)) gt 2]">
                    <xsl:sort select="sum(key('avaliacao', @id)/@stars) div count(key('avaliacao', @id))" order="descending" />
                </xsl:apply-templates>
            </body>
        </html>
    </xsl:template>

    <xsl:template match="produto">
        <xsl:variable name="nr" select="count(key('avaliacao', @id))"/>
        <xsl:variable name="stars" select="sum(key('avaliacao', @id)/@stars)"/>
        <xsl:variable name="media" select="$stars div $nr"/>

        <xsl:value-of select="$media"/>
    </xsl:template>
</xsl:stylesheet>