Как стать автором
Обновить

Комментарии 50

Только один раз сталкивался с XSL, правда, в тяжелом случае, но на декларативный вид переписывать уже не буду.
В следующий раз обязательно вспомню и учту :)

Хотелось бы уточнить на тему apply-templates. А как быть, если item нужно вывести несколько раз на странице из одного набора, причем в каждом случае по-своему?
В «обычном» виде это решается через CreateItemLink, CreateItemSubmenuLink, CreateItemDescriptionLink например.
Посмотрите в сторону атрибута mode.
столкнулся с xslt при работе для Head Hunter. И скажу, что декларативный стиль на очень больших проектах очень помогает упрощать работу.
Вот насчет читабельности не надо. XQuery и то более читабельный, хотя вообще говоря, оба языка в плане читабельности «не фонтан».
НЛО прилетело и опубликовало эту надпись здесь
Скорость вполне хорошая, если конечно понимать как писать шаблоны и сколько данных подавать на обработку, есть и более тормозные шаблонизаторы, например Smarty. На практике XSLT отлично применяется мною уже много лет, ищу чем бы заменить, вдруг что-то лучшее придумали, но пока не нашел ничего лучше. После декларативности XSLT совершенно не хочется возвращаться в процедурщину.

Прелесть XSLT как раз в том, что он есть везде, при смене языка программирования не придется изучать еще и какой-нибудь новый шаблонизатор только из-за того, что прежний был реализован только на одном языке программирования, да еще и с ошибками (в XSLT процессорах ошибок уже давно нет).
НЛО прилетело и опубликовало эту надпись здесь
Я имел ввиду не переносимость шаблонов при смене основы сайта, что редко и никому не нужно, а про то, что нет нужды изучать совершенно новый язык шаблонов при работе на различных платформах.

Насчет сложного не совсем согласен, нужно просто выделить что XSLT умеет делать отлично (например работа с деревьями), а что вообще не умеет, и переложить эту работу на другой язык программирования.

Прелесть XSLT еще и в том, что если он запустился, то с огромной вероятностью проблем с шаблонами в будущем вообще не будет. В других шаблонизаторах с этим всё довольно плохо, хотя у меня не большой опыт работы с другими шаблонизаторами, но и этого хватило, чтобы оставаться на XSLT :)
Не согласен, что код получается только для записи, поддерживать его легко, если конечно привык к XSLT коду, даже через долгое время правка кода не вызывает проблем, и главное, что всё тут же работает без ошибок, имхо такая надежность у всех декларативных языков.
НЛО прилетело и опубликовало эту надпись здесь
Со скоростью обычно проблемы возникают есть при большом количестве данных использовать не полные xpath (//foo/@bar). xslt-процессору приходится проходить по всему дереву, по одному разу на каждый подобный xpath.
Смешной скоростью? xslt в libxslt-реализации очень быстр.

Дольше всего занимает парсинг больших xml и компиляция xsl. Если хранить скомпилированные стили и часто используемые распарсенные xml в памяти, то можно очень быстро гонять шаблонизацию.
Когда начинают говорить про скорость XSLT, хочется всегда сказать, что XSLT — это далеко не только шаблонизатор для сайтов…
А быстрее нативного PHP ничего не будет работать. А для XSLT нужно еще данные в XML собрать внутри PHP, а это тоже не особо быстро будет по сравнению с обычными массивами.
Но, тем не менее, у Яндекса все хорошо работать на XSLT.
Собственно, думаю, что наверняка Яндексу проще купить еще серверов, чтобы сэкономить время программистов, которым намного быстрее и удобнее поддерживать такую шаблонизацию.
Так в яндексе и не на PHP пишут ведь)
Ну тут я имел ввиду, что у них шаблонизатор XSLT и он работает неплохо у них.
А есть процессоры которые могут держать шаблоны в ОЗУ (shared memory к примеру) в уже распарсеном виде? Т.е. что бы при получении данных он сразу же мог выполнять трансформацию не тратя на каждый запрос время на загрузку и парсинг шаблона.
Есть, например, такой проект. Честно говоря, не пробовал.
Я использовал xslcache в реальных проектах.

