(495) 925-0049, ITShop интернет-магазин 229-0436, Учебный Центр 925-0049
  Главная страница Карта сайта Контакты
Поиск
Вход
Регистрация
Рассылки сайта
 
 
 
 
 

Использование xslt-шаблонов в реальных проектах

Источник: habrahabr
Holden

В статье вы не найдёте сравнительных тестов шаблонизаторов. Зато найдёте информацию об использовании xslt в качестве шаблонизатора на реальных проектах. Рассмотрены возможности именованных шаблонов, использование шаблонов-функций, справочников.

1. Структура проекта


Обычно страница сайта состоит из нескольких общих блоков (меню, футер, ...) и контентной части, которую для общности будем называть основным блоком. Все эти блоки размещаются внутри некоторого индексного шаблона, который знает в каком месте какой блок отобразить: меню должно быть вверху, основной блок в центре, а футер внизу.

Получаем следующую структуру

/themes - здесь раполагаются все шаблоны
/themes/index/main.xsl - индексный шаблон
/themes/models/user.xsl - именованные шаблоны, которые относятся к модели пользователя
/themes/inc/functions.xsl - именованные шаблоны-функции
/themes/blocks/footer.xsl - шаблон футера
/themes/blocks/menu.xsl - шаблон меню
/themes/cabinet/main.xsl - шаблон основного блока главной страницы кабинета пользователя

Контроллер главной страницы кабинета пользователя работает следующим образом:

  1. получает данные для основного блока, обрабатывает их с помощью /themes/cabinet/main.xsl и результат (готовый html) помещает в итоговый xml
  2. аналогично обрабатывает данные для других блоков (меню, футер) и результат помещает в xml
  3. итоговый xml, в котором находятся данные всех блоков, обрабатывает с помощью индексного шаблона /themes/index/main.xsl и результат отдаёт пользователю в виде html.


Индексный шаблон /themes/index/main.xsl может выглядет следующим образом:
<xsl:template match="page">   
    <head>
        <title><xsl:value-of select="title" /></title>
    </head>
    <body>        
        <div class="page-container">
            <xsl:value-of select="blocks/menu_top/html" disable-output-escaping="yes"/>            
            <div class="main">         
                <xsl:value-of select="blocks/content/html" disable-output-escaping="yes"/>
            </div>            
            <xsl:value-of select="blocks/footer/html" disable-output-escaping="yes"/>
        </div>
    </body>
</xsl:template>

2. Именованные шаблоны


Шаблон xslt принимает данные в виде xml-документа. Это удобно тем, что мы можем оперировать целыми узлами. Например для вывода имени пользователя у нас может быть такой шаблон
<xsl:template name="inc_show_user">
    <xsl:param name="user"/>
    <img src="/img/{$user/userpic}.png"/>
    <xsl:value-of select="concat($user/first_name, ' ', $user/last_name)"/>
</xsl:template>
который располагается в файле /themes/models/user.xsl.

Мы можем использовать этот шаблон как для отображения текущего пользователя

<xsl:call-template name="inc_show_user">
    <xsl:with-param name="user" select="/*/cur_user"/>
</xsl:call-template>

так и для отображения списка пользователей
<xsl:for-each select="users/item">
    <xsl:call-template name="inc_show_user">
        <xsl:with-param name="user" select="."/>
    </xsl:call-template>            
</xsl:for-each>

Такое единство отображения сущностей позволяет быстро изменять их отображение. Конечно не у всех пользователей есть картинка, а значит и выводить её нужно не для всех

<xsl:template name="inc_show_user">
    <xsl:param name="user"/>
    <xsl:choose>
        <xsl:when test="$user/userpic>0">
            <img src="/img/{$user/userpic}.png"/>        
        </xsl:when>
        <xsl:otherwise>
            <img src="/img/default.png"/>
        </xsl:otherwise>
    </xsl:choose>    
    <xsl:value-of select="concat($user/first_name, ' ', $user/last_name)"/>
