You are on page 1of 26

IDZ DO

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

Setki gotowych rozwiza dla programistw XML i XSLT


Jzyk XSLT to jedna z najwaniejszych technologii sucych do przeksztacania
dokumentw XML. Za pomoc tego jzyka mona pobiera dane XML, przeksztaca
je na strony HTML, a nawet generowa na ich podstawie wykresy w formacie SVG.
Niniejsza ksika to praktyczny przewodnika po tych oraz wielu innych funkcjach
jzyka XSLT, a przedstawiony w niej materia obejmuje take rozbudowane moliwoci
najnowszej wersji XSLT 2.0.
Ksika XSLT. Receptury. Wydanie II zawiera setki gotowych rozwiza problemw
stojcych przed programistami uywajcymi XSLT. Znajdziesz tu sposoby wykonania
rnych zada zwizanych z transformacj danych XML, zarwno tych podstawowych,
jak i skomplikowanych. Poznasz rozmaite techniki przetwarzania dokumentw XML
bazujce na obu wersjach jzyka XSLT. Zrozumiesz take praktyczne zagadnienia
zwizane z wydajnoci tworzonych rozwiza i wygod ich stosowania. W wielu
recepturach znajdziesz alternatywne rozwizania problemw, dziki czemu bdziesz
mg wybra technik najbardziej odpowiadajc wykonywanemu przez Ciebie
zadaniu.
Opis XSLT 2.0
Wprowadzenie do jzyka XPath
Wyszukiwanie danych w dokumentach XML
Przeksztacanie danych XML na rne formaty (zwyky tekst, HTML, SVG, XML)
Przetwarzanie acuchw znakw i wyrae matematycznych
Obsuga dat i czasu
Obsuga zapyta XML
Obsuga XSLT w innych jzykach
Generowanie kodu
Zaawansowane zastosowania XSLT
Testowanie arkuszy XSLT
Gotowe rozwizania przedstawione w tej ksice pomog
Ci w szybkim tworzeniu niezawodnych programw

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

2. acuchy znakw ..........................................................................................................37


2.0. Wprowadzenie
2.1. Sprawdzanie, czy dany acuch znakw
koczy si innym acuchem znakw
2.2. Znajdowanie pozycji podacucha znakw
2.3. Usuwanie wybranych znakw z acucha znakw
2.4. Znajdowanie podacuchw na kocu acucha znakw
2.5. Powtrzenie acucha znakw N razy
2.6. Odwracanie acucha znakw
2.7. Zastpowanie tekstu
2.8. Zmiana wielkoci liter
2.9. Tokenizacja acucha znakw
2.10. Radzenie sobie bez wyrae regularnych
2.11. Wykorzystywanie wyrae regularnych
2.12. Korzystanie z rozszerze dla acuchw znakw EXSLT

37
38
39
39
41
46
48
52
56
58
60
62
63

3. Liczby i matematyka .....................................................................................................67


3.0. Wprowadzenie
3.1. Formatowanie liczb
3.2. Zaokrglanie liczb z okrelon dokadnoci
3.3. Konwersja z liczb rzymskich na arabskie
3.4. Konwersja z jednej podstawy na inn
3.5. Implementacja popularnych funkcji matematycznych
3.6. Obliczanie sum i iloczynw
3.7. Znajdowanie minimum i maksimum
3.8. Obliczanie funkcji statystycznych
3.9. Obliczanie funkcji kombinatorycznych
3.10. Testowanie bitw

67
68
76
77
79
82
92
97
103
106
108

4. Data i czas .....................................................................................................................113


4.0. Wprowadzenie
4.1. Obliczanie dnia tygodnia
4.2. Obliczanie ostatniego dnia miesica
4.3. Otrzymanie nazw dni i miesicy
4.4. Obliczanie numeru dnia juliaskiego i bezwzgldnego dla podanej daty
4.5. Obliczanie numeru tygodnia dla podanej daty
4.6. Praca z kalendarzem juliaskim
4.7. Praca z kalendarzem ISO
4.8. Praca z kalendarzem muzumaskim
4.9. Praca z kalendarzem ydowskim
4.10. Formatowanie daty i czasu
4.11. Ustalenie wit wieckich i religijnych

113
115
116
117
121
125
126
127
129
131
138
149

5. Wybieranie wzw i przechodzenie drzew ............................................................ 153