Идея действительно такая как было сказано выше.
Прирост производительности — порядка 20%(зависит от XSLT)
Жаль только что похоже проект остановился в развитии еще несколько лет назад
Пробовал в своих проектах, но к сожалению большого прироста производительности не получил, вместо этого на порядок выросла нагрузка на CPU, с чем это было связано я так и не докопался тогда. Возможно, если бы проект развивался дальше — это решилось бы, а так последняя ревизия была 4 года назад ((
nginx так умеет, получать от backend xml и трансформировать его xslt
Насчёт shared memory не знаю, но просто в памяти процесса держать скомпилированные xsl позволяет libxslt. Очень шустро получается.
Кроме PHP наверное любой распространенный язык может) Для PHP есть xslcache но он не развивается. Хотя пару лет назад на одном проекте его использовали — все работало.
Ваша статья не раскрывает такие важные темы, как организация всего этого декларативного безобразия. Часто именно императивный шаблон легче сопровождать, чем выискивать «затерявшуюся» декларацию. Я пытался донести эту мысль в своей статье по XSLT.
Написать хороший шаблон на XSLT намного сложнее, чем плохой и часто среднестатистический Razor-код бывает понятнее среднестатистического XSLT.
XSLT даёт возможность удобно работать с иерархическими данными (отображение структуры сайта в навигацию), но когда отображение становится очень далеко от данных (отображение 2-3х чисел в пэйджинг новостей), то вам приходится городить структуры данных именно в угоду XSLT.
Правильный план: это всегда разумная достаточность, комбинирование шаблонизаторов и чувство простоты — однако это искусство и приходит оно с опытом.
Полностью согласен.
Я так и не нашёл идеального варианта «организации безобразия». Поэтому и не включил эту тему в статью.
Как найду — отпишусь =) А Razor — это и правда круто.
Согласен, насчет организации,
но for-each тоже не может выступать в качестве универсального решения, поскольку в таком случае теряется возможность переопределения правил для специфичных случаев
Чтобы не городить плохой XSLT, нужно просто напросто перенести этот огород туда, где формируются XML данные. Ну и в этой статье написано как лучше делать, и как лучше не делать.
Вот как раз переносить логику отображения в данные — плохо: поскольку так мы получаем узкоспециализированную ViewModel, которая не совсем годится для генерации другого HTML из тех же данных.
Насчет поиска декларации: иногда очень помогает некоторое подобие call-стека: на отладочной странице выводится стек подгруженных шаблонов, показана информация кто из какого файла, сразу видно кто кого перекрывает. Отладочная страница естественно может быть сгенерирована для каждого конкретного URL путем добавления GET-параметра, либо другим удобным, для вашего URL-маршрутизатора, способом.
Я всем советую использовать mode, чтобы не париться с колстэками. Кстати отладку сделать и колстэк можно посмотреть в Visual Studio
Ибо если у вас уже шаблон дошёл до такой степени, что без отладки в тяжело, то это хороший повод для рефакторинга.
Спасибо, хорошая статья.
Правда, смутила фраза

«Причём, если для шаблона используется mode, то дочерние узлы тоже будут преобразовываться с этим mode»


mode не наследуется его необходимо принудительно прописать для apply-templates, вне зависимости от mode самого шаблона. Может поведение в разных парсерах и отличается, но для libxslt это так.
Да уж, намудрил. Имелось в виду именно то, что вы сказали. Fixed.
Очень хороший цикл статей
по практическому применению XSLT (временные деревья) здесь

В целом он конечно больше ориентирован на опытных разработчиков.
На моей практике часто встречался вопрос: Как разложить список в N-колоночную таблицу.
Я всегда отвечаю примером:
  <xsl:template match="items" mode="table">
    <xsl:variable name="$cols" />
    <table>
      <xsl:for-each select="item[position() mod $cols] = 1">
        <tr>
          <xsl:for-each select=".|following-sibling::items[position() < $cols]">
            <td>
              <xsl:apply-templates select="." mode="table-cell" />
            </td>
          </xsl:for-each>
        </tr>
      </xsl:for-each>
    </table>
  </xsl:template>

Я даю «православный» совет?
Мои заповеди:
  • если представление зависит от позиции элемента в наборе (position()) — правильно использовать for-each
  • если шаблон — вспомогательный (как в вашем примере) и/или ему всё равно, что выводить — это должен быть именованный шаблон
