Pull to refresh

Comments 119

В ряде случаев удобнее использовать «xsl:apply-templates select=…» вместо вызова по имени + передача параметра.

Совет лично от себя: на подавляющем большинстве проектов имеет смысл делать общую страницу-лейаут, на которую закинуть основную разметку, а на конечных страницах только кидать в виде параметров основной контент по областям (в head, в осноной контент, в сайдбар и т.п.)
Обработка так и идёт
итоговый xml, в котором находятся данные всех блоков, обрабатывает с помощью индексного шаблона /themes/index/main.xsl и результат отдаёт пользователю в виде html.
Не совсем: у вас вставляются по сути куски html и через xsl:value-of, я предлагаю использовать xslt полностью, но тогда нужно xsl:copy-of. По крайней мере, насколько я понял. value-of для нод отдает только текст, а не теги/атрибуты.
В моём варианте в индексный шаблон попадают данные блоков уже в html-виде уже со всеми тегами и атрибутами.
Затем вставляются в нужное место не через xsl:copy-of, а через xsl:value-of с disable-output-escaping=«yes»:
<xsl:value-of select=«blocks/menu_top/html» disable-output-escaping=«yes»/>

На сколько я вы предлагаете делать то же только через xsl:copy-of.
Я о том же: у меня-то xsl сквозной для всего вообще, в принципе это и удобно (например, через 2 слоя передаю во всякие сложные странички дополнительные js и css в , по сути, не меняя шаблон-лейаут), а у вас — есть уже готовые куски html.
я не понимаю разницы. В готовых кусках html также могут содержаться js и css.
Из справки:
«Note: Namespace nodes, child nodes, and attributes of the current node are automatically copied as well!»
Т.е. value-of всегда возвращает строку (даже если будут заэкранированные символы разметки — это будет именно строка), а copy-of корректно передает тэги.
Вот тут пример более наглядный — сравнение xsl:copy, xsl:copy-of и xsl:value-of
Спасибо. Теперь я понял вашу идею.
Результат каждого xsl-преобразования вы рассматриваете как xml-документ, я же рассамтриваю его как html-строку.

В в вашем подходе вижу несколько положительных моментов. Например, итоговый xslt может выбрать все теги link и вывести их в самом начале документа.
Нет никакой гарантии, что сгенерированный где-то html будет содержать валидную xml-структуру. Мало того, он еще и не обязан быть таковым (meta, link и т.п.).

Поэтому разумно включать непроверенный html в исходное XML-дерево только как CDATA, и, соответственно, выводить в шаблоне через xsl:value-of с disable-output-escaping=«yes».

Доступ к структуре произведенного где-то html в шаблоне уже не нужен, поэтому не вижу выгоды (кроме вреда) в том, чтобы встраивать html в формате xml, а не в виде неструктурированных строк cdata.
Уже давно пора забыть xml как страшный сон. JSON наше все.
JSON хорош для js
Для xslt шаблонов XML — идеальный вариант.
Кроме того существует ли какой-нибудь аналог XPath для JSON?
Ну, если прям по чесноку — то XSLT чертовски перегружен визуально. Это многих пугает. С появлением Node.js я облизываюсь на что-нибудь наподобие YATE (довольно интересное описание как раз в сравнении с XSLT есть в этом посте) — просто чтобы ту же работу делать в несколько более дружественной и лаконичной обстановке. Много всяких неясностей со стандартизацией и необходимостью весьма кастомной настройки сервера, но, думаю, за этим будущее, пускай и не близкое.
Согласен XSLT в браузерах поддерживается очень плохо. Начиная от firefox, где есть особенности, заканчивая браузером android, где xslt вообще не поддерживается. Но даже с учётом этих нюансов есть разумные варианты.

Перегруженость — это цена понятности. Правда, я считаю xslt понятным. Также стоит посмотреть на названия функций во фреймворках. Никого же не пугают строки
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
не говоря уже о Zend.
На первом месте понятность, на втором уже лаконичность.
Меня, меня лично пугают строки типа MyCompany\Components\SuperShit\Controllers\MyCompanySuperShittyControllerHelperFactory. Куча повторяющихся слов и 0 смысла.
Мне не нравится словоблудие XSLT.
Мне не нравится синтаксический мусор XML (все эти ненужные скобки, кавычки, закрывающие тэги и пр.).

Суперкраткий синтаксис языка Си выдавил практически все остальное, хотя и не отличается особой читаемостью (особенно если активно использовать тернарный оператор и запятую). Элементы HTML называются a, p и div, а не anchor, paragraph, division. Популярные библиотеки в javascript вызываются через $ и _, которые вообще не несут никакого смысла — и ничего, никто не умер.
При некоторых условиях, можно спокойно заменить длинную колбасу на нечто вроде //property[name='email'] (двойной слеш — показывает, что нужно искать среди всех потомков узла) например. Принцип, который позже перекочевал в jQuery (если никто не понял тонкого намека от авторов — query от XQuery, который в свою очередь развивался параллельно с тем же CSS) и показал себя очень удобным: можно не описывать весь путь, а только указать на уникальные тэги/атрибуты.
По поводу громоздкости синтаксиса XML согласен с Вами.
Но не представляю ситуацию, когда в XSLT необходимо много и часто писать длинные пути.
Если у вас так получилось, это говорит о неправильной огранизации (1 шаблон обрабатывает все-все данные. должно быть много шаблонов), о том, что не используете переключение контекста (call-template вместо apply-templates) или плохо знаете о том, что путь можно сохранить в переменную и в xpath-выражениях использовать эту переменную.
В одном большом проекте работал с XSLT. Честно признать… Я не могу до сих пор найти причин его использовать где-либо в дальнейшем. Он вызывает у меня блевание негативные эмоции. Конечно же это мое личное мнение.
XML слишком распространен, что бы про него просто взять и забыть. А, вообще, чем JSON лучше XML?
Да никто про него хотя бы в корпорейте не забудет еще долго.
А JSON лучше: более простым синтаксисом и лаконичностью, чуть большей однообразностью (я вот до сих пор не могу придумать реальных ситуаций, когда атрибуты и субноды не взаимозаменяемы), дружелюбностью к браузерам через JS, более простой сериализацией/десериализацией на серверной стороне (т.к. по сути есть только один способ создания сложных конструкций, все велосипеды давно написаны).
Что хранить в ноде, а что в атрибуте — скорее философский вопрос.
Именно. Но из-за этого для перегонки объектов в xml нужно писать маленький велосипед (пускай и на уровне сниппета или библиотечной функции), а для json есть стандартный json_encode и его аналоги в разных языках.
В спецификации написано, что аттрибуты рекомендуется использовать для метаданных. Мой пример: вы десериализируете записи из базы данных и пишите primary key в аттрибут, если primary key не имеет смысла в контесте вашей бизнес модели. Таким образом запись полностью слита в XML, а побочная информация удобно отделена. Мне кажется это довольно хорошо для human readability.
JSON компактней и нативно обрабатывается JS, который становится все популярней и в клиентских приложениях, и на серверах. При этом он менее функционален по мелочи: нельзя указывать кодировку текста, нельзя указать версию стандарта, нельзя пользоваться атрибутами.
UFO just landed and posted this here
С хорошей IDE избыточность не заметна.

