воскресенье, 6 марта 2011 г.

XSLT

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

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

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

Итак, на входе у нас есть простейший XML с тегом и количеством его упоминаний:

<?xml version="1.0" encoding="utf-8" ?>
<cloud>
       <row id="1">
                <name>биология</name>
                <weight>2</weight>
        </row>
        <row id="2">
                   <name>русский язык</name>
                   <weight>20</weight>
        </row>
        <row id="3">
                        <name>алгебра</name>
                        <weight>13</weight>
         </row>
         <row id="4">
                       <name>география</name>
                       <weight>2</weight>
         </row>
         <row id="5">
                                <name>физкультура</name>
                                        <weight>20</weight>
          </row>
          <row id="6">
                                <name>астрономия</name>
                                <weight>1</weight>
          </row>
          <row id="7">
                                <name>правоведение</name>
                                <weight>7</weight>
          </row>
          <row id="8">
                                  <name>история</name>
                                       <weight>14</weight>
</row>
</cloud>

* This source code was highlighted with Source Code Highlighter.


теперь сделаем преобразование:


<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/">
<html>
<body>
<xsl:apply-templates />
</body>
</html>
</xsl:template>

<xsl:template match="cloud">
<xsl:variable name="theMax" select="row[not(weight < ../row/weight)]/weight" />
<xsl:variable name="theMin" select="row[not(weight > ../row/weight)]/weight" />

<xsl:variable name="perc100" select="$theMax - $theMin"/>
<xsl:variable name="perc1">
<xsl:choose>
<xsl:when test="$perc100 = 0">100</xsl:when>
<xsl:otherwise><xsl:value-of select="100 div $perc100"/></xsl:otherwise>
</xsl:choose>
</xsl:variable>

<xsl:variable name="maxfont">26</xsl:variable>
<xsl:variable name="minfont">11</xsl:variable>

<xsl:variable name="font" select="$maxfont - $minfont"/>
<div style="width:300px">
<xsl:for-each select="row">
<xsl:variable name="size" select="$minfont + ceiling($font div 100 * ((weight - $theMin) * $perc1))"/>
<a href="/tag/{name}" style="font-size: {$size}px">
<xsl:value-of select="name" />
</a>
<xsl:if test="position() != last()"><xsl:text> </xsl:text></xsl:if>
</xsl:for-each>
</div>
</xsl:template>

</xsl:stylesheet>

* This source code was highlighted with Source Code Highlighter.

В переменные $minfont и $maxfont задаются значения размера шрифта тега в пикселях. Остальные вычисления необходимы для того, чтобы понять, какое количество пикселей нужно прибавить к $minfont в зависимости от величины «веса» того или иного тега. Можно перенести это из переменных в параметры шаблона, и тогда в разных местах сайта можно будет указывать разные значения максимального и минимального размеров шрифтов при вызове шаблона, для более гармоничного отображения.
В результате вычислений значения изменяются довольно плавно, и теги с небольшими различиями в весе при небольшом диапазоне от $minfont до $maxfont будут иметь одинаковый размер.

В результате представленного выше преобразования, получаем следующий HTML:

<html>
<body>
<div style="width: 300px;">
<a href="/tag/биология" style="font-size: 12px;" title="weight: 2">биология</a>
<a href="/tag/русский язык" style="font-size: 26px;" title="weight: 20">русский язык</a>
<a href="/tag/алгебра" style="font-size: 21px;" title="weight: 13">алгебра</a>
<a href="/tag/география" style="font-size: 12px;" title="weight: 2">география</a>
<a href="/tag/физкультура" style="font-size: 26px;" title="weight: 20">физкультура</a>
<a href="/tag/астрономия" style="font-size: 11px;" title="weight: 1">астрономия</a>
<a href="/tag/правоведение" style="font-size: 16px;" title="weight: 7">правоведение</a>
<a href="/tag/история" style="font-size: 22px;" title="weight: 14">история</a>
</div>
</body>
</html>

* This source code was highlighted with Source Code Highlighter.

А выглядит это так:









Таким образом генерировать облако тегов можно и при помощи client-side XSLT-преобразований.

Конструктивная критика приветствуется. Буду рад, если пригодится не только мне. :)




 

Комментариев нет:

Отправить комментарий