XSLT

индекс
184,21

Практический XSLT. Использование в качестве шаблонизатора

В сети доступно масса документации по языку XSL. Данный раздел не претендует на роль документации по языку, а лишь кратко, по шагам объясняет, как создать свой XSLT-шаблон.

Описанная ниже схема успешно мною используется уже более 3 лет. По началу я к XSLT относился с большой опаской (особенно, когда разбирал чужие исходники), однако однажды поняв, что к чему, уже не представляю, как без него можно работать.

Рабочий стол

Определим, что нам нужно для работы:
  • Входной XML-документ
  • XHTML-макет шаблона
  • Парсер XML для склейки XML с XSL

У меня входной XML документ выдает CMS-система, в которой каждая страница с материалом собирается в XML-дерево.

К XHTML-макету никаких ограничений нет. Есть лишь определенные рекомендации по верстке, которые позволят значительно сэкономить время на формирование шаблона.

В качестве парсера (сборщика) конечного документа можно использовать браузер. Нужно лишь указать в XML-документы путь к файлу шаблону:
<?xml-stylesheet type="text/xsl" href="template.xsl" ?>

Хотя, как показала практика, этот механизм довольно глючный (мне пришлось пользовать IE). Лучше воспользоваться средствами XML-парсинга языка, на котором написана CMS-система. Я использую Parser (на нем, вообщем-то, у меня вся система и работает).

Входной XML-документ

Для начала разберемся со входным XML-документом. Для того, чтобы использовать XSL нужно иметь полное представление о его структуре.

Я использую следующую схему:
<?xml version="1.0" encoding="windows-1251"?>
Начало

<lang_table>
/>
</lang_table>
<item id="0" parent_id="0" is_published="1" section="1">
Начало
/

<item id="1" parent_id="0" is_published="1" section="1">
Новости
news







Обозначенный выше пример схемы не претендует на свою оптимальность. В силу тех или иных причин, мне он удобен. Но, обо всем по порядку.

<?xml version="1.0" encoding="windows-1251"?> — заголовок XML-файла. Должен идти строго с начала файла. В нем прописана версия используемого XML-языка и кодировка документа. Я как правило работаю в windows-1251 (пока так удобнее), но, по идее UTF-8 лучше.

- корневой элемент документа (можно придумать свое имя). Атрибуты:
  • Lang - язык документа. Нужен для создания мультиязычных шаблонов.
  • Id - идентификатор текущего раздела.

<lang_table> - таблица языков, используемых на сайте.
- блок элементов навигации:
- блок основной навигации (основная структура сайта):
<item id="0" parent_id="0" is_published="1" section="1"> - элемент структуры сайта. Атрибуты:
  • Id - идентификатор раздела.
  • Parent_id - идентификатор родительского раздела.
  • Is_published - опубликован ли раздел.
  • Dir - uri-адрес раздела. По нему формируются полные адреса.
  • Section - тип раздела. Используется если необходимо разбить меню на основное и сервисное.

- блок содержимого.
В моей CMS используется модульная структура: все наполнение сайта представляет собой модули двух видов:
  • Html - текстовый модуль. Статические модули, которые заполняет редактор сайта.
  • Com - модуль-компонента. Динамические модули, которые формируют различные программные модули CMS: новости, статистика, поисковые блоки и т.д.

В XSL-шаблонах есть разметка блоков, в которые можно размещать модули. Для определения блоков я использую простую нумерацию.

