Таблицы в несколько колонок в XSLT-шаблонах

Материал из Umicms
Перейти к:навигация, поиск


Замечание

Если вы столкнулись с этим вопросом и пытаетесь вывести не табличные данные, то следует обратить внимание на использование "плавающих" элементов (например, элементы 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() &lt; $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)}">&#160;</td>
	</xsl:if>
 </xsl:template>

</xsl:stylesheet>

Как и в первом примере, сначала мы выбрали 1-й элемент item и каждый элемент item, позиция которого при делении на $colnum дает остаток 1 (то есть каждый элемент, который должен попасть на новую строку таблицы).

Второй шаблон создает элемент tr, и выбирает текущий элемент item а также необходимое количество его следующих соседей. Здесь мы опять используем ось following-sibling.

Два последних шаблона обрабатывают случаи для всех элементов и для последнего элемента списка. Для последнего элемента необходимо предусмотреть случай, когда число элементов не кратно $colnum - в этом случае мы добавим элемент td с соответствующим значением colspan.

Символьная ссылка &#160; используется вместо сущности, обозначающей неразрывный пробел (см. также Определение сущностей в 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>