Swappa : Uni / Basi di Dati - Complementi - XQuery
Creative Commons License

 :: Basi di Dati - Complementi ::

XQuery

Cos'è

Un documento XML può arrivare a contenere un enorme numero di informazioni, e reperirle semplicemente scorrendo il listato non è così efficiente. Nasce dunque l'esigenza di interrogare il documento come se fosse una vera e propria base di dati, utilizzando un opportuno linguaggio di interrogazione: l' XQuery.

L'XQuery non è basato sull'XML, ma è semanticamente più simile alle interrogazioni SQL. Implementa il linguaggio XPath aumentandone il potere di ricerca, permettendo di effettuare elaborazioni molto più complesse.

Dal 23 gennaio 2007 l'XQuery è felicemente diventato W3C recommendation.
Il W3C ne ha inoltre sviluppato una versione che usa sintassi XML, XQueryX, che non interessa ai nostri scopi.

FLWOR

Un'interrogazione scritta in XQuery sfrutta la sintassi delle espressioni XPath per selezionare specifiche porzioni del documento, a cui aggiunge espressioni proprie per un recupero più selettivo delle informazioni. Tali espressioni sono le cosiddette FLWOR, che costituiscono una generalizzazione del costrutto SELECT-FROM-WHERE in SQL. Il termine FLWOR è dato dalle iniziali delle varie clausole che lo compongono, ovvero: for, let, where, order by e return.

For

Il for serve a dichiarare quelle variabili che permettono di iterare sugli elementi di un documento. Genera come risultato una sequenza ordinata di tuple, chiamata anche tuple stream.

La sintassi generale è la seguente: FOR $x IN pathExpression
, dove $x è la variabile il cui valore è il risultato della path expression.

Ad esempio, abbiamo il seguente documento "birra.xml":

<birra produttore="Dasteb">
  <nome>Chiara</nome>
  <preparato>Pilsener</preparato>
  <confezione>Bottiglia</confezione>
  <confezione>Lattina</confezione>
  <confezione>Botte</confezione>
</birra>
<birra produttore="Dasteb">
  <nome>Rossa</nome>
  <preparato>Yorkshire</preparato>
  <confezione>Botte</confezione>
</birra>

L'interrogazione:

(1) FOR $conf IN document("birra.xml")//confezione
(2)     RETURN $conf

La (1) dichiara la variabile $conf, che contiene il risultato della path expression document("birra.xml")//confezione, quindi tutti gli elementi di tipo confezione presenti nel documento. Anticipiamo poi che in (2) la clausola return specifica che il risultato dell'interrogazione coincide con il valore della variabile $conf, ovvero:

<confezione>Bottiglia</confezione>
<confezione>Lattina</confezione>
<confezione>Botte</confezione>

Infine, è possibile avere espressioni for nidificate. Riprendendo l'esempio di prima, se volessimo ottenere i tipi di confezione di tutte le birre dovremmo scrivere:

(1) FOR $bir IN document("birra.xml")//birra
(2)     FOR $conf IN $bir/confezione
(3) RETURN $conf

In (2) si può notare che $conf fa uso del valore della variabile $bir per la sua interrogazione.

Let

Grazie alla clausola let è possibile dichiarare variabili associate al risultato dell’espressione, eventualmente associandole a quelle introdotte con for.
La sintassi generale è la seguente: LET $x := pathExpression

Possiamo riscrivere l'ultima interrogazione di esempio vista utilizzando la let:

FOR $bir IN document("birra.xml")//birra
LET $conf := $bir/confezione
RETURN $conf

La differenza rispetto all'utilizzo di for nidificate è che in questo caso viene associato come valore della variabile $conf l'intero insieme delle confezioni delle birre collegate alla variabile $bir, mentre nel primo caso avremmo avuto il passaggio di un singolo valore per volta (scandito dalle iterazioni del for nidificato).

Where

Con where si possono esprimere condizioni, quindi filtrare le tuple prodotte dalla for o dalla let.
La sintassi generale è la seguente: WHERE condizione
, dove condizione può coinvolgere diverse variabili e/o elementi e/o valori e fa uso dei classici operatori logici e aritmetici.

