<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl"  href="/xslt/final.xslt"?><html>
  <head>
    <title>XSLT- примеры. Вып.5 Вывод данных данных в несколько колонок HTML-таблицы</title>
    <meta name="css" content=""/>
    <meta name="js" content=""/>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <meta name="id" content="26"/>
    <link rel="alternate" type="application/rss+xml" title="RSS" href="/rss.xml"/>
  </head>
  <body>
    <div class="main">
      <div class="wrap">
        <div class="L">
          <h1><a href="/">..</a> / XSLT- примеры. Вып.5 Вывод данных данных в несколько колонок HTML-таблицы</h1>
          <ol class="tags big">
            <li>
              <a href="/xslt-examples">xslt-examples</a>
            </li>
            <li>
              <a href="/xslt-group">xslt-group</a>
            </li>
          </ol>
          <div class="myContent"><p>В отличие от предыдущих четырех выпусков этот посвящен достаточно часто встречающейся задаче.  Предположем есть витрина магазина. Для нее сформирован список товаров. Товары нужно разместить в несколько колонок в таблице, так чтобы каждый товар попал в свою ячейку, как например это сделано на <a href="#" title="www.amazon.com/s/ref=nb_ss_shoe?url=node%3D679486011&amp;field-keywords=&amp;x=12&amp;y=26" rel="nofollow" class="external">Амазоне</a></p>
<p>Рассмотрим несколько возможных вариантов группировки товаров по ячейкам таблицы. В качестве входного XML  возьмем известный из предыдущих выпусков список книг:</p>

<table class="code">
    <tbody>
        <tr>
            <td><!--php-->
            <pre class="brush: plain">&lt;books&gt;
   &lt;book author="Багряк П."  cost="123" type="old"&gt;   Синие люди&lt;/book&gt;                
   &lt;book author="Булгаков М."  cost="34" type="old"&gt;   Роковые яйца&lt;/book&gt;           

     
....................................................

        
   &lt;book author="Ленин В.И."  cost="344" type="old"&gt;   Что делать&lt;/book&gt;                
            &lt;/books&gt;   </pre><!--/php--></td>
        </tr>
    </tbody>
</table>
<p> </p>
<h2>Пример 1.  Вывод товаров в три колонки</h2>
<p>На Амазоне товары размещены в три колонки. Ну и наш менеджер хочет чтобы было все как на Амазоне (типа такой же богатый будет как <span>Джефф Безос</span>)</p>

<table class="code">
    <tbody>
        <tr>
            <td><!--php-->
            <pre class="brush: plain">&lt;xsl:template match="books"&gt;
       &lt;table&gt;  
            &lt;xsl:apply-templates select="book"/&gt;  
       &lt;/table&gt;         
   &lt;/xsl:template&gt;     
   
   &lt;xsl:template match="book"&gt;  
       &lt;xsl:variable name="i" select="position()"/&gt;  
        &lt;xsl:if test="$i mod 3  = 1"&gt;  
        &lt;tr class="{$i}"&gt;  
          &lt;td&gt;   &lt;xsl:value-of select="." /&gt;   &lt;/td&gt;  
          &lt;td&gt;   &lt;xsl:value-of select="../book[$i+1]" /&gt;   &lt;/td&gt;  
          &lt;td&gt;   &lt;xsl:value-of select="../book[$i+2]" /&gt;   &lt;/td&gt;  
      &lt;/tr&gt;  
        &lt;/xsl:if&gt;  
   &lt;/xsl:template&gt;  
   
  </pre><!--/php--></td>
        </tr>
    </tbody>
