Serwis prównujący ceny z wielu sklepów internetowych



Podobne dokumenty
Środowisko publikacyjne oparte na XML-u. Szymon Zioło 1 maja 2004

Słowem wstępu. Część rodziny języków XSL. Standard: W3C XSLT razem XPath 1.0 XSLT Trwają prace nad XSLT 3.0

Język XSLT. UEK w Krakowie Janusz Stal & Grażyna Paliwoda-Pękosz. UEK w Krakowie Janusz Stal & Grażyna Paliwoda-Pękosz

LABORATORIUM 5 WSTĘP DO SIECI TELEINFORMATYCZNYCH WPROWADZENIE DO XML I XSLT

I. Informacje ogólne. Jednym z takich systemów jest Mambo.

Język JAVA podstawy. wykład 1, część 2. Jacek Rumiński. Politechnika Gdańska, Inżynieria Biomedyczna

Cocoon środowisko publikacyjne oparte na XML-u

Zawartość. Wstęp. Moduł Rozbiórki. Wstęp Instalacja Konfiguracja Uruchomienie i praca z raportem... 6

XQTav - reprezentacja diagramów przepływu prac w formacie SCUFL przy pomocy XQuery

Temat: Ułatwienia wynikające z zastosowania Frameworku CakePHP podczas budowania stron internetowych

znajdowały się różne instrukcje) to tak naprawdę definicja funkcji main.

XML extensible Markup Language 3

Być może jesteś doświadczonym programistą, biegle programujesz w Javie,

Continuous Integration z ClickOnce

ABC języka HTML i XHTML / Maria Sokół. wyd. 2. Gliwice, cop Spis treści

Po zakończeniu rozważań na temat World Wide Web, poznaniu zasad organizacji witryn WWW, przeczytaniu kilkudziesięciu stron i poznaniu wielu nowych

Instrukcja obsługi DHL KONWERTER 1.6

Wprowadzenie do arkuszy stylistycznych XSL i transformacji XSLT

Facelets ViewHandler

Webowy generator wykresów wykorzystujący program gnuplot

INSTRUKCJA INSTALACJI I KONFIGURACJI APLIKACJI WEBSOFT SITE ANALYZER 2.7.1

Instrukcja obsługi Multiconverter 2.0

Komunikacja i wymiana danych

World Wide Web? rkijanka

Przykłady tworzenia aplikacji komponentowych w technologii JavaServer Faces 2.1 na podstawie

INSTRUKCJA INSTALACJI

Architektury Usług Internetowych. Laboratorium 2. Usługi sieciowe

Dokumentacja Użytkownika Systemu

WYKŁAD 1 METAJĘZYK SGML CZĘŚĆ 1

Wybrane działy Informatyki Stosowanej

Generator recept. Program pomagający tworzyć wypełnione wydruki recept lekarskich. Instrukcja obsługi użytkownika

Extensible Markup Language III

Java jako język programowania

Backend Administratora

Instrukcja instalacji środowiska testowego na TestingCup wersja 1.0

Silent setup SAS Enterprise Guide (v 3.x)

Programowanie obiektowe

Dokumentacja Użytkownika Systemu

29. Poprawność składniowa i strukturalna dokumentu XML

1 90 min. Aplikacje WWW Harmonogram spotkań, semestr zimowy (studia stacjonarne)

Programowanie obiektowe. Literatura: Autor: dr inŝ. Zofia Kruczkiewicz

METODY REPREZENTACJI INFORMACJI

Aplikacje WWW Wprowadzenie

Data modyfikacji:

Instrukcja instalacji PS Bonus Pack do IBM SPSS Statistics 20 w systemie operacyjnym Windows

Instrukcja instalacji PHP-Hypercachera Refresher Standard oraz PHP-Hypercachera Refresher GZIP na Twojej witrynie

System Zarządzania Treścią

Jak ustawić cele kampanii?

Wskaźniki a tablice Wskaźniki i tablice są ze sobą w języku C++ ściśle związane. Aby się o tym przekonać wykonajmy cwiczenie.

Typy przetwarzania. Przetwarzanie zcentralizowane. Przetwarzanie rozproszone

Aktualizacja środowiska JAVA a SAS

Funkcje wyszukiwania i adresu PODAJ.POZYCJĘ

PHP: bazy danych, SQL, AJAX i JSON

Tworzenie aplikacji Web Alicja Zwiewka. Page 1

Dariusz Brzeziński. Politechnika Poznańska, Instytut Informatyki

Tomasz Boiński: 1. Pozycjonowanie stron i zastosowanie mod_rewrite

5. Mechanizm szablonów.

SSI Katalog. Program do katalogowania zawartości dysków. Dariusz Kalinowski

Podstawy technologii WWW

Instrukcja obsługi i konfiguracji dodatku Ceneo dla Virtuemart 2 v 1.0.1

