XQuery deriva da Quilt un linguaggio d'interrogazione per XML, il quale a sua volta prende molte delle sue caratteristiche da altri linguaggi:
Alcuni aspetti rimangono aperti, legati al legame di XQuery con altri attività di ricerca su XML:the following symbols are used:
| . | Il nodo corrente |
| .. | Il padre del nodo corrente |
| / | Il nodo radice o il separatore tra diversi passi dell'espressione di percorso. |
| // | I figli del nodo corrente. |
| @ | Gli attributi del nodo corrente. |
| * | Qualsiasi nodo. |
| [ ] | Parentesi che che contengono un'espressione booleana per limitare i nodi selezionati in un certo passo. |
| [n] | Seleziona un elemento figlio da una lista di elementi. |
es: document("zoo.xml")/chapter[2]//figure[caption = "Tree Frogs"]
In aggiunta alla sintassi di XPath, XQuery ha il predicato RANGE preso da XQL:
Trova tutti gli elementi figure nei capitoli 2,3,4 e 5 del documento zoo.xml:
document("zoo.xml")/chapter[RANGE 2 TO 5]//figure.
Un altro operatore aggiunto in XQuery rispetto a XPath è l'operatore
di deferenza ("->"). Esso si applica ad attributi di tipo IDREF e ritorna
l'elemento referenziato, l'operatore è seguito da un nome che indica
il nomem dell'elemento obiettivo:
Trovare i titoli delle immagini referenziate dagli elementi <figref> nei capitoli di "zoo.xml" e aventi titolo "Frogs":
document("zoo.xml")/chapter[title = "Frogs"]//figref/@refid->fig/caption
LET $tagname := name($e) RETURN <$tagname> $e/@*, 2 * number($e) </$tagname>
FOR/LET : servono per assegnare un valore ad una o più variabili referenziate nella query, mentre il FOR assegna un valore alla volta alla variabile, LET assegna una lista di nodi:
FOR $x IN /library/book
comporta tanti assegnamenti ad $x quanti sono i book in library
LET $x := /library/book results in a single binding
comporta il singolo assegnamento della lista dei book a $x.
Un espressione FLWR può contenere molte proposizioni FOR e LET. Il risultato della sequenza di FOR e LET è una lista di tuple di variabili assegnate.
WHERE: Solo le tuple per cui le condizioni della sezione WHERE è vera sono usate nella sezione RETURN.I predicati presenti in questa sezione possono essere collegati conn AND, OR, e NOT.
RETURN: Genera l'output della query, che può essere un nodo, un insieme di nodi o un valore primitivo.
Vediamo alcuni esempi:
(Q9) Titoli dei libri publicati da Morgan Kaufmann nel 1998.
FOR $b IN document("bib.xml")//book
WHERE $b/publisher = "Morgan Kaufmann"
AND $b/year = "1998"
RETURN $b/title
(Q13) Per ogni libro che ha un prezzo maggiore del prezzo medio,
ritorniamo il titolo del libro e la differenza fra il suo prezzo e il prezzo
medio.
<result> LET $a := avg(//book/price) FOR $b IN /book WHERE $b/price > $a RETURN <expensive_book> $b/title , <price_difference> $b/price - $a </price_difference> </expensive_book> </result>(Q15) Per ogni editore, visualizziamo i libri che ha pubblicato ordinati in base al prezzo dal più caro al più economico.Gli editori sono elencati in ordine alfabetico.
<publisher_list>
FOR $p IN distinct(document("bib.xml")//publisher)
RETURN
<publisher>
<name> $p/text() </name> ,
FOR $b IN document("bib.xml")//book[publisher = $p]
RETURN
<book>
$b/title ,
$b/price
</book> SORTBY(price DESCENDING)
</publisher> SORTBY(name)
</publisher_list>
(Q16) Tutti gli elementi presenti tra l'occorrenza del primo ed il secondo elemento incisionnella prima occorrenza di procedure.
<critical_sequence> LET $p := //procedure[1] FOR $e IN //* AFTER ($p//incision)[1] BEFORE ($p//incision)[2] RETURN shallow($e) </critical_sequence>La funzione shallow fa una copia del nodo,includendogli attributi ma non gli elementi figli.
FOR $h IN //holding RETURN <holding> $h/title, IF $h/@type = "Journal" THEN $h/editor ELSE $h/author </holding> SORTBY (title)come ogni espressione XQuery, le espressioni condizionali si possono trovare dovunque è atteso un valore.
(Q19) Trovare i titoli dei libri nei quali ESISTE un paragrafo che contiene le parole sailing e windsurfing.
FOR $b IN //book WHERE SOME $p IN $b//para SATISFIES contains($p, "sailing") AND contains($p, "windsurfing") RETURN $b/title(Q20) Trovare i titoli dei libri nei quali la parola sailing è menzionata in TUTTI i paragrafi.
FOR $b IN //book WHERE EVERY $p IN $b//para SATISFIES contains($p, "sailing") RETURN $b/title
LET $b := document("cookbook.xml")
RETURN
<toc>
filter($b, $b//section | $b//section/title | $b//section/title/text() )
</toc>
Alcuni tipi di dati sono automaticamente riconosciuti da XQuery:
| Type | Example of literal |
| xsd:string | "Hello" |
| xsd:boolean | TRUE, FALSE |
| xsd:integer | 47, -369 |
| xsd:decimal | -2.57 |
| xsd:float | -3.805E-2 |
mentre gli altri hanno bisogno di un costruttore: date("2000-06-25").
N.B: Non tutti i costruttori sono stati definiti.
(Q22) Trovare la massima profondità del documento "partlist.xml."
NAMESPACE xsd = "http://www.w3.org/2000/10/XMLSchema-datatypes"
FUNCTION depth(ELEMENT $e) RETURNS xsd:integer
{
-- An empty element has depth 1
-- Otherwise, add 1 to max depth of children
IF empty($e/*) THEN 1
ELSE max(depth($e/*)) + 1
}
depth(document("partlist.xml"))
Una query si può riferire a qualsiasi elemento o tipo definito in uno schema che:
NAMESPACE xsd = "http://www.w3.org/2000/10/XMLSchema-datatypes".
<?xml version="1.0"> <schema xmlns="http://www.w3.org/2000/10/XMLSchema" <!--namespace di default--> targetNamespace="http://www.BigCompany.com/BigNames"> <complexType name="emp_type"> <sequence> <element name="name" type="string"/> <element name="deptno" type="string"/> <element name="salary" type="decimal"/> <element name="location" type="string"/> </sequence> </complexType> <complexType name="dept_type"> <sequence> <element name="deptno" type="string"/> <element name="headcount" type="integer"/> <element name="payroll" type="decimal"/> </sequence> </complexType> </schema>(Q26) Usando lo schema definito, definiamo una funzione che ritorna il numero di impiegati per diupartimento e il loro costo totale.
NAMESPACE DEFAULT = "http://www.BigCompany.com/BigNames"
FUNCTION summary(LIST(emp_type) $emps) RETURNS LIST(dept_type)
{
FOR $d IN distinct($emps/deptno)
LET $e := $emps[deptno = $d]
RETURN
<dept>
$d,
<headcount> count($e) </headcount>,
<payroll> sum($e/salary) </payroll>
</dept>
}
summary(document("acme_corp.xml")/emp[location = "Denver"] )
$x INSTANCEOF zoonames:animal
è True se il tipo dinamico di $x è zoonames:animal o un tipo derivato da zoonames:animal. INSTANCEOF ha la stessa sintassi di instanceof in Java.
Per i tipi primiti e derivati di XML Schema si può usare l'operatore CAST . Per esempio: CAST AS integer (x DIV y) converte il risultato di x DIV y nel tipo integer. L'insieme dei tipi supportati da CAST sono ancora da definire. CAST non può essere usata per i tipi definiti dall'utente.
TREAT dice al processatore della query di trattare un espressione come se avesse come tipo uno dei tipi derivati dal suo tipo statico. Per esempio TREAT AS Cat($mypet) dice di trattare $mypet come istanza del tipo Cat, anche se il suo tipo è un supertipo di Cat ad esempio Animal.
-- First define some functions to set the stage
NAMESPACE xsd = "http://www.w3.org/2000/10/XMLSchema-datatypes"
FUNCTION quack(duck $d) RETURNS xsd:string
{ "String depends on properties of duck" }
FUNCTION woof(dog $d) RETURNS xsd:string
{ "String depends on properties of dog" }
--This function illustrates simulated subtype polymorphism
FUNCTION sound(animal $a) RETURNS xsd:string
{
IF $a INSTANCEOF duck THEN quack(TREAT AS duck($a))
ELSE IF $a INSTANCEOF dog THEN woof(TREAT AS dog($a))
ELSE "No sound"
}
-- This query returns the sounds made by all of Billy's pets
FOR $p IN /kid[name="Billy"]/pet
RETURN sound($p)
Consideriamo il seguente schema relazionale:
S(sno,sname)
P(pno,descrip)
SP(sno,pno,price)
S contiene i dati sui fornitori (suppliers); P contiene le informazioni su le parti fornite e SP rappresenta la relazzione fra le prime due tabelle.
Una possibile tarduzione in XML è la seguente:
<s> <s_tuple> <sno> <sname>
<p> <p_tuple> <pno> <descrip>
<sp> <sp_tuple> <sno> <pno> <price>(Q29) Esempio di Selezione
SQL:
SELECT pno FROM p WHERE descrip LIKE 'Gear' ORDER BY pno;XQuery:
FOR $p IN document("p.xml")//p_tuple
WHERE contains($p/descrip, "Gear")
RETURN $p/pno SORTBY(.)
"SORTBY(.)", significa ordina gli elementi <pno> in base al loro contenuto.
SQL:
SELECT pno, avg(price) AS avgprice FROM sp GROUP BY pno HAVING count(*) >= 3 ORDER BY pno;XQuery:
FOR $pn IN distinct(document("sp.xml")//pno)
LET $sp := document("sp.xml")//sp_tuple[pno = $pn]
WHERE count($sp) >= 3
RETURN
<well_supplied_item>
$pn,
<avgprice> avg($sp/price) </avgprice>
</well_supplied_item> SORTBY(pno)
FOR $sp IN document("sp.xml")//sp_tuple,
$p IN document("p.xml")//p_tuple[pno = $sp/pno],
$s IN document("s.xml")//s_tuple[sno = $sp/sno]
RETURN
<sp_pair>
$s/sname ,
$p/descrip
</sp_pair> SORTBY (sname, descrip)
Q31 ritorna informazioni solo sui pezzi che hanno un fornitore e
dei fornitori che forniscono almeno un pezzo.
(Q32) Left Outer Join, mostriamo anche i fornitori che non forniscono alcun pezzo.
FOR $s IN document("s.xml")//s_tuple
RETURN
<supplier>
$s/sname,
FOR $sp IN document("sp.xml")//sp_tuple[sno = $s/sno],
$p IN document("p.xml")//p_tuple[pno = $sp/pno]
RETURN $p/descrip SORTBY(.)
</supplier> SORTBY(sname)
In sostituzione dei dati mancanti SQL usa il valore NULL, mentre una query
XML potrebbe rappresentare la mancanza di informazioni con un elemento
vuoto o l'assenza dell'elemento.
(Q33) Full Outer Join
<master_list>
(FOR $s IN document("s.xml")//s_tuple
RETURN
<supplier>
$s/sname,
FOR $sp IN document("sp.xml")//sp_tuple[sno = $s/sno],
$p IN document("p.xml")//p_tuple[pno = $sp/pno]
RETURN
<part>
$p/descrip,
$sp/price
</part> SORTBY (descrip)
</supplier> SORTBY(sname)
)
UNION
-- parts that have no supplier
<orphan_parts>
FOR $p IN document("p.xml")//p_tuple
WHERE empty(document("sp.xml")//sp_tuple[pno = $p/pno])
RETURN $p/descrip SORTBY(.)
</orphan_parts>
</master_list>
Le future versioni di XQuery potrebbero includere ulteriori funzionalità, tra le quali: