Altri hanno già spiegato come le variabili sono immutabili - che non ci sono istruzioni di assegnazione in XSLT (come con linguaggi di programmazione puramente funzionali in generale).
Ho un'alternativa alle soluzioni che sono state proposte finora. Evita il passaggio dei parametri (che è verboso e brutto in XSLT - anche io lo ammetterò).
In XPath, si può semplicemente contare il numero di <section>
elementi che precedono quella attuale:
<xsl:template name="section">
<span class="title" id="title-{1 + count(preceding-sibling::section)}">
<xsl:value-of select="title"/>
</span>
</xsl:template>
(Nota: la formattazione del codice spazi non apparirà nel vostro risultato, come spazi bianchi solo i nodi di testo viene rimosso automaticamente dal foglio di stile.)
Un grande vantaggio di questo approccio (al contrario di usare position()
) è che dipende solo dal nodo corrente, non sull'elenco dei nodi corrente. Se in qualche modo hai modificato l'elaborazione (ad esempio, così <xsl:for-each>
elaborava non solo sezioni ma anche qualche altro elemento), il valore di position()
non corrisponderebbe più necessariamente alla posizione degli elementi <section>
nel documento. D'altra parte, se si utilizza count()
come sopra, corrisponderà sempre alla posizione di ciascun elemento <section>
. Questo approccio riduce l'accoppiamento con altre parti del codice, che in genere è una cosa molto buona.
Un'alternativa a count() sarebbe quella di utilizzare l'istruzione <xsl:number>
. E 'il comportamento di default sarà numerare tutti gli elementi come il nome allo stesso livello, che risulta essere ciò che si vuole:
<xsl:template name="section">
<xsl:variable name="count">
<xsl:number/>
</xsl:variable>
<span class="title" id="title-{$count}">
<xsl:value-of select="title"/>
</span>
</xsl:template>
Si tratta di un trade-off in prolissità (che prescrivono una dichiarazione variabile aggiuntiva se si desidera continuare a utilizzare il modello di valore dell'attributo parentesi graffe), ma solo leggermente, in quanto semplifica drasticamente anche l'espressione XPath.
C'è ancora più spazio per migliorare. Mentre abbiamo rimosso la dipendenza dall'elenco dei nodi corrente, dipendiamo ancora dal nodo corrente. Questo, in sé e per sé, non è una cosa negativa, ma non è immediatamente chiaro dal punto di vista del template quale sia il nodo corrente. Tutto ciò che sappiamo è che il modello è denominato "section
"; per sapere con certezza cosa viene elaborato, dobbiamo cercare altrove nel nostro codice. Ma anche questo non deve essere il caso.
Se mai senti portato a utilizzare <xsl:for-each>
e <xsl:call-template>
insieme (come nel tuo esempio), un passo indietro e capire come utilizzare <xsl:apply-templates>
invece.
<xsl:template match="/doc">
<xsl:apply-templates select="section"/>
</xsl:template>
<xsl:template match="section">
<xsl:variable name="count">
<xsl:number/>
</xsl:variable>
<span class="title" id="title-{$count}">
<xsl:value-of select="title"/>
</span>
</xsl:template>
Non solo questo approccio meno dettagliato (<xsl:apply-templates/>
sostituisce sia <xsl:for-each>
e <xsl:call-template/>
), ma diventa anche immediatamente chiaro quale sia il nodo attuale. Tutto quello che devi fare è esaminare l'attributo match
e immediatamente sai che stai elaborando un elemento <section>
e che gli elementi <section>
sono ciò che stai contando.
Per una spiegazione sintetica di come funzionano le regole modello (ovvero gli elementi <xsl:template>
con attributo match
), vedere "How XSLT Works".
Grazie mille !! Questo post e la risposta è stata incredibilmente utile – anpatel
Prego! Mi fa piacere che l'abbia trovato utile. –
Mi dispiace, Evan, ma questa è una soluzione molto inefficiente (O (N^2)). Una soluzione che utilizza il passaggio dei parametri può essere solo O (N). Tutto questo parlare di "verbosità" è proprio questo - verbosità e non menzionare una parola sull'efficienza. Potresti rendere questa risposta più utile al lettore se menzioni la complessità temporale della soluzione proposta e la confronta con altre possibili soluzioni. Per questi motivi considero questa risposta come di tipo light-tutorial e non pratica per il lavoro di produzione. –