Question

Je ne sais pas si c'est possible, mais je me demande comment faire...

Disons que nous avons le XSL suivant :

<xsl:template name="foo">
  Bla bla bla
</xsl:template>
...
<xsl:template name="bar">
  Bla bla bla
</xsl:template>
...
<xsl:template match="/">
  <xsl:if test="$templateName='foo'">
    <xsl:call-template name="foo"/>
  </xsl:if>
  <xsl:if test="$templateName='bar'">
    <xsl:call-template name="bar"/>
  </xsl:if>
</xsl:template>

Est-il possible de changer le XSL pour lire quelque chose comme...

<xsl:template match="/">
  <xsl:call-template name="$templateName"/>
</xsl:template>
Était-ce utile?

La solution

Non, ceci est impossible pas directement possible. La convention d'appel est la suivante:

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

Où un QName est défini comme :

QName ::= PrefixedName | UnprefixedName

PrefixedName   ::= Prefix ':' LocalPart
UnprefixedName ::= LocalPart

Prefix         ::= NCName
LocalPart      ::= NCName

En gros, cela se résume à & "; caractères; pas d'expressions &";; Comme le soulignent les autres réponses, il existe des moyens de faire quelque chose d’équivalent, mais l’approche directe / na & # 239; aucune approche ne fonctionnera.

Autres conseils

Ce n'est pas possible exactement comme vous le décrivez, mais si vous voulez pouvoir choisir un modèle au moment de l'exécution en fonction de la valeur que vous avez définie ailleurs, il existe un truc pour le faire. L'idée est de faire en sorte que votre modèle nommé corresponde également à un nœud avec un nom correspondant dans un mode distinct (afin qu'il ne gâche pas votre transformation normale), puis qu'il corresponde. Par exemple:

<xsl:stylesheet ... xmlns:t="urn:templates">

  <!-- Any compliant XSLT processor must allow and ignore any elements 
       not from XSLT namespace that are immediate children of root element -->
  <t:templates>
    <t:foo/>
    <t:bar/>
  </t:templates>

  <!-- document('') is the executing XSLT stylesheet -->     
  <xsl:variable name="templates" select="document('')//t:templates" />

  <xsl:template name="foo" match="t:foo" mode="call-template">
    Bla bla bla
  </xsl:template>

  <xsl:template name="bar" match="t:foo" mode="call-template">
    Bla bla bla
  </xsl:template>

  <xsl:template match="/">
    <xsl:variable name="template-name" select="..." />
    <xsl:apply-templates select="$templates/t:*[local-name() = $template-name]"
                         mode="call-template"/>
  </xsl:template>

Notez que vous pouvez utiliser <xsl:with-param> dans <xsl:apply-templates> pour pouvoir tout faire avec ce que vous pourriez faire avec un texte simple <xsl:call-template>.

En outre, le code ci-dessus est un peu plus long que vous n’auriez peut-être besoin du fait qu’il évite d’utiliser des extensions XSLT. Si votre processeur prend en charge exslt:node-set(), vous pouvez simplement générer des nœuds directement à l'aide de <xsl:element> et utiliser node-set() pour convertir le fragment d'arborescence obtenu en un nœud en clair, sans qu'il soit besoin de document('') bidouiller.

Pour plus d'informations, voir FXSL , une bibliothèque de programmation fonctionnelle. pour XSLT qui repose sur ce concept.

Pour toute référence future:

Voici un exemple de travail basé sur la réponse de Pavel Minaev. Aucune pensée originale de ma part. ;-) Je l'ai commuté pour utiliser msxml: node-set comme il l'a décrit (plus ou moins) afin que cela fonctionne dans .NET.

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" version="1.0">
    <xsl:variable name="templates">
        <templates>
            <foo />
            <bar />
        </templates>
    </xsl:variable>
    <xsl:template name="foo" match="foo" mode="call-template">
        <FooElement />
    </xsl:template>
    <xsl:template name="bar" match="bar" mode="call-template">
        <BarElement />
    </xsl:template>
    <xsl:template match="/">
        <Root>
            <xsl:variable name="template-name">bar</xsl:variable> <!-- Change this to foo to get the other template. -->
            <xsl:apply-templates select="msxsl:node-set($templates)/*/*[local-name() = $template-name]" mode="call-template" />
        </Root>
    </xsl:template>