</xsl:template>

3. Импорт шаблонов


Для того чтобы в шаблоне блока иметь доступ к отображению сущности "пользователь" мы должны подключить файл /themes/models/user.xsl. 
Для шаблона /themes/cabinet/main.xsl подключение будет выглядеть так
<xsl:import href="../models/user.xsl"/>
(xsl:import должен описываться сразу после xsl:stylesheet)

4. Ни строчки php-кода в представлении


Патерн MVC предполагает разделение модели, логики и представления. Логика приложения запрашивает необходимые данные у модели и передаёт их в представление. Представление должно получить необходимое количество данных, чтобы их отобразить пользователю. Т.е. в представлении мы должны только вывести их и не должны как-либо ещё преобразовывать данные. Мы не должны получать имя пользователя по его id, не должны получать текущее время, и т.д. все эти данные уже должны быть доступны для представления. Если каких-либо данных не хватает, значит контроллер должен их предоставить.

Xslt позволяет производить простейшие операции с данными: сравнение, подсчёт количества, сортировка, форматирование чисел, округление, арифметические операции, конкатенация,… Казалось бы, что это противоречит предыдущему абзацу. Но позвольте заметить, что в результате всех этих операций мы не получаем новых данных, а лишь преобразуем имеющиеся данные.

Не всегда есть все необходимые средства для получения необходимого результата. Например, вывод окончания для числа. Думаю у многих есть подобная функция

function str_plural_form($n, $form1='штука', $form2='штуки', $form5='штук'){
  $lastN=$num%10;
  $lastT=$num%100;
  if($lastT>=10 && $lastT<=20){
    return $form5;
  }
  switch ($lastN){
    case 1:
      return $form1;
    case 2:
    case 3:
    case 4:
      return $form2;
    default:
      return $form5;
  }
}

И даже больше, xslt позволяет вызвать эту функцию прямо из шаблона
<xsl:value-of select="php:function('str_plural_form', 1*$cnt_users, 'пользователь', 'пользователя', 'пользователей')"/>

Но это не только противоречит заголовку раздела, но и является неким атавизмом. Лучше избегать вызовов php-функций внутри xslt-шаблонов.
Что же делать? Есть 2 выхода:
  1. пусть контролер вызывает str_plural_form и отдаёт нужные данные
  2. сделать именованный шаблон-функцию, которую мы поместим в /themes/inc/functions.xsl

<xsl:template name="f_plural_form">
    <xsl:param name="num"></xsl:param>
    <xsl:param name="format">### ###</xsl:param>
    <xsl:param name="is_show_num">1</xsl:param>
    <xsl:param name="space"/>
    
    <xsl:param name="str1">штука</xsl:param>
    <xsl:param name="str2">штуки</xsl:param>
    <xsl:param name="str5">штук</xsl:param>
    
    <xsl:if test="$is_show_num=1">
      <xsl:value-of select="format-number($num, $format)"/>
      <xsl:choose>
        <xsl:when test="$space!=''">
          <xsl:value-of select="$space" disable-output-escaping="yes"/>    
        </xsl:when>
        <xsl:otherwise>
          <xsl:text> </xsl:text>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:if>
    
    <xsl:variable name="lastN" select="$num mod 10"/>
    <xsl:variable name="lastT" select="$num mod 100"/>
    
    <xsl:choose>
      <xsl:when test="$lastT>=10 and 20>=$lastT">
        <xsl:value-of select="$str5" disable-output-escaping="yes"/>
      </xsl:when>
      <xsl:when test="$lastN=1">
        <xsl:value-of select="$str1" disable-output-escaping="yes"/>
      </xsl:when>      
      <xsl:when test="$lastN=2 or $lastN=3 or $lastN=4">
        <xsl:value-of select="$str2" disable-output-escaping="yes"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="$str5" disable-output-escaping="yes"/>
      </xsl:otherwise>      
    </xsl:choose>
