Reputation: 521
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 > 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?
Upvotes: 0
Views: 397
Reputation: 70648
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>
Upvotes: 1