Считаю избыточным конструкции вида
<?php
my_func();
?>
посреди HTML-шаблона.
А как распечатать переменную в xlst?
Для этого значение переменной должно быть во входящем xml-е.
Тогда вывести её можно так
<xsl:value-of select="my_param"/>
В этом случае все html-мнемоники автоматически экранируются.
Или так
<xsl:value-of select="my_param" disable-output-escaping="yes"/>
В этом случае значение будет выведено как есть.

т.е. нам даже не нужно заботиться о содержимом. Все данные по-умолчанию экранируются, если не указано обратного. А это значит что в php-скрипте можно забыть о htmlentities.
кроме того есть xsl:copy-of (аналогичная функциональность, но в нее можно и ноды закинуть)
для отладки можно использовать xsl:comment и xsl:message
Шаблонизитор для шаблонизатора — это сильно
Вообще-то это не шаблонизатор. Прочтите более внимательно и поймете. Он транслирует свои конструкции в привычный вам xslt.
Недавно как раз написал небольшую библиотечку, так и назвал: habrahabr.ru/post/143103/ :)
Самый главный и существенный недостаток, это невозможность использования в подключаемых файлах: <xsl:import href=""/>
Какая неповоротливая гадость. Напомнило PHPTAL избыточным синтаксисом, аж передернуло…
В чём неповоротливость?
Визуальная. Резко сниженное когнитивное восприятие и ориентирование по коду по сравнению как с традиционными языками программирования, так и с шаблонизаторами, отказавшихся от кода в стиле xml/html разметки.

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

И при этом всем профит по отношению к аналогам практически нулевой (и то, только потому что, если мне не изменяет память, знание xslt — обязательное требование на одну из должностей в Яндекс).
Профит от использования XSLT заключается, как ни странно, в синтаксической равномерности. Тэги всегда с тэгами (окей, это html и xsl, но все же это лучше, чем html и php). Кроме того, в архитектуре работы с XSLT специально проводится довольно отчетливая граница между кодом и интерфейсом (танцы с вызовами php методов из шаблона считаю глубоко некошерными), что положительно сказывается на общей надежности и предсказуемости приложения.

А то, что кому-то синтаксис не нравится — слабый аргумент при обсуждении той или иной технологии.
А я и не упоминал вставку в php.
Я говорю о том, что профит от XSLT такой же, как от любого другого шаблонизатора вроде Smarty, Twig и т.д.

То, что он xml-style, чести не добавляет ни капли. Только редактировать сложнее и читать код из-за лишних конструкций.

"{{ user.name }}" куда круче толпы аттрибутов в теге: в одном задается тип выводимого значения, в другом переменная, откуда брать, а в третьем, нужно ли это экранировать. Да я даже в смс любимой девушке столько лишних символов не пишу.

Я осуждаю только адекватность использования XML-стиля, не более. Сами шаблонизаторы — это хорошо, т.к. они защищают от доступа до внутренних переменных (т.к. разработчик явно предварительно указывает, какие данные передать в шаблонизатор) и ускоряют разработку итерационных и блочных частей визуализации (шаблонизаторы бывают не только для веб-страниц).

То, что некоторые (в том числе и в комментариях ниже) утверждают о более легком усвоении XSLT, т.к. он похож на привычный HTML, и не нужно ничего нового учить,- в корне неверно, т.к. все равно нужно учить или «знать со словарем» как минимум толпу новых неизвестных доселе аттрибутов для тегов.

+ проблема подсветки синтаксиса. Что тебе id=«myTable», что style=«width:100%;», что class=«hidden», что disable-output-escaping=«yes» — все будет подсвечено одинаково — это крайнее хамство для глаз разработчика, т.к. чтобы проконтролировать правильность и законченность блока нужно будет тщательно перечитать все, а не пробежаться по подсвеченным флагам, тегам и включениям на заметно другом языке.

>> А то, что кому-то синтаксис не нравится — слабый аргумент при обсуждении той или иной технологии.

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

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

Аргументом за XSLT также не может быть тот факт, что якобы вот этот шаблонизатор только для Node.js, а этот только для PHP, а XSLT зато ко всему подходит, потому что xml, xpath, xsl. Покажите мне какой-нибудь проект, где использовался шаблонизатор и в котором приходилось менять язык, на котором он написан? Если пишется боевой проект, в нем подбирается все тютелька-в-тютельку с нужными коэффициентами масштабирования, полиморфности и производительности, а не «ой, а вдруг мы вот тут вместо RoR решим уйти на php, давайте лучше использовать XSLT».
Какие есть достойные аналоги XSLT? В Яндексе только YATE нашли как хоть что-то примерно похожее, но ведь YATE не сможешь использовать в том же PHP и во многих других языках (пока по крайней мере).
Ну опять же: выбираешь язык — выбираешь шаблонизатор, с PHP есть уже упомянутый Twig, например — все зависит от того, что в проекте требуется получить на выходе.