</xsl:template>

Вызов функции будет выглядеть так

<xsl:call-template name="f_plural_form">
  <xsl:with-param name="is_show_num">1</xsl:with-param>
  <xsl:with-param name="num" select="$cnt_users"/>
  <xsl:with-param name="str1">пользователь</xsl:with-param>
  <xsl:with-param name="str2">пользователя</xsl:with-param>
  <xsl:with-param name="str5">пользователей</xsl:with-param>
</xsl:call-template>

5. Справочники


Вернёмся к выводу информации о пользователе. К примеру на странице форума нам нужно вывести 
  • список постов с именами пользователей,
  • список самых активных пользователей,
  • список пользователей которые в данный момент просматривают эту страницу.

Можно решить задачу влоб. При получении каждого из списков делать LEFT JOIN users и получать необходимые данные для вывода информации о пользователе. Но есть и отрицательные моменты такого решения. Первое - возможная избыточность данных (пользователи из списков могут повторяться), второе - дополнительная нагрузка на sql-сервер.

Другой вариант решения задачи. Получить все списки. Затем из этих списков получить набор user_id. И по этому набору сделать один запрос к таблице users. Результат сложить в xml по известному адресу, например /ref_users.
В итоге у нас должен получиться xml-документ с узлами posts, active_users, online_users, ref_users.

Для вывода информации о пользователе сделаем такой именованный шаблон

<xsl:template name="inc_show_user_by_id">
    <xsl:param name="user_id"/>
    
    <!-- поиск пользователя в справочнике по его id -->
    <xsl:variable name="cur_user" select="/*/ref_users/item[user_id=$user_id]"/>
    <xsl:call-template name="inc_show_user">
        <xsl:with-param name="user" select="$cur_user"/>
    </xsl:call-template>
</xsl:template>
и сохраним его в /themes/models/user.xsl. Это шаблон для вывода пользователя по его id.

Вывести список постов с информацией о пользователе можно так

<xsl:for-each select="posts/item">
    <xsl:call-template name="inc_show_user_by_id">
        <!-- передаём в шаблон user_id автора поста -->
        <xsl:with-param name="user_id" select="user_id"/>
    </xsl:call-template>
    
    <!-- далее вывод самого поста -->
    <!-- ... -->
</xsl:for-each>

Заключение


Статья получилась объёмной, поэтому не рассмотренными остались вопросы организации шаблонов для ajax, "абстрактные шаблоны", поддержка нескольких языков. А также вопросы скорости и кеширования.

Ссылки по теме


 Распечатать »
 Правила публикации »
  Написать редактору 
 Рекомендовать » Дата публикации: 09.11.2012 
 

Магазин программного обеспечения   WWW.ITSHOP.RU
Oracle Database Personal Edition Named User Plus License
ABViewer Professional пользовательская
IBM Rational Functional Tester Floating User License
TeeBI for RAD Studio Suite with source code single license
WinRAR 5.x Standard Licence - для частных лиц 1 лицензия
 
Другие предложения...
 
Курсы обучения   WWW.ITSHOP.RU
 
Другие предложения...
 
Магазин сертификационных экзаменов   WWW.ITSHOP.RU
 
Другие предложения...
 
3D Принтеры | 3D Печать   WWW.ITSHOP.RU
 
Другие предложения...
 
Новости по теме
 
Рассылки Subscribe.ru
Информационные технологии: CASE, RAD, ERP, OLAP
Безопасность компьютерных сетей и защита информации
Новости ITShop.ru - ПО, книги, документация, курсы обучения
СУБД Oracle "с нуля"
OS Linux для начинающих. Новости + статьи + обзоры + ссылки
Один день системного администратора
Delphi - проблемы и решения
 
Статьи по теме
 
Новинки каталога Download
 
Исходники
 
Документация
 
 



    
rambler's top100 Rambler's Top100