5.0. Wprowadzenie
5.1. Ignorowanie zduplikowanych elementw
5.2. Wybr wszystkich elementw z wyjtkiem jakiego okrelonego
5.3. Wybieranie wzw poprzez kontekst
5.4. Przechodzenie drzewa w porzdku preorder
5.5. Przechodzenie drzewa w porzdku postorder
5.6. Przechodzenie drzewa w porzdku in-order
5.7. Przechodzenie drzewa w porzdku level-order
5.8. Przetwarzanie wzw wedug pozycji

153
155
160
161
162
166
168
171
175

6. Wykorzystywanie XSLT 2.0 .........................................................................................181


6.0. Wprowadzenie
6.1. Konwersja prostych nazwanych szablonw na funkcje XSLT
6.2. Przewaga for-each-group nad metod grupowania Muencha

Spis treci

181
182
183

6.3. Modularyzacja i tryby


6.4. Uywanie typw dla bezpieczestwa i dokadnoci
6.5. Unikanie puapek przy przenoszeniu aplikacji z XSLT 1.0 na 2.0
6.6. Emulowanie wzorcw projektowych i metod ponownego uycia
znanych z programowania zorientowanego obiektowo
6.7. Przetwarzanie nieustrukturyzowanego tekstu
za pomoc wyrae regularnych
6.8. Rozwizywanie trudnych problemw serializacyjnych z tablicami znakw
6.9. Zwracanie wielu dokumentw
6.10. Radzenie sobie z literaami acuchowymi zawierajcymi cudzysowy
6.11. Rozumienie nowych moliwoci starych cech XSLT 1.0

186
187
188
190
194
197
198
200
201

7. Konwersja XML na tekst .............................................................................................207


7.0. Wprowadzenie
7.1. Radzenie sobie z biaymi znakami
7.2. Eksportowanie XML do danych rozdzielonych ogranicznikami
7.3. Utworzenie raportu z kolumnami
7.4. Wywietlanie hierarchii
7.5. Numerowanie tekstowych danych wyjciowych
7.6. Zawijanie tekstu do okrelonej szerokoci i wyrwnania

207
208
212
227
236
243
250

8. Z XML na XML .............................................................................................................255


8.0. Wprowadzenie
8.1. Konwersja atrybutw na elementy
8.2. Konwersja elementw na atrybuty
8.3. Zmiana nazwy elementw lub atrybutw
8.4. czenie dokumentw o identycznym schemacie
8.5. czenie dokumentw o rnych schematach
8.6. Dzielenie dokumentw
8.7. Spaszczanie hierarchii XML
8.8. Pogbianie hierarchii XML
8.9. Reorganizacja hierarchii XML

255
256
258
261
266
270
275
276
279
284

9. Zapytania XML ........................................................................................................... 289


9.0. Wprowadzenie
9.1. Wykonywanie operacji na zbiorach wzw
9.2. Wykonywanie operacji na zbiorach wzw
z uyciem semantyki wartoci
9.3. Ustalanie rwnoci zbiorw wedug wartoci
9.4. Wykonywanie zapyta zachowujcych struktur
9.5. Zczenia
9.6. Implementowanie przypadkw uycia zapyta XML z W3C w XSLT

Spis treci

289
290
293
301
305
306
311

10. Z XML na HTML ...........................................................................................................335


10.0. Wprowadzenie
10.1. Uywanie XSLT jako jzyka stylizacji
10.2. Tworzenie dokumentw z hiperczami
10.3. Tworzenie tabel HTML
10.4. Tworzenie ramek
10.5. Tworzenie arkuszy stylw sterowanych przez dane
10.6. Tworzenie samodzielnej transformacji HTML
10.7. Wypenianie formularza

335
336
342
345
351
356
362
365

11. Z XML do SVG .............................................................................................................. 371


11.0. Wprowadzenie
11.1. Transformacja istniejcego SVG
11.2. Tworzenie nadajcych si do ponownego uycia narzdzi
generujcych SVG dla wykresw
11.3. Tworzenie diagramu drzewa
11.4. Tworzenie interaktywnych stron internetowych z SVG

371
372
378
408
416

12. Generowanie kodu .................................................................................................... 425


12.0. Wprowadzenie
12.1. Generowanie definicji staych
12.2. Generowanie kodu przeczajcego
12.3. Generowanie zalepek dla kodu obsugi komunikatw
12.4. Generowanie opakowa dla danych
12.5. Generowanie pretty-printer
12.6. Generowanie klienta webowego do wprowadzania danych testowych
12.7. Generowanie CGI do wprowadzania danych testowych
12.8. Generowanie kodu z modeli UML za pomoc XMI
12.9. Generowanie XSLT z XSLT