Qmail radość listonosza. Autorzy: Bartosz Krupowski, Marcin Landoch IVFDS

Pomoc dla systemu WordPress

SUM Edukacja Techniczno Informatyczna Języki i Systemy Programowania. Wykład 3. dr Artur Bartoszewski - WYKŁAD: Języki i Systemy Programowania,

Tworzenie i obsługa wirtualnego laboratorium komputerowego

Dokumentacja Użytkownika Systemu. Integracja z Okazje.info, Skąpiec, Sklepy24

Programowanie obiektowe zastosowanie języka Java SE

Instrukcja instalacji oprogramowania dla środowiska Windows

Dokumentacja Użytkownika Systemu

Dokumentacja Użytkownika Systemu

Programowanie dla początkujących w 24 godziny / Greg Perry, Dean Miller. Gliwice, cop Spis treści

Aplikacje internetowe laboratorium XML, DTD, XSL

Nadzorowanie stanu serwerów i ich wykorzystania przez użytkowników

WINDOWS Instalacja serwera WWW na systemie Windows XP, 7, 8.

Generatory pomocy multimedialnych

Języki i narzędzia programowania III. Łukasz Kamiński Wykład II

XML w bazach danych i bezpieczeństwie

Nowoczesne aplikacje internetowe w praktyce

XML materiały dydaktyczne - Kurs Podstawowy XSL - wprowadzenie. XSL warstwa przekształcania (XSLT) oraz prezentacji informacji (XSL FO).

E-commerce. Genialnie proste tworzenie serwisów w PHP i MySQL.

Aktualizowanie systemów operacyjnych

Dokumentacja Użytkownika Systemu

Programowanie Strukturalne i Obiektowe Słownik podstawowych pojęć 1 z 5 Opracował Jan T. Biernat

Rozpoczynamy import Kreator uruchamiamy przyciskiem Z tekstu, znajdującym się na karcie Dane, w grupie Dane zewnętrzne.

Podstawowym zadaniem, które realizuje

Generated by Foxit PDF Creator Foxit Software For evaluation only. System Szablonów

DVD2one DVD2one 1.4 Start Program Start Screen Compression Mode Constant Ratio Variable Ratio Copy Mode Movie-only Full disk Join: Movie-only

Dokumentacja Użytkownika Systemu

WPROWADZENIE DO JĘZYKA JAVA

Przetwarzanie dokumentów XML za pomocą XSLT ( r.)

Rys. 1. Widok uruchomienia polecenia apt-get install build-essential. Rys. 2. Widok uruchomienia polecenia apt-get install apache2

INSTRUKCJA INSTALACJI I KONFIGURACJI APLIKACJI WEBSOFT CEIDG MONITOR

Komputer nie myśli. On tylko wykonuje nasze polecenia. Nauczmy się więc wydawać mu rozkazy

CMS- kontakty (mapa)

Dokumentacja wstępna TIN. Rozproszone repozytorium oparte o WebDAV

XHTML - Extensible Hypertext Markup Language, czyli Rozszerzalny Hipertekstowy Język Oznaczania.

Budowa i oprogramowanie komputerowych systemów sterowania. Laboratorium 4. Metody wymiany danych w systemach automatyki DDE

Instrukcja użytkownika Porównywarki cen Liquid

Bazy danych i strony WWW

KARTA KURSU. Przetwarzanie dokumentów XML i zaawansowane techniki WWW

Transkrypt:

Warsztat Przemysław Pokrywka, Przemysław Kazienko Na CD: Na płycie CD umieściliśmy spakowane źródła systemu Cocoon w wersji 2.1.2 (cocoon/cocoon2.1.2-src), kod źródłowy zmodyfikowanego komponentu HTML Generator (cocoon/ HTMLGenerator.java), aplikację zaprezentowaną w artykule (katalog zestawienie-cen). Serwis prównujący ceny z wielu sklepów internetowych D zięki wielości sklepów internetowych, konsumenci zainteresowani kupnem określonego towaru mogą wybrać ofertę najlepiej spełniającą ich oczekiwania. To jednak tylko teoria. W praktyce na odnalezienie najkorzystniejszej oferty traci się dużo czasu. Z pomocą przychodzą wtedy serwisy porównujące ceny z wielu sklepów. W artykule krok po kroku zbudujemy taki mocno uproszczony, lecz działający i dający się rozszerzać serwis, zestawiający ze sobą ceny procesorów z trzech sklepów internetowych. Problemy do rozwiązania Serwis, który zamierzamy stworzyć, będzie możliwie najprostszy. Składał się będzie z pojedynczej strony, zawierającej tabelę cen procesorów w trzech sklepach (Rysunek 3). Każdemu wierszowi będzie przypisany jeden procesor, każdej kolumnie jeden sklep, a na przecięciu wiersza i kolumny znajdzie się cena procesora w danym sklepie. Dzięki takiemu układowi będziemy mogli szybko zorientować się, w którym sklepie możemy zakupić interesujący nas procesor po najniższej cenie. Budowa jednak nawet tak prostego serwisu postawi nas w obliczu poważnych problemów. Musimy odpowiedzieć sobie na pytanie, jak z poziomu programu uzyskać potrzebne nam dane, w szczególności aktualne ceny in- Przemysław Pokrywka jest studentem ostatniego roku informatyki na Wydziale Informatyki i Zarządzania Politechniki Wrocławskiej. Szczególnie interesuje się językiem Java, w którym programuje od 6 lat, a także dobrymi praktykami rozwoju oprogramowania, wzorcami projektowymi, refaktoryzacją i programowaniem ekstremalnym. Jest entuzjastą oprogramowania open source. Kontakt z autorem: emo@skrzynka.pl Przemysław Kazienko od 5 lat prowadzi wykład z języka XML na Wydziale Informatyki i Zarządzania Politechniki Wrocławskiej. Jest także współautorem książki XML na poważnie oraz licznych artykułów o tym języku. Wraz ze studentami prowadzi serwis poświęcony językowi XML Centrum XML, dostępny pod adresem: http://www.centrumxml.pwr.wroc.pl. Kontakt z autorem: kazienko@pwr.wroc.pl, http://www.pwr.wroc.pl/~kazienko. 70 Rysunek 1. Witryny trzech sklepów internetowych teresujących nas procesorów, oraz jak poradzić sobie z problemem odmiennego nazywania tych samych procesorów w różnych sklepach. Dostęp do danych HTML Mamy szczęście, jeśli sklepy, których oferty porównujemy, udostępniły nam swoje bazy danych przez protokoły w rodzaju ODBC. Wówczas sprawa pobrania potrzebnych danych sprowadza się do oprogramowania dostępu do tych baz za pomocą dobrze znanych technik. Co jednak zrobić, gdy jedyne dane, jakimi dysponujemy, to strony internetowe tych sklepów w formacie HTML? Tu zaczynają się schody, bo z gąszczu nie zawsze poprawnych składniowo znaczników, opisujących sposób prezentacji, trzeba wydobyć interesujące nas informacje: kategorię produktu, producentów, nazwy, ceny oraz dostępność towaru. Oczywiście moglibyśmy posłużyć się algorytmami analizy tekstu. Z pewnością pomyślałeś już, Czytelniku, o wyrażeniach regularnych, techniki te jednak wciąż mają swoje wady. Wyrażenia regularne służące do wydobywania interesujących nas danych potrafią być bardzo skomplikowane, a przez to trudne do modyfikacji, gdy strona, z której pobieramy dane, zostanie zmodyfikowana. Niemal każda zmiana na stronie wymusza zmianę w wyrażeniu regularnym. Dodatkowo, dla niektórych stron opracowanie odpowiednich wyrażeń może być bardzo trudne lub jest wręcz niemożliwe. Zupełnie inaczej sprawa wyglądałaby, gdyby sklep udostępniał swoją ofertę w postaci pliku XML, na przykład poprzez mechanizm web servi- www.software.com.pl

Serwis porównujący ceny z wielu sklepów internetowych Szybki start Do uruchomienia systemu niezbędny jest J2SDK w wersji 1.4. Zaczynamy od rozpakowania dystrybucji Cocoona i podmienienia pliku src/blocks/html/java/org/apache/cocoon/ generation/htmlgenerator.java na jego nową wersję (z katalogu cocoon na CD). Ustawiamy zmienną środowiskową JAVA_ HOME tak, by wskazywała katalog z Javą, na przykład: set JAVA_HOME=c:\j2sdk1.4.2._04 Następnie kompilujemy Cocoona, uruchamiając w jego głównym katalogu skrypt build.bat oraz kopiujemy katalog zestawienie-cen z CD do podkatalogu build/webapp. Po tych zabiegach możemy już uruchomić platformę Cocoon poleceniem: cocoon.bat servlet Działający przykład możemy teraz oglądać wpisując w przeglądarce lokalny adres: http://localhost:8888/zestawienie-cen/zestawienie ces. Nawet gdyby różne sklepy stosowały swoje własne formaty XML, wydobycie interesujących nas danych byłoby proste wystarczy rzut oka na dokument w takim formacie, by wiedzieć, jakich wyrażeń XPath użyć. R E K Niestety, rzeczywistość nas nie rozpieszcza. Sklepy, mając na uwadze przeciętnych internautów, udostępniają swoją ofertę wyłącznie w wersji HTML i nie widzą sensu inwestowania w inne sposoby prezentacji swoich danych. A gdyby ów HTML w cudowny sposób zamienił się w XML-a, z którego można by wydobywać dane za pomocą prostych ścieżek XPath? Mamy dobre wieści: taka możliwość istnieje i to zupełnie za darmo. Dostarcza ją Apache Cocoon, darmowe środowisko publikacyjne, oparte na XML-u, rozpowszechniane na zasadach liberalnej (Apache-style) licencji open-source. Transformacji niepoprawnego HTML-a do poprawnego składniowo XHTML-a potrafi mianowicie dokonać jeden z komponentów Cocoona HTML Generator. Samo środowisko Cocoon, ze względu na bogactwo oferowanych możliwości, zasługuje na oddzielny artykuł (polecamy warsztaty Szymona Zioło XML i Cocoon książka kucharska, Software 2.0, nr 9/2003), nam jednak do korzystania z niego wystarczy poznanie samych jego podstaw. Wyjątkiem od tej reguły będzie konieczność wejścia w dosyć intymny kontakt z kodem źródłowym HTML Generatora. Uczynimy to w celu dodania do niego pełnej obsługi polskich znaków, ograniczonej domyślnie do Unikodu. Polskie strony WWW najczęściej bywają bowiem mniej łaskawe i serwisy sklepów internetowych kodowane są w większości za pomocą ISO-8859-2 (Latin 2) lub Windows-1250. L A M A

