<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl"  href="/xslt/final.xslt"?><html>
  <head>
    <title>XSLT- примеры. Вып.6  Разворачиваем деревья</title>
    <meta name="css" content=""/>
    <meta name="js" content=""/>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <meta name="id" content="28"/>
    <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- примеры. Вып.6  Разворачиваем деревья</h1>
          <ol class="tags big">
            <li>
              <a href="/xslt-recursive">xslt-recursive</a>
            </li>
            <li>
              <a href="/xslt-examples">xslt-examples</a>
            </li>
            <li>
              <a href="/xslt-group">xslt-group</a>
            </li>
            <li>
              <a href="/client-side-xslt">client-side-xslt</a>
            </li>
          </ol>
          <div class="myContent"><p>Вывод данных в виде древовидных структур - задача достаточно типовая. Это может быть дерево сообщений в форумах и блогах, подобных этому, отображение карты сайта, различные многоуровневые рубрикаторы и т.п.  Способов организации таких структур в базах данных достаточно много, материалов в Сети тоже (см. пордборку в конце этой заметки).  Применительно к блогу рассмотрим самый простой (но не самый эффективный) способ, при котором в каждой записи хранится свой идентентификатор id и идентификатор родителя parentid. В виде XML ветка обсуждения в блоге имеет вид типа:</p>

<table class="code">
    <tbody>
        <tr>
            <td><!--php-->
            <pre class="brush: plain">&lt;item&gt;
&lt;topic id="1"  parentid="0" author="Иванов И.И." &gt;  Лучший шаблонизатор - PHP&lt;/topic&gt; 
&lt;topic id="9"  parentid="8" author="Говорухо-Отрок С.П." &gt;  Smarty - вот шаблонизатор&lt;/topic&gt; 
&lt;topic id="13"  parentid="9" author="Тынгылчав И.И." &gt;  Нет Smarty это дурь&lt;/topic&gt; 
&lt;topic id="14"  parentid="13" author="Рабинович П.Е." &gt;  Нет. дурь - это не Smarty&lt;/topic&gt; 
&lt;topic id="15"  parentid="9" author="Вышку Н.Н." &gt;  Кто про дурь говорит?&lt;/topic&gt; 
....................................................................................
....................................................................................
....................................................................................
&lt;/item&gt;  </pre><!--/php--></td>
        </tr>
    </tbody>
</table>
<p> Как приличные люди, мы должны организовать вывод этой ветки в виде <a href="#" title="pepelsbey.net/2008/04/semantic-coding-1/" rel="nofollow" class="external">семантически-грамотной верстки</a>. Все сообщения в совокупности - ненумерованный список UL. Каждоее сообщение в отдельности - элемент ненумерованного списка LI. Каждое сообщение может иметь вложенный список сообщений - откликов.  </p>

<table class="code">
    <tbody>
        <tr>
            <td><!--php-->
            <pre class="brush: plain">&lt;ul&gt;
     &lt;li  id="1"&gt;  &lt;h3&gt;  Иванов И.И."&lt;/h3&gt;      Лучший шаблонизатор - PHP
         &lt;ul&gt; 
             &lt;li  id="9"&gt;  &lt;h3&gt;  Говорухо-Отрок С.П.&lt;/h3&gt;  Smarty - вот шаблонизатор
                &lt;ul&gt; 
                  &lt;li  id="13"&gt;  &lt;h3&gt;  Тынгылчав И.И.&lt;/h3&gt;  Нет Smarty - это дурь&lt;/li&gt; 
                     &lt;ul&gt; 
                        &lt;li  id="14"&gt;  &lt;h3&gt;  Рабинович П.Е.&lt;/h3&gt;  Нет. дурь - это не Smarty&lt;/li&gt; 
....................................................................................
....................................................................................
                     &lt;/ul&gt; 
                 &lt;/ul&gt; 
             &lt;/li&gt; 
         &lt;/ul&gt; 
  &lt;/li&gt; 
&lt;/ul&gt;  </pre><!--/php--></td>
        </tr>
    </tbody>
</table>
<p>Шаблон для такого преобразования достаточно простой.</p>

