Quelles sont les différences entre 'call-template' et 'apply-templates' en XSL?

119

Je suis nouveau dans XSLT donc je suis un peu confus au sujet des deux balises,

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

et

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

Alors, pouvez-vous énumérer la différence entre eux?

Venkat
la source

Réponses:

167

<xsl:call-template> est un équivalent proche de l'appel d'une fonction dans un langage de programmation traditionnel.

Vous pouvez définir des fonctions dans XSLT, comme celle-ci simple qui génère une chaîne.

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

Cette fonction peut être appelée via <xsl:call-template name="dosomething">.

<xsl:apply-templates>est un peu différent et c'est la vraie puissance de XSLT: il prend n'importe quel nombre de nœuds XML (quoi que vous définissiez dans l' selectattribut), les itère ( c'est important: apply-templates fonctionne comme une boucle! ) et trouve les modèles correspondants pour eux:

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

De cette façon, vous abandonnez un peu de contrôle au processeur XSLT - ce n'est pas vous qui décidez où va le flux du programme, mais le processeur le fait en trouvant la correspondance la plus appropriée pour le nœud qu'il traite actuellement.

Si plusieurs modèles peuvent correspondre à un nœud, celui avec l'expression de correspondance la plus spécifique l'emporte. S'il existe plus d'un modèle correspondant avec la même spécificité, celui déclaré en dernier l'emporte.

Vous pouvez vous concentrer davantage sur le développement de modèles et avoir besoin de moins de temps pour faire de la «plomberie». Vos programmes deviendront plus puissants et modulaires, moins profondément imbriqués et plus rapides (car les processeurs XSLT sont optimisés pour la correspondance de modèles).

Un concept à comprendre avec XSLT est celui du "nœud actuel". Avec <xsl:apply-templates>le noeud courant se déplace à chaque itération, alors que <xsl:call-template>ne change pas le noeud courant. C'est-à-dire que le .dans un modèle appelé fait référence au même nœud que le .dans le modèle appelant. Ce n'est pas le cas avec apply-templates.

C'est la différence fondamentale. Il y a d'autres aspects des modèles qui affectent leur comportement: Leur modeet priority, le fait que les modèles peuvent avoir à la fois un nameet un match. Cela a également un impact si le modèle a été importé ( <xsl:import>) ou non. Ce sont des utilisations avancées et vous pouvez les gérer lorsque vous y arrivez.

Tomalak
la source
5
@Tomalak: Bonne réponse! Cependant, l'instruction: "xsl: apply-templates est une boucle" n'est pas correcte. Il n'y a aucune indication dans aucune spécification officielle du W3C qui <xsl:apply-templates>doit être implémentée en boucle - au contraire, elle peut être implémentée en parallèle, car les différentes applications sur les différents nœuds de la liste de nœuds sont absolument indépendantes les unes des autres.
Dimitre Novatchev
8
@Dimitre: Ce que je voulais dire: Du point de vue de l'utilisateur final, <xsl:apply-templates>se comporte comme une boucle. Les différences d'implémentation du côté du processeur XSLT ne m'affecteront pas en tant que programmeur XSLT, le résultat est absolument le même pour les implémentations parallélisées et itératives. Mais pour un débutant XSLT avec un fond impératif, cela aide à envisager <xsl:apply-templates>comme une sorte de boucle for-each, même si - techniquement - ce n'est pas le cas.
Tomalak
@Tomalak: Bien que cela puisse être utile pour les programmeurs XSLT novices, je pense que cela les induit souvent en erreur car ils pensent pouvoir réutiliser les informations d'état accumulées lors de "l'exécution de la boucle".
Dimitre Novatchev
@Tomalak: En raison de ces faits, je pense qu'il serait approprié de modifier "xsl: apply-templates est une boucle" avec quelque chose comme: "xsl: apply-templates est comme une boucle"
Dimitre Novatchev
@Tomalak: Loop est une itération, quelque chose apply-templates et les call-templateinstructions ne sont pas pour. Ils sont le mécanisme de récursivité dans XSLT. Et comme Dimitre a répondu, apply-templates est le polymorphisme ou mécanisme piloté par les données.
15

Pour ajouter à la bonne réponse de @Tomalak:

Voici quelques différences importantes et non mentionnées :

  1. xsl:apply-templatesest beaucoup plus riche et plus profond que xsl:call-templateset même à partir de xsl:for-each, simplement parce que nous ne savons pas quel code sera appliqué sur les nœuds de la sélection - dans le cas général, ce code sera différent pour différents nœuds de la liste de nœuds.

  2. Le code qui sera appliqué peut être écrit bien après l'écriture du xsl:apply templates et par des personnes qui ne connaissent pas l'auteur original.

L' implémentation par la bibliothèque FXSL des fonctions d'ordre supérieur (HOF) dans XSLT ne serait pas possible si XSLT n'avait pas l' <xsl:apply-templates>instruction.

Résumé : Les modèles et les <xsl:apply-templates>instructions expliquent comment XSLT implémente et traite le polymorphisme.

Référence : Voir l'intégralité de ce fil: http://www.biglist.com/lists/lists.mulberrytech.com/xsl-list/archives/200411/msg00546.html

Dimitre Novatchev
la source
8

xsl:apply-templatesest généralement (mais pas nécessairement) utilisé pour traiter tout ou un sous-ensemble des enfants du nœud actuel avec tous les modèles applicables. Cela prend en charge la récursivité de l'application XSLT qui correspond à la (possible) récursivité du XML traité.

xsl:call-templated'autre part, cela ressemble beaucoup plus à un appel de fonction normal. Vous exécutez exactement un modèle (nommé), généralement avec un ou plusieurs paramètres.

J'utilise donc xsl:apply-templatessi je veux intercepter le traitement d'un nœud intéressant et (généralement) injecter quelque chose dans le flux de sortie. Un exemple typique (simplifié) serait

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

alors que xsl:call-templateje résous généralement des problèmes tels que l'ajout du texte de certains sous-nœuds ensemble, la transformation de certains ensembles de nœuds en texte ou d'autres ensembles de nœuds, etc. - tout ce pour quoi vous écririez une fonction spécialisée et réutilisable.

Éditer:

Comme remarque supplémentaire au texte de votre question spécifique:

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

Cela appelle un modèle qui est nommé «nœuds»:

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

C'est une sémantique différente de:

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

... qui applique tous les modèles à tous les enfants de votre nœud XML actuel dont le nom est «nœuds».

TToni
la source
2

La fonctionnalité est en effet similaire (en dehors de la sémantique d'appel, où call-templatenécessite un nameattribut et un modèle de noms correspondant).

Cependant, l'analyseur ne s'exécutera pas de la même manière.

Depuis MSDN :

Contrairement à <xsl:apply-templates>, <xsl:call-template>ne modifie pas le nœud actuel ou la liste de nœuds actuelle.

Oded
la source