К слову, YATE охрененнен по сравнению с XSLT, подробнее для тех, кто еще не видел, хороший пиар тут:
habrahabr.ru/company/yandex/blog/151700/

По ссылке также приведены причины, почему XML — бяка.

На всякий случай: Не нужно искать универсальный шаблонизатор под все языки. Есть проект. Выбран язык. Выбирай шаблонизатор.

Под каждый язык есть шаблонизаторы, где они могут применяться: где-то это Twig, где-то YaTE, где-то nJSt или Mu, из всех доступных под выбранный язык можно найти достойного,) Не имеет смысла вообще зацикливаться на XSLT, независимо от выбора языка или целей проекта, это динозавр.
Я понял похоже, почему одни ругают XSLT, а другие защищают. XSLT это функциональный язык, если вы думаете в его стиле, то вам не подойдут процедурные языки шаблонизации. И наоборот. Поэтому YATE может заменить XSLT, а Twig — нет. Но YATE пока реализован лишь для одной платформы, и для меня пока он не существует, потому что шаблонизация на клиенте мне не нужна, да и я бы не сказал так однозначно, что он гораздо лучше, чтобы такое говорить, нужно сделать хотя бы один проект.

XSLT еще хорош тем, что на нем действительно можно «зациклиться» и использовать на любой платформе, особенно если уже привык к нему. Вот то что он перестал развиваться, плохо, рано или поздно придется искать замену.
Вряд ли стоит ждать yate для php или java. Потому что суть yate — преобразование шаблона в js-код.

XSLT не перестал развиваться. Перестала развиваться его поддержка в браузерах/языках. Например в php до сих пор поддерживается только XSLT версии 1.0, хотя уже давно есть версия 2.

В браузерах же всё ещё хуже. В упомянутой статье habrahabr.ru/company/yandex/blog/151700/ говорится о том, что в современных браузерах будет работать шаблонизитор, написаный на скриптовом языке js, чем нативный шаблонизитор. Это звучит удивительно и печально.
Вообще у меня есть в планах сделать компиляцию yate в php.
Не в ближайших правда, но однажды непременно.
Не напрягает, что для использования XSLT нужны специально обученные люди с особым складом ума, а остальными шаблонизаторами может пользоваться любой дурак?
Если перестать обращать внимание на неймспейсы «xsl:», то нет, не сильно он избыточный. Зато позволяет использовать гораздо больше копипасты и делает сам процесс шаблонизации на порядок более предсказуемым и прозрачным, чем какие-то доморощенные шаблонизаторы или чем смарти на сложных данных.
Сама по себе избыточность немного неприятна (впрочем, сниппеты это нивелируют), лично у меня есть большие надежды на JSON + Node.js + YATE (или аналоги) — это будет счастье, но пока нужно подождать, т.к. стабильность пока хромает.
Конечно, у xslt порог вхождения выше чем у того же смарти. Потому что смарти — это просто сахар для php. А xslt — это технология. Для того чтобы научиться им пользоваться нужно понимать не только xsl, но и xml и xpath. А также научиться мыслить не переменными, а узлами и атрибутами.
Но не так страшен чёрт. У нас даже верстальщики понимают xslt.
Ну давайте теперь не пользоваться компьютерами, ведь порог вхождения в управление телевизором намного ниже.

XSLT выучил один раз, и можешь его использовать везде, а ваш Smarty придется забыть, как только смените платформу разработки, и изучать другой шаблонизатор. Да и не согласен я, что Smarty это сахар для PHP, это совершенно другой стиль, и у него полно своих нюансов, которые требуют обучения, сравните для примера объем документации к нему и к тому же XSLT.
а ваш Smarty придется забыть, как только смените платформу разработки, и изучать другой шаблонизатор

Изучать шаблонизатор? Да вы сметесь.
Это xslt вы можете изучать, а шаблонизатор изначально понятен, за исключением некоторых тонкостей, которые гуглятся в мануале.
Я называю изучением то, что вы называете гуглением в мануале. Основа XSLT это XML, который не сложнее уже всем знакомого HTML, разве что вводятся дополнительные вещи, такие как: XML Namespace, XPath, но их знание совершенно не повредит для общего развития веб-разработчика.
Наоборот, XSLT понять намного проще — проще чем X-Path вряд ли что-то придумаешь. Гибкость работы с данными потрясающая. Для одного и того же узла можно делать несколько шаблонов с разными mode и вызывать нужный в зависимости от входных данных. На мой взгляд, самый легко читаемый из шаблонизаторов.
абсолютно согласен. щас работаю с твигом — довольно проблематично визуальное восприятие. да и проверка обработка данных выглядит «страшнее». да и обработку:

<xsl:for-each select="node/node[count(menu[@name='main_menu']) != 0]">...</xsl:for-each>


сделать на твиге не афигев от количества строк — проблематично.

зы: но это чисто мое мнение :)
здесь count()!=0 лишнее, достаточно написать:
node/node[menu[@name='main_menu']]
да, ты прав.

