XML – ćwiczenia 7: XPath i XQuery

Standardy

Standardy służące przetwarzaniu dokumentów XML: XSLT, XPath i XQuery, są ze sobą związane i występują ogólnie rzecz biorąc w dwóch wersjach.

  1. Starsza i prostsza:

  2. Nowsza i bogatsza:

Technikalia

Proponuję korzystać z narzędzia Saxon w wersji 9.x HE (darmowa, Open-Source).

Należy pobrać plik saxon9he.jar. Następnie można uruchamiać Saxona m.in. w poniższy sposób:

Wyrażenia XPath

Analogiczne wprowadzenie jest teraz częścią wykładu, ale pozostawiam tu tekst, który został już napisany...

Zmienne

$foo jest odwołaniem do zmiennej o nazwie foo. Zmienna musi być dostępna w kontekście w momencie ewaluacji wyrażenia.

Literały

Poprawnymi wyrażeniami XPath są literały różnych typów.

Typ wartościPrzykładowe literały
string'12.5' "He said, ""I don't like it."""
integer123 5
decimal12.3 5.0 .23
double125E2 1.13e-8

Konstruktory i rzutowanie typów

  • xs:date("2001-08-25") (o ile prefiks xs odnosi się do przestrzeni nazw XML Schema)
  • string(2 + 2)

To samo można uzyskać dzięki rzutowaniu typów:

  • "2001-08-25" cast as xs:date
  • ...

Konstruktor sekwencji

Sekwencje można jawnie tworzyć poprzez wyliczenie ich elementów lub podanie przedziałów (dla liczb całkowitych). Całą sekwencję obejmuje się nawiasami, a poszczególne elementy i przedziały rozdziela przecinkami.

