2009-08-05 24 views
14

Non so se è possibile, ma mi chiedo come si fa ...Come chiamare i modelli nominati in base a una variabile?

Diciamo che abbiamo la seguente XSL:

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

E 'possibile cambiare il XSL per leggere qualcosa di simile ...

<xsl:template match="/"> 
    <xsl:call-template name="$templateName"/> 
</xsl:template> 

risposta

6

No, questo è impossibile non direttamente possibile. La convenzione di chiamata è:

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

Dove un QName is defined as:

QName ::= PrefixedName | UnprefixedName 

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

Prefix   ::= NCName 
LocalPart  ::= NCName 

In pratica questo si riduce a "personaggi soli, senza espressioni". Come evidenziano le altre risposte, ci sono in effetti modi per fare qualcosa di equivalente, ma l'approccio diretto/approccio ingenuo non funzionerà.

+0

Ah, ma c'è un brutto trucco per aggirare questo problema - vedi la mia risposta. –

+0

@Tomalak Questo è stato possibile (anche se in una diversa forma sintattica) per quasi 8 anni :) Vedi la mia risposta per i dettagli. –

11

Non è possibile esattamente come descrivi, ma se vuoi essere in grado di scegliere un modello in fase di esecuzione in base ad un valore che hai impostato altrove, c'è un trucco per farlo. L'idea è di fare in modo che il modello nominato corrisponda a un nodo con un nome corrispondente in una modalità distinta (in modo da non rovinare la normale trasformazione), e quindi abbinarlo. Per esempio:

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

noti che è possibile utilizzare in <xsl:with-param><xsl:apply-templates>, in modo da poter fare tutto con questo che si potrebbe fare con una pianura <xsl:call-template>.

Inoltre, il codice di cui sopra è leggermente più lungo di quanto potrebbe essere necessario perché cerca di evitare l'uso di estensioni XSLT. Se il processore supporta exslt:node-set(), è possibile generare direttamente i nodi utilizzando <xsl:element> e utilizzare node-set() per convertire il frammento di albero risultante in un nodo normale in modo che corrisponda, senza la necessità di document('') hack.

Per ulteriori informazioni, vedere FXSL - è una libreria di programmazione funzionale per XSLT basata su questo concetto.

2

Aggiornamento: I link qui sotto sono stati aggiornati per puntare a web.archive.org - purtroppo, IDEAlliance ha fatto tutti Exteme linguaggi di markup atti di convegni disponibile ... A tempo debito, troverò un altro luogo permanente per questi due articoli.


Questo è implementato in FXSL.

Ci sono buone spiegazioni dei principi principali di FXSL.

Vedi le seguenti due articoli:

"Programmazione funzionale in XSLT utilizzando la libreria FXSL" (per XSLT 1.0), (PDF) a:

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

(HTML) a:

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



"programmazione funzionale di ordine superiore con XSLT 2.0 e FXSL (PDF):

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

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



Utilizzando FXSL sono stato in grado di risolvere in modo semplice e elegantemente molti problemi, che sembrano "impossibili per XSLT". Si possono trovare molti esempi here.

+0

Bentornato. :) – Tomalak

+0

Sfortunatamente, entrambi i link non funzionano, puoi ricontrollarli? Forse sono legati a una sessione valida o qualcosa del genere, continuo a ricevere errori "Pagina non trovata". – Tomalak

+0

@Tomalak: Grazie per avermelo fatto sapere. Indagherò C'è qualcosa di strano stamattina: facebook è inaccessibile e twitter sembra violato ... –

2

Penso di avere più o meno lo stesso problema di te. Avevo un modello "esterno" e volevo chiamare un diverso modello "interno" a seconda di alcune variabili impostate in fase di esecuzione. Ho trovato la tua domanda su Google per un modo per avere una dinamica <xsl:call-template>. L'ho risolto usando <xsl:apply-templates> invece, come segue.

L'XML di input (generato a run-time) contiene qualcosa sulla falsariga di:

<template name="template_name_1"/> 

Il XSL nel modello "esterno" ha:

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

(Il select="template" in questo apply-templates si riferisce al tag <template> nell'XML di input)

E infine "interno" modello, che ho voluto inserire come conseguenza del valore dell'attributo name nel mio XML, si presenta come:

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

(Anche in questo caso, il match="template[@name='xyz']" si riferisce alla precedente select="template" e, a sua volta al tag <template> e il suo attributo name nell'input XML)

In questo modo posso avere un template "chiamato" dinamicamente semplicemente controllato dal mio input XML.

Questo potrebbe non essere lo stesso problema che stai cercando di risolvere, ma penso che sia abbastanza vicino, e molto più semplice delle soluzioni FSXL menzionate altrove in questa pagina.

3

Per riferimento futuro di nessuno:

Ecco un esempio di lavoro in base alla risposta di Pavel Minaev. Nessun pensiero originale da parte mia. ;-) L'ho cambiato per usare msxml: node-set come ha descritto (più o meno) in modo che funzioni in .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> 
0

Che dire di questo?:

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

È possibile semplificare una "chiamata" del modello utilizzando una variabile allo stesso modo come descritto in un precedente contributo:

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

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

noti che opzionale <xsl:with-param> può essere usato come al solito.

Problemi correlati