Rozdział
-->
12[Author:T]
.
WML, ASP, JSP, serwlety i Perl
W tym rozdziale zajmiemy się kilkoma różnymi tematami, między innymi Bezprzewodowym językiem znaczników (WML, Wireless Markup Language), czyli popularną aplikacją XML przeznaczoną do użycia w telefonach komórkowych, PDA i innych prostych urządzeniach elektronicznych obsługujących protokół WAP (Wireless Application Protocol). WML jest językiem prostym, obecnie można się na niego już w wielu miejscach natknąć, a nowe serwery WAP pojawiają się jak grzyby po deszczu. W tym rozdziale dużo uwagi poświęcimy tworzeniu dokumentów WML i oglądaniu ich w przeglądarkach WML (często nazywanych mikroprzeglądarkami).
W tym rozdziale zajmiemy się także użyciem XML w połączeniu z istniejącymi technologiami działającymi po stronie serwera, takimi jak Active Server Pages (ASP), Java Server Pages (JSP), serwlety Javy i Perl. Wiele firm usiłuje teraz zaistnieć na rynku XML/Internet, wobec czego pojawia się mnóstwo oprogramowania - zajrzyj na stronę Microsoftu pod adres http://msdn.microsoft.com/xml/demos/default.asp, gdzie znajdziesz zestawienie. Jedną z popularnych technologii działających po stronie serwera jest Prosty protokół dostępu do obiektów (SOAP, Simple Object Access Protocol). Jest to faktycznie prosty protokół, który umożliwia wymianę komunikatów w środowisku rozproszonym, przy czym komunikaty zapisane są w XML. SOAP często jest używany do wysyłania poleceń w nagłówkach HTTP, gdyż protokoły zdalnego wywołania metod, takie jak DCOM Microsoftu, nie są ani dość proste, ani dość elastyczne, aby można je było zastosować w Internecie. Trzeba zresztą powiedzieć, że Microsoft jest jednym z głównych promotorów SOAP, co może kazać się zastanowić nad przyszłością DCOM. Nad SOAP także intensywnie pracują IBM i Lotus.
Więcej o SOAP
Trudno jest w Internecie znaleźć informacje o SOAP, gdyż w języku angielskim słowo to oznacza po prostu mydło i wśród odpowiedzi większość dotyczyła będzie czystości i telewizyjnych tasiemców („opery mydlane”). Na początek możesz zatem poszukiwania zacząć od następujących adresów:
http://msdn.microsoft.com/xml/general/soapspec.asp
www.oasis-open.org/cover/soap.html
www.develop.com/soap
www.develop.com/soap/soapfaq.xml
Tutaj koniec ramki „Wyróżnienie”
W tym rozdziale przyjrzymy się też tworzeniu dokumentów XML po stronie serwera. W tym celu będziemy pobierać dane z pliku bazy danych db.mdb w zwykłym formacie Microsoft Access. Następnie dane będziemy formatować w XML i przesyłać wynikowe dokumenty do komputerów klienckich. Baza danych jest bardzo prosta, zawiera jedynie imiona ośmiorga studentów wraz z ich oceną wyrażoną literą - tabela 12.1.
Tabela 12.1.
Studenci z pliku db.mdb
Student |
Ocena |
Ann |
C |
Mark |
B |
Ed |
A |
Frank |
A |
Ted |
A |
Mabel |
B |
Ralph |
B |
Tom |
B |
Zaczniemy od zastosowania Obiektów danych ActiveX (ADO, ActiveX Data Objects) zainstalowanych na serwerze przeszukujących bazę danych i tworzących dokument XML wyświetlany za pomocą Active Server Pages.
Programowanie po stronie serwera
W pierwszej części tego rozdziału, kiedy opisywać będziemy programowanie od strony serwera, wiele technologii omówionych zostanie bardzo pobieżnie. Niestety nie sposób omówić tutaj wszystkiego, co potrzebne do programowania Active Server Pages, Java Server Pages, serwletów Javy czy Perla. Jeśli potrzebne będą Ci dodatkowe informacje, musisz poszukać ich gdzie indziej. Kiedy w drugiej części tego rozdziału omawiać będziemy WML, tego rodzaju ograniczeń już nie będzie - zaczniemy omawianie wszystkiego od samego początku.
XML i Active Server Pages
Active Server Pages (ASP) to technologia internetowa działająca po stronie serwera zaproponowana przez Microsoft, która umożliwia tworzenie dokumentów w locie. Dokumenty tworzone są na serwerach takich, jak Microsoft Internet Information Server (IIS); w naszym wypadku wyszukamy imiona w bazie db.mdb i zwrócimy je w postaci następującego dokumentu XML:
<?xml version="1.0" encoding="iso-8859-2"?>
<document>
<student>
Ann
</student>
<student>
Mark
</student>
<student>
Ed
</student>
<student>
Frank
</student>
<student>
Ted
</student>
<student>
Mabel
</student>
<student>
Ralph
</student>
<student>
Tom
</student>
</document>
Najważniejsze w przypadku ASP to upewnić się, że kod wygeneruje dokument XML, gdyż domyślnym typem dokumentu jest HTML. Jeśli opis typu zawartości w nagłówku HTTP nie zawiera informacji, że mamy do czynienia z dokumentem XML, przeglądarka dokumentu tego nie potraktuje jako XML (i zapewne potraktuje go jako HTML). Typ zawartości określa się za pomocą instrukcji <% Response.ContentType %> podając typ application/xml:
<% Response.ContentType = "application/xml" %>
.
.
.
Następnie dodajemy deklarację XML oraz element główny, document:
<% Response.ContentType = "application/xml" %>
<?xml version="1.0" encoding="iso-8859-2"?>
<document>
.
.
.
Teraz potrzebne nam są imiona studentów z bazy db.mdb. Użyjemy do tego protokołu ADO Microsoftu, gdyż ASP przeznaczony jest do pracy na platformach Windows, takich jak IIS. Utworzymy połączenie ADO oraz użyjemy instrukcji SQL pobierającej zestaw wszystkich rekordów:
<% Response.ContentType = "application/xml" %>
<?xml version="1.0" encoding="iso-8859-2"?>
<document>
<%
DIM adoConnect
DIM adoRecordset
Set adoConnect = Server.CreateObject("ADODB.Connection")
adoConnect.open "Provider=Microsoft.Jet.OLEDB.4.0;" _
& "Data Source=C:\xml\db.mdb"
Set adoRecordset = adoConnect.Execute("SELECT * FROM Students")
.
.
.
Teraz pozostało nam już tylko zorganizować pętlę po wszystkich rekordach i utworzyć w każdym przejściu element XML student:
<% Response.ContentType = "application/xml" %>
<?xml version="1.0" encoding="iso-8859-2"?>
<document>
<%
DIM adoConnect
DIM adoRecordset
Set adoConnect = Server.CreateObject("ADODB.Connection")
adoConnect.open "Provider=Microsoft.Jet.OLEDB.4.0;" _
& "Data Source=C:\xml\db.mdb"
Set adoRecordset = adoConnect.Execute("SELECT * FROM Students")
Do While Not adoRecordset.EOF
Response.Write "<student>" + adoRecordset("Name") + "</student>"
adoRecordset.MoveNext
Loop
adoRecordset.Close
set adoRecordset = Nothing
%>
</document>
W ten sposób utworzony zostanie potrzebny nam dokument XML, co pokazano na rysunku 12.1.
Rysunek 12.1. Tworzenie dokumentu XML za pomocą ASP |
Nie mogę wykonać rysunku, gdyż wymaga IIS. Rysunek można zeskanować z książki (dlatego właśnie nie zmieniłem znaczników document na dokument ani nie zmieniałem imion na polskie odpowiedniki. Rysunek powinien być taki jak poniżej, ale inny powinien być pasek tytułu (jak w książce); to samo dotyczy rysunków 12.2 i 12.3.
|
Zwróć uwagę na to, że następne rysunki będą bardzo podobne do powyższego; aby zauważyć różnice między nimi, dokładnie przyglądaj się paskom tytułu przeglądarki.
XML i serwlety Javy
Serwlety Javy mają być dla serwerów sieciowych tym, czym są aplety Javy dla komputerów klienckich. Serwletów można użyć do tworzenia dokumentów sieciowych na różnych serwerach. Aby tworzyć serwlety, możesz załadować Java Servlet Development Kit (JSDK) ze strony java.sun.com (w chwili pisania strona główna poświęcona serwletom to http://java.sun.com/products/servlet/index.html) i tworzyć serwlety za pomocą klas z archiwów servlet.jar i server.jar.
Aby odczytać z bazy danych db.mdb imiona studentów, użyjemy pakietu JDBC (Java Database Connectivity) łącząc się z db.mdb po zarejestrowaniu bazy danych jako źródła danych ODBC. Kiedy wyszukamy już imiona studentów, umieścimy je w dokumencie XML i dokument ten odeślemy do klienta.
Znów najważniejsze jest stworzenie dokumentu XML, a nie domyślnego HTML. W przypadku serwletów dokument XML tworzy się za pomocą metody setContentType klasy ServletResponse podając jako typ zawartości application/xml:
import java.net.*;
import java.sql.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import javax.servlet.*;
public class xml extends GenericServlet
{
public void service(ServletRequest request, ServletResponse
response) throws ServletException, IOException
{
response.setContentType("application/xml");
.
.
.
Następnie zwracamy klientowi deklarację XML i element główny:
import java.net.*;
import java.sql.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import javax.servlet.*;
public class xml extends GenericServlet
{
public void service(ServletRequest request, ServletResponse
response) throws ServletException, IOException
{
response.setContentType("application/xml");
PrintWriter printwriter = response.getWriter();
printwriter.println("<?xml version=\"1.0\" encoding=\"iso-8859-2\"?>");
printwriter.println("<document>");
.
.
.
Teraz możemy użyć JDBC do utworzenia zbioru wyników zawierającego wszystkie rekordy z bazy db.mdb:
import java.net.*;
import java.sql.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import javax.servlet.*;
public class xml extends GenericServlet
{
public void service(ServletRequest request, ServletResponse
response) throws ServletException, IOException
{
response.setContentType("application/xml");
PrintWriter printwriter = response.getWriter();
printwriter.println("<?xml version=\"1.0\" encoding=\"iso-8859-2\"?>");
printwriter.println("<document>");
try
{
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
connection = DriverManager.getConnection(
"jdbc:odbc:students", "Steve", "password");
statment = connection.createStatement();
String SQL = "SELECT Name FROM Students";
ResultSet resultset = statement.executeQuery(SQL);
.
.
.
Teraz już tylko musimy utworzyć pętlę po zbiorze wyników, w której pobierzemy imiona studentów i odeślemy je do klienta zamknięte elementami student:
import java.net.*;
import java.sql.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import javax.servlet.*;
public class xml extends GenericServlet
{
public void service(ServletRequest request, ServletResponse
response) throws ServletException, IOException
{
response.setContentType("application/xml");
PrintWriter printwriter = response.getWriter();
printwriter.println("<?xml version=\"1.0\" encoding=\"iso-8859-2\"?>");
printwriter.println("<document>");
try
{
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
connection = DriverManager.getConnection(
"jdbc:odbc:students", "Steve", "password");
statment = connection.createStatement();
String SQL = "SELECT Name FROM Students";
ResultSet resultset = statement.executeQuery(SQL);
while (resultset.next()) {
printwriter.println("<student> +
resultset.getString(1) + "</student>");
}
}
catch(Exception e) {}
printwriter.println("</document>");
printwriter.close();
}
}
I to już wszystko. Wynik działania serwleta pokazano na rysunku 12.2, gdzie do klienta zwrócony został ten sam dokument, co w przypadku omawianego poprzednio ASP.
Rysunek 12.2. Tworzenie dokumentów za pomocą serwletów Javy |
Nie mogę wykonać rysunku, gdyż wymaga serwera HTTP/WWW. Rysunek można zeskanować z książki (dlatego właśnie nie zmieniłem znaczników document na dokument ani nie zmieniałem imion na polskie odpowiedniki. |
Kolejną zdobywającą popularność technologią z wykorzystaniem Javy jest użycie Java Server Pages, co omówiono w następnym podrozdziale.
Java Server Pages
Java Server Pages (JSP) to reakcja środowiska Javy na Active Server Pages Microsoftu. JSP umożliwia tworzenie dynamicznych stron sieciowych przez uruchamianie skryptów na serwerze. Dokładny opis JSP znajdziesz na stronie http://java.sun.com/products/jsp/index.html. JSP używa się podobnie jak ASP.
W tym przykładzie użyjemy serwera Apache Tomcat będącego oficjalnie wzorcową implementacją JSP (a także serwletów Javy). Serwer ten możesz „ściągnąć” ze strony http://jakarta.apache.org/tomcat/.
Utworzymy taki sam dokument XML jak w dwóch poprzednich przykładach na podstawie danych z bazy db.mbd. Jako że powtórnie korzystamy z Javy, znów użyjemy do sięgania do bazy danych JDBC.
Znów na początek musimy zapewnić prawidłową interpretację typu dokumentu, aby użyty został typ application/xml, a nie domyślny HTML. W JSP korzysta się z atrybutu contentType:
<%@ page language="java" contentType="application/xml"
import="java.sql.*" %>
.
.
.
Znów inicjalizujemy sterownik JDBC:
<%@ page language="java" contentType="application/xml"
import="java.sql.*" %>
<% Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); %>
.
.
.
Następnie wstawiamy deklarację XML oraz element główny:
<%@ page language="java" contentType="application/xml"
import="java.sql.*" %>
<% Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); %>
<?xml version="1.0" encoding="iso-8859-2"?>
<document>
.
.
.
Teraz pobieramy zbiór wyników z JDBC - rekordy wszystkich studentów zwrócone przez zapytanie SQL:
<%@ page language="java" contentType="application/xml"
import="java.sql.*" %>
<% Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); %>
<?xml version="1.0" encoding="iso-8859-2"?>
<document>
<%
Connection connection = DriverManager.getConnection(
"jdbc:odbc:students", "Steve", "password");
Statement statement = connection.createStatement();
ResultSet resultset =
statement.executeQuery("select * from Students"); %>
.
.
.
Teraz już pozostało tylko utworzenie pętli po studentach i wygenerowanie elementów student:
<%@ page language="java" contentType="application/xml"
import="java.sql.*" %>
<% Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); %>
<?xml version="1.0" encoding="iso-8859-2"?>
<document>
<%
Connection connection = DriverManager.getConnection(
"jdbc:odbc:students", "Steve", "password");
Statement statement = connection.createStatement();
ResultSet resultset =
statement.executeQuery("select * from Students"); %>
<% while(resultset.next()){ %>
<student> <%= resultset.getString() %> </student>
<% } %>
<document>
Na rysunku 12.3 pokazano wyniki działania skryptu JSP. Jak widać, wyniki wcale nie są gorsze niż w przypadku zastosowania ASP, zresztą znam bardzo wielu programistów XML, którzy do udostępniania dokumentów XML wolą właśnie JSP zamiast ASP, gdyż praca z XML w Javie jest niejako naturalna, o czym można było się przekonać w rozdziałach 8 i 9 niniejszej książki.
Rysunek 12.3. Tworzenie dokumentów XML za pomocą Java Server Pages |
Rysunek wymaga serwera Tomcat, który w mojej konfiguracji nie działa. Rysunek można zeskanować z książki (dlatego właśnie nie zmieniłem znaczników document na dokument ani nie zmieniałem imion na polskie odpowiedniki. |
XML i Perl
Praktyczny język pobierania danych i raportowania (PERL, Practical Extraction and Reporting Language) przez długi czas był podstawowym narzędziem do programowania serwerów i podstawą CGI. Język ten też szybko znalazł zastosowanie do obsługi XML, nietrudno byłoby na ten temat napisać osobną książkę.
Moduły Perla rozproszone są po sieciowym archiwum Perla (CPAN, Comprehensive Perl Archive Network) dostępnym pod adresem www.cpan.org, wiele z tych modułów służy do obsługi XML (autor doliczył się 156 takich modułów). W tabeli 12.2 zestawiono wybrane moduły wraz z ich opisem podawanym w witrynie CPAN.
Tabela 12.2.
Moduły Perla do obsługi XML wraz z opisem z CPAN
Moduł |
Opis |
Apache::AxKit::XMLFinder |
Wykrywa pliki XML |
Apache::MimeXML |
--> „Nasłuchiwacz” typów kodowania mime mod_perl wyszukujący pliki XML.[Author:T] |
Boulder::XML |
Procedury formatowania XML strumieni wejściowo-wyjściowych --> Boulder[Author:T] . |
Bundle::XML |
Pakiet instalujący wszystkie moduły powiązane z XML. |
CGI::XMLForm |
Rozszerzenie CGI.pm odczytujące/generujące sformatowany XML. |
Data::DumpXML |
Zapisuje dowolne struktury danych jako XML. |
DBIx::XML_RDB |
Rozszerzenie Perla służące do generacji XML na podstawie istniejących źródeł danych DBI. |
GoXML::XQI |
Rozszerzenie Perla służące do obsługi interfejsu XML Query w xqi.goxml.com. |
Mail::XML |
Dodaje do Mail::Internet metodę toXML(). |
MARC::XML |
Podklasa MARC.pm zapewniająca obsługę XML. |
PApp::XML |
Sekcje pxml i inne. |
XML::Catalog |
Rozwija identyfikatory publiczne i przekształca identyfikatory systemowe. |
XML::CGI |
Rozszerzenie Perla służące do konwersji zmiennych CGI.pm z/na XML. |
XML::Checker |
Moduł Perla służący do walidacji XML. |
XML::Checker::Parser |
XML::Parser walidujący podczas parsowania dokumentów. |
XML::DOM |
Moduł Perla służący do tworzenia struktur dokumentów zgodnych z DOM Level 1. |
XML::DOM::NamedNodeMap |
Interfejs tablic haszujących dla XML::DOM. |
XML::DOM::NodeList |
Listy węzłów używane przez XML::DOM. |
XML::DOM::PerlSAX |
Stara nazwa XML::Handler::BuildDOM. |
XML::DOM::ValParser |
XML::DOM::Parser walidujący w czasie parsowania. |
XML::Driver::HTML |
Sterownik SAX przeznaczony dla HTML nie sformułowanego poprawnie w rozumieniu XML. |
XML::DT |
Pakiet przekształcania XML na napisy. |
XML::Edifact |
Moduł Perla obsługujący komunikaty XML::Edifact. |
XML::Encoding |
Moduł Perla do parsowania map kodowania XML. |
XML::ESISParser |
Parser PerlSAX używający nsgmls. |
XML::Filter::DetectWS |
Filtr PerlSAX wykrywający białe znaki, które mogą zostać pominięte. |
XML::Filter::Hekeln |
Edytor strumieniowy SAX. |
XML::Filter::Reindent |
Uzupełnia białe znaki, aby uzyskać dokument XML w ładnej graficznie postaci. |
XML::Filter::SAXT |
Replikuje zdarzenia SAX kilku procedurom obsługi zdarzeń SAX. |
XML::Generator |
Rozszerzenie Perla do generacji XML. |
XML::Grove |
Perlopodobne obiekty XML. |
XML::Grove::AsCanonXML |
Wyprowadza obiekty XML w postaci kanonicznego XML. |
XML::Grove::AsString |
Wyprowadza treść obiektów XML jako napisy. |
XML::Grove::Builder |
Procedura obsługi PerlSAX do tworzenia XML::Grove. |
XML::Grove::Factory |
Upraszcza tworzenie obiektów XML::Grove. |
XML::Grove::Path |
Zwraca obiekt z podanej ścieżki. |
XML::Grove::PerlSAX |
Interfejs zdarzeń PerlSAX dla obiektów XML. |
XML::Grove::Sub |
Uruchamia procedurę filtrującą na dokumencie. |
XML::Grove::Subst |
Podstawia wartości do szablonu. |
XML::Handler::BuildDOM |
Procedura obsługi PerlSAX tworząca struktury dokumentu XML::DOM. |
XML::Handler::CanonXMLWriter |
Wyprowadza dane w postaci kanonicznego XML. |
XML::Handler::Composer |
Generuje, drukuje i zapisuje XML. |
XML::Handler::PrintEvents |
Drukuje zdarzenia PerlSAX (przydatne przy usuwaniu błędów w programach). |
XML::Handler::PyxWriter |
Przekształca zdarzenia PerlSAX na ESIS nsgmls. |
XML::Handler::Sample |
Elementarna procedura obsług zdarzeń PerlSAX. |
XML::Handler::Subs |
Klasa bazowa procedury obsługi zdarzeń PerlSAX przeznaczona do wywoływania procedur zdefiniowanych przez użytkownika. |
XML::Handler::XMLWriter |
Procedura obsługi zdarzeń PerlSAX przeznaczona do wypisania czytelnego dla człowieka XML. |
XML::Handler::YAWriter |
Kolejny PerlSAX XML Writer 0.15. |
XML::Node |
Oparte na obsłudze węzłów parsowanie XML; uproszczony interfejs do XML. |
XML::Parser |
Moduł Perla do parsowania dokumentów XML. |
XML::Parser::Expat |
Parser expat Jamesa Clarka umożliwiający dostęp niskiego poziomu. |
XML::Parser::PerlSAX |
Parser PerlSAX używający XML::Parser. |
XML::Parser::PyxParser |
Konwertuje ESIS nsgmls lub Pyxie na PerlSAX. |
XML::PatAct::Amsterdam |
Moduł procedur do uproszczonych arkuszy stylów. |
XML::PatAct::MatchName |
Moduł wzorców do dobierania nazw elementów. |
XML::PatAct::ToObjects |
Moduł procedur do tworzenia obiektów Perla. |
XML::PYX |
Generator XML na PYX. |
XML::QL |
Język zapytań XML. |
XML::RegExp |
Wyrażenia regularne dla nazw XML. |
XML::Registry |
Moduł Perla ładujący i zapisujący rejestry XML. |
XML::RSS |
Tworzy i aktualizuje pliki RSS. |
XML::SAX2Perl |
Przekształca metody PerlSAX na metody w stylu Java/CORBA. |
XML::Simple |
Elementarny interfejs API do czytania i zapisywania XML (szczególnie plików konfiguracyjnych). |
XML::Stream |
Tworzy połączenie XML i parsuje dane zwrotne. |
XML::Stream::Namespace |
Obiekt ułatwiający definiowanie przestrzeni nazw. |
XML::Template |
Instancja szablonu Perl XML. |
XML::Twig |
Moduł Perla przeznaczony do przetwarzania bardzo dużych dokumentów XML jako drzewek. |
XML::UM |
Przekształca napisy UTF-8 na dowolne kodowanie obsługiwane przez XML::Encoding. |
XML::Writer |
Rozszerzenie Perla przeznaczone do zapisywania dokumentów XML. |
XML::XPath |
Zestaw modułów do parsowania i interpretacji XPath. |
XML::XPath::Boolean |
Logiczne wartości prawdy i fałszu. |
XML::XPath::Builder |
Procedura obsługi zdarzeń SAX do tworzenia drzewka XPath. |
XML::XPath::Literal |
Proste wartości tekstowe. |
XML::XPathNode |
Wewnętrzna reprezentacja węzła. |
XML::XPath::NodeSet |
Lista węzłów dokumentu XML. |
XML::XPath::Number |
Proste wartości numeryczne. |
XML::XPath::PerlSAX |
Generator zdarzeń PerlSAX. |
XML::XPath::XMLParser |
Domyślna klasa parsowania XML dająca drzewo węzłów. |
XML::XQL |
Moduł Perla do zadawania zapytań dotyczących drzewiastych struktur XML za pomocą XQL. |
XML::XQL::Date |
Dodaje typ XQL::Node służący do reprezentacji i porównywania wartości daty i czasu. |
XML::XQL::DOM |
Dodaje do węzłów XML::DOM obsługę XQL. |
XML::XSLT |
Moduł Perla do przetwarzania XSLT. |
XMLNews::HTMLTemplate |
Moduł do konwersji NITF na HTML. |
XMLNews::Meta |
Moduł do odczytu i zapisu plików metadanych XMLNews. |
Większość modułów Perl z tabeli 12.2 trzeba przed użyciem ściągnąć i zainstalować (proces ten jest żmudny, choć prosty; zarówno w Windows, jak i w UNIXie istnieją narzędzia zarządzające ładowaniem i instalacją). Standardowa dystrybucja Perla zawiera wbudowaną częściową obsługę XML, na przykład moduł XML::Parser.
Oto przykład użycia modułu XML::Parser. W tym wypadku parsować będziemy dokument XML i za pomocą Perla go wydrukujemy. Moduł XML::Parser może obsłużyć wywołania zwrotne, czyli wywoływać podprocedury na początku elementu, przy treści i przy końcu elementu. Oto jak przygotowujemy takie wywołania wiążąc je z procedurami obsługi zdarzeń start_handler, char_handler oraz end_handler tworząc nowy obiekt parsera $parser:
use XML::Parser;
$parser = new XML::Parser(Handlers => {Start => \&start_handler,
End => \&end_handler,
Char => \&char_handler});
.
.
.
Teraz potrzebny jest nam dokument XML, który będziemy parsować. Użyjemy dokumentu spotkania.xml z rozdziału 5:
<?xml version="1.0" encoding="iso-8859-2"?>
<SPOTKANIA>
<SPOTKANIE TYP="nieformalne">
<PRZEWODNICZĄCY>Ted Bond</PRZEWODNICZĄCY>
<TYTUŁ>XML w praktycznych zastosowaniach</TYTUŁ>
<NUMER>2079</NUMER>
<TEMAT>XML</TEMAT>
<DATA>6/1/2002</DATA>
<OSOBY>
<OSOBA STATUS="obecny">
<IMIĘ>Edward</IMIĘ>
<NAZWISKO>Samson</NAZWISKO>
</OSOBA>
<OSOBA STATUS="nieobecny">
<IMIĘ>Ernestyna</IMIĘ>
<NAZWISKO>Johnson</NAZWISKO>
</OSOBA>
<OSOBA STATUS="obecny">
<IMIĘ>Betty</IMIĘ>
<NAZWISKO>Richardson</NAZWISKO>
</OSOBA>
</OSOBY>
</SPOTKANIE>
</SPOTKANIA>
Metoda parsefile obiektu $parser umożliwia nam parsowanie tego dokumentu:
use XML::Parser;
$parser = new XML::Parser(Handlers => {Start => \&start_handler,
End => \&end_handler,
Char => \&char_handler});
$parser->parsefile('spotkania.xml');
.
.
.
Teraz wystarczy już tylko utworzyć podprocedury start_handler, char_handler i end_handler. Zaczniemy od pierwszej z nich, która wywoływana jest przy napotkaniu początku elementu XML. Nazwa elementu zapisywana jest w pierwszej komórce standardowej tablicy Perla --> $_[Author:T] zawierającej argumenty podprocedur. Element ten wraz ze znacznikiem początkowym możemy wyświetlić następująco:
use XML::Parser;
$parser = new XML::Parser(Handlers => {Start => \&start_handler,
End => \&end_handler,
Char => \&char_handler});
$parser->parsefile('spotkania.xml');
sub start_handler
{
print "<$_[[1]>\n";
}
.
.
.
Podobnie drukujemy znacznik końcowy w podprocedurze end_handler:
use XML::Parser;
$parser = new XML::Parser(Handlers => {Start => \&start_handler,
End => \&end_handler,
Char => \&char_handler});
$parser->parsefile('spotkania.xml');
sub start_handler
{
print "<$_[[1]>\n";
}
sub end_handler
{
print "</$_[1]>\n";
}
.
.
.
Z kolei dane elementu możemy wydrukować w podprocedurze char_handler, pominiemy tylko zbędne spacje:
use XML::Parser;
$parser = new XML::Parser(Handlers => {Start => \&start_handler,
End => \&end_handler,
Char => \&char_handler});
$parser->parsefile('spotkania.xml');
sub start_handler
{
print "<$_[[1]>\n";
}
sub end_handler
{
print "</$_[1]>\n";
}
sub char_handler
{
if(index($_[1], " ") < 0 && index($_[1], "\n") < 0){
print "$_[1]\n";
}
}
Program jest już gotowy, uruchomienie takiego skryptu Perla da wynik taki, jak pokazano poniżej:
<SPOTKANIA>
<SPOTKANIE>
<PRZEWODNICZĄCY>
Ted Bond
</PRZEWODNICZĄCY>
<TYTUŁ>
XML w praktycznych zastosowaniach
</TYTUŁ>
<NUMER>
2079
</NUMER>
<TEMAT>
XML
</TEMAT>
<DATA>
6/1/2002
</DATA>
<OSOBY>
<OSOBA>
<IMIĘ>
Edward
</IMIĘ>
<NAZWISKO>
Samson
</NAZWISKO>
</OSOBA>
<OSOBA>
<IMIĘ>
Ernestyna
</IMIĘ>
<NAZWISKO>
Johnson
</NAZWISKO>
</OSOBA>
<OSOBA>
<IMIĘ>
Betty
</IMIĘ>
<NAZWISKO>
Richardson
</NAZWISKO>
</OSOBA>
</OSOBY>
</SPOTKANIE>
</SPOTKANIA>
Jak zapewne zauważyłeś, parsowanie dokumentu i definiowanie funkcji zwrotnych w Perlu bardzo przypomina to, co robiliśmy w rozdziale 9, kiedy omawialiśmy interfejs SAX.
Teraz przyjrzymy się udostępnianiu dokumentów XML przez skrypty Perla. Niestety, Perl nie zawiera tak rozbudowanego protokołu komunikacji z bazą danych jak JDBC wraz z odpowiednim ODBC lub ASP z ADO. Obsługa baz danych wbudowana w Perl oparta jest na plikach DBM, które mają strukturę --> haszowanych[Author:T] baz danych. Możesz też oczywiście zainstalować moduły Perla, które pozwalają obsługiwać wszelakie bazy danych, od ODBC po Oracle.
W naszym przypadku użyjemy skryptu Perla, który umożliwi podanie klucza (na przykład warzywo) wraz z wartością (na przykład brokuły), taka para będzie przechowywana w bazie danych w formacie NDBM domyślnie obsługiwanym przez Perla. Baza danych znajdować się będzie na serwerze. Kiedy użytkownik poda klucz na stronie, nasz program wyszuka w bazie danych odpowiednie rekordy i jeśli jakieś znajdzie, zwróci klucze wraz z ich wartościami. Jeśli na przykład wpiszesz jako klucz warzywo, jako wartość brokuły, taka para zostanie dopisana do bazy danych. Kiedy następnie wyszukiwać będziesz klucza warzywo, skrypt zwróci klucz wraz z odpowiadającą mu wartością w postaci dokumentu XML:
<?xml version="1.0" encoding="iso-8859-2"?>
<dokument>
<klucz>warzywo</klucz>
<wartość>brokuły</wartość>
</dokument>
Na rysunku 12.4 pokazano wyniki działania skryptu CGI. Aby dodać do bazy nowy rekord, wpisuje się klucz i odpowiadającą mu wartość, następnie klika przycisk Dodaj. Na rysunku 12.4 właśnie dodawana jest wartość brokuły z kluczem warzywo.
Rysunek 12.4. Perlowy skrypt CGI jako program obsługi bazy danych |
|
Aby pobrać z bazy danych wartość, wpisuje się w pole szukany klucz i klika przycisk Szukaj. Baza danych jest przeszukiwana, a wyniki w postaci dokumentu XML są odsyłane do klienta, co pokazano na rysunku 12.5. W tym wypadku wyszukiwany był klucz warzywo. Wprawdzie uzyskany dokument XML wyświetlany jest w przeglądarce, ale dość prosto jest za pomocą wtyczek internetowych (Internet sockets) Perla taki dokument obsłużyć także bez przeglądarki.
Rysunek 12.5. Dokument XML generowany przez skrypt Perl |
Rysunek został wykonany inną metodą, bezwzględnie konieczne jest usunięcie przez grafika z paska tytułu nazwy pliku i pozostawienie tam tylko po lewo napisu „Microsoft Internet Explorer”!
|
W tym skrypcie użyjemy standardowo do Perla dołączanego modułu CGI.pm. Zaczniemy od utworzenia strony sieciowej z rysunku 12.4 zawierającej między innymi potrzebne kontrolki HTML:
#!/usr/local/bin/perl
use Fcntl;
use NDBM_File;
use CGI;
$co = new CGI;
if(!$co->param()) {
print $co->header,
$co->start_html('Przykład funkcji CGI'),
$co->center($co->h1('Przykład bazy danych CGI')),
$co->hr,
$co->b("Dodanie pary klucz/wartość do bazy danych..."),
$co->start_form,
"Klucz dodawany do bazy: ",
$co->textfield(-name=>'key', -default=>'', -override=>1),
$co->br,
"Wartość dodawana do bazy danych: ",
$co->textfield(-name->'value', -default=>'', -override=>1),
$co-br,
$co->hidden(-name=>'type', -value=>'write', -override=>1),
$co->br,
$co->center(
$co->submit('Dodaj'),
$co>reset
),
$co->end_form,
$co-hr,
$co->b("Wyszukiwanie wartości w bazie danych..."),
$co->start_form,
"Szukany klucz: ", $co->textfield(-name=>'key', -default=>'', -override=>1),
$co->br,
$co->hidden(-name=>'type',-value=>'read', -override=>1),
$co->br,
$co->center(
$co->submit('Wyszukanie wartości'),
$co->reset
),
$co->end_form,
$co->hr;
print$co->end_html;
}
.
.
.
Ten skrypt CGI utworzy dwa formularze HTML: jeden do zapisywania par klucz/wartość do bazy, drugi do wyszukiwania wartości odpowiadającej kluczowi. Nie wskazaliśmy, gdzie dane z formularzy mają być przesyłane, wobec czego zostaną odesłane do tego samego skryptu. To, czy skrypt otrzymał przy wywołaniu jakieś dane do przetwarzania, możemy sprawdzić sprawdzając wartość zwróconą przez metodę CGI.pm param. Jeśli otrzymamy wartość true, jakieś dane już czekają na przetwarzanie.
Zwracany przez ten skrypt dokument jest dokumentem XML, a nie domyślnym HTML, zatem konieczne jest wskazanie tego w nagłówku HTTP, w opisie typu zawartości. Używamy metody header, jej parametrowi type przypisujemy wartość application/xml. Oto fragment kodu skryptu znajdujący się bezpośrednio za kodem dotąd napisanym:
if($co->param()) {
print $co->header(-type=>"application/xml");
print "<?xml version=\"1.0\" encoding=\"iso-8859-2\"?>";
print "<dokument>";
.
.
.
Rozdzieliliśmy dwa formularze HTML dodając dla rozróżnienia zmienną type. Jeśli zmienna ta ma wartość write, podane przez użytkownika dane mają być dopisane do bazy danych:
if($co->param()) {
print $co->header(-type=>"application/xml");
print "<?xml version=\"1.0\" encoding=\"iso-8859-2\"?>";
print "<dokument>";
if($co->param('type') eq 'write') {
tie %dbhash, "NDBM_File", "dbdata", O_RDWR|O_CREATE, 0644;
$key = $co->param('key');
$value = $co->param('value');
$dbhash{$key} = $value;
untie %dbhash;
if ($!) {
print "Wystąpil błąd: $!";
} else {
print "$key=>$value zostały zapisane w bazie danych";
}
}
.
.
.
}
W przeciwnym wypadku szukamy w bazie danych podanego klucza i zwracamy klucz wraz z wartością w postaci dokumentu XML:
if($co->param()) {
print $co->header(-type=>"application/xml");
print "<?xml version=\"1.0\" encoding=\"iso-8859-2\"?>";
print "<dokument>";
if($co->param('type') eq 'write') {
tie %dbhash, "NDBM_File", "dbdata", O_RDWR|O_CREATE, 0644;
$key = $co->param('key');
$value = $co->param('value');
$dbhash{$key} = $value;
untie %dbhash;
if ($!) {
print "Wystąpil błąd: $!";
} else {
print "$key=>$value zostały zapisane w bazie danych";
}
} else {
tie %dbhash, "NDBM_File", "dbdata", O_RDWR|O_CREAT, 0644;
$key = $co->param('key');
$value = $dbhash{$key};
$value = $dbhash{$key};
print "<klucz>";
print $key;
print "</klucz>";
print "<wartość>;
print $value;
print "</wartość>;
if ($value) {
if ($!) {
print "Wystąpił błąd: $!";
}
} else {
print "Brak wartości dla podanego klucza";
}
untie %dbhash
}
print "</dokument>";
}
W ten sposób utworzyliśmy skrypt Perl, który umożliwia zapisywanie danych w bazie i odczytywanie ich w postaci XML. Na wydruku 12.1 pokazano pełny kod programu, dbxml.cgi. Oczywiście samodzielne robienie wszystkiego jest trudnym zadaniem - jeśli zamierzasz zająć się obsługą XML w Perlu, powinieneś przyjrzeć się dokładniej licznym modułom Perla do obsługi XML udostępnionym w CPAN.
Wydruk 12.1.
dbxml.cgi
#!/usr/local/bin/perl
use Fcntl;
use NDBM_File;
use CGI;
$co = new CGI;
if(!$co->param()) {
print $co->header,
$co->start_html('Przykład funkcji CGI'),
$co->center($co->h1('Przykład bazy danych CGI')),
$co->hr,
$co->b("Dodanie pary klucz/wartość do bazy danych..."),
$co->start_form,
"Klucz dodawany do bazy: ",
$co->textfield(-name=>'key', -default=>'', -override=>1),
$co->br,
"Wartość dodawana do bazy danych: ",
$co->textfield(-name->'value', -default=>'', -override=>1),
$co-br,
$co->hiddent(-name=>'type', -value=>'write', -override=>1),
$co->br,
$co->center(
$co->submit('Dodaj'),
$co>reset
),
$co->end_form,
$co-hr,
$co->b("Wyszukiwanie wartości w bazie danych..."),
$co->start_form,
"Szukany klucz: ", $co->textfield(-name=>'key', -default=>'', -override=>1),
$co->br,
$co->hidden(-name=>'type',-value=>'read', -override=>1),
$co->br,
$co->center(
$co->submit('Wyszukanie wartości'),
$co->reset
),
$co->end_form,
$co->hr;
print$co->end_html;
}
if($co->param()) {
print $co->header(-type=>"application/xml");
print "<?xml version=\"1.0\" encoding=\"iso-8859-2\"?>";
print "<dokument>";
if($co->param('type') eq 'write') {
tie %dbhash, "NDBM_File", "dbdata", O_RDWR|O_CREATE, 0644;
$key = $co->param('key');
$value = $co->param('value');
$dbhash{$key} = $value;
untie %dbhash;
if ($!) {
print "Wystąpil błąd: $!";
} else {
print "$key=>$value zostały zapisane w bazie danych";
}
} else {
tie %dbhash, "NDBM_File", "dbdata", O_RDWR|O_CREAT, 0644;
$key = $co->param('key');
$value = $dbhash{$key};
$value = $dbhash{$key};
print "<klucz>";
print $key;
print "</klucz>";
print "<wartość>;
print $value;
print "</wartość>;
if ($value) {
if ($!) {
print "Wystąpił błąd: $!";
}
} else {
print "Brak wartości dla podanego klucza";
}
untie %dbhash
}
print "</dokument>";
}
Bezprzewodowy język znaczników
Jedną z aplikacji XML skupiających powszechną uwagę jest Bezprzewodowy język znaczników WML (Wireless Markup Language). WML i związany z nim protokół WAP przeznaczone są do obsługi przenośnych urządzeń takich jak telefony komórkowe, PDA i inne urządzenia o ograniczonych możliwościach technicznych. WML to język z mocno ograniczoną składnią, który łatwo jest w takich urządzeniach zastosować, programy ten język obsługujące w urządzeniach często nazywa się mikroprzeglądarkami.
Oto lista wybranych zasobów na temat WML:
www.wapforum.org. Doskonały adres, pod którym znajdziesz mnóstwo o WML. Pełni rolę punktu zbiorczego.
http://wap.colorline.no/wap-faq/. Niezależne FAQ (często zadawane pytania) na temat WAP, zawierają mnóstwo informacji, między innymi listę firm oferujących usługi WAP.
www.apachesoftware.com. Wszystko o Klondike, popularnej przeglądarce WML.
hotfiles.zdnet.com/cgi-bin/texis/swlib/hotfiles/info.html?fcode=0018AV. Strona, z której można „ściągnąć” Klondike.
www.apachesoftware.com/wml/wmldemo.wml. Przykłady WML Klondike.
www.wap-uk.com/Developers/Tutorial.htm. Podręcznik WML.
www.wapdesign.org.uk/tutorial.html. Inny podręcznik WML.
www.wapdesign.org.uk/server.html. Podręcznik dla usługodawców WAP.
www.wapforum.org/DTD/wml_1.1.xml. DTD WML 1.1 (bieżącej wersji). Doskonałe miejsce, w którym można rozwiać wszelkie wątpliwości odnośnie składni.
W tabeli 12.3 zestawiono elementy WML wraz z ich atrybutami.
Tabela 12.3.
Elementy WML
Element |
Realizowana funkcja |
Atrybuty |
a |
hiperłącze |
class href id title xml:lang |
access |
element dostępu |
class domain id path |
anchor |
pełni rolę zakładki |
class id title xml:lang |
b |
pogrubienie |
class id xml:lang |
big |
powiększony tekst |
class id xml:lang |
br |
koniec wiersza |
class id xml:lang |
card |
tworzy kartę |
class do id label name newcontext onenterbackward onenterforward ontimer optional ordered title type xml:lang |
em |
akcentuje tekst |
class id xml:lang |
fieldset |
zestaw pól |
class id title xml:lang |
go |
nawigacja |
accept-charset class href id method sendreferer |
head |
część nagłówkowa |
class id |
i |
kursywa |
class id xml:lang |
img |
obsługa obrazków |
align alt class height hspace id localsrc src vspace width xml:lang |
input |
pole tekstowe |
class emptyok format id maxlength name size tabindex title type value xml:lang |
meta |
zawiera metadane |
class content forua http-equiv id name scheme |
noop |
brak operacji (pomocniczy) |
class id |
onevent |
obsługa zdarzenia |
class id type |
optgroup |
tworzy grupę opcji |
class id title xml:lang |
option |
opcja |
class id onpick title value xml:lang |
p |
akapit |
align mode xml:lang class id |
postfield |
przesyła pole danych |
class id name value |
prev |
przejście do poprzedniej karty |
- |
refresh |
obsługa odświeżania |
class id |
select |
wybiera kontrolkę |
class id iname ivalue multiple name tabindex title value xml:lang |
setvar |
nadaje zmiennej wartość |
class id name value |
small |
tekst pomniejszony |
class id xml:lang |
strong |
wyróżnienie tekstu |
class id xml:lang |
table |
tworzy tabelę |
align class columns id title xml:lang |
td |
komórka danych tabeli |
class id xml:lang |
template |
szablon |
class id onenterbackward onenterforward ontimer |
timer |
tworzy zegar |
class id name value |
tr |
wiersz tabeli |
class id |
u |
podkreślenie |
class id xml:lang |
Oprócz tego WML obsługuje następujące encje znakowe:
& |
symbol & |
' |
apostrof (') |
> |
znak większości (>) |
< |
znak mniejszości (<) |
|
spacja nierozdzielająca (' ') |
" |
cudzysłów (") |
­ |
łącznik opcjonalny (-) |
W kolejnych punktach używać będziemy popularnej przeglądarki WML Apache Klondike, którą można pobrać z witryny www.apachesoftware.com. Przeglądarka ta jest dobrze opracowana i warto ją zainstalować.
Zaczynamy poznawać WML
Mikroprzeglądarki nie mają zbyt wielkich wyświetlaczy, wobec czego dokumenty WML dzieli się na karty, za każdym razem wyświetlana jest właśnie jedna taka karta. Dokument WML nazywany talią to zestaw takich kart. Talia ujęta jest w element wml, natomiast poszczególne karty w elementy card. Kiedy mikroprzeglądarka odczytuje dokument WML, od razu odczytuje całą talię mimo że na raz pokazywana jest pojedyncza karta.
Dokument WML zaczyna się deklaracją XML:
<?xml version="1.0"?>
.
.
.
W WML (podobnie jak w XHTML) używa się znacznika <!DOCTYPE> z formalnym identyfikatorem publicznym, tyle tylko, że ciałem standaryzacyjnym jest WAP Forum, a nie W3C:
<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN"
"http://www.wapforum.org/DTD/wml_1.1.xml">
.
.
.
Dokument czyli talia zaczyna się znacznikiem <wml>:
<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN"
"http://www.wapforum.org/DTD/wml_1.1.xml">
<wml>
.
.
.
</wml>
Do tworzenia poszczególnych kart w talii używa się elementu card; naszej karcie nadamy identyfikator Card1 i tytuł Pierwszy przykład WML (tytuł pokazuje się w pasku tytułowym Klondike):
<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN"
"http://www.wapforum.org/DTD/wml_1.1.xml">
<wml>
<card id="Card1" title="Pierwszy przykład WML">
.
.
.
</card>
</wml>
W dokumentach WML komentarze wstawia się tak jak w zwykłym XML:
<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN"
"http://www.wapforum.org/DTD/wml_1.1.xml">
<wml>
<card id="Card1" title="Pierwszy przykład WML">
<!-- To jest komentarz. -->
.
.
.
</card>
</wml>
Każda karta zawierać musi element p (czyli akapit), w naszym przykładzie w tym elemencie umieścimy krótkie pozdrowienie:
<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN"
"http://www.wapforum.org/DTD/wml_1.1.xml">
<wml>
<card id="Card1" title="Pierwszy przykład WML">
<!-- To jest komentarz. -->
<p>
Pozdrowienia z WML.
</p>
</card>
</wml>
I tak wygląda nasz pierwszy dokument. Na rysunku pokazano ten przykład w przeglądarce Klondike.
Rysunek 12.6. Pierwszy dokument WML |
|
Wyrównanie tekstu
Element p ma atrybut align, który jest przydatny do określania sposobu wyrównania tekstu. Atrybutowi temu można przypisać jedną z wartości left, center lub right. Istnieje też atrybut mode, którego można użyć, czy tekst ma być zawijany, czy też nie - odpowiednio wartości wrap lub nowrap. W poniższym przykładzie pokazano wyrównanie tekstu za pomocą omawianych atrybutów:
<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN"
"http://www.wapforum.org/DTD/wml_1.1.xml">
<wml>
<card id="Card1" title="Wyrównanie tekstu">
<p align="center">Wyrównanie tekstu</p>
<p align="left">Tekst wyrównany do lewej strony</p>
<p align="center">Tekst wyśrodkowany</p>
<p align="right">Tekst wyrównany do prawej strony</p>
<p mode="wrap">Nie zawijany tekst w długim wierszu...</p>
</card>
</wml>
Na rysunku 12.7 pokazano ten dokument w przeglądarce.
Rysunek 12.7. Wyrównywanie tekstu w dokumencie WML |
|
Podstawowe formatowanie tekstu
W WML obsługiwane są także niektóre elementy formatujące tekstu odziedziczone po HTML, takie jak <b> do pogrubienia, <i> do kursywy czy <u> do podkreślenia. Oto przykład ich zastosowania (pamiętaj jednak, że nie wszystkie mikroprzeglądarki obsługują te elementy):
<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN"
"http://www.wapforum.org/DTD/wml_1.1.xml">
<wml>
<card id="Card1" title="Formatowanie tekstu">
<p align="center"><b>Formatowanie tekstu</b></p>
<p>
W WML obsługiwane są następujące sposoby formatowania tekstu:
<b>pogrubienie</b>,
<big>powiększenie</big>,
<em>zaakcentowanie</em>,
<i>kursywa</i>,
<small>zmniejszenie</small>,
<strong>wyróżnienie</strong>
oraz <u>podkreślenie</u>.
</p>
</card>
</wml>
Wynik w przeglądarce pokazano na rysunku 12.8.
Rysunek 12.8. Formatowanie tekstu w WML |
|
Przyciski
W WML przyciski tworzy się za pomocą elementu do. Załóżmy na przykład, że chcemy umożliwić użytkownikowi dokumentu WML przejście na stronę www.starpowder.com/planets.wml. Zaczniemy od elementu do, przypiszemy mu atrybut type o wartości accept i dodamy etykietę za pomocą atrybutu label:
<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN"
"http://www.wapforum.org/DTD/wml_1.1.xml">
<wml>
<card id="Card1" title="Przyciski">
<p align="center"><b>Przyciski</b></p>
<do type="accept" label="Skok na nową stronę...">
.
.
.
</do>
</card>
</wml>
Do przejścia do nowego dokumentu służy element go, w którym w atrybucie href podaje się docelowy adres URI:
<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN"
"http://www.wapforum.org/DTD/wml_1.1.xml">
<wml>
<card id="Card1" title="Przyciski">
<p align="center"><b>Przyciski</b></p>
<do type="accept" label="Skok na nową stronę...">
<go href="http://www.starpowder.com/planets.wml"/>
</do>
</card>
</wml>
Na rysunku pokazano wynik naszej pracy - pojawił się przycisk. Jego kliknięcie spowoduje skok pod adres www.starpowder.com/planets.wml.
Rysunek 12.9. Wyświetlanie w dokumencie WML przycisku |
|
Jak już wcześniej wspomniano, w talii może znajdować się wiele kart, ale zawsze jest widoczna tylko jedna na raz. Jak zatem dostać się do pozostałych? Używa się do tego przycisków. W tym wypadku atrybutowi href elementu go przypisujesz identyfikator karty docelowej.
Oto przykład, gdzie mamy dwie karty i przycisk umożliwiający użytkownikowi nawigację z pierwszej karty do drugiej:
<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN"
"http://www.wapforum.org/DTD/wml_1.1.xml">
<wml>
<card id="Card1" title="Wiele kart">
<p align="center"><b>Wiele kart</b></p>
<do type="accept" label="Na drugą kartę">
<go href="#Card2"/>
</do>
</card>
<card id="Card2" title="Karta 2">
<p>
To jest karta 2.
</p>
</card>
</wml>
Wynik pokazano na rysunku 12.10. Kiedy użytkownik kliknie przycisk, przeglądarka przeskoczy na drugą kartę z talii. Tak właśnie można się poruszać między kartami w WML.
Rysunek 12.10. Wyświetlanie w dokumencie WML przycisku nawigacyjnego |
|
Jak teraz użytkownik ma się dostać z powrotem z karty 2 na kartę 1? To właśnie temat następnego punktu.
Przycisk Wstecz
W WML obsługiwany jest specjalny przycisk, który jest bardzo często wyświetlany - Wstecz. Aby taki przycisk dodać do drugiej karty, użyjemy elementu prev:
<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN"
"http://www.wapforum.org/DTD/wml_1.1.xml">
<wml>
<card id="Card1" title="Wiele kart">
<p align="center"><b>Wiele kart</b></p>
<do type="accept" label="Na drugą kartę">
<go href="#Card2"/>
</do>
</card>
<card id="Card2" title="Karta 2">
<p>
To jest karta 2.
</p>
<do type="prev" label="Wstecz">
<prev/>
</do>
</card>
</wml>
I to już wystarczy. Jak widać na rysunku 12.11, na drugiej karcie pojawił się przycisk Wstecz. Kiedy użytkownik go kliknie, przeglądarka przeskoczy na poprzednią kartę. Pamiętaj, że użytkownik używa przycisków do poruszania się między kartami talii, więc wskazane jest umieszczenie przycisku Wstecz na każdej karcie (mikroprzeglądarki zwykle nie mają wbudowanego przycisku Wstecz czy Back, który istnieje w Klondike).
Rysunek 12.11. Wyświetlanie przycisku Wstecz |
|
Hiperłącza
W WML obsługiwany jest także element a umożliwiający tworzenie hiperłączy. Tak jak w HTML, tak i tu docelowy adres podawany jest w atrybucie href. Oto przykład, w którym hiperłącze zawiedzie użytkownika do przykładu firmy Apache:
<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN"
"http://www.wapforum.org/DTD/wml_1.1.xml">
<wml>
<card id="Card1" title="Hiperłącza">
<p align="center"><b>Hiperłącza</b></p>
<p>
Chcesz zobaczyć różne przykłady WML?
Obejrzyj zatem
<a href="http://www.apachesoftware.com/wml/wmldemo.wml">
przykłady Apache
</a>.
</p>
</card>
</wml>
Na rysunku 12.12 pokazano wynik; kiedy użytkownik kliknie hiperłącze, przeglądarka przeniesie go pod wskazany adres.
Rysunek 12.12. Hiperłącze WML |
|
Tabele
Tabele w WML tworzy się za pomocą znanych z HTML elementów table, tr i td (nie istnieją natomiast th, tbody, thead ani tfoot). Zwróć uwagę, jak bardzo poniższy przykład przypomina tabelę HTML:
<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN"
"http://www.wapforum.org/DTD/wml_1.1.xml">
<wml>
<card id="Card1" title="Tabele">
<p align="center"><b>Tabele</b></p>
<p align="center">
<table columns="3">
<tr>
<td>TIC</td>
<td>TAC</td>
<td>TOE</td>
</tr>
<tr>
<td>x</td>
<td>o</td>
<td>x</td>
</tr>
<tr>
<td>o</td>
<td>x</td>
<td>o</td>
</tr>
<tr>
<td>x</td>
<td>o</td>
<td>x</td>
</tr>
</table>
</p>
</card>
</wml>
Na rysunku 12.13 pokazano wynik.
Rysunek 12.13. Tabele WML |
|
Wprowadzanie danych tekstowych
W WML obsługiwany jest także element input. Jeśli jego atrybutowi type nadasz wartość text, wyświetlone zostanie pole tekstowe, takiej jak pola znane z HTML (jednak nie wszystkie mikroprzeglądarki są w stanie ten element obsłużyć).
W poniższym przykładzie umożliwimy użytkownikowi podać nazwę pliku lokalnego w polu tekstowym. Kiedy użytkownik kliknie przycisk Skocz, przeglądarka wyświetli podany plik. Zaczniemy od utworzenia pola tekstowego:
<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN"
"http://www.wapforum.org/DTD/wml_1.1.xml">
<wml>
<card id="Card1" title="Wprowadzanie tekstu">
<p align="center"><b>Wprowadzanie tekstu</b></p>
<p>
Skocz pod adres:
<input type="text" name="uri"/>
.
.
.
</p>
</card>
</wml>
Kiedy użytkownik kliknie przycisk Skocz, będziemy musieli jakoś odczytać tekst z pola uri. Do wartości pola tekstowego można się odwołać stosując zapis $(uri):
<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN"
"http://www.wapforum.org/DTD/wml_1.1.xml">
<wml>
<card id="Card1" title="Wprowadzanie tekstu">
<p align="center"><b>Wprowadzanie tekstu</b></p>
<p>
Skocz pod adres:
<input type="text" name="uri"/>
<do type="accept" label="Skocz">
<go href="$(uri)"/>
</do>
</p>
</card>
</wml>
Na rysunku 12.14 pokazano wyniki. Kiedy użytkownik w polu tekstowym poda adres dokumentu lokalnego i kliknie przycisk Skocz, przeglądarka odczyta nazwę dokumentu i go otworzy.
Rysunek 12.14. Obsługa wprowadzania tekstu |
|
Niejako przy okazji zetknęliśmy się tu z pojęciem zmiennych WML, w tym przypadku $(uri). Możliwość bezpośredniej obsługi zmiennych czyni z WML język nie tylko znacznikowy, ale też zawierający pewne funkcje skryptowe. Istnieje też element setvar, który umożliwia przypisywanie zmiennym wartości:
<setvar name="uri" value="rys12-13.wml"/>
W następnym punkcie zajmiemy się zmiennymi dokładniej.
Listy wyboru
Tak jak w HTML, tak i w WML obsługiwany jest element select tworzący kontrolkę wyboru (działającą jak lista rozwijalna). W ramach przykładu taką kontrolkę utworzymy teraz. Kiedy po dokonaniu już wyboru użytkownik kliknie przycisk Odczyt wyboru, zostanie przeniesiony na nową kartę, która dokonany wybór pokaże.
Zaczniemy od zdefiniowania kontrolki i nadania jej nazwy selection:
<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN"
"http://www.wapforum.org/DTD/wml_1.1.xml">
<wml>
<card id="Card1" title="Wybór">
<p align="center"><b>Wybór</b></p>
<select name="selection">
.
.
.
</select>
Tak jak w HTML, poszczególne opcje podajemy stosując element option:
<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN"
"http://www.wapforum.org/DTD/wml_1.1.xml">
<wml>
<card id="Card1" title="Wybór">
<p align="center"><b>Wybór</b></p>
<select name="selection">
<option value="brokuły">Brokuły</option>
<option value="zielone fasolki">Zielone fasolki</option>
<option value="szpinak">Szpinak</option>
</select>
.
.
.
Następnie dodajemy przycisk Odczyt wyboru, którego kliknięcie spowoduje przejście do następnej karty, karty 2:
<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN"
"http://www.wapforum.org/DTD/wml_1.1.xml">
<wml>
<card id="Card1" title="Wybór">
<p align="center"><b>Wybór</b></p>
<select name="selection">
<option value="brokuły">Brokuły</option>
<option value="zielone fasolki">Zielone fasolki</option>
<option value="szpinak">Szpinak</option>
</select>
<do type="accept" label="Odczyt wyboru">
<go href="#card2"/>
</do>
.
.
.
Na karcie 2 wyświetlimy wartość kontrolki wyboru, do której odwołamy się stosując zapis $(selection). Wartość ta jest napisem z atrybutu value aktualnie wybranego elementu option. Na karcie 2 wyświetlimy dokonany wybór:
<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN"
"http://www.wapforum.org/DTD/wml_1.1.xml">
<wml>
<card id="Card1" title="Wybór">
<p align="center"><b>Wybór</b></p>
<select name="selection">
<option value="brokuły">Brokuły</option>
<option value="zielone fasolki">Zielone fasolki</option>
<option value="szpinak">Szpinak</option>
</select>
<do type="accept" label="Odczyt wyboru">
<go href="#Card2"/>
</do>
</card>
<card id="Card2" title="Karta 2">
<p>
Wybrano $(selection).
</p>
</card>
</wml>
Na rysunku 12.15 pokazano naszą talię w działaniu - wybrano Szpinak.
Rysunek 12.15. Wybieranie wartości |
|
Kliknięcie przycisku Odczyt wyboru powoduje przejście do karty 2, na której pokazywany jest wybór dokonany przez użytkownika - rysunek 12.16.
Rysunek 12.16. Informowanie o dokonanym wyborze |
|
Inną użyteczną możliwością zastosowania kontrolek wyboru jest użycie atrybutu onpick elementów option, co umożliwia przenoszenie się pod inne adresy URI kiedy tylko użytkownik wybierze jakąś opcję. Oto przykład - wystarczy ustawić wartość atrybut onpick poszczególnych elementów option na adresy URI; kiedy użytkownik wybierze jeden z nich, przeglądarka przeskoczy pod wskazany adres:
<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN"
"http://www.wapforum.org/DTD/wml_1.1.xml">
<wml>
<card id="Card1" title="Wybór">
<p align="center"><b>Wybór</b></p>
<select name="selection">
<option onpick="http://www.starpowder.com/mercury.wml">
Merkury
</option>
<option onpick="http://www.starpowder.com/venus.wml">
Wenus
</option>
<option onpick="http://www.starpowder.com/earth.wml">
Ziemia
</option>
</select>
</card>
</wml>
Użycie zegara
W WML można użyć zegara do odmierzenia zadanego czasu, a przeglądarka po upływie tego okresu automatycznie coś wykona. Jeśli na przykład atrybutowi ontimer karty przypiszemy identyfikator innej karty, to przeglądarka po upływie zadanego czasu przejdzie do karty docelowej:
<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN"
"http://www.wapforum.org/DTD/wml_1.1.xml">
<wml>
<card id="Card1" ontimer="#Card2" title="Użycie zegara">
.
.
.
</card>
.
.
.
Zegar tworzy się stosując element timer i przypisując mu okres czasu w atrybucie value (miarą jest dziesiąta część sekundy). Nasz zegar ustawimy na 10 sekund:
<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN"
"http://www.wapforum.org/DTD/wml_1.1.xml">
<wml>
<card id="Card1" ontimer="#Card2" title="Użycie zegara">
<p align="center"><b>Użycie zegara</b></p>
<timer value="100"/>
<p>
W ciągu dziesięciu sekund zostanie przeniesiony
na drugą kartę.
</p>
</card>
.
.
.
Teraz należy dodać tę drugą kartę:
<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN"
"http://www.wapforum.org/DTD/wml_1.1.xml">
<wml>
<card id="Card1" ontimer="#Card2" title="Użycie zegara">
<p align="center"><b>Użycie zegara</b></p>
<timer value="100"/>
<p>
W ciągu dziesięciu sekund zostanie przeniesiony
na drugą kartę.
</p>
</card>
<card id="Card2" title="Witaj">
<p>
Witaj na karcie 2.
</p>
</card>
</wml>
Kiedy otwierasz tę talię, wyświetlana jest karta 1, co pokazano na rysunku 12.17. Po dziesięciu sekundach przeglądarka przełącza się na kartę 2. W przeglądarce Klondike upływ czasu jest pokazywany w prawym dolnym rogu, w okienku Timer; na rysunku widać, że do przełączenia zostało jeszcze 7 sekund.
Rysunek 12.17. Użycie zegara |
|
Łączenie się z serwerem
W WML można tworzyć formularze, które są bardzo podobne w działaniu do formularzy HTML. Dane formularza WML są tak samo kodowane, można je zatem przekazać do skryptu CGI (jednak trzeba pamiętać, że nie wszystkie przeglądarki formularze obsługują).
W poniższym przykładzie prosimy użytkowników o ich komentarze, które przekazujemy do skryptu CGI o nazwie comments.cgi. Na początek tworzymy przycisk z etykietą Ładowanie danych, jego atrybut method ustawiamy na post, zaś href na adres, pod który dane mają być wysyłane, tutaj http://www.starpowder.com/comments.cgi - zupełnie jak w HTML:
<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN"
"http://www.wapforum.org/DTD/wml_1.1.xml">
<wml>
<card id="Card1" ontimer="#Card2" title="Ładowanie danych">
<p align="center"><b>Ładowanie danych</b></p>
<do type="accept" label="Ładowanie danych">
<go method="post"
href="http://www.starpowder.com/comments.cgi">
.
.
.
</go>
.
.
.
Teraz trzeba tylko wskazać ładowane dane i dane te nazwać. Używa się do tego atrybutów name i value elementu postfield. W tym wypadku ładować będziemy tekst z pola comments:
<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN"
"http://www.wapforum.org/DTD/wml_1.1.xml">
<wml>
<card id="Card1" ontimer="#Card2" title="Ładowanie danych">
<p align="center"><b>Ładowanie danych</b></p>
<do type="accept" label="Ładowanie danych">
<go method="post"
href="http://www.starpowder.com/comments.cgi">
<postfield name="comments" value="$(comments)"/>
</go>
<p>
Proszę podać swoje uwagi:
<input type="text" name="comments"/>
</p>
</card>
</wml>
To już wystarczy. Skrypt CGI może odczytać załadowane dane tak, jak odczytałby je z dokumentu HTML. Zwróć uwagę, że podczas odsyłania odpowiedzi dane należy sformatować jako WML, a w nagłówku HTTP jako typ MIME podać text/vnd.wap.wml.
Obrazki
W WML można wyświetlać obrazki, ale jest tu pewna pułapka: wszystkie te obrazki muszą być w specjalnym formacie WBMP, a ten format nie pozwala uzyskać takiej głębi kolorów, do jakiej przywykłeś. Tak naprawdę WBMP jest formatem czarno białym bez żadnej skali szarości - jeden bit na piksel.
Pod adresami z poniższej listy znajdziesz nieco informacji i programów do obsługi WBMP:
www.creationflux.com/laurent/wbmp.html. Wtyczka (plug-in) do Photoshopa Adobe pozwalająca tworzyć pliki WBMP.
www.gingco.de/wap/content/download.html. Gotowy do pobrania konwerter obrazków pozwalający uzyskać format WBMP.
www.phnet.fi/public/jiikoo/ Przydatny program do rysowania w formacie WBMP o nazwie WAPDraw.
www.teraflops.com/wbmp. Konwerter działający za pośrednictwem Internetu, umożliwia proste konwertowanie obrazków na format WBMP. Uzyskane obrazki można pobrać dowolną przeglądarką, byle nie rozumiała tego formatu, gdyż wtedy obrazek zostanie po prostu wyświetlony.
Aby wyświetlić obrazek, używa się elementu img - chyba nie jesteś zaskoczony? Ustawia się atrybuty alt, src, width i height, jak w poniższym przykładzie:
<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN"
"http://www.wapforum.org/DTD/wml_1.1.xml">
<wml>
<card id="Card1" title="Obrazki">
<p align="center"><b>Obrazki</b></p>
<p align="center">
<img alt="Obrazek WML"
src="twarz.wbmp" width="164" height="164"/>
</p>
</card>
</wml>
Na rysunku 12.18 pokazano dokument WML wraz z obrazkiem WBMP.
Rysunek 12.18. Wyświetlanie obrazka |
|
I tak oto kończymy poznawanie WML, a także XML. W trakcie czytania tej książki poznałeś naprawdę wiele tematów związanych z XML, od podstawowych jak składnia XML po zaawansowane, jak programowa obsługa dokumentów, poznałeś też różne aplikacje XML, na przykład VML czy WML. Teraz zostało Ci już tylko jedno: zaprząc tę niezwykłą technologię, aby pracowała na Twoje potrzeby --> .[Author:T]
Właściwie pole ukryte formularza. (przyp. tłum.)
Jak widać w pasku tytułu, przeglądarka ta nie zawsze dobrze sobie radzi z polskimi literami. (przyp. tłum.)
24 Część I ♦ Podstawy obsługi systemu WhizBang (Nagłówek strony)
Rozdział 1 ♦ Pierwsze kroki (Nagłówek strony)
24 C:\Moje dokumenty\Wojtek Romowicz\Książki\XML Vademecum profesjonalisty\r12-01.doc
C:\Moje dokumenty\Wojtek Romowicz\Książki\XML Vademecum profesjonalisty\r12-01.doc 1
w oryginale 20
proszę o sprawdzenie
proszę o sprawdzenie
u autora @_; wskazana konsultacja kogoś znającego Perla
proszę o kontrolę/podmianę
Ostatni akapit zmieniony - usunąłem wyliczankę tematów, gdyż w polskim wydaniu pominięte zostały niektóre istotne zagadnienia, które znalazły się w innych książkach Wydawnictwa.