Quais são as diferenças entre 'call-template' e 'apply-templates' no XSL?

119

Eu sou novo em XSLT, então estou um pouco confuso sobre as duas tags,

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

e

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

Então você pode listar a diferença entre eles?

Venkat
fonte

Respostas:

167

<xsl:call-template> é quase o equivalente a chamar uma função em uma linguagem de programação tradicional.

Você pode definir funções em XSLT, como este simples que produz uma string.

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

Esta função pode ser chamada via <xsl:call-template name="dosomething">.

<xsl:apply-templates>é um pouco diferente e nele está o verdadeiro poder do XSLT: ele pega qualquer número de nós XML (o que quer que você defina no selectatributo), os itera ( isso é importante: o apply-templates funciona como um loop! ) e encontra os modelos correspondentes para eles:

<!-- 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>

Dessa forma, você cede um pouco de controle ao processador XSLT - não você decide para onde o fluxo do programa vai, mas o processador o faz encontrando a correspondência mais apropriada para o nó que está processando no momento.

Se vários modelos podem corresponder a um nó, aquele com a expressão de correspondência mais específica vence. Se houver mais de um modelo correspondente com a mesma especificidade, o declarado por último vence.

Você pode se concentrar mais no desenvolvimento de modelos e precisa de menos tempo para fazer o "encanamento". Seus programas se tornarão mais poderosos e modularizados, menos profundamente aninhados e mais rápidos (pois os processadores XSLT são otimizados para correspondência de modelos).

Um conceito a ser entendido com XSLT é o de "nó atual". Com <xsl:apply-templates>o nó atual, segue em frente com cada iteração, enquanto <xsl:call-template>não muda o nó atual. Ou seja, .dentro de um modelo chamado refere-se ao mesmo nó .do modelo de chamada. Este não é o caso com os modelos de aplicação.

Essa é a diferença básica. Existem alguns outros aspectos dos modelos que afetam seu comportamento: Seu modee priority, o fato de que os modelos podem ter tanto a namequanto a match. Também tem um impacto se o modelo foi importado ( <xsl:import>) ou não. Esses são usos avançados e você poderá lidar com eles quando chegar lá.

Tomalak
fonte
5
@Tomalak: Boa resposta! No entanto, a declaração: "xsl: apply-templates é um loop" não está correta. Não há nenhuma indicação em qualquer especificação oficial do W3C que <xsl:apply-templates>deva ser implementada como um loop - pelo contrário, ela pode ser implementada em paralelo, porque as diferentes aplicações nos diferentes nós da lista de nós são absolutamente independentes umas das outras.
Dimitre Novatchev
8
@Dimitre: O que eu quis dizer: da perspectiva do usuário final, <xsl:apply-templates>se comporta como um loop. As diferenças de implementação na extremidade do processador XSLT não me afetarão como um programador XSLT, o resultado é absolutamente o mesmo para implementações paralelizadas e iterativas. Mas, para um novato em XSLT com um histórico imperativo, é útil imaginar <xsl:apply-templates>como uma espécie de loop for-each, mesmo que - tecnicamente - não seja.
Tomalak
@Tomalak: Embora isso possa ser útil para programadores XSLT novatos, acho que muitas vezes é enganoso para eles, pois eles pensam que podem reutilizar informações de estado acumuladas na "execução do loop".
Dimitre Novatchev
@Tomalak: Por causa desses fatos, acho que seria apropriado modificar "xsl: apply-templates é um loop" com algo como: "xsl: apply-templates é como um loop"
Dimitre Novatchev
@Tomalak: Loop é iteração, algo apply-templatese as call-templateinstruções não são para. Eles são o mecanismo de recursão em XSLT. E como Dimitre respondeu, aplicar modelos é o polimorfismo ou mecanismo dirigido por dados.
15

Para adicionar à boa resposta de @Tomalak:

Aqui estão algumas diferenças importantes e não mencionadas :

  1. xsl:apply-templatesé muito mais rico e profundo do que xsl:call-templatese até mesmo de xsl:for-each, simplesmente porque não sabemos qual código será aplicado nos nós da seleção - no caso geral, esse código será diferente para nós diferentes da lista de nós.

  2. O código que será aplicado pode ser escrito bem depois que o xsl:apply templates foi escrito e por pessoas que não conhecem o autor original.

A implementação da biblioteca FXSL de funções de ordem superior (HOF) em XSLT não seria possível se XSLT não tivesse a <xsl:apply-templates>instrução.

Resumo : os modelos e a <xsl:apply-templates>instrução são como o XSLT implementa e lida com o polimorfismo.

Referência : Veja este tópico completo: http://www.biglist.com/lists/lists.mulberrytech.com/xsl-list/archives/200411/msg00546.html

Dimitre Novatchev
fonte
8

xsl:apply-templatesé geralmente (mas não necessariamente) usado para processar todos ou um subconjunto de filhos do nó atual com todos os modelos aplicáveis. Isso suporta a recursividade do aplicativo XSLT que está correspondendo à (possível) recursividade do XML processado.

xsl:call-templatepor outro lado, é muito mais parecido com uma chamada de função normal. Você executa exatamente um modelo (nomeado), geralmente com um ou mais parâmetros.

Então, eu uso xsl:apply-templatesse quero interceptar o processamento de um nó interessante e (geralmente) injetar algo no fluxo de saída. Um exemplo típico (simplificado) seria

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

enquanto com xsl:call-templateeu normalmente resolvo problemas como adicionar o texto de alguns subnós juntos, transformar conjuntos de nós selecionados em texto ou outros conjuntos de nós e semelhantes - qualquer coisa para a qual você escreveria uma função especializada reutilizável.

Editar:

Como uma observação adicional ao texto de sua pergunta específica:

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

Isso chama um modelo chamado 'nós':

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

Esta é uma semântica diferente de:

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

... que aplica todos os modelos a todos os filhos de seu nó XML atual cujo nome é 'nós'.

TToni
fonte
2

A funcionalidade é de fato semelhante (além da semântica de chamada, onde call-templaterequer um nameatributo e um modelo de nomes correspondente).

No entanto, o analisador não será executado da mesma maneira.

Do MSDN :

Ao contrário <xsl:apply-templates>, <xsl:call-template>não altera o nó atual ou a lista de nós atual.

Oded
fonte