Lo sviluppo di tecnologie diverse ha portato la necessità di creare una notazione flessibile per navigare all'interno di un documento XML. Il risultato finale è XPath, utilizzato da XML per determinare l'identità e descrivere i campi d'azione.
Abbiamo già parlato di XPath nella Guida linguaggi XML. In questo articolo riprenderemo alcuni dei concetti già visti ma approfondiremo maggiormente alcuni costrutti fondamentali di XPath. In particolare ci concentreremo sulla costruzione delle espressioni i cosiddetti "Location Path" e le parti che li compongono, i "Location Step"
Esempio di espressione XPath
rcp:esempio[@qunant='4' and @unita='tazza']/@home
Location Step
In XPath un percorso (Location Path) definisce una sequenza di nodi in un albero XML. La sequenza risultante rispetterà sempre l'ordine del documento e non conterrà mai duplicati di nodi identici. La sequenza dei nodi è definita come una sequenza di "Location Step" (passi di locazione) separati da un carattere "slash" (/
), ognuno dei quali è composto da:
- asse
- test di nodo
- e da 0 a N predicati
Ricapitolando avremo la seguente situazione:
asse :: testnodo [espr1]...[esprN]
L'espressione viene valutata a partire da un nodo principale poi si scende nelle diramazioni seguendo i passi di locazione. Questo nodo principale viene anche chiamato "contesto" perché determina il punto iniziale della ricerca.
La valutazione di un'espressione produce una serie di N nodi. Generalizzando possiamo dire che una trasformazione prende una sequenza di nodi in input e ne restituisce un'altra.
A questo punto è facile definire il comportamento di un percorso di locazione (path) come il risultato dei comportamenti dei passi (step) che lo compongono. Per capire meglio, cominciamo osservando lo schema:
Ogni nodo dell'albero ha un indice numerico univoco che lo contraddistingue ed una lettera come descrizione. Prendiamo, come esempio, il seguente percorso:
descendant :: C/child :: F
- Si parte sempre dalla radice dell'albero che nel nostro caso è
A1
- Prendiamo il primo pezzo del percorso:
descendant :: C
; quindi partendo dalla radice prendiamo tutti i nodi con descrizione C e che siano discendenti del nodo radice (A1
) - Otteniamo la seguente serie di nodi:
C4, C5, C9
. - Il passo successivo è valutare i figli di C.
- Infatti prendendo la seconda parte del percorso,
child :: F
bisogna valutare i figli che siano etichettati come F. - Quindi avremo come risultato finale la seguente serie di nodi:
F8, F11, F12
.
I Contesti
Il contesto di un'espressione XPath è caratterizzato da:
- un nodo contesto (nodo appartenente all'albero XML)
- posizione e dimensioni del contesto (due numeri)
- un insieme di legami di variabili
- una libreria di funzioni
- un insieme di dichiarazioni di namespace
Il contesto iniziale è determinato dall'applicazione che invoca la valutazione dell'XPath. Durante la valutazione di uno o piu passi di locazione abbiamo visto che il nodo contesto varia e così anche la sua posizione e le sue dimensioni (numero di nodi coinvolti).
Se nel passo i-esimo
abbiamo ottenuto una lunghezza pari a N
; il passo successivo i+1
, il contesto sarà il nodo stesso. Più avanti, nel corso dell'articolo vedremo che la posizione e la lunghezza del contesto servono per la valutazione dei predicati.
Gli Assi
L'asse determina la relazione che intercorre tra il nodo di contesto e gli altri nodi nell'albero. Determinare un asse in un Location Step significa voler selezionare i nodi che hanno una precisa relazione con il contesto.
XPath prevede 12 tipologie di relazione:
Relazione | Abbreviazione | Descrizione |
---|---|---|
child |
niente asse |
rappresenta i figli del nodo contesto |
descendant |
sono i discendenti del nodo contesto | |
parent |
.. |
padre del nodo contesto |
ancestor |
antenati del nodo contesto | |
following |
sono tutti i fratelli | |
following-sibling |
sono i fratelli posti "a destra" (nella rappresentazione) rispetto il nodo contesto | |
preceding-sibling |
sono i fratelli posti "a sinistra" rispetto il nodo contesto | |
self |
. |
il nodo contesto |
descendant-or-self |
// |
concatenazione di self + descendant |
ancestor-or-self |
concatenazione di self + ancestor | |
attribute |
@ |
tutti i nodi attributi |
Possiamo anche non definire l'asse in un Location Step. In questo caso viene considerata la relazione child
per default. Altre relazioni consentono forme abbreviate, come parent
, che si può sostituire con due punti (..
).
Ecco qualche altro esempio di utilizzo delle relazioni.
Tipi di nodo (testnodo)
Il primo test che rifinisce la ricerca è quello che ci permette di indicare che tipo di nodo stiamo cercando. I tipi di nodo sono:
- elementi particolari: quelli designati da nome e namespace (es.
<asp:TextBox>
//asp.TextBox
tutti i nodiTextBox
del namespaceasp
) - text: i nodi testo, ovvero il testo presente all'interno degli elementi o al di fuori (es.
blabla
è il nodo testo nella stringa<div>blabla</div>
) - comment: sono i nodi commento
- node: tutti i nodi presente nell'albero XML
- processing-instruction: i nodi che contengono istruzioni (es.
<?php echo "andimar" ?>
)
Predicati
I predicati sono espressioni che ci aiutano a rifinire ulteriormente le ricerche. Queste espressioni possono essere soddisfatte dal nodo, se le caratteristiche del nodo rendono l'espressione verificata, oppure no. Ne primo caso il nodo appartiene all'insieme dei nodi ricercati, nel secondo il nodo viene scartato.
I predicati sono racchiusi tra parentesi quadre e possono essere aggiunti in coda a qualunque Location Step.
È possibile combinare N
espressioni attraverso gli operatori logici and
, or
e not
. Un esempio di espressione è la seguente:
descendant :: C/child :: F[attribute::nome='esempio']
In questo caso selezionerà tutti i nodi F, figli del nodo C e con l'attributo nome
uguale a "esempio".
I valori prodotti possono appartenere anche a tipi diversi dal boolean come numeri, caratteri, stringhe e sequenze e sono convertiti automaticamente in booleani come segue:
- un numero vale true quando il suo valore è identico alla posizione corrente del contesto
- una stringa vale true quando la sua lunghezza è maggiore di zero
- una sequenza vale true quando la sua lunghezza è maggiore di zero
Commenti in XPath
Come tutti i linguaggi anche XPath dispone di una notazione particolare per inserire dei commenti. I commenti hanno la seguente sintassi:
(: commento :)
Le Espressioni
Abbiamo già osservato l'importanza delle espressioni in XPath. Ne esistono diverse tipologie, osserviamone alcune.
Espressioni Booleane
XPath supporta gli operatori logici and
, or
e not
. la loro combianzione forma un'espressione booleana che restituisce come risultato true
o false
. L'espressione restituisce true per le seguenti condizioni:
- il valore booleano
true
- una stringa non vuota
- una sequenza di lunghezza maggiore di
0
Sequenze
Possiamo definire la sequenza di espressioni come una concatenazione di N espressioni con N > 0
. Se N = 0
la sequenza si dice vuota.
Espressione1, Espressione2,...,EspressioneN
L'espressione Espressione1 to Espressione4
, restituisce una sequenza di valori che dall'espressione 1 arrivi fino all'espressione 4. Un esempio è il seguente:
1 to 5 restituirà la sequenza: 1, 2, 3, 4, 5
Le sequenze che contengono esclusivamente nodi possono essere combinate con gli operatori union
, intersect
ed exept
Filtri
I predicati dei percorsi di locazione possono essere generalizzati in sequenze arbitrarie che contengono un insieme di nodi e valori. La sintassi è la seguente:
Espressione1[Espressione2]
che permette di usare come filtri espressioni arbitrarie forzate a una valutazione booleana.
Espressioni aritmetiche ed espressioni letterali
XPath supporta tutti gli operatori aritmetici. Possiamo effettuare le operazioni fondamentali (+,-,*,/) su tutti i tipi numerici (interi
, decimali
, float
e double
), inoltre li interi supportano la divisione intera (idiv
) e l'operatore di modulo (mod
).
Un'espressione letterale denota un valore atomico costante o più precisamente una sequenza singleton, ovvero che contiene un solo valore.
Espressioni di Confronto
Le espressioni di confronto in XPath si suddividono in tre categoria; confronti tra valori, confronti generali e confronti tra nodi.
Confronto tra nodi
Il confronto tra i nodi viene effettuato attraverso i seguenti operatori
Operatore | Descrizione |
---|---|
is |
operatore di identità, stabilisce se due espressioni rappresentano lo stesso nodo (es. nota[1] is *[@nome="la"][1] è verificata se il primo figlio di nota è anche il primo nodo che ha attributo nome="la" |
isnot |
il cotrario di is |
<< |
verifica che il primo nodo sia precedente al secondo |
>> |
verifica che il primo nodo sia successivo al secondo |
Esempio di confronto tra nodi
/rcp::C << (rcp::F)
Confronto generale
Il confronto generale utilizza i seguenti operatori:
Operatore | Descrizione |
---|---|
= |
Uguale |
!= |
Diverso |
< |
Minore |
> |
Maggiore |
<= |
Minore o Uguale |
>= |
Maggiore o Uguale |
e vengono utilizzati per confrontare tutti i valori. Un esempio può essere il seguente:
descendant :: C/child :: F = 3
Confronto tra valori
Il confronto tra valori, invece, utilizza i seguenti operatori:
Operatori | |||||
---|---|---|---|---|---|
eq |
ne |
lt |
gt |
le |
ge |
e vengono utilizzati per confrontare i singoli valori atomici. Un esempio può essere il seguente:
//rcp:descrizione/text() eq "Esempio di confronto per valore"
Funzioni
XPath mette a disposizione una serie di operatori e funzioni che si rivelano alla elaborazione dei dati. Cerchiamo di esaminare i blocchi di funzioni più importanti.
Funzioni Booleane
Funzione | Descrizione |
---|---|
fn:true() |
restituisce il valore booleano true |
fn:false() |
restituisce il valore booleano false |
fn:not(expr) |
effettua l'operazione logica di negazione (not ) alla espressione inserita |
Esempi
fn:true() = true fn:false() = false fn:not(1) = false fn:not(0) = true
Funzioni di Stringa
Funzione | Descrizione |
---|---|
fn:concat(stringa1, ..., stringaN) |
concatena le stringhe inserite nella funzione |
fn:string-join((stringa1, ..., stringaN), stringaReplace) |
è la combinazione di una concatenazione e di un Replace |
fn:substring(stringa, partenza, fine) |
restituisce la sottostringa |
fn:string-length(stringa) |
restituisce il numero di caratteri che compongono la stringa |
fn:lower-case(stringa) |
restituisce la stringa con caratteri minuscoli |
fn:upper-case(stringa) |
restituisce la stringa con caratteri maiuscoli |
Esempi
fn:concat("esempio", " di ", " prova") = "esempio di prova" fn:string-join(("1", "2", "3", "4"), "+") = "1+2+3+4" fn:substring("esempio di prova", 2, 5) = "sempi" fn:string-length("esempio di prova") = 16 fn:lower-case("STRINGA") = "stringa" fn:upper-case("stringa") = "STRINGA"
Funzioni Matematiche
Funzione | Descrizione |
---|---|
fn:max(numero1, ..., numeroN) |
restituisce il numero massimo della serie |
fn:min(numero1, ..., numeroN) |
restituisce il numero minimo della serie |
fn:sum(numero1, ..., numeroN) |
restituisce la somma della serie |
xs:integer(numero) |
restituisce l'intero |
xs:decimal(numero) |
restituisce il numero con i decimali |
xs:float(numero) |
restituisce il numero in formato float (virgola mobile) |
xs:double(numero) |
restituisce il numero in formato double (virgola mobile, doppia precisione) |
Esempi
fn:max(1, 2, 3, 4, 5, 6, 7, 8) : 8 fn:min(1, 2, 3, 4, 5, 6, 7, 8) : 1 fn:sum(1, 2, 3, 4, 5) : 15 xs:integer(3.5) : 3 xs:decimal(3) : 3.0 xs:float(2) : 2.0E0 xs:double(14.3) : 1.43E1