Se ad esempio volessimo interrogare "birra.xml" per sapere quali sono le Pilsener prodotte da "Dasteb", dovremmo scrivere:

FOR $bir IN document("birra.xml")//birra
WHERE $bir/@produttore="Dasteb"
      AND $bir/preparato="Pilsener"
RETURN $bir

Come si può notare ha una forma molto simile a quella dell'SQL, dal quale eredita inoltre alcune funzioni aggregate, come la count(). Ad esempio se volessimo sapere i tipi di confezioni che nell'elenco hanno almeno due birre, scriveremmo:

FOR $conf IN document("birra.xml")//birra/confezione
LET $bir:= document("birra.xml")//birra[confezione=$conf]
WHERE count($bir) > 2
RETURN $conf
Order by

La clausola order by permette di ordinare le tuple prodotte dalla for o dalla let.

Ad esempio, per trovare nome e preparato di tutte le birre presenti nel documento "birra.xml", e ordinare il risultato in ordine alfabetico in base al nome, si scrive:

FOR $bir IN document("birra.xml")//birra
RETURN <birra>
         $bir/nome,
         $bir/preparato
       </birra>
ORDER BY(nome ASCENDING)

I parametri per la order by sono:

Return

Con l'utilizzo di return, è possibile infine generare il risultato dell'espressione FLWOR. Il risultato può essere un nodo, un insieme di nodi o un singolo valore. E' l'unica clausola obbligatoria delle cinque viste finora.

Per quanto riguarda la sintassi, la return può contenere costruttori di elementi, riferimenti a variabili definite da for o let, espressioni annidate. Per costruttore di elemento si intende un'espressione che specifica la struttura del risultato a partire da elementi fissi o dal valore di variabili o espressioni, il tutto racchiuso tra un tag iniziale e finale.

Un esempio di definizione di costruttore sul solito documento "birra.xml" è:

FOR $bir IN document("birra.xml")//birra
WHERE $bir/@produttore="Dasteb"
RETURN <ProdDasteb>
         $bir/Nome
       </ProdDasteb>

che produce il seguente risultato:

<ProdDasteb><Nome>Chiara</Nome></ProdDasteb>
<ProdDasteb><Nome>Rossa</Nome></ProdDasteb>

Join tra documenti XML

Come si realizza con XQuery un join tra documenti lo vediamo attraverso un esempio. Abbiamo due documenti XML:

"costruttore.xml" "macchina.xml"
<costruttore>
  <nome-co>Toyota</nome-co>
  <anno>2005</anno>
  <modello>
    <nome-mo>Prius</nome-mo>
    <cilindrata>1497</cilindrata>
    <potenza>77</potenza>
    <aliment>benzina</aliment>
  </modello>
  ...
</costruttore>
<macchina>
  <venditore>Mario Rossi</venditore>
  <marca>Toyota</marca>
  <anno>2005</anno>
  <modello>Prius</modello>
  <colore>grigio metalizz</colore>
  <prezzo>25000</prezzo>
  ...
</macchina>

Vogliamo realizzare un join tra i documenti, ponendo <nome-co> = <marca>, <nome-mo> = <modello> e <anno> = <anno>, e memorizzare in un nuovo elemento autovettura le informazioni relative a marca, venditore, modello, cilindrata e prezzo.
Scriveremo il codice seguente:

FOR $c IN document(“costruttore.xml")//costruttore,
      $m IN document(“macchina.xml")//macchina,
      $mo IN $c/modello
WHERE $c/anno=$m/anno
      AND $c/nome-co=$m/marca
      AND $mo/nome-mo=$m/modello
RETURN <autovettura>
         $m/marca,
         $m/venditore,
         $m/modello,
         $mo/cilindrata,
         $m/prezzo
       </autovettura>

Torna alla pagina di Basi di Dati - Complementi

(Printable View of http://www.swappa.it/wiki/Uni/BDC-XQuery)