425
433
436
440
443
447
453
454
458
472

13. Receptury na specjalistyczne aplikacje w XSLT ........................................................477


13.0. Wprowadzenie
13.1. Konwersja dokumentw Visio VDX na SVG
13.2. Praca z arkuszami kalkulacyjnymi Excel XML
13.3. Generowanie map poj XTM z modeli UML za pomoc XMI
13.4. Generowanie stron internetowych z map poj XTM
13.5. Dostarczanie dokumentacji SOAP za pomoc WSDL

477
478
489
496
511
524

14. Rozszerzanie i osadzanie XSLT ..................................................................................537


14.0. Wprowadzenie
14.1. Funkcje rozszerze w Saxonie
14.2. Elementy rozszerze Saxona

Spis treci

537
538
539

14.3. Funkcje rozszerze Xalan-Java 2


14.4. Funkcje rozszerze Javy z uyciem przestrzeni nazw formatu klasy
14.5. Funkcje rozszerze Javy z uyciem przestrzeni nazw formatu pakietu
14.6. Funkcje rozszerze Javy z uyciem przestrzeni nazw formatu Javy
14.7. Tworzenie skryptw funkcji rozszerze za pomoc kodu skryptu
wewntrz programu
14.8. Elementy rozszerze Xalan-Java 2
14.9. Elementy rozszerze Javy
14.10. Tworzenie skryptw elementw rozszerze
14.11. Funkcje rozszerze MSXML
14.12. Uywanie wbudowanych rozszerze Saxona i Xalana
14.13. Rozszerzanie XSLT za pomoc JavaScriptu
14.14. Dodawanie funkcji rozszerze z uyciem Javy
14.15. Dodawanie elementw rozszerze za pomoc Javy
14.16. Uywanie XSLT w Perlu
14.17. Uywanie XSLT w Javie

539
540
540
540
541
541
541
542
543
543
555
560
566
578
580

15. Testowanie i usuwanie bdw ................................................................................ 583


15.0. Wprowadzenie
15.1. Efektywne uywanie xsl:message
15.2. ledzenie przetwarzania arkusza stylw
za pomoc jego dokumentu wejciowego
15.3. Automatyzacja wstawiania danych wyjciowych debugera
15.4. Umieszczanie osadzonych danych testw jednostkowych
w arkuszach stylw narzdzi
15.5. Tworzenie testw jednostkowych
15.6. Testowanie warunkw brzegowych i bdw

583
584
587
592
597
601
603

16. Programowanie oglne i funkcyjne ...........................................................................607


16.0. Wprowadzenie
16.1. Tworzenie polimorficznego XSLT
16.2. Tworzenie oglnych funkcji agregujcych elementy
16.3. Tworzenie oglnych funkcji ograniczonej agregacji
16.4. Tworzenie oglnych funkcji odwzorowania
16.5. Tworzenie oglnych generatorw zbiorw wzw

607
613
619
629
635
642

Skorowidz ....................................................................................................................647

Spis treci

ROZDZIA 1.

XPath

Neo, prdzej czy pniej zorientujesz si, tak jak ja wczeniej,


e jest rnica pomidzy poznaniem cieki a kroczeniem po niej.
Morpheus (Matrix)

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

1.1. Efektywne uywanie osi


Problem
Naley wybra wzy w drzewie XML w sposb uwzgldniajcy skomplikowane relacje wewntrz struktury hierarchicznej.

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.

Osie dziecka i potomka


O dziecka jest domyln osi w XPath. Oznacza to, e nie ma potrzeby uywania specyfikacji osi child::, cho osoby pedantyczne mog tak uczyni. Mona sign w gb drzewa
XML, korzystajc z osi descendant:: i descendant-or-self::. Pierwsza z nich wyklucza
wze kontekstowy, natomiast druga uwzgldnia go.
<Test id="descendants">
<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>
</Test>
(: Wybierz wszystkie dzieci o nazwie X :)
X
(: to samo co child::X :)
Wynik: <X id="1"/> <X id="2"/> <X id="4"/> <X id="7"/> <X id="8"/>
(: Wybierz pierwsze dziecko X :)
X[1]
Wynik: <X id="1"/>
(: Wybierz ostatnie dziecko X :)
X[last( )]
Wynik: <X id="8"/>

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.

1.1. Efektywne uywanie osi

19

<!-- Przykadowy dokument z zaznaczonym wzem kontekstowym. -->