</table>
<p> </p>
<p>Первый шаблон <span style="font-weight: bold;">match="books"</span> запускает в обработку весь список книг. Внутри него вызывается шаблон обработки каждой книги в отдельности. В нем происходит группировка по колонкам.<br/>
В шаблоне <span style="font-weight: bold;">match="book" </span>производится проверка номера позиции <span style="font-weight: bold;">position()</span> книги в списке. И производится разбивка списка по тройке книг из которых формируется строка таблицы.</p>
<p>Сделали и порадовались. Но как обычно по ходу задачи аналитики уточнили задачу. Теперь они захотели изменить порядок следования товаров так, чтобы размещение товаров в таблице шло не по горизонтали, а по вертикали.  Т.е. чтобы порядок был таким:</p>

<table width="200" cellspacing="1" cellpadding="1" border="1">
    <tbody>
        <tr>
            <td>1</td>
            <td>4</td>
            <td>7</td>
        </tr>
        <tr>
            <td>2</td>
            <td>5</td>
            <td>8</td>
        </tr>
        <tr>
            <td>3</td>
            <td>6</td>
            <td>9</td>
        </tr>
    </tbody>
</table>
<p>Ну пожалуйста.</p>
<h2>Пример 1a.  Изменение порядка вывода элементов в таблице</h2>
<p> </p>

<table class="code">
    <tbody>
        <tr>
            <td><!--php-->
            <pre class="brush: plain">&lt;xsl:template match="books"&gt;
       &lt;xsl:variable name="N" select="ceiling(count(book) div 3)"&gt;   &lt;/xsl:variable&gt;  
       &lt;table&gt;  
            &lt;xsl:apply-templates select="book"&gt;  
                &lt;xsl:with-param name="N" select="$N"/&gt;  
            &lt;/xsl:apply-templates&gt;  
       &lt;/table&gt;         
   &lt;/xsl:template&gt;     
   
   &lt;xsl:template match="book"&gt;  
       &lt;xsl:param name="N"/&gt;  
       &lt;xsl:variable name="i" select="position()"/&gt;  
     &lt;xsl:if test="$N &gt;   = $i"&gt;  
         &lt;tr &gt;  
         &lt;td class="{$i}"&gt;   &lt;xsl:value-of select="."/&gt;   &lt;/td&gt;  
             &lt;td&gt;   &lt;xsl:value-of select="../book[$i+$N]"/&gt;   &lt;/td&gt;  
             &lt;td&gt;   &lt;xsl:value-of select="../book[$i+$N*2]"/&gt;   &lt;/td&gt;  
         &lt;/tr&gt;  
     &lt;/xsl:if&gt;  
  

   &lt;/xsl:template&gt;   </pre><!--/php--></td>
        </tr>
    </tbody>
</table>
<p>Пример практически аналогичный предыдущему.  Но теперь тройки товаров в одной строке таблицы формируются по другому принципу.  Определяется шаг, на котором отстоят друг от друга товары в соседних ячейках одной строки (переменная N), очевидно этот шаг равен одной трети от общего числа книг в списке.</p>
<p>Шаблон <span style="font-weight: bold;">match="book"</span> проводит проверку позиции книги в списке и из первой трети формирует строки таблицы, размещая в первую строку текущий элемент. Во вторую ясейку строки  записываются книги отстоящие от текущей на N, в третью - на N*2</p>
<p>Сделали и порадовались, но новый редактор сайта захотел разместить все не в три, а в пять колонок как на Эльдорадо!  Поскольку завтра он или его сменщик снова изменит  число колонок желательно предусмотреть универсальный вариант, в котором количество колонок может быть произвольным и удовлетворит любого нового редактора/менеджера/аналитика.</p>
<h2>Пример 2. Произвольное число колонок в таблице.</h2>

<table class="code">
    <tbody>
        <tr>
            <td><!--php-->
            <pre class="brush: plain">&lt;xsl:template match="books"&gt;
       &lt;table&gt;  
           &lt;xsl:for-each select="book[position() mod 3= 1]"&gt;  
               &lt;tr&gt;  
                   &lt;xsl:apply-templates    select=".
