Distanční opora předmětu: Databázové systémy Tématický blok č. 5: Dotazovací jazyk XPath Autor: RNDr. Jan Lánský, Ph.D. Obsah kapitoly 1 XPath 1.1 Cesta 1.2 Osy 1.3 Test uzlu 1.4 Podmínka 1.5 Vestavěné funkce 2 XPath v SQL Serveru Studijní cíle Cíle nutné k zahájení studia dalšího tématického bloku Schopnost vytvořit XPath dotaz s využitím os child, parent, descendant-or-self a atribute. V XPath dotazu schopnost použít podmínku testující existenci uzlu nebo porovnávající hodnotu uzlu s konstantou. Schopnost vyhodnotit XPath dotaz nad XML daty v SQL Serveru. Další cíle Využití vestavěných funkcí v XPath dotazu. Znalost všech XPath os. Schopnost modifikace XML dat (vložení, smazání kusu XML dokumentu) v SQL Serveru pomocí XPath dotazu.
Čas potřebný ke studiu 2 - 6 hodiny na prostudování výukových textů + zodpovězení otázek k rekapitulaci 1 - 3 hodiny na vypracování modelových úloh na PC 1 hodina na praktické zopakování učiva na PC ( v jiný den) 30 min - 1 hodina na (znovu)zodpovězení otázek k rekapitulaci (v jiný den) Časy jsou hodně individuální a jsou závislé na míře znalostí z oblasti databázových systémů získaných během bakalářského studia.
Úvod V tomto bloku probereme následující témata. Nejprve se seznámíme se stromovým modelem XML dokumentu, který je využíván pro XPath dotazy. Vysvětlíme si pojmy cesta a krok, na jednoduchých příkladech probereme osy child a attribute. Vysvětlíme si všech 12 os. Naučíme se testovat množinu uzlů získanou pomocí osy na typ a název uzlu. Naučíme se používat podmínky, které redukují množinu uzlů získanou pomocí osy a testu uzlu. Probereme některé z vestavěných funkcí, které se dají použít v podmínce. Naučíme se používat XPath pro dotazování nad XML daty uloženými v SQL Serveru. Naučíme se používat XPath pro modifikaci dokumentů (insert, delete) v SQL Serveru. Výkladová část Vysvětlivky Červený text – Porušením nebo opomenutím takto označených pravidel vznikají těžko odladitelné chyby (zejména pro začínající programátory). Modrý text – Doporučení jak programovat v praxi. Často prevence závažných chyb. 1 XPath XPath je dotazovací jazyk nad XML dokumenty. Výsledkem dotazů v jazyce XPath je část XML dokumentu. Základní myšlenka tohoto jazyka je založena na pohybu ve stromovitém modelu dokumentu, obdoba pohybu v systému souborů. Dotaz lze chápat jako cestu k určité části XML dokumentu. Na jazyku XPath je založeno mnoho dalších XML technologií, například XQuery či XSLT. Na slajdu č. 5 vidíme příklad XML dokumentu, jehož stromový model budeme vytvářet pro účely dotazování v jazyce XPath.. Na slajdech č. 6 – 11 vidíme jak postupně model vzniká. Model je vždy zobrazen v pravé polovině slajdu, červeně označené řádky XML dokumentu jsou aktuálně na daném slajdu do modelu přidávané. Na slajdu č. 12 je zobrazen již celý hotový model. Jedná se o strom, ve kterém jsou uzly reprezentující celý dokument, elementy, atributy, nebo textový obsah elementů. Kořen stromu document reprezentuje celý XML dokument a je označen modře, má jediného syna kořenový element dokumentu objednávka. Zelenou barvu mají uzly elementů. Oranžově jsou obarveny uzly atributů, hodnoty atributů jsou uvedeny pod těmito uzly. Šedou barvu mají uzly pro textový obsah, konkrétní text je uveden opět pod těmito uzly. Model může obsahovat ještě uzly pro komentáře, uzly pro proveditelné konstrukce a uzly pro jmenné prostory, žádný z těchto typů uzlů se však na našem obrázku nenachází. Model neobsahuje sekce CDATA, odkazy na entity a DTD.
Přestože atributy (oranžově označené) v modelu vypadají jako potomkové svých elementů, z hlediska využití tohoto stromu po dotazy v jazyku XPath nejsou jako jejich potomci brány. 1.1 Cesta Výrazem v jazyce Xpath je cesta, která se skládá s kroků. Cesta může být absolutní (začínající v kořeni stromu) nebo relativní (a k ní musí být známa množina uzlů, ze kterých se má startovat). Jednotlivé kroky cesty se oddělují symbolem lomítka (/) a reprezentují jednotlivé uzly v modelu dokumentu. Návratovou hodnotou cesty je množina uzlů. Výsledek není uspořádán a může být zobrazeno jeho pořadí, které je různé od pořadí elementů v dokumentu. Na slajdech č. 16 – 19 je na stromovém modelu dokumentu znázorněno postupné vyhodnocování cesty /objednavka/polozky/polozka/cena/@kod. Elementy, které jsou právě vyhodnocovány v daném kroku cesty jsou ve stromovém modelu označeny červeným rámečkem. Cesta obsahující samotný symbol / označuje celý dokument (situace na slajdu č. 16). Na slajdu č. 17 obsahuje cesta /objednavka navíc element objednavka. Na slajdu č. 18 jsme cestu /objednavka/polozky/polozka rozšířili o dva kroky najednou. Nejprve jsme přistoupili k elementu polozky, který je potomkem elementu objednavka. Poté jsme zároveň přistoupili k oběma elementům polozka, které jsou potomky elementu polozky. Na tomto příkladu vidíme, že jeho výsledkem cesty může být i množina elementů, nejen jeden samotný element. Celá cesta /objednavka/polozky/polozka/cena/@kod je vyhodnocena na slajdu č. 19. Nově přibyl poslední krok @kod. Operátor @ značí přístup k atributu. Výsledkem dotazu jsou oba atributy kod patřící oběma dvěma elementům polozka. Na slajdu č. 20 vidíme podobný příklad. Pouze v posledním kroku cesty je nahrazen @kod za text() značící textový obsah elementu. Na slajdu č. 21 je poslední krok nahrazen za barva. Tento element se nachází jako podelement pouze u jednoho (pravého) ze dvou elementu polozka získaných v předchozím kroku cesty. Na slajdech č. 22 a 23 jsou cesty, jejichž výsledkem je prázdná množina elementů. V obou dvou případech je v cestě jako krok použit element, který se v dokumentu vůbec nevyskytuje. Na slajdech č. 25 – 28 jsou různé výsledky vyhodnocení relativní cesty cena/text() vzhledem k různým počátečním množinám elementů, pro které vyhodnocování probíhá. Elementy patřící do počáteční množiny jsou označeny na slajdu červenou šipkou. Na slajdu č. 27 je výsledkem prázdná množina. 1.2 Osy V předchozí kapitole jsme si ukázali, že krokem XPath výrazu je přechod od rodičovského elementu na jeden nebo více elementů, které jsou jeho potomky. Jednalo se pouze o speciální příklad XPath kroku, ve skutečnosti je syntax bohatší. XPath krok je definován jako osa::test-uzlu podmínka. Osa udává požadovaný vztah hledaných uzlů vzhledem k danému počátečnímu uzlu v rámci stromového modelu XML
dokumentu. Test uzlu omezuje množinu konkrétních kandidátů (uzlů) daných konkrétní osou na uzly daného typu a případně názvu. Podmínka pak specifikuje pokročilé požadavky na uzly, které byly vybrány osou a prošly testem uzlu. Podmínek smí být použito i více. V našich příkladech byla podmínka prázdná, osa byla defaultní (tedy nebyla uvedena). Defaultní osa se nazývá child. Na slajdu č. 32 dole v rámečku vidíme dva možné zápisy dotazu využívající tuto osu. První zápis je zkrácený, se kterým jsme se již seznámily, druhý zápis je plný. Na slajdech č. 33 – 46 jsou představeny další osy. Červenou šipkou je označen uzel (budeme mu říkat uzel u), pro který se daný krok cesty vyhodnocuje. Červenými rámečky jsou označeny uzly, které jsou výsledkem daného kroku dotazu. Výsledkem použití osy self (slajd č. 33) je samotný uzel u. Výsledkem použití osy parent (slajd č. 34) je rodič uzlu u. Výsledkem použití osy ancestor (slajd č. 35) jsou všichni předci uzlu u, tedy všechny uzly ležící na cestě od kořene k uzlu u. Výsledkem použití osy ancestor-or-self (slajd č. 36) jsou všichni předci uzlu u včetně uzlu u. Výsledkem použití osy child (slajd č. 37) jsou všechny děti uzlu u. Výsledkem použití osy descendant (slajdy č. 38 a 39) jsou všichni potomci uzlu u. Výsledkem použití osy descendant-or-self (slajd č. 40) jsou všichni potomci uzlu u včetně uzlu u. Na slajdu č. 41 je znázorněno očíslování uzlu stromového modelu XML dokumentu pomocí algoritmu DFS (průchod stromem do hloubky). Čísla uzlů jsou uvedena nahoře vlevo u každého z nich. Toto očíslování uzlů se využívá u následujících několika os. Výsledkem použití osy preceding-sibling (slajd č. 42) jsou všichni sourozenci uzlu u, kteří mají nižší číslo přidělené průchodem stromu do hloubky. Sourozenci, kteří se nacházejí v dokumentu před uzlem u. Výsledkem použití osy preceding (slajd č. 43) jsou všechny uzly, které mají nižší číslo přidělené průchodem stromu do hloubky než jaké je přiděleno uzlu u. Uzly, které se nacházejí v dokumentu před uzlem u. Výsledkem použití osy following-sibling (slajd č. 44) jsou všichni sourozenci uzlu u, kteří mají vyšší číslo přidělené průchodem stromu do hloubky. Sourozenci, kteří se nacházejí v dokumentu za uzlem u. Výsledkem použití osy following (slajd č. 45) jsou všechny uzly, které mají vyšší číslo přidělené průchodem stromu do hloubky než jaké je přiděleno uzlu u. Uzly, které se nacházejí v dokumentu za uzlem u. Výsledkem použití osy attribute (slajd č. 45) jsou všechny atributy uzlu u. Tato osa jako jediná vybírá do výsledku atributy, všechny ostatní osy atributy ignorují. 1.3 Test uzlu Po výběru množiny uzlů za použití příslušné osy přichází na řadu test těchto vybraných uzlů. Testuje se typ uzlu, případně i jeho název. Zatím jsme se seznámili pouze s testem na přesný název uzlu (kapitola 1.1) Testem node() úspěšně projdou všechny uzly vybrané osou. Na slajdu č. 51 vidíme vybrání všech potomků (osa descendent) uzlu položky. Testem text() úspěšně projdou všechny textové uzly vybrané osou. Na slajdu č. 53 vidíme vybrání všech textových uzlů, které jsou potomky položky.
Testem * projdou všechny uzly vybrané osou, které mají jméno. Jméno mají všechny elementy i atributy, ale neexistuje osa, které by vybírala z obou skupin zároveň. Nepojmenované jsou uzly s textovým obsahem, ty vybrány nebudou nikdy. Na slajdu č. 55 vidíme vybrání všech pojmenovaných elementových potomků uzlu položky. Na slajdu č. 57 vidíme zkrácené zápisy pro některé kombinace os a testů uzlů. Písmeno P značí předchozí část cesty. Na prvním řádku je název osy vynechán, použije se defaultní osa child (s tímto zápisem jsme se již seznámili) na druhém řádku symbolem @ nahrazujeme osu attribute. Na třetím řádku pomocí dvou teček (..) nahrazujeme plný zápis pro vybrání rodičovského uzlu použití osy parent. Jedná se o analogii pro přístup k rodičovskému adresáři v souborovém systému. Na čtvrtém řádku vidíme prázdný krok //, což je zkrácený zápis pro přeskočení libovolného množství potomků. Často se používá zápis //název pro vybrání všech uzlů daného jména název v celém dokumentu bez ohledu na jejich umístění 1.4 Podmínka Po výběru množiny uzlů za použití příslušné osy a jejich otestování podle typu uzlu může nepovinně následovat podmínka (slajd č. 58), která z množiny uzlů odstraní ty uzly, která ji nesplňují. Podmínek smí být použito více za sebou. Podmínka se nachází v hranatých závorkách [ ] a může být i složená za použití logických spojek and, or a not. V případě spojky not je nutné negovanou podmínku navíc uzávorkovat kulatými závorkami. Podmínkou může být relativní (vzhledem ke zpracovávanému uzlu) XPath cesta. Tento typ podmínky je vyhodnocen jako splněný, pokud množina uzlů daná relativní cestou v podmínce je neprázdná. Na slajdu č. 60 vidíme příklad na tento typ podmínky (existence uzlu daného relativní cestou). Dotaz na slajdu vybere ty uzly položka, které obsahují atribut kód. Do výsledné množiny uzlů jsou zařazeny oba uzly položka, které se v dokumentu nacházejí. Na slajdu č. 61 je podobný dotaz. Vybíráme uzly položka, které obsahují atribut cena. Tuto podmínku splňuje pouze jeden uzel (levý). Na slajdu č. 62 vidíme opět použití relativní cesty v podmínce dotazu. Testujeme zda dědeček uzlu položka obsahuje atribut stav. Na slajd č. 63 testujeme zda některý ze předků uzlu položka obsahuje atribut stav. V našem stromovém modelu XML dokumentu je výsledek dotazu shodný s předchozím dotazem, v obecném XML dokumentu se mohou lišit. Na slajdu č. 64 je opět výsledek dotazu shodný s předchozími dvěma dotazy, ale v obecném XML dokumentu se výsledek může lišit. V podmínce můžeme také porovnávat relativní XPath cestu (k atributu nebo elementu) s hodnotou pomocí operátorů =, !=, <, >, <=, >=. Pokud je operandem element, jeho hodnotou pro porovnávání je jeho textový obsah. V podmínce lze také použít operátory &eq; ≠ < > ≤ ≥ pro porovnání dvou hodnot.(nesmí se jednat o uzly). Pokud by jedním z jejich operandů byl uzel, převede se na textovou hodnotu. Tyto operátory bývají častěji použity chybně, než správně a úmyslně. Na slajdu č. 66 vidíme dotaz vyhledávající uzly položka, které obsahují element barva s hodnotou textového obsahu modrá. Na slajdu č. 67 vidíme dotaz vyhledávající uzly položka, které obsahují element cena s hodnotou textového obsahu (který se automaticky
konvertuje na číslo) větším než 30. Výsledek dotazu je prázdný. Na slajdu č. 67 vidíme složitější dotaz. Hledáme uzly položka, které mají předka objednávka s hodnotou atributu stav expedován. Na slajdu č. 70 opět vidíme dotaz vyhledávající uzly položka, které obsahují element barva s hodnotou textového obsahu modrá. Na slajdu č. 71 vidíme dotaz, který vrátí ten samý výsledek co předchozí dotaz, přestože jsme v podmínce změnili operátor = na !=. Protože uzel položka obsahuje dva elementy barva, je podmínka splněna pro druhý z elementů barva, který má hodnotu žlutá. Pokud chceme najít uzel položka, který nemá žádný z elementů barva s hodnotou modrá, musíme použít zápis [not (barva = "modrá")]. Na slajdu č. 72 vidíme syntakticky špatný zápis kdy místo operátoru = použijeme eq;. 1.5 Vestavěné funkce V právě zpracovávaném kroku XPath cesty pracujeme s několika uzly. Tyto uzly mají své pořadí dané jejích umístěním v XML dokumentu a směrem použité osy. Voláním funkce position() toto pořadí zjistíme. Voláním funkce last() zjistíme počet uzlů se kterými v daném kroku cesty pracujeme. Na slajdu č. 74 hledáme uzel položka, který je prvním potomek uzlu položky. Na slajdu č. 75 hledáme uzel položka, který je posledním potomek uzlu položky. V obou případech jsme použili funkci position() a její hodnotu jsme porovnali s požadovanou pozicí uzlu. Tento typ podmínky má i svůj zkrácený zápis, ve kterém je celá rovnost nahrazena požadovanou pozicí uzlu. Na slajdech č. 76 a 77 jsou tyto zkrácené zápisy předvedeny. Funkce count vrací počet uzlů, které jsou výsledkem XPath výrazu uvedeného jako její parametr. Na slajdu č. 79 v dotazu hledáme uzly položky, které mají nejméně 3 uzly položka. Na slajdu č, 80 vidíme seznam dalších vestavěných funkcí, jedná se zejména o funkce řetězcové a matematické. 2 XPath v SQL Serveru Práce s XPath v každém databázovém systému bývá řešena rozdílnými způsoby. My si v této kapitole popíšeme situaci v SQL Serveru 2005. V SQL dotazu v klauzuli SELECT můžeme u sloupců datového typu XML použit následující funkce query, exist a value, které vykonají XPath (obecně dokonce XQuery) dotaz na hodnotách daného sloupce (datového typu XML). Funkce query vrací část XML dokumentu, která je výsledkem XPath dotazu aplikovaného na XML dokument, který je hodnotou daného sloupce, na kterém je funkce zavolána. Funkce exist vrací hodnotu 1 pokud je výsledek dotazu tvořen alespoň jedním uzlem. Pokud je výsledkem dotazu prázdná množina, výsledná hodnota je 0. Funkce value má dva parametry, prvním z nich je dotaz a druhým datový typ. Výsledek dotazu (hodnota uzlu) se převede na požadovaný datový typ.
Pokud se tabulka jmenuje XMLTab a sloupec datového typu XML data se jmenuje xml, poté základní dotaz vypadá následovně. SELECT xml.query('text dotazu') FROM XMLTab. Dotaz může být i složitější, může obsahovat i všechny další klauzule. Funkce modify umožňuje mazat nebo vkládat části XML dokumentu v rámci příkazu UPDATE. Jejím parametrem je opět XPath (obecně dokonce XQuery dotaz). Při mazání je doplněn o slovo delete. Při vkládání začínáme slovem insert, následuje kus XML dokumentu, který má být vložen a pokračuje slovem into následovaným samotným dotazem udávající místo vložení. Místo vložení musí být jednoznačně určený uzel, například pomocí plné cesty od kořene až k danému uzlu a uzly na této cestě mají daná pořadová čísla, jako v příkladě dole. V následujícím příkladě prvním příkazem do XML dokumentu vložíme element xxx. a druhým příkazem ho vymažeme. UPDATE XMLtab SET xml.modify('insert <xxx>test into /PLAY[1]/TITLE[1]') WHERE id=1*/ UPDATE XMLtab SET xml.modify('delete /xxx') WHERE id=1
Klíčové pojmy XPath stromový model cesta, krok, osa, test uzlu, podmínka self, parent, ancestor, ancestor-or-self, child, descendant, descendant-or-self, preceding-sibling, precedig, following-sibling, following, atribute node(), text(), * last(), position(), count() query(), exist(), value() Otázky k rekapitulaci Upozornění: odpovědi na některé zde uvedené otázky nelze najít ve studijním textu tohoto tématického bloku. Lze je získat vlastním experimentováním se zdrojovými kódy nebo studiem doporučené literatury. Vytvořte stromový model XML dokumentu pro malý XML soubor obsahující okolo 20 elementů (z toho alespoň 5 různých názvů), 20 atributů. Vytvořený model vysvětlete. V dalších otázkách můžete tento model využít. Vysvětlete pojem XPath cesta. Co musí a může obsahovat její jednotlivý krok? Každou z 12 os vysvětlete a zformulujte pro ní dotaz, ve kterém se využije. Na slajdech 62 – 64 jsou tři různé dotazy vracející shodný výsledek. Za jakých podmínek by vrácené výsledky byly různé? Co vše může obsahovat testu uzlu? Jaké jsou nejběžnější kombinace os a testů uzlů, jaké mají zkrácené zápisy?
Co může obsahovat podmínka? Jak lze vybrat x-tého potomka daného uzlu? Vysvětlete proč rozdílné dotazy na slajdech č. 70 a 71 dávají shodný výsledek. Jakým způsobem docílíme různého výsledku? Jaké tři funkce v SQL Serveru vyhodnocují výsledek XPath dotazu, aniž by modifikovaly původní dokument. Jak se tyto funkce liší? Jak lze modifikovat XML dokument v SQL serveru s využitím XPath dotazu? Své odpovědi zdůvodněte. Můžete přidat i syntaktické zápisy tam, kde je to vhodné. Doporučené příklady k naprogramování Následující dotazy utvořte nad tabulkou XMLTab naplněnou XML dokumenty ze souboru xml.zip nacházejícím se v adresáři se studijními materiály k tomu předmětu. Pro každý z dotazů vymyslete co největší počet různých zápisů, s použitím různých os. Vyhodnocení některých dotazů může trvat i desítky sekund. 1. 2. 3. 4. 5. 6. 7. 8.
Zjistěte, které osy jsou v SQL Serveru podporovány a které nejsou. Které postavy (PERSONA) se nenacházejí ve skupině postav (PGROUP)? Najděte skupinu postav, ve které se nenachází postava CORNELIUS. Jaké postavy (SPEAKER) vystupují v předposlední scéně (SCENE) druhého aktu (ACT) ? Vypište názvy (TITLE) scén, které se nacházejí v aktech majících alespoň 3 scény?. Přidejte vlastní jméno do seznamu postav a následně ho v dalším dotazu zase odstraňte. Vypište názvy her (TITLE), ve kterých vystupuje alespoň 15 postav. Které postavy (SPEAKER) vystupují v alespoň jedné scéně, ve které vystupuje postava BERNARDO? Studijní literatura
[1] Mlýnková, Nečaský: Slajdy k 3. přednášce z předmětu technologie XML (PRG036) vyučovaného na MFF UK (v tomto tématickém bloku označované jako slajdy). https://is.vsfs.cz/auth/el/6410/leto2010/EQ_N_DS/um/DS4a.ppt [2] Mlýnková a kol.: Technologie XML - Principy a aplikace v praxi. Grada, Praha, 2008. [3] Seriál článků o XML: http://programujte.com/?akce=clanek&cl=2007030501-xml-prozacatecniky-1-cast [4] http://www.kosek.cz/xml/