просто xalan который я юзал в яве в 2001-году, кажется на такой конструкции погонял. может ошибаюсь, но привычка писать так осталась, надо переучиваться :)
Много лет использовал XSLT но в последнее время перешел к нативному шаблонизатору Yii
Мое мнение:
— XSLT очарователен в своей концепции. Но его надо использовать по назначению!
— Конструкции вида <xsl:value-of select="php:function('str_plural_form', 1*$cnt_users, 'пользователь', 'пользователя', 'пользователей')"/> могут вызывать утечку памяти на некоторых версиях php (см на php.net)
— Отказался по причине что чтоб сделать простую вещь — например оторбазить GET параметр — его надо сначала запихать в XML а потом вывести в шаблоне (про безопасность я тут НЕ говорю!)
— В шаблон можно передавать только строковые переменные. Никаких объектов и т.д… ну или извращаться с сериализацией \ десериализацией объектов
Я на xslt около года работаю и практически все время на одном шаблонизаторе (там есть кой-какие допилы, мне, правда, до конца неизвестные):
— для GET, POST и кукизов есть возможность получать значения через объявленные xsl:param в корне xsl:stylesheet (не поручусь, что это дефолтное решение — повторюсь, работал на сервер-сайде с большими допилами);
— про то, что можно передавать только строковые переменные — имеете в виду, что их нельзя закинуть в xsl:variable/xsl:param? Иначе я немного не понимаю — простенький сериализатор php->xml по аналогии с json_encode решает проблему.
На счёт вызова php-функций. В статье я привожу пример, где показываю что на самом деле так делать не рекомендуется. И здесь я с вами согласен.

Если передавать в шаблон объект, то велико искушение использовать методы объекта. Методы объекта могут не только возращать данные, но и изменять их, а это противоречит парадигме MVC, следуя которой view должен только отображать данные.
Если, как указал Holden, имеете в виду, что в вызове через неймспейс «php:» — то оно совсем вредное для передачи объектов. Сериализатор и REST-шлюз решают проблему достаточно радикально.
Приведенные примеры режут глаз. Как, примерно, мы используем xslt шаблоны:

<!-- Вывод информации о пользователе -->
<xsl:template match="*" mode="user">
	<div class="user">
		<xsl:apply-templates select="." mode="user_picture"/>
		<xsl:value-of select="concat(first_name, ' ', last_name)"/>
	</div>
</xsl:template>

<!-- Вывод фотографии пользователя -->
<xsl:template match="*" mode="user_picture">
	<!-- По хорошему в xml нужно хранить путь до картинки целиком -->
	<img class="user__avatar" src="/img/{string(userpic)}.png" />
</xsl:template>

<!-- Загрушка, если нету фотографии пользователя -->
<xsl:template match="*[not(userpic)]" mode="user_picture">
	<span class="user__avatar user__avatar_default"></span>
</xsl:template>

<xsl:template match="*" mode="post">
	<!-- Выводим пользователя из поста или найденного по user_id -->
	<xsl:apply-templates select="(user|/*/ref_users/item[user_id=current()/user_id])[1]" mode="user"/>
</xsl:template>


<!-- Выводим текущего пользователя, или пользователей, соответствующих xpath выоражению -->
<xsl:apply-templates select="/*/cur_user" mode="user"/>


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

XSLT не понацея, но очень удобный шаблонизатор, когда знаешь, как с ним работать. Реальный пример вижу каждый день — у нас две версии проекта: старая и новая, обе рабочие. В новой версии chikuyonok бережно переписал, заложил возможности для расширения в тех местах, где это может предположительно потребоваться, что аж глаз радуется :). А самое главное — разобрать шаблоны не составляет большого труда, чего не скажешь о шаблонах в старом проекте.
Причем синтаксическая корректность самого шаблона легко проверяется, так сказать, налету. Например, в netbeans есть встроенное средство валидации шаблона — очень удобно.
Зачем везде звездочки? Вы же знаете, что у вас в XML.
Можно и без звездочек.
Иногда требуется использовать шаблон в разных контекстах, но с одинаковой структурой внутри.

Это пример, не более того.
Кто нибудь подскажет, какими средствами XSLT применяют? У меня есть корпоративное приложение, которое готовит отчеты в XML формате. И я хочу сделать веб-клиент для просмотра этих отчетов. Тобиш мне нужно конвертировать XML в HTML. Где это должно происходить, на сервере или в браузере? Если на сервере, какие есть популярные инструменты?
У нас генерируются Excell документы таким образом (as.net mvc): на стороне сервера генерируется xml документ (в основном средствами sql server), из БД подтягивается шаблон и с помощью трансформации, клиенту отдается готовый документ, который открывается в MS Office или Open Office.
UFO just landed and posted this here
Не понял, как ваша ссылка должна мне помоч. Там просто товарищ просил объяснить почему его трафнсормация не работала так, как он ожидал.
Посмотрите документацию .NET, как на сервере делать XSLT преобразование, это всего лишь несколько строчек кода. Не связывайтесь с клиентским XSLT, там проблем много, и нужно хорошо в этом разбираться.
На заметку: хороший пример широкого применения XSL — система HostCMS, с незапамятных врем там используются эти шаблоны, отличный кладезь примеров разной сложности.
Единственная причина, имхо, почему такой пост жестко не заминусован — это то, что немногие разбираются в XSLT. Это даже на tutorial для новичков потянуть не может, как минимум, просто из-за тотального незнания автором как XSLT, так и возможностей PHP для работы с ним.
пройденный этап лет эдак пять назад…
как ни красив xslt — он медленный, как и dom-xml

я даже отказался от использования dom в сторону скорости.
мерси, пригодится, надеюсь, в ближайшем будущем
что пригодится — шаблонизатор Яндекса или моя статья?
Вопрос к автору — что вас заставило начать использовать xslt? Я на работе вынужден, к большому сожалению, использовать xslt. C этим у нас вылезает огромная куча багов. Но, к сожалению, уже не возможно от него отказаться, поскольку аппликация настолько огромна, что избавиться от него равносильно избавиться от аппликации.

Вместо того, что бы на страничке использовать кусочек js кода, приходится писать что-то в этом роде:
&lt;script language='text/javascript'&gt;
  jQuery(function(){
    //... do something
  });
&lt;/script&gt;


