Indice del libro

Obiettivi di apprendimento

  • Comprendere che cos'è XPath
  • Conoscere la sintassi si XPath
  • Conoscere gli Axis e imparare a usarli
  • Imparare l'uso di funzioni e operatori

XPath è un linguaggio che fa parte della famiglia XML, che permette di individuare i nodi all'interno di un documento XML. Le espressioni XPath, a differenza delle espressioni XML, non servono a identificare la struttura di un documento, bensì a localizzarne con precisione i nodi.

XPath è nato originariamente dall'esigenza di fornire una sintassi e un comportamento comune fra XPointer e XSL; è stato successivamente adottato dagli sviluppatori come metodo di interrogazione dei dati in formato XML. La versione 1.0 di XPath è diventata uno standard W3C il 16 novembre 1999.

Notazione

modifica

Il tipo più comune di espressione XPath (e quella che ha dato origine al suo nome) è la path expression. Una path expression è scritta come una sequenza di passi per raggiungere un nodo XML, partendo dal nodo corrente (percorso "relativo"). In alternativa è possibile utilizzare dei percorsi "assoluti" utilizzando come riferimento la radice del documento. Gli elementi sono separati dal carattere '/'. Ogni elemento ha tre componenti:

Sono state definite due notazioni:

  1. Sintassi abbreviata, compatta, che permette la realizzazione di costrutti intuitivi e facilmente realizzabili;
  2. Sintassi completa, più complessa, che contiene maggiori opzioni, in grado di specificare con più particolarità gli elementi.

Sintassi abbreviata

modifica

La notazione abbreviata permette molte differenti sintassi per i casi comuni. L'XPath più semplice ha una forma del tipo:

  • /A/B/C

che seleziona gli elementi di C che sono figli degli elementi B che sono figli dell'elemento A che rappresenta la radice del documento XML. La sintassi XPath è stata progettata per imitare la sintassi del URI (Uniform Resource Identifier) e quella usata per indicare i file o le directory nei file system.

Le espressioni più complesse possono essere costruite specificando un Axis differente da un semplice nome o predicato, che può essere scritto fra parentesi quadre dopo tutta l'espressione. Per esempio:

  • A//B/*[1]