Warsztat Cocoon Cocoon jest opartym na XML-u środowiskiem do budowy aplikacji webowych. Od swoich dalekich krewnych PHP, ASP, JSP i wszelkiego rodzaju skryptów server-side różni się filozofią działania. Nacisk położony jest w nim przede wszystkim na separację zagadnień (ang. separation of concerns). Aplikacje w nim budowane można łatwiej niż gdzie indziej podzielić na warstwy danych, logiki i prezentacji. Osiąga się to poprzez: korzystanie z danych źródłowych w formacie XML, neutralnym pod względem prezentacji, wydzielenie zazwyczaj z wykorzystaniem XSLT opisu sposobu transformacji danych do formatów wyjściowych, m.in. HTML, PDF, SVG, JPEG, PNG, TXT, WML, RDF, plików MS Excela, VRML, wyspecyfikowanie logiki przetwarzania, czyli kolejności i rodzaju przekształceń, w planie witryny (ang. sitemap) dedykowanym pliku konfiguracyjnym aplikacji webowej (oczywiście w formacie XML). Drugą zasadniczą cechą Cocoona jest jego budowa komponentowa. Każdy komponent realizuje jeden określony krok przetwarzania. Może to być pobranie danych z pliku, z sieci lub z bazy danych, przekształcenie danych arkuszem XSLT, czy w końcu przekazanie wersji HTML przeglądarce. Komponenty komunikują się ze sobą za pomocą zdarzeń SAX, dzięki czemu można je łączyć w potoki (ang. pipelines), podobnie jak w przypadku zestawiania procesów w Unixie, przekazując wyjście jednego komponentu na wejście drugiego. W planie witryny deklarujemy, których komponentów i w jakiej kolejności używamy w celu zrealizowania określonego żądania. Wraz z instalacją Cocoona otrzymujemy bogaty zestaw komponentów, wystarczających do realizacji większości typowych zadań. W razie potrzeby możemy także wspomóc się napisanymi ręcznie stronami JSP (Cocoon jest napisany w Javie i działa w kontenerze serwletów) lub XSP (extensible Server Pages), czyli w pełni XML-owymi, rozszerzalnymi stronami interpretowanymi po stronie serwera. W każdej chwili możemy też rozbudować Cocoona o własne komponenty wymaga to jednak znajomości Javy i wykorzystywanej w Cocoonie architektury komponentów Avalon. Unifikacja nazw towarów Skąd wiadomo, że Procesor AMD DURON 1800 MHz oznacza to samo, co Duron 1800Mhz Applebread lub AMD Duron 1.8GHz? Dla każdego średnio zorientowanego użytkownika może to być oczywiste. Sęk w tym, że dla komputera to zupełnie różne ciągi znaków. Żeby móc wygenerować sensowne zestawienie, trzeba w jakiś sposób przekazać maszynie, że te trzy napisy oznaczają dokładnie to samo. Można w tym celu spróbować zastosować jakąś funkcję badającą podobieństwo tekstów. Można też próbować normalizować teksty: sortować wyrazy wewnątrz nazwy, usuwać białe znaki, zamieniać wszystkie duże litery na małe, a znaki na słowa (na przykład + na plus ), itd. Tych podejść nie będziemy jednak stosować w naszym systemie, choćby ze względu na chęć zachowania jego prostoty. Do naszych celów doskonale nada się prosty słownik nazw, Listing 1. Słownik towarów <?xml version="1.0" encoding="utf-8"?> <slownik> <kategoria nazwa="procesory"> <producent nazwa="amd"> <czesc nazwa="amd Duron 1800 MHz"> <askryptor>amd Duron 1.8GHz <askryptor>procesor AMD DURON 1800 MHz <askryptor>duron 1800Mhz Applebread <czesc nazwa="amd Athlon XP 2500+ Barton"> <askryptor>amd Athlon XP 2500+ Barton <askryptor>procesor AMD ATHLON XP 2500+ - 333MHz <askryptor>athlon XP 2500+ Barton <czesc nazwa="amd Athlon XP 2200+"> <askryptor>amd Athlon XP 2200+ <askryptor>procesor AMD ATHLON XP 2200+ - 266MHz <askryptor>athlon XP 2200+ </producent> <producent nazwa="intel"> <czesc nazwa="intel Pentium 4 2.8 GHz BOX"> <askryptor>intel Pentium4 2.8GHz Prescott BOX <askryptor>procesor INTEL PENTIUM 4 2.8 GHz 800MHz BOX <askryptor>intel PIV 2,80GHZ 800 Socket 478 BOX <czesc nazwa="intel Pentium 4 3.0 GHz BOX"> <askryptor>intel Pentium4 3.0GHz Hyper-Threading BOX <askryptor>procesor INTEL PENTIUM 4 3.0 GHz 800MHz BOX <askryptor>intel PIV 3,00GHZ 800 Socket 478 BOX <czesc nazwa="intel Celeron 2600 MHz"> <askryptor>intel Celeron 2.6GHz Northwood <askryptor>procesor INTEL CELERON 2600 MHz <askryptor>intel Celeron 2600 SOC.478 OEM </producent> </kategoria> <!-- inne kategorie --> </slownik> 72 www.software.com.pl