<Test id="preceding-siblings">
<A id="1"/>
<A id="2"/>
<B id="3"/>
<A id="4"/>
<B id="5"/>
<C id="6"/>
<A id="7"/>
<A id="8"/>
<B id="9"/>
</Test>
(: Wybierz wszystkie wzy rodzestwa A poprzedzajce wze kontekstowy. :)
preceding-sibling::A
Wynik: <A id="1"/> <A id="2"/> <A id="4"/>
(: Wybierz wszystkie wzy rodzestwa A nastpujce po wle kontekstowym. :)
following-sibling::A
Wynik: <A id="8"/>
(: Wybierz wszystkie wzy rodzestwa poprzedzajce wze kontekstowy. :)
preceding-sibling::*
Wynik: <A id="1"/> <A id="2"/> <B id="3"/> <A id="4"/> <B id="5"/> <C id="6"/>
(: Wybierz pierwszy poprzedzajcy wze rodzestwa o nazwie A, liczc od wza kontekstowego (biecego). :)
preceding-sibling::A[1]
Wynik: <A id="4"/>
(: Element bezporednio poprzedzajcy wze kontekstowy (biecy), pod warunkiem e wzem tym jest A. :)
preceding-sibling::*[1][self::A]
Wynik: ( )
(: Gdyby wzem kontekstowym by <A id="8"/>, wynikiem byoby <A id="7"/>. :)
(: Wszystkie poprzedzajce wzy rodzestwa niebdce A. :)
preceding-sibling::*[not(self::A)]
Wynik: <B id="3"/> <B id="5"/> <C id="6"/>
(: Dla nastpnych receptur naley uy tego dokumentu. :)
<Test id="preceding-siblings">
<A id="1">
<A/>
</A>
<A id="2"/>
<B id="3">
<A/>
</B>
<A id="4"/>
<B id="5"/>
<C id="6"/>
<A id="7"/>
<A id="8"/>
<B id="9"/>
</Test>
(: Element bezporednio poprzedzajcy wze kontekstowy, pod warunkiem e ma on dziecko A. :)
preceding-sibling::*[1][A]

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"/>

Osie rodzica i przodkw


O rodzica (parent::) odnosi si do rodzica wza kontekstowego. Wyraenie parent::X nie
powinno by mylone z ../X. To pierwsze utworzy sekwencj z dokadnie jednym elementem, pod warunkiem e rodzicem wza kontekstowego bdzie X, bd zwrci pusty element.
To drugie jest skrconym zapisem wyraenia parent::node()/X, ktre wybierze wszystkie
wzy rodzestwa o nazwie X dla danego wza kontekstowego, wcznie z samym wzem
kontekstowym, o ile nosi on nazw X.
By przej do wyszych poziomw drzewa XML (dziadkw, pradziadkw, prapradziadkw
i tak dalej), naley uy wyraenia ancestor:: lub ancestor-or-self::. To pierwsze pomija wze kontekstowy, to drugie zawiera go.
(: Wybierz rodzica wza kontekstowego, pod warunkiem e jest nim element X. W przeciwnym wypadku zwr pusty
element. :)
parent::X
(: Wybierz rodzica wza kontekstowego. Moe by pusty, tylko jeli wze kontekstowy jest elementem z najwyszego
poziomu. :)
parent::*
(: Wybierz rodzica, jeli znajduje si on w przestrzeni nazw skojarzonych z prefiksem NS. Prefiks musi by zdefiniowany,
w przeciwnym razie jest to bd. :)
parent::NS:*
(: Wybierz rodzica bez wzgldu na jego przestrze nazw, pod warunkiem e jego lokalna nazwa to X. :)
parent::*:X
(: Wybierz wszystkich przodkw (z rodzicem wcznie) o nazwie X. :)
ancestor::X
(: Wybierz wszystkich przodkw wza kontekstowego o nazwie X oraz sam wze kontekstowy, jeli nazywa si X :)
ancestor-or-self::X

1.1. Efektywne uywanie osi

21

Osie poprzedzajce i nastpujce


Osie poprzedzajce i nastpujce maj potencjalnie moliwo wyboru duej liczby wzw,
gdy bior one pod uwag wszystkie elementy poprzedzajce wze kontekstowy lub po nim
nastpujce w kolejnoci dokumentu, z wyczeniem wzw przodkw lub potomkw. O
nastpujca pomija potomkw, a o poprzedzajca przodkw. Nie naley zapomnie, e
obie osie pomijaj wzy przestrzeni nazw i ich atrybuty.
(: Wszystkie wzy poprzedzajce o nazwie X. :)
preceding::X
(: Najbliszy wze poprzedzajcy o nazwie X. :)
preceding::X[1]
(: Najdalszy wze nastpujcy o nazwie X. :)
following::X[last( )]

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.

