Massimo Martinelli
massimo.martinelli AT isti.cnr.it
Istituto di Scienza e Tecnologie dell'Informazione
Consiglio Nazionale delle Ricerche
via G. Moruzzi, 1 - 56124 Pisa
Corso CODIFICA DI TESTI
Pisa 10 Dicembre 2018
<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="biblioteca.css"?>
<biblioteca>
<libro codice="R414">
<titolo>2001: Odissea nello spazio</titolo>
<autore>
<cognome>Clarke</cognome>
<nome>Arthur Charles</nome>
</autore>
<editore>Rizzoli</editore>
<parola_chiave>romanzo</parola_chiave>
<parola_chiave>fantascienza</parola_chiave>
</libro>
</biblioteca>
titolo { display: block; cognome, nome { display: inline; }
text-align: center; editore { display: block;
background: blue; margin-left: 15%;
color: white; color: green;
font-family: Arial; font-family: Arial;
font-size: 20pt font-size: 14pt
} }
autore { display: block; parola_chiave { display: block;
margin-left: 10%; margin-left: 5%;
text-align: left; color: black;
color: red; font-family: "Times New Roman";
font-family: Arial; text-align: justify;
font-style: italic; font-size: 14pt
font-size: 14pt }
}
<xsl:template match="modello">
... trasformazione ...
</xsl:template>
<xsl:template match="nodo">
testo <tag> <xsl:value-of select="." /> </tag>
</xsl:template>
Se un nodo del documento XML combacia con quello della regola dell'esempio viene prodotto come risultato
testo <tag> valore (contenuto) dell'elemento corrente </tag>
Dato il seguente frammento XML
<nominativo>Mario Rossi</nominativo>
e il il seguente frammento XSLT
<xsl:template match="nominativo">
Nominativo: <strong><xsl:value-of select="."/></strong>
</xsl:template>
Risultato trasformazione:
Nominativo: <strong>Mario Rossi</strong>
Visualizzato da un browser in questo modo:
Nominativo: Mario Rossi
Abbiamo visto che una regola di template specifica un nodo come sagoma
ma come si specificano i nodi ? ...
/Corsi/XSL/index.xml
<li>
quale oggetto nell'elenco, il 1°, o il 2°, ...)esempio: biblioteca/libro/titolo 3 passi separati dal carattere "/"
/
" /biblioteca/libro
/
" libro/titolo
asse::nodo di test [predicati] (zero o più predicati)
child::para
seleziona tutti gli elementi para figli del nodo di contesto (NDC)child::*
tutti gli elementi figli del NDCchild::text()
tutti i nodi text figli del NDCchild::node()
tutti i figli del NDC, qualsiasi tipo di nodo sianoattribute::name
il nome dell'attributo del NDCattribute::*
tutti gli attributi del NDCdescendant::para
gli elementi para discendenti del NDCancestor::div
tutti gli elementi div avi del NDCancestor-or-self::div
come precedente più il NDC stesso se è un elemento divdescendant-or-self::para
tutti gli elementi para discendenti compreso il NDC se è un elemento paraself::para
seleziona il NDC se è un elemento para (niente altrimenti)child::capitolo/descendant::para
gli elementi para discendenti dell'elemento capitolo figlio del NDCchild::*/child::para
gli elementi para nipoti del NDC/
l'elemento radice del documento (sempre genitore del "document element")/descendant::olist/child::item
tutti gli elementi item che hanno un padre olist e che sono nello stesso documento del NDCchild::para[position()=1]
il primo figlio para del NDCchild::para[position()=last()-1]
il penultimo elemento para figlio del NDCchild::para[position()>1]
tutti i figli para del NDC eccetto il primofollowing-sibling::capitolo[position()=1]
il primo elemento capitolo fratello successivo del NDCpreceding-sibling::capitolo[position()=1]
il primo elemento capitolo fratello precedente del NDC/child::doc/child::capitolo[position()=5]/child::sezione[position()=2]
il secondo elemento del 5° capitolo dell'elemento doc figlio dell'elemento radicechild::para[attribute::tipo='attenzione'][position()=5]
il 5° figlio para del NDC che ha un attributo tipo con il valore attenzionechild::para[position()=5][attribute::type="warning"]
identico al precedentechild::capitolo[child::titolo='Introduzione']
i figli capitolo del NDC che hanno uno o più figli titolo con valore uguale a Introduzionechild::capitolo[child::titolo]
i figli capitolo del NDC che hanno uno o più figli titolochild::*[self::capitolo or self::appendice][position()=last()]
l'ultimo capitolo o appendice figli di NDCpara
seleziona gli elementi para figli del NDC*
tutti gli elementi figli del NDCtext()
tutti i nodi testo figli del NDC@nome
l'attributo nome del NDC@*
tutti gli attributi del NDCpara[1]
il primo elemento para figlio del NDCpara[last()]
l'ultimo nodo*/para
tutti gli elementi para nipoti del NDC/doc/capitolo[5]/sezione[2]
il 2° figlio sezione del 5° figlio capitolo dell'elemento doc figlio della radicechapter//para
tutti gli elementi para discendenti dell'elemento capitolo figlio del NDC//para
tutti gli elementi para discendenti dell'elemento radice (stesso documento del NDC)//olist/item
tutti gli elementi item figli di olist discendenti della radice item.
il nodo di contesto.//para
gli elementi para discendenti del NDC..
il genitore del NDC../@lang
l'attributo lang del genitore del NDCpara[@tipo="attenzione"]
tutti i figli para che hanno un attributo tipo con valore attenzionepara[@tipo="attenzione"][5]
il 5° figlio para del NDC con un attributo tipo con valore attenzionepara[5][@tipo="attenzione"]
identico al precedentecapitolo[titolo="Introduzione"]
il figlio capitolo figlio del NDC che ha almeno un elemento figlio titolo con valore uguale a Introduzionecapitolo[titolo]
tutti i figli del NDC capitolo con almeno un figlio titoloimpiegato[@codice and @tipo]
tutti i figli del NDC impiegato con un attributo codice e uno tipoSpecifica la direzione verso cui spostarsi a partire dal nodo di contesto
ancestor
corrisponde agli elementi avi del nodo correnteancestor-or-self
avi e nodo correnteattribute
attributo del nodo corrente (abbreviato con "@")child
figli del nodo corrente (asse di default)descendant
tutti i discendenti del nodo correntedescendant-or-self
discendenti e nodo correntefollowing
tutti i nodi che seguono quello corrente
(in ordine di apparizione all'interno del documento)following-sibling
nodi fratelli successivi al nodo correntenamespace
i nodi namespace del nodo correnteparent
il genitore del nodo corrente (abbreviato con "..")preceding
i nodi che precedono quello corrente
(in ordine di apparizione all'interno del documento)preceding-sibling
nodi fratelli precedenti al nodo correnteself
il nodo corrente (abbreviato con ".")Il Node-Test determina il tipo di nodo da selezionare
nome
combacia con i nodi elementi <nome>*
qualsiasi nodo di tipo elementonamespace:nome
ogni elemento <nome> con il namespace specificatonamespace:*
qualsiasi elemento con il namespace specificatocomment()
i nodi di tipo commentonode()
qualsiasi nodotext()
I nodi di tipo testoprocessing-instruction()
le istruzioni di processoEsempi
nodetest[1]
combacia con il primo nodonodetest[position()=last()]
l'ultimo nodonodetest[position() mod 2 = 0]
nodo parielement[@id='val']
elementi con un attributo id con valore "val"element[not(@id)]
elementi che non hanno un attributo idpersona[nome="Mario"]
elementi <persona> che hanno un
elemento figlio nome con valore "Mario".persona[normalize-space(nome)="Mario"]
identico al precedente senza tenere di conto gli spaziInsiemi di nodi
last()
restituisce il numero di nodi in un insieme di nodiposition()
posizione del nodo di contestocount(node-set)
il numero di nodilocal-name(node-set)
il nome locale (senza namespace) del primo nodonamespace-uri(node-set)
URI del namespace del primo nodoname(node-set)
il nome qualificato (con namespace) del primo nodoBooleani
and
or
true()
false()
!=
<
<=
=
>
>=
Esempio:
<xsl:template match="libro[position() > 2]">
...
</xsl:template>
Stringhe
starts-with(string string1, string string2)
- Booleancontains(string string1, string string2)
- Booleansubstring(string string1, number offset, number length)
- Stringsubstring-before(string string1, string string2)
- Stringsubstring-after(string string1, string string2)
- Stringstring-length(string string1)
- Numbernormalize-space(string string1)
- Stringtranslate(string string1, string string2,string string3)
- Stringconcat(string string1, string string2,...)
- StringNumeri
+
Addizione-
Sottrazione*
Moltiplicazionediv
Divisionemod
Moduloceiling()
Intero più grandefloor()
Intero più piccoloround()
Intero più vicino (arrotondamento)sum()
Somma di numeriDocumento XML
<?xml version="1.0" encoding="UTF-8" ?>
<saluto>
Benvenuto nel mondo di XSL-T
</saluto>
Documento XSL-T
<?xml version="1.0" encoding='UTF-8'?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<head><title>Saluto</title></head>
<body>
<xsl:apply-templates select="saluto"/>
</body>
</html>
</xsl:template>
<xsl:template match="saluto">
<xsl:value-of select="."/>
</xsl:template>
</xsl:stylesheet>
Associare lo stile aggiungendo nel file xml alla 2a riga
<?xml-stylesheet href="esempio3_documento.xsl" title="stile" type="text/xsl"?>
e aprire il file per esempio con Firefox e osservare con firebug oppure con Opera
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <-- aggiunta dal processore
<title>Saluto</title>
</head>
<body>
Benvenuto nel mondo di XSL-T
</body>
</html>
<xsl:template match="/">
<xsl:template match="x">
Nel successivo esempio vedremo questo template
<xsl:template match="n/x">
Documento XML
<?xml version="1.0" encoding="UTF-8" ?>
<documento>
<autore>Mario Rossi</autore>
</documento>
Documento XSL-T
<?xml version="1.0" encoding='UTF-8'?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<head><title>Autore</title></head>
<body>
<xsl:apply-templates select="documento/autore"/>
</body>
</html>
</xsl:template>
<xsl:template match="autore">
<xsl:value-of select="."/>
</xsl:template>
</xsl:stylesheet>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Autore</title>
</head>
<body>Mario Rossi</body>
</html>
<xsl:apply-template select="x">
<xsl:value-of select=".">
Documento XML
<?xml version="1.0" encoding="utf-8" ?>
<documento>
<autore>Mario Rossi</autore>
</documento>
Documento XSLT
<?xml version="1.0" encoding="utf-8" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:template match="autore">
<div>Autore: <strong> <xsl:apply-templates /> </strong></div>
</xsl:template>
</xsl:stylesheet>
Applica i template relativi agli elementi figli (ove ve ne siano)
...e non solo...
<div>
Autore:
<strong>Mario Rossi</strong>
</div>
Attenzione: non funziona come ci aspetteremmo perché esistono delle regole predefinite...
p.s. togliamo i due tag <div>
e </div>
e controlliamo cosa fanno firefox e opera:
<result>
che include il risultato<xsl:template match="nodo">
testo <tag> <xsl:apply-templates /> </tag>
</xsl:template>
testo <tag>
valore dell'elemento corrente <--regola di default
applicazione delle altre regole di template
</tag>
1. <xsl:template match="/ | *"> Applica le regole per qualsiasi elemento
<xsl:apply-templates/>
</xsl:template>
2. <xsl:template match="text()"> per qualsiasi testo
<xsl:value-of select="."/>
</xsl:template>
3. <xsl:template match="@*"> La regola per gli attributi è "ingannevole"
<xsl:value-of select="."/> Se non specifichiamo il template per gli attributi
</xsl:template> non vengono prodotti in output i valori
4. <xsl:template match="comment()"/> Non applicare le regole per i commenti
5. <xsl:template match="processing-instruction()"/> Ne per le istruzioni di processo
Dato il seguente file XML ...
<?xml version="1.0"?>
<biblioteca>
<libro codice="R415">
<titolo>Destinazione cervello</titolo>
<autore>
<cognome>Asimov</cognome>
<nome>Isaac</nome>
</autore>
<editore>Mondadori</editore>
<parola_chiave>romanzo</parola_chiave>
<parola_chiave>fantascienza</parola_chiave>
</libro>
<libro codice="N516">
<titolo>Sostiene Pereira</titolo>
<autore>
<cognome>Tabucchi</cognome>
<nome>Antonio</nome>
</autore>
<editore>Feltrinelli</editore>
<parola_chiave>romanzo</parola_chiave>
<parola_chiave>narrativa</parola_chiave>
</libro>
</biblioteca>
... e il seguente stylesheet minimale
<?xml version="1.0" encoding='UTF-8'?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
</xsl:stylesheet>
il risultato della trasformazione:
<?xml version="1.0" encoding="UTF-8"?> <--Prologo XML Destinazione cervello Asimov Isaac Mondadori <-- contenuto degli elementi senza i relativi tag romanzo fantascienza Sostiene Pereira Tabucchi Antonio Feltrinelli <-- Attenzione agli spazi prodotti!!! romanzo Il secondo template di default ha narrativa prodotto in output anche gli spazi
<xsl:template match="nodo">
</xsl:template>
Non applica alcuna trasformazione per il nodo specificato
<xsl:template match="*|text()" />
Non applica alcuna per gli elementi e per i testi (a meno di regole più specifiche)
<xsl:output method="xml"/>
<xsl:output method="html"/>
<xsl:output method="text"/>
<xsl:output indent="yes"/>
<xsl:output doctype-system="nomefile.dtd"/>
<!DOCTYPE elementoradice SYSTEM "nomefile.dtd">
<xsl:apply-templates/>
<xsl:apply-templates select="nodo" />
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml"
doctype-public="-//W3C//DTD XHTML 1.1//EN"
doctype-system="http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"/>
<xsl:template match="/">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>esempio di output XHTML</title>
</head>
<body>
<xsl:apply-templates />
</body>
</html>
</xsl:template>
...
</xsl:stylesheet>
Concorso CNR 2017
Problema: ottenere elenco pubblicazioni seguendo le regole del concorso
2018: Martinelli M., Tampucci M. - Ottenere l'elenco delle pubblicazioni CNR con 'stile' - Nota tecnica aperta.
Dato il seguente documento XML:
<?xml version="1.0"?>
<brano id="5">
<titolo>Asturias<titolo/>
<autore>Andres Segovia</autore>
<incisione>Deutsche Grammophon</incisione>
</brano>
Trasformare in XHTML 1 (strict) in modo da produrre questo risultato:
Titolo brano: Asturias
Identificatore: 5
Incisione: Deutsche Grammophon
La priorità di default è determinata come segue:
*
" non qualificato ha priorità -0.5Esempi
elemento
", "html:p
", e "@attributo
" hanno priorità 0html:*
" ha priorità -0.25*
" ha priorita -0.5elemento1/elemento2
" ha priorità 0.5elemento[@attributo]
" ha priorità 0.5<doc>
<para>Questo è un <em>esempio</em>.
<em>Contenuto <emphasis>nidificato</emphasis></em>.</para>
</doc>
<html>
<head>
<title>titolo del documento</title>
</head>
<body>
<p>Questo è un <em>esempio</em>.
<em>Contenuto <span>nidificato</span></em>.</p>
</body>
</html>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="doc">
<html><head><title>Titolo del documento</title></head>
<body><xsl:apply-templates/></body></html>
</xsl:template>
<xsl:template match="para">
<p><xsl:apply-templates/></p>
</xsl:template>
<xsl:template match="em">
<em><xsl:apply-templates/></em>
</xsl:template>
<xsl:template match="em/em">
<span><xsl:apply-templates/></span>
</xsl:template>
</xsl:stylesheet>
A volte può essere necessario includere più volte lo stesso nodo del documento sorgente in quello finale, ovvero applicare più trasformazioni sullo stesso nodo (ad esempio per fare un indice di oggetti presenti nel documento).
I modi permettono di applicare più regole per lo stesso nodo
<?xml version="1.0"?>
<capitolo id="c1"> <titolo>Titolo capitolo</titolo>
<para>Questo capitolo si auto referenzia:
<xref linkend="c1" /> . </para>
</capitolo>
<h2>Titolo capitolo</h2>
<p>Questo capitolo si auto referenzia:
<em>Titolo capitolo</em>.</p>
<?xml version='1.0'?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="html"/>
<xsl:template match="capitolo/titolo">
<h2><xsl:apply-templates/></h2>
</xsl:template>
<xsl:template match="capitolo/titolo" mode="crossref">
<em><xsl:apply-templates/></em> \
</xsl:template> \
\
applica questo
\
<xsl:template match="xref"> \
<xsl:variable name="linkend" select="@linkend"/> \
<xsl:apply-templates select="//*[@id=$linkend]/titolo" mode="crossref"/>
</xsl:template>
<xsl:template match="para">
<p><xsl:apply-templates/></p>
</xsl:template>
</xsl:stylesheet>
<xsl:text>xyz</xsl:text>
Restituisce in output il testo xyz
Scrivere xyz all'interno di un template è equivalente
<xsl:template match="nome_elemento">
xyz
</xsl:template>
Commenti in XSL-T
<xsl:comment>commento</xsl:comment>
Come abbiamo visto XSL-T permette di elaborare elementi multipli contenuti all'interno di
altri elementi mediante l'applicazione di due template:
il primo fa eseguire il secondo al suo interno.
<xsl:template match="persona">
<xsl:apply-templates select="cognome"/>
</xsl:template>
<xsl:template match="cognome">
<xsl:value-of select="."/>
</xsl:template>
Esiste un'altra regola, molto più leggibile, che permette di ottenere lo stesso risultato:
<xsl:for-each select="el">
Cicla su tutti gli elementi el all'interno dell'elemento corrente
<xsl:template match="persona">
<xsl:for-each select="cognome">
<xsl:value-of select="."/>
</xsl:for-each>
</xsl:template>
select="." all'interno del for-each seleziona l'elemento selezionato dal for-each (cognome)
<xsl:if test="$condizione">
questo messaggio apparirà solo se $condizione è true
</xsl:if>
<xsl:if test="nome">
esiste l'elemento "nome", figlio dell'elemento corrente ?<xsl:if test="count(x)>1">
esiste più di un elemento "x" figlio dell'elemento corrente ?<xsl:if test="$x">
il valore della variabile "x" è true ?Dividiamo gli autori con una virgola:
<xsl:template match="autore">
<xsl:value-of select="./cognome" />
<xsl:text> </xsl:text>
<xsl:value-of select="./nome" />
<xsl:apply-templates />
<xsl:if test="not(position()=last())">, </xsl:if>
</xsl:template>
^
<xsl:variable name="var" expr="subelement[position() mod 3]"/>
* Notare la dichiarazione di una variabile il cui valore è una espressione matematica
<xsl:variable name="persona">
<xsl:if test="$nome">...</xsl:if>
</xsl:variable>
<xsl:template match="film">
<h1> elenco dvd</h1>
<table>
<xsl:apply-templates select="dvd"/>
</table>
<h1> elenco videocassette</h1>
<table>
<xsl:apply-templates select="cassetta"/>
</table>
</xsl:template>
Supponiamo di dover gestire la prenotazione di lezioni che possono essere di gruppo o individuali
<xsl:template match="lezione">
<h3><xsl:value-of select="titoloLezione"/></h3>
<h4>Aula: <xsl:value-of select="../../@name"/></h4>
<h4>Prenotata da : <xsl:value-of select='prenotataDa'/></h4>
<h4>Allievi:</h4>
<xsl:for-each select='allievi'>
<xsl:choose>
<xsl:when test="gruppo"> <-- Esiste un elemento gruppo figlio dell'elemento corrente ?
  Gruppo: <em><xsl:value-of select="gruppo"/></em><br />
</xsl:when>
<xsl:otherwise>
  <xsl:value-of select="individuo"/><br />
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
<p> dalle ore <xsl:value-of select="oriario/da"/>
alle ore <xsl:value-of select="orario/alle"/></p>
. . .
</xsl:template>
  ==
<xsl:template match="elemento">
<xsl:variable name="var" expr="sottoelemento[position() mod 3]"/>
<xsl:choose>
<xsl:when test='$var=1'>
... fai qualcosa...
</xsl:when>
<xsl:when test='$var=2'>
... fai un'altra cosa ...
</xsl:when>
<xsl:otherwise>
... fai qualcosaltro ...
</xsl:otherwise>
</xsl:choose>
<xsl:apply-templates/>
</xsl:template>
Modificare l'ordine dei libri per autore
<xsl:template match="biblioteca"> <xsl:apply-templates select="libro[code >= 'M']" > <xsl:sort select="libro/autore/cognome" />
Ordina per cognome<xsl:sort select="libro//nome" />
poi per nome</xsl:apply-templates> </xsl:template>
Supponendo di voler modificare l'ordine per prezzo (numerico)
<xsl:sort select="libro/prezzo" order="descending"
Specifica l'ordine discendente (per difetto = ascending)data-type="number" />
Specifica il tipo di dato (per difetto = text)
Numerazione
<xsl:template match="libro"> <xsl:number /> <xsl:text> </xsl:text>
Inserisce uno spazio tra il numero e il titolo<xsl:value-of select="titolo" /> </xsl:template>
xsl:number
inserisce una sequenza di numeri contanto il numero dei fratelli che precedono l'elemento e aggiunge 1
1 Destinazione cervello
2 Sostiene Pereira
Indica il normato della numerazione
<xsl:number format="tipo_formato">
tipo_formato
<xsl:template match="titolo">
<xsl:number level="multiple"
count="capitolo|sezione|sottosezione"
format="1.1.a" />
<xsl:apply-templates />
</xsl:template>
1 Titolo del capitolo 1.1 Titolo della Sezione 1.1.a Titolo della Sottosezione 1.2 ...
Se aggiungo questo:
<xsl:template match="capitolo/titolo">
<xsl:number level="multiple"
count="capitolo"
format="1:" />
<xsl:apply-templates />
</xsl:template>
Capitolo 1 Titolo del capitolo 1.1 Titolo della Sezione 1.1.a Titolo della Sottosezione 1.2 ...
<xsl:element name="nome_elemento">
Crea un elemento <nome_elemento> e lo restituisce in uscita
<xsl:element name="cognome">
<xsl:value-of select=".">
</xsl:element>
Crea un elemento <cognome>
contenente il valore dell'elemento corrente
<xsl:attribute name="nome_attributo">
Crea un attributo nome_attributo su <xsl:element>
corrente.
Il contenuto di <xsl:attribute>
diventa il valore dell'attributo creato
<indirizzo_sito_web>http://www.cnr.it</indirizzo_sito_web>
<xsl:element name="a">
<xsl:attribute name="href">
<xsl:value-of select="indirizzo_sito_web">
</xsl:attribute>
il sito web del CNR
</xsl:element>
<a href="http://www.cnr.it">il sito web del CNR</a>
Riferimenti incrociati e funzione id()
<xsl:value-of select="id(@refid)/@reftext" />
restituisce l'attributo @reftext del nodo che ha un id con un valore equivalente al valore @refid del nodo corrente
solo un attributo deve essere dichiarato ID nella DTD/Schema
Key supera questo limite
XSL-T mette a disposizione la possibilita di invocare una regola template per nome passandogli dei parametri
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="nome" /> // parametro con visibilità globale
<xsl:template name="calcoloArea">
<xsl:param name="larghezza" />
<xsl:param name="altezza" />
<xsl:value-of select="$larghezza * $altezza" />
</xsl:template>
<xsl:call-template name="calcolaArea"> // invoca il template
<xsl:with-param name="larghezza" select="10" /> // passaggio di parametro
<xsl:with-param name="altezza" select="20" /> // passaggio di parametro
<xsl:call-template>
</xsl:stylesheet>
I template si possono invocare ricorsivamente (call template all'interno dello stesso template che chiama)
Un ottimo esempio è il template Somma riportato nel capitolo 7 sezione 2 del libro "XSL-T" O'Reilly
http://oreilly.com/catalog/orxmlapp/chapter/ch07.html
XSL-T mette a disposizione due metodi per combinare regole template contenute in documenti distinti: import e include
<xsl:import href = "uri-reference" />
href = URI del foglio di stile da importare
<xsl:import>
importa uno stylesheet esterno
Le regole template importate da un'altro documento hanno una priorità inferiore.
<xsl:include href = "uri-reference" />
<xsl:include>
include le regole da un altro documento:
Le regole template incluse da un altro documento hanno la stessa priorità di quelle contenute nel primo documento.
Questi due metodi vanno specificati subito dopo il tag <xsl:stylesheet>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:import href="nomefile.xsl"/>
<xsl:include href="nomealtrofile.xsl"/>
...
</xsl:stylesheet>
Un foglio di stile può elaborare più di un documento XML caricando altri documenti con la funzione document()
prodotti.xml
<?xml version="1.0"?>
<prodotti>
<prodotto>
<nome>Monitor<nome>
<prezzo valuta="eu">900</prezzo>
<descrizione>Display LCD ... </descrizione>
</prodotto>
...
</prodotti>
valute.xml
<?xml version="1.0"?>
<valute>
<valuta>
<codice>eu<codice>
<nome>Euro<nome>
</valuta>
...
</valute>
...
<xsl:variable
nome=valute
select="document(valute.xml)/valute" />
...
<xsl:template match="prodotto">
<xsl:variable name="valuta" select="prezzo/@valuta" />
<xsl:value-of select="prezzo" />
<xsl:value-of select="$valute/valuta[codice="$valuta"]/nome" />
<xsl:value-of select="descrizione" />
</xsl:template>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/XSL/Transform"
xmlns:myxslt="http://www.apache.org/xslt" exclude-result-prefixes="myxslt">
...
<xsl:variable name="angolo" select="javascript-extension:cos(90)" />
...
<myxslt:component prefix="javascript-extension" functions=cos sin">
<myxslt:script lang="javascript">
function cos(a)
{
return Math.cos(a);
}
function sin(a)
{
return Math.cos(a);
}
</myxslt:script>
</myxslt:component>
...
</xsl:stylesheet>
Linux:
sudo apt-get install xsltproc xsltproc --output risultato.xml directorystile/stile.xsl directorysorgente/sorgente.xml
Da una applicazione si può richiamare un processore XSL per eseguire una trasformazione di un documento XML
XSLTProcessor processor = XSLTProcessorFactory.getProcessor();
processor.process(new XSLTInputSource(XMLFile),
new XSLTInputSource(XSLFile),
new XSLTResultTarget(NewXMLFile));
Apache Xalan (XSL 1.0)
Saxonica saxon (XSL 1.0 e 2.0)
Apache FOP (XSL 1.0 e XSL-FO)
<?xml version="1.0"?>
<anagrafe>
<persona>
<cognome>Rossi</cognome>
<nome>Mario</nome>
<datanascita>
<giorno>15</giorno>
<mese>05<mese>
<anno>2003<anno>
</datanascita>
<persona>
<persona>
...
<persona>
</anagrafe>
Trasformare in XHTML con una tabella come questa:
<table summary="...." >
<caption>
<thead>
<tr>
<th>cognome</th>
</tr>
</thead>
<tbody>
<tr>
<td>Rossi</td><td>Mario</td><td>15/05/2003</td>
<tr>
</tbody>
</table>
I valori devono essere ordinati per anno, mese, giorno di nascita
Analizziamo gli esempi iniziali
trasformazione di un stesso documento XML in SVG, HTML e PDF
Linguaggio di interrogazione
SQL : database relazionali = XQuery : documenti XML su Web
"Trasformazione" da XML a XML
Si avvaleva di un XPath modificato
Forti implicazioni con XSL (XPath2 uniforma l'uso nei due linguaggi XSL e XQuery)
<utenti>
<utente>
<userid>U01</userid>
<nome>Mario Rossi</nome>
</utente>
...
Elenca i nomi degli utenti che hanno fatto un acquisto singolo di almeno 100 euro
<risultato>
{
for $u in document("utenti.xml")//utente
let $s := document("acquisti.xml")//acquisto[userid=$u/userid and costo>=100]
where count($s) > 1 Se c'è n'è almeno uno
order by $u/utente/nome descending
return
<spendaccione>{ $u/nome/text() }</spendaccione>
}
</risultato>
Risultato effettivo :
<risultato>
<spendaccione>Maria Bianchi</spendaccione>
<spendaccione>Anna Verdi</spendaccione>
<spendaccione>Giuseppe Gialli</spendaccione>
</risultato>
Domande?
... troverete le slide all'indirizzo (http://www1.isti.cnr.it/~Martinelli/XML/doc/xsl/)