following-sibling::book[position() &lt;3]"/&gt;  
               &lt;/tr&gt;  
               &lt;/xsl:for-each&gt;  
       &lt;/table&gt;         
   &lt;/xsl:template&gt;     
   
   &lt;xsl:template match="book"&gt;  
       &lt;td&gt;  
           &lt;xsl:value-of select="." /&gt;  
       &lt;/td&gt;  
   &lt;/xsl:template&gt;   </pre><!--/php--></td>
        </tr>
    </tbody>
</table>
<p>Здесь я немного отступаю от xslt fun style и ввожу для разнообразия оператор цикла. Который делает абсолютно то же самое самое что условие <span style="font-weight: bold;">if</span> в предыдущем примере (1) - запускает обработку каждого третьего элемента списка. При этом остальные элементы обрабатываются отдельно. <br/>
<br/>
Условие для формирование тройки элементов на каждом шаге использует <a href="#" title="www.citforum.ru/internet/xpath/xpath02.shtml#axes" rel="nofollow" class="external">ось following-sibling</a> - ось последующих за текущим элементов.  Запускается на обработку текущий элемент и следующие за ним два элемента.  Образец шаблона <span style="font-weight: bold;">match="book"</span> здесь производит только запись книги в ячейку таблицы.</p>
<p>Все здорово. Но новый главный редактор захотел в каждой ячейки таблицы дать рамочку. А в нашем шаблоне список книг не кратен трем. В результате последняя ячейка не выводитс и таблица получается немного с обгрызенным углом. Придется все переделывать и делать еще более универсальное решение.</p>
<h2>Пример 3.</h2>

<table class="code">
    <tbody>
        <tr>
            <td><!--php-->
            <pre class="brush: plain">   
&lt;xsl:template match="books"&gt;  
       &lt;xsl:variable name="ColNum" select="3"/&gt;  
       &lt;xsl:variable name="Colbook" select="count(book)"&gt;   &lt;/xsl:variable&gt;  

     &lt;table&gt;  
         &lt;xsl:for-each select="book[position() mod $ColNum= 1]"&gt;  
             
         &lt;tr&gt;  
             &lt;xsl:apply-templates    
               select=".|following-sibling::book[position() &lt;$ColNum]"/&gt;  
                   &lt;xsl:call-template name="zeroCell"&gt;  
                       &lt;xsl:with-param name="nCol" 
                        select="position() * $ColNum - $Colbook"/&gt;  
                   &lt;/xsl:call-template&gt;  
         &lt;/tr&gt;  
         &lt;/xsl:for-each&gt;  
     &lt;/table&gt;         
 &lt;/xsl:template&gt;     
   
&lt;xsl:template match="book"&gt;  
    &lt;td&gt;  
        &lt;xsl:value-of select="." /&gt;  
    &lt;/td&gt;  
&lt;/xsl:template&gt;  
   
            &lt;xsl:template name="zeroCell"&gt;  
   &lt;xsl:param name="nCol" /&gt;  
   &lt;xsl:for-each select="preceding-sibling::node()[position() &lt;= $nCol]"&gt;  
    &lt;td&gt;   &lt;/td&gt;  
   &lt;/xsl:for-each&gt;  

&lt;/xsl:template&gt;       </pre><!--/php--></td>
        </tr>
    </tbody>