1.2. Filtrowanie wzw


Problem
Naley wybra wzy w oparciu o dane, ktre zawieraj, a nie ich nazw lub pozycj.

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(@*) &lt; 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(.)]]

1.2. Filtrowanie wzw

23

(: Wybierz dzieci X, jeli maj one jakie dziecko. :)


X[node( )]
(: Wybierz dzieci X, jeli zawieraj one wze komentarza. :)
X[comment( )]
(: Wybierz dzieci X, jeli zawieraj one @a, ktrego warto numeryczna jest mniejsza od 10. Wyraenie to bdzie dziaao
zarwno w XPath 1.0, jak i 2.0, bez wzgldu na to, czy @a jest acuchem znakw czy liczb. :)
X[number(@a) < 10]
(: Wybierz X, jeli ma co najmniej jeden poprzedzajcy go wze rodzestwa o nazwie Z z atrybutem y, ktry nie jest
rwny 10. :)
X[preceding-sibling::Z/@y ne '10']
(: Wybierz dzieci X, ktrych warto acucha znakw skada si z jednego znaku spacji. :)
X[. = ' ']
(: Dziwny sposb uzyskania pustej sekwencji! :)
X[false( )]
(: To samo co uycie wyraenia X. :)
X[true( )]
(: Elementy X z dokadnie 5 dzieci. :)
X[count(*) eq 5]
(: Elementy X z dokadnie 5 dzieci (wczajc w to wzy elementw, tekstowe, komentarzy i PI, jednak nie wzy atrybutw). :)
X[count(node( )) eq 5]
(: Elementy X, ktre maj dokadnie 5 wzw dowolnego typu. :)
X[count(@* | node( )) eq 5]
(: Pierwsze dziecko X, jeli ma warto 'some text'; w przeciwnym wypadku zwraca pusty element. :)
X[1][. eq 'some text']
(: Wybierz wszystkie dzieci X o wartoci 'some text' i zwr pierwsze z nich lub pusty element, jeli takie dziecko nie wystpuje.
Ujmujc to w prostszy sposb, pierwsze dziecko, ktre ma warto acucha znakw 'some text'. :)
X[. eq 'some text'][1]

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]

Informatyk powiedziaby, e operator warunkowy [] wie bardziej, ni operator ciekowy /.

24

Rozdzia 1. XPath

1.3. Praca z sekwencjami


Problem
Naley przetworzy zbiory dowolnych wzw i niepodzielnych wartoci pochodzcych z dokumentu bd dokumentw XML.

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)

1.3. Praca z sekwencjami

25

(: Sprawd, czy sekwencja jest pusta. :)


empty($seq) (: lepsze ni uycie count($seq) eq 0 :)
(: Znajd wszystkie pozycje elementu w sekwencji. "index-of" zwraca indeksy jako sekwencj liczb cakowitych
odpowiadajcych kademu elementowi sekwencji podanej jako pierwszy argument, ktry jest rwny z elementem
podanym jako drugi argument. :)
index-of($seq, $item)
(: Okrelanie podzbiorw. :)
(: Do 3 elementw z $seq, rozpoczynajc od drugiego. :)
subsequence($seq, 2, 3)
(: Wszystkie elementy z $seq na pozycji od 3 od koca sekwencji. :)
subsequence($seq, 3)
(: Wstaw sekwencj $seq2 przed trzeci element sekwencji pocztkowej, $seq1. :)
insert-before($seq1, 3, $seq2)
(: Skonstruuj now sekwencj, ktra zawiera wszystkie elementy sekwencji $seq1 z wyjtkiem trzeciego. :)
remove($seq1, 3)
(: Jeli naley usun kilka elementw, mona rozway nastpujce wyraenia. :)
$seq1[not(position( ) = (1,3,5))]
$seq1[position( ) gt 3 and position( ) lt 7]

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.

1.4. Skracanie kodu warunkw z uyciem wyrae if


Problem
Przy wyraaniu prostych warunkw if-then-else kod XSLT jest zbyt dugi i skomplikowany ze wzgldu na uycie rozwlekego XML.

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

1.4. Skracanie kodu warunkw z uyciem wyrae if

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 &gt; 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' "/>