CMS при сборке страницы просто выводит в все модули, которые задействованы на странице в виде:
Атрибуты:
  • Id - идентификатор модуля.
    Container - блок-назначение (в каком блоке шаблона выводиться).
    Sorting - порядок вывода в блоке.
    Type - тип:
    • Com - модуль-компонентаю
      Html - текстовый модуль.

    Method - обработчик данных.
    Title - название модуля.
    DTD я практически не использую (лишь в самом общем виде):
    <!DOCTYPE site_page [

    <!ENTITY nbsp " ">
    <!ENTITY sect "§" >
    <!ENTITY copy "©">
    <!ENTITY laquo "«">
    <!ENTITY reg "®">
    <!ENTITY deg "°">
    <!ENTITY plusmn "±">
    <!ENTITY para "¶">
    <!ENTITY raquo "»">
    <!ENTITY times "×">



    <!ENTITY bull "•">
    <!ENTITY hellip "…">



    <!ENTITY ndash "–">
    <!ENTITY mdash "—">
    <!ENTITY lsquo "‘">
    <!ENTITY rsquo "’">
    <!ENTITY sbquo "‚">
    <!ENTITY ldquo "“">
    <!ENTITY rdquo "”">
    <!ENTITY bdquo "„">
    <!ENTITY lsaquo "‹">
    <!ENTITY rsaquo "›" >
    <!ENTITY euro "€">
    ]>

    Его можно вставить прямо в XML-документ. Сразу после <?xml version="1.0" encoding="windows-1251"?>.

    Подготовка XHML-шаблона


    XSL-шаблон создается на базе XHTML-шаблона (некой типовой страницы сайта). Код XHTML-страницы, при этом, должен быть валидным.

    Рассмотрим по шагам процесс создания шаблона.

    Проверив валидность XHML-страницы своего шаблона, для облегчения собственной работы, обозначьте в нем положение всех динамических блоков:
    • Меню (и других элементов навигации).
    • Информационных блоков страницы - то место в шаблоне, в котором будут выводиться модули сайта.
    • Заголовка/названия страницы.

    Сделать это лучше всего с помощью обычных HTML-комментариев:
    ...


    Администрирование сайта


    ...

    • Начало
    • Новости
    • Разделы


    ...

    Всякие новости

    ...

    Текст

    ...


    Основы описания XSL-шаблонов


    Все файлы XSL-шаблонов имеют следующий вид:
    <xsl:stylesheet version = '1.0' encoding="UTF-8"?>
    <xsl:template match="element">
    данные шаблона
    </xsl:template>
    </xsl:stylesheet>


    Где: <xsl:stylesheet version = '1.0' encoding="UTF-8"?> - определяет тип XML-документа и кодировку. Я использую UTF-8 (не спрашивайте, почему).
    <xsl:stylesheet> </xsl:stylesheet> - начало и конец XSL-документа.
    <xsl:template match="element"> </xsl:template> - начало и конец шаблона для элемента element.

    Шаблоны можно условно разделить на три вида:
    • <xsl:template match="element"></xsl:template> - шаблон, описывающий правила преобразования элемента element. Применяется автоматически ко всем элементам element.
    • <xsl:template match="element" mode="mode1"></xsl:template> - шаблон, описывающий правила преобразования элемента element в режиме mode1. Таким образом можно описать различные правила обработки элементов element.
    • <xsl:template name="template-name"></xsl:template> - шаблон с именем template-name. Не имеет привязки к какому-либо элементу XML-документа.

    Если элементы одного вида могут встречаться в различных частях структуры XML-документа (например, в XML-документе, формируемом системой элемент item используется повсеместно и имеет разное значение), то в шаблоне можно указать "структурный адрес" такого элемента:
    <xsl:template match="navigation/sections/item"></xsl:template>
    При этом, порядок применения шаблонов иерархичный, т.е., сначала шаблон применяется к корневому элементу, а затем, к дочерним, т.е. если мы вызвали обработчик для navigation, то для вызова обработчика для navigation/sections/item нам достаточно указать адрес sections/item.

    Структура папок шаблонов


    Для того, чтобы хранить на одном сайте несколько модулей необходимо как-то продумать структуру их хранения в папкам. При этом, удобнее разбить шаблоны на модули по нескольким xsl-файлам. Такой подход позволит в дальнейшем повторно их использовать при создании новых шаблонов.

    В простейшем варианте можно создать каталог xsl и там все складировать.

    Далее, чтобы внутри этого каталог шаблоны не путались (для каждого шаблона у нас получиться несколько файлов) создадим вложенные каталоги:
    • template_folder - каталог с файлами шаблона. Называть ее можно по имени шаблона, например my_template.
    • dtd - файлы описания основных сущностей. Могут быть полезными.
    • lang - шаблоны сообщений для различных языков (если на сайте используется их используется несколько).
    • mod - шаблоны модулей.

    Нам для начала потребуется создать каталог xsl/my_template и в нем, файл layout.xsl следующего вида:
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE xsl:stylesheet SYSTEM "../dtd/entities.dtd">
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:template match="/node()">
    </xsl:template>

    </xsl:stylesheet>

    Где:
    <xsl:template match="/node()"> </xsl:template> - шаблон для элемента /node() (корневого). Вместо /node() можно указать //document, т.к. он у нас являеться корневым узлом.

    Копируем весь XHTML-код внутрь блока <xsl:template match="/node()"></xsl:template>

    Этот шаблон будет автоматически применяться ко всему XML-документу. В нашем случае, XSL-преобразование заменит весь XML-код на XHTML-код вашего шаблона.

    Далее, необходимо в директории XSL создать файл template.xsl (где, template - название вашего шаблона), в котором размещаем следующий код:
    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:import href=" my_template /layout.xsl"/>
    </xsl:stylesheet>

    Где:
    <xsl:import href="my_template/layout.xsl"/>
    Директива импорта внешнего XSL-файла (обрабатываеться XSL-процессором) из указанного файла. Путь к файлу указываем относительный.

    Создание шаблона для основного навигационного меню


    Наш предыдущий шаблон не обладает никакой динамикой, т.к. просто заменяет весь выходной XML-документ на код нашего шаблона.

    Следующий шаг - создание шаблона для меню.

    Меню навигации сайта строиться на основе его структуры, представленной в XML-документе в следующем виде:
    <item id="0" parent_id="0" is_published="1" section="1">
    Начало
    /

    <item id="1" parent_id="0" is_published="1" section="1" hit="yes">
    Новости
    news




    Текущий раздел определяется по двум параметрам:
    • Атрибуту id у корневого элемента document - он всегда равен id текущего раздела.
    • Атрибуту hit у элемента item - если таковой имеется, то это значит, мы находимся на "главной странице раздела".

    Соответственно, для того, чтобы вывести меню сайта необходимо создать шаблон для элементов:
    • sections - корневой элемент меню.
    • item - элемент меню.

    При этом, необходимо учесть, что элементы item могут содержать другие элементы item, в том случае, если у раздела есть подразделы:



    1. Создаем в директории xsl/my_template файл navigation.xsl следующего вида:


    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE xsl:stylesheet SYSTEM "../dtd/entities.dtd">
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:template match="sections" mode="global_menu">
    </xsl:template>

    </xsl:stylesheet>


    2. Вставляем в шаблон код нашего меню из файла layout.xsl:



    <xsl:template match="sections" mode="global_menu">

    </xsl:template>


    3. …а на его место в файле layout.xsl вставляем вызов нашего шаблона меню:



    <xsl:apply-templates select="navigation/sections" mode="global_menu"/>


    Где:
    select="navigation/sections" - относительный (относительно текущего) путь-адрес элемента. При этом, будут обработаны все элементы navigation/sections.

    mode="global_menu" - используем шаблон с режимом global_menu. Это нам нужно на тот случай, если нужно будет выводить еще и сервисное меню, отдельно, или "хлебные крошки", или что-еще другое на основе одной и той же ветки навигации.

    4. Плюс, добавим в файл layout.xsl директиву импорта файла шаблона navigation.xsl:


    <xsl:import href="navigation.xsl"/>

    5. Далее, создаем в файле navigation.xsl еще один шаблон, для обработки пунктов меню:



    <xsl:template match="item" mode="global_menu">
    <xsl:call-template name="href_attribute"/>
    <xsl:value-of select="title"/>


    </xsl:template>


    Где:
    <xsl:call-template name="href_attribute"/> - вызов шаблона по имени. При этом шаблон не имеет привязки к элементу, т.е. вызывается произвольно.

    <xsl:value-of select="title"/> - вставка-вывод значения элемента title текущего элемента. Если в параметре перед именем элемента поставить символ @ - выводиться будет значения атрибута текущего элемента.

    6. Немного изменяем шаблон sections:



    <xsl:template match="sections" mode="global_menu">

    </xsl:template>


    Где:
    <xsl:apply-templates select="item" mode="global_menu"/> - обработка всех элементов item элемента sections. При этом, элементы item самих элементов item (sections/item/item) обрабатываться не будут, т.е. выводиться только один уровень меню разделов.

    Мы вынесли обработку элементов item (пунктов меню) в отдельный шаблон. При этом, в нем мы добавили еще и вызов другого шаблона: <xsl:call-template name="href_attribute"/>

    Этот шаблон будет формировать нормальные uri-ссылки для элементов нашего меню. О нем немного позже.

    7. Теперь нам необходимо доделать меню,


    чтобы оно учитывало, какой раздел является текущим. Для этого нам придется добавить условную обработку в наш шаблон элемента item:

    <xsl:template match="item" mode="global_menu">
    <xsl:choose>

    <xsl:when test="descendant-or-self::*/@id = /node()/@id">
    <xsl:value-of select="title"/>
    </xsl:when>

    <xsl:otherwise>
    <xsl:call-template name="href_attribute"/>
    <xsl:value-of select="title"/>

    </xsl:otherwise>
    </xsl:choose>

    </xsl:template>


    Здесь мы сталкиваемся с новой конструкцией:
    <xsl:choose>
    <xsl:when></xsl:when>
    <xsl:otherwise></xsl:otherwise>
    </xsl:choose>

    …которая, собственно, и задает условную обработку XML-элементов. В качестве параметра мы задаем условие: <xsl:when test="descendant-or-self::*/@id = /node()/@id">

    В нашем случае это условие равенства атрибутов ID у корневого элемента (document) и текущего элемента (item), которое и определяет, является ли элемент текущим.

    Внутри блока <xsl:when></xsl:when> располагается то, что выводиться в случае выполнения условия. В блоке <xsl:otherwise></xsl:otherwise> - если условие не выполняется.

    8. Теперь, разберем шаблон href_attribute:



    <xsl:template name="href_attribute">
    <xsl:attribute name="href">
    <xsl:text>/</xsl:text>
    <xsl:for-each select="ancestor-or-self::item">
    <xsl:value-of select="dir"/>
    <xsl:text>/</xsl:text>
    </xsl:for-each>
    </xsl:attribute>
    </xsl:template>


    Здесь мы сталкиваемся с инструкцией xsl:attribute. Она позволяет создавать атрибуты для элементов внутри которого она вызывается. В нашем случае мы вызываем ее из элемента a, соответственно, она создаст для него атрибут href, т.е. адрес.

    Инструкция <xsl:for-each select="ancestor-or-self::item"> задает цикл обработки для всех элементов, удовлетворяющих условию. В нашем случае мы выбираем ancestor-or-self::item - ось элементов от корневого элемента до текущего по цепочке. В нашем случае это позволяет выбрать для всей цепочки узлы dir, т.е. построить полный адрес текущего узла-раздела.

    Далее, нам необходимо каким-то образом определить, как у нас будут обрабатываться модули содержимого. Но, об этом в следующий раз.

    UPD:
    Материалы к статье. Собрал из того, что было:
    parser.proc.ru/iso/xslt-1.zip

    В шаблоне все пути прописаны от корня (делал на основе шаблона работающего на реальном сайте) поэтому либо перепишите их на относительные либо запускайте из под Apache.

    В архиве входной XML-документ лежит в /xsl/document.xml
