XQuery XQuery XQuery (XML Query Language) XQuery 1.0: An XML Query Language. W3C Recommendation http://www.w3.org/tr/xquery/ Język programowania funkcyjnego (podobnie jak Lisp) Język zapytań do danych XML-owych Tadeusz Pankowski www.put.poznan.pl/~tadeusz.pankowski T. Pankowski 2 Przykład dokument XML XQuery wyrażenie ścieżkowe Podaj autorów książek w cenie mniejszej niż 60 zł Wyrażenie ścieżkowe: doc(".xml")//ksiazka[@cena<60]/autor SQL Server: select.query('//ksiazka[@cena<60]/autor') from Wynik: Wynik nie jest dokumentem XML. Jest sekwencją dwóch fragmentów.! T. Pankowski 3 T. Pankowski 4
XQuery wyrażenie FLWOR XQuery konstruowanie dokumentu Podaj autorów książek w cenie mniejszej niż 60 zł Wyrażenie FLWOR: for $k in doc(".xml")//ksiazka where $k/@cena<60 $k/autor SQL Server: select.query(' for $k in //ksiazka where $k/@cena<60 $k/autor') from Wynik: Podaj autorów książek w cenie mniejszej niż 60 zł for $k in //ksiazka where $k/@cena<60 $k/autor Wynik: T. Pankowski 5 T. Pankowski 6 XQuery konstruowanie dokumentu XQuery sortowanie wyniku Podaj autorów książek w cenie mniejszej niż 60 zł for $k in //ksiazka where $k/@cena<60 <nazwisko> $k/autor/text() </nazwisko> Wynik: <nazwisko>nowak</nazwisko> < nazwisko>kubiak</nazwisko> Podaj autorów książek w cenie mniejszej niż 60 zł for $k in //ksiazka where $k/@cena<60 order by $k/@cena $k/autor Wynik: T. Pankowski 7 T. Pankowski 8
XQuery przykład Dla każdego autora podaj wykaz jego książek: for in distinct-values(//ksiazka[wydawnictwo/text()=""]/autor/text()) <wykaz> for in //ksiazka[autor/text()=]/tytul/text() <tytul></tytul> </wykaz> XDM XQuery 1.0 and XPath 2.0 Data Model (XDM) W3C Recommendation 23 January 2007 http://www.w3.org/tr/xpath-datamodel/ Model danych dla: XSLT 2.0, XQuery 1.0, and XPath 2.0 Język jest domknięty ze względu na model, jeśli mamy gwarancję, że wartość każdego wyrażenia należy do modelu. distinct-values = funkcja eliminująca duplikaty T. Pankowski 9 T. Pankowski 10 Definicje modelu XDM [Def.1] Każda instancja modelu jest sekwencją [Def.2] Sekwencja jest uporządkowaną kolekcją jednej lub wielu pozycji (items). Sekwencja nie może należeć do sekwencji. Pojedyncza pozycja traktowana jest jako sekwencja zawierająca jedną pozycję. [Def.3] Pozycja jest wierzchołkiem (node) lub wartością atomową (atomic value). [Def. 4] Każdy wierzchołek jest jednym z 7 typów (document (lub root), element, attribute, text, namespace, processing instruction, comment). Każdy wierzchołek należy do co najwyżej jednego drzewa, każde drzewo ma dokładnie jeden korzeń. [Def.5] Drzewo, którego korzeń jest typu Document nazywamy documentem. [Def.6] Drzewo, którego korzeń nie jest typu Document nazywamy fragmentem. Definicje modelu XDM (2) [Def.7] Wartość atomowa należy do przestrzeni wartości typu atomowego i jest etykietowana nazwą tego typu atomowego. [Def.8] Istnieją 23 pierwotne typy proste (primitive simple types), np.: string, boolean, float, time, date, hexbinary, [Def.9] Typ reprezentowany jest za pomocą expanded-qname. [Def.10] Expanded-QName składa się z trzech części: prefix (może być pusty), URI przestrzeni nazw (może być pusty), nazwy lokalnej. Np.: prefix xs: związany z URI http://www.w3.org/2001/xmlschema T. Pankowski 11 T. Pankowski 12
Definicje modelu XDM (3) Wierzchołki są jednoznaczne, mają tożsamość, są różne od wszystkich innych. Wartości atomowe nie mają tożsamości (identyfikatora); każda instancja wartości "5" jest identyczna z każdą inną instancją "5" (jako integer). Jednoznaczności wierzchołków nie należy mylić z wartościami unique ID, gdzie wartość tego typu przypisana jest elementowi jako jego nazwa i służy do realizacji referencji typu ID/IDREF. Definicje modelu XDM (4) [Def.11] Uporządkowanie dokumentu jest zdefiniowane pomiędzy wszystkimi wierzchołkami. Jest to porządek całkowity. Nieformalnie, uporządkowanie dokumentu jest zgodne z porządkiem przy jego serializacji. [Def.12] Porządek dokumentu jest stabilny, tzn. kolejność wierzchołków nie zmienia się podczas przetwarzania. Korzeń jest pierwszym wierzchołkiem. Wierzchołek poprzedza wszystkie swoje dzieci i wszystkie wierzchołki potomne. Wierzchołek przestrzeni nazw następuje bezpośrednio po wierzchołku elementowym, do którego jest przypisany. Wierzchołki atrybutowe po swoim wierzchołku elementowym i ew. po wierzchołku przestrzeni nazw. Dzieci i potomkowie wierzchołka występują przed jego rodzeństwem. T. Pankowski 13 T. Pankowski 14 Język XQuery sekwencje 1. Sekwencją jest to uporządkowany ciąg wierzchołków lub wartości atomowych (prostych). 2. Sekwencje nie mogą być zagnieżdżane. Porządek w sekwencji zwracanej przez wyrażenie jest inaczej niż w SQL ściśle określony; jest to tzw. porządek dokumentu. 3. Kolejność tę można zmienić żądając sortowania za pomocą klauzuli order by. 4. Sekwencje mogą być wynikiem wyrażeń, można je też zapisać jawnie ujmując elementy, oddzielone przecinkami, w nawiasy zwykłe. Pustą sekwencję zapisuje się w postaci pary nawiasów:(). 5. Na przykład: wynikiem kombinacji a, (a,b) i () jest sekwencja (a,b,c). T. Pankowski 15 Język XQuery wyrażenia 1. Wszystkie konstrukcje języka XQuery składają się z wyrażeń. 2. Wyrażenia zwracają sekwencje i mogą być zagnieżdżane. 3. Wyrażenia mogą zawierać: stałe, jawnie zapisane sekwencje, odwołania do zmiennych, wywołania funkcji wbudowanych i funkcji użytkownika, ścieżki XPath, wyrażenia FLWOR, wyrażenia warunkowe, operatory. 4. Wyrażenia wykonywane są w kontekstach wyrażeń, na które składa się informacja mająca wpływ na wynik wyrażenia. Informacja to może tworzyć kontekst statyczny lub kontekst dynamiczny. T. Pankowski 16
Język XQuery zmienne 1. Nazwy zmiennych poprzedzane są znakiem dolara. 2. Zmienne mogą być deklarowane, ale nie jest to obowiązkowe. Zapytania Najprostszym zapytaniem w XQuery jest wyrażenie ścieżkowe XPath. <tytuly> doc("publik.xml")//tytul </tytuly> lub select.query(' <tytuly> //tytul </tytuly>') from publik daje w wyniku dokument o następującej postaci: <tytuly> </tytuly> gdyż ścieżka XPath zwraca sekwencję elementów <tytul>. T. Pankowski 17 T. Pankowski 18 Zapytania W rozważanych zapytania ścieżka XPath //tytul zwraca sekwencję elementów typu <tytul>. W pierwszym zapytaniu odwołano się do zewnętrznego dokumentu jako do źródła danych, a w drugim do dokumentu w bazie danych (publik.). Tak proste zapytanie daje stosunkowo niewielkie możliwości, dlatego do konstruowania praktycznie przydatnych zapytań najczęściej używa się wyrażeń FLWOR. Czym jest XQuery? Jest językiem zapytań, który: wybiera elementy/atrybuty z dokumentu wejściowego, łączy dane z wielu dokumentów wejściowych, umożliwia modyfikację danych, wylicza nowe dane, umożliwia budowanie dokumentu wynikowego dodaje nowe elementy/atrybuty do wyniku, sortuje wynikowy dokument T. Pankowski 19 T. Pankowski 20
Wyrażenia FLOWOR Konstruktory XML Prolog zapytań Funkcje użytkownika Związek z innymi językamij Wyrażenia warunkowe Wyrażenia arytmetyczne Wyrażenia kwantyfikowane Funkcje i operatory Model danych (XDM) XQuery 1.0 XPath 2.0 XSLT 2.0 XPath 1.0 Wyrażenia ścieżkowe Wyrażenia logiczne Funkcje Arkusze stylów (stylesheets) Szablony (templates) itd. T. Pankowski 21 Źródła a danych Dostęp do źródeł danych dla zapytań zapewniają dwie funkcje wbudowane: doc(uri) zwraca (jako wierzchołek dokumentu, korzeń) dokument znajdujący się pod wskazanym adresem URI; collection(uri) zwraca sekwencję korzeni dokumentów będących wynikiem odwołania się do wskazanego adresu URI. Odwołanie do dokumentu w SQL Server: @zmienna.query('xquery') kolumna.query('xquery') T. Pankowski 22 Przykłady http://www.w3.org/tr/xmlquery-use-cases DTD przykład <!ELEMENT ( )> <!ELEMENT książka (, (autor+ editor+ ), wydawnictwo, cena )> <!ATTLIST książka rok CDATA #REQUIRED > <!ELEMENT autor (nazwisko, imię )> <!ELEMENT editor (nazwisko, imię, afiliacja )> <!ELEMENT (#PCDATA )> <!ELEMENT nazwisko (#PCDATA )> <!ELEMENT imię (#PCDATA )> <!ELEMENT afiliacja (#PCDATA )> <!ELEMENT wydawnictwo (#PCDATA )> <!ELEMENT cena (#PCDATA )> T. Pankowski 23 T. Pankowski 24
@rok autor+ edytor+ wydawnictwo cena imię nazwisko imię nazwisko afiliacja <!ELEMENT ( )> <!ELEMENT książka (, (autor+ edytor+ ), wydawnictwo, cena )> <!ATTLIST książka rok CDATA #REQUIRED > <!ELEMENT autor (imię, nazwisko )> <!ELEMENT editor (imię, nazwisko, afiliacja )> <!ELEMENT (#PCDATA )> <!ELEMENT imię (#PCDATA )> <!ELEMENT nazwisko (#PCDATA )> <!ELEMENT afiliacja (#PCDATA )> <!ELEMENT wydawnictwo (#PCDATA )> <!ELEMENT cena (#PCDATA )> <książka rok="1994"> <>TCP/IP Illustrated</> <autor><imię>w.</imię><nazwisko>stevens</nazwisko></autor> Addison-Wesley <cena> 65.95</cena> <książka rok="1992"> <>Advanced Programming in the Unix</> <autor><imię>w.</imię><nazwisko>stevens</nazwisko></autor> Addison-Wesley <cena>65.95</cena> <książka rok="2000"> <>Data on the Web</> <autor><imię>serge</imię><nazwisko>abiteboul</nazwisko></autor> <autor><imię>peter</imię><nazwisko>buneman</nazwisko></autor> <autor><imię>dan</imię><nazwisko>suciu</nazwisko></autor> Morgan Kaufmann <cena> 39.95</cena> <książka rok="1999"> <>The Economics of Technology for Digital TV</> <editor> <imię>darcy</imię><nazwisko>gerbarg</nazwisko> <afiliacja>citi</afiliacja> </editor> Kluwer Academic <cena>129.95</cena> Q1: Podaj książki wydane przez Addison-Wesley po roku 1991, uwzględnij rok wydania i $k Przykład: Q1 Q1: Podaj książki wydane przez Addison-Wesley po roku 1991, uwzględnij rok wydania i @rok $r autor+ edytor+ wydawnictwo $w imię nazwisko imię nazwisko afiliacja cena @rok $r XQuery: for $k in //książka, $r in $k/@rok, in $k//text(), $w in $k/wydawnictwo where $w = "Addison-Wesley" and $r > 1991 <książka rok="$r"> <></> select Dok.query(' for $k in //książka where $k/wydawnictwo = ''Addison-Wesley'' and $k/@rok > 1991 <książka rok=" $k/@rok "> $k/ ') from Tab T. Pankowski 28
Przykład: Q1 Q1: Podaj książki wydane przez Addison-Wesley po roku 1991, uwzględnij rok wydania i select Dok.query(' for $k in //książka where $k/wydawnictwo = ''Addison-Wesley'' and $k/@rok > 1991 <książka rok=" $k/@rok "> $k/ ') from Tab Przykład: Q2 Q2: Utwórz płaską listę wszystkich par -autor, gdzie każda para należy do elementu "wynik" @rok autor+ imię nazwisko $k edytor+ wydawnictwo $w imię nazwisko afiliacja cena autor wyniki wynik* ZF: autur, wynik XQuery: <wyniki> <książka rok="1994"> for <>TCP/IP Illustrated</> $k in //książka, in $k/, <książka rok="1992"> in $k/autor <>Advanced Programming in the Unix</> T. Pankowski 29 </wyniki> T. Pankowski 30 Przykład: Q3 Q2: Dla każdej książki podaj w elemencie "wynik" jej i listę jej autorów. wyniki Q2: Q3: $k wynik* @rok autor+ imię nazwisko edytor+ wydawnictwo $w imię nazwisko afiliacja cena ZF: wynik autor+ XQuery: <wyniki> for $k in //książka, in $k/ for in $k/autor </wyniki>
Przykład: Q4 Q2: Dla każdego autora podaj wykaz ów jego książek. wyniki Q4: @rok autor+ imię nazwisko ZF: książka $k edytor+ wydawnictwo $w imię nazwisko afiliacja cena autor wynik* ZF: autor wynik + XQuery: <wyniki> for in distinct-values(//książka/autor) for in //książka[autor=]/title </wyniki> T. Pankowski 34 Przykład: Q6 Q6: Dla każdej książki podaj jej oraz co najwyżej dwóch pierwszych autorów. Jeśli autorów jest więcej niż dwóch, to wypisz pusty element ze znacznikiem "i-inni". Przykład: Q12 Q12: Podaj pary książek, które mają tych samych autorów for $k in //książka where count($k/autor) > 0 <książka> $k/ for in $k/autor[position()<=2] if (count($k/autor) > 2) then <i-inni/> else () for $k1 in //książka, $k2 in //książka let ut1 := $k1/autor, ut2 := $k2/autor where $k1 < $k2 and $k1/!= $k2/ and ut1=ut2 <para> $k1/ $k2/ </para> 35 36
Zapytania rekurencyjne Przykład pokazuje, w jaki sposób można użyć zapytanie rekurencyjne do skonstruowania dokumentu hierarchicznego o dowolnej głębokości ze struktury płaskiej. T. Pankowski 37 DTD: Przykładowe dane: Dokument wejściowy <!DOCTYPE Lista [ <!ELEMENT Lista (Część*)> <!ELEMENT Część EMPTY> <!ATTLIST Część IdCz CDATA #REQUIRED NależyDo CDATA #IMPLIED Nazwa CDATA #REQUIRED> ]> <Lista> <Część IdCz="0" Nazwa="samochód"/> <Część IdCz="1" NależyDo="0" Nazwa="silnik"/> <Część IdCz="2" NależyDo="0" Nazwa="drzwi"/> <Część IdCz="3" NależyDo="1" Nazwa="cylinder"/> <Część IdCz="4" NależyDo="2" Nazwa="okno"/> <Część IdCz="5" NależyDo="2" Nazwa="zamek"/> <Część IdCz="10" Nazwa="hulajnoga"/> <Część IdCz="11" NależyDo="10" Nazwa="deska"/> <Część IdCz="12" NależyDo="10" Nazwa="kółko"/> <Część IdCz="20" Nazwa="kajak"/> </Lista> T. Pankowski 38 DTD: <!DOCTYPE Hierarchia [ <!ELEMENT Hierarchia (Część*)> <!ELEMENT Część(Część*)> <!ATTLIST Część IdCz CDATA #REQUIRED Nazwa CDATA #REQUIRED> ]> Dokument wynikowy: Dokument wynikowy Program w XQuery (implementacja: Stylus Studio) declare function local:one_level($p as element()) as element() <Część IdCz=" $p/@idcz " Nazwa=" $p/@nazwa " > for $s in doc("listacz.xml")//część where $s/@należydo = $p/@idcz local:one_level($s) </Część> ; <Hierarchia> for $p in doc("listacz.xml")//część[empty(@należydo)] local:one_level($p) </Hierarchia> T. Pankowski 40