<table class="code">
    <tbody>
        <tr>
            <td><!--php-->
            <pre class="brush: plain">&lt;xsl:template match="item"&gt;
     &lt;ul&gt; 
         &lt;xsl:apply-templates select="topic[@parentid=0]" /&gt; 
     &lt;/ul&gt; 
 &lt;/xsl:template&gt; 

 &lt;xsl:template match="topic"&gt; 
     &lt;xsl:variable name="id" select="@id"/&gt; 
     &lt;li id="{@id}"&gt;   &lt;h3&gt;   &lt;xsl:value-of select="@author"/&gt;  пишет:&lt;/h3&gt; 
         &lt;p&gt;   &lt;xsl:apply-templates/&gt;   &lt;/p&gt; 
           &lt;ul&gt; 
               &lt;xsl:apply-templates select="../topic[@parentid=$id]"/&gt; 
           &lt;/ul&gt; 
     &lt;/li&gt; 
    
 &lt;/xsl:template&gt;   </pre><!--/php--></td>
        </tr>
    </tbody>
</table>
<p>Первый шаблон (match="item") зацепляет первое сообщение ветки обсуждения у которого нет родителя. Т.е. parentid=0. Далее запускается <a href="/tags/xslt-recursive/">рекурсивная процедура</a>  (match="topic") которая выводит текущее сообщение и вытаскивает всех детей этой ветки. Т.е. сообщения являющиеся откликом непосредственно на текущее.</p>
<p>Как всегда не могу не сделать замечания относительно производительности. XSLT-преобразования ресурсоемкие. Запускать в них итерации не всегда разумно. Хотя в моем блоге формирование дерева производится не на стороне сервера, а на стороне клиента. За счет этого производительность не страдает. Но <a href="/tags/client-side-xslt/">клиентское XSLT-преобразование</a>  - экзотика, допустимая только из любви к искусству. По крайней мере ближайшие годы.</p>
<p>Как обычно, все исходники можно найти в архиве <a href="../../../../doc/xslt-examples.zip">xslt-examples.zip</a> в директории ex6</p></div>
          <ol class="tags big">
            <li class="date">2008-12-08</li>
            <li>
              <a href="/xslt-recursive">xslt-recursive</a>
            </li>
            <li>
              <a href="/xslt-examples">xslt-examples</a>
            </li>
            <li>
              <a href="/xslt-group">xslt-group</a>
            </li>
            <li>
              <a href="/client-side-xslt">client-side-xslt</a>
            </li>
          </ol>
          <ol class="see">
            <li>
              <a href="#"><span>www.realcoding.net/article/view/2766</span> - <b>Отрисовка связанного дерева с помощью XSLT и XPath</b></a>
            </li>
            <li>
              <a href="#"><span>bassistance.de/jquery-plugins/jquery-plugin-treeview/</span> - <b>jQuery plugin: Treeview (Отображение деревьев при помощи  плагинов jquery)</b></a>
            </li>
            <li>
              <a href="#"><span>phpclub.ru/faq/Tree?v=w5u</span> - <b>FAQ от  phpclub. Способы хранения деревьев в базах данных</b></a>
            </li>
            <li>
              <a href="#"><span>erum.ru/article/21</span> - <b>Моя CSS-подборка. См. раздел "Деревья"</b></a>
            </li>
            <li>
              <a href="#"><span>javascript.ru/unsorted/tree</span> - <b>Грамотное javascript-дерево за 7 шагов (рецепты от javascript.ru)</b></a>
            </li>
            <li>
              <a href="#"><span>www.alexandersperl.de/tutorials/css/sitemap.php</span> - <b>Hierarchical Sitemap with Dashed Lines (Отображение деревьев чистым CSS)</b></a>
            </li>
          </ol>
          <ul class="comment">
            <li id="a193" title="a0">
              <a name="developer" title="" rel="08.12.08"/>
              <div>Не хватает проверки на наличие вложенных сообщений. Появляются пустые ul.</div>
            </li>
            <li id="a329" title="a0">
              <a name="&#x41B;&#x435;&#x448;&#x430;" title="lesha.dn.ua" rel="26.08.09"/>
              <div>Ну нету так нету ) допиши сам. Функция XPath - count поможет)</div>
            </li>
            <li id="a330" title="a329">
              <a name="&#x418;&#x441;&#x430;&#x430;&#x43A; &#x422;&#x44B;&#x43D;&#x433;&#x44B;&#x43B;&#x447;&#x430;&#x432;" title="" rel="26.08.09"/>
              <div>Нафига count? Можно проверить на наличие дочерних li. Получится дешевле. <br/>Непонятно только откуда эти пустые ul возьмутся.</div>
            </li>
            <li id="a602" title="a0">
              <a name="Le capitaine Nemo" title="" rel="12.03.11"/>
              <div>Хороший рабочий пример рекурсии. То что и требовалось, спасибо.</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>