+55
24 марта 2008, 16:47
168

комментарии (100)

0
spelesto #
Спасибо! Интересно изложили..
+2
switchON #
Отлично, как давно я искал такой мануал. Всё по делу и ничего лишнего. Огромное спасибо!
+3
abarmot #
Спасибо, хорошая статья!

Мне во многих проектах доводилось плотно заниматься xsl-трансформацией. За это время накопились несколько замечаний, которые стоит учесть при выборе этой технологии.

1. тормозит
Нельзя сказать, что безумно, но если дело доходит до оптимизации скорости ответа сервера — xsl-трансформация окажется одним из самых «узких» мест. Можно писать «правильные» шаблоны и со временем научиться «разгонять» скорость их обработки. Но значительного прироста в скорости это не принесет. В последнем проекте это сыграло решающую роль и пришлось отказаться от xsl вообще.


2. нет четкой структуры. В случае большого объема кода приходится изобретать и постоянно придерживаться четких правил для вложенности шаблонов. Встроенных средств для этого нет.

3. верстальщики не знают xsl. Это заметно осложняет последующую поддержку проекта.
+5
CurlyBrace #
1. Для того чтобы не тормозило надо использовать кеширование.
2. Четких правил придерживаться стоит всегда.
3. Плохие верстальщики не хотят знать XSL. Хороших можно научить.
0
abarmot #
Согласен по всем пунктам, однако:

