Я знаю, что XSLT не работает с процедурной точки зрения, но, к сожалению, я слишком долго занимался процедурными языками. Может ли кто-нибудь помочь мне, объяснив простыми словами, как работают такие вещи, как apply-templates, и помочь таким тупицам, как я, понять это.
Я написал запись в блоге много лет назад, который показывает простую таблицу стилей, написанную в «процедурном» стиле с использованием xsl:for-each
и его эквивалента с использованием xsl:apply-templates
. Это ни в коем случае не исчерпывающее руководство, но, надеюсь, оно будет полезно.
Я не уверен, что согласен с мнением - для каждой структуры много проще! XSLT ребята для понимания, а XSLT уже слишком многие считают вуду (читаемость имеет значение) - но это хорошо написанная часть
Это действительно начинает уменьшать мистицизм, окружающий меня магическими шаблонами. Кроме того, я только что обнаружил, что пошаговое выполнение примеров с использованием Visual Studio (2008) тоже помогло.
Полностью согласен с сообщением в блоге. Подробнее об этом читайте в моем ответе.
Я знаю, что прошло много лет, но ссылка на вашу запись в блоге кажется мертвой. Этот контент еще доступен?
Ага - ты прав, ссылка была мертва. Теперь обновили его на правильный.
Что заставляет вас думать, что процедурные условия здесь не применяются? Просто соглашение о вызовах несколько более неявно, чем вы традиционно ожидали, потому что здесь задействован невидимый контекст. Все, что делает apply-templates
, можно выразить процедурными терминами.
По сути, apply-templates
- это не что иное, как цикл for-each. Начиная с того места, где вы сейчас находитесь в документе (контекст, подумайте «this
»), он перебирает дочерние узлы.
Для каждого дочернего элемента процессор выбирает соответствующий xsl:template
с наивысшим приоритетом (на основе их соответствующих атрибутов match
и priority
), устанавливает контекст для данного дочернего элемента и запускает этот шаблон (подумайте «function
»). После того, как шаблон возвращается, контекст возвращается, и наступает очередь следующего ребенка.
Даже когда что-то становится рекурсивным (чего трудно избежать в XSLT), весь процесс действительно не становится более сложным. «Указатель» контекста перемещается, и вызываются шаблоны.
Вы можете ограничить набор узлов, который выполняет итерация apply-templates
, используя атрибут select
:
<!-- all children of the context node regardless -->
<xsl:apply-templates />
<!-- all children of the context node being "data" with a @name of "Foo" -->
<xsl:apply-templates select = "data[@name='Foo']" />
Вы можете отсортировать набор узлов до итерации, если хотите:
<!-- all children of the context node being "data" with a @name of "Foo",
ordered by their respective "detail" count -->
<xsl:apply-templates select = "data[@name='Foo']">
<xsl:sort select = "count(detail)" data-type = "number" order = "descending"/>
</xsl:apply-templates>
И вы можете передать параметры в свой шаблон, если вам нужно, как и при обычном вызове функции:
<!-- pass in some parameter -->
<xsl:apply-templates select = "data[@name='Foo']">
<xsl:with-param name = "DateSetIcon" select = "$img_src" />
</xsl:apply-templates>
Вот и все, что нужно знать об этом.
Обновлено:
Знаю, что последний комментарий несколько провокационный. Это сделано намеренно, для базового понимания того, как работает apply-templates
, это более или менее. Последствия и возможности, возникающие из-за того, что не ты определяют, какой шаблон вызывать, а позволяют процессору выбрать правильный для вас, конечно, больше, чем то, как это звучит для неподготовленного уха. Декларативный / неявный подход ко всему этому, безусловно, требует некоторого времени, чтобы осваиваться.
«Вот и все» ... Не совсем, см. Мой ответ.
Я полностью согласен с ответом и сообщением в блоге Грега Бича.
Для более подробного сравнения <xsl:for-each>
и <xsl:apply-templates>
см. мой ответ к вопросу «xsl: for-each vs. xsl: apply-templates» в xsl-list и наслаждайтесь целая нить.
«xsl: apply-templates намного богаче и глубже, чем xsl: for-each, даже просто потому, что мы не знаем, какой код будет применен к узлам выбор - в общем случае этот код будет другим для разные узлы списка узлов. Также код, который будет применяться можно написать после того, как были написаны шаблоны xsl: apply и люди, которые не знают первоначального автора».
Еще одно отличие от процедурного языка программирования заключается в том, что порядок, в котором будут применяться шаблоны, не определен заранее. В чистом функциональном языке программирования нет понятия «состояние» или «порядок выполнения».
Ни XSLT 2.0, ни XSLT 1.0 не определяют какой-либо конкретный порядок применения выбранных правил шаблона - только то, что их результаты будут объединены в соответствии с порядком узлов (в отсортированной последовательности, если есть какие-либо директивы <xsl:sort>
или иначе в порядке документа узлы), на которых применяются шаблоны.
«Каждое проверяемое правило шаблона создает в качестве результата последовательность элементов. Результирующие последовательности (по одной для каждого узла в отсортированной последовательности) затем объединяются, чтобы сформировать единую последовательность. Они объединяются, сохраняя порядок узлов в отсортированной последовательности. Окончательная объединенная последовательность формирует результат инструкции xsl: apply-templates»
В спецификации XSLT 1.0 говорится:
"Реализации могут обрабатывать исходный документ любым способом, который дает такой же результат, как если бы он был обработан с использованием этой модели обработки.."
Возможно даже, что реализация XSLT может применять шаблоны (или тело <xsl:for-each>
) параллельно.
Я не вижу, что было бы неправильным в моем ответе. Вы добавляете подробности о порядке выполнения, но для результата преобразования (и всего остального, XSL должен быть свободным от побочных эффектов) порядок выполнения не имеет значения, или нет? Мое «об этом все» может быть провокационным, но что еще?
Tomalak, мой комментарий был: «Вот и все, что есть» ... Не совсем, см. Мой ответ ». Я никогда не говорил, что ваш ответ был неправильным. Проще говоря, <xsl: apply-templates> - это гораздо более обширная тема. Ваше здоровье
Я подумал, что «не совсем» было бы более дружелюбным способом сказать «это неправильно» (обычно это происходит в англоязычном мире).
(И, сложив два и два, я подумал, что голосование против вас было вашим и что в моем ответе должна быть ошибка.)
Эй, я давно не голосовал против! :) Спасибо за напоминание. И нет, я даже не знал (никак не мог это увидеть), что ваш ответ был отклонен. Вы хотите это проверить? Могу прислать вам скриншот моей вкладки "Голоса". Ваше здоровье
Не обязательно, я вам верю! ;-) Все равно ничего страшного. Иногда голоса против могут быть связаны с комментариями типа «Я так не думаю», поэтому это казалось вероятным. Жалко, что голоса против часто идут без объяснения причин.
Да, я думаю, было бы хорошо, если бы SO изменил способ голосования против, сделав объяснение обязательным. Может быть, даже показать идентификатор пользователя, проголосовавшего против.
Это сработает только в том случае, если каждый пользователь будет разумным и справедливым, что можно смело исключить. Многие пользователи переключились бы в режим «око за око» ... К сожалению, кажется, что никто не может придумать работоспособную альтернативу, были сделаны различные предложения по Uservoice, но все они так или иначе были ошибочными.
Полностью согласен с сообщением в блоге Грега Бича. Подробнее об этом читайте в моем ответе.