Плохочитаемо и не всегда трансформация происходит успешно. О вменяемоей подсветке, естественно, можно забыть. Трансформация на серверной стороне у нас происходит, поэтому порой в репозиторий коммитится код, который не трансформируется и т.п. В общем, куча костылей и проблем от XSLT у нас хватает.
ИМХО JS на страничке без веской необходимости — это весьма плохо, даже если удобно (потому что потом искать и править такое — как раз очень неудобно). Под необходимость попадает нечто, нагенеренное из данных, например инициализация карт, где хватает просто вызова функций.
Смотрите в сторону атрибутов xsl:output, у меня в стандартном виде делать указанные вами извращения не требуется (исключение — «&»)
<xsl:output method="xml" encoding="utf-8" doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" media-type="text/html" indent="yes" undeclare-namespaces="yes" omit-xml-declaration="yes"/>
Вижу, что вы используете xsl:output method=«xml», это прямое следствие habrahabr.ru/post/151241/#comment_5395567
Я рекомендую использовать
<xsl:output method="html" version="1.0" omit-xml-declaration="yes" encoding="utf-8"/>
В таком случае генерируемый html будет более валиден. Кроме того метод method=«xml» не совсем подходит для генерации html. Были некоторые косяки, о которых сейчас не вспомню. Но мой выбор method=«html» вполне осознан.
Вполне возможно. Хотя мы для себя выбрали XHTML, для него это как раз весьма подходящий вариант, позволяющий как раз сделать боле-мене сложную конструкцию. Кроме того, при желании можно закинуть html в конечные страницы, сохранив xml для всех внутренних — по идее должно работать корректно, хотя проверять — учитывая размеры и количество уже работающих систем — желанием не горю)
все не так просто. есть проект которому на вскидку лет 10(может чуть по-меньше). есть тысячи страниц. Есть самописный фреймворк, обросший своими костылями. нет не сил не возможности поменять всю инфраструктуру. Возможно, у меня лишь негативный опыт. Но тем ни менее. Горюшка я успел похлебать немало с XSLT.
Это есть такое. Сам-то я наоборот, глядя на глючный, заморочный и кривой шаблонизатор внешне похожий на смарти — радовался как ребенок, когда понял, что можно это все кинуть на xslt и хотя бы получать предсказуемый результат без копания в PHP на каждом чихе. Выпил, наверное, цистерну кофе, пока разобрался и нашел все необходимое для работы, но оно того стоило.
Приведёный пример работать будет, но зачем так делать, если следующий код прекрасно работает (скопировано прямо из проекта)
    <script>
      dtime = 43;
      T_time=null;
      $(function(){
        downtime();
        T_time=window.setInterval("downtime()", 1000);      
      });
    </script>


Кроме того существует cdata
<![CDATA[ тут всё что угодно ]]>


О подсветке кода js внутри xsl — вопрос к IDE не находите? Также IDE поможет вам сделать валидный xsl и о проблеме с трансформацией можно забыть.
<![CDATA[ тут всё что угодно ]]> — это и есть те самые вещи, которые не делают мою жизнь разработчика проще. Хотя возможно я не прав и XSLT отличная штука. Ну и в прицнипе IDE такие IDE — нельзя от них ожидать отличной поддержки чего-либо. Можно лишь ожидать попытку облегчить жизнь разработчиков. ;-)
Почему выбор пал на xslt? Конечно изначально я пользовался обычными темплейтами, не лучше и не хуже остальных. Затем сменив работу, был удивлён что там использовали какой-то монструозный и непонятный xslt, вместо красивых быстрых понятных и нативных шаблонов. Освоив xslt, уже невозможно от него отказаться. (Не скажу что освоил я его легко и с первого раза, но оно того стоит)

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

Какими данными оперирует отображение — важный вопрос MVC.
При использовании xslt данные находятся в xml. Это даёт нам возможность вывести данные которые попадают в шаблон в виде дерева. Что очень наглядно и позволяет легко выделить именно те данные которые мы сейчас собираемся вывести. Это очень помогает при отладке. И это один из основных плюсов такого подхода.
Только что вспомнил: возможна проблема с лишними атрибутами в xsl:output. Если там есть нечто наподобие cdata-section-elements=«script» — это запросто может быть причиной ваших мучений.
Знакомо. У нас даже написан отдельный шаблон для этого.
В комментарии к шаблону есть его применение.
Выстрадано шишками.
Умники скажут, что скрипт в теле страницы это неправильно и будут правы.
Но тем не менее на моей памяти было пару моментов,
когда надо было вставить тег скрипт и обходных путей не было.

<!-- Создание тегов script -->
    <xsl:template name="script-in-xhtml">
        <!-- Вызов:
        <xsl:call-template name="script-in-xhtml">
            <xsl:with-param name="script-code">
                <![CDATA[
                alert("Test script");
                ]]>
            </xsl:with-param>
        </xsl:call-template>
        -->
        <xsl:param name="script-code" />
        <xsl:param name="script-type" select="'text/javascript'"/>
        <script type="{$script-type}">
            <xsl:text disable-output-escaping="yes">
//<![CDATA[</xsl:text>
            <xsl:value-of select="$script-code" disable-output-escaping="yes"/>
            <xsl:text disable-output-escaping="yes">//]]>
</xsl:text>
        </script>
    </xsl:template>



А в чем проблема то собственно? Если не охота эскейпить вручную данные в коде, то есть же для этого

<![CDATA[
<script>if (a && b) document.wite('<b>'+a+', '+b+'</b>');</script>
]]>
Речь идёт о выводе xhtml.
В этом случае xsl:output примерно такой:

<xsl:output method="xml"
                encoding="utf-8"
                standalone="yes"
                indent="yes"
                omit-xml-declaration="yes"
                doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
                doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN"/>


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

При выводе html c нижеследующим xsl:output Ваш код, да, работает вполне и без плясок с бубном.

<xsl:output 
        method="html"
        encoding="UTF-8" 
        doctype-public="-//W3C//DTD HTML 4.0//EN"
        doctype-system="http://www.w3.org/TR/1998/REC-html40-19980424/strict.dtd"
        indent="yes" 
        lang=""
        omit-xml-declaration="no" />