1. действительно это один из способов «разгона», но если страница на 100% динамическая — помогает мало.
2. это гораздо удобней делать, когда правила встроены в технологию или даже диктуются на уровне синтаксиса.
3. к сожалению кадровой политикой везде занимались другие люди и большого выбора верстальщиков не было.

Да вобщем-то верстальщиков тоже можно понять — они шли верстать макеты в хтмл, ну максимум править шаблоны очень похожие на хтмл, а сложный хсл шаблон достаточно далек от результирующего хтмл'я.

И кстати, «я за наших!» т.е. мне нравится xsl и интересно было с ним работать. Но есть моменты на которые необходимо обратить внимание при выборе технологии. Т.к. отказаться от xsl, когда проект уже практически готов будет очень сложно.
+4
CurlyBrace #
Плох тот верстальщик, который не хочет научиться большему ) Я вобще против такой профессии. Более уместно будет Front-End Web Developer, тут даже само название обязывает знать больше чем просто верстка. )

А в плане технологий - все просто и неоднократно оговорено. Технологию надо выбирать в зависимости от нужд проекта, а не в зависимости от самой технологии. Это как "php-программист" )
0
shadeR #
не нужно решать за людей чему им учиться.
человек имеет право решать - нужно ему это или нет.

знания xsl скорее нужны девелоперу, и как результат, грамотного верстальщика может просто не оказаться под рукой когда он нужен ( девелоперы обычно заняты на 120%)
0
ayavryk #
Не знаю что хуже, программист верстающий HTML, или верстальщик ковыряющийся в SQL. Беда коль сапоги начнет тачать пирожник, а пироги печи сапожник.
–1
shadeR #
Именно поэтому есть такая профессия - верстальщик
+1
CurlyBrace #
Во-первых вы невнимательно прочитали мой комментарий. Девелоперы тоже делятся на Front-End и Back-End.

Во-вторых вы видимо не имели дело с XSLT. Никто при разработке больших проектов не будет верстать все в статике, а затем просить "девелопера" переводить все на XSLT-шаблоны. Это бессмысленая трата времени.

XSLT имеет самое прямое отношение к верстке и является частью Front-End'a.

Кроме того, я ни за кого ничего не решаю, каждый сам себе Прокруст. И вы, пожалуйста не решайте, что мне говорить, а чего не стоит.
0
dfitiskin #
Никто при разработке больших проектов не будет верстать все в статике, а затем просить "девелопера" переводить все на XSLT-шаблоны.

Мне кажется это разного плана задачи - одно дело отладить сверстанный дизайн под все браузеры, другое дело связать с бекэндом.
–1
shadeR #
На счет больших проектов - вы не поверите что там происходит :) Там и HTML в базу кладут и еще похлеще вытворяют. Знаю, участвовал и да сих пор общаюсь с людьми, которые делают проекты для Билайна, Боинга и других крупных корпораций.

Далее, "не будет верстать все в статике, а затем просить "девелопера" переводить все на XSLT-шаблоны".
Простите, а Вы стадию прототипирования начисто игнорируете? И frontend и backend "по-живому" делаете? Не хочу в это верить, боюсь я таких людей :)

Ну и по последнему - я не указываю Вам, тут все выражают мнение. Обратите внимание, я как раз и писал о том что каждый выбирает сам. Это Вы пытаетесь указать "Плох тот верстальщик, который не хочет научиться большему", что как я вижу есть принуждение.

P.S. XSLT нужно применять осторожно и с умом. И только когда это оправдано.
+1
CurlyBrace #
Я хорошо знаю что происходит в больших проектах, так как принимаю в них непосредственное участие. И думаю что все зависит от компании и работников.

Backend'ом я не занимаюсь, а frontend сразу начинаю с XSLT, это гораздо удобнее, по крайней мере в моей компании. Прототипирование здесь не причем. Это более ранняя стадия.

Если вы считаете что мои слова - принуждение, то скажу более глобально. Плох тот разработчик, который не хочет учиться чему-то новому. Разработчика, который считает что он уже все знает, надо гнать в шею.

По поводу технологий согласен и повторюсь. Цель определяет средства, а не наоборот.
0
shadeR #
Можите привести примеры крупных проектов с примением XSLT?
+1
CurlyBrace #
Давайте в личке продолжим, ок? )
0
Flack #
Почти все проекты Яндекса, чего далеко ходить.
0
antonlyapunov #
Правильная позиция. Нет смысла плодить узких специалистов. Пусть специалист будет узким пока он ничего не умеет. А с таким подходом специалисты не хотят ничему учиться, потому что это не их область, они, видите ли пришли на html-верстальщиков.
0
vol_de_mar #
Я верстальщик с двухлетним стажем, очень жажду изучить XSL, но на работе так заваливают рутино, что времени вообще ноль.
0
Fade #
Почитайте http://www.zvon.org/xxl/XSLTutorial/Outp…
Мне хватило недели, чтобы разобраться.
0
igeek #
хм, забавно... через полгода работы с XSLT 2.0 (Saxon) я понял что я бог и могу делать на нем все, через год до меня дошло что я не знаю ключевых моментов даже XSLT 1.0, через полтора я каждый раз сомневаюсь в разумности использования той или иной конструкции, и каждый день сулит все новые и новые открытия, и день когда я скажу что разобрался с XSLT по-моему никогда не наступит...

