|
13
Firma-firma |
|
Czytelnik wie już dużo o XML-u. Poznał interfejsy SAX, DOM i JDOM, znajome mu są struktury publikacji i zaawansowane transformacje, jak również model XML-RPC; zna także zagadnienia związane z zastosowaniem XML-a w procesach konfiguracji oraz z wykorzystaniem tego języka jako źródła danych; potrafi również tworzyć dane XML z programów w Javie. W niniejszym rozdziale zostanie omówiony bardzo modny temat, a mianowicie zastosowanie XML-a w aplikacjach typu firma-firma. Przedsiębiorstwa wkroczyły w erę internetową i właściwa komunikacja stała się najważniejszym warunkiem prowadzenia handlu. Wiele firm przywiązuje większą wagę do procesów komunikacyjnych niż... do własnych produktów. Agresywne kampanie online i aplikacje e-biznesowe mogą przyczynić się do pokonania konkurencji, która może nawet oferować atrakcyjniejsze produkty. Ogromną rolę w pojęciu „firma-firma” odgrywa XML. Język ten stanowi standardowy sposób reprezentacji danych i właśnie dzięki niemu firmy wykorzystujące różne aplikacje, systemy i języki programowania mają możliwość komunikowania się ze sobą.
W niniejszym rozdziale Czytelnik dowie się, w jaki sposób za pomocą XML-a można uzyskać taką właśnie możliwość porozumienia pomiędzy różnymi aplikacjami; na potrzeby rozdziału zostaną nawet stworzone wyimaginowane firmy. Tym razem XML nie posłuży do wymiany informacji pomiędzy składnikami jednej aplikacji ani też jako źródło danych, ale do komunikacji pomiędzy różnymi aplikacjami. Najpierw zostanie zaprezentowana Biblioteka Publiczna NaNiby, której dostawcy będą mogli wprowadzać nowe tytuły w trybie online. Książki będą następnie dodawane do składnicy danych biblioteki do późniejszego wykorzystania. Niestety, w dzisiejszych czasach trudno o dobrych programistów Javy, a więc nasza biblioteka będzie opierała swoje działanie na programie CGI napisanym w Perlu. Nowe książki wpisywane online są sortowane przez skrypt właśnie w tym języku.
Będzie też druga firma, KsiegarniaTechniczna.com. W tej księgarni sprzedaje się w systemie online — w porozumieniu z innymi dużymi księgarniami — książki o tematyce technicznej i komputerowej (takie jak ta). Ostatnio podpisano umowę z Biblioteką Publiczną NaNiby, zgodnie z którą firma będzie uzyskiwała książki od tej biblioteki na specjalnych warunkach. KsiegarniaTechniczna.com opłaci koszty dostawy i administracyjne, zaś biblioteka zamówi dodatkowe egzemplarze książek po specjalnej, obniżonej cenie; te dodatkowe książki sprzeda następnie KsiegarniaTechniczna.com. KsiegarniaTechniczna.com --> musi [Author:RG] mieć dostęp do danych wprowadzanych w Bibliotece Publicznej NaNiby przez dostawców, tak aby wiedzieć o nowych tytułach i móc je reklamować u siebie. Jednakże nie wiadomo, w jaki sposób uzyskać dostęp do danych systemu biblioteki opartego na Perlu. Co więcej, pomiędzy obiema firmami nie istnieją chronione połączenia sieciowe, a więc konieczne jest wykorzystanie zwyczajnego protokołu HTTP.
Czytelnik będzie mógł spojrzeć na te aplikacje z punktu widzenia klientów KsiegarniaTechniczna.com. Księgarnia oferuje produkty osobom aktywnym w Internecie, a więc chce ogłaszać się w witrynach w rodzaju Netscape Netcenter; chce także, aby klienci mogli w prosty sposób uzyskać informacje z ich witryny o nowych ofertach. Jednakże, podobnie jak w przypadku Biblioteki Publicznej NaNiby, --> KsiegarniaTechniczna.com nie posiada informacji o tym, jak to zrobić[Author:RG] . Przedstawiciele grupy Netscape Netcenter poinformowali programistów księgarni, że na potrzeby takiego reklamowania się najlepiej nadaje się RSS (Rich Site Summary). Ale programiści księgarni nawet nie wiedzą, czym jest RSS!
Zaczniemy od Biblioteki Publicznej NaNiby — przyjrzymy się, jak zbudowany jest ich system napisany w Perlu. Następnie przejdziemy do firmy KsiegarniaTechniczna.com, a jeszcze później do klientów tej księgarni. Zobaczymy, jak pomiędzy tymi wszystkimi stronami stworzyć komunikację opartą na języku XML.
Biblioteka Publiczna NaNiby
Tworzenie systemu typu firma-firma rozpoczniemy od zbadania, jaki stan rzeczy zastaliśmy w bibliotece. Zanim jednak przejdziemy do samego kodu aplikacji, musimy poznać wymagania biblioteki (aby nie tworzyć systemu, którego nie będzie można potem obsłużyć).
Określenie wymagań
Często dobre rozwiązanie nie oznacza jeszcze — w przypadku określonej firmy — rozwiązania zgodnego z wymaganiami. Świetnym przykładem jest tutaj Biblioteka Publiczna NaNiby — problemy tej biblioteki i firmy KsiegarniaTechniczna.com można byłoby rozwiązać za pomocą serwletów Javy działających po obu stronach. Jednakże nie zostałyby wówczas zaspokojone wymagania biblioteki. A więc najpierw należy przyjrzeć się właśnie wymaganiom:
rozwiązanie musi być napisane w Perlu; w bibliotece nie ma programistów Javy;
rozwiązanie nie może wymagać instalacji nowego oprogramowania czy bibliotek;
rozwiązanie nie może wpłynąć na istniejący system zamawiania (nie może być zmian w interfejsie).
Nie są to może jakieś zaporowe wymagania, ale na pewno zmuszają do ponownego przeanalizowania problemu. Nie wolno nam korzystać z Javy. Oczywiście, ponieważ ta książka jest o XML-u, Czytelnik może się domyślać, że dane o nowych książkach będą zapisywane w formacie XML, następnie przekazywane klientom protokołem HTTP i wykorzystywane w dowolny sposób. Tak, i jest to o wiele lepsze rozwiązanie niż komunikacja pomiędzy serwletami; XML może zostać użyty w dowolnej firmie lub u dowolnego klienta i nie trzeba „przywiązywać” biblioteki (i wszystkich jej książek) do jednej, określonej firmy. I w ten sposób zostało nakreślone zadanie związane z aktualizacją systemu biblioteki — zachować wpisane informacje w postaci kodu XML, a następnie stworzyć klientom możliwość dostępu do tych danych poprzez protokół HTTP.
Wprowadzanie książek
Po pierwsze trzeba poznać istniejący interfejs, za pomocą którego dostawcy wprowadzają nowe książki do systemu. W przykładzie 13.1 pokazano, jak zbudowany jest sam statyczny formularz.
Przykład 13.1. Statyczny interfejs Biblioteki Publicznej NaNiby w HTML-u
<html>
<head>
<title>Biblioteka Publiczna NaNiby: Wprowadzanie książek</title>
<style>
<!--
body { font-family: Arial }
h1 { color: #000080 }
-->
</style>
</head>
<body link="#FFFF00" vlink="#FFFF00" alink="#FFFF00">
<table border="0" width="100%" cellpadding="0" cellspacing="0">
<tr>
<td width="15%" bgcolor="#000080" valign="top" align="center">
<b><i>
<font color="#FFFFFF" size="4">Opcje</font>
</i></b>
<p><b>
<font color="#FFFFFF">
<a href="/javaxml/foobar">Menu Główne</a>
</font>
</p></b>
<p><b>
<font color="#FFFFFF">
<a href="/javaxml/foobar/catalog.html">Katalog</a>
</font>
</b></p>
<p><b>
<i><font color="#FFFF00">Wprowadzanie książek</font></i>
</b></p>
<p><b>
<font color="#FFFFFF">
<a href="/javaxml/foobar/logout.html">Wylogowanie</a>
</font>
</p></td>
<td width="*" valign="top" align="center">
<h1 align="center">Biblioteka Publiczna NaNiby</h1>
<h3 align="center"><i>- Dodawanie książek -</i></h3>
<!-- Poniżej ścieżka do katalogu i skryptu CGI, którym zajmiemy się w następnej kolejności -->
<form method="POST" action="/cgi/addBook.pl">
<table border="0" cellpadding="5" width="100%">
<tr>
<td width="100%" valign="top" align="center" colspan="2">
Tytuł
<input type="text" name="title" size="20">
<hr width="85%" />
</td>
</tr>
<tr>
<td width="50%" valign="top" align="right">Autor
<input type="text" name="author" size="20">
</td>
<td width="50%" valign="top" align="left">Temat
<select size="1" name="subject">
<option>Beletrystyka</option>
<option>Biografie</option>
<option>Nauka</option>
<option>Przemysł</option>
<option>Komputery</option>
</select></td>
</tr>
<tr>
<td width="50%" valign="top" align="right">Wydawca
<input type="text" name="publisher" size="20">
</td>
<td width="50%" valign="top" align="left">ISBN
<input type="text" name="isbn" size="20">
</td>
</tr>
<tr>
<td width="50%" valign="top" align="right">Cena
<input type="text" name="price" size="20">
</td>
<td width="50%" valign="top" align="left">Stron
<input type="text" name="numPages" size="20">
</td>
</tr>
<tr>
<td width="100%" valign="top" align="center" colspan="2">
Opis
<textarea rows="2" name="description" cols="20"></textarea>
</td>
</tr>
</table>
<p>
<input type="submit" value="Dodaj książkę" name="addBook">
<input type="reset" value="Wyczyść formularz" name="reset">
<input type="button" value="Anuluj" name="cancel">
</p>
</form>
</td>
</tr>
</table>
</body>
</html>
Powyższy plik, zachowany jako addBooks.html, umożliwia wprowadzenie nowych książek przysyłanych do biblioteki.
|
W tym rozdziale zostanie wydrukowany pełny kod wszystkich opisywanych przykładów, tak aby Czytelnik mógł sam stworzyć przykładową aplikację i dokładnie zaznajomić się z procesem uruchamiania komunikacji XML pomiędzy firmami. Możliwe jest też obejrzenie działających przykładów pod adresem http://www.newInstance.com. Stamtąd, jak również spod adresu http://www.oreilly.com/catalog/javaxml/, można także pobrać przykładowe pliki. W tym rozdziale założono, że Czytelnik użyje nazw plików zgodnych z opisywanymi; w przeciwnym razie trzeba odpowiednio dostosować kod (miejsca wymagające takich zmian odpowiednio zaznaczono). |
Po załadowaniu powyższego przykładu do przeglądarki, Czytelnik otrzyma wynik przypominający ten na rysunku 13.1. Tutaj nie będą omawiane pozostałe pozycje menu, ale przecież dostawca może chcieć przejrzeć katalog biblioteki, przejść do menu głównego czy wylogować się — wszystkie te opcje muszą więc znaleźć się w zasięgu ręki.
|
Rysunek 13.1. Interfejs HTML biblioteki
Formularz taki pozwala dostawcy wprowadzić szczegółowe informacje o każdej książce przesyłanej do biblioteki. Wprowadzane są następujące dane: tytuł, autor, wydawca, liczba stron, cena, numer ISBN, opis, a także kategoria tematyczna książki.
Po wprowadzeniu informacji formularz przesyłany jest do skryptu CGI:
<form method="POST" action="/cgi/addBook.pl">
Skrypt ten ma następnie zwrócić dane XML. Najprościej byłoby załadować bibliotekę Perla do obsługi przetwarzania XML, np. Xerces-Perl; należy jednak pamiętać o tym, że jedno z wymagań brzmi: żadnych nowych bibliotek i oprogramowania. Takie ograniczenie może wydawać się głupie, ale trzeba pamiętać, że w wielu firmach oprogramowanie produkcyjne traktuje się w sposób bardzo mało elastyczny. Biblioteka Publiczna NaNiby ma „zaistnieć” w Internecie, ale nie możemy przeznaczyć na to żadnych dodatkowych zasobów i środków.
Na szczęście naszym zadaniem jest tylko uzyskać dane XML. Można to zrobić w dość łatwy sposób — „brutalnie” generując pliki z informacjami wprowadzonymi do formularza. Ponieważ wszystkie dotychczasowe informacje i tak mają być zachowywane, zamiast tworzyć nowe pliki, wystarczy dołączyć nowe informacje do plików już istniejących. Dla programistów Javy napisanie --> odpowiedniego programu w Perlu jest banalnym zadaniem — cały kod został zamieszczony w przykładzie 13.2.[Author:RG]
Przykład 13.2. Skrypt Perl CGI generujący wpisy XML z wprowadzonych książek
#!/usr/local/bin/perl
$baseDir = "/usr/local/projects/javaxml/foobar/books/";
$filename = "books.txt";
$bookFile = $baseDir . $filename;
# Pobieramy dane od użytkownika.
use CGI;
$query = new CGI;
$title = $query->param('title');
$author = $query->param('author');
$subject = $query->param('subject');
$publisher = $query->param('publisher');
$isbn = $query->param('isbn');
$price = $query->param('price');
$numPages = $query->param('numPages');
$description = $query->param('description');
# Zachowujemy dane w pliku XML.
if (open(FILE, ">>" . $bookFile)) {
print FILE "<book subject=\"" . $subject . "\">\n";
print FILE " <title><![CDATA[" . $title . "]]></title>\n";
print FILE " <author><![CDATA[" . $author . "]]></author>\n";
print FILE " <publisher><![CDATA[" . $publisher . "]]></publisher>\n";
print FILE " <numPages>" . $numPages . "</numPages>\n";
print FILE " <saleDetails>\n";
print FILE " <isbn>" . $isbn . "</isbn>\n";
print FILE " <price>" . $price . "</price>\n";
print FILE " </saleDetails>\n";
print FILE " <description><![CDATA[" . $description . "]]></description>\n";
print FILE "</book>\n\n";
# Wysyłamy potwierdzenie użytkownikowi.
print <<"EOF";
Content-type: text/html
<html>
<head>
<title>Biblioteka Publiczna NaNiby: Potwierdzenie</title>
</head>
<body>
<h1 align="center">Książka została dodana</h1>
<p align="center">
Dziękujemy. Książka została dodana do Biblioteki.
</p>
</body>
</html>
EOF
} else {
print <<"EOF";
Content-type: text/html
<html>
<head>
<title>Biblioteka Publiczna NaNiby: Błąd</title>
</head>
<body>
<h1 align="center">Błąd przy dodawaniu książki.</h1>
<p align="center">
Książka NIE została wprowadzona do biblioteki.
</p>
</body>
</html>
EOF
}
close (FILE);
Powyższy program, zachowany jako addBook.pl, uruchamiany jest po wysłaniu formularza. Skrypt definiuje nazwę pliku, do którego mają zostać zapisane dane, a następnie przypisuje parametry pobrane z formularza zmiennym lokalnym:
$title = $query->param('title');
$author = $query->param('author');
$subject = $query->param('subject');
$publisher = $query->param('publisher');
$isbn = $query->param('isbn');
$price = $query->param('price');
$numPages = $query->param('numPages');
$description = $query->param('description');
Kiedy już wartości te są dostępne, skrypt otwiera plik zdefiniowany wcześniej w trybie do dopisywania (symbol >> poprzedzający nazwę pliku) i na jego końcu zapisuje dane sformatowane jako XML:
print FILE "<book subject=\"" . $subject . "\">\n";
print FILE " <title><![CDATA[" . $title . "]]></title>\n";
print FILE " <author><![CDATA[" . $author . "]]></author>\n";
print FILE " <publisher><![CDATA[" . $publisher . "]]></publisher>\n";
print FILE " <numPages>" . $numPages . "</numPages>\n";
print FILE " <saleDetails>\n";
print FILE " <isbn>" . $isbn . "</isbn>\n";
print FILE " <price>" . $price . "</price>\n";
print FILE " </saleDetails>\n";
print FILE " <description><![CDATA[" . $description . "]]></description>\n";
print FILE "</book>\n\n";
Temat wykorzystywany jest jako atrybut elementu znajdującego się wyżej w hierarchii (book), natomiast pozostałe informacje zostają wprowadzone jako poszczególne elementy. Ponieważ pola zawierające tytuł, nazwisko autora, opis i nazwę wydawcy książki mogą zawierać cudzysłowy, apostrofy, „ampersandy” i inne znaki wymagające wstawienia ich w sekwencje unikowe, dane te zamkniemy w sekcji CDATA, co zwolni nas z konieczności znoszenia specjalnych znaczeń tych znaków.
Ponadto powinniśmy zauważyć, że nie tworzymy deklaracji XML ani elementu głównego (w jednym pliku będą zawarte informacje o wielu książkach). Ponieważ sprawdzenie, czy plik istnieje, zapisanie deklaracji i elementu głównego, jeśli nie istnieje, a następnie zapisanie elementu kończącego (który po każdej nowej porcji informacji będzie musiał zostać nadpisany) jest nieco kłopotliwe, pozostawimy ten plik w takiej postaci, w jakiej jest — jako fragment dokumentu XML. Na przykład tak wyglądałby plik po wprowadzeniu dwóch książek:
<book subject="Computers">
<title><![CDATA[Java Servlet Programming]]></title>
<author><![CDATA[Jason Hunter]]</author>
<publisher><![CDATA[O'Reilly & Associates]]></publisher>
<numPages>528</numPages>
<saleDetails>
<isbn>156592391X</isbn>
<price>36.95</price>
</saleDetails>
<description><![CDATA[Doskonałe wprowadzenie do serwletów Javy i
różnych mechanizmów komunikacyjnych.]]></description>
</book>
<book subject="Fiction">
<title><![CDATA[Second Foundation]]></title>
<author><![CDATA[Isaac Asimov]]</author>
<publisher><![CDATA[Bantam Books]]></publisher>
<numPages>279</numPages>
<saleDetails>
<isbn>0553293362</isbn>
<price>5.59</price>
</saleDetails>
<description><![CDATA[Po zagarnięciu Pierwszej Fundacji tylko Druga Fundacja mogła zapobiec całkowitej destrukcji.]]></description>
</book>
Może nie jest to kompletny dokument XML, ale sam ten fragment jest sformatowany poprawnie i mógłby zostać wstawiony do dokumentu XML zawierającego już nagłówek i element główny. I tak właśnie zrobimy, kiedy za chwilę zajmiemy się mechanizmem wyświetlającym listę książek.
Reszta skryptu zwraca odpowiednie dane HTML w zależności od tego, czy dodawanie książki się powiodło, czy nie. W pierwszym przypadku dostawca zobaczy proste potwierdzenie, takie jak na rysunku 13.2.
|
Rysunek 13.2. Komunikat potwierdzający dodanie książki
Teraz można już wykorzystać ten fragment dokumentu do udzielania odpowiednich informacji stronom żądającym.
Wyświetlanie listy dostępnych książek
Do wyświetlenia listy nowych książek znów posłuży Perl. Załóżmy, że jakaś inna porcja aplikacji biblioteki okresowo odczytuje dane XML i aktualizuje katalog. Ten składnik aplikacji byłby odpowiedzialny również za usuwanie wpisów w naszym pliku, tak aby książki już wprowadzone do katalogu nie były klasyfikowane jako „nowe”. Zadanie dla naszego drugiego skryptu w Perlu jest więc następujące: odczytać fragment kodu XML i dodać dane do dokumentu wyświetlanego na ekranie. Jak już było wspomniane, konieczne jest także dodanie deklaracji XML i elementu głównego, „otaczającego” dostarczoną zawartość. Nowy skrypt (przykład 13.3) odczytuje plik utworzony przez addBook.pl i wyświetla odpowiednią zawartość po otrzymaniu żądania przez HTTP.
Przykład 13.3. Skrypt Perl CGI wyświetlający dokument XML z nowymi książkami
#!/usr/local/bin/perl
$baseDir = "/usr/local/projects/javaxml/foobar/books/";
$filename = "books.txt";
$bookFile = $baseDir . $filename;
# Najpierw otwieramy plik.
open(FILE, $bookFile) || die "Could not open $bookFile.\n";
# Przekazujemy przeglądarce informacje o rodzaju przesyłanych danych.
print "Content-type: text/plain\n\n";
# Wyświetlamy nagłówek i element główny XML.
print "<?xml version=\"1.0\"?>\n";
print "<books>\n";
# Wyświetlamy książki.
while (<FILE>) {
print "$_";
}
# Zamykamy element główny.
print "</books>\n";
close(FILE);
Powyższy skrypt, zachowany jako supplyBooks.pl, przyjmie żądanie, odczyta plik stworzony przez addBook.pl i wyświetli dane XML po żądaniu HTTP. Przykładowy wynik (z dodanymi książkami) można obejrzeć na rysunku 13.3.
|
Rysunek 13.3. Wynik działania skryptu supplyBooks.pl
Jak widać, prostą aplikację w Perlu łatwo można zamienić w składnik, który potrafi dostarczyć użyteczne informacje klientom — takim jak księgarnia KsiegarniaTechniczna.com. Zrobiliśmy to bez instalacji nowego oprogramowania, bez zmiany architektury systemu lub aplikacji i bez pisania choćby jednej linijki kodu w Javie!
KsiegarniaTechniczna.com
Biblioteka Publiczna NaNiby umożliwia już uzyskanie dostępu do danych o nowych książkach w formacie XML. Teraz KsiegarniaTechniczna.com jest już bliska osiągnięcia zamierzonego celu — dostarczyć aktualne informacje swoim klientom. W firmie tej już dawno wykorzystuje się Javę do budowania aplikacji, co bardzo uprości proces uzyskiwania dostępu i korzystania z danych XML oferowanych przez bibliotekę — Java świetnie obsługuje XML, o czym zresztą przekonuje cała niniejsza książka. Najpierw chcemy umożliwić wyświetlanie w firmie KsiegarniaTechniczna.com danych dotyczących nowych książek, a następnie udostępnić te informacje klientom tej firmy.
Filtrowanie danych XML
W firmie KsiegarniaTechniczna.com mają być wyświetlane wyłącznie dane o książkach technicznych. Jak zapewne Czytelnik pamięta, Biblioteka Publiczna NaNiby pozwalała na wprowadzanie książek o zróżnicowanej tematyce; KsiegarniaTechniczna.com akceptuje wyłącznie książki o problematyce informatycznej. Na szczęście, odpowiednia informacja jest zawarta w atrybucie subject elementu book. Najpierw należy więc odfiltrować wszystkie książki, których tematem nie jest „Computers”. Kiedy już uzyskamy w ten sposób książki o tematyce informatycznej, musimy je sformatować do postaci strony HTML, którą pokażemy klientom odwiedzającym witrynę firmy KsiegarniaTechniczna.com.
Tutaj nie będziemy korzystali ze strony statycznej, ponieważ strona z nowymi pozycjami musi zostać wygenerowana przy każdej próbie jej pobrania. Oczywiście, tym razem do obsługi takich żądań wykorzystamy serwlet. Do konwersji danych XML z biblioteki na postać HTML świetnie nadawałby się Apache Cocoon, ale pracownicy firmy KsiegarniaTechniczna.com muszą całe zadanie wykonać jak najszybciej i na razie nie chcą wprowadzać tak dużych zmian w istniejącym systemie. Wolą wykorzystać parsery i procesory XML, a dopiero w drugiej fazie wdrażania zainstalować Cocoon. A więc trzeba obsłużyć konwersję XML-HTML, a oprócz tego jeszcze filtrowanie i dodawanie elementów prezentacyjnych (np. logo firmy czy pasek menu).
Ale jeśli Czytelnik przywoła całą wiedzę o XML-u i XSL-u, to być może przypomni sobie, że nawet bez Cocoona można przekształcać dokumenty XML na format HTML-a — za pomocą arkuszy XSL. W trakcie transformacji można również odfiltrować książki o tematyce innej niż komputerowa. Pamiętając o tym wszystkim, możemy już stworzyć arkusz stylu, który zostanie zastosowany do dokumentu przesłanego z Biblioteki Publicznej NaNiby. Początkowy fragment takiego arkusza, obsługujący generację dokumentu HTML, został zamieszczony w przykładzie 13.4.
Przykład 13.4. Arkusz stylu dla danych otrzymywanych z Biblioteki Publicznej NaNiby
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0"
>
<xsl:template match="books">
<html>
<head>
<title>Księgarnia Techniczna - Twój sklep z literaturą komputerową</title>
</head>
<body background="http://newInstance.com/javaxml/techbooks/images/background.gif"
link="#FFFFFF" vlink="#FFFFFF" alink="#FFFFFF">
<h1 align="center">
<font face="Arial" color="#00659C">
<KsiegarniaTechniczna.com>
</font>
</h1>
<p align="center">
<i><b>Twoje źródło książek o tematyce komputerowej i technicznej.</b></i>
</p>
<p align="center">
<b><font size="4" color="#00659C">
<u>Nowe pozycje</u>
</font></b>
</p>
<table border="0" cellpadding="5" cellspacing="5">
<tr>
<td valign="top" align="center" nowrap="nowrap" width="115">
<p align="center">
<font color="#FFFFFF"><b>
<a href="http://newInstance.com/javaxml/techbooks/">Strona główna</a>
</b></font>
</p>
<p align="center">
<font color="#FFFFFF"><b>
<a href="http://newInstance.com/javaxml/techbooks/current.html">Obecne pozycje</a>
</b></font>
</p>
<p align="center">
<b><font color="#FFFFFF">
<i>Nowe pozycje</i>
</font></b>
</p>
<p align="center">
<font color="#FFFFFF"><b>
<a href="http://newInstance.com/javaxml/techbooks/contact.html">Kontakt</a>
</b></font>
</p>
</td>
<td valign="top" align="left">
<table border="0" cellpadding="5" cellspacing="5">
<tr>
<td width="450" align="left" valign="top">
<p>
<b>
Witamy w firmie <font face="courier">KsiegarniaTechniczna.com</font>,
oferującej książki o tematyce komputerowej i technicznej.
Po lewej stronie zamieszczono najnowsze tytuły. Aby nabyć którąś z tych wspaniałych książek, wystarczy kliknąć odsyłacz "Kup książkę!" co spowoduje jej przeniesienie do koszyka. Miłych zakupów!
</b>
</p>
<p>
<b>
Można także przejrzeć nasze wcześniejsze tytuły, zajrzeć do informacji
o sklepie, albo skontaktować się z nami. Wszystkie niezbędne odsyłacze
znajdują się po lewej stronie. Dziękujemy za zakupy u nas!
</b>
</p>
</td>
<td align="left">
<!-- Tutaj tworzymy zawartość dla każdej nowej *komputerowej* książki -->
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Co prawda nie zostały jeszcze odfiltrowane przychodzące dane XML (nie zostały również przekształcone), ale interfejs HTML przedstawiany użytkownikowi jest już gotowy. Często o wiele prościej jest najpierw zająć się tymi „prezentacyjnymi drobiazgami”, a dopiero potem samą logiką transformacji.
|
Przy tworzeniu arkuszy XSL, szczególnie na potrzeby aplikacji WWW, należy zawsze testować wynik poprzez procesor XSLT, wywołując go z wiersza poleceń. W ten sposób zostanie zagwarantowane, że na każdym etapie tworzenia dokument przetwarzany jest zgodnie z oczekiwaniami. O wiele trudniej usuwać błędy w dużym, gotowym już arkuszu stylu. Informacje o tym, jak korzystać z procesora Apache Xalan z wiersza poleceń, zostały zawarte w rozdziale 7. W tym konkretnym przypadku można pobrać plik supplyBooks.pl za pomocą przeglądarki, zachować wynik jego działania w pliku XML i wtedy przetestować arkusz stylu. |
Podobnie jak w przypadku aplikacji w Bibliotece Publicznej NaNiby, po lewej stronie tworzone jest menu z odsyłaczami do innych części aplikacji; umieszczony jest również krótki opis firmy i jej oferty. Natomiast po prawej stronie pozostawiliśmy miejsce na nowe pozycje książkowe.
Przed odfiltrowaniem zawartości trzeba dodać szablon wyświetlający zawartość HTML z jednego elementu book. Wpis będzie wyglądał mniej więcej tak:
<book subject="Computers">
<title><![CDATA[Running Linux]]></title>
<author><![CDATA[Matt Welsh]]</author>
<publisher><![CDATA[O'Reilly & Associates]]></publisher>
<numPages>630</numPages>
<saleDetails>
<isbn>1565921518</isbn>
<price>29.95</price>
</saleDetails>
<description><![CDATA[Zgodnie z tradycją tytułów O'Reilly, książka Running
Linux oferuje przejrzyste instrukcje krok po kroku, zawsze dostarczające
Czytelnikowi akurat tyle informacji, ile potrzeba.]]></description>
</book>
Takie dane należy przekształcić w kod HTML za pomocą następującego szablonu XSL:
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0"
>
<xsl:template match="books">
<!-- Interfejs użytkownika -->
</xsl:template>
<xsl:template match="book">
<table border="0" cellspacing="1" bgcolor="#000000">
<tr>
<td>
<table border="0" cellpadding="3" cellspacing="0">
<tr>
<td width="100%" bgcolor="#00659C" nowrap="nowrap" align="center">
<b><font color="#FFFFFF">
<xsl:value-of select="title" />
</font></b>
</td>
</tr>
<tr>
<td width="100%" align="center" nowrap="nowrap" bgcolor="#FFFFFF">
<font color="#000000"><b>
Autor: <xsl:value-of select="author" /><br />
Wydawca: <xsl:value-of select="publisher" /><br />
Stron: <xsl:value-of select="numPages" /><br />
Cena: <xsl:value-of select="saleDetails/price" /><br />
<br />
</b></font>
<xsl:element name="a">
<xsl:attribute name="href">/servlets/BuyBookServlet?isbn=
=<xsl:value-of select="saleDetails/isbn" />
</xsl:attribute>
<font color="#00659C">Kup książkę!</font>
</xsl:element>
</td>
</tr>
</table>
</td>
</tr>
</table>
<br />
</xsl:template>
</xsl:stylesheet>
Szablon dopasowuje element book, a następnie tworzy tabelę z nagłówkiem w jednym wierszu i zawartością w drugim. Cała tabela umieszczona jest wewnątrz innej tabeli, dzięki czemu w przeglądarce ta pierwsza tabela sprawia wrażenie otoczonej czarną ramką. Tytuł wstawiany jest do nagłówka tabeli, a informacje o książce (autor, wydawca, liczba stron i cena) do zawartości tabeli. Jest tam również odsyłacz do serwleta Javy BuyBookServlet, za pomocą którego można w prosty sposób zakupić daną książkę. Jako argument wywołania serwleta podawany jest numer ISBN tej książki.
|
W arkuszu XSL trzeba sprawdzić, czy wiersz opisujący użycie BuyBookServlet oraz wiersz z elementem xsl:value-of tworzą tak naprawdę jedną linijkę. W przeciwnym razie do wynikowego adresu URL mogłyby „przedostać się” spacje i znaki nowego wiersza i serwlet otrzymałby niepoprawne dane. W przedstawionym arkuszu stylów, w wyniku łamania tekstu w druku, te informacje zostały rozbite na dwa wiersze. |
Teraz trzeba jeszcze zagwarantować, że nowy szablon zostanie zastosowany i że zostaną do niego przekazane wyłącznie książki o tematyce „Computers”. Wartość atrybutu subject poznamy poprzez odwołanie się do niego za pomocą symbolu @; filtrowanie nastąpi poprzez atrybut select elementu xsl:apply-templates:
</td>
<td align="left">
<!-- Tutaj tworzymy zawartość dla każdej nowej *komputerowej* książki -->
<xsl:apply-templates select="book[@subject='Computers']" />
</td>
</tr>
</table>
Odwołujemy się do wartości atrybutu i porównujemy go z łańcuchem znaków (w apostrofach
— to dlatego, że całe wyrażenie XPath znajduje się w cudzysłowach). Ponieważ „obrabiamy” atrybut elementu zagnieżdżonego, odwołujemy się do niego przez nazwę i otaczamy wyrażenie związane z jego atrybutem nawiasami kwadratowymi. W ten sposób gwarantujemy, że szablon zostanie zastosowany tylko na książkach o tematyce „Computers”. Po stworzeniu arkusza stylów można go zachować jako computerBooks.xsl i odwoływać się do niego poprzez serwlet Javy, który zostanie przedstawiony poniżej.
XSLT poprzez serwlet
Arkusz stylu jest gotowy. Potrzebny jest jeszcze kod w Javie, który spowoduje zastosowanie tego arkusza na danych z biblioteki. Dostęp do danych odbędzie się za pośrednictwem klasy Javy URL, poprzez którą wyślemy żądanie HTTP do systemu biblioteki. Po tym wszystkim pozostanie już tylko wykonać faktyczną transformację z poziomu programu. W przykładzie 13.5 przedstawiono kod serwleta ładującego dane XML z biblioteki i ukazującego, w którym miejscu znajdzie się kod przekształcający (wykonujący transformację).
Przykład 13.5. Serwlet Javy przekształcający informacje o książkach na postać kodu HTML
package com.techbooks;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URL;
import javax.servlet.*;
import javax.servlet.http.*;
public class ListBooksServlet extends HttpServlet {
/** Host, z którego pobierzemy listę książek */
private static final String hostname = "newInstance.com";
/** Port powyższego hosta */
private static final int portNumber = 80;
/** Plik (ścieżka URI) zawierający listę książek */
private static final String file = "/cgi/supplyBooks.pl";
/** Arkusz stylu, według którego przekształcimy XML */
private static final String stylesheet = "/home/client/java/newinstance/www/javaxml/techbooks/XSL/computerBooks.xsl";
public void service(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
res.setContentType("text/html");
// Łączymy się w celu pobrania listy książek
URL getBooksURL = new URL("http", hostname, portNumber, file);
InputStream in = getBooksURL.openStream();
// Przekształcamy dane XML za pomocą arkusza stylu
}
}
Ten prosty serwlet wysyła żądanie HTTP do biblioteki i otrzymuje odpowiedź w języku XML w postaci strumienia InputStream. Strumień zostanie następnie wykorzystany jako parametr procesora XSLT oraz jako baza do przekształcenia przez arkusz stylu zdefiniowany w serwlecie jako statyczny.
Obecnie nie istnieje interfejs API Javy, który określałby, jak programowo wykonać transformację XSLT; jednakże każdy producent procesora powinien udostępniać klasy umożliwiające uruchomienie przekształcania z kodu Javy. Tutaj ponownie zostanie wykorzystany procesor Apache Xalan; informacji o sposobie wywoływania metod transformacji w innym parserze należy zasięgnąć u producenta.
W przypadku procesora Apache Xalan do opisanego celu służy klasa XSLTProcessor z pakietu org.apache.xalan.xslt. Jako parametry przyjmuje ona klasę XSLTInputSource reprezentującą plik XML do przetwarzania, klasę XSLTInputSource reprezentującą arkusz stylu oraz XSLTResultTarget reprezentującą wynik transformacji. Wszystkie te klasy pomocnicze znajdują się również w pakiecie org.apache.xalan.xslt. Klasy te tworzy się w wygodny sposób, przekazując InputStream (do XSLTInputSource) lub OutputStream (do XSLTResultTarget). Nasz dokument ma postać obiektu InputStream, arkusz stylu „zapakujemy” w FileInputStream, zaś interfejs serwleta pozwala nam w prosty sposób uzyskać dostęp do obiektu ServletOutputStream poprzez metodę getOutputStream(), wywołaną na obiekcie HttpServletResponse. Na koniec trzeba jeszcze omówić sposób uzyskania egzemplarza XSLTProcessor. Ponieważ do przetwarzania mogą być wykorzystane różne mechanizmy wewnętrzne, egzemplarza tej klasy nie tworzy się bezpośrednio, ale poprzez klasę XSLTProcessorFactory, również znajdującą się w pakiecie org.apache.xalan.xslt. Czytelnik wie już, jak korzystać z klas typu „factory”, a więc pozostało tylko zaimportować wymagane klasy i dodać do serwleta wywołania metod przetwarzających:
package com.techbooks;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URL;
import javax.servlet.*;
import javax.servlet.http.*;
// Import komponentów procesora Xalan XSLT
import org.apache.xalan.xslt.XSLTInputSource;
import org.apache.xalan.xslt.XSLTProcessor;
import org.apache.xalan.xslt.XSLTProcessorFactory;
import org.apache.xalan.xslt.XSLTResultTarget;
public class ListBooksServlet extends HttpServlet {
/** Host, z którego pobierzemy listę książek */
private static final String hostname = "newInstance.com";
/** Port powyższego hosta */
private static final int portNumber = 80;
/** Plik (ścieżka URI) zawierający listę książek */
private static final String file = "/cgi/supplyBooks.pl";
/** Arkusz stylu, według którego przekształcimy XML */
private static final String stylesheet =
"/home/client/java/newinstance/www/javaxml/techbooks/XSL/computerBooks.xsl";
public void service(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
res.setContentType("text/html");
// Łączymy się w celu pobrania listy książek
URL getBooksURL = new URL("http", hostname, portNumber, file);
InputStream in = getBooksURL.openStream();
try {
XSLTProcessor processor = XSLTProcessorFactory.getProcessor();
// Przekształcamy XML za pomocą arkusza stylu
processor.process(new XSLTInputSource(in),
new XSLTInputSource(new FileInputStream(stylesheet)),
new XSLTResultTarget(res.getOutputStream()));
} catch (Exception e) {
PrintWriter out = res.getWriter();
out.println("Błąd: " + e.getMessage());
out.close();
}
}
}
Procesor wysyła dane wyjściowe do ServletOutputStream, a więc nie trzeba nawet dodawać żadnych dodatkowych danych wynikowych, oczywiście poza przypadkami błędów! Teraz można zachować serwlet jako ListBooksServlet.java i po kompilacji będzie on dostępny poprzez mechanizm serwletów i przeglądarkę.
|
Jeśli Czytelnik stara się wykonywać opisywane przykłady, to przed uruchomieniem serwleta będzie musiał przedsięwziąć pewne kroki. Po pierwsze, musi ustanowić połączenie z Internetem albo dokonać zmian w przykładach, tak aby mogły być uruchamiane lokalnie; serwlet obsługujący KsiegarniaTechniczna.com musi mieć dostęp do danych biblioteki. Po drugie, warto wpisać kilka książek o różnej tematyce do systemu biblioteki poprzez interfejs HTML. W ten sposób Czytelnik będzie mógł zobaczyć, co dokładnie robią aplikacje i jak ze sobą współpracują. Kiedy już dane znajdują się w bibliotece, a do samej biblioteki mamy dostęp, można uruchomić ListBooksServlet. |
Uruchomiony serwlet wysyła żądanie pobrania danych z Biblioteki Publicznej NaNiby. Dane te (lista nowych książek) są następnie przekształcane i wyświetlane na ekranie jako HTML. Odpowiedź z serwleta powinna wyglądać podobnie do tej pokazanej na rysunku 13.4 — widzimy spis nowych książek i aktualne informacje o nich (dzięki zmianom w bibliotece!); mamy także odsyłacze pozwalające na natychmiastowy zakup wybranej książki. Klienci firmy KsiegarniaTechniczna.com w prosty sposób przeglądają nowe tytuły online; pozostaje jeszcze „wypchnąć” te informacje do klientów tak, aby nie musieli nawet wpisywać adresu URL. Rozwiązanie tego problemu znajduje się w dalszej części rozdziału.
Pobieranie a „wypychanie” informacji
Do tej pory aplikacje tworzyliśmy z założeniem, że klienci sami będą pobierali dane i zawartość. Innymi słowy, klient musiał wpisać adres URL w przeglądarce (jak przy liście nowych książek w witrynie KsiegarniaTechniczna.com), lub też aplikacja taka jak opisywany wyżej serwlet musiała wysłać żądanie HTTP pobrania danych XML (jak w bibliotece). Oczywiście, nie ma tutaj żadnego problemu — ale takie rozwiązanie nie zawsze jest najlepsze z marketingowego punktu widzenia. Klienci pobierający dane muszą pamiętać, gdzie kupować książki, a często po jednej wizycie nie powracają w dane miejsce przez dni, tygodnie i miesiące. Sporadyczne zakupy na pewno nie przynoszą takich dochodów jak transakcje nawet mniejsze, ale za to częstsze.
Dlatego KsiegarniaTechniczna.com chce mieć możliwość wypychania (ang. push) danych do klientów. Klient dowiaduje się o nowych pozycjach wydawniczych lub promocjach bez konieczności wykonywania jakichkolwiek działań. Wynikiem są częstsze zakupy — klient nie musi sam pamiętać o odwiedzaniu strony. Ale w Internecie nie jest łatwo uzyskać takie wypychanie danych — sieć globalna to nie klient uproszczony, nie da się tak po prostu wyświetlić okienka „pop-up” z nowymi informacjami. Popularność zyskują natomiast „strony startowe” w rodzaju My Netscape firmy Netscape czy My Yahoo firmy Yahoo. W rozmowach z Netscape przedstawiciele firmy KsiegarniaTechniczna.com usłyszeli o technologii RSS — może to jest właśnie sposób uzyskania zaplanowanego celu?
|
Rysunek 13.4. Strona HTML powstała w wyniku pobrania listy książek
Rich Site Summary
Rich Site Summary (RSS) to szczególna odmiana języka XML. Posiada własną definicję DTD i definiuje pojęcie kanału. Kanał to sposób reprezentacji danych na określony temat. Zawiera tytuł i opis kanału, grafikę (logo) oraz szereg pozycji (ang. items) kanału. Każda pozycja to coś, co wiąże się z kanałem, ewentualnie produkt lub usługa. Ponieważ dozwolone elementy pozycji są raczej ogólne (tytuł, opis, odsyłacz), pozycją kanału może być niemal wszystko. Kanał RSS nie ma dostarczać kompletnej zawartości serwisu, lecz raczej „streszczenie” informacji o firmie lub usłudze, wyświetlane w postaci „portalowej”, ewentualnie jako pasek informacji na innej stronie WWW. Tak naprawdę poszczególne „widżety” w serwisie Netscape Netcenter to właśnie kanały RSS. Netscape udostępnia możliwość tworzenia nowych kanałów RSS, rejestrowanych w Netcenter. Netscape posiada również wbudowany system wyświetlania kanałów w formacie HTML, które wtedy świetnie spisują się jako strony startowe Netcenter.
Czytelnik może w tej chwili niepokoić się, czy RSS nie jest czasem dla firmy Netscape czymś takim jak parser Microsoft XML dla firmy Microsoft — czymś zupełnie nieużytecznym w połączeniu z innymi narzędziami czy produktami innych firm. Rozwiązanie to na początku faktycznie było opracowywane pod kątem Netcenter; jednak dzięki strukturze języka XML technologia RSS może zostać wykorzystana przez dowolną aplikację potrafiącą „czytać” pliki DTD. Coraz więcej portali i aplikacji korzysta z RSS — przykładem może być projekt Apache Jetspeed (http://java.apache.org/jetspeed), mający na celu stworzenie systemu Enterprise Information Portal w „stylu” open source. Jetspeed wykorzystuje dokładnie ten sam format RSS co Netscape, ale w zupełnie inny sposób. Jest to możliwe dzięki temu, że RSS ma bardzo spójną gramatykę.
Wielu użytkowników korzysta ze stron „startowych” lub „domowych” — miejsc najczęściej odwiedzanych w sieci. KsiegarniaTechniczna.com postanowiła stworzyć kanał RSS przedstawiający listę najnowszych książek i umożliwiający zainteresowanym natychmiastowy zakup określonego tytułu. To właśnie nazwać można „wypychaniem” danych — produkty takie jak Netcenter automatycznie aktualizują zawartość kanału RSS tak często, jak życzy sobie tego klient.
Tworzenie dokumentu RSS XML
Po pierwsze, konieczne jest utworzenie pliku RSS. A to jest prostsze, niż można byłoby przypuszczać — poza wpisaniem odwołania do właściwej DTD i trzymania się określonych w tej definicji zasad, nie ma tutaj nic skomplikowanego. W przykładzie 13.6 pokazano propozycję pliku RSS dla naszej księgarni.
Przykład 13.6. Przykładowy dokument RSS opisujący kanał firmy KsiegarniaTechniczna.com
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE rss PUBLIC "-//Netscape Communications//DTD RSS 0.91//EN"
"http://my.netscape.com/publish/formats/rss-0.91.dtd">
<rss version="0.91">
<channel>
<title>KsiegarniaTechniczna.com Nowe Tytuły</title>
<link>http://www.newInstance.com/javaxml/techbooks/</link>
<description>
Twoje źródło książek i materiałów o tematyce komputerowej.
</description>
<language>en-us</language>
<image>
<title>KsiegarniaTechniczna.com</title>
<url>
http://newInstance.com/javaxml/techbooks/images/techbooksLogo.gif
</url>
<link>http://newInstance.com/javaxml/techbooks</link>
<width>140</width>
<height>23</height>
<description>
Źródło książek technicznych.
</description>
</image>
<item>
<title>Java Servlet Programming</title>
<link>
http://newInstance.com/javaxml/techbooks/buy.xsp?isbn=156592391X
</link>
<description>
Doskonałe wprowadzenie do serwletów Javy i
różnych mechanizmow komunikacyjnych.
</description>
</item>
</channel>
</rss>
Element główny musi nazywać się rss; musi zostać także zdefiniowany atrybut version. Oprócz tego, wartość tego atrybutu musi odpowiadać wersji DTD, do której się odwołujemy. W elemencie głównym musi wystąpić dokładnie jeden element channel. Wewnątrz niego znajdują się natomiast elementy opisujące dany kanał (title, link, description i language). Z kanałem można również skojarzyć opcjonalny plik graficzny (oraz informacje o tym pliku). Następnie może wystąpić do 15 elementów item, z których każdy opisuje jedną pozycję związaną z kanałem. Każdy item posiada elementy title, link i description (ich znaczenia nie trzeba chyba wyjaśniać).
|
Tak jak w poprzednich przykładach, również tutaj w elementach link i url nie powinny znaleźć się białe znaki — całość powinna mieć postać jednego wiersza. W druku nie było to możliwe, dlatego wiersz został rozdzielony. |
Można także dodać opcjonalne pole tekstowe i przycisk do wysyłania informacji, czego w tym przykładzie nie pokazano. Szczegółowy opis elementów i atrybutów znajduje się na stronie http:// my.netscape.com/publish/help/mnn20/quickstart.html.
Tworzenie plików RSS programowo nie jest trudne; procedura podobna jest do tej, jaka została wykorzystana przy generowaniu pliku HTML na potrzeby księgarni. Połowa pliku RSS (informacje o kanale oraz o grafice) to treść statyczna; tylko elementy item są budowane dynamicznie. Ale kiedy już programista uruchamia edytor vi i zasiada do tworzenia kolejnego arkusza XSL, na biurku znajduje kartkę z kolejnym wymogiem: komputer, na którym znajdzie się kanał RSS, to inny serwer niż ten używany w ostatnim przykładzie; dostępne są na nim tylko bardzo stare wersje bibliotek Apache Xalan. Ponieważ na maszynie tej działają również pewne aplikacje wysokiej dyspozycyjności (np. system naliczania należności), KsiegarniaTechniczna.com nie chce aktualizować tych bibliotek, chyba że przy precyzyjnej kontroli efektów zmian (taki proces zajmuje tydzień). Na samym serwerze są jednak dostępne nowsze wersje bibliotek Xerces (ponieważ w systemie naliczania konieczne jest przetwarzanie XML-a), a więc dostępne są również interfejsy API Javy do obsługi XML-a. Oczywiście, dałoby się tutaj wykorzystać interfejsy SAX i DOM, ale po raz kolejny najlepszą metodą wydaje się JDOM. To za jego pomocą (przykład 13.7) dokonamy konwersji pliku XML z Biblioteki Publicznej NaNiby na format kanału RSS.
Przykład 13.7. Serwlet Javy konwertujący listę nowych książek na dokument kanału RSS
package com.techbooks;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URL;
import java.util.Iterator;
import java.util.List;
import javax.servlet.*;
import javax.servlet.http.*;
// JDOM
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.Builder;
import org.jdom.input.SAXBuilder;
public class GetRSSChannelServlet extends HttpServlet {
/** Z tego hosta pobieramy listę książek */
private static final String hostname = "newInstance.com";
/** Numer portu powyższego hosta */
private static final int portNumber = 80;
/** Ścieżka URI prowadząca do dokumentu */
private static final String file = "/cgi/supplyBooks.pl";
public void service(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
res.setContentType("text/plain");
PrintWriter out = res.getWriter();
// Łączymy się i pobieramy listę książek
URL getBooksURL = new URL("http", hostname, portNumber, file);
InputStream in = getBooksURL.openStream();
try {
// Żądamy implementacji SAX i korzystamy z domyślnego parsera.
Builder builder = new SAXBuilder();
// Tworzymy dokument.
Document doc = builder.build(in);
// Wyświetlamy XML.
out.println(generateRSSContent(doc));
} catch (JDOMException e) {
out.println("Error: " + e.getMessage());
} finally {
out.close();
}
}
/**
* <p>
* Tutaj generujemy dokument RSS XML, korzystając z dostarczonego
* obiektu JDOM <code>Document</code>.
* </p.
*
* @param doc <code>Document</code> dane wejściowe.
* @return <code>String</code> - plik wyjściowy RSS.
* @throws <code>JDOMException</code> w razie wystąpienia błędów.
*/
private String generateRSSContent(Document doc) throws JDOMException {
StringBuffer rss = new StringBuffer();
rss.append("<?xml version=\"1.0\"?>\n")
.append("<!DOCTYPE rss PUBLIC ")
.append("\"-//Netscape Communications//DTD RSS 0.91//EN\" ")
.append("\"http://my.netscape.com/publish/formats/rss-0.91.dtd\">\n")
.append("<rss version=\"0.91\">\n")
.append(" <channel>\n")
.append(" <title>Książki techniczne</title>\n")
.append(" <link>http://newInstance.com/javaxml/techbooks</link>\n")
.append(" <description>\n")
.append(" Twoje źródło książek i materiałów o tematyce komputerowej.\n ")
.append(" </description>\n")
.append(" <language>en-us</language>\n")
.append(" <image>\n")
.append(" <title>KsiegarniaTechniczna.com</title>\n")
.append(" <url>")
.append("http://newInstance.com/javaxml/techbooks/images/techbooksLogo.gif")
.append("</url>\n")
.append(" <link>http://newInstance.com/javaxml/techbooks</link>\n")
.append(" <width>140</width>\n")
.append(" <height>23</height>\n")
.append(" <description>\n")
.append(" Źródło książek technicznych.\n")
.append(" </description>\n")
.append(" </image>\n");
// Dodajemy element dla każdego nowego tytułu, w którym jako temat
// określono Computers.
List books = doc.getRootElement().getChildren("book");
for (Iterator i = books.iterator(); i.hasNext(); ) {
Element book = (Element)i.next();
if (book.getAttribute("subject")
.getValue().equals("Computers")) {
// Wyświetlamy pozycję.
rss.append("<item>\n")
// Dodajemy tytuł
.append(" <title>")
.append(book.getChild("title").getContent())
.append("</title>\n")
// Dodajemy odsyłacz umożliwiający kupno książki
.append(" <link>")
.append("http://newInstance.com/javaxml/techbooks/buy.xsp?isbn=")
.append(book.getChild("saleDetails")
.getChild("isbn")
.getContent())
.append("</link>\n")
.append(" <description>")
// Dodajemy opis
.append(book.getChild("description").getContent())
.append("</description>\n")
.append("</item>\n");
}
}
rss.append(" </channel>\n")
.append("</rss>");
return rss.toString();
}
}
Na tym etapie nauki ani jeden fragment powyższego kodu nie powinien już Czytelnika dziwić. Importujemy wymagane klasy JDOM i wejścia-wyjścia oraz uzyskujemy dostęp do aplikacji biblioteki publicznej dokładnie tak, jak w serwlecie ListBooksServlet. Wynikowy InputStream wykorzystywany jest do stworzenia obiektu JDOM Document, za pomocą parsera domyślnego (w JDOM 1.0 jest to Apache Xerces) oraz implementacji JDOM zbudowanej na bazie SAX-a:
// Żądamy implementacji SAX i korzystamy z domyślnego parsera
Builder builder = new SAXBuilder();
// Tworzymy dokument.
Document doc = builder.build(in);
Teraz przekazujemy Document do metody generateRSSContent(), która drukuje całą zawartość statyczną kanału. Metoda ta pobiera elementy book z biblioteki, przetwarza je kolejno i ignoruje te, w których jako subject określono coś innego niż „Computers”:
// Dodajemy element dla każdego nowego tytułu, w którym jako temat
// określono Computers.
List books = doc.getRootElement().getChildren("book");
for (Iterator i = books.iterator(); i.hasNext(); ) {
Element book = (Element)i.next();
if (book.getAttribute("subject")
.getValue().equals("Computers")) {
// Wyświetlamy pozycję.
}
}
Każdy element, który przejdzie pomyślnie powyższy test, dodawany jest do kanału RSS. Prawda, że nic nadzwyczajnego? Na rysunku 13.5 przedstawiono przykładowe dane zwracane przez serwlet, który zachowano jako plik GetRSSChannelServlet.java.
KsiegarniaTechniczna.com udostępniła w ten sposób informacje wszystkim usługodawcom, którzy obsługują technologię RSS. Żeby jeszcze klienci mogli korzystać z takiego kanału, KsiegarniaTechniczna.com zarejestruje kanał w Netscape Netcenter.
Sprawdzanie poprawności kanału RSS
Po stworzeniu kanału należy sprawdzić jego poprawność. W ten sposób nie tylko zagwarantujemy, że dokument jest zgodny z wymogami określonymi przez definicję RSS DTD; będzie on również zgodny z pewnymi ograniczeniami narzucanymi przez Netscape, a niemożliwymi do określenia w definicji DTD (w przyszłości być może rozwiązaniem tego problemu będzie XML Schema). Firma Netscape oferuje mechanizm sprawdzania poprawności kanałów online, znajdujący się pod adresem http://my.netscape.com/publish/help/validate.tmpl. Po wpisaniu na tej stronie adresu naszego kanału RSS (który może mieć postać serwleta, skryptu CGI lub pliku statycznego) odpowiedni program sprawdzi jego poprawność. Na rysunku 13.6 przedstawiono stronę wyświetlaną po udanym sprawdzeniu poprawności.
Teraz można już zarejestrować nasz kanał w usłudze Netcenter.
|
Rysunek 13.5. Kanał RSS wygenerowany przez serwlet GetRSSChannelServlet
|
Rysunek 13.6. Potwierdzenie sprawdzania poprawności kanału RSS
Rejestracja kanału
Po sprawdzeniu poprawności --> opublikujemy kanał [Author:RG] w serwisie Netcenter (lub u innego usługodawcy). W tym celu wchodzimy na stronę http://my.netscape.com/publish. Należy podać nazwę konta Netcenter, ponieważ e-mail potwierdzający zostanie wysłany na adres podany przy zakładaniu takiego konta. Po podaniu adresu poprawnego kanału RSS, Netcenter dodaje go do systemu kanałów i wysyła e-mail. W wiadomości takiej zawarte są instrukcje dotyczące dodania odsyłacza do kanału RSS ze strony WWW (np. z KsiegarniaTechniczna.com, o czym za chwilę) oraz dotyczące dodania kanału do strony startowej Netcenter.
Korzystanie z kanału
Sprawdzenie poprawności i rejestracja kanału nie przedstawiały trudności. Otrzymany e-mail upraszcza nawet dodanie takiego kanału do strony startowej. Od tej pory nasz kanał RSS w postaci HTML będzie można oglądać jako fragment strony startowej Netcenter. --> Po każdym otwarciu [Author:AJ] tej strony startowej użytkownik zobaczy „ramkę” KsiegarniaTechniczna.com, w której znajdzie nowe tytuły i będzie mógł je natychmiast zakupić. To na pewno zwiększy przychody ze sprzedaży online.
Aby rozreklamować kanał, do stworzonego arkusza stylu można jeszcze dodać odsyłacz, który spowoduje automatyczne dodanie kanału do strony startowej oglądającego. Tak więc jedna operacja pobrania danych może zaowocować codziennymi „wypchnięciami” oferty firmy. Oto sposób dodania odsyłacza do arkusza:
<p align="center">
<font color="#FFFFFF"><b>
<a href="http://newInstance.com/javaxml/techbooks/contact.html">Kontakt</a>
</b></font>
</p>
<br>
<p align="center">
<A HREF="http://my.netscape.com/addchanneltmpl?service=net.2209">
<IMG SRC="http://my.netscape.com/publish/images/addchannel.gif"
WIDTH="88" HEIGHT="31" BORDER="0" /></A>
</p>
</td>
<td valign="top" align="left">
<table border="0" cellpadding="5" cellspacing="5">
<tr>
<td width="450" align="left" valign="top">
<p>
<b>
Witamy w firmie <font face="courier">KsiegarniaTechniczna.com</font>,
oferującej książki o tematyce komputerowej i technicznej.
Po lewej stronie zamieszczono najnowsze tytuły. Aby nabyć
którąś z tych wspaniałych książek, wystarczy kliknąć odsyłacz "Kup książkę!" co spowoduje przeniesienie wybranej pozycji
do koszyka. Miłych zakupów!
</b>
</p>
Wprowadzenie takiego fragmentu (który otrzymujemy e-mailem z Netscape po rejestracji kanału) spowoduje dodanie elementu graficznego, odsyłającego prosto do strony, --> która dodaje [Author:RG] kanał do strony startowej użytkownika. Sformatowana strona HTML po wprowadzeniu zmiany wygląda tak, jak --> na rysunku 13.9[Author:AJ] .
|
Rysunek 13.9. Strona HTML z odwołaniem do kanału RSS Netscape
Przykładowy problem komunikacji typu firma-firma został rozwiązany. Punktem wyjścia była organizacja pracująca w jednym języku i bez możliwości wykorzystania XML-a (Biblioteka Publiczna NaNiby wraz z jej skryptami w Perlu); w wyniku działań przedstawionych w tym rozdziale uzyskała ona możliwość komunikacji z firmą korzystającą z zupełnie innej technologii (serwlety Javy). Obie firmy nie były w żaden sposób ze sobą zsynchronizowane — żaden fragment kodu jednej nie łączył się w jakikolwiek sposób z kodem drugiej. Ponieważ jako nośnik informacji został użyty język XML, w obu firmach mogą się zmienić aplikacje, technologie, a nawet architektury, a i tak nie wpłynie to na stworzony w rozdziale mechanizm. Następnie Czytelnik dowiedział się, jak w wyniku takiej komunikacji można stworzyć zawartość HTML prezentowaną użytkownikom (na zupełnie różne sposoby zależnie od aplikacji) oraz jak „wypchnąć” tę zawartość do klientów w jeszcze jednym formacie HTML poprzez kanały RSS. Wszystko to możliwe było dzięki obecnemu „za kulisami” XML-owi.
Praktyka
Niewiele więcej można powiedzieć o aplikacjach typu firma-firma. Omawiany przykład został zaczerpnięty z życia — podobne wymagania i cele określone zostały w pewnych dużych firmach.
W kolejnych podrozdziałach Czytelnik dowie się, czym różni się to rozwiązanie skoncentrowane wokół XML-a od technologii Electronic Data Interchange (EDI); omówione zostaną również inne zastosowania kanałów RSS.
XML kontra EDI
Zapotrzebowanie na komunikację pomiędzy firmami jest coraz większe i to przyczyniło się do spopularyzowania technologii Electronic Data Interchange (EDI). Drogie produkty i rozwiązania typu „heavy-duty”, jeśli tylko na ich pudełkach widnieje napis „EDI”, od razu sprzedają się jak świeże bułeczki. Ale te kosztowne rozwiązania, co oczywiste, nie są popularne w mniej zamożnych firmach. Od kiedy pojawił się XML, nawet firmy o wysokim budżecie rezygnują z EDI na rzecz XML-a. Wynika to nie tylko z faktu, ze XML jest rozwiązaniem wysoce standardowym, ale również z prostoty tego języka. Przecież w jednym rozdziale został opisany sposób komunikacji zupełnie oddzielnych systemów! Dziesięć lat temu wymagałoby to całego zespołu programistów, a powstałe rozwiązanie i tak działałoby tylko w tych konkretnych warunkach.
Można dowieść, że XML całkowicie znosi potrzebę korzystania z EDI. Stare systemy, aplikacje własne, masywne bazy danych i produkty o podwyższonym stopniu bezpieczeństwa — one wszystkie mogą wymieniać dane za pomocą formatu XML. Interfejsy API w rodzaju SAX-a, DOM-a, a obecnie również JDOM-a powodują, że tworzenie pełnych rozwiązań XML jest praktyczne, a budowanie warstw XML „na” istniejących danych w różnych formatach to kwestia tygodni i miesięcy, a nie lat. EDI powoli zacznie znikać z rynku, jego miejsce zastąpią oferty e-biznesowe oparte na XML-u i Javie.
Kanały RSS — czy to coś trwałego?
Często pada pytanie, czy formaty XML w rodzaju RSS to rozwiązanie „trwałe”. Format ten jest wykorzystywany w pewien konkretny sposób (np. na stronie Netscape Netcenter) — czy więc RSS jest rozwiązaniem firmy Netscape? Tak, RSS kojarzy się z konkretną firmą, ale ponieważ oparty jest na XML-u, może być wykorzystywany tak jak dowolny inny dokument XML. Styl dokumentu jest całkowicie umowny, a napisanie arkusza przekształcającego RSS na WML dla telefonów bezprzewodowych to rzecz banalna. Zresztą zostało już wspomniane, że projekt Apache Jetspeed korzysta z RSS, a sieć O'Reilly Network (http://www.oreillynet.com) „zatrudniła” kanały RSS w serwisach takich jak XML.com (http://www.xml.com).
Jeszcze ważniejsze jest to, że rozwiązania wykorzystujące XML z natury nie mają nic wspólnego z rozwiązaniami „własnymi”. Dowolny dokument XML może być przekształcony tak, jak sobie tego zażyczy autor lub programista. Nie ulega wątpliwości, że w ciągu najbliższych lat dokonana zostanie migracja większości warstw prezentacyjnych do XML-a, bądź też konkretnej odmiany XML-a (np. RSS). Firmy chcą budować strony o dynamicznej zawartości, ale nie mają zamiaru zatrudniać przy tym całej armii twórców witryn.
Co dalej?
Czytelnik umie już posługiwać się XML-em „wewnątrz” kodu w Javie. Potrafi tworzyć, przetwarzać, budować style, przekształcać, zawężać i sprawdzać poprawność XML-a. Wie również, jak korzystać ze struktur publikacji, ze zdalnych wywołań procedur, jak przechowywać informacje o konfiguracji w dokumencie XML oraz jak budować XML „w locie” z kodu Javy. To powinno wystarczyć do zbudowania niemal dowolnej aplikacji w języku XML. W następnym rozdziale, już ostatnim w tej książce, zostaną przedstawione schematy XML Schema. Czytelnik wie już, jak za ich pomocą zawężać dokumenty XML; teraz dowie się, dlaczego XML Schema jest tak innowacyjny, oraz jak wpływa na sposób korzystania z języka XML. Rozdział ten nie dotyczy samego języka Java, ale omawiana w nim problematyka jest niezwykle istotna z punktu widzenia sposobu, w jaki wykorzystywany jest język XML w aplikacjach.
Więcej informacji o klasie URL i operacjach wejścia-wyjścia Javy można znaleźć w książce Java I/O Eliotte Rusty Harolda (O'Reilly & Associates).
Tak, to nieco wydumany przykład, pewnie mało prawdopodobny. Ale pozwala Czytelnikowi poznać jeszcze jedną alternatywę co do sposobu programowego tworzenia XML-a. Jednak tak naprawdę wszystkie przykłady w tej książce (łącznie z tymi głupiutkimi) oparte są na prawdziwych doświadczeniach związanych z prowadzeniem konsultingu w rzeczywistych firmach!
350 Rozdział 13. Firma-firma
Co dalej? 351
H:\Książki\!Kudlaty\Java i XML\92 po poprawkach korektora\13-08.doc — strona 350
H:\Książki\!Kudlaty\Java i XML\92 po poprawkach korektora\13-08.doc — strona 351
H:\Książki\!Kudlaty\Java i XML\92 po poprawkach korektora\13-08.doc — strona 323
Chyba wyszły za duże odstępy i 2 wiersze "spadły" na następną stronę.
Spadło :-(
W.D.: Opuszczenie na stronie 410 oryginału; ilustracja 13.8: Netcenter z dostosowanym kanałem RSS.
W.D.: Opuszczenie na stronie 412 oryginału; ilustracja 13.9: Strona HTML z kanałem RSS Nestcape.