Есть ещё серьезные различия между xsl:output xml и html, приводящие к проблемам, но я плохо помню.
Вроде бы xml всегда приводит пустые теги к виду <tag/>, даже если они были написаны как
<tag> </tag> (даже с пробелами внутри в xsl шаблоне). И ещё что-то, но я не упомню, т.к. давно перешёл на вывод html вместо xml.
Не помню чтобы это было проблемой, давно уже начал использовать XHTML, и выводил через <xsl:output type="xml">, специально нашел старый свой сайт (шаблон), где используется XHTML, и теги <script src=""></script> закрываются как надо.
<!-- SWeb banner code begins -->
<!--
<script type="text/javascript" src='http://ad.sweb.ru/b.js'></script>
<script type="text/javascript">sweb_bans_show(31, 11655);</script>
-->
<!-- SWeb banner code ends -->


А вот к этому я как раз имею прямое отношение, т.к. работаю в sweb.ru. Были вебмастером? Не завидую. А сейчас скорее всего в партнёрке timeweb.ru?

В вашем примере doctype
doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN"

в моём
doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN"

Запомнил эти 2 doctype, ещё html (уже упомянал выше) и гоняю с ними тестовый фрагмент шаблона:
<script>
               <![CDATA[
if (a && b) document.wite('<b>'+a+', '+b+'</b>');
]]>
               </script>


При наших с Вами doctype (XHTML Transitional и Strict),
этот код выдаёт тег скрипт с испорченными внутренностями (угловые скобки и & заменены на сущности), cкрипт получился нерабочий. Убедитесь сами, если не верите.

А вот при doctypehtml вывод отличается, внутренность сохранилась в оригинальном виде — угловые скобки и & остались как были, скрипт рабочий. Вот такая сложность с внутренностью тега скрипт в xhtml.
Да, написать скрипт без CDATA невозможно — сразу будет проблема с валидностью из-за угловых скобок и &. Однако скрипты без этих спецсимволов не имеют проблем.

В Вашем шаблоне тегов скрипт с содержимым нет, а проблема именно когда вы начинаете писать JS-код внутри тега со всякими & и <,>. При подключении отдельного JS-файла код JS не находится в XSL-шаблоне и, соответственно, никак не преобразуется и не валидируется на XML.

Т.к. проблема с преобразованием и валидацией символов в теге скрипт возникает только при наличии там угловых скобок и &, то ещё есть способ обхода этой проблемы через алгоритм, схожий с обфускацией.
Например, если я хочу написать условие if (a && b) { ... }.
Я могу уйти от & так:
if (eval('a ' + unescape('%26%26') + ' b') { ... })
Но это уж совсем для безвыходных ситуаций костыль.
Про CDATA уже где-то выше писал, в чем проблема то его использования в шаблонах? Да, это нужно делать, или вручную заниматься преобразованием некоторых символов, тоже не велика беда, понимаешь же, что делаешь XHTML, у людей зачастую он не валидный из-за незакрытых тегов и т.п., на что браузеры чихают на самом деле. Сейчас правда уже не актуально, давно перешел на HTML5, и использую <xsl:output type="html"/>.
Объясните, как в вашем случае связаны XSLT с jQuery?
И почему вы не можете использовать JS код напрямую?
Никак. Это как пример выдранный из памяти. Довольно часто приходится зарегестрировать/произвести какое-либо дополнительное действие, когда страничка загрузится и т.д. и т.п.
тоже писал функцию склонения существительных с числами, вот она:
<xsl:template name="declension">
        <xsl:param name="int"/>
        <xsl:param name="expr0"/>
        <xsl:param name="expr1"/>
        <xsl:param name="expr2"/>

        <xsl:variable name="count" select="$int mod 100"/>

        <xsl:choose>
            <xsl:when test="$count >= 5 and $count <= 20">
                <xsl:value-of select="$expr2"/>
            </xsl:when>
            <xsl:otherwise>

                <xsl:variable name="count1" select="$count mod 10"/>

                <xsl:choose>
                    <xsl:when test="$count1 = 1">
                        <xsl:value-of select="$expr0"/>
                    </xsl:when>
                    <xsl:when test="$count1 >= 2 and $count <= 4">
                        <xsl:value-of select="$expr1"/>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:value-of select="$expr2"/>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:otherwise>
        </xsl:choose>

    </xsl:template>


Сейчас я использую XSLT, но испытываю недостатки в нём при попытках ускорить работу скриптов.
У меня есть идея сохранять в кеш сразу отработанные до готового HTML блоки веб-интерфейса,
это позволяет не получать и обрабатывать шаблоном целые фрагменты веб-страницы,
если мы знаем, что эти данные были ранее обработаны и не менялись.

C XSLT тут оказывается провал, т.к. применяя шаблоны XSLT, мы доверяем самим шаблонам XSLT обрабатывать все фрагменты интерфейса. XSLT не имеет возможности сходить в хранилище кеша и взять оттуда кусок готового HTML. Приходится писать промежуточный слой между шаблонизатором XSLT и контроллером, который выглядит менее удобно и работает медленнее, чем та же конструкция, написанная целиком на PHP.
Т.е. такая задача с XSLT хорошо не решается. А то, что мы с XSLT приближаемся к правильному MVC — меня греет меньше, чем решение реальных задач :)
Кстати с ним верстальщики больше отделены от программистов. Но верстальщик всё равно может испортив сайт, загрузив неправильный шаблон. И не все ошибки в xslt чисто синтаксические и могут быть выловлены. Есть ещё runtime-ошибки, такие как попытка добавить атрибут элементу, которому уже добавлен контент, что тоже приведет к фейлу при обработке данных таким шаблоном и отловить такую ошибку можно только применив этот шаблон в реальных условиях.
Я говорю о XSLT на серверной стороне. Также XSLT можно применять в браузере (в JavaScript) — в таком виде его использовала почта Яндекса, например.
Верстальщик может испортить любым шаблонизатором сайт, поставив лишний </div>, или написав нехорошее слово в заголовке сайта :)

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

