Professional Documents
Culture Documents
PRZYKADOWY ROZDZIA
SPIS TRECI
KATALOG KSIEK
KATALOG ONLINE
ZAMW DRUKOWANY KATALOG
TWJ KOSZYK
DODAJ DO KOSZYKA
CENNIK I INFORMACJE
ZAMW INFORMACJE
O NOWOCIACH
ZAMW CENNIK
CZYTELNIA
FRAGMENTY KSIEK ONLINE
Wydawnictwo Helion
ul. Kociuszki 1c
44-100 Gliwice
tel. 032 230 98 63
e-mail: helion@helion.pl
XSLT. Receptury.
Wydanie II
Autor: Salvatore Mangano
Tumaczenie: Anna Trojan
ISBN: 83-246-0461-8
Tytu oryginau: XSLT Cookbook
Format: B5, stron: 664
Spis treci
Przedmowa .....................................................................................................................9
1. XPath ............................................................................................................................. 17
1.0. Wprowadzenie
1.1. Efektywne uywanie osi
1.2. Filtrowanie wzw
1.3. Praca z sekwencjami
1.4. Skracanie kodu warunkw z uyciem wyrae if
1.5. Eliminowanie rekurencji z wyrae for
1.6. Radzenie sobie ze skomplikowan logik z uyciem kwantyfikatorw
1.7. Uywanie operacji na zbiorach
1.8. Uywanie porwna wzw
1.9. Radzenie sobie z rozszerzonym systemem typw XPath 2.0
1.10. Wykorzystywanie rozszerzonego systemu typw XPath 2.0
17
18
22
25
26
29
31
32
33
34
36
37
38
39
39
41
46
48
52
56
58
60
62
63
67
68
76
77
79
82
92
97
103
106
108
113
115
116
117
121
125
126
127
129
131
138
149
153
155
160
161
162
166
168
171
175
Spis treci
181
182
183
186
187
188
190
194
197
198
200
201
207
208
212
227
236
243
250
255
256
258
261
266
270
275
276
279
284
Spis treci
289
290
293
301
305
306
311
335
336
342
345
351
356
362
365
371
372
378
408
416
425
433
436
440
443
447
453
454
458
472
477
478
489
496
511
524
Spis treci
537
538
539
539
540
540
540
541
541
541
542
543
543
555
560
566
578
580
583
584
587
592
597
601
603
607
613
619
629
635
642
Skorowidz ....................................................................................................................647
Spis treci
ROZDZIA 1.
XPath
1.0. Wprowadzenie
XPath jest jzykiem wyrae, ktry jest fundamentalny dla przetwarzania XML. Osignicie
mistrzostwa w posugiwaniu si XSLT bez biegoci w XPath jest tak samo prawdopodobne,
jak osignicie mistrzostwa w posugiwaniu si jzykiem polskim bez znajomoci alfabetu.
Niektrzy czytelnicy pierwszego wydania XSLT. Receptury zrugali mnie za pominicie XPath.
Ten rozdzia zosta dodany czciowo, by zaspokoi ich oczekiwania, a czciowo ze wzgldu na coraz wiksze moliwoci najnowszych specyfikacji XPath 2.0. Wiele z podanych tutaj
receptur da si jednak zastosowa take do XPath 1.0.
W XSLT 1.0 XPath odgrywa trzy kluczowe role. Po pierwsze, jest uywany w szablonach do
adresowania wewntrz dokumentu podczas jego przetwarzania (w celu ekstrakcji danych).
Po drugie, skadnia XPath uywana jest jako jzyk wzorcw w reguach dopasowania dla
szablonw. Po trzecie, uywany jest do prostych oblicze matematycznych i manipulacji acuchami znakw poprzez wbudowane w XPath operatory i funkcje.
XSLT 2.0 utrzymuje i wzmacnia zaleno od XPath 2.0 poprzez korzystanie z nowych moliwoci obliczeniowych XPath 2.0. Waciwie mona nawet postawi tez, e rozszerzone moliwoci XSLT 2.0 wynikaj w duej mierze z rozwoju w XPath 2.0. Nowe opcje XPath 2.0 obejmuj sekwencje, wyraenia regularne, wyraenia warunkowe i iteracyjne, a take ulepszony
system typw zgodnych z XML Schema wraz z du iloci nowych, wbudowanych funkcji.
Kada receptura w tym rozdziale jest zbiorem minireceptur do rozwizywania pewnych klas
problemw z XPath, ktre czsto pojawiaj si przy uywaniu XSLT. Oznaczamy kade wyraenie XPath zgodnie z konwencj komentarzy XPath 2.0 (: komentarz :), jednak uytkownicy XPath/ XSLT 1.0 powinni mie wiadomo, e komentarze takie nie s dozwolon
skadni. Pokazujc rezultat oblicze XPath, ktry jest pusty, uywamy (), co jest jednoczenie metod zapisu pustej sekwencji w XPath 2.0.
17
Rozwizanie
Kade z poniszych rozwiza zorganizowane jest wok powizanych zbiorw osi. Dla kadej grupy przedstawiany jest przykadowy dokument XML wraz z wzem kontekstowym
(ang. context node) opisanym czcionk pogrubion. Zaczono take wyjanienie efektu wyznaczania cieki wraz z oznaczeniem wzw, ktre zostan zaznaczone w wyrnionym
kontekcie. W niektrych przypadkach w rozwizaniu inne wzy zostan potraktowane jako
kontekst sucy zilustrowaniu finezyjnoci danej cieki wyraenia.
18
Rozdzia 1. XPath
(: Wybierz pierwszy element, pod warunkiem e jest to X. W przeciwnym wypadku zwr pusty. :)
*[1][self::X]
Wynik: <X id="1"/>
(: Wybierz ostatnie dziecko, pod warunkiem e jest to X. W przeciwnym wypadku zwr pusty. :)
*[last( )][self::X]
Wynik: ( )
*[last( )][self::Y]
Wynik: <Y id="9"/>
(: Wybierz wszystkich potomkw o nazwie X. :)
descendant::X
Wynik: <X id="1"/> <X id="2"/> <X id="3-1"/> <X id="3-3"/> <X id="4"/> <X id="7"/>
<X id="8"/>
(: Wybierz wze kontekstowy, pod warunkiem e jest to X, i wszystkich potomkw o nazwie X. :)
descendant-or-self::X
Wynik: <X id="1"/> <X id="2"/> <X id="3-1"/> <X id="3-3"/> <X id="4"/> <X id="7"/>
<X id="8"/>
(: Wybierz wze kontekstowy i wszystkich potomkw. :)
descendant-or-self::*
Wynik: <parent> <X id="1"/> <X id="2"/> <Y id="3"> <X id="3-1"/> <Y id="3-2"/> <X
id="3-3"/> </Y> <X id="4"/> <Y id="5"/> <Z id="6"/> <X id="7"/> <X id="8"/> <Y
id="9"/> </parent> <X id="1"/> <X id="2"/> <Y id="3"> <X id="3-1"/> <Y id="3-2"/> <X
id="3-3"/> </Y> <X id="3-1"/> <Y id="3-2"/> <X id="3-3"/> <X id="4"/> <Y id="5"/> <Z
id="6"/> <X id="7"/> <X id="8"/> <Y id="9"/>
Osie rodzestwa
Osie rodzestwa obejmuj preceding-sibling:: i following-sibling::. Zgodnie z nazw
o preceding-sibling zawiera rodzestwo poprzedzajce wze kontekstowy, z kolei following-sibling nastpujce po nim. Rodzestwo to oczywicie wzy dzieci majcych tego
samego rodzica. Wikszo przykadw poniej korzysta z preceding-sibling::, jednak bez
wikszych problemw mona take obliczy wynik dla following-sibling::.
Naley pamita, e uycie pozycyjnego wyraenia ciekowego w formie preceding-sibling
::*[1] oznacza odniesienie si do wza rodzestwa bezporednio poprzedzajcego wze
kontekstowy, a nie do pierwszego wza rodzestwa w kolejnoci dokumentu. Niektre osoby mog by zdziwione, gdy wyniki zwracane s w sekwencji zgodnej z kolejnoci w dokumencie bez wzgldu na to, czy uywa si preceding-sibling:: czy following-sibling::.
Wyraenie ../X, nie bdc w istocie wyraeniem dotyczcym osi, w praktyce jest wykorzystywane do wybrania zarwno poprzedniego, jak i nastpnego wza rodzestwa o nazwie
X wraz z wzem kontekstowym, jeli nosiby on nazw X. Z formalnego punktu widzenia
jest to skrt od parent::node()/X. Naley zauway, e (preceding-sibling::*)[1] oraz
(following-sibling::*)[1] wybior pierwszy poprzedni lub nastpny wze rodzestwa
zgodnie z kolejnoci w dokumencie.
19
20
Rozdzia 1. XPath
Wynik: ( )
(: Pierwszy z elementw poprzedzajcych wze kontekstowy, majcych dziecko A. :)
preceding-sibling::*[A][1]
Wynik: <B id="3"> ...
(: XPath 2.0 pozwala na wiksz elastyczno w wyborze elementw w odniesieniu do ich przestrzeni nazw. W nastpnych
recepturach wykorzystywany jest nastpujcy dokument XML. :)
<Test xmlns:NS="http://helion.pl/ksiazki/xsltre/ns/1"
xmlns:NS2="http://helion.pl/ksiazki/xsltre/ns/2">
<NS:A id="1"/>
<NS2:A id="2"/>
<NS:B id="3"/>
<NS2:B id="3"/>
</Test>
(: Wybierz wszystkie elementy rodzestwa poprzedzajce wze kontekstowy, ktrych przestrze nazw jest przestrzeni
skojarzon z prefiksem NS. :)
preceding-sibling::NS:*
Wynik: <NS:A id="1"/>
(: Wybierz wszystkie wzy rodzestwa poprzedzajce wze kontekstowy, ktrych lokaln nazw jest A. :)
preceding-sibling::*:A
Wynik: <NS:A id="1"/>, <NS2:A id="2"/>
21
Analiza
XPath uywa pojcia osi do podzielenia drzewa dokumentu na podzbiory wzgldem pewnego wza zwanego wzem kontekstowym. Oglnie rzecz biorc, podzbiory te nakadaj
si na siebie; jednak osie przodka, potomka, poprzedzajce i nastpujce dziel dokument
(ignorujc wzy przestrzeni nazw i atrybutw): nie nakadaj si na siebie i razem zawieraj
wszystkie wzy dokumentu. Wze kontekstowy jest ustalany przez jzyk zawierajcy XPath.
W XSLT kontekst ustala si poprzez:
dopasowanie szablonu (<xsl:template match="x"> ... </xsl:template>),
xsl:for-each,
xsl:apply-templates.
Efektywne korzystanie z tego typu wyrae ciekowych stanowi klucz do wykonywania zarwno prostych, jak i bardziej skomplikowanych transformacji. Dowiadczenie z tradycyjnymi jzykami programowania czasami dezorientuje i prowadzi do bdw przy uyciu XPath.
Ja na przykad czsto api si na pisaniu czego w stylu <xsl:if test="preceding-sibling
::X[1]"> </xsl:if>, kiedy naprawd mam na myli <xsl:if test="preceding-sibling
::*[1][self::X]"> </xsl:if>. Prawdopodobnie dzieje si tak, poniewa to drugie jest mao intuicyjnym sposobem powiedzenia sprawd, czy bezporednio nastpujcy wze rodzestwa jest X.
Oczywicie niemoliwoci jest przedstawienie kadej przydatnej kombinacji wyrae ciekowych z uyciem osi. Jednak jeli zrozumie si czci skadowe przedstawione wczeniej, jest
si na najlepszej drodze do zrozumienia znaczenia konstrukcji takich jak preceding-sibling
::X[1]/descendant::Z[A/B] lub jeszcze bardziej skomplikowanych.
22
Rozdzia 1. XPath
Rozwizanie
Wiele z minireceptur z Receptury 1.1 uywa predykatw do filtrowania wzw, jednak te
predykaty oparte byy cile na pozycji wza lub jego nazwie. Tutaj rozwaymy rne predykaty, ktre filtruj na podstawie zawartoci danych. W poniszych przykadach uywamy
prostej cieki elementu dziecka X przed kadym predykatem, jednak mona w miejsce X
wstawi dowolne inne wyraenie ciekowe, cznie z tymi wymienionymi w Recepturze 1.1.
W poniszych przykadach uywamy operatorw porwnania z XPath 2.0 (eq, ne, lt,
le, gt i ge) w miejsce operatorw (=, !=, <, <=, > i >=). Dzieje si tak, poniewa przy
porwnywaniu wartoci niepodzielnych preferowane s nowe operatory. W XPath
1.0 do dyspozycji jest tylko ten drugi zestaw operatorw, naley zatem je odpowiednio zastpi. Nowe operatory zostay wprowadzone w XPath 2.0, gdy maj prostsz
semantyk i w rezultacie powinny by bardziej wydajne. Zoono wczeniejszych
operatorw pojawia si w przypadkach, gdy po ktrej stronie porwnania znajduje
si sekwencja. Wicej na ten temat znajduje si w Recepturze 1.8.
Jeszcze jedna uwaga odnosi si do XPath 2.0 i zwizana jest z faktem, e wersja ta
docza informacj o typie tam, gdzie dostpny jest schemat. Moe to sprawi, e
w poniszych wyraeniach pojawi si bdy typu. Na przykad X[@a = 10] nie
jest tym samym, co X[@a = '10'], jeli atrybut a jest liczb cakowit. Tutaj zakadamy, e schemat nie wystpuje i dlatego wszystkie wartoci niepodzielne s typu
untypedAtomic. Wicej na ten temat znajduje si w Recepturach 1.9 i 1.10.
(: Wybierz dzieci X, ktre maj atrybut a. :)
X[@a]
(: Wybierz dzieci X, ktre maj przynajmniej jeden atrybut. :)
X[@*]
(: Wybierz dzieci X, ktre maj przynajmniej trzy atrybuty. :)
X[count(@*) > 2]
(: Wybierz dzieci X, ktrych atrybuty sumuj si do wartoci mniejszej ni 7. :)
X[sum(foreach $a in @* return number($a)) < 7] (: W XSLT 1.0 naley uy sum(@*) < 7 :)
(: Wybierz dzieci X, ktre nie maj atrybutu o nazwie a. :)
X[not(@a)]
(: Wybierz dzieci X, ktre nie maj adnych atrybutw. :)
X[not(@*)]
(: Wybierz dzieci X, ktre maj atrybut o nazwie a i wartoci '10'. :)
X[@a eq '10']
(: Wybierz dzieci X, ktre maj dziecko o nazwie Z i o wartoci '10'. :)
X[Z eq '10']
(: Wybierz dzieci X majce dziecko o nazwie Z i wartoci, ktra nie jest rwna '10'. :)
X[Z ne '10']
(: Wybierz dzieci X, jeli maj one przynajmniej jedno dziecko bdce wzem tekstowym. :)
X[text( )]
(: Wybierz dzieci X, jeli maj wze tekstowy z przynajmniej jednym znakiem niebdcym znakiem biaym (spacja,
tabulator itd.). :)
X[text( )[normalize-space(.)]]
23
Analiza
Tak jak w przypadku Receptury 1.1 niemoliwe jest przedstawienie wszystkich interesujcych kombinacji predykatw filtrujcych. Jednake opanowanie podanych wyej przykadw
powinno pomc w pniejszym napisaniu dowolnych innych wyrae filtrujcych. Naley
te zauway, e mona tworzy jeszcze bardziej skomplikowane warunki, uywajc operatorw logicznych and, or i funkcji not().
number(@a) > 5 and X[number(@a) < 10]
Jeli uywa si predykatw ze skomplikowanymi wyraeniami ciekowymi, naley rozumie efekt zastosowania nawiasw.
(: Wybierz pierwsze dziecko Y kadego dziecka X wza kontekstowego. Wyraenie to moe skutkowa zwrceniem sekwencji
wicej ni jednego Y. :)
X/Y[1]
(: Wybierz sekwencj wzw X/Y, a nastpnie we pierwszy z nich. To wyraenie zwraca maksymalnie jeden Y. :)
(X/Y)[1]
24
Rozdzia 1. XPath
Rozwizanie
XPath 1.0
W XPath 1.0 nie istnieje pojcie sekwencji i dlatego te receptury nie maj zastosowania. XPath
1.0 ma zbiory wzw. Istnieje jednak idiomatyczny sposb, by skonstruowa pusty zbir wzw z uyciem XSLT 1.0.
(: Pusty zbir wzw. :)
/..
XPath 2.0
(: Konstruktor pustej sekwencji. :)
( )
(: Sekwencja skadajca si z jednego niepodzielnego elementu 1. :)
1
(: Naley skorzysta z przecinka, by skonstruowa sekwencj. Tutaj budujemy sekwencj wszystkich dzieci X danego kontekstu,
nastpnie wszystkich dzieci Y oraz wszystkich dzieci Z. :)
X, Y, Z
(: Naley skorzysta z operatora "to", by skonstruowa przedziay. :)
1 to 10
(: Tutaj czymy przecinek z kilkoma przedziaami. :)
1 to 10, 100 to 110, 17, 19, 23
(: Zmienne i funkcje take mog by wykorzystane. :)
1 to $x
1 to count(para)
(: Sekwencje nie zagniedaj si, zatem ponisze dwie sekwencje s takie same. :)
((1,2,3), (4,5, (6,7), 8, 9, 10))
1,2,3,4,5,6,7,8,9,10
(: Operator "to" nie moe stworzy bezporednio sekwencji malejcej. :)
10 to 1 (: Ta sekwencja jest pusta! :)
(: Zamierzony efekt da si jednak osign w nastpujcy sposb. :)
for $n in 1 to 10 return 11 - $n
(: Usu z sekwencji duplikaty. :)
distinct-values($seq)
(: Zwr wielko sekwencji. :)
count($seq)
25
Analiza
W XPath 2.0 kady element danych (warto) jest sekwencj. Dlatego niepodzielna warto 1
jest tak sam sekwencj jak wynik wyraenia (1 to 10). Innym sposobem przedstawienia
tego faktu jest powiedzenie, e kade wyraenie XPath 2.0 jest przeksztacane na sekwencj.
Sekwencja moe zawiera zero lub wicej wartoci i te wartoci mog by wzami, wartociami niepodzielnymi lub mieszank obu. Odniesienie si do pojedynczych elementw sekwencji rozpoczyna si od pozycji 1 (nie 0, jak mogaby oczekiwa osoba znajca jzyki C lub Java).
XPath 1.0 nie ma sekwencji, a raczej zbiory wzw. Zbiory wzw nie s koncepcj tak jasn, jak sekwencje, ale w wielu przypadkach rnice midzy nimi nie maj znaczenia. Przykadowo, dowolne wyraenie XPath 1.0 korzystajce z funkcji count() i empty() powinno
zachowywa si tak samo w XPath 2.0. Zalet XPath 2.0 jest to, e sekwencja jest elementem
typu first-class, czyli moe by jawnie skonstruowana i przetwarzana z uyciem rozmaitych
nowych funkcji XPath 2.0. Receptury w tej czci wprowadzaj wiele wanych idiomw sekwencji; kolejne pojawi si w innych recepturach tej ksiki.
26
Rozdzia 1. XPath
Rozwizanie
XPath 1.0
Jest kilka prostych sztuczek, ktre mona zastosowa w XPath 1.0, by unikn rozwlekych xsl
:choose w prostych sytuacjach. Sztuczki te opieraj si przede wszystkim na fakcie, e false
konwertowane jest do 0, a true do 1 w przypadku uycia ich w kontekcie matematycznym.
Zatem na przykad warto minimalna, maksymalna i bezwzgldna mog by obliczone bezporednio w XPath 1.0. W poniszych przykadach naley zaoy, e $x i $y zawieraj liczby
cakowite.
(: Warto minimalna. :)
($x <= $y) * $x + ($y < $x) * $y
(: Warto maksymalna. :)
($x >= $y) * $x + ($y > $x) * $y
(: Warto bezwzgldna. :)
(1 - 2 * ($x < 0)) * $x
XPath 2.0
Dla prostych przypadkw z rozwizania dla XPath 1.0 (warto minimalna, maksymalna, bezwzgldna) istniej teraz wbudowane funkcje XPath. Dla innych prostych warunkw naley
skorzysta z nowego wyraenia warunkowego if.
(: Warto domylna brakujcego atrybutu jest ustalana na 10. :)
if (@x) then @x else 10
(: Warto domylna brakujcego elementu jest ustalana na "unauthorized". :)
if (password) then password else 'unauthorized'
(: Ochrona przed dzieleniem przez zero. :)
if ($d ne 0) then $x div $d else 0
(: Tekst elementu bdcego argumentem, jeli zawiera przynajmniej jeden znak inny od znaku biaego (spacja, tabulator);
w przeciwnym wypadku pojedyncza spacja. :)
if (normalize-space(para)) then string(para) else ' '
Analiza
Wikszo weteranw programowania w XSLT 1.0 prawdopodobnie kuli si ze strachu za
kadym razem, gdy ma doda do szablonu dodatkowy fragment kodu warunkowego. Ja sam
tak robi. Czsto pniej z blem przechodz przez kolejne zawioci sposobw dopasowywania do wzorca w XSLT, by tylko zminimalizowa ilo kodu z warunkami. Dzieje si tak
nawet nie dlatego, e taki kod jest w XSLT bardziej skomplikowany czy niewydajny, a dlatego, e jest tak straszliwie rozwleky. Proste xsl:if nie jest jeszcze takie ze, ale jeli naley
przedstawi logik if-then-else, to trzeba skorzysta ze znacznie obszerniejszego xsl:choose.
Okropno!
W XSLT 2.0 istnieje dla tego alternatywa, jednak pochodzi ona raczej z XPath 2.0, ni z samego XSLT 2.0. Na pierwszy rzut oka mona odnie wraenie, e XPath zosta niejako pogwacony przez wprowadzenie czego, co w programowaniu proceduralnym nazywa si cigiem
27
instrukcji sterujcych. Jednake jak tylko zacznie si w peni korzysta z XPath 2.0, wysuwa
si wniosek, e zarwno XPath, jak i XSLT zyskay na tych ulepszeniach. Ponadto wyraenia
warunkowe XPath 2.0 nie uniewaniaj elementu xsl:if, a co najwyej redukuj jego uycie
w tych przypadkach, gdy jest to niewygodne. Dla zilustrowania powyszych informacji mona porwna nastpujce fragmenty kodu:
<!-- XSLT 1.0 -->
<xsl:variable name="size">
<xsl:choose>
<xsl:when test="$x > 3">duy</xsl:when>
<xsl:otherwise>may</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<!-- XSLT 2.0 -->
<xsl:variable name="size" select="if ($x gt 3) then 'duy' else 'may' "/>
Wyraenia te znajduj swoje zastosowanie take w sytuacjach niezdefiniowanych lub nieoczekiwanych wynikw. W poniszym przykadzie mamy potrzeb, by wynikiem byo 0, a nie
number('Infinity').
if ($divisor ne 0) then $dividend div $divisor else 0
Oczywicie, mona take skonstruowa bardziej skomplikowane warunki. Nastpujcy fragment suy do dekodowania numerowanej listy.
if (size eq 'XXL') then 50
else if (size eq 'XL') then 45
else if (size eq 'L') then 40
else if (size eq 'M') then 34
else if (size eq 'S') then 32
else if (size eq 'XS') then 29
else -1
Tutaj zakadamy, e wze kontekstowy ma tylko jedno dziecko; w przeciwnym razie wyraenie to jest niedozwolone (cho wtedy mona uy size[1]). Polegamy take na fakcie, e
jeli szukany element nie zostaje znaleziony, index-of zwraca pust sekwencj, do ktrej nastpnie dodajemy 7, by mc obsuy przypadek else.
28
Rozdzia 1. XPath
Rozwizanie
XPath 1.0
Nie da si zastosowa w XPath 1.0. Naley zamiast tego skorzysta z szablonu rekurencyjnego XSLT.
XPath 2.0
Naley w tym wyraeniu skorzysta z XPath 2.0. Poniej pokazujemy cztery przypadki,
w ktrych wyraenie for moe odwzorowywa sekwencje wyjciowe i wejciowe rnice
si wielkoci.
Agregacja
(: Suma kwadratw. :)
sum(for $x in $numbers return $x * $x)
(: rednia kwadratw. :)
avg(for $x in $numbers return $x * $x)
Odwzorowanie
(: Odwzorowanie sekwencji sw we wszystkich akapitach na sekwencj dugoci sw. :)
for $x in //para/tokenize(., ' ') return string-length($x)
(: Odwzorowanie sekwencji sw w akapicie na sekwencj dugoci sw zawierajcych wicej ni trzy litery. :)
for $x in //para/tokenize(., ' ') return if (string-length($x) gt 3) the
string-length($x) else ( )
(: To samo, co powyej, ale z warunkiem dla sekwencji wejciowej. :)
for $x in //para/tokenize(., ' ')[string-length(.) gt 3] return string-length($x)
Generowanie
(: Generowanie sekwencji kwadratw pierwszych 100 liczb cakowitych. :)
for $i in 1 to 100 return $i * $i
(: Generowanie sekwencji kwadratw w odwrotnej kolejnoci. :)
for $i in 0 to 10 return (10 - $i) * (10 - $i)
Rozszerzanie
(: Odwzorowanie sekwencji akapitw na zduplikowan sekwencj akapitw. :)
for $x in //para return ($x, $x)
(: Duplikowanie sw. :)
for $x in //para/tokenize(., ' ') return ($x, $x)
29
czenie
(: Dla kadego klienta wynikiem jest identyfikator i suma wszystkich jego zamwie. :)
for $cust in doc('customer.xml')/*/customer
return
($cust/id/text( ),
sum(for $ord in doc('orders.xml')/*/order[custID eq $cust/id]
return ($ord/total)) )
Analiza
Jak zaznaczono w Recepturze 1.4, dodanie instrukcji sterujcych do jzyka wyrae takiego
jak XPath moe na pocztku wydawa si dziwne lub nawet bdne. Ale gdy tylko odkryje
si wyzwalajc moc tych konstrukcji w XPath 2.0, szybko pokonuje si wszelkie wtpliwoci. Jest tak w szczeglnoci w przypadku wyraenia for z XPath 2.0.
Sia for ujawnia si w peni, kiedy uwiadomi si sobie, jak mona wykorzysta to wyraenie
w celu zredukowania wielu skomplikowanych rekurencyjnych rozwiza XSLT 1.0 do jednej
linii wyraenia XPath 2.0. Rozwamy na przykad problem obliczania sum w XSLT 1.0. Jeli
potrzebna jest tylko prosta suma, nie ma problemu, bo wbudowana funkcja XPath 1.0 sum
doskonale si sprawdzi. Jednak kiedy potrzebne jest otrzymanie sumy kwadratw, konieczne
staje si napisanie wikszego, niewygodnego i mniej przejrzystego szablonu rekurencyjnego.
Waciwie dua cz pierwszego wydania tej ksiki skadaa si z takich wanie powtarzalnych rozwiza do radzenia sobie z rekurencyjn gimnastyk. W XPath 2.0 suma kwadratw
to nic innego jak sum(for $x in $numbers return $x * $x), gdzie $numbers zawiera sekwencj liczb, ktre chcemy doda. Ile drzew mogem uratowa, gdyby to uatwienie byo
dostpne w XPath 1.0!
Wyraenie for kryje w sobie jednak jeszcze wicej mocy. Nie jest si ju ograniczonym do
tylko jednej zmiennej iteracyjnej. Moliwe jest poczenie kilku zmiennych i stworzenie zagniedonych ptli, ktre mog tworzy sekwencje z powizanych ze sob w skomplikowanym dokumencie wzw.
(: Zwraca sekwencj skadajc si z wartoci atrybutu id poszczeglnych elementw para oraz elementu ref bdcego
dzieckiem danego elementu para. :)
for $s in /*/section,
$p in $s/para,
$r in $p/ref
return ($p/@id, $r)
Naley zauway, e poza tym, e jest krtsze powysze wyraenie nie rni si niczym od:
for $s in /*/section
return for $p in $s/para
return for $r in $p/ref
return ($p/@id, $r)
Warto take zauway, e nie ma potrzeby korzystania z zagniedonych ptli for, jeli bardziej
eleganck reprezentacj zamierzonej sekwencji przedstawia tradycyjne wyraenie ciekowe.
(: To uycie "for" jest tylko rozwlekym sposobem napisania "/*/section/para/ref". :)
for $s in /*/section,
$p in $s/para,
$r in $p/ref return $r
30
Rozdzia 1. XPath
Czasami warto zna pozycj kadego z elementw sekwencji w czasie jej przetwarzania. Nie
mona tu uy funkcji position() tak, jak by to zrobiono dla xsl:for-each gdy wyraenie XPath nie zmienia pozycji kontekstu. Ten sam efekt da si jednak osign, korzystajc z poniszego wyraenia:
for $pos in 1 to count($sequence),
$item in $sequence[$pos]
return $item , $pos
Rozwizanie
XPath 1.0
Jeli warunek oparty jest na rwnoci, wtedy w zupenoci wystarczy semantyka operatorw
= i != z XPath 1.0 i 2.0.
(: Prawdziwe, jeli wystpuje odniesienie do przynajmniej jednej czci. :)
//section/@id = //ref/@idref
(: Prawdziwe, jeli istnieje odniesienie do kadej czci. :)
count(//section) = count(//section[@id = //ref/@idref])
XPath 2.0
W XPath 2.0 naley skorzysta z wyrae some i every, by osign ten sam efekt.
(: Prawdziwe, jeli wystpuje odniesienie do przynajmniej jednej czci. :)
some $id in //para/@id satisfies $id = //ref/@idref
(: Prawdziwe, jeli istnieje odniesienie do kadej czci. :)
every $id in //section/@id satisfies $id = //ref/@idref
31
Analiza
Semantyka =, !=, <, >, <=, >= w XPath 1.0 i 2.0 czasami zaskakuje niewtajemniczonych, kiedy
jeden z operandw jest sekwencj lub zbiorem wzw XPath 1.0. Dzieje si tak, poniewa
operatory s obliczane do wartoci logicznej prawda, jeli istnieje co najmniej jedna para
wartoci z kadej strony wyraenia, ktra da si porwna zgodnie z relacj. W XPath 1.0 czasami dziaa to na korzy uytkownika, jak pokazalimy wczeniej, jednak kwestia ta potrafi
niekiedy przyprawi o bl gowy i sprawi, e chce si wrci do pitej klasy podstawwki,
gdzie matematyka jeszcze miaa sens. Przykadowo, mona domniemywa, e relacja $x = $x
jest zawsze prawdziwa, a jednak nie jest tak, jeli $x jest pust sekwencj! Wynika to z faktu,
e nie da si znale pary rwnych elementw wewntrz dwch pustych sekwencji.
Rozwizanie
XPath 1.0
Operator | oznaczajcy sum zbiorw na wzach jest obsugiwany przez XPath 1.0, ale trzeba skorzysta z maych sztuczek, eby uzyska cz wspln zbiorw i ich rnic.
(: Suma zbiorw. :)
$set1 | $set2
(: Cz wsplna zbiorw. :)
$set1[count(. | $set2) = count($set2)]
(: Rnica zbiorw. :)
$set1[count(. | $set2) != count($set2)]
XPath 2.0
Operator | jest nadal obecny w XPath 2.0, jednak dodano do niego take union jako jego alias.
Dodatkowo dostpne s intersect i except dla uzyskania odpowiednio: czci wsplnej zbiorw i ich rnicy.
$set1 union $set2
(: Cz wsplna zbiorw. :)
$set1 intersect $set2
(: Rnica zbiorw. :)
$set1 except $set2
Analiza
W XPath 2.0 zbiory wzw s zastpione sekwencjami. W przeciwiestwie do zbiorw wzw sekwencje s uporzdkowane i mog zawiera zduplikowane elementy. Jednake przy
32
Rozdzia 1. XPath
uyciu operacji na zbiorach XPath 2.0 zarwno duplikaty, jak i uporzdkowanie s ignorowane, zatem sekwencje zachowuj si tak samo, jak zbiory. Wynik operacji na zbiorach nie bdzie nigdy zawiera duplikatw, nawet jeli posiaday je zbiory wejciowe.
Operator except jest uywany w idiomie XPath 2.0 sucym do wybrania wszystkich atrybutw z wyjtkiem podanego zbioru.
(: Wszystkie atrybuty z wyjtkiem @a. :)
@* except @a
(: Wszystkie atrybuty z wyjtkiem @a i @b. :)
@* except @a, @b
Co ciekawe, XPath pozwala na operacje na zbiorach tylko na sekwencjach wzw. Niedozwolone s wartoci niepodzielne. Dzieje si tak, poniewa operacje na zbiorach odbywaj si po
identyfikatorze wza, a nie jego wartoci. Efekt zbiorw wartoci mona uzyska korzystajc
z poniszych wyrae XPath 2.0; w XPath 1.0 naley skorzysta z rekurencji XSLT. Wicej na
ten temat w rozdziale 9.
(: Suma zbiorw. :)
distinct-values( ($items1, $items2) )
(: Cz wsplna zbiorw. :)
distinct-values( $items1[. = $items2] )
(: Rnica zbiorw. :)
distinct-values( $items1[not(. = $items2)] )
Zobacz rwnie
Receptury 9.1 i 9.2 zawieraj wicej przykadw operacji na zbiorach.
Rozwizanie
XPath 1.0
W poniszych przykadach naley zaoy, e $x i $y zawieraj pojedynczy wze z tego samego dokumentu. Trzeba te pamita, e kolejno w dokumencie oznacza kolejno, w jakiej
wzy wystpuj w dokumencie.
(: Sprawd, czy $x i $y s tym samym wzem. :)
generate-id($x) = generate-id($y)
(: Mona take skorzysta z tego, e operator | usuwa duplikaty. :)
count($x|$y) = 1
33
(: Sprawd, czy $x poprzedza $y w kolejnoci w dokumencie (zadziaa tylko, jeli $x i $y nie s atrybutami). :)
count($x/preceding::node( )) < count($y/preceding::node( )) or
$x = $y/ancestor::node( )
(: Sprawd, czy $x nastpuje po $y w kolejnoci w dokumencie (zadziaa tylko, jeli $x i $y nie s atrybutami). :)
count($x/following::node( )) < count($y/following::node( )) or
$y = $x/ancestors::node( )
XPath 2.0
(: Sprawd, czy $x i $y s tym samym wzem. :)
$x is $y
(: Sprawd, czy $x poprzedza $y w kolejnoci w dokumencie. :)
$x << $y
(: Sprawd, czy $x nastpuje po $y w kolejnoci w dokumencie. :)
$x >> $y
Analiza
Nowe operatory porwnania z XPath 2.0 s prawdopodobnie bardziej wydajne i na pewno
atwiejsze do zrozumienia ni ich odpowiedniki z XPath 1.0. Jednake uywajc XSLT 2.0,
nie napotka si zbyt wielu sytuacji, w ktrych operatory te s wymagane. W wielu sytuacjach
zdarza si, e myli si o uyciu << lub >> w miejscu, gdzie preferowany jest element. xsl:
for-each-group.
Rozwizanie
Wikszo niezgodnoci pomidzy XPath/XSLT 1.0 i 2.0 wynika z bdw typu. Dzieje si
tak bez wzgldu na to, czy schemat jest obecny, czy te nie. Wiele problemw napotkanych
przy przenoszeniu dotychczasowych aplikacji pomidzy XSLT 1.0 i XSLT 2.0 (ktre rni si
midzy innymi wersj XPath) mona wyeliminowa dziki uywaniu trybu zgodnoci z 1.0.
<xsl:stylesheet version="1.0">
<!-- ... -->
</xsl:stylesheet>
Moim zdaniem kady w ktrym momencie przestaje w kocu uywa trybu zgodnoci. XPath
2.0 posiada kilka udogodnie dla konwersji typw. Po pierwsze, mona bezporednio zastosowa funkcje konwertujce.
(: Konwersja pierwszego dziecka X kontekstu na liczb. :)
number(X[1]) + 17
34
Rozdzia 1. XPath
XPath 2.0 posiada take konstruktory typw, mona wic bezporednio kontrolowa interpretacj acucha znakw.
(: Stworzenie daty z acucha znakw. :)
xs:date("2006-06-01")
(: Stworzenie liczb zmiennoprzecinkowych podwjnej precyzji z acucha znakw. :)
xs:double("1.1e8") + xs:double("23000")
Wreszcie XPath posiada operatory castable as, cast as oraz treat as. Przez wikszo
czasu korzysta si z dwch pierwszych z nich.
if ($x castable as xs:date) then $x cast as xs:date else xs:date("1970-01-01")
Operator treat as nie jest konwersj jako tak, a raczej stwierdzeniem, ktre obiecuje procesorowi XPath, e w czasie wykonywania programu warto ta bdzie zgodna z danym typem.
Jeli tak si nie dzieje, wystpi bd typu. W XPath 2.0 dodano treat as, by implementatorzy XPath mogli dokona statycznego (w czasie kompilacji) sprawdzania typw obok sprawdzania dynamicznego (w czasie wykonywania), pozwalajc jednoczenie na selektywne wyczenie sprawdzania statycznego. Statyczne sprawdzanie typw w implementacjach XSLT
2.0 bdzie najprawdopodobniej stosunkowo rzadkie, mona wic treat as na razie zignorowa. O wiele bardziej prawdopodobne jest pojawienie si go w wyszej klasy procesorach
XQuery, ktre dokonuj statycznego sprawdzania typw, by uatwi rozmaite optymalizacje.
Analiza
Praca z procesorem XSLT 2.0 w trybie kompatybilnoci z wersj 1.0 nie oznacza, e nie mona
korzysta z adnych nowych cech 2.0. Zacza on po prostu kilka regu konwersji z XPath 1.0.
Pozwala na automatyczn konwersj na liczby typw nieliczbowych uytych w kontekcie,
kw w kontekcie, w ktrym oczekiwane s acuchy znakw, poprzez atomizacj, a nastpnie uycie funkcji string().
(: W trybie zgodnoci nastpujcy fragment zwraca wynik 2, jednak powoduje bd typu w 2.0. :)
string-length(1 + 2 + 3 + 4 + 5)
Automatycznie usuwa elementy z sekwencji o rozmiarze dwa lub wikszym, jeli s one
uyte w kontekcie, w ktrym oczekiwany jest element pojedynczy. Czsto si tak dzieje,
kiedy wynik wyraenia ciekowego podawany jest do funkcji.
<poem>
<line>There once was a programmer from Nantucket.</line>
<line>Who liked his bits in a bucket.</line>
<line>He said with a grin</line>
<line>and drops of coffee on his chin,</line>
<line>"If XSLT had a left-shift, I would love it!"</line>
<poem>
(: W trybie zgodnoci oba wyraenia zwracaj wynik 43, jednak to pierwsze powoduje bd typu w 2.0. :)
string-length(/poem/line)
string-length(/poem/line[1])
35
Rozwizanie
Jeli sprawdza si poprawno dokumentw ze schematem, wzom wynikowym przypisuje
si informacj o ich typie. Typy te mona nastpnie sprawdza w XPath 2.0 (a take w dopasowywaniu szablonw w XSLT 2.0).
(: Testowanie, czy wszystkie elementy invoiceDate zostay sprawdzone jako daty. :)
if (order/invoiceDate instance of element(*, xs:date)) then "invoicing complete" else
"invoicing incomplete"
instance of jest przydatny tylko w sprawdzaniu poprawnoci ze schematem. Dodatkowo nie jest wcale odpowiednikiem castable as. Przykadowo, 10 castable
as xs:positiveInteger jest zawsze prawdziwe, podczas gdy 10 instance of
xs:positiveInteger nigdy nie bdzie prawdziwe, gdy literay liczbowe s oznaczone jako xs:decimal.
Zalet sprawdzania poprawnoci jest jednak nie tylko moliwo sprawdzania typw z uyciem instance of, lecz take bezpieczestwo i wygoda wynikajca ze wiadomoci, e po
przejciu przez sprawdzanie poprawnoci adne niespodziewane bdy nie powinny si ju
pojawi. To moe prowadzi do bardziej zwizych arkuszy stylw.
(: Bez sprawdzania poprawnoci powinno si kodowa nastpujco. :)
for $order in Order return xs:date($order/invoiceDate) - xs:date($order/createDate)
(: Wiedzc, e wszystkie elementy danych zostay sprawdzone, mona opuci konstruktor xs:date :).
for $order in Order return $order/invoiceDate - $order/createDate
Analiza
Osobicie wol uywa XML Schema jako dokumentu ze specyfikacj, a nie narzdzia do sprawdzania poprawnoci. Dlatego te pisz transformacje XSLT w taki sposb, by byy odporne na
bdy typu i uywam bezporednich konwersji tam, gdzie jest to konieczne. Arkusze stylw
napisane w ten sposb bd dziaa bez wzgldu na obecno sprawdzania poprawnoci.
Jeli zacznie si pisa arkusze stylw polegajce na sprawdzaniu poprawnoci, ogranicza si
do takich implementacji, ktre musz przeprowadza sprawdzanie poprawnoci. Z drugiej
strony jeli standardy firmowe mwi, e wszystkie dokumenty XML musz by sprawdzane
ze schematem przed ich przetworzeniem, rwnie dobrze mona uproci swj XSLT, opierajc si na pewnoci, e odpowiednie typy danych pojawi si w odpowiednich sytuacjach.
36
Rozdzia 1. XPath