J'aime votre question. Vous vous exprimez très bien sur ce que vous ne comprenez pas encore. Vous avez juste besoin de quelque chose pour relier les choses ensemble. Je vous recommande de lire "Comment fonctionne XSLT" un chapitre que j'ai écrit pour répondre exactement aux questions que vous posez. J'aimerais savoir si cela vous permet de faire le point.
De manière moins formelle, je vais tenter de répondre à chacune de vos questions.
- Dans quel ordre les modèles s'exécutent-ils, et
- Lorsqu'ils s'exécutent, correspondent-ils (a) au XML source d'origine ou (b) à la sortie actuelle du XSLT pour le transformer ? la sortie actuelle du XSLT à ce stade ? ce point ?
À n'importe quel moment du traitement XSLT, il y a, en quelque sorte, deux contextes, que vous identifiez comme (a) et (b) : où vous êtes dans le arbre source et où vous vous trouvez dans le arbre des résultats . L'endroit où vous vous trouvez dans l'arbre des sources s'appelle le noeud actuel . Il peut changer et sauter tout autour de l'arbre source, car vous choisissez des ensembles arbitraires de nœuds à traiter à l'aide de XPath. Cependant, d'un point de vue conceptuel, on ne "saute" jamais autour de l'arbre des résultats de la même manière. Le processeur XSLT le construit de manière ordonnée ; il crée d'abord le nœud racine de l'arbre de résultat ; puis il ajoute des enfants, construisant le résultat dans l'ordre du document (profondeur d'abord). [Votre post me motive à reprendre mes expériences de visualisation logicielle pour XSLT...].
L'ordre des règles du modèle dans une feuille de style n'a jamais d'importance. Vous ne pouvez pas savoir, juste en regardant la feuille de style, dans quel ordre les règles du modèle seront instanciées, combien de fois une règle sera instanciée, ou même si elle le sera tout court. ( match="/"
est une exception ; on peut toujours savoir qu'elle sera déclenchée).
Je suppose que le modèle n°1 sera s'exécutera en premier. Je ne sais pas pourquoi je suppose cela -- est-ce juste parce qu'il apparaît en premier dans le document ?
Non. Il sera appelé en premier même si vous le placez en dernier dans le document. L'ordre des règles de gabarit n'a jamais d'importance (sauf en cas d'erreur lorsque plusieurs règles de gabarit avec la même priorité correspondent au même noeud ; même dans ce cas, c'est facultatif pour l'implémenteur et vous ne devriez jamais compter sur un tel comportement). Elle est appelée en premier parce que la première chose que toujours se produit chaque fois que vous exécutez un processeur XSLT est un appel virtuel à <xsl:apply-templates select="/"/>
. L'appel virtuel unique construit l'arbre de résultat entier. Rien ne se passe en dehors de celui-ci. Vous pouvez personnaliser, ou "configurer", le comportement de cette instruction en définissant des règles de modèle.
Le modèle n°2 sera-t-il exécuté ? Il correspond à un nœud dans le XML source, mais le temps que l'on arrive à ce modèle (en supposant qu'il s'exécute en second), le noeud "firstName" ne sera pas dans l'arbre de sortie.
Le modèle n° 2 (ni aucune autre règle de modèle) ne sera jamais déclenché à moins que vous n'ayez une règle de type <xsl:apply-templates/>
quelque part dans le match="/"
règle. Si vous n'en avez pas, alors aucune règle de modèle autre que match="/"
sera déclenché. Pensez-y de cette façon : pour qu'une règle de modèle soit déclenchée, elle ne peut pas simplement correspondre à un nœud de l'entrée. Elle doit correspondre à un nœud que vous avez choisi de faire correspondre à la règle de modèle. processus (en utilisant <xsl:apply-templates/>
). Inversement, il continuera à faire correspondre le nœud autant de fois que vous choisirez de le traiter.
Est-ce que [le match="/"
modèle] empêchent tous les autres modèles de s'exécuter puisqu'il n'y a rien à faire correspondre après que le premier modèle est terminé ?
Cette règle prévaut sur les autres en n'incluant nulle part <xsl:apply-templates/>
en elle. Il y a encore beaucoup de noeuds qui pourrait être traitées dans l'arbre source. Ils sont toujours là, mûrs pour la cueillette ; traitez chacun d'eux autant de fois que vous le souhaitez. Mais la seule façon de les traiter en utilisant des règles de modèle est d'appeler <xsl:apply-templates/>
.
Jusqu'à présent, j'ai été préoccupé avec les modèles ultérieurs ne s'exécutant pas parce que les noeuds sur lesquels ils ont opéré n'apparaissent pas dans la sortie, mais mais qu'en est-il de l'inverse ? Est-ce qu'un modèle modèle "antérieur" peut-il créer un nœud sur lequel un modèle "ultérieur" peut faire quelque chose avec ?
Ce n'est pas qu'un modèle "antérieur" crée un nouveau nœud à traiter ; c'est qu'un modèle "antérieur" traite à son tour d'autres nœuds de l'arbre source, en utilisant cette même instruction ( <xsl:apply-templates
). On peut considérer qu'il s'agit d'appeler la même "fonction" de manière récursive, avec des paramètres différents à chaque fois (les nœuds à traiter, déterminés par le contexte et l'attribut select
).
Au final, vous obtenez une pile arborescente d'appels récursifs à la même "fonction" ( <xsl:apply-templates>
). Et cette arborescence est isomorphique à votre résultat réel. Tout le monde ne s'en rend pas compte ou n'y a pas pensé de cette façon ; c'est parce que nous ne disposons pas d'outils de visualisation efficaces... pour l'instant.
Le modèle #1 crée un nouveau noeud appelé "nom complet". Le modèle n°2 correspond à ce même noeud. Le modèle n°2 sera-t-il exécuté parce que le nœud "fullName" existe existe dans la sortie au moment où nous que nous arrivions au modèle n°2 ?
Non. La seule façon de faire une chaîne de traitement est de la configurer explicitement de cette façon. Créez une variable, par exemple $tempTree
qui contient la nouvelle <fullName>
et ensuite traiter il comme ceci <xsl:apply-templates select="$tempTree">
. Pour faire cela dans XSLT 1.0, vous devez envelopper la référence de la variable avec une fonction d'extension (par exemple, exsl:node-set()
), mais dans XSLT 2.0, il fonctionnera tel quel.
Que vous traitiez les nœuds de l'arbre source d'origine ou d'un arbre temporaire que vous construisez, dans tous les cas, vous devez indiquer explicitement les nœuds que vous souhaitez traiter.
Ce que nous n'avons pas couvert, c'est la façon dont le XSLT obtient tous ses comportements implicites. Vous devez également comprendre le règles de modèles intégrés . J'écris constamment des feuilles de style qui n'incluent même pas une règle explicite pour le nœud racine ( match="/"
). Au lieu de cela, je m'appuie sur la règle intégrée pour les nœuds Root (appliquer les modèles aux enfants), qui est la même que la règle intégrée pour les nœuds d'éléments. Ainsi, je peux ignorer une grande partie de l'entrée, laisser le processeur XSLT la parcourir automatiquement, et ne faire quelque chose de spécial que lorsqu'il rencontre un noeud qui m'intéresse. Je peux aussi écrire une seule règle qui copie tout de manière récursive (appelée la transformation d'identité), en ne la remplaçant qu'en cas de besoin, pour apporter des modifications progressives à l'entrée. Après avoir lu "How XSLT Works", votre prochaine tâche consistera à rechercher la "identity transform".
Je réalise que je suis profondément ignorant sur le "zen" de XSLT. Jusqu'à présent, mes feuilles de style ont consisté en un modèle correspondant au nœud Root, puis sont complètement procédurales à partir de là. J'en ai assez de faire ça. Je préférerais plutôt comprendre correctement XSLT correctement, d'où ma question.
Je vous applaudis. Maintenant il est temps de prendre la "pilule rouge" : lire "Comment fonctionne XSLT"