Кешировать части страниц не обязательно в самом XSLT, для этого можно использовать старый добрый SSI, который вставлять в страницу через xsl:comment.
Ещё можно написать интерфейс с долей шаблонизации на жаваскрипте, с подгрузкой частей страницы аяксом :) И мой первоначальный вариант и Ваш и мой вариант из этого коментария размазывает логику отображения по нескольким местам и потому, тяжелее в поддержке, чем использование одного умного шаблонизатора, например php.
PHP как шаблонизатор не удобен, потому и существует такое множество шаблонизаторов. При работе с AJAX я предпочитаю отправлять уже готовые HTML данные, которые не нужно шаблонизировать на клиенте, к тому же зачастую эти данные требуется выводить и без AJAX, поэтому по-любому нужна серверная шаблонизация.
То что, неудобен как шаблонизатор, с вами согласен. Отчасти поэтому практически сразу как изучил PHP перестал пользоваться им как шаблонизатором :) Но у него есть способности для выполнения любых действий, это бывает нужно иногда. И, да, в плохих руках такие способности у шаблонизатора приводят к их неправильному использованию. «Выводить данные и без AJAX» — от этой проблемы тоже можно увернуться, разве нет? Шаблонизация на клиенте имеет плюс в том, что сервер не тратит на нее ресурсов, он просто выдаёт данные, а обрабатывает браузер. Хороший пример с шаблонизацией на JS — phpanel.ru/user/reg, тут вся шаблонизация на JS. P.S. я связан с данным сайтом только тем, что работаю в той же сфере.
Когда-то XSLT был главным претендентом на клиентскую шаблонизацию, но увы, не вышло, хотя очень близко подошел он к этому, теперь конечно слово за JS.
Да, XSLT слишком сложная технология для отрасли браузеров.
Нельзя разработчикам всех браузеров просто взять и реализовать поддержку XSLT :)
«Кусочек» xslt, на мой взгляд, лидирует в своей области до сих пор. А именно XPath, в качестве селектора узлов.
На любой серверной платформе реализовано, а в браузерах сложно? Хотя на самом деле уже реализовано, все современные браузеры поддерживают, но время упущено, программисты не хотят его уже использовать. Проблема видимо еще и в том, что некоторые старые браузеры, которыми еще пользуются, совсем не поддерживают, поэтому и не запустишь проект на клиентском XSLT, пока эти динозавры не отомрут полностью. Так что может еще и увидим XSLT в браузере.

XPath можно использовать и без XSLT. В PHP есть замечательная встроенная библиотека SimpleXml, ей можно пользоваться и без использования XML, только для нужд PHP, XPath в ней есть.
Яндекс когда переводил свою почту с клиентского XSLT на YATE жаловались на неоднообразность в некоторых моментах и меньшую скорость работы со сложными шаблонами и на несколько большую избыточность передачи XML вместо JSON.
Треш из тегов и в XSLT можно получить. Достаточно применить CDATA или <xsl:value-of/> c параметром disable-output-escaping, который кстати автор поста опасно использует в примерах.
Я внизу написал о том, что думаю по поводу DOE, это тонкий инструмент, и его редко когда нужно использовать (я использую только в одном месте, где идет вывод заведомо правильного контента в XHTML, который был до этого преобразован из Markdown, проверен на наличие незакрытых тегов, опасных тегов и атрибутов, и т.п.), за его использование не по назначению нужно верстальщика бить по рукам.
Почему же опасно? Вывод с disable-output-escaping производится только сгенерёного контента, или того что ввёл сам программист. А не доверять собственному коду, это уже явный перебор.
В принципе можно. Но потенциально опасно. Использовать disable-output-escaping это как потерять лишнюю ступеньку защиты. Это как не использовать плейсхолдеры в запросах к БД из соображений, что данные вы готовите сами. Придёт другой программист, менее разбирающийся в коде, доработает функционал так, что там появится и юзерский ввод, вот и здравствуй XSS.

Кроме того в этом коде чувствуется какая проблема с архитектурой. Именно чувствуется, т.к. внятно сформулировать проблему не могу. Вот что выглядит странно:
В Ваш XML с данными Вы сохраняете в узлы blocks/content/html HTML-код блоков.
HTML, если бы он был XHTML, мог бы располагаться в виде структуры узлов, с которой можно было бы проводить различные дополнительные xslt-преобразования. Но судя по топику я так понял, что у вас он не XHTML, а HTML, то он лежит в виде простого контента, единого текстового узла. И работаете вы с ним, как с текстом через xsl:value-of. Есть в этом что-то неправильное, как микроскопом гвозди забивать.
Зря разбиваете на header, footer, menu, это составные части одной страницы (точнее всех страниц сайта), их лучше в один файл положить. А вот шаблоны обработки разных контроллеров лучше разделять, чтобы не загружать лишнее при обработке. Лучше следовать такому принципу, чтобы не грузились шаблоны, которые не работают в данных условиях, например, зачем при выводе данных о пользователе загружать еще и шаблон вывода списка новостей. Поэтому делается главный шаблон с оформлением страницы, и шаблоны объектов, которые уже и подцепляют этот главный.

Потом, у вас есть пример использования xsl:call-template, и в нем же идет xsl:choose, не лучше ли в этом случае использовать xsl:apply-templates, и несколько xsl:template? Вместо xsl:for-each/xsl:call-template/xsl:with-param нужно делать просто <xsl:apply-templates select="users/item"/> или &lt:xsl:apply-templates select="/*/cur_user"/> и сам шаблон: <xsl:template match="users/item|cur_user"> (в крайнем случае можно использовать параметр mode="user": <xsl:template match="*" mode="user"> и в <xsl:apply-templates mode="user">).

Не увлекайтесь disable-output-escaping="yes", допустимо его использовать только если вы получаете уже готовый XHTML контент, например после Markdown, но уж ни в коем случае не для заголовка и подвала сайта.

