Не так давно столкнулся с необходимостью реализовать на одном из проектов то, что в народе называют «облаком тегов» — набор ссылок, в котором наиболее «весомые» элементы имеют бОльший размер. Для этого можно было бы, конечно, посчитать и получить все необходимые данные в PHP, на котором работает проект, но мне хотелось сделать конечный вариант отображения на XSLT и CSS, чтобы все необходимые величины для конфигурирования максимальных/минимальных размеров шрифта, например, были заданы в представлении, а не в логике приложения.
Возможно, кому-то мой опыт окажется полезным, поэтому публикую конечное решение здесь.
Итак, на входе у нас есть простейший XML с тегом и количеством его упоминаний:
Возможно, кому-то мой опыт окажется полезным, поэтому публикую конечное решение здесь.
Итак, на входе у нас есть простейший XML с тегом и количеством его упоминаний:
<?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><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.
В переменные $minfont и $maxfont задаются значения размера шрифта тега в пикселях. Остальные вычисления необходимы для того, чтобы понять, какое количество пикселей нужно прибавить к $minfont в зависимости от величины «веса» того или иного тега. Можно перенести это из переменных в параметры шаблона, и тогда в разных местах сайта можно будет указывать разные значения максимального и минимального размеров шрифтов при вызове шаблона, для более гармоничного отображения.
В результате вычислений значения изменяются довольно плавно, и теги с небольшими различиями в весе при небольшом диапазоне от $minfont до $maxfont будут иметь одинаковый размер.
В результате представленного выше преобразования, получаем следующий 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.
А выглядит это так:
Таким образом генерировать облако тегов можно и при помощи client-side XSLT-преобразований.
Конструктивная критика приветствуется. Буду рад, если пригодится не только мне. :)