Как стать автором
Обновить

Облако тегов средствами XSLT

Время на прочтение7 мин
Количество просмотров2.9K
Не так давно столкнулся с необходимостью реализовать на одном из проектов то, что в народе называют «облаком тегов» — набор ссылок, в котором наиболее «весомые» элементы имеют бОльший размер. Для этого можно было бы, конечно, посчитать и получить все необходимые данные в PHP, на котором работает проект, но мне хотелось сделать конечный вариант отображения на XSLT и CSS, чтобы все необходимые величины для конфигурирования максимальных/минимальных размеров шрифта, например, были заданы в представлении, а не в логике приложения.

Возможно, кому-то мой опыт окажется полезным, поэтому публикую конечное решение здесь.

Итак, на входе у нас есть простейший 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-преобразований.

Конструктивная критика приветствуется. Буду рад, если пригодится не только мне. :)
Теги:
Хабы:
Всего голосов 36: ↑29 и ↓7+22
Комментарии31

Публикации

Истории

Ближайшие события

15 – 16 ноября
IT-конференция Merge Skolkovo
Москва
22 – 24 ноября
Хакатон «AgroCode Hack Genetics'24»
Онлайн
28 ноября
Конференция «TechRec: ITHR CAMPUS»
МоскваОнлайн
25 – 26 апреля
IT-конференция Merge Tatarstan 2025
Казань