seleziona il primo elemento ("[1]"), figlio di B, indipendentemente dal suo nome, e dal numero di nodi che intercorrono tra A e B (//). Da notare che l'espressione non inizia con "/", quindi A è un nodo del contesto corrente.

Sintassi espansa

modifica

Nella sintassi completa, i due esempi qui sopra sarebbero scritti:

  • /child::A/child::B/child::C
  • child::A/descendant-or-self::B/child::node()[1]

In questo caso, ad ogni punto del XPath, l'Axis (per esempio child o descendant-or-self) è specificato esplicitamente, seguito da :: ed ancora seguito dal test del nodo, come A o node() degli esempi sopra citati.

L'Axis indica il senso di percorrenza dell'albero del documento XML. Gli Axis disponibili, nella sintassi completa ed abbreviata, sono:

child
default, non specificato nella sintassi abbreviata
attribute
@
descendant
non disponibile nella sintassi abbreviata
descendant-or-self
//
parent
..
ancestor
non disponibile nella sintassi abbreviata
ancestor-or-self
non disponibile nella sintassi abbreviata
following
non disponibile nella sintassi abbreviata
preceding
non disponibile nella sintassi abbreviata
following-sibling
non disponibile nella sintassi abbreviata
preceding-sibling
non disponibile nella sintassi abbreviata
self
.
namespace
non disponibile nella sintassi abbreviata

Ad esempio, usando la seguente sintassi abbreviata, //a/@href si seleziona un attributo denominato href in un qualunque elemento a dell'albero del documento. L'Axis self è più comunemente usato per riferirsi al nodo attualmente selezionato. Per esempio, h3[.='See also'] seleziona un elemento denominato h3 nel contesto corrente, il cui testo è uguale a "See also".


Node Test

modifica

I node test possono controllare nomi specifici di nodi o espressioni più generali. Nel caso di un documento XML in cui il prefisso del namespace gs è stato definito, //gs:enquiry troverà tutti i nodi enquiry di quel namespace.

Altri node test sono:

comment()
trova un nodo di commento XML, per esempio <!-- Commento -->
text()
trova un nodo di tipo testo, per esempio hello in <k>hello</k>
processing-instruction()
trova istruzioni di processamento XML come <?php echo $a;?>. In questo caso ('php').
node()
trova il nodo.

Predicati

modifica

Espressioni di qualunque entità possono essere indicate fra parentesi quadre, le quali dovranno essere soddisfatte affinché il nodo possa essere preso in considerazione. Ad esempio //a[@href='help.php'], che abbinerà un elemento con un attributo href di cui il valore è help.php. Non c'è limite al numero di predicati e non devono essere limitati all'ultimo elemento di un'espressione XPath. Possono anche essere annidati. I percorsi specificati nei predicati faranno riferimento al contesto del relativo punto (cioè quello immediatamente prima del test del nodo).

//a[@href='help.php'][../div/@class='header']/@target selezionerà il valore dell'attributo target di un elemento a, se l'elemento ha un attributo href il cui valore è help.php e se il parent è un elemento div che ha un attributo class di valore header

Funzioni ed operatori

modifica

XPath 1.0 definisce quattro tipi di dati: node-set (insiemi di nodi senza ordine intrinseco), stringhe, numeri e booleani.

Gli operatori disponibili sono:

  • Operatori "/", "//" e [...] usati nelle espressioni del percorso, come precedentemente descritto.
  • Un operatore di unione, "|", che forma l'unione di due node-set.
  • Operatori booleani "and" e "or" e la funzione "not()".
  • Operatori aritmetici "+", "-", "*", "div" e "mod".
  • Operatori di confronto "=", "!=", "<", ">", "<=", ">=".

La function library include:

  • Funzioni per manipolare stringhe: concat(), substring(), contains(), substring-before(), substring-after(), translate(), normalize-space(), string-length()
  • Funzioni per manipolare numeri: sum(), round(), floor(), ceiling()
  • Funzioni per accedere alle proprietà dei nodi: name(), local-name(), namespace-uri()
  • Funzioni per accedere a informazioni del contesto del nodo: position(), last()
  • Funzioni per la conversione dei tipi: string(), number(), boolean()

Alcune delle funzioni più comuni sono dettagliate successivamente. Per una descrizione completa, si veda il documento di riferimento del W3C

Funzioni su i nodi

modifica
position()
restituisce un numero che rappresenta la posizione di questo nodo rispetto ai relativi fratelli dal XPath a questo punto.
count(node-set)
restituisce il numero di nodi che corrispondono alla relativa richiesta

Funzioni per la manipolazione di stringhe

modifica
string(object?)
converte ognuno dei quattro tipi di dati di XPath in una stringa. L'argomento può essere un XPath, nel qual caso i nodi abbinati sono convertiti in stringa.
concat(string, string, string*)
concatena tutte le stringhe.
contains(s1, s2)
restituisce true se s1 contiene s2.
normalize-space(string?)
tutti i whitespace all'inizio e alla fine vengono rimossi e tutte le sequenze di whitespace sono sostituite da un singolo spazio. È molto utile quando l'XML originale dev'essere ben formattato, in grado di rendere ulteriormente fidata elaborazione della stringa.

Funzioni booleane

modifica
not(boolean)
nega tutta l'espressione booleana.

Funzioni numeriche

modifica
sum(node-set)
Converte i valori della stringa di tutti i nodi trovati, in numeri, quindi restituisce la somma di questi numeri.

Le espressioni possono essere generate usando gli operatori: =, !=, <=, <, >= e >. Le espressioni booleane possono essere unite con le parentesi () e combinate con operatori booleani and, or e not(). I calcoli numerici possono usare *, +, -, div e mod. Le stringhe possono consistere di tutti i caratteri di Unicode.

All'interno o all'esterno dei predicati, interi node-set possono essere uniti usando il carattere | ("pipe").

v[x or y] | w[z] restituirà un singolo node-set con tutti gli elementi di v che hanno come figli elementi y o x, insieme a tutti gli elementi di w che hanno figli z, trovati nel contesto corrente.

//item[@price > 2*@discount] seleziona gli item di cui l'attributo price è maggiore del doppio del valore dell'attributo discount.

Esempi pratici

modifica

Analizziamo ora un semplice documento XML per capire meglio come accedere ai dati in esso contenuti.

 <?xml version="1.0"?>
 <listautenti>
  <account user="fabio">
    <mail>fabio@aaaa.com</mail>
    <nome>Fabio V.</nome>
    <principale>
      <indirizzo>
        <via>Via Vai 1</via>
        <cap>98100</cap>
        <citta>Messina</citta>
      </indirizzo>
      <telefoni>
        <fisso>090123456</fisso>
        <cellulare gestore="aaa">3001234567</cellulare>
      </telefoni>
    </principale>
    <altrirecapiti>
      <ufficio>
        <indirizzo>
          <via>Via di Qua, 2</via>
          <cap>98100</cap>
          <citta>Messina</citta>
        </indirizzo>
        <telefoni>
          <fisso>09078901</fisso>
          <fax>3001234567</fax>
        </telefoni>
      </ufficio>
    </altrirecapiti>
  </account>
 </listautenti>
/listautenti/account//telefoni/*
restituisce la lista di tutti i nodi all'interno del nodo telefoni, in questo caso fisso, cellulare e fax.
/listautenti/account//indirizzo/..
restituisce tutti i nodi che contengono un nodo indirizzo al loro interno, l'impiego dell'Axis // fa sì che vengano individuati anche nodi di livelli differenti purché all'interno di account.