В чем разница между call-template и apply-templates в XSL?

119

Я новичок в XSLT, поэтому меня немного смущают два тега,

<xsl:apply-templates name="nodes">

и

<xsl:call-template select="nodes"> 

Можете ли вы перечислить разницу между ними?

Venkat
источник

Ответы:

167

<xsl:call-template> является близким эквивалентом вызова функции на традиционном языке программирования.

Вы можете определять функции в XSLT, например эту простую, которая выводит строку.

<xsl:template name="dosomething">
  <xsl:text>A function that does something</xsl:text>
</xsl:template>

Эту функцию можно вызвать через <xsl:call-template name="dosomething">.

<xsl:apply-templates>немного отличается, и в этом заключается реальная сила XSLT: он принимает любое количество узлов XML (независимо от того, что вы определяете в selectатрибуте), выполняет их итерацию ( это важно: apply-templates работает как цикл! ) и находит подходящие шаблоны для них:

<!-- sample XML snippet -->
<xml>
  <foo /><bar /><baz />
</xml>

<!-- sample XSLT snippet -->
<xsl:template match="xml">
  <xsl:apply-templates select="*" /> <!-- three nodes selected here -->
</xsl:template>

<xsl:template match="foo"> <!-- will be called once -->
  <xsl:text>foo element encountered</xsl:text>
</xsl:template>

<xsl:template match="*"> <!-- will be called twice -->
  <xsl:text>other element countered</xsl:text>
</xsl:template>

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

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

Вы можете больше сконцентрироваться на разработке шаблонов и меньше времени уделять «сантехнике». Ваши программы станут более мощными и модульными, менее глубоко вложенными и более быстрыми (поскольку процессоры XSLT оптимизированы для сопоставления шаблонов).

С XSLT следует понимать концепцию «текущего узла». С <xsl:apply-templates>текущим узлом переходит к каждой итерации, <xsl:call-template>при этом текущий узел не изменяется. Т.е. .внутри вызываемого шаблона относится к тому же узлу, что и .в вызывающем шаблоне. Это не относится к шаблонам приложений.

Это основная разница. Есть и другие аспекты шаблонов, которые влияют на их поведение: их modeи priority, тот факт, что шаблоны могут иметь как a, так nameи match. Это также влияет на то, был ли шаблон импортирован ( <xsl:import>) или нет. Это сложные варианты использования, и вы сможете с ними справиться, когда доберетесь до них.

Томалак
источник
5
@Tomalak: Хороший ответ! Однако утверждение: «xsl: apply-templates - это цикл» неверно. Ни в одной официальной спецификации W3C нет указания, что <xsl:apply-templates>должна быть реализована как цикл - наоборот, он может быть реализован параллельно, потому что разные приложения на разных узлах списка узлов абсолютно независимы друг от друга.
Димитр Новачев
8
@Dimitre: То, что я хотел сказать: с точки зрения конечного пользователя <xsl:apply-templates>ведет себя как цикл. Различия в реализации на стороне XSLT-процессора не повлияют на меня как на XSLT-программиста, результат абсолютно одинаков как для параллельных, так и для итеративных реализаций. Но для новичка в XSLT с императивным фоном это помогает представить себе <xsl:apply-templates>как бы своего рода цикл для каждого, даже если - технически - это не так.
Tomalak
@Tomalak: Хотя это может быть полезно для начинающих программистов XSLT, я думаю, что это часто вводит их в заблуждение, поскольку они думают, что могут повторно использовать информацию о состоянии, накопленную при «выполнении цикла».
Dimitre Novatchev
@Tomalak: Исходя из этих фактов, я думаю, что было бы уместно изменить «xsl: apply-templates is a loop» на что-нибудь вроде: «xsl: apply-templates похожи на цикл»
Димитр Новачев,
@Tomalak: Цикл - это итерация, а что-то apply-templatesи call-templateинструкции не для этого. Это механизм рекурсии в XSLT. И, как ответил Димитр, шаблоны приложений - это полиморфизм или механизм, управляемый данными.
15

Чтобы добавить к хорошему ответу @Tomalak:

Вот некоторые не упомянутые и важные отличия :

  1. xsl:apply-templatesнамного богаче и глубже, чем xsl:call-templatesи даже от xsl:for-each, просто потому , что мы не знаем, какой код будет применен к узлам выборки - в общем случае этот код будет отличаться для разных узлов списка узлов.

  2. Код, который будет применяться, может быть написан после того, как xsl:apply templateбыл написан s, и людьми, которые не знают первоначального автора.

Библиотека FXSL «s реализация функций высшего порядка (Хоф) в XSLT не было бы возможно , если XSLT не было <xsl:apply-templates>инструкции.

Резюме : Шаблоны и <xsl:apply-templates>инструкции - это то, как XSLT реализует полиморфизм и работает с ним.

Ссылка : См. Всю эту ветку: http://www.biglist.com/lists/lists.mulberrytech.com/xsl-list/archives/200411/msg00546.html

Димитр Новачев
источник
8

xsl:apply-templatesобычно (но не обязательно) используется для обработки всех или подмножества дочерних элементов текущего узла со всеми применимыми шаблонами. Это поддерживает рекурсивность приложения XSLT, которая соответствует (возможной) рекурсивности обрабатываемого XML.

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

Поэтому я использую, xsl:apply-templatesесли хочу перехватить обработку интересного узла и (обычно) что-то ввести в выходной поток. Типичный (упрощенный) пример:

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

тогда как с xsl:call-templateя обычно решаю такие проблемы, как добавление текста некоторых подузлов вместе, преобразование выбранных наборов узлов в текст или другие наборы узлов и т.п. - все, для чего вы бы написали специализированную функцию многократного использования.

Редактировать:

В качестве дополнительного примечания к тексту вашего конкретного вопроса:

<xsl:call-template name="nodes"/> 

Это вызывает шаблон с именем «узлы»:

    <xsl:template name="nodes">...</xsl:template>

Это другая семантика, чем:

<xsl:apply-templates select="nodes"/>

... который применяет все шаблоны ко всем дочерним элементам вашего текущего узла XML, имя которого - «узлы».

TToni
источник
2

Функциональность действительно похожа (кроме семантики вызова, где call-templateтребуется nameатрибут и соответствующий шаблон имен).

Однако парсер не будет работать таким же образом.

Из MSDN :

В отличие от <xsl:apply-templates>, <xsl:call-template>не изменяет текущий узел или текущий список узлов.

Одед
источник