I'm creating a football league website and need to produce a results table.
I've got 75% of the table done so far but...
Issue 1: I'm struggling to come up with a method to total multiple property values for the total goals scored by a club / scored against that club and the difference between the 2.
Issue 2: I need to then sort the table by the points Descending , then Goal difference.
My structure is like so:
Clubs - Club 1 - Club 2 - Club 3 - And so on...
Fixtures And Results - Game 1 (homeTeam / homeGoals / awayTeam / awayGoals) - Game 2 - Game 3 - And so on...
Any help would be greatly appreciated as I've hit a brick wall. My XSLT so far is below. Also if there is anything suspect in my method below please let me know :)
You can perform a couple of "optimizations" that makes the code read a little better:
./ is not necessary, so you can remove all those (e.g.: count($homeGames [./homeTeamGoals < ./awayTeamGoals]) => count($homeGames[homeTeamGoals < awayTeamGoals]))
/descendant:: can be shortened to // (e.g.: $Results/descendant::FixtureOrResult => $Results//FixtureOrResult
That was spot on and I've done my house keeping, a couple of nice tips thanks.
Must say I'm really liking the flexibility of Umbraco especially for a front end guy like me.
Still stuck with the my second issue now I have all the values in the table I need to sort the data and put the club with the most points at the top and descending down.
I've spent some time searching and can see that you can't use a variable i.e $points, <xsl:sort select="$points" order="descending"/>, do you have any clue how this could be done or a similar post that could help?
So you could extract all the variables back into a giant sort selection that didn't use variables, but it would be hard to read and understand before you'd have finished the rest of the site - so here's a better/nicer approach:
When dealing with large sets of data like that, it can be much more efficient to simply pre-calculate the results and create an XML variable with those, and use that instead for rendering the table - e.g., having something like this (for every team):
As you can see, it should then be easy as pie to sort on any of all those bits (though you'd probably be better off using some sort of "sortable table" JS plugin for that).
Here's a crude version of how you'd do something like the above:
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:umbraco.library="urn:umbraco.library"
exclude-result-prefixes="umbraco.library"
>
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes" />
<xsl:param name="currentPage" />
<!-- Index the published resultnodes by team for speedy lookup -->
<xsl:key name="homeGamesForTeam" match="FixtureOrResult[publishResult = 1]" use="homeTeam" />
<xsl:key name="awayGamesForTeam" match="FixtureOrResult[publishResult = 1]" use="awayTeam" />
<xsl:variable name="$Source" select="umbraco.library:GetXmlNodeById($currentPage/selectedNode)/Clubs" />
<xsl:template match="/">
<!-- Process the Clubs node in the selected section -->
<xsl:apply-templates select="$Source" />
</xsl:template>
<!-- Template for the Clubs node -->
<xsl:template match="Clubs">
<xsl:variable name="resultsProxy">
<!-- Run through all the teams -->
<xsl:for-each select="Club">
<!-- Scope these to the current team to reduce number of nodes searched -->
<xsl:variable name="homeGames" select="key('homeGamesForTeam', @id)" />
<xsl:variable name="awayGames" select="key('awayGamesForTeam', @id)" />
<!-- Collect all the results -->
<xsl:variable name="homeWins" select="count($homeGames[homeTeamGoals > awayTeamGoals])"/>
<xsl:variable name="homeDraws" select="count($homeGames[homeTeamGoals = awayTeamGoals])"/>
<xsl:variable name="homeLose" select="count($homeGames[homeTeamGoals < awayTeamGoals])"/>
<!-- Away Games -->
<xsl:variable name="awayWins" select="count($awayGames [homeTeamGoals < awayTeamGoals])"/>
<xsl:variable name="awayDraws" select="count($awayGames [homeTeamGoals = awayTeamGoals])"/>
<xsl:variable name="awayLose" select="count($awayGames [homeTeamGoals > awayTeamGoals])"/>
<!-- Totals -->
<xsl:variable name="totalWins" select="$homeWins + $awayWins"/>
<xsl:variable name="totalDraws" select="$homeDraws + $awayDraws"/>
<xsl:variable name="totalLose" select="$homeLose + $awayLose"/>
<!-- Goals -->
<xsl:variable name="goalsFor" select="sum($homeGames/homeTeamGoals | $awayGames/homeTeamGoals)"/>
<xsl:variable name="goalsAgainst" select="sum($homeGames/awayTeamGoals | $awayTeamGoals/awayTeamGoals)"/>
<xsl:variable name="goalsDiff" select="$goalsFor - $goalsAgainst"/>
<!-- Points -->
<xsl:variable name="points" select="($totalWins * 3) + ($totalDraws)"/>
<!-- Wrap everything in a precalculated <result> for this team -->
<result club="{@id}" name="{@nodeName}">
<played><xsl:value-of select="count($homeGames | $awayGames)"/></played>
<homeWins><xsl:value-of select="$homeWins" /></homeWins>
<homeDraws><xsl:value-of select="$homeDraws" /></homeDraws>
<homeLose><xsl:value-of select="$homeLose" /></homeLose>
<awayWins><xsl:value-of select="$awayWins" /></awayWins>
<awayDraws><xsl:value-of select="$awayDraws" /></awayDraws>
<awayLose><xsl:value-of select="$awayLose" /></awayLose>
<totalWins><xsl:value-of select="$homeWins + $awayWins" /></totalWins>
<totalDraws><xsl:value-of select="$homeDraws + $awayDraws" /></totalDraws>
<totalLose><xsl:value-of select="$homeLose + $awayLose" /></totalLose>
<goalsFor><xsl:value-of select="$goalsFor" /></goalsFor>
<goalsAgainst><xsl:value-of select="$goalsAgainst" /></goalsAgainst>
<goalsDiff><xsl:value-of select="$goalsDiff" /></goalsDiff>
<points><xsl:value-of select="$points" /></points>
</result>
</xsl:for-each>
</xsl:variable>
<!-- (This is needed to get an "XPath-navigable" variable) -->
<xsl:variable name="results" select="make:node-set($resultsProxy)/result" />
<!-- Output table of results -->
<table>
<tr>
<th>Team</th>
<th>Played</th>
<th>HW</th>
<th>HD</th>
<th>HL</th>
<th>AW</th>
<th>AD</th>
<th>AL</th>
<th>W</th>
<th>D</th>
<th>L</th>
<th>GF</th>
<th>GA</th>
<th>GD</th>
<th>Pts</th>
</tr>
<!-- Run through the results, sorted backwards by points scored -->
<xsl:apply-templates select="$results">
<xsl:sort select="points" data-type="number" order="descending" />
</xsl:apply-templates>
</table>
</xsl:template>
<!-- Template for a single <result> -->
<xsl:template match="result">
<!-- Just pick the pre-calculated results one by one -->
<tr>
<td><xsl:value-of select="@name" /></td>
<td><xsl:value-of select="played" /></td>
<td><xsl:value-of select="homeWins" /></td>
<td><xsl:value-of select="homeDraws" /></td>
<td><xsl:value-of select="homeLose" /></td>
<!-- etc. -->
</tr>
</xsl:template>
</xsl:stylesheet>
Counting property values and totalling
Hi,
I'm creating a football league website and need to produce a results table.
I've got 75% of the table done so far but...
Issue 1:
I'm struggling to come up with a method to total multiple property values for the total goals scored by a club / scored against that club and the difference between the 2.
Issue 2:
I need to then sort the table by the points Descending , then Goal difference.
My structure is like so:
- Club 1
- Club 2
- Club 3
- And so on...
- Game 1 (homeTeam / homeGoals / awayTeam / awayGoals)
- Game 2
- Game 3
- And so on...
Any help would be greatly appreciated as I've hit a brick wall. My XSLT so far is below. Also if there is anything suspect in my method below please let me know :)
Thanks you Kyle.
<!-- Clubs & Results -->
<xsl:param name="Source" select="umbraco.library:GetXmlNodeById($currentPage/selectedNode)/Clubs" />
<xsl:param name="Results" select="umbraco.library:GetXmlNodeById($currentPage/selectedNode)/FixturesAndResults" />
<table>
<tr>
<td>Team</td>
<td>Played</td>
<td>HW</td>
<td>HD</td>
<td>HL</td>
<td>AW</td>
<td>AD</td>
<td>AL</td>
<td>W</td>
<td>D</td>
<td>L</td>
<td>GF</td>
<td>GA</td>
<td>GD</td>
<td>Pts</td>
</tr>
<xsl:for-each select="$Source/Club">
<xsl:variable name="parentId" select="@id"/>
<!-- Games Played -->
<xsl:variable name="played" select="count($Results/descendant::FixtureOrResult [@isDoc and ./publishResult = 1 and (./homeTeam = $parentId or ./awayTeam = $parentId)])"/>
<!-- Home Games -->
<xsl:variable name="homeGames" select="$Results/descendant::FixtureOrResult [@isDoc and ./publishResult = 1 and (./homeTeam = $parentId)]"/>
<xsl:variable name="homeWins" select="count($homeGames [./homeTeamGoals > ./awayTeamGoals])"/>
<xsl:variable name="homeDraws" select="count($homeGames [./homeTeamGoals = ./awayTeamGoals])"/>
<xsl:variable name="homeLose" select="count($homeGames [./homeTeamGoals < ./awayTeamGoals])"/>
<!-- Away Games -->
<xsl:variable name="awayGames" select="$Results/descendant::FixtureOrResult [@isDoc and ./publishResult = 1 and (./awayTeam = $parentId)]"/>
<xsl:variable name="awayWins" select="count($awayGames [./homeTeamGoals < ./awayTeamGoals])"/>
<xsl:variable name="awayDraws" select="count($awayGames [./homeTeamGoals = ./awayTeamGoals])"/>
<xsl:variable name="awayLose" select="count($awayGames [./homeTeamGoals > ./awayTeamGoals])"/>
<!-- Totals -->
<xsl:variable name="totalWins" select="$homeWins + $awayWins"/>
<xsl:variable name="totalDraws" select="$homeDraws + $awayDraws"/>
<xsl:variable name="totalLose" select="$homeLose + $awayLose"/>
<!-- Goals -->
<xsl:variable name="goalsFor" select="1"/>
<!-- Points -->
<xsl:variable name="points" select="($totalWins * 3) + ($totalDraws)"/>
<tr>
<td>
<xsl:value-of select="@nodeName"/>
</td>
<td>
<xsl:value-of select="$played"/>
</td>
<td>
<xsl:value-of select="$homeWins"/>
</td>
<td>
<xsl:value-of select="$homeDraws"/>
</td>
<td>
<xsl:value-of select="$homeLose"/>
</td>
<td>
<xsl:value-of select="$awayWins"/>
</td>
<td>
<xsl:value-of select="$awayDraws"/>
</td>
<td>
<xsl:value-of select="$awayLose"/>
</td>
<td>
<xsl:value-of select="$totalWins"/>
</td>
<td>
<xsl:value-of select="$totalDraws"/>
</td>
<td>
<xsl:value-of select="$totalLose"/>
</td>
<td>
Goals For
</td>
<td>
Goals Against
</td>
<td>
Goal Difference
</td>
<td>
<xsl:value-of select="$points"/>
</td>
</tr>
</xsl:for-each>
</table>
Hi Kyle - welcome to Our !
To calculate all the goals you can use the sum() function, e.g. something like this (taking a qualified guess):
(The pipe -
|
- joins two or more nodesets)You can perform a couple of "optimizations" that makes the code read a little better:
./
is not necessary, so you can remove all those (e.g.:count($homeGames [./homeTeamGoals < ./awayTeamGoals])
=>count($homeGames[homeTeamGoals < awayTeamGoals])
)/descendant::
can be shortened to//
(e.g.:$Results/descendant::FixtureOrResult
=>$Results//FixtureOrResult
Hope that helps (and that the home team wins!)
/Chriztian
Thanks Chriztian,
That was spot on and I've done my house keeping, a couple of nice tips thanks.
Must say I'm really liking the flexibility of Umbraco especially for a front end guy like me.
Still stuck with the my second issue now I have all the values in the table I need to sort the data and put the club with the most points at the top and descending down.
I've spent some time searching and can see that you can't use a variable i.e
$points
,<xsl:sort select="$points" order="descending"/>
, do you have any clue how this could be done or a similar post that could help?Kind Regards,
Kyle
Hi Kyle,
So you could extract all the variables back into a giant sort selection that didn't use variables, but it would be hard to read and understand before you'd have finished the rest of the site - so here's a better/nicer approach:
When dealing with large sets of data like that, it can be much more efficient to simply pre-calculate the results and create an XML variable with those, and use that instead for rendering the table - e.g., having something like this (for every team):
As you can see, it should then be easy as pie to sort on any of all those bits (though you'd probably be better off using some sort of "sortable table" JS plugin for that).
Here's a crude version of how you'd do something like the above:
/Chriztian
Hi Chriztian,
Thanks again, a minor tweak and it worked a treat. Another really handy method.
I changed the "make:"
To
Kind Regards,
Kyle
Hi Kyle,
Ha :) Good catch - I do forget to change that, from time to time :-)
/Chriztian
is working on a reply...