• In general, un document XML este stocat ca fisier individual sau intr-o baza de date relationala / obiect-relationala.
• => Nevoia de a interoga datele XML asa cum se interogheaza structurile relationale.
C07 - DS
interogheaza structurile relationale.
• Astfel ca a fost nevoie de un limbaj specializat in interogarea datelor XML (stocate in fisiere externe sau stocate in coloane de tip XML, pe server-e ca SQL-Server sau Oracle).
XQuery = XML Query Language
– XQuery foloseste constructii XPath ca si sintaxa de localizare si, in plus, introduce constructii gen SQL pentru facilitati in interogarea datelor.
Observatii:– Sunt situatii in care XPath + XSLT ofera o mai buna interogare a datelor,
dar sunt si situatii in care mai bine se descurca XQuery.
C07 - DS
dar sunt si situatii in care mai bine se descurca XQuery.– SELECT-SQL este bazat pe algebra relationala – este specializat sa
interogheze date in structuri relationale; nu este facut sa interogheze structuri ierarhice, gen XML.
– Specificatii generale XQuery: este un limbaj non-procedural; exista o sintaxa XML pentru limbajul de interogare s.a.
– In primii ani de dezvoltare a XQuery s-au elaborat n specificatii. Aceste documente incearca sa cuprinda cat mai bine o specificatie XQuery.
– XQuery este inca in curs de dezvoltare (sau parti din el), specificatiile sunt complexe, dar se spera catre o clarificare si o simplificare a acestora. ☺(currently in Last Call)
– (Vezi: http://www.w3.org/XML/Query/)
• XQuery = 3 limbaje in 1:– sintaxa „surface” – sintaxa „human readable” care se aseamana cu
SQL pentru bd relationale– sintaxa alternativa XML-based (inca in dezvoltare sau dezvoltata)– limbaj formal algebric – defineste formal semanticile XQuery
C07 - DS
• Cateva reguli de sintaxa– XQuery este case-sensitive (minuscule)– o valoare string se include intre „” sau ‚’– o variabila este precedata de $– comentariile XQuery sunt delimitate de (: comentariu :)
• Documente XML folosite in exemple:
• Profi:
<catedre>
<catedra idc="C1" sefi="P11 P12">
Sisteme Informatice
</catedra>
<catedra idc="C2" sefi="P21">
Limbaje de programare
C07 - DS
Limbaje de programare
</catedra>
<prof idp="P11" cat="C1">
<nume>prof 1</nume>
<birou>333</birou>
<disciplina tip="obl">bd</disciplina>
<disciplina tip="opt">ds</disciplina>
<observatii>obs P1</observatii>
</prof>
<prof idp="P12" cat="C1">
<nume>prof 2</nume>
<birou>406</birou>
<disciplina tip="fac">pdpj</disciplina>
<observatii>obs prof 2</observatii>
</prof>
...
</catedre>
• Documente XML folosite in exemple:
• Produse:
<produse>
<produs idp="P4" categ="C1">
<denumire>basme</denumire>
<pret>55</pret>
<descriere>descriere basme</descriere>
C07 - DS
<descriere>descriere basme</descriere>
</produs>
<produs idp="P6" categ="C2">
<denumire>poezii</denumire>
<pret>100</pret>
<descriere>descriere poezii</descriere>
</produs>
</produse>
• Operatori
• XQuery suporta toti operatorii pentru XPath, plus un set de alti operatori. Dintre acestia:– aritmetici: binari + - * DIV MOD; unari + - data()
– de comparatie: = != < <= > >=
– logici: binari or and; functie unara not()
– sequence-related: paranteze (); secvente , *; range to; node sequences union,
C07 - DS
– sequence-related: paranteze (); secvente , *; range to; node sequences union, intersect, except; before after
• Observatie:
• Comparatii generale: = != < <= > >=
• Comparatii pe valoare: eq ne lt le gt ge
• Diferenta:– $bookstore//book/@q > 10 => intoarce true daca cel putin un atribut book/@q are
valoarea >10
– $bookstore//book/@q gt 10 => intoarce true daca exista un singur atribut intors de expresia XPath si valoarea lui este >10; daca expresia intoarce mai multe atribute, rezultatul este eroare
• Expresii
• Expresii de localizare
• Este tipul de expresie folosit pentru a localiza datele in arborele XML. O
C07 - DS
• Este tipul de expresie folosit pentru a localiza datele in arborele XML. O asemenea expresie returneaza un set de noduri sau o valoare de un tip primitiv (de exemplu: numarul de noduri dintr-un set) si nu returneaza noduri duplicat.
• Exemplu: pentru al 5-lea client, comenzile unui anumit vanzator
document(„nume_doc”)//client[5]/comanda[vanzator=”geo”]
• Expresii constructori de elemente / atribute
• Se poate utiliza XQuery pentru a genera noi elemente, nu doar pentru a cauta (precum in XPath + XSLT).
• O expresie se include intre {} pentru a indica faptul ca aceasta va fi evaluata, si nu doar tratata ca text.
C07 - DS
<rez>
<prof2 catedra="{/catedre/prof[2]/@cat}">
{/catedre/prof[2]/nume/text()}
</prof2>
</rez>
=>
<rez>
<prof2 catedra="C1">prof 2</prof2>
</rez>
• Expresii secventa
• XQuery suporta operatori pentru constructia, filtrarea si combinarea expresiilor.
• Secventele nu sunt imbricate.
C07 - DS
• Exemple de construire:
(10, 1, 2, 3, 4)
(10, (1, 2), (), (3, 4)) (similar)
(10, 1 to 4) (similar)
(salary, bonus) (toti fiii salary + fiii bonus ai elementului de context)
($price, $price) (daca $price=5 atunci (5, 5))
• Expresii secventa
• Filtrare pe secventa – cu ajutorul predicatelor XPath:
$produse[pret gt 100] (unde $produse contine o secventa de
C07 - DS
$produse[pret gt 100] (unde $produse contine o secventa de
preturi)
(1 to 100)[. mod 5 eq 0] (elementele divizibile cu 5)
(21 to 29)[5] (al 5-lea element al secventei)
$comenzi[fn:position() = (5 to 9)] (elementele de pe
pozitiile de la 5 la 9)
/studenti/student[3]/nume/text() =>> numele celui de-al 3-lea
student din secventa de studenti
• Expresii secventa
• Combinarea secventelor de noduri:
• Exemplu: fie elementele A, B, C si$seq1 este (A, B)
C07 - DS
$seq1 este (A, B)
$seq2 este (A, B)
$seq3 este (B, C)
=>
$seq1 union $seq2 = (A, B)
$seq2 union $seq3 = (A, B, C)
$seq1 intersect $seq2 = (A, B)
$seq2 intersect $seq3 = (B)
$seq1 except $seq2 = empty sequence
$seq2 except $seq3 = (A)
• Expresii FLWR (FLWOR)
• FLWR = for, let, where, return – cuvintele cheie folosite in acest tip de expresii
• Sau• FLWOR = for, let, where, order by, return• (echivalentul lui SELECT – FROM – WHERE – ORDER BY din SQL)
C07 - DS
• (echivalentul lui SELECT – FROM – WHERE – ORDER BY din SQL)
• O asemenea expresie poate sa – atribuie o valoare unei variabile, sa returneze o secventa de noduri sau valori primitive; pot fi folosite pentru a calcula join intre doua sau mai multe documente, pentru restructurarea datelor s.a.
• Contine:– una sau mai multe clauze FOR si/sau LET– o clauza optionala WHERE– o clauza optionala ORDER BY– o clauza RETURN
• Procesarea expresiilor FLWOR:
– FOR / LET Clauses
– ( => lista ordonata de noduri / variabile)
C07 - DS
– WHERE Clause
– ( => lista filtrata de noduri)
– ORDER BY Clause
– ( => lista ordonata de noduri)
– RETURN Clause
• Clauzele FOR
• FOR variabila IN expr_XPath ...
• numele variabilelor incep cu „$”• expr_XPath este o expresie XPath sau o secventa explicita• o variabila FOR ia pe rand ca valoare fiecare obiect din setul de noduri
C07 - DS
• o variabila FOR ia pe rand ca valoare fiecare obiect din setul de noduri returnat de expresia XPath
• tot ce urmeaza dupa FOR este executat o data pentru fiecare valoare a variabilei
• Clauzele FOR
• Urmeaza exemple scrise pe sintaxa SQL-Server; exista un tabel “txml1” care contine o coloana “doc” de tip XML. Metoda “query” aplicata unui XML (dintr-o variabila SQL sau coloana dintr-un tabel) permite executarea de interogari XQuery pe acel XML.
C07 - DS
SELECT iddoc, doc.query('
for $n in //prof/nume
return $n/text()
')
FROM txml1
where iddoc=2
=>
prof 1prof 2prof 3
SELECT iddoc, doc.query('
for $n in //prof/nume
return $n
')
FROM txml1
where iddoc=2
=>
<nume>prof 1</nume>
<nume>prof 2</nume>
<nume>prof 3</nume>
• Clauzele FOR
SELECT iddoc, doc.query('
for $n in (1, 2, 3)
return $n
C07 - DS
')
FROM txml1
where iddoc=2
=>
1 2 3
SELECT iddoc, doc.query('
for $n in (1, 2), $m in (3, 4)
return <pereche>{$n} si {$m}</pereche>
')
FROM txml1
where iddoc=2
=>
<pereche>1 si 3</pereche>
<pereche>1 si 4</pereche>
<pereche>2 si 3</pereche>
<pereche>2 si 4</pereche>
C7. XQuery
• Clauzele LET
• LET variabila:=expresie_XPath
• valoarea variabilei devine setul de noduri intors de expresia XPath (=>
C07 - DS
• valoarea variabilei devine setul de noduri intors de expresia XPath (=> variabila primeste ca valoare o secventa de zero, unul sau mai multe noduri)
• doar clauza LET nu produce iteratie
• Observatie: Clauza LET nu este implementata pe SQL 2005, este implementata pe SQL 2008.
• Clauzele LET
• Exemplu:let $fac:=/facultati/facultate/@denumire
return
C07 - DS
<nume_facultati>{$fac}</nume_facultati>=>
<nume_facultati>Mate-info Fizica ...</nume_facultati>
• Exemplu:let $x:=(1 to 5)
return <test>{$x}</test>
=>
<test>1 2 3 4 5</test>
• Diferenta dintre legarea variabilelor cu FOR / LET:
let $s := (<A/>, <B/>, <C/>)
return <out>{$s}</out>
=>
<out>
<A/> <B/> <C/>
C07 - DS
<A/> <B/> <C/>
</out>
Si
for $s in (<A/>, <B/>, <C/>)
return <out>{$s}</out>
=>
<out><A/></out>
<out><B/></out>
<out><C/></out>
• Clauza WHERE
• WHERE conditie
Exemplu:for $n in (2,3,4,5), $m in (4,5,6,7,8,9,10)
where ($m mod $n=0)
C07 - DS
where ($m mod $n=0)
return
<pereche>
<divizibile>{$m} si {$n}</divizibile>
</pereche>
=><pereche>
<divizibile>4 si 2</divizibile>
</pereche>
<pereche>
<divizibile>6 si 2</divizibile>
</pereche>
...
• Clauza ORDER BY
• Cu „order by” se poate sorta rezultatul unui query, in functie de una sau mai multe expresii, ascendent (implicit) sau descendent.
C07 - DS
• ORDER BY criteriu_ordonare [ascendent|descendent]
• Clauza ORDER BY
Exemplu:
for $n in (2,3,4,5), $m in (4,5,6,7,8,9,10)
C07 - DS
where ($m mod $n = 0)
order by $m
return
<pereche>
<divizibile>
{$m} si {$n}
</divizibile>
</pereche>
=>
<pereche>
<divizibile>4 si 2</divizibile>
</pereche>
<pereche>
<divizibile>4 si 4</divizibile>
</pereche>
<pereche>
<divizibile>5 si 5</divizibile>
</pereche>
...
• Clauza ORDER BY
• Exemplu:
<rezultat>
{
for $p in ("ioana", "alin", "vali", "maria")
C07 - DS
for $p in ("ioana", "alin", "vali", "maria")
order by $p
return $p
}
</rezultat>
=>
<rezultat>alin ioana maria vali</rezultat>
• Clauza ORDER BY
• Exemplu:
<rezultat>
{
C07 - DS
{
for $p in ("ioana", "alin", "vali", "maria")
order by $p
return
<prenume>
{$p}
</prenume>
}
</rezultat>
=>
<rezultat>
<prenume>alin</prenume>
<prenume>ioana</prenume>
<prenume>maria</prenume>
<prenume>vali</prenume>
</rezultat>
• Expresii conditionale
• Sunt structuri if-then-else de forma:
if (conditie)
C07 - DS
if (conditie)
then output1
else output2
• Clauza else este obligatorie. Daca nu este nimic de scris pentru ea, se lasa else ().
• Expresii conditionale
• Exemplu:for $n in (2,3,4,5), $m in (4,5,6,7,8,9,10)
return
<pereche>
{
C07 - DS
{
if ($m mod $n=0)
then <divizibile>{$m} si {$n}</divizibile>
else ()
}
</pereche>
<pereche>
<divizibile>4 si 2</divizibile>
</pereche>
<pereche />
<pereche>
<divizibile>6 si 2</divizibile>
</pereche>
<pereche />
...
• Exemplu
<profi>
{
for $n in //prof
return
<prof>
<profi>
<prof>
<cat>catedra 1</cat>
<nume_prof>prof 1</nume_prof>
C07 - DS
<prof>
{
if ($n/@cat="C1")
then <cat>catedra 1</cat>
else <cat>catedra 2</cat>
}
<nume_prof>
{$n/nume/text()}
</nume_prof>
</prof>
}
</profi>
<nume_prof>prof 1</nume_prof>
</prof>
<prof>
<cat>catedra 1</cat>
<nume_prof>prof 2</nume_prof>
</prof>
<prof>
<cat>catedra 2</cat>
<nume_prof>prof 3</nume_prof>
</prof>
</profi>
• Expresii cuantificate
• Expresiile cuantificate introduc cuvintele cheie „some” si „every”; acestea reprezinta cuantificatorii existential & universal.
C07 - DS
• Cuvantul „some” testeaza existenta a cel putin unui element care satisface o anumita conditie.
• Cuvantul „every” verifica daca toate elementele verifica o conditie.
• Exemplu: daca un prof are cel putin o disciplina de tip obligatoriu, ii afiseaza toate disciplinele predate
SELECT iddoc, doc.query('
<rezultat>
{
for $p in //prof
C07 - DS
for $p in //prof
where some $disc in $p/disciplina/@tip
satisfies ($disc="obl")
return
<element>
{$p/disciplina}
</element>
}
</rezultat>
')
FROM txml1
where iddoc=8
<rezultat>
<element>
<disciplina tip="obl">bd</disciplina>
<disciplina tip="opt">ds</disciplina>
</element>
</rezultat>
• Exemplu:
SELECT iddoc, doc.query('
<rezultat>
{
for $p in //prof
where every $disc in $p/disciplina/@tip
C07 - DS
where every $disc in $p/disciplina/@tip
satisfies ($disc="obl")
return
<element>
{$p/disciplina}
</element>
}
</rezultat>
')
FROM txml1
where iddoc=1
<rezultat />
• Exemplu: evaluare pe 9 tuple
some $x in (1, 2, 3), $y in (2, 3, 4)
satisfies $x + $y = 4
=> true
C07 - DS
=> true
every $x in (1, 2, 3), $y in (2, 3, 4)
satisfies $x + $y = 4
=> false
• Functii
• XQuery include functiile XPath, plus unele particulare, precum:
– functii de agregare: count() sum() avg() min() max()
– distinct() – elimina nodurile duplicat
C07 - DS
– distinct() – elimina nodurile duplicat
– empty() – intoarce True daca este o secventa de noduri goala
• Observatie: Se ofera posibilitatea de a definii functii proprii (user-defined) – de exemplu – pe SQL-Server 2008
• Exemplu:
select doc.query('
<facultate>
{
for $s in distinct-values(//student/cods)
order by $s
C07 - DS
return
<sectie>
<cod>{$s}</cod>
<denumire>{//sectie[cods = $s]/denumires/text()}
</denumire>
<nrstuds>{count(//student[cods = $s])}</nrstuds>
</sectie>
}
</facultate>
')
from txml where iddoc=4
• Exemplu:
C07 - DS
<facultate>
<sectie>
<cod>1</cod>
<denumire>Matematicã</denumire>
<nrstuds>4</nrstuds>
</sectie>
<sectie><sectie>
<cod>2</cod>
<denumire>Informaticã</denumire>
<nrstuds>11</nrstuds>
</sectie>
<sectie>
<cod>3</cod>
<denumire>Matematicã-Informaticã</denumire>
<nrstuds>10</nrstuds>
</sectie>
</facultate>
• Exemplu:
SELECT iddoc, doc.query('
<rezultate>
{
for $s in /studenti/student
return
<rezultat>
C07 - DS
<rezultat>
<nume>{$s/nume/text()}</nume>
<nr_note>{count($s/nota)}</nr_note>
<nota_min>{min($s/nota/valoare)}</nota_min>
<nota_max>{max($s/nota/valoare)}</nota_max>
<media_calc>{avg($s/nota/valoare)}</media_calc>
<media_data>{$s/media/text()}</media_data>
</rezultat>
}
</rezultate>
')
FROM txml1 where iddoc=3
• Exemplu:
C07 - DS
<rezultate>
<rezultat>
<nume>stud 1</nume>
<nr_note>3</nr_note>
<nota_min>8</nota_min>
<nota_max>10</nota_max>
<media_calc>9</media_calc><media_calc>9</media_calc>
<media_data />
</rezultat>
<rezultat>
<nume>stud 4</nume>
<nr_note>1</nr_note>
<nota_min>10</nota_min>
<nota_max>10</nota_max>
<media_calc>10</media_calc>
<media_data />
</rezultat>
</rezultate>
• Exemplu – not in / not exists: sectiile in care nu exista nici un student
select doc.query('
<facultate>
{
for $s in /root/sectie
where empty(/root/student[sectie=$s/cods])
C07 - DS
where empty(/root/student[sectie=$s/cods])
return
<info_sectie>
<sectie>{$s/denumires/text()}</sectie>
</info_sectie>
}
</facultate>
')
from txml1 where iddoc=4
<facultate>
<info_sectie>
<sectie>mate-info</sectie>
</info_sectie>
</facultate>
• Exemplu – “left join”: sunt afisate toate sectiile, si pentru fiecare sectie ii sunt afisati studentii (posibil multime vida)
select doc.query('
<facultate>
{
for $s in /root/sectie
return
<info_sectie>
C07 - DS
<info_sectie>
<sectie>{$s/denumires/text()}</sectie>
<studenti>
{
for $st in /root/student
where $s/cods=$st/sectie
return $st/nume
}
</studenti>
</info_sectie>
}
</facultate>
')
from txml1 where iddoc=4
• Exemplu:
<facultate>
<info_sectie>
<sectie>info</sectie>
<studenti>
C07 - DS
<studenti>
<nume>stud 1</nume>
<nume>stud 2</nume>
</studenti>
</info_sectie>
<info_sectie>
<sectie>info</sectie>
<studenti>
<nume>stud 4</nume>
</studenti>
</info_sectie>
<info_sectie>
<sectie>info</sectie>
<studenti />
</info_sectie>
</facultate>
• Exemplu – inner join: sunt afisate toate sectiile in care sunt studenti, si acesti studenti
select doc.query('
<facultate>
{
for $s in /studenti/sectie
where not(empty(/studenti/student[sectie=$s/cods]))
return
<info_sectie>
C07 - DS
<info_sectie>
<sectie>{$s/denumires/text()}</sectie>
<studenti>
{
for $st in /studenti/student
where $s/cods=$st/sectie
return $st/nume
}
</studenti>
</info_sectie>
}
</facultate>
')
from txml1 where iddoc=4
• Exemplu:
<facultate>
<info_sectie>
<sectie>info</sectie>
<studenti>
<nume>stud 1</nume>
C07 - DS
<nume>stud 1</nume>
<nume>stud 2</nume>
</studenti>
</info_sectie>
<info_sectie>
<sectie>mate</sectie>
<studenti>
<nume>stud 4</nume>
</studenti>
</info_sectie>
</facultate>
• Exemplu – inner join: sunt afisate toate sectiile in care sunt studenti, si acesti studenti
select doc.query
('<r>
C07 - DS
('<r>
{
for $se in //sectii, $st in //studenti[CodS=$se/CodS]
return ($se, $st)
}
</r>')
from txml1
where iddoc = 10
<r>
<sectii>
<CodS>1</CodS>
<DenumireS>Matematicã</DenumireS>
</sectii>
<studenti>
<CodS>1</CodS>
<NrMatricol>8481</NrMatricol>
<Nume>Alexandru Ionel</Nume>
C07 - DS
<sectii>
<CodS>2</CodS>
<DenumireS>Informaticã</DenumireS>
</sectii>
<studenti>
<CodS>2</CodS>
<NrMatricol>9259</NrMatricol>
<Nume>Lazar Paul-Daniel</Nume>
......
</studenti>
<sectii>
<CodS>1</CodS>
<DenumireS>Matematicã</DenumireS>
</sectii>
<studenti>
<CodS>1</CodS>
<NrMatricol>9105</NrMatricol>
<Nume>Muntean Alexandra</Nume>
...
</studenti>
...
</studenti>
<sectii>
<CodS>2</CodS>
<DenumireS>Informaticã</DenumireS>
</sectii>
<studenti>
<CodS>2</CodS>
<NrMatricol>9275</NrMatricol>
<Nume>Micu Ofelia-Emanuela</Nume>
...
</studenti>
...
</r>
Doar sectiile care au studenti