Domanda

Sto elaborando un file XML in cui voglio tenere il conto del numero di nodi, in modo da poterlo utilizzare come ID mentre scrivo nuovi nodi.

Al momento ho una variabile globale chiamata "contatore".Sono in grado di accedervi all'interno di un modello, ma non ho trovato un modo per manipolarlo all'interno di un modello.

Ecco una versione ridotta del mio file XSLT:

<xsl:variable name="counter" select="1" as="xs:integer"/>

<xsl:template match="/"> 
   <xsl:for-each select="section">
      <xsl:call-template name="section"></xsl:call-template>
   </xsl:for-each>
</xsl:template>

<xsl:template name="section">

   <!-- Increment 'counter' here -->

   <span class="title" id="title-{$counter}"><xsl:value-of select="title"/></span>
</xsl:template>

Qualche suggerimento su come procedere da qui?

È stato utile?

Soluzione

Altri hanno già spiegato come le variabili siano immutabili - che non ci sono istruzioni di assegnazione in XSLT (come nei linguaggi di programmazione puramente funzionali in generale).

Ho un'alternativa alle soluzioni che sono state proposte finora. Evita il passaggio dei parametri (che è dettagliato e brutto in XSLT - anche lo ammetto).

In XPath, puoi semplicemente contare il numero di <section> elementi che precedono quello 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 degli spazi bianchi non apparirà nel tuo risultato, poiché i nodi di testo solo per gli spazi bianchi vengono automaticamente rimossi dal foglio di stile. Quindi non sentirti obbligato a mettere le istruzioni sulla stessa riga.)

Un grande vantaggio di questo approccio (rispetto all'utilizzo di position()) è che dipende solo dal nodo corrente, non dall'elenco dei nodi corrente. Se in qualche modo hai modificato la tua elaborazione (ad es., Quindi <xsl:for-each> non solo ha elaborato sezioni ma anche qualche altro elemento), il valore di count() non corrisponderebbe più necessariamente alla posizione di <xsl:number> elementi nel tuo documento. D'altra parte, se si utilizza section come sopra, corrisponderà sempre alla posizione di ciascun <xsl:call-template> elemento. Questo approccio riduce l'accoppiamento con altre parti del codice, il che è generalmente un'ottima cosa.

Un'alternativa a count () sarebbe usare l'istruzione <xsl:apply-templates>. Il suo comportamento predefinito numererà tutti gli elementi con lo stesso nome allo stesso livello, che sembra essere quello che vuoi:

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

È un compromesso in termini di verbosità (che richiede una dichiarazione di variabile aggiuntiva se si desidera ancora utilizzare le parentesi graffe del modello di valore dell'attributo), ma solo leggermente, poiché semplifica drasticamente l'espressione XPath.

C'è ancora più spazio per il miglioramento. Mentre abbiamo rimosso la dipendenza dall'elenco dei nodi corrente, siamo ancora dipendenti dal nodo corrente. Questo, di per sé, non è una cosa negativa, ma non è immediatamente chiaro osservando il modello quale sia il nodo corrente. Tutto quello che sappiamo è che il modello è chiamato & Quot; <xsl:apply-templates/> & Quot ;; per sapere con certezza cosa viene elaborato, dobbiamo cercare altrove nel nostro codice. Ma anche quello non deve essere il caso.

Se ti senti mai indotto a usare <xsl:call-template/> e match insieme (come nel tuo esempio), fai un passo indietro e scopri come usare <xsl:template>.

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

Questo approccio non solo è meno dettagliato (<=> sostituisce sia <=> che <=>), ma diventa anche immediatamente chiaro quale sia il nodo corrente. Tutto quello che devi fare è guardare l'attributo <=> e sai immediatamente che stai elaborando un <=> elemento e che <=> gli elementi sono ciò che stai contando.

Per una spiegazione sintetica del funzionamento delle regole del modello (ovvero <=> elementi che hanno un <=> attributo), vedere " Come funziona XSLT " .

Altri suggerimenti

Le variabili XSLT non possono essere modificate. Dovrai passare il valore da un modello all'altro.

Se si utilizza XSLT 2.0, è possibile disporre di parametri e utilizzare il tunneling per propagare la variabile nei modelli giusti.

Il tuo modello sarà simile a questo:

<xsl:template match="a">
<xsl:param name="count" select="0">
  <xsl:apply-templates>
     <xsl:with-param select="$count+1"/>
  </xsl:apply-templates>
</xsl:template>

Guarda anche se usi generate-id () se vuoi creare id.

Le variabili in XSLT sono immutabili, quindi devi affrontare il problema con questo in mente. Puoi utilizzare position() direttamente:

<xsl:template match="/"> 
   <xsl:for-each select="section">
      <xsl:call-template name="section"/>
   </xsl:for-each>
</xsl:template>

<xsl:template name="section">
   <span class="title" id="title-{position()}"><xsl:value-of select="title"/></span>
</xsl:template>

O in un modo più orientato al modello:

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

<xsl:template match="section">
   <span class="title" id="title-{position()}"><xsl:value-of select="title"/></span>
</xsl:template>

le variabili hanno ambito locale e leggono solo in xslt.

A seconda del processore XSLT, potresti essere in grado di introdurre funzioni con script nel tuo XLST. Ad esempio, la libreria Microsoft XML supporta l'inclusione di javascript. Vedi http://msdn.microsoft.com/en- us / library / aa970889 (VS.85) .aspx per un esempio. Questa tattica ovviamente non funzionerà se hai intenzione di distribuire / eseguire XSLT su browser client pubblici; deve essere eseguito da un processore XSLT specifico.

Puoi usare la funzione position () per fare quello che vuoi. Sembrerebbe qualcosa del genere.

<xsl:template match="/">
  <xsl:for-each select="section">
    <xsl:call-template name="section">
      <xsl:with-param name="counter" select="{position()}"/>
    </xsl:call-template>
  </xsl:for-each>
</xsl:template>

<xsl:template name="section">
  <xsl:param name="counter"/>
  <span class="title" id="title-{$counter}">
    <xsl:value-of select="title"/>
  </span>
</xsl:template>

Non l'ho provato personalmente, ma potresti provare a passare un parametro al modello.Nel tuo primo modello imposti il ​​parametro su count() (o current() forse?) all'interno dell'istruzione for-each e poi passi quel valore al tuo modello "sezione".

Ecco di più passaggio dei parametri ai modelli

Usa <xsl:variable name="RowNum" select="count(./preceding-sibling::*)" /> e $RowNum come valore crescente.

Ad esempio: <xsl:template name="ME-homeTiles" match="Row[@Style='ME-homeTiles']" mode="itemstyle"> <xsl:variable name="RowNum" select="count(./preceding-sibling::*)" /> ...<a href="{$SafeLinkUrl}" class="tile{$RowNum}"><img ....></a>

Questo creerà classi per il collegamento con i valori tile1, tile2, tile3 ecc ...

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top