Таблицы в несколько колонок в XSLT-шаблонах
Содержание
Замечание
Если вы столкнулись с этим вопросом и пытаетесь вывести не табличные данные, то следует обратить внимание на использование "плавающих" элементов (например, элементы div с css-свойствами float и min-height). Если этот вариант все-таки не устраивает, тогда можно воспользоваться описанными ниже решениями.
Эти решения также демонстрируют использование осей XPath.
Исходные данные
Есть ответ макроса, например, список объектов каталога:
<udata module="catalog" method="getObjectsList" generation-time="0.302167">−
<lines>
<item id="42" alt_name="sovet_tc1" link="/shop/sovet_tc1/" xlink:href="upage://42">Sovet TC1</item>
<item id="47" alt_name="elektronika_432" link="/shop/elektronika_432/" xlink:href="upage://47">Elektronika 432</item>
<item id="50" alt_name="moskwich" link="/shop/moskwich/" xlink:href="upage://50">Moskwich</item>
<item id="33" alt_name="televizor_horizont" link="/shop/televizor_horizont/" xlink:href="upage://33">Телевизор «Horizont»</item>
<item id="48" alt_name="oki_7" link="/shop/oki_7/" xlink:href="upage://48">Oki 7</item>
<item id="43" alt_name="sovet_tc2" link="/shop/sovet_tc2/" xlink:href="upage://43">Sovet TC2</item>
<item id="51" alt_name="soviet_b1" link="/shop/soviet_b1/" xlink:href="upage://51">Soviet B1</item>
<item id="37" alt_name="televizor_horizont1" link="/shop/televizor_horizont1/" xlink:href="upage://37">Телевизор «LG»</item>
<item id="45" alt_name="sovet_tc3" link="/shop/sovet_tc3/" xlink:href="upage://45">Sovet TC3</item>
<item id="38" alt_name="televizor_horizont2" link="/shop/televizor_horizont2/" xlink:href="upage://38">Телевизор «Panasonic»</item>
<item id="52" alt_name="soviet_ba" link="/shop/soviet_ba/" xlink:href="upage://52">Soviet BA </item>
<item id="53" alt_name="soviet_t7" link="/shop/soviet_t7/" xlink:href="upage://53">Soviet T7</item>
<item id="39" alt_name="televizor_horizont3" link="/shop/televizor_horizont3/" xlink:href="upage://39">Телевизор «Philips»</item>
<item id="40" alt_name="televizor_horizont4" link="/shop/televizor_horizont4/" xlink:href="upage://40">Телевизор «Vityas»</item>
</lines>
<total>14</total>
<per_page>25</per_page>
<category_id>31</category_id>
<type_id>9</type_id>
</udata>
Таблица в 3 колонки
Допустим, мы выводим список объектов каталога из раздела с id = 31. В месте вызова макроса укажем:
<xsl:apply-templates select="document('udata://catalog/getObjectsList/notemplate/31')/udata"/>
Теперь необходимо описать шаблоны обработки результатов макроса:
<xsl:template match="udata[@module = 'catalog'][@method = 'getObjectsList']">
<table>
<xsl:apply-templates select="lines/item[position() = 1]|lines/item[position() mod 3 = 1]"/>
</table>
</xsl:template>
<xsl:template match="item">
<tr>
<td><xsl:value-of select="."/></td>
<td><xsl:value-of select="following-sibling::item[1]"/></td>
<td><xsl:value-of select="following-sibling::item[2]"/></td>
</tr>
</xsl:template>
В первом шаблоне мы выбираем первый элемент item (условие position() = 1), а также каждый следующий 4-й (position() mod 3 = 1).
Второй шаблон выводит элемент tr, внутри которого мы создаем элементы td. В первом элементе td мы выводим значение текущего элемента item при помощи <xsl:value-of select="."/>. Для того, чтобы вывести следующие 2 соседних элемента, мы используем ось following-sibling и указываем, что по этой оси сначала нужно взять 1-й элемент, потом 2-й.
В итоге мы получим следующийх HTML-код:
<table>
<tr>
<td>Sovet TC1</td>
<td>Elektronika 432</td>
<td>Moskwich</td>
</tr>
<tr>
<td>Телевизор «Horizont»</td>
<td>Oki 7</td>
<td>Sovet TC2</td>
</tr>
<tr>
<td>Soviet B1</td>
<td>Телевизор «LG»</td>
<td>Sovet TC3</td>
</tr>
<tr>
<td>Телевизор «Panasonic»</td>
<td>Soviet BA</td>
<td>Soviet T7</td>
</tr>
<tr>
<td>Телевизор «Philips»</td>
<td>Телевизор «Vityas»</td>
<td></td>
</tr>
</table>
Если мы захотим выводить исходные данные в 4 колонки, необходимо будет изменить условие [position() mod 3 = 1] в первом шаблоне на [position() mod 4 = 1] и придется добавить во второй шаблон еще одну строку:
<xsl:template match="item">
<tr>
<td><xsl:value-of select="."/></td>
<td><xsl:value-of select="following-sibling::item[1]"/></td>
<td><xsl:value-of select="following-sibling::item[2]"/></td>
<td><xsl:value-of select="following-sibling::item[3]"/></td>
</tr>
</xsl:template>
Таблица с произвольным числом колонок
Воспользуемся глобальным параметром, который будет регулировать число колонок. Этот параметр необходимо определять на одном уровне с элементами <xsl:template> непосредственно после тега элемента <xsl:output> (использование глобальных параметров в UMI.CMS позволяет принимать значения из GET-параметров в URL - см. Использование GET и POST параметров в XSLT-шаблонах).
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes"/>
<xsl:param name="colnum" select="3"/>
<xsl:template match="/">
... разметка страницы и вызов макроса как и в первом примере ...
</xsl:template>
<!-- шаблоны, обрабатывающие ответ макроса и выводящие таблицу-->
<xsl:template match="udata[@module = 'catalog'][@method = 'getObjectsList']">
<table>
<xsl:apply-templates select="lines/item[position() = 1]|lines/item[position() mod $colnum = 1]"/>
</table>
</xsl:template>
<xsl:template match="item">
<tr>
<xsl:apply-templates select=".|following-sibling::item[position() < $colnum]" mode="td"/>
</tr>
</xsl:template>
<xsl:template match="item" mode="td">
<td><xsl:value-of select="."/></td>
</xsl:template>
<xsl:template match="item[position() = last()]" mode="td">
<td><xsl:value-of select="."/></td>
<xsl:if test="position() mod $colnum">
<td colspan="{$colnum - (position() mod $colnum)}"> </td>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Как и в первом примере, сначала мы выбрали 1-й элемент item и каждый элемент item, позиция которого при делении на $colnum дает остаток 1 (то есть каждый элемент, который должен попасть на новую строку таблицы).
Второй шаблон создает элемент tr, и выбирает текущий элемент item а также необходимое количество его следующих соседей. Здесь мы опять используем ось following-sibling.
Два последних шаблона обрабатывают случаи для всех элементов и для последнего элемента списка. Для последнего элемента необходимо предусмотреть случай, когда число элементов не кратно $colnum - в этом случае мы добавим элемент td с соответствующим значением colspan.
Символьная ссылка   используется вместо сущности, обозначающей неразрывный пробел (см. также Определение сущностей в XSLT-шаблонах)
Теперь, если мы запросим страницу с параметром: http://адрес_сайта/?colnum=4, то получим следующий HTML-код:
<table>
<tr>
<td>Sovet TC1</td>
<td>Elektronika 432</td>
<td>Moskwich</td>
<td>Телевизор «Horizont»</td>
</tr>
<tr>
<td>Oki 7</td>
<td>Sovet TC2</td>
<td>Soviet B1</td>
<td>Телевизор «LG»</td>
</tr>
<tr>
<td>Sovet TC3</td>
<td>Телевизор «Panasonic»</td>
<td>Soviet BA</td>
<td>Soviet T7</td>
</tr>
<tr>
<td>Телевизор «Philips»</td>
<td>Телевизор «Vityas»</td>
<td colspan="2"> </td>
</tr>
</table>