Sdz, e wikszo czytelnikw bdzie wolaa rozwizanie z XPath 2.0, ni to poprzednie,


z XSLT 1.0.
Jedn wan rzecz w wyraeniach warunkowych XPath jest to, e else nie jest opcjonalne.
Programici jzyka C doceni ten fakt, porwnujc go sobie z wyraeniem a ? b : c z tego
jzyka. Czsto uywa si pustego elementu () w przypadku, gdy nie ma adnej sensownej
wartoci do wstawienia do wyraenia else.
Wyraenia warunkowe s przydatne do zwracania wartoci domylnych wtedy, gdy nie ma
schematu z wartociami domylnymi.
(: Ustalenie wartoci domylnej opcjonalnego atrybutu. :)
if (@optional) then @optional else 'some-default'
(: Ustalenie wartoci domylnej opcjonalnego elementu. :)
if (optional) then optional else 'some-default'

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

Jednake w tym wypadku uycie sekwencji moe by adniejszym rozwizaniem, szczeglnie


jeli zastpimy dosowne sekwencje zmiennymi, ktre mog by inicjalizowane z zewntrznego pliku XML.
(50,45,40,34,32,29,-1)[(index-of((('XXL', 'XL', 'L', 'M', 'S', 'XS')), size), 7)[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

1.5. Eliminowanie rekurencji z wyrae for


Problem
Chcemy przeksztaci sekwencj wejciow na sekwencj wyjciow w taki sposb, by kady
element wyjciowej by dowolnie skomplikowan funkcj wejciowej i by wielko obu sekwencji niekoniecznie bya taka sama.

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)

1.5. Eliminowanie rekurencji z wyrae for

29

(: Odwzorowanie sw na sowa wraz z ich dugoci. :)


for $x in //para/tokenize(., ' ') return ($x, string-length($x))

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

1.6. Radzenie sobie ze skomplikowan logik


z uyciem kwantyfikatorw
Problem
Naley przetestowa sekwencj pod ktem obecnoci warunku w kilku bd wszystkich jej
elementach.

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

W XPath 2.0 mona jednak bez wikszego wysiku pj jeszcze dalej.


(: Istnieje jaka cz, ktra zawiera odniesienie do wszystkich sekcji z wyjtkiem siebie samej. :)
some $s in //section satisfies
every $id in //section[@id ne $s/@id]/@id satisfies $id = $s/ref/@idref
(: $sequence2 jest czci $sequence1 :)
count($sequence2) <= count($sequence1) and
every $pos in 1 to count($sequence1),
$item1 in $sequence1[$pos],
$item2 in $sequence2[$pos] satisfies $item1 = $item2

Po usuniciu sprawdzania zliczania count w poprzednim wyraeniu kod ten zapewnia, e


przynajmniej pierwsze count($sequence1) elementw w $sequence2 jest takiej samo, jak te
odpowiadajce im w $sequence1.

1.6. Radzenie sobie ze skomplikowan logik z uyciem kwantyfikatorw

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.

1.7. Uywanie operacji na zbiorach


Problem
Naley przetworzy sekwencje tak, jakby byy one zbiorami matematycznymi.

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

W XPath 1.0 potrzebne s bardziej niezgrabne wyraenia, jak poniej:


@*[local-name(.) != 'a' and local-name(.) != '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.

1.8. Uywanie porwna wzw


Problem
Naley zidentyfikowa wzy lub odnie si do nich wedug ich pozycji w dokumencie.

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

1.8. Uywanie porwna wzw

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.

1.9. Radzenie sobie z rozszerzonym systemem


typw XPath 2.0
Problem
Rygorystyczne zasady zwizane z typami w XPath 2.0 sprawiaj, e zorzeczy si na W3C
i tskni za jzykiem Perl.

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

(: Konwersja liczby w $n na acuch znakw. :)


concat("id-", string($n))

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,

w ktrym oczekiwane s liczby, poprzez atomizacj, a nastpnie uycie funkcji number().


(: W trybie zgodnoci nastpujcy fragment zwraca 18.1, jednak powoduje bd typu w 2.0. :)
"1.1" + "17"

Pozwala na automatyczn konwersj typw innych ni acuch znakw na acuch zna-

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])

1.9. Radzenie sobie z rozszerzonym systemem typw XPath 2.0

35

1.10. Wykorzystywanie rozszerzonego systemu


typw XPath 2.0
Problem
Przy przetwarzaniu XML cile przestrzega si zalece XML Schema i chce si wykorzysta
jego zalety.

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

You might also like