📜 ⬆️ ⬇️

Tag Cloud with XSLT

Not so long ago, I was faced with the need to implement on one of the projects what the people call the “tag cloud” - a set of links in which the most “weighty” elements are of a large size. To do this, you could, of course, calculate and retrieve all the necessary data in PHP, on which the project runs, but I wanted to make the final display on XSLT and CSS so that all the necessary values ​​for configuring maximum / minimum font sizes, for example, were set in the view, not in the application logic.

Perhaps someone my experience will be useful, so publish the final solution here.

So, at the entrance we have the simplest XML with a tag and the number of its references:
')
<? xml version ="1.0" encoding ="utf-8" ? > <br> < cloud > <br> < row id ="1" > <br> < name > </ name > <br> < weight > 2 </ weight > <br> </ row > <br> < row id ="2" > <br> < name > </ name > <br> < weight > 20 </ weight > <br> </ row > <br> < row id ="3" > <br> < name > </ name > <br> < weight > 13 </ weight > <br> </ row > <br> < row id ="4" > <br> < name > </ name > <br> < weight > 2 </ weight > <br> </ row > <br> < row id ="5" > <br> < name > </ name > <br> < weight > 20 </ weight > <br> </ row > <br> < row id ="6" > <br> < name > </ name > <br> < weight > 1 </ weight > <br> </ row > <br> < row id ="7" > <br> < name > </ name > <br> < weight > 7 </ weight > <br> </ row > <br> < row id ="8" > <br> < name > </ name > <br> < weight > 14 </ weight > <br> </ row > <br> </ cloud > <br><br> * This source code was highlighted with Source Code Highlighter .
<? xml version ="1.0" encoding ="utf-8" ? > <br> < cloud > <br> < row id ="1" > <br> < name > </ name > <br> < weight > 2 </ weight > <br> </ row > <br> < row id ="2" > <br> < name > </ name > <br> < weight > 20 </ weight > <br> </ row > <br> < row id ="3" > <br> < name > </ name > <br> < weight > 13 </ weight > <br> </ row > <br> < row id ="4" > <br> < name > </ name > <br> < weight > 2 </ weight > <br> </ row > <br> < row id ="5" > <br> < name > </ name > <br> < weight > 20 </ weight > <br> </ row > <br> < row id ="6" > <br> < name > </ name > <br> < weight > 1 </ weight > <br> </ row > <br> < row id ="7" > <br> < name > </ name > <br> < weight > 7 </ weight > <br> </ row > <br> < row id ="8" > <br> < name > </ name > <br> < weight > 14 </ weight > <br> </ row > <br> </ cloud > <br><br> * This source code was highlighted with Source Code Highlighter .
<? xml version ="1.0" encoding ="utf-8" ? > <br> < cloud > <br> < row id ="1" > <br> < name > </ name > <br> < weight > 2 </ weight > <br> </ row > <br> < row id ="2" > <br> < name > </ name > <br> < weight > 20 </ weight > <br> </ row > <br> < row id ="3" > <br> < name > </ name > <br> < weight > 13 </ weight > <br> </ row > <br> < row id ="4" > <br> < name > </ name > <br> < weight > 2 </ weight > <br> </ row > <br> < row id ="5" > <br> < name > </ name > <br> < weight > 20 </ weight > <br> </ row > <br> < row id ="6" > <br> < name > </ name > <br> < weight > 1 </ weight > <br> </ row > <br> < row id ="7" > <br> < name > </ name > <br> < weight > 7 </ weight > <br> </ row > <br> < row id ="8" > <br> < name > </ name > <br> < weight > 14 </ weight > <br> </ row > <br> </ cloud > <br><br> * This source code was highlighted with Source Code Highlighter .


now do the conversion:

<? xml version ="1.0" encoding ="utf-8" ? > <br> < xsl:stylesheet version ="1.0" xmlns:xsl ="http://www.w3.org/1999/XSL/Transform" > <br> <br> < xsl:template match ="/" > <br> < html > <br> < body > <br> < xsl:apply-templates /> <br> </ body > <br> </ html > <br> </ xsl:template > <br> <br> < xsl:template match ="cloud" > <br> < xsl:variable name ="theMax" select ="row[not(weight < ../row/weight)]/weight" /> <br> < xsl:variable name ="theMin" select ="row[not(weight > ../row/weight)]/weight" /> <br> <br> < xsl:variable name ="perc100" select ="$theMax - $theMin" /> <br> < xsl:variable name ="perc1" > <br> < xsl:choose > <br> < xsl:when test ="$perc100 = 0" > 100 </ xsl:when > <br> < xsl:otherwise >< xsl:value-of select ="100 div $perc100" /></ xsl:otherwise > <br> </ xsl:choose > <br> </ xsl:variable > <br> <br> < xsl:variable name ="maxfont" > 26 </ xsl:variable > <br> < xsl:variable name ="minfont" > 11 </ xsl:variable > <br> <br> < xsl:variable name ="font" select ="$maxfont - $minfont" /> <br> < div style ="width:300px" > <br> < xsl:for-each select ="row" > <br> < xsl:variable name ="size" select ="$minfont + ceiling($font div 100 * ((weight - $theMin) * $perc1))" /> <br> < a href ="/tag/{name}" style ="font-size: {$size}px" > <br> < xsl:value-of select ="name" /> <br> </ a > <br> < xsl:if test ="position() != last()" >< xsl:text > </ xsl:text ></ xsl:if > <br> </ xsl:for-each > <br> </ div > <br> </ xsl:template > <br> <br> </ xsl:stylesheet > <br><br> * This source code was highlighted with Source Code Highlighter .
<? xml version ="1.0" encoding ="utf-8" ? > <br> < xsl:stylesheet version ="1.0" xmlns:xsl ="http://www.w3.org/1999/XSL/Transform" > <br> <br> < xsl:template match ="/" > <br> < html > <br> < body > <br> < xsl:apply-templates /> <br> </ body > <br> </ html > <br> </ xsl:template > <br> <br> < xsl:template match ="cloud" > <br> < xsl:variable name ="theMax" select ="row[not(weight < ../row/weight)]/weight" /> <br> < xsl:variable name ="theMin" select ="row[not(weight > ../row/weight)]/weight" /> <br> <br> < xsl:variable name ="perc100" select ="$theMax - $theMin" /> <br> < xsl:variable name ="perc1" > <br> < xsl:choose > <br> < xsl:when test ="$perc100 = 0" > 100 </ xsl:when > <br> < xsl:otherwise >< xsl:value-of select ="100 div $perc100" /></ xsl:otherwise > <br> </ xsl:choose > <br> </ xsl:variable > <br> <br> < xsl:variable name ="maxfont" > 26 </ xsl:variable > <br> < xsl:variable name ="minfont" > 11 </ xsl:variable > <br> <br> < xsl:variable name ="font" select ="$maxfont - $minfont" /> <br> < div style ="width:300px" > <br> < xsl:for-each select ="row" > <br> < xsl:variable name ="size" select ="$minfont + ceiling($font div 100 * ((weight - $theMin) * $perc1))" /> <br> < a href ="/tag/{name}" style ="font-size: {$size}px" > <br> < xsl:value-of select ="name" /> <br> </ a > <br> < xsl:if test ="position() != last()" >< xsl:text > </ xsl:text ></ xsl:if > <br> </ xsl:for-each > <br> </ div > <br> </ xsl:template > <br> <br> </ xsl:stylesheet > <br><br> * This source code was highlighted with Source Code Highlighter .

The variables $ minfont and $ maxfont specify the font size of the tag in pixels. The remaining calculations are necessary in order to understand how many pixels you need to add to $ minfont depending on the size of the "weight" of a particular tag. You can transfer this from the variables to the template parameters, and then in different parts of the site you can specify different values ​​for the maximum and minimum font sizes when calling the template for a more harmonious display.
As a result of the calculations, the values ​​change quite smoothly, and tags with small differences in weight with a small range from $ minfont to $ maxfont will have the same size.

As a result of the above transformation, we get the following HTML:

< html > <br> < body > <br> < div style ="width: 300px;" > <br> < a href ="/tag/" style ="font-size: 12px;" title ="weight: 2" > </ a > <br> < a href ="/tag/ " style ="font-size: 26px;" title ="weight: 20" > </ a > <br> < a href ="/tag/" style ="font-size: 21px;" title ="weight: 13" > </ a > <br> < a href ="/tag/" style ="font-size: 12px;" title ="weight: 2" > </ a > <br> < a href ="/tag/" style ="font-size: 26px;" title ="weight: 20" > </ a > <br> < a href ="/tag/" style ="font-size: 11px;" title ="weight: 1" > </ a > <br> < a href ="/tag/" style ="font-size: 16px;" title ="weight: 7" > </ a > <br> < a href ="/tag/" style ="font-size: 22px;" title ="weight: 14" > </ a > <br> </ div > <br> </ body > <br> </ html > <br><br> * This source code was highlighted with Source Code Highlighter .
< html > <br> < body > <br> < div style ="width: 300px;" > <br> < a href ="/tag/" style ="font-size: 12px;" title ="weight: 2" > </ a > <br> < a href ="/tag/ " style ="font-size: 26px;" title ="weight: 20" > </ a > <br> < a href ="/tag/" style ="font-size: 21px;" title ="weight: 13" > </ a > <br> < a href ="/tag/" style ="font-size: 12px;" title ="weight: 2" > </ a > <br> < a href ="/tag/" style ="font-size: 26px;" title ="weight: 20" > </ a > <br> < a href ="/tag/" style ="font-size: 11px;" title ="weight: 1" > </ a > <br> < a href ="/tag/" style ="font-size: 16px;" title ="weight: 7" > </ a > <br> < a href ="/tag/" style ="font-size: 22px;" title ="weight: 14" > </ a > <br> </ div > <br> </ body > <br> </ html > <br><br> * This source code was highlighted with Source Code Highlighter .
< html > <br> < body > <br> < div style ="width: 300px;" > <br> < a href ="/tag/" style ="font-size: 12px;" title ="weight: 2" > </ a > <br> < a href ="/tag/ " style ="font-size: 26px;" title ="weight: 20" > </ a > <br> < a href ="/tag/" style ="font-size: 21px;" title ="weight: 13" > </ a > <br> < a href ="/tag/" style ="font-size: 12px;" title ="weight: 2" > </ a > <br> < a href ="/tag/" style ="font-size: 26px;" title ="weight: 20" > </ a > <br> < a href ="/tag/" style ="font-size: 11px;" title ="weight: 1" > </ a > <br> < a href ="/tag/" style ="font-size: 16px;" title ="weight: 7" > </ a > <br> < a href ="/tag/" style ="font-size: 22px;" title ="weight: 14" > </ a > <br> </ div > <br> </ body > <br> </ html > <br><br> * This source code was highlighted with Source Code Highlighter .

And it looks like this:


Thus, a tag cloud can be generated using client-side XSLT transformations.

Constructive criticism is welcome. I would be glad if it is useful not only to me. :)

Source: https://habr.com/ru/post/114983/


All Articles