</table>
<p> Пример практически копирует предыдущий. Но как обещано он сделан более универсальным. Количество колонок <strong>ColNum</strong> вынесено в отделную переменную, а втеле цикла<strong> for</strong>  добавлен вызов именованного шаблона <strong>zeroCell</strong>, который добавляет в  концевую строку таблицы пустые ячейки.</p>
<p>Здесь, возможно надо объяснить тонкость связанную с вычислением <strong>position()</strong>. Здесь вычисляет позиция не в общем списке книг, а в наборе book[position() mod $ColNum= 1] Поэтому значение position для последнего элемента списка фактически равно одной трети (мы задали вывод в  три колонки) от общего числа книг.  Поэтому в именованном шаблоне в последней строке добавляется (count(book) mod 3) пустые ячейки.</p>
<p>Как обычно, все исходники можно найти в архиве <a href="../../../../doc/xslt-examples.zip">xslt-examples.zip</a> в директории ex5</p></div>
          <ol class="tags big">
            <li class="date">2008-11-21</li>
            <li>
              <a href="/xslt-examples">xslt-examples</a>
            </li>
            <li>
              <a href="/xslt-group">xslt-group</a>
            </li>
          </ol>
          <ol class="see">
            <li>
              <a href="#"><span>www.dpawson.co.uk/xsl/sect2/N7450.html</span> - <b>Оформление таблиц в "XSLT Questions and Answers - FAQ"  Dave Pawson?s</b></a>
            </li>
            <li>
              <a href="#"><span>erum.ru/article/19</span> - <b>XSLT- примеры. Вып.1 Группировки в XSLT</b></a>
            </li>
            <li>
              <a href="#"><span>www.artlebedev.ru/tools/technogrette/xslt/alpha-index/</span> - <b>Вариант разбиения таблицы у Артемия Лебедева</b></a>
            </li>
          </ol>
          <ul class="comment">
            <li id="a432" title="a0">
              <a name="&#x43D;&#x43E;&#x443;&#x43D;&#x44D;&#x439;&#x43C;&#x44A;" title="" rel="26.01.10"/>
              <div>Здравствуйте.<br/>1. В показанном на экране примере 1a появились пробелы в условии gt;  =  ... в 2 съедена вертикальная |(или) и мнемоника lt; показана браузером как уголок, что делает нерабочими... примеры, скопированные с экрана, хотя в архиве всё правильно.<br/>Что-то похожее и в <a title="/article/16" rel="nofollow" class="external" href="#">ссылка</a>   (на x9.ru всё было правильно)... вот, и какая-то, понимаешь ли, типа-совесть... не дозволяет ставить естественные сцылки, в коих часто нуждаются стрёмные головы, склонные к ереси.xml<br/>Может быть это поправить? Там типа !--php-- маячит.<br/>2. нельзя ли во всяких там .container width:60em... несколько резиновее учесть то обстоятельство, что далеко не все читают в широком окне?<br/>3. Где можно увидеть, хоть и приблизительную, но на актуальную... статистику: какой % каких браузеров понимает XSLT?</div>
            </li>
            <li id="a433" title="a432">
              <a name="&#x418;&#x441;&#x430;&#x430;&#x43A; &#x422;&#x44B;&#x43D;&#x433;&#x44B;&#x43B;&#x447;&#x430;&#x432;" title="erum.ru" rel="26.01.10"/>
              <div>1. Увы. Делал этот блог на скорую руку. Теперь не знаю когда переделать по человечески. <br/>По поводу ссылок - не понял. <br/>2. см. п.1 <br/>3. Все. Даже опера ~ с версии 8.5</div>
            </li>
            <li id="a675" title="a0">
              <a name="&#x41C;&#x43E;&#x439; &#x41C;&#x418;&#x420;" title="" rel="18.12.11"/>
              <div>Neslabo.com<br/>HTML тег &amp;lt;TABLE&amp;gt; создает таблицу. Все прочие элементы HTML таблицы должны быть вложенными в него. Допускается также вложение таблиц одна в другую, т.е. содержимым ячейки может быть другая таблица. Закрывающий тег обязателен.<br/>По умолчанию таблица распологается у левого края страницы и занимает по ширине ровно столько места, чтобы поместить все надписи. Если надпись не помещается, браузер сам переносит ее на новую строку.</div>
            </li>
          </ul>
        </div>
      </div>
      <div class="R">
        <a href="/" title="&#x41D;&#x430; &#x433;&#x43B;&#x430;&#x432;&#x43D;&#x443;&#x44E;"/>
      </div>
    </div>
    <div id="li"/>
  </body>
</html>