впрочем, это исключительно проблемы моего собственного мозга, у вас конечно все получится намного быстрее)
0
ibnteo #
Уже ничего на этом сервере нет, на главной высвечивается - "It works!", надеюсь что временно.
+1
Fade #
Смотрю - все есть... идите прямо по ссылке.
0
ibnteo #
Заработал сайт, это радует :)
0
magnit #
если страница на 100% динамическая

1. тогда узкое место будет скорее всего не в трансформации
2. скорее всего можно будет грузить динамику httpRequest'ом и рисовать javascript'ом на закешированой :) после преобразования болванке (например корзина и т.д.)
0
tbkba #
не знаю, что у вас за шаблоны, но свои я оцениваю как достаточно сложные (потому как результирующее DOM дерево после формирования еще раз обрабатываеся внутри xslt, но и не только) и формирование документа из моего шаблона занимает от одной до четырех сотых секунды. шаблоны все в распарсенном состоянии хранятся в памяти, системы - suse linux 10.1 на pentium d 2.8 GHz и mac os x 10.5 на core 2 duo 2.33 GHz, везде последние libxml2 & libxslt
0
ibnteo #
Верстальщики не знают ничего кроме верстки, всему надо учить, и лучше один раз научить XSLT.
0
kosiakk #
спасибо за статью!
было бы очень удобно скачать все файлы статьи одним архивом... хотя бы открыть в любимом xslt-редакторе (подсветка, навигация и т.п.)
+2
Fade #
Собрал из того, что было:
http://parser.proc.ru/iso/xslt-1.zip

В шаблоне все пути прописаны от корня (делал на основе шаблона работающего на реальном сайте) поэтому либо перепишите их на относительные либо запускайте из под Apache.

В архиве входной XML-документ лежит в /xsl/document.xml
0
kosiakk #
оу, даже с картинками =)
many thanks!
0
ibnteo #
Поместите это в конце статьи, чтобы людям не пришлось искать в комментариях.
0
Fade #
Ok.
0
mastikhin #
Спасибо, интересно, подробно и познавательно! Классная статья.
Но только одно замечание - вы забыли, как и все сторонники хслт, о самом важном вопросе, а именно: "нахрена козе баян?"
Система тратит время как на составление хмля, так и на его же парсинг, а где же плюсы? Каково принципиальное отличие от тех же пхпшных шаблонизаторов, от того же популярного смарти?
+1
Fade #
Цель статьи ответить на вопрос: Как? а не Зачем.
+2
Fade #
Иначе получиться очередной холивар. Всегда должен быть выбор. Я свой сделал. Однако, я не собираюсь никого убеждать в оптимальности своего выбора. Просто он такой.

По тем же причинам я использую
- Parser, а не PHP
- Xara, а не Corel или Illustrator.
... список можно продолжать дальше.
0
b_positive #
Не смешите, хотите сказать, что смарти отличается большой производительностью?
0
shadeR #
Грамотно настроенная и на небольших проектах - да. Возможно и на средних нормально покажет себя.
+2
ayavryk #
>Каково принципиальное отличие от тех же пхпшных шаблонизаторов
Главное отличие в том, что XSLT является w3-стандартом, поддерживаемый всеми ведущими разработчиками. А смарти - это всего навсего одна из многих надстроек в PHP, которая даже в рамках PHP не рассматривается как стандарт.
–1
pietrovich #
Каково принципиальное отличие от тех же пхпшных шаблонизаторов, от того же популярного смарти?


приниципальное - трансформации можно гонять на клиенте а не на сервере ;)

хотя на практике мало кто этим пользуется...
0
ayavryk #
Возникает куча проблем.
- устаревшие броузеры не подцепят.
- если делать тупо в лоб, возникают траблы с поисковыми машинами
- Операция ресурсоемкая, на слабых комп. торможение заметно.
- XSLT в броузерах неполноценное. Навскидку - траблы с disable-output-escaping.
0
pietrovich #
ну... я же про принципиальное отличие, а не про плюсы/минусы/проблемы ;)
+1
ayavryk #
Вы - идеалист :)
Мне кажется когда броузеры научаться парсить XSLT(2), дискуссия XSLT ver php-шаблонизаторы потеряет смысл.
0
medvoodoo #
XSLT дает очередную возможность отделения мух от котлет, притом полную, сам стараюсь работать только с xslt, простейший пример: есть XML и его можно вывести как заполненную форму так и просто как два дива, плюс при выводе вида не надо заморачиваться с экранированием спец символов.
P.S. Русские примеры xml/xpatch/xslt немного посеченгная версия английской версии. И, по хорошему, кучу нюансов эти примеры не отражают, искал в свое время некоторые решения по маленьким кусочкам, так что куча документации - это громкие слова
0
apk #
спасибо, за статью, есть вопросик - почему именно шаблоны lang, как мне кажется в случае локализации лучше всего поможет именно dtd?
0
Fade #
В настоящее время у меня для разных языков используются специальные xsl-таблицы. С ними проще работать чем с DTD. Кроме того, я сейчас пытаюсь перевести все на динамические XSL-шаблоны, которые формируются индивидуально для каждого пользователя.
0
apk #
не вижу особых проблем написать в dtd <!ENTITY site.about.title "Привет мир">,
а потом в шаблоне <xsl:text>&site.about.title</xsl:text>, а каким образом Вы делаете вызов разных таблиц для разных локалей, через call-template или apply-template?
0
Fade #
Можно. Попробую. Но будут проблемы, если мне нужно вставлять что-то вроде:

184209, Мурманская обл., г. Апатиты, ул.Такаято,
<br />
<a href="mailto:mail@domen.ru"><a href="mailto:mail@domen.ru">mail@domen.ru</a></a>

Насчет вызова разных таблиц - напишу в следующей статье. Там много тонкостей.
НЛО прилетело и опубликовало эту надпись здесь
+1
igeek #
<xsl:template match="/node()"> </xsl:template> - шаблон для элемента /node() (корневого). Вместо /node() можно указать //document, т.к. он у нас являеться корневым узлом.

меня немного пугают используемые вами xpath-выражения, если вы хотите взять корневой элемент почему бы не сделать это хотя бы так match="/document", во втором случае (//document) процессор не остановится на первом элементе, а продолжит бежать по всему дереву в поисках элемента document, а оно вам надо? старайтесь использовать // как можно реже, вы теряете в производительности
0
Fade #
У меня используется /node().
//document я указал, т.к. /document подглючивал у меня сегодня в IE.

Насчет // - согласен.
+1
igeek #
лично для себя я считаю хорошей практикой начинать с корня

<xsl:template match="/">
<xsl:apply-templates />
</xsl:template>

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

<xsl:template match="document">
...
</xsl:template>

но это уже каждый сам для себя решает, что хорошо, а что плохо)
0
Fade #
Раньше я так и делал, но когда схема документа "разрослась" стал называть все, чтобы было проще самому читать свой код.
–2
nikitad #
Подходит для относительно небольших страниц, на которых в основном статический контент. Если что-то больше - лучше использовать native php или шаблонизатор на компилируемом языке, например Си.
0
bitman #
Идеология очень хороша, практикую уже 2 года. Но есть проблема: шаблонизированные формы, т.е. элементы form, которые обёрнуты в шаблон XSLT. Так вот, при отправке методом POST, поля такой формы не передаются серверу из Opera. Из FF и IE передаются, но исключительно в UTF-8, какой-бы чарсет ни был установлен.
Если кто-нибудь разобрался с этим, пожалуйста, поделитесь решением.
0
Fade #
Странно. Попробуйте зайти на http://parser.proc.ru/forum/ (там все на XSLT)
Я оперой давно не пользуюсь, поэтому скатать четко не могу, но проблем быть не должно.
0
Futbolist #
Решение есть такое:
<xsl:output method="xml"
...
/>
Именно из-за этого я делаю один шаблон для Оперы и еще один для остальных браузеров.
Ну а вообще в Опере 9.5 это уже поддерживается.
0
MikhailEdoshin #
Некоторые XPath-селекторы несколько нечеткие. Например, node() совпадает в т. ч. и с текстовыми узлами и выражение /node() выглядит как если бы вы хотели выбрать либо элемент, либо текстовый узел. Из контекста же ясно, что имеется в виду только элемент, тем более, что текстового узла в руте и быть не может. Возможно, разумнее использовать более узкий селектор *.

В descendant-or-self::*/@id = /node()/@id, как мне кажется, вся часть descendant-or-self::*/ лишняя, достаточно @id = /node()/@id, т. е. @id = /*/@id. А я так бы бы еще и переменную завел

<xsl:variable name="current-section" select="/*/@id" />

и сравнивал бы так: @id = $current-section.

Кстати, ведь браузеры по уму должны уметь отображать произвольный XML, если им дать соответствующий CSS для него. Т. е. насколько я понимаю, можно, во всяком случае, теоретически, не втискивать страничку в прокрустово ложе XHTML, а писать XML, точно отображающий структуру сайта. Не делать меню в виде ul id="main-menu", а использовать свой тэг <menu> и задать ему в CSS все те опции, которые сейчас для #main-menu указаны. Единственное ссылки и формы непонятно, как делать, хотя, в принципе, ничто не мешает смешивать свои теги со стандартным XHTML, разделяя их по namespaces.
0
Fade #
насчет node() я писал немного выше - я не утверждаю, что так и надо. Просто мне пока так удобнее читать: выбираем корневой узел.

Про <xsl:variable name="current-section" select="/*/@id" /> я постараюсь поговорить позже. Это действительно удобнее. Просто, нужно будет еще объяснить переменные XSL.

Насчет ul id="main-menu" - эта конструкция более валидная, чем <menu>
0
MikhailEdoshin #
Возможно, удобнее читать, но вы ведь не узел на самом деле выбираете, а элемент. А элемент — *. Если бы документ был такой

<sample>
Some text <some element>some more text</some element>
</sample>

то селектор /sample/node()[1] выбрал бы текстовый узел “Some text” (с пробельным материалом вокруг). Когда видишь node(), это читается как «будем работать с текстом и элементами». У вас же работа с текстом не подразумевается.
+1
Futbolist #
В чем преимущество парсинга при помощи браузера? А в том, что пользователь один раз загрузит xsl-шаблон для страницы (т.е. по сути всю разметку) и потом будет подгружать только данные из xml. Работает это очень и очень быстро.

Минуса два. Первый - это то, что постоянно сталкиваешься с тем, что в каком-нибудь браузере что-то из xslt не реализовано. Конечно, чаще всего этим браузером становится Опера:) И второй минус - Яндекс не индексирует сделанные таким образом сайты. Т.е. бот заходит, но не индексирует. В чем проблема - пока не знаю. Буду очень признателен, если кто-нибудь поделится своим опытом в этой связи.
0
magnit #
1. скорее всего, яндекс, видя чистый xml-документ, не может определить, что у вас там будет title, h1 и т.д.
2. то что читает бот, не есть то, что видит пользователь. т.е. у вас в каждом xml может быть роман "Война и мир" но после xsl-трансофрмации в итоговую страницу ничего этого не войдет.

Это нормальная политика для поисковика, не давать себя спамить и т.д. для поддержания высокого качества выдачи.
0
Futbolist #
Дак в том-то и дело. Что я сделал выходной xml-файл так, что он выглядит как обычный html со всеми head, body. Ни одного не-html-ного тега нет. Только в начале да подключается xsl.
Т.е. я сделал тупо текстовую версию сайта со всеми ссылками, переходами. Гугл захавал - я смотрю в кеше и вижу то, что и задумывал. Но вот яндекс, зараза...
0
MikhailEdoshin #
А namespace прописан?
0
ibnteo #
Возможно дело в Content-Type, Яндекс не хочет брать text/xml? Но без него браузер не будет правильно обрабатывать.
0
magnit #
Спросите у Яндекса напряму. Без их строки поиска :)
0
Futbolist #
Да вопрос задавался еще черт-те когда. А ответить соизволили как раз сегодня. Таки да, не поддерживает их робот Content-Type: text/xml.
Но зато они разрешили делать подмену заголовка специально для их робота - надо будет на стенку в рамочке повесить как официальное разрешение на клоакинг от яндекса:)
0
Vit228 #
Спасибо за статью, будем ждать продолжения :)

не в тему:
когда уже Хабр будет код подсвечивать и форматировать, а?
0
Fade #
Надо подключить парсер посмотреть профиль Spearance
0
ionicman #
Огромное спасибо за отличнейшую статью. Сам использую XSLT вот уже 3-й год весьма нравится. весьма быстро и удобно. Но мало еще народа переходит в сайтостроительстве на него, я надеюсь что после таких статей наших прибавится.
0
romka777 #
Как с помощью xslt вывести список в два столбца ?
например есть список:
<list>
<item>1</item>
<item>2</item>
<item>3</item>
<item>4</item>
<item>5</item>
<item>6</item>
</list>
Как его преобразовать в такое:
<table>
<tr>1<td></td><td>4</td></tr>
<tr>2<td></td><td>5</td></tr>
<tr>3<td></td><td>6</td></tr>
</table>
???
0
snapper #
использовать count(list/item) и в зависимости от этого строить нужное кол-во столбцов и строк в них.
0
marazmus #
Если вам нужны _визуальные_ столбцы, может, лучше использовать CSS и свойства float+width?
0
ibnteo #
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/list">
<table>
<xsl:apply-templates select="item[count(preceding-sibling::item) <= count(following-sibling::item)]" mode="tr"/>
</table>
</xsl:template>

<xsl:template match="item" mode="tr">
<xsl:variable name="pos" select="ceiling(count(../item) div 2)"/>
<tr>
<xsl:apply-templates select="." mode="td"/>
<xsl:apply-templates select="following-sibling::item[$pos]" mode="td"/>
</tr>
</xsl:template>

<xsl:template match="item" mode="td">
<td><xsl:value-of select="."/></td>
</xsl:template>

</xsl:stylesheet>
0
ibnteo #
вместо "<=" конечно же нужно поставить "&lt;="
0
romka777 #
спасиб
–1
ionicman #
XML:



1
2
3


XSLT:




















В браузере открывать XML, XSLT-шный файл обозвать transform.xsl и бросить тудаже где файл.xml
0
ibnteo #
Когда код посылаете, нажимайте "предпросмотр", т.к. неясно как его хабр отформатирует.
Символы "<" нужно заменить на "&lt;"
Сам код лучше обернуть в <code>...</code>.
0
ionicman #
спс, буду знать
–1
ionicman #
ЕМАЕ! УЖАС КАКОЙ!!!! :D
Откуда такие грабли?

XML:

<?xml version="1.0" encoding="Windows-1251"?&rt;
<?xml-stylesheet type="text/xsl" href="transform.xsl"?&rt;
<list&rt;
<item&rt;1</item&rt;
<item&rt;2</item&rt;
<item&rt;3</item&rt;
</list&rt;

XSLT:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&rt;
<xsl:output method="html" encoding="windows-1251" doctype-system="http://www.w3.org/TR/html4/strict.dtd" doctype-public="-//W3C//DTD HTML 4.01//EN"/&rt;

<xsl:template match="/list"&rt;
<html&rt;
<body&rt;
<table&rt;
<xsl:for-each select="item[(position() - 1) mod 2=0]"&rt;
<tr&rt;
<td&rt;<xsl:value-of select="./text()" /&rt;</td&rt;
<td&rt;<xsl:value-of select="following-sibling::item/text()" /&rt;</td&rt;
</tr&rt;
</xsl:for-each&rt;
</table&rt;
</body&rt;
</html&rt;
</xsl:template&rt;

</xsl:stylesheet&rt;
0
ionicman #
Господи!!!!
Почему так криво то??? Какая нафиг подсветка синтаксиса, если оно простое то схавать не может?!!! Охренеть можно.... Раз в 5 минут и так криво!!! :D :D :D Я понимаю что надо предпросмотр юзать - но некогда мне - быстро написал пример и отправил.... Блин! Господа владельцы сайта, давайте я вам дам код для текстарии?? :D
0
ibnteo #
Это решение задачи в другом направлении, где будет на выходе получаться
1 - 2
3 - 4
5 - 6

Требовалось же
1 - 4
2 - 5
3 - 6
что сложнее
0
ionicman #
ага, недочитал - пример не посмотрел... но можно тоже на фориче рализовать в принципе
0
Fade #
В коде много переменных, но за счет них он работает в IE.

<xsl:variable name="totalItems"><xsl:value-of select="count(//list/item)"/></xsl:variable>
<xsl:variable name="totalItemsHalf"><xsl:value-of select="$totalItems div 2"/></xsl:variable>

<xsl:template match="//document">
<html>
<body>

<table border="1">
<xsl:apply-templates select="//list/item" mode="list"/>
</table>

</body>
</html>
</xsl:template>

<xsl:template match="item" mode="list">
<xsl:variable name="cur">
<xsl:value-of select="position()"/>
</xsl:variable>
<xsl:variable name="next">
<xsl:value-of select="$totalItemsHalf + $cur"/>
</xsl:variable>
<tr>
<xsl:choose>
<xsl:when test="position() > $totalItems div 2"></xsl:when>
<xsl:otherwise>
<td><xsl:value-of select="text()"/></td>
<td><xsl:value-of select="parent::*/item[position() = $next]/text()"/></td>
</xsl:otherwise>
</xsl:choose>
</tr>
</xsl:template>


А так, если использовать CGI-склеивание XML с XSL то код получиться короче
0
ibnteo #
И смысл использования трансформации на клинете, если придется так извращаться? :)
Если трансформер не поддерживает стандарт, то не надо его использовать, это будет мучение одно.
0
Fade #
Я привел пример для тех, у кого нет возможности по быстрому настроить CGI трансформацию. Этот пример можно просто загрузить в браузер и посмотреть.

Для рабочих проектов можно использовать все средства XSLT. В этом случае код уменьшается в разы и легче читается.

Я не говорю, что нужно использовать трансформацию на клиенте. Для этого пока нет достаточной поддержки со стороны браузеров.
+1
lyxsus #
подсказка:
match="item[position() div 2 = 1]"
0
KBA #
о-о-о... что то это мне напоминает одно тестовое задание :)
я прав?
0
Flack #
XSLT на фронтенде пока зло. На РИТе помнится было смешно, когда про это рассказывал Кудинов (вроде).
Забили помидорами под корень.
0
igeek #
А под фронтендом вы здесь подразумеваете клиент/браузер я так понимаю... чтобы почувствовать зло его ведь надо вкусить не так ли?.. вы его вкусили?.. надеюсь что нет. Мне, вот, повезло меньше, я вкусил, но, должен сказать, зло оказалось не таким уж противным на вкус))

Взять, к примеру, проблему индексации "сайта с XSLT на клиенте" поисковиками, проблема? согласен. А как насчет бэк-офисов, интранет-систем? если вы решаете задачу в этих рамках, то проблем с индексацией у вас уже нет, потому что она там не нужна. Видите, одним злом сразу стало меньше. Нужно просто поискать правильную сферу применения.

Что касается РИТа, то я на нем не был, но я смотрел запись этого доклада, мне он смешным не показался, мне он показался очень любопытным. Интересно, а как вы оцениваете ваши собственные доклады, уважаемый Flack?
0
Flack #
Шо ж вы серьезный-то такой.
Нет, я неделаю интранет-проектов. Не интересно мне как-то. Так что для меня неиндексируемая технология не существует, уж извините :)

Я говорил не про доклад, а про обсуждение.
0
igeek #
ну как можно обвинять в серьезности человека с такой аватаркой))

просто ваше утверждение звучит уж очень безапеляционно, мне захотелось немного его расшатать, и я не являюсь адвокатом Кудинова, но фраза показалась мне не очень дружелюбной)

P.S. Ты же сам докладчик, Лёха) прикинь, я напишу: было смешно, когда про это рассказывал Рыбаков (вроде)................ без обид)
0
Flack #
Я всегда стараюсь рассказывать, чтобы было смешно
0
igeek #
все, уложил на лопатки, я сдаюсь)
0
KBA #
я рассказывал, и сам же сказал что делать этого не стоит (если ты не делаешь админку под себя или интранет) и объяснил почему.
а вопрос этот обсуждается и сейчас, а толковой информации как небыло так и нет.
0
Fade #
Вопрос исключительно в удобстве: каму как. Мне удобно. Многим нет. Раньше тоже считал это бредом, пока не "попробовал". Теперь у меня вся CMS-ка работает на XSLT: и админка и сам сайт. При этом, алгоритм "сборки" для обоих частей CMS един.
0
KBA #
и не на РИТе, а ClientSide
0
Flack #
На Рите, на Рите.
0
KBA #
хм... интересно :)
как хоть назывался? и кто читал? а то Кудинова я в докладчиках не нашел. или это было в 2007?
0
Fade #
0
dyakov #
Хех… хабр весь исходный код поел((
Fade, не дадите ссылку на эту статью на другом сайте, где такой беды не приключилось?)

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.