</xsl:stylesheet>

Mise à jour:Les liens ci-dessous ont été mis à jour pour pointer vers web.archive.org -- malheureusement, IDEALLIANCE a tout fait Langages de balisage extrêmes actes de conférence indisponibles...Le moment venu, je trouverai une place plus permanente pour ces deux articles.


Ceci est mis en œuvre dans FXSL.

Il existe de bonnes explications sur les grands principes de FXSL.

Voir les deux articles suivants :

"Programmation fonctionnelle en XSLT à l'aide de la bibliothèque FXSL" (pour XSLT 1.0), (PDF) à l'adresse :

http://web.archive.org/web/20070710091236/http://www.idealliance.org/papers/extreme/proceedings/xslfo-pdf/2003/Novatchev01/EML2003Novatchev01.pdf

(HTML) à :

http://conferences.idealliance.org/extreme/html/2003/Novatchev01/EML2003Novatchev01.html



"Programmation fonctionnelle d'ordre supérieur avec XSLT 2.0 et FXSL" (PDF) à l'adresse :

http://web.archive.org/web/20070222111927/http://www.idealliance.org/papers/extreme/proceedings/xslfo-pdf/2006/Novatchev01/EML2006Novatchev01.pdf

(HTML) à :http://conferences.idealliance.org/extreme/html/2006/Novatchev01/EML2006Novatchev01.html



En utilisant FXSL, j'ai pu résoudre facilement et avec élégance de nombreux problèmes qui semblent "impossibles pour XSLT".On peut trouver beaucoup d'exemples ici.

Je pense avoir eu plus ou moins le même problème que vous. J'ai eu un & Quot; externe & Quot; modèle et souhaitait appeler un autre " inner " modèle dépendant d'une variable définie au moment de l'exécution. J'ai trouvé votre question sur Google pour trouver un moyen d'avoir une dynamique <xsl:call-template>. Je l'ai résolu en utilisant <xsl:apply-templates> à la place, comme suit.

Le XML d'entrée (généré au moment de l'exécution) contient un élément similaire à:

<template name="template_name_1"/>

Le XSL dans le " externe " le modèle a:

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

(le select="template" dans ces apply-templates fait référence à la balise <template> dans le XML d'entrée)

Et enfin, le " intérieur & "; Le modèle que je voulais inclure en raison de la valeur de l'attribut name dans mon code XML ressemble à ceci:

<xsl:template match="template[@name='template_name_1']">
    <!-- XSL / XHTML goes here -->
</xsl:template>

(Encore une fois, le match="template[@name='xyz']" fait référence au précédent <=> puis à la balise <=> et à son attribut <=> dans le XML d'entrée)

De cette manière, je peux avoir dynamiquement & "appelé &"; modèle simplement contrôlé par mon entrée XML.

Ce n'est peut-être pas le même problème que vous essayez de résoudre, mais je pense que c'est assez proche et beaucoup plus simple que les solutions FSXL mentionnées ailleurs dans cette page.

Qu'en est-il de celui-ci?:

  <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

      <xsl:template match="xsl:template[@name='foo']" name="foo">
    Bla bla bla foo
      </xsl:template>

      <xsl:template match="xsl:template[@name='bar']" name="bar">
    Bla bla bla bar
      </xsl:template>

      <xsl:template match="/">
        <xsl:variable name="templateName" select="'bar'"/>
        <xsl:apply-templates select="document('')/*/xsl:template[@name=$templateName]"/>
        <xsl:apply-templates select="document('')/*/xsl:template[@name='foo']"/>
      </xsl:template>

    </xsl:stylesheet>

Vous pouvez simplifier un " appel " du modèle en utilisant une variable similaire à celle décrite dans une contribution précédente:

<xsl:variable name="templates" select="document('')/*/xsl:template"/> 

<xsl:apply-templates select="$templates[@name=$templateName]"/>
<xsl:apply-templates select="$templates[@name='foo']"/>

Notez que l'option <xsl:with-param> peut être utilisée normalement.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top