Przykłady:

  • () – sekwencja pusta
  • ("ala") – singleton równoważny wartości atomowej "ala"
  • (1, 2,3, 4 ,6, 7, -3)
  • (1 to 4, 6 to 7, -3)
  • ("ala", 20.5, 2 + 5, //obiekt/opis)
  • (10, (1, 2), (), (3, 4)) – jest równe (10, 1, 2, 3, 4)

Operatory arytmetyczne i logiczne

Wyrażeniami XPath są "normalne" wyrażenia arytmetyczne z operatorami + - * div idiv mod.

Dodawanie i odejmowanie działają także na typach daty i czasu (tzn. do daty można dodać duration itp.).

Poza operatorami arytmetycznymi, są dostępne także logiczne or i and.

Przykłady:

  • 2 + 2
  • 12.5 div 3
  • 13 idiv 3
  • 14 mod 3 = 2 and 3 > 2

Istnieją także specjalne operatory dla sekwencji węzłów (w wersji 1.0 "zbiorów węzłów"). Wyniki tych operatorów to sekwencje bez powtórzeń, uporządkowane według porządku dokumentu (nawet jeśli argumenty tego nie spełniały):

  • union lub | – suma zbiorów
  • intersect – przecięcie zbiorów
  • except – różnica zbiorów

Porównania

Do porównywania wartości atomowych służą operatory porównania atomowego: eq, ne, lt, le, gt i ge.

Argumenty są rzutowane sa najwęższy wspólny typ, a jeśli takiego nie ma lub jest nim xs:untypedAtomic, rzutowane na xs:string. Dla pewnych kombinacji typów niektóre operatory mogą nie być zdefiniowane, wówczas pojawia się błąd.

Do porównywania sekwencji służą operatory porównania ogólnego: = != < <= > >=. Porównanie dla dwóch sekwencji L i R zwraca prawdę wtedy i tylko wtedy, gdy dla chociaż jednej pary: l (elementu L po atomizacji) oraz r (elementu R po atomizacji) zachodzi porównanie atomowe odpowiadające zadanemu porównaniu ogólnemu.

Poza tym istnieją operatory porównania specyficzne dla węzłów: is (identyczność węzłów), << i >> (porównywanie względem porządku dokumentu).

Przykłady:

  • 5 gt 3
  • (3) eq 2
  • () eq 2
  • (2, 3) eq 2
  • (2) = (2)
  • 2 = 2
  • () = 2
  • (2, 3) = 2
  • (1, 2) = (2, 3)
  • (2, 3) = (3, 4)
  • (1, 2) = (3, 4)
  • (1, 2) != (1, 2)
  • //obiekt[9]/opis/text() = //obiekt[10]/opis/text()
  • //obiekt[9]/opis/text() is //obiekt[10]/opis/text()
  • //obiekt is //obiekt

Wywołania funkcji

W XPath można wywoływać funkcje. Wiele funkcji zdefiniowanych jest w tej rekomendacji. Funkcje te znajdują się w przestrzeni nazw http://www.w3.org/2005/xpath-functions. W ewaluatorze XML Spy nie trzeba używać prefiksów, w XSLT 2.0 zalecane jest używanie prefiksów.

Standardy XSLT i XQuery przewidują definiowanie własnych funkcji. Definiowanie własnych funkcji dostępne jest także poprzez specjalne interfejsy programistyczne. Istnieje pewien zbiór rozszerzeń, które są powszechnie dostępne: EXSLT.

Przykłady:

  • not(false()) eq true()
  • concat("Ala ", "ma", " kota")
  • sum(//obiekt/@parzysty)
  • moje:moja_funkcja(12, //jakieś_elementy)

Wyrażenie for

Wyrażenie for $x in E1 return E2 może być obliczone w następujący (lub równoważny) sposób:

  1. Obliczamy wyrażenie E1, jego wynikiem jest sekwencja.
  2. Dla każdego elementu Vi obliczonej sekwencji wykonujemy ewaluację wyrażenia E2 w kontekście wzbogaconym o zmienną x, której przypisano wartość równą Vi.
  3. Wynikiem jest sekwencja złożona z wyników poszczególnych ewaluacji, następnie "spłaszczona".

W jednym forze można związać wiele zmiennych.

Przykłady:

  • for $n in (10, 20, 30.5) return $n + 5
  • for $x in //obiekt return concat("Obiekt o nazwie: ", $x/@nazwa)
  • for $x in (1 to 5), $y in (3 to 5) return 10 * $x + $y

Wyrażenia warunkowe

Obliczenie wyrażenia if (W) then E1 else E2 sprowadza się do obliczenia W, a następnie, w zależności od wyniku, E1 lub E2.

Przykład:

  • for $x in //obiekt return if($x/@nazwa) then concat("Obiekt ma nazwę: ", $x/@nazwa) else "Obiekt nie ma nazwy"

Kwantyfikatory

Wyrażenie some $var in E1 satisfies E2 zwraca prawdę gdy przynajmniej jeden element sekwencji obliczonej z E1 spełnia wyrażnie E2, tzn. E2 w kontekście wzbogaconym o zmienną var z wartością równą elementowi sekwencji wylicza się do prawdy.

Analogicznie every $var in E1 satisfies E2 zwraca prawdę gdy każdy element sekwencji obliczonej z E1 spełnia wyrażenie E2.

Obliczanie wyrażeń kwantyfikowanych może odbywać się w dowolnej kolejności, może być leniwe i może zostać przerwane po wystąpieniu dynamicznego błędu.

Przykłady:

  • some $x in (1,2,3) satisfies $x = 3 (prawda)
  • every $x in (1,2,3) satisfies $x = 3 (fałsz)
  • some $x in (//obiekt, 'aaa') satisfies $x is //obiekt[2] (prawda lub błąd w zależności od kierunku ewaluacji, spróbujcie zmienić kolejność w sekwencji)

Ścieżki XPath

To wyrażenia najbardziej charakterystyczne dla XPath. Służą do odczytywania (adresowania) fragmentów dokumentu.

Zasadnicza składnia

Ścieżka względna ma następującą postać:

krok/krok ...

gdzie krok to:

::test-węzłów [predykat] [predykat] ...

Ścieżka bezwzględna dodatkowo zaczyna się od / lub //.

Obliczenie wyrażenia zaczyna się od węzła konktekstowego (ścieżka względna) lub węzła dokumentu (ścieżka bezwzględna). W każdym kroku na wejściu ("z lewej strony") mamy jakąś sekwencję węzłów. Dla każdego węzła z tej sekwencji krok prowadzi do jakiejś sekwencji węzłów (np. dzieci). Wszystkie uzyskane w ten sposób węzły tworzą sekwencję, która jest wynikiem kroku i "przechodzi na prawą stronę".

Wynikiem całej ścieżki jest sekwencja węzłów, która jest wynikiem ostatniego kroku.

Oś wskazuje "kierunek", w którym podążamy w danym kroku (tak naprawdę określa jakąś sekwencję węzłów). Test węzłów pozwala na proste wybranie tylko niektórych węzłów z danej osi. Predykaty to dowolne wyrażenia dodatkowo filtrujące węzły.

Test węzłów

Zasadniczo są dwa rodzaje testów: po rodzaju węzła i po nazwie. Oto reprezentatywne przykłady:

  • node() – dowolne węzły,
  • element() – dowolne elementy,
  • text() – dowolne węzły tekstowe,
  • processing-instruction() – dowolne instrukcje przetwarzania,
  • comment() – dowolne komentarze,
  • attribute() – dowolne atrybuty,
  • element(obiekt) – elementy o nazwie obiekt,
  • element(*, TGość) – elementy o dowolnej nazwie, o typie TGość (ustalonym na podstawie załączonej schemy),
  • attribute(licznik, xs:integer) – atrybuty o nazwielicznik i typie xs:integer (ustalonym na podstawie załączonej schemy),
  • obiekt – węzły o nazwie obiekt w przestrzeni nazw o pustym identyfikatorze (albo domyślnej przestrzeni nazw?),
  • pre:obiekt – węzły o nazwie obiekt w przestrzeni nazw wskazanej prefiksem pre,
  • *:obiekt – węzły o lokalnej nazwie obiekt,
  • pre:* – węzły w przestrzeni nazw o prefiksie pre.

Osie

Każda oś wskazuje sekwencję (ew. pustą) węzłów. Kolejność węzłów w sekwencji jest zgodna lub przeciwna do ich wystąpienia w dokumencie (w zależności od tego czy oś jest w przód czy w tył).

  • child – zawiera dzieci węzła kontekstowego. Jedynie węzeł dokumentu i elementu mają dzieci (mogą to być elementy, instrukcje przetwarzania, komentarze, lub węzły tekstowe; dziećmi nie są atrybuty, przestrzenie nazw i węzły dokumentu).
  • descendant – potomkowie, domknięcie przechodnie osi child.
  • parent – rodzic węzła kontekstowego.
  • ancestor – domknięcie przechodnie osi parent (zawiera węzeł dokumentu chyba, że był to węzeł kontekstowy).
  • following-sibling – rodzeństwo, które zgodnie z porządkiem dokumentu występuje później (dla węzłów atrybutu i przestrzeni nazw ta oś jest pusta).
  • preceding-sibling – analogicznie.
  • following – wszyscy potomkowie węzła dokumentu nie będący potomkami węzła kontekstowego i w dokumencie występujący po nim.
  • preceding – analogicznie.
  • attribute – atrybuty węzła kontekstu.
  • self – węzeł kontekstu.
  • descendant-or-self – połączenie osi descendant i self.
  • ancestor-or-self – połączenie osi ancestor i self.
  • namespace – dostęp do węzła przestrzeni nazw. W XPath 2.0 jest deprecated. Zastępują ją funkcje fn:get-in-scope-prefixes i fn:get-namespace-uri-for-prefix.

Przykłady:

  • /child::lista/child::obiekt – sekwencja wszystkich elementów obiekt z dokumentu
  • child::obiekt – sekwencja wszystkich elementów obiekt, które są dziećmi "węzła konktekstowego", jest sens obliczać z elementu lista
  • attribute::* – wszystkie atrybuty węzła konktekstowego (sprawdź w obiekcie)
  • preceding-sibling::obiekt – sprawdź w obiekcie w środku dokumentu oraz w dzieciach obiektu
  • preceding::obiekt – sprawdź w obiekcie w środku dokumentu oraz w dzieciach obiektu
  • child::attribute() – czy są to atrybuty bieżącego węzła?
  • attribute::node() – a to?
  • /child::lista/child::obiekt/attribute::node()
  • /descendant-or-self::node()
  • /descendant-or-self::element()/attribute::attribute()

Składnia skrócona

Można stosować różne skróty notacyjne. Domyślną osią jest child, rozpoczęcie nazwy węzła od @ oznacza przejście na oś atrybutów.

// oznacza wszystkich potomków (nie tylko dzieci jak /), .. oznacza rodzica (parent::node()), natomiast . (kropka) węzeł kontekstowy (self::node()).

Przykłady:

  • /lista/obiekt
  • obiekt
  • @*
  • //node()
  • //* (czym się różnią?)

Predykaty

Predykaty pozwalają na sprawdzanie własności, których nie da się wyrazić w samych testach węzłów. Predykat jest obliczany dla każdego węzła z sekwencji (wyniku wyrażenia z lewej strony predykatu), tzn. kolejne węzły są ustawiane jako węzły kontekstowe. Jeśli dla danego węzła test zachodzi, węzeł znajdzie się w wynikowej sekwencji („przejdzie na prawą stronę”). Jeśli test nie zachodzi, węzeł zostanie „zatrzymany”.

Predykatem może być dowolne wyrażenie XPath. Jeśli jego wynikiem jest wartość numeryczna, wówczas predykat zachodzi wtw gdy pozycja testowanego węzła jest równa tej liczbie. Jeśli jego wynikiem nie jest wartość numeryczna, wówczas wynik jest rzutowany na xs:boolean. W szczególności pusta sekwencja jest rzutowana na fałsz, a sekwencja z jakimkolwiek węzłem na początku na prawdę.

Przykłady:

  • //obiekt[2] – drugi obiekt
  • //obiekt[position() > 5] – obiekty o pozycji > 5
  • //obiekt[length()] – ostatni obiekt
  • //obiekt[@nazwa='drugi'] – obiekt z atrybutem nazwa równym drugi
  • //obiekt[@nazwa] – obiekt z jakimkolwiek atrybutem nazwa
  • //obiekt[@nazwa and position() = 6] – ...
  • //obiekt[@nazwa][position() = 6] – ...
  • //obiekt[@nazwa]/opis – ...

Zadanie 1.

Za pomocą XPath wybierz określone elementy dokumentu przyklad.xml lub wyraź określone konstrukcje.

  1. wszystkie obiekty,
  2. zagnieżdżone opisy (tzn. znajdujące się w innych opisach),
  3. obiekt o id równym E4,
  4. obiekty z opisem,
  5. obiekty bez opisu,
  6. opisy w obiektach bez nazwy,
  7. tylko drugie opisy obiektów,
  8. obiekty parzyste,
  9. dodatki znajdujące się za opisami,
  10. dodatki znajdujące się bezpośrednio za opisami,
  11. obiekty, których wszystkie dzieci posiadają podelement wyr,
  12. sekwencja: dla każdego obiektu, liczba jego dzieci.

Zobacz także

XQuery

XQuery jest językiem służącym do „odpytywania” dokumentów XML, wydobywania informacji z dokumentów XML. W swoich założeniach ma być tym dla XML, czym SQL jest dla relacyjnych baz danych.

Związek z XPath

Standard XQuery jest silnie związany z XPath. Oba opierają się o ten sam model danych i posiadają tą samą bibliotekę funkcji (i operatorów).

O samym języku XQuery można myśleć jak o rozszerzeniu języka XPath, jednak definicje obu tych języków są osobnymi rekomendacjami.

O ile wyrażenia XPath są wykorzystywane w innych standardach (XSLT, XPointer, XML Schema), to XQuery jest samodzielnym standardem. Jednak, w przeciwieństwie do wielu innych standardów W3C :), zapytanie XQuery nie jest dokumentem XML.

Zapytania XQuery

XPath jako XQuery

(Prawie?) każde wyrażenie XPath jest poprawnym wyrażeniem XQuery. A pojedyncze wyrażenie jest poprawnym zapytaniem.

Poprawnymi zapytaniami są więc wyrażenia arytmetyczne, logiczne, wyrażenia na sekwencjach itp.

Zapytaniami XQuery są także ścieżki XPath (i wyrażenia zawierające ścieżki). Aby jednak ścieżka bezwzględna mogła zostać obliczona, musi być znany dokument kontekstowy, a dla ścieżki względnej także węzeł kontekstowy w tym dokumencie.

Odczyt zewnętrznych dokumentów

Za pomocą funkcji doc można odczytywać zawartość dokumentów XML z zewnętrznych źródeł danych (plików, adresów URL). Np. doc("przyklad.xml") zwraca węzeł dokumentu zapisanego w pliku przyklad.xml.

Dzięki temu poprawnymi zapytaniami są ścieżki takie jak doc("przyklad.xml")/lista/obiekt[@id='E4]. Zapytania takie działają niezależnie od dokumentu kontekstowego (nie trzeba go określać).

Deklaracje

Przed ciałem zapytania dokument XQuery może zawierać deklaracje. Oto niektóre z nich:

  • deklaracja wersji – to (opcjonalny) nagłówek całego dokumentu (zapytania) XQuery,
  • deklaracja przestrzeni nazw – deklaruje prefiks dla przestrzeni nazw,
  • deklaracja zmiennej – deklaruje zmienną lub parametr zapytania,
  • deklaracja funkcji – definiuje funkcję (opis w dalszej części zajęć).

Przykład 1. Przykłady deklaracji

xquery version "1.0" encoding "utf-8";
declare namespace foo = "http://example.org";
declare default element namespace "http://inny.org";

<foo:bar> Coś tu <xx> Coś tam </xx></foo:bar>
xquery version "1.0" encoding "utf-8";
declare variable $id as xs:string external;
declare variable $doc := doc("przyklad.xml");

$doc//obiekt[@id = $id]

Sposoby serializacji

Wynik zapytania XQuery można zapisać ("zserializować") na różne sposoby, m.in jako XML i jako tekst. Do wyboru sposobu serializacji służą parametry serializacji, z których najważniejszym jest method.

Domyślnie wynik wypisywany jest w postaci XML. Dokładie mówiąc wynikiem takiej serializacji nie musi być dokument XML, a tzw. encja ogólna przetwarzana (general parsed entity), czyli wynik przekształcenia wstawiony do sztucznego elementu głównego utworzy poprawny dokument XML.

Zadanie 2.

Spróbuj wykonać poniższe zapytania wybierając metody serializacji xml i text.

  • 2 + 2
  • (1, "Ala", 3.0)
  • doc("przyklad.xml")/lista/obiekt[@id='E7']
  • doc("przyklad.xml")/lista/obiekt[@nazwa]
  • doc("przyklad.xml")//text()
  • doc("przyklad.xml")//*

Zadanie 3. (Opcjonalne)

Dla dokumentu pracownicy.xml napisz zapytania zwracające:

  • liczbę wszystkich pracowników
  • liczbę pracowników księgowości
  • listę wszystkich pracowników księgowości (elementów XML)

Konstruktory węzłów XML

Wyrażeniem XQuery może być nie tylko odpowiednik wyrażenia XPath, ale także konstruktor. Dzięki temu w wynikowej sekwencji mogą pojawić się nie tylko węzły odczytane z dokumentów, ale także nowe, dynamicznie skonstruowane.

Konstruktory dzielą się na bezpośrednie (exact) i obliczane (computed).

Konstruktory bezpośrednie

Jeżeli w zapytaniu XQuery znajdzie się znacznik otwierający elementu, to cały fragment zapytania od tego znacznika aż do odpowiadającego mu znacznika zamykającego zostanie potraktowany jak konstruktor. W wyniku zapytania znajdzie się właśnie ten element. Atrybuty i zawartość tekstowa wewnątrz także zostaną po prostu skopiowane do wyniku.

Przykład 2.

Bezpośredni konstruktor elementu book.

<book isbn="isbn-0060229357">
  <title>Harold and the Purple Crayon</title>
  <author>
    <first>Crockett</first>
    <last>Johnson</last>
    <?cel Wartość?>
    <!--Komentarz-->
  </author>
</book>

Bezpośredni konstruktor elementu umieszczony wewnątrz wyrażenia.

for $ob in doc("przyklad.xml")//* return
  <elem>Element o nieustalonej nazwie</elem>

Jeżeli wewnątrz wygenerowanego w ten sposób elementu chcemy umieścić wartość obliczoną dynamicznie, możemy umieścić wyrażenie XQuery w nawiasach klamrowych.

Zafgnieżdżone wyrażenie (jak każde) oblicza się do jakiejś sekwencji. W miejsce wystąpienia wyrażenia wstawiana jest wynikowa sekwencja, z tym że wartości atomowe są rzutowane na xs:string, a sąsiadujące wartości atomowe są sklejane do pojedynczych węzłów tekstowych, z pojedynczymi spacjami pomiędzy. Węzły są wstawiane jako węzły.

Wyrażenie w nawiasach klamrowych można umieścić też w wartości atrybutu. W tym przypadku wynik zagnieżdżonego wyrażenia (łącznie z węzłami) jest rzutowany na xs:string (między elementami sekwencji wstawiane są pojedyncze spacje).

Przykład 3.

Bezpośredni konstruktor elementu elem jest umieszczony w wyrazeżeniu, a sam zawiera wyrażenia obliczające wartość atrybutu i część zawartości elementu.

<wynik>{
  for $el in doc("przyklad.xml")//* return
    <elem głębokość="{count($el/ancestor::node())}">Element o nazwie: {name($el)}</elem>
}</wynik>

Konstruktory obliczane

Konstruktory obliczane są bardziej ogólnym sposobem tworzenia węzłów XML. W szczególności pozwalają one na dynamiczne generowanie nazw elementów czy atrybutów.

Przykład 4.

Konstruktor obliczany elementu book (ze statyczną zawartością).

element book { 
   attribute isbn {"isbn-0060229357" }, 
   element {"title"} { "Harold and the Purple Crayon"},
   element author { 
      element first { text { "Crockett" } }, 
      element last {"Johnson" }
      processing-instruction cel { "Wartość" }
      commment { "Komentarz" }
   }
}

Konstruktor obliczany, w którym obliczana jest nie tylko zawartość, ale także nazwa elementu.

<wynik>{
  for $el in doc("przyklad.xml")//* return
    element {concat('elem-', name($el))} {
      attribute głębokość {count($el/ancestor::node())},
      text {"Element o nazwie: "},
      text {name($el)}
    }
}</wynik>

Zadanie 4.

Sprawdź, czy bezpośrednimi konstruktorami są komentarz, instrukcja przetwarzania i fragment tekstu (umieszczone po prostu w wyrażeniu XQuery).

Wyrażenia FLWOR

Wyrażenia for z XPath, w XQuery są zastąpione przez bardziej rozbudowane wyrażenia FLWOR (od For, Let, Where, Order by, Return). Jest to odpowiednik wyrażeń SELECT z SQL.

Wyrażenie składa się z następujących części (klauzul):

  • for – wiąże zmienną, jej wartość przebiega wszystkie elementy sekwencji,
  • let – wiąże zmienną jednorazowo przypisując jej wartość (całą sekwencję),
  • where – filtruje elementy sekwencji,
  • order by – sortuje sekwencję,
  • return – wyrażenie obliczane dla każdego elementu sekwencji (tej z for ale przefiltrowanej i posortowanej).

Klauzule for i let mogą występować wielokrotnie i być wymieszane. where i order są opcjonalne.

Przykład 5. Przykłady wyrażeń FLWOR

let $obiekty := doc("przyklad.xml")/lista/obiekt
  return <wynik>{ $obiekty }</wynik>
for $obiekt in doc("przyklad.xml")/lista/obiekt
  return <wynik>{ $obiekt }</wynik>
for $obiekt in doc("przyklad.xml")/lista/obiekt
  let $pop := $obiekt/preceding-sibling::element()
  let $nazwa-pop1 := $pop[1]/@nazwa
  where $obiekt/@nazwa
  order by $obiekt/@nazwa
  return
    <wynik>
      Obiekt o nazwie {xs:string($obiekt/@nazwa)} ma {count($pop)} poprzedników.
      Najbliższym poprzednikiem jest obiekt o nazwie {xs:string($nazwa-pop1)}.
    </wynik>

Zadanie 5.

Weź plik sklep1.xml

Napisz zapytanie, które wypisuje kolejno wszystkie kategorie i dla każdej kategorii wszystkie towary z tej kategorii.

Spróbuj użyć elementów HTML do sformatowania wyniku (prawdopodobnie w XML Spy można to wtedy wyświetlić jeśli użyje się serializacji do (X)HTML).

Zadanie 6.

To samo, ale dla pliku sklep2.xml. Tak, żeby kategorie się nie powtarzały!

Zadanie 7. (Opcjonalne)

Dla dokumentu pracownicy.xml napisz zapytania zwracające dla każdego działu:

  • nazwę działu,
  • liczbę pracowników z podziałem na poszczególne stanowiska,
  • sumaryczną liczbę pracowników.

Definiowanie własnych funkcji

W XQuery istnieje możliwość definiowania własnych funkcji, których następnie można używać w wyrażeniach (także w innych funkcjach). Funkcje powinny być zadeklarowane w prologu dokumentu XQuery (przed ciałem zapytania, obok innych deklaracji).

Własne funkcje powinno się definiować we własnych przestrzeniach nazw lub w predefiniowanej przestrzeni nazw o prefiksie local.

Przykład 6.

declare function local:podwoj(
  $x as xs:double)
  as xs:double?
{ 2* $x };

(: Filtruje wartosci z sekwencji przepuszczając tylko mniejsze od zadanej wartości :)
declare function local:tylkoMniejsze(
  $lista,
  $wartosc as xs:decimal)
{
for $el in $lista
where $el < $wartosc
return $el
};

<wynik>
<pierwszy>
{ local:podwoj(100) }
</pierwszy>
<drugi>
{
  let $seq := (1, 20, 3, 40, 5, 60)
  return local:tylkoMniejsze($seq, 10)
}
</drugi>
</wynik>

Zadanie 8.

Dalej pliki ze sklepem. Zdefiniuj funkcję średnia-cena obliczającą średnią cenę w podanej sekwencji towarów (lub średnią cenę w podanej kategorii).

Używając funkcji napisz zapytanie, które filtruje sklep2.xml zachowując strukturę dokumentu i kolejność elementów towar, ale usuwając towary droższe niż średnia dla danej kategorii.

Zobacz także


Valid XHTML 1.1Valid CSS