Не нужно выносить в XSLT то, что он умеет делать плохо, например обработку строк, лучше добавить во входные данные дополнительный параметр, ведь когда сериализуете ваши данные, всегда можно вставить дополнительный обработчик, чтобы получить готовые для вывода данные. Если формируете данные в элементы, то такие дополнительно обработанные можно положить в атрибуты, в вашем случае это может быть cnt_users/@f_plural_form.
header, footer, menu в один файл не обязательно класть. Например, на разных страницах может быть разный header.

Не люблю xsl:apply-templates по той причине, что он заставляет плодить дополнительные xsl:template, в которых нет нужды. Моё правило «каждый xsl:template служит для определённой цели». Создание xsl:template для реализации простого ветвления не добавляет читаемости коду.
Кроме того нигде нет официальных рекомендаций, что использовать xsl:apply-templates лучше, чем xsl:call-template.
А нравится мне xsl:call-template за то, что такая запись приближает нас к процедурному языку, что может быть немного противоречит идеологии xslt.

О disable-output-escaping ответил чуть выше habrahabr.ru/post/151241/#comment_5397729

Почему xslt плохо работает со строками?
Например, на разных страницах может быть разный header.
Так и шаблоны для заголовка могут быть в этом случае в тех же файлах, что используются для вывода конкретного объекта, получается что мы просто переопределяем шаблон, тем более, что есть такая штука как <xsl:apply-imports/>.

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

Со строками работать можно, даже есть очень удобные функции для этого, но приходится использовать рекурсию, и опять же, получается многословно. Вынося обработку текстов в процедурный язык, получаем большие возможности, меньше кода. Ведь не обязательно делать это из XSLT, можно на этапе формирования XML данных.
При правильной организации и использовании модов, call-template и apply-templates практически эквивалентны. Разница лишь в том, что в at можно сразу ноду передать (одновременно используя предикаты для ограничений). Использовать это можно (и нужно), когда для работы шаблона в любом случае нужно значение ноды. Например, так достаточно удобно отдавать на ресайз картинки: вызывает at, внутри творим всякую мусорную магию (вызов внешнего ресурса по REST, длиннющая строка, оформление img в тег, генерация alt) — и все одним вызовом, потому что все необходимое уже есть в ноде. Можно ее и через параметр передать, не спорю, но они все же более ориентированы на передачу простых строчных значений.
Кроме того в at удобно кидать всякие списки — непосредственно в apply-templates делаем обвязку, наподобие ul, внутри через for-each перебираем все итемы и творим с ними магию. Итого на входе apply-templates, на выходе целиком спосок со своей обвязкой, все аккуратно и мило.
call-template тоже имеет доступ к текущей ноде. Передачу ноды в template использую для удобства и гибкости. Например, данные для пейджера могут быть в ноде pager, а могут быть в ноде pager_main, если на странице несколько пейджеров.
к текущей ;)
в apply-templates можно передавать субноды (у меня на этом построено очень удобное однообразие вызовов во вложенных шаблонах — позволяет меньше ошибаться и больше оправданной копипасты использовать) и можно передавать внешние документы.
Многократно использовать at проблем так же нет.
Единственно для чего действительно нужен xsl:call-template, это для рекурсивных вызовов шаблонов с передачей параметров xsl:with-param. Я считаю, что само наличие call-template довольно сильно навредило XSLT, вместо коротких удобных шаблонов пишутся громоздкие, которые сразу отпугивают новичков, прививая иммунитет против дальнейшего использования XSLT. Вместо <xsl:call-template name="name"/> можно вполне использовать <xsl:apply-templates select="." mode="name"/>. Хотя вот автор топика не согласен с моим мнением, и вполне себе использует call-template.
Хм, а что помешает использовать apply-templates с модом для рекурсивных вызовов?) Мне все же кажется, что они сильно взаимозаменяемы в плане передачи параметров/нод и ключевая разница только в возможности с at ловить одним вызовом разные шаблоны — матчем по предикатам. Сам я этой штукой пользуюсь не слишком часто, т.к. без значительной разницы между разными состояниями нод предпочитаю думать методами DRY — один xsl:choose или xsl:if лучше, чем копия шаблона.
apply-template наиболее читабельнее выглядит в этом случае, имхо
вредные советы, какие-то в статье

1. структура файлов хаотичная. логику создания директорий так и не уловил.

2. накладывание трансформация кучи маленьких xml, и склеивание их вместе через промежуточную сериализацию в html — это медленно, не удобно и попросту багоёмко. нормальная практика — сформировать 1 xml, потом его трансформировать за один запуск xslt.

3. именованные шаблоны нельзя перегружать. какой смысл использовать xslt и не использовать его основную фишку — выбор шаблона на основе данных?

4. вместо «справочника» надо использовать ключи. они именно для этого и предназначены и именно для этого оптимизированы.

5. огульное использование disable-output-escaping — потенциальная дырень в безопасности. использовать его нужно там, где без него никак. в данном же случае он нахрен не нужен.

по обсуждению

1. развели флейма как вставить скрипты в html. считайте, что xslt — это перила, которые не дают вам упасть в говнокод.

2. xslt конечно громоздок. и все это понимают. но альтернатив-то особо и нет. если это так уж сильно напрягает — могу выложить доведённую до ума вот эту либу: www.php.ru/forum/viewtopic.php?f=27&t=27236

> 1. развели флейма как вставить скрипты в html. считайте, что xslt — это перила, которые не дают вам упасть в говнокод.

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

Тег скрипт в xslt нужно вставлять порой для передачи данных из шаблона в JS.
Например, инициализировать какую-то либу данными, приходящими в шаблоне.
Кстати говоря, счётчики яндекс.метрики и гугл аналатикса как раз являются таким кодом, вставляляемым по настоянию яндекса или гугла именно в шаблон. А флеймите скорее вы сами :)

Я тоже писал «smarty для xslt», сокращающий синтаксис, да и другие здешние комментаторы писали, так что удивительного в этом ничего нет.
Sign up to leave a comment.

Articles