Т.о. я почти согласен с вашим решением.
нет. что если у тебя данных 13 штук, а ширина таблицы 5 ячеек? вместо пустых ячеек будут дырки, что не всегда приемлемо. что, если у пользователя узкий/широкий экран? будут либо слишком большие поля, либо скроллинг.
лучше заверстать без таблички и чтобы количество столбцов бинамически подстраивалось под размер экрана
довод понятен, но сабж не про верстку
Почти, ни к чему использовать for-each здесь, просто унести td в вызываемый шаблон.

for-each имеет смысл использовать если внутри цикла есть условия, сортировка или для уменьшения раздробленности.
Ну вот я воспользовался for-each именно для уменьшения раздробленности структуры таблицы.
Сортировка — не аргумент. xsl:sort применим как для for-each, так и для apply-templates
так тут всё равно вызывается
<xsl:apply-templates select="." mode="table-cell" />

так, что раздробленность наличествует
Да. Вот когда он разрастётся свичами, ифами и HTML-кодом, тогда можно будет его разделять, а пока лучше не трогать.
Дело вкуса и стиля программирования.

Не совсем так в части именованных шаблонов. Есть еще такой критерий как реюзинг. И когда в десяти разных шаблонов осуществляется, например, рендеринг таблицы, а стиль которой един для всего сайта, то такие шаблоны просто необходимо выносить в качестве именованных. Собственно говоря, тот самый «процедурный» подход в программировании был придуман как раз с целью реюзинга. Так что я бы добавил условие, «если вы используете такой шаблон только один раз». Иначе вы можете сэкономить несколько строк и выиграть битву в рамках отдельно взятого xslt, но проигрываете войну в рамках всего проекта в целом))

Я всё ещё собираю подобные советы, т.ч. если у вас есть, что добавить, обязательно отпишитесь в комментах.

Самое веселое, что мне доводилось делать в XSLT — это реализация циклов от X до Y. Можно показать их рекурсивную реализацию. Так же можно посоветовать сразу обратить внимание на возможности расширений XSLT. Как правило, многие трансформеры имеют возможность подключать внешние библиотеки с реализацией тех или иных функций. В некоторых их можно писать на JS прямо в теле стиля. Просто по моему наблюдению многие отказываются от XSLT как только возникает необходимость в каком-то даже не очень сложном вычислении, а сделать его представляется проблематичным, в силу очень скудного набора базовых функций.
не надо программировать на xslt. рекурсивные алгоритмы — это громоздко, тормозно и геморройно
Иногда приходиться. Хорошо, когда это простая задачка в виде шаблонизатора для сайта и ты можешь подкрутить выдаваемый xml. Но xslt также часто используется для обеспечения интерфейса между двумя системами. У одной — свой xml-выхлоп, у другой — свой входной xml. И никак на это повлиять нельзя. XSLT, как правило, справляется гораздо лучше, чем ручной разбор и трансформация, но очень часто находятся некоторые мелкие и неприятные затычки. Например, тебе на входе идет строка +7(322)223-33-22, а на выходе />. Это тоже трансформация, но к ней XSLT не готов.
Тут нужны экстеншены. Umbraco вся построена на экстеншенах.
Вы правы. Нужно использовать все возможности языка по назначению. Чуть выше я привёл свои правила по выбору стиля.
Самое веселое, что мне доводилось делать в XSLT — это реализация циклов от X до Y. Можно показать их рекурсивную реализацию

habrahabr.ru/blogs/xslt/47545/
Собственно, с этой статьи и создан был блог, но дальше руки не дошли что-то писать. Вот теперь неплохую статью автор выкатил, я тоже хотел тогда давно об этом написать.
НЛО прилетело и опубликовало эту надпись здесь
Я в шаблонах раньше всегда такой добавлял:
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>


Сейчас на XSLT почти не приходится писать…
НЛО прилетело и опубликовало эту надпись здесь
Я тоже не уверен, поэтому привел свой вариант :)
У libxslt не очень удачная реализация document().
Каждый раз при вызове функции, файл открывается и парсится заново. Кеширования нет. Поэтому имеет смысл встроить свои справочники либо в сам xslt, либо во входной xml.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации