Paolo Pialorsi

SOA, Workflow Foundation (WF), Windows Communication Foundation (WCF) e le Architetture Distribuite

Costrutti iterativi: for-each

Abbiamo visto cosa sono e come funzionano i template.
A volte però fa anche comodo poter eseguire dei cicli senza richiamare i template, anche perchè ogni volta che invochiamo un template ci tocca eseguire dei salti nella struttura gerarchica del documento XSLT.

Se vogliamo eseguire un set di operazioni prefissate su un gruppo di nodi
possiamo utilizzare l'istruzione for-each. Essa prevede un solo attributo, di
nome select, che rappresenta la regola XPath di selezione dei nodi.

All'interno del blocco for-each dovremo indicare le operazioni da svolgere,
riferendoci ai nodi da cercare con percorsi relativi al nodo di contesto.

Cosa è il "nodo di contesto"? Si tratta del nodo sul quale è posizionato il "puntatore" del processore XSLT. Nel caso di un ciclo for-each si tratterà, passo dopo passo, di ciascuno dei nodi che fanno parte del risultato della regola XPath indicata nell'attributo select.

Quindi partendo dal seguente documento:

<?xml version="1.0"?>
<products>
 <product id="P01" name="Prodotto 01" />
 <product id="P02" name="Prodotto 02" />
 <product id="P03" name="Prodotto 03" />
 <product id="P04" name="Prodotto 04" />
 <product id="P05" name="Prodotto 05" />
</products>

se scriviamo:

<xsl:for-each select="/products/product">
 <!-- qui il nodo di contesto saranno i singoli elementi product -->
</xsl:for-each>

Allora per ottenere il valore dell'attributo @id del prodotto corrente ci basterà scrivere:

<xsl:for-each select="/products/product">
 <xsl:value-of select="@id" />
</xsl:for-each>

Forse non tutti sanno che possiamo combinare diverse regole XPath nel momento in cui eseguiamo una selezione. Per esempio il documento:

<?xml version="1.0"?>
<products>
 <tangible id="T01" deliveryTime="24" name="Prodotto tangibile 01" />
 <service id="S01" name="Servizio non tangibile 01" />
 <tangible id="T02" deliveryTime="36" name="Prodotto tangibile 02" />
 <tangible id="T03" deliveryTime="48" name="Prodotto tangibile 03" />
 <tangible id="T04" deliveryTime="24" name="Prodotto tangibile 04" />
 <service id="S02" name="Servizio non tangibile 02" />
 <service id="S03" name="Servizio non tangibile 03" />
 <service id="S04" name="Servizio non tangibile 04" />
</products>

prevede sia elementi <tangible> che <service>. I prodotti tangibili avranno un tempo di consegna (in ore), mentre i servizi saranno a consegna immediata (scusate la scarsa fantasia!).
Ora, sfruttando una regola XPath composta, potremmo voler scrivere in HTML tutti i servizi e i prodotti consegnabili entro e non oltre 24h:

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

<xsl:template match="/">
<html><body>
 <ul>
 <xsl:for-each select="products/tangible[@deliveryTime &lt;= 24] | products/service">
  <li><xsl:value-of select="@id" /> - <xsl:value-of select="@name" /></li>
 </xsl:for-each>
 </ul>
</body></html>
</xsl:template>

</xsl:transform>

Per ottenere:

<html><body>
<ul>
<li>T01 - Prodotto tangibile 01</li>
<li>S01 - Servizio non tangibile 01</li>
<li>T04 - Prodotto tangibile 04</li>
<li>S02 - Servizio non tangibile 02</li>
<li>S03 - Servizio non tangibile 03</li>
<li>S04 - Servizio non tangibile 04</li>
</ul>
</body></html>

Sui prodotti tangibili è stato applicato un filtro XPath secondo la regola:

axes::nodetest[predicate]

Per ulteriori dettagli su XPath vi rimando alla documentazione di MSXML 4.0 o di .NET Framework, oppure al mio tascabile su XML (http://education.mondadori.it/Libri/SchedaLibro.asp?IdLibro=88-8331-341-0) ... che arriva Natale e ho bisogno di soldi per fare i regali :-D!

La prossima volta vedremo come ordinare i nodi e come lavorare con nodi e percorsi XPath relativi, per esempio per dividere le categorie di prodotti o per mostrare tabelle con righe alternate.