Serwis porównujący ceny z wielu sklepów internetowych Listing 2. Budowa serwisu plik sitemap.xmap <?xml version="1.0" encoding="iso-8859-2"?> <map:sitemap xmlns:map="http://apache.org/cocoon/sitemap/1.0"> <map:components> <map:generators default="file"> <map:generator name="html" src="org.apache.cocoon.s generation.htmlgenerator"> <jtidy-config>jtidy.properties</jtidy-config> <in-encoding>iso-8859-2</in-encoding> </map:generator> </map:generators> <map:transformers default="xslt"/> <map:serializers default="html"/> <map:readers default="resource"/> <map:matchers default="wildcard"/> <map:pipes default="caching"/> </map:components> <map:pipelines> <map:pipeline> <!-- Aktualizacja danych źródłowych co 12 godz. --> <map:parameter name="expires" value="access plus 12 hours"/> <map:match pattern="age"> <map:generate src="http://www.sklep.age.pl/s list.php?m_grupa=pr&m_sort=n_nazwa" type="html"/> <map:serialize type="xml"/> <map:match pattern="arest"> <map:generate src="http://www.arest.pl/s index.php?inc=cennik&katid=1" type="html"> <map:parameter name="in-encoding" value="windows-1250"/> </map:generate> <map:serialize type="xml"/> <map:match pattern="proline"> <map:generate src="http://www.proline.pl/s shop.php?kat=procesory" type="html"/> <map:serialize type="xml"/> </map:pipeline> <map:pipeline> <map:match pattern="zestawienie"> <map:generate src="slownik.xml"/> <map:transform src="glowny.xsl"/> <map:serialize type="xhtml"/> </map:pipeline> </map:pipelines> </map:sitemap> zapisany w postaci dokumentu XML (Listing 1), w którym wymienione zostaną reprezentacyjne nazwy części komputerowych (te, które będą wyświetlane w docelowym zestawieniu) deskryptory, oraz ich nie zalecane odpowiedniki (te, które występują w sklepach) askryptory. W celu większej przejrzystości ostatecznego zestawienia, części pogrupujemy wg kategorii i producenta. W naszym przykładzie z procesorami oznaczałoby to, że deskryptorem byłby na przykład AMD Duron 1800 MHz, a wymienione wcześniej nazwy byłyby askryptorami. System, po napotkaniu nazwy na stronie sklepu, wyszuka ją w słowniku, i w przypadku odnalezienia, dalej posłuży się już tylko jej deskryptorem. Takie rozwiązanie pociąga za sobą konieczność ciągłej ręcznej aktualizacji słownika nazw towarów. W zamian daje pewność poprawnego kojarzenia towarów występujących na stronach różnych sklepów, czego tak łatwo nie bylibyśmy w stanie zagwarantować, nawet używając skomplikowanych algorytmów porównywania tekstów. Uzyskaliśmy odpowiedzi na zasadnicze pytania: w jaki sposób uzyskać dane ze sklepów, oraz jak je unifikować. Pora teraz na wykorzystanie tej wiedzy w praktyce. Naszym pierwszym krokiem będzie... Konfiguracja środowiska pracy Do instalacji Cocoona potrzebny nam będzie Java 2 Software Development Kit. Sama maszyna wirtualna nie wystarczy, gdyż Cocoon jest od pewnego czasu rozpowszechniany tylko w postaci źródeł i wymagana jest jego kompilacja. Ściągnięty J2SDK instalujemy do wybranego przez nas katalogu (najlepiej, żeby jego ścieżka nie zawierała spacji) i ustawiamy zmienną środowiskową JAVA_HOME tak, by wskazywała na ten katalog. Zmiennej tej potrzebuje skrypt kompilujący Cocoona, żeby wiedzieć, gdzie jest kompilator Javy. Gdy mamy już zainstalowaną i skonfigurowaną Javę, instalujemy samego Cocoona, rozpakowując jego dystrybucję do wybranego katalogu znów bez spacji w ścieżce. Zostanie w nim utworzony dodatkowy katalog, cocoon-2.1.2-src, zawierający źródła. Są one gotowe do kompilacji, jednak zanim przejdziemy do tego kroku, musimy zmodyfikować źródło komponentu HTML Generator, aby umożliwić poprawną obsługę polskich znaków oraz adresów URL przekazanych mu z planu witryny. W tym celu kopiujemy przygotowaną wersję HTML Generatora (na CD HTMLGenerator.java) do katalogu src\blocks\html\java\ org\apache\cocoon\generation (wewnątrz katalogu coco- www.software.com.pl 73

Warsztat Tidy Skromny, darmowy programik Dave'a Raggetta, goszczący niegdyś na stronach WWW Consortium (W3C), a obecnie na SourceForge, którego autor prosi o pocztówkę, jeśli jego dzieło komuś się przyda, reklamuje się jako automatyczny oczyszczacz niedbale napisanych stron WWW, radzący sobie szczególnie dobrze z HTML-em generowanym automatycznie przez narzędzia i zwracający uwagę na dostępność stron dla osób niepełnosprawnych. Tidy rozwiązuje szeroką gamę problemów w dokumentach HTML i pseudo-html, takich jak: niepodomykane znaczniki, elementy zachodzące na siebie, atrybuty nie przewidziane dla danego elementu HTML, wartości atrybutów nie otoczone apostrofami lub cudzysłowami, elementy spoza HTML-a. Tidy generuje dokumenty XHTML. Do jego znanych słabości należą m.in.: tolerowanie podwójnych wystąpień atrybutów w elemencie i słaba obsługa nieprawidłowo osadzonych skryptów JavaScript. on-2.1.2, powstałego po rozpakowaniu źródeł). Dzięki tej poprawce będziemy mogli w planie witryny specyfikować rodzaj kodowania znaków, który ma być użyty przy przetwarzaniu danej strony WWW. Teraz już możemy uruchomić proces kompilacji. W tym celu w katalogu cocoon-2.1.2 uruchamiamy plik wsadowy build.bat. Po zakończonej kompilacji w tym samym katalogu pojawia się katalog build, zawierający katalog webapp. W katalogu webapp założymy katalog naszego serwisu zestawienie-cen, w którym utworzymy: plik konfiguracyjny HTML Generatora jtidy.properties, plik słownika slownik.xml (Listing 1), plan witryny sitemap.xmap, przekształcenie generujące gotowe zestawienie glowny.xsl. Plik jtidy.properties określa ustawienia, jakie mają być brane pod uwagę przy przekształcaniu HTML-a do XHTML-a. Są to faktycznie ustawienia programu JTidy (Javowej wersji programu Tidy), który wykorzystywany jest do czyszczenia niepoprawnych składniowo dokumentów HTML wewnątrz HTML Generatora. Szczegółowa znajomość opcji tego programu nie jest nam potrzebna, warto jednak wiedzieć, że aby transformacje w naszej aplikacji przebiegały poprawnie, musimy nakazać JTidy zwracać dokumenty w kodowaniu UTF-8, ustawiając opcję: char-encoding: utf8 a także opcję: output-xhtml: true aby zwracane przezeń dokumenty były w formacie XHTML. Konfiguracja serwisu Nasz serwis nie jest skomplikowaną witryną. Jej konfiguracja zawarta jest w planie witryny, tj. w pliku sitemap.xmap (Listing 2). Jest to dokument XML złożony z dwóch podstawowych sekcji: components i pipelines. W sekcji <map:components> deklarowane są wykorzystywane przez dany plan witryny komponenty (generatory, serializery, transformatory, itd.) HTML Generator, wymieniony na naszej liście komponentów, posiada dwa parametry: kodowanie pobieranych stron (domyślnie ustawione na ISO-8859-2) oraz położenie pliku konfiguracyjnego JTidy. Inne istotne komponenty to: procesor XSLT (transformator) oraz serializer do formatu XHTML, którego zadaniem będzie utworzenie dokumentu dla przeglądarki. Sekcja <map:pipelines> zawiera konfigurację poszczególnych potoków, wraz z wzorcami ich wywołania (<map: match pattern= >). Nasza aplikacja zawiera łącznie cztery potoki: po jednym potoku dla każdego sklepu oraz potok generujący docelowe zestawienie (Rysunek 2). Osobne potoki dla poszczególnych sklepów są niezbędne po to, aby wskazać źródła pobieranych stron oraz określić sposób ich oczyszczania do formatu XHTML. Każdy ze sklepów ma inny wzorzec swojego wywołania, na przykład pattern="age", co wykorzystamy później w odpowiednich odwołaniach w przekształceniu XSLT. W na- Rysunek 2. Budowa serwisu integrującego dane z trzech sklepów internetowych 74 www.software.com.pl

Serwis porównujący ceny z wielu sklepów internetowych Listing 3. Transformacja generująca zestawienie cen (fragmenty) <xsl:variable name="age" <xsl:variable name="arest" select="document('cocoon:/age')"/> select="document('cocoon:/arest')" /> <xsl:variable name="proline" select="document('cocoon:/proline')" /> <xsl:template match="czesc"> <tr> <p><xsl:value-of select="@nazwa"/></p> <xsl:for-each select="askryptor"> <xsl:variable name="czesc" <xsl:if test="$czesc"> <a href=";" title="{.}"> select="$age//*[.=current()]"/> <xsl:value-of select="$czesc/../../h:td[3]"/> </a> </xsl:if> </xsl:for-each> <xsl:for-each select="askryptor"> <xsl:variable name="czesc" select="$arest//*[.=current()]"/> <xsl:if test="$czesc"> <a href=";" title="{.}"> <xsl:value-of </a> </xsl:if> </xsl:for-each> select="$czesc/../../h:td[4]/h:a"/> <xsl:for-each select="askryptor"> <xsl:variable name="czesc" select="$proline//*[.=current()]"/> <xsl:if test="$czesc"> <a href=";" title="{.}"> <xsl:value-of </a> </xsl:if> </xsl:for-each> </tr> </xsl:template> select="$czesc/../../../h:td[3]"/> szym przypadku wartość age możemy traktować jako nazwę potoku. Każdy ze sklepów ma poza tym inny parametr generatora (src= http:// ), określający adres internetowy pobieranej strony. Ponieważ domyślnym generatorem jest HTML Generator, więc będzie on wywoływany dla każdego sklepu. Uważny Czytelnik od razu spostrzeże coś, co różni sklep Arest od innych. Chodzi o zmianę domyślnego kodowania. Otóż sklep ten, w przeciwieństwie do dwóch pozostałych, używa zamiast Latin 2 strony kodowej Windows 1250. Wszystkie potoki sklepów kończą się serializacją przekształconego dokumentu źródłowego. Potok zestawienia cen jest uruchamiany zapytaniem HTTP zawierającym jego nazwę (zestawienie). Pobiera on słownik towarów (slownik.xml) i wykonuje na nim transformację XSLT zdefiniowaną w pliku glowny.xsl. Transformacja ta odwołuje się z kolei do potoków poszczególnych sklepów, dzięki czemu integrujemy dane z nich pochodzące. Końcowym akcentem jest wygenerowanie docelowego dokumentu HTML przez serializer i przekazanie go przeglądarce. Generowanie zestawienia arkusz XSLT Przyjrzyjmy się teraz sercu naszego systemu arkuszowi stylów XSLT, którego zadaniem jest generowanie zestawienia cen. Listing 3 przedstawia jego najważniejsze fragmenty, odpowiedzialne za integrowanie danych z poszczególnych sklepów oraz generowanie zestawienia dla konkretnej części. z potoków poszczególnych sklepów została zrealizowana dzięki funkcji document() dostępnej w XSLT. Przy jej pomocy ładujemy zewnętrzne dokumenty XML, przypisując ich zawartość do zmiennych, a następnie wykorzystujemy je w przekształceniu na równi z zawartością dokumentu wejściowego. Cocoon oferuje wprawdzie bardziej eleganckie i elastyczne metody integrowania danych, na przykład agregatory czy transformator XInclude, jednak proste rozwiązanie, na które się zdecydowaliśmy, ma jedną podstawową zaletę: jest uniwersalne i można je wykorzystać także samodzielnie, bez użycia Cocoona. Wygenerowanie tabeli cen polega na przejściu w pętli po wszystkich wpisach ze słownika. Każdy wiersz zawiera w pierwszej komórce nazwę części, pobraną ze słownika. Następne komórki zawierają ceny tej części w kolejnych sklepach, bądź są puste, jeśli dany sklep nie ma w ofercie danej części. Jeśli część pojawia się w sklepie, to oprócz jej ceny udostępniamy użytkownikowi odpowiadający jej askryptor, wyświetlany po najechaniu myszką na cenę. Dzięki temu użytkownik, dziwiący się ogromnej różnicy w cenach tego samego procesora, może się ewentualnie przekonać, że tak naprawdę w zestawieniu znalazły się dwa różne modele (na przykład na skutek błędu autora zestawienia). Pomińmy nieistotne z punktu widzenia naszego wywodu szczegóły generowania układu strony oraz www.software.com.pl 75

Warsztat niezwykle prosta, i w dodatku jednakowa dla wszystkich sklepów: //* Analizując treść strony w bezpośredniej okolicy askryptora, łatwo jest też odkryć, w jaki sposób dotrzeć do odpowiedniego węzła z ceną. W przypadku sklepu Age, ścieżka od nazwy części do jej ceny ma postać:../../h:td[3] Rysunek 3. Zestawienie cen z trzech sklepów internetowych nagłówków tabel dla poszczególnych kategorii i producentów, i przyjrzyjmy się szablonowi dla elementu czesc, wypisującemu wiersz z nazwą części i jej cenami w kolejnych sklepach. Nie jest problemem wypisanie nazwy części pochodzi ona ze słownika. Większe wyzwanie stanowi odnalezienie ceny tej części w danym sklepie. Podejście, które zastosujemy, opiera się na obserwacji, że sklepy publikują swoje cenniki HTML mimo wszystko w uporządkowanej, powtarzalnej postaci. Zazwyczaj nazwa części i jej cena znajdują się w jednym wierszu tabeli, choć mogą być pozagnieżdżane w elementach <a>, <img>, <b>, itp. Istotne jest to, że dysponując węzłem nazwy części, możemy używając względnego wyrażenia XPath przejść do węzła zawierającego jej cenę. Dla każdego węzła nazwy na stronie danego sklepu zrobimy to w ten sam sposób. Aby więc umieć odnaleźć cenę danej części ze słownika na konkretnej stronie, musimy: potrafić odnaleźć askryptor szukanej części w treści strony, wymyślić względną ścieżkę XPath, która z nazwy części skieruje nas do jej ceny. Spójrzmy, gdzie w strukturze strony dowolnego z trzech sklepów mogą znajdować się nazwy części. Wprawdzie strukturę tę można badać analizując źródło strony, to jednak trzeba się przy tym sporo napracować i łatwo się jest przy tym pomylić. Na stronach WWW sklepów internetowych normą jest wielokrotne zagnieżdżanie tabel (element <table>), dochodzą do tego elementy <div>, <center>, <a>, <b> i tym podobne. Dlatego łatwiej i bezpieczniej będzie skorzystać ze spostrzeżenia, że askryptorów możemy szukać po prostu w całej zawartości strony! Ścieżka XPath wskazująca położenie askryptora w treści strony będzie więc gdzie h jest przedrostkiem przestrzeni nazw XHTML. Zatem aby we wzorcu czesc wypisać cenę konkretnej części, musimy przeiterować po wszystkich askryptorach tej części (nie wiemy bowiem, który askryptor występuje w danym sklepie), i spróbować znaleźć bieżący askryptor na stronie sklepu. W przypadku sklepu Age robimy to wyrażeniem: $age//*[.=current()] Wartość wyrażenia (węzeł zawierający askryptor) zapamiętujemy na zmiennej czesc w celu późniejszego przeniesienia się z niej do węzła ceny. Znając (specyficzną dla każdego sklepu) drogę od węzła części do jej ceny, wypisujemy ją, dodatkowo umieszczając w atrybucie title łącza sam askryptor. Efekt Mając przygotowaną witrynę, nie pozostaje nam nic innego, niż ją uruchomić i cieszyć się efektem. Uruchamiamy Cocoona z jego głównego katalogu poleceniem: cocoon servlet a następnie wprowadzamy w przeglądarce adres: http://localhost:8888/zestawienie-cen/zestawienie Po pewnym czasie, niezbędnym do ściągnięcia danych ze sklepów oraz ich zintegrowania, ujrzymy stronę zestawienia. Stworzony w ten sposób serwis jest bardzo uproszczony i ma charakter prototypowy. Brakuje mu prawdziwej szaty graficznej, nie ma opcji wyszukiwania interesujących nas towarów, ale działa na prawdziwych danych. Ci z Czytelników, którym pomysł integracji się spodobał, mogą przekształcić zaproponowany system tak, aby działał również dla innych sklepów internetowych z częściami komputerowymi a także dla kategorii innych niż procesory. Powodzenia! 76 www.software.com.pl