2006.05_XML i PHP w praktyce _[XML].pdf

(771 KB) Pobierz
440386032 UNPDF
Dla zaawansowanych
XML i PHP w praktyce
Guillaume Ponçon
Stopień trudności: ll l
Bazy danych, dokumenty biurowe, RSS: coraz
więcej formatów gromadzenia i przesyłania
danych opiera się na XML-u. Jego główną
zaletą jest łatwość tworzenia i przetwarzania
dokumentów XML niezależnie od platformy
sprzętowej i systemowej. Jako programiści PHP,
mamy szerokie możliwości wykorzystania XML-
a przy użyciu co najmniej kilku technik...
Markup Language został określo-
ny przez World Wide Web Con-
sortium (W3C). Obecnie jest przeważnie
wykorzystywany jako format gromadze-
nia i wymiany danych (np. SXW, ODT,
RDF, RSS) oraz tworzenia specjalistycz-
nych języków opartych na znacznikach
– jest więc metajęzykiem. Każdy doku-
ment XML zawiera dane uporządkowa-
ne w hierarchii drzewiastej. Spójrzmy na
Listing 1: przedstawiamy na nim przykła-
dowy kod XML. Jego struktura opiera się
na znacznikach zawartych w nawiasach
trójkątnych (podobnie jak w przypadku
HTML-a). Para znaczników, np. <title>
i </title> określa element dokumentu
XML-owego, który może zawierać tekst
lub kolejne elementy (zwane podrzędny-
mi lub potomnymi). Składnia każdego do-
kumentu XML musi być ściśle przestrze-
gana (nie wolno np. pozostawiać niedo-
mkniętych znaczników; można też okre-
ślić inne zasady korzystając z plików
DTD czy XML Schema), gdyż w innym
wypadku program odczytujący ten doku-
ment zgłosi błąd.
Techniki przetwarzania
XML-a w PHP
Pisząc skrypty w języku PHP możemy
swobodnie korzystać z dokumentów XML-
owych. Do ich przetwarzania służą roz-
szerzenia języka PHP o nazwach: SAX,
W SIECI
Co należy wiedzieć...
Przydatna będzie znajomość podstaw
programowania obiektowego w PHP5.
http://www.w3.org/XML/
oicjalna specyikacja stan-
dardu XML
http://www.saxproject.org/
– strona projektu SAX
http://www.w3.org/DOM/
– oicjalna specyikacja stan-
dardu DOM
http://books.evc-cit.info/
odbook/book.html – oicjalna
specyikacja formatu Open-
Document
Co obiecujemy...
Przedstawimy zasady działania roz-
szerzeń języka PHP: DOM, SAX oraz
SimpleXML oraz pokażemy, jak korzy-
stając z SimpleXML tworzyć i odczyty-
wać dokumenty XML-owe, w tym pliki
OpenOfice.org i dane programu Gant-
tproject.
62
www.phpsolmag.org
PHP Solutions Nr 5/2006
S tandard XML, czyli eXtensible
440386032.011.png
 
440386032.012.png 440386032.013.png 440386032.001.png 440386032.002.png 440386032.003.png
 
Dla zaawansowanych
PEAR
DOM-XML (PHP4), DOM (PHP5) oraz
SimpleXML (tylko PHP5). Omówimy po-
krótce SAX, DOM-XML oraz SimpleXML,
podając przykłady wykorzystania każdego
z tych rozszerzeń.
SAX
SAX ( http://www.saxproject.org/ , http://
www.php.net/xml ).oznacza Simple API for
XML i umożliwia sekwencyjny odczyt do-
kumentów XML. Pozwala na odczyt prak-
tycznie każdego rodzaju dokumentów
XML, nawet tych, które zostały utworzo-
ne niepoprawnie. SAX nie umożliwia nato-
miast zapisu ani modyikacji danych.
Na Listingu 2 przedstawiamy skrypt
służący do odczytu dokumentu XML-owe-
go z użyciem techniki SAX. Zaczynamy od
utworzenia parsera ($xml_parser ), który
jest zasobem (ang. resource ) tworzonym
przy użyciu funkcji xml_parser_create() i
reprezentującym dokument XML, który bę-
dziemy przetwarzali. Do tego ostatniego w
technice SAX służą funkcje zwane handle-
rami (uchwytami), które są wywoływane
przez język PHP podczas odczytu nasze-
go dokumentu. Musimy je sami utworzyć,
zanim się do nich odwołamy. W naszym
przykładzie zdeiniujemy najpierw dwa
podstawowe uchwyty: początku ( startE-
lement() ) i końca ( endElement() ) każdego
elementu XML-owego, uruchamiane od-
powiednio, gdy parser natrai na znacznik
rozpoczynający (np. <author> ) i kończący
(np. </author> ) dany element. W przypad-
ku napotkania elementu danych pomiędzy
dwoma znacznikami XML wywoływany
jest uchwyt dataHandler . Handlery począt-
ku i końca elementu deiniujemy przy po-
mocy funkcji xml_set_element_handler() ,
a uchwyt elementu danych używając xml_
set_character_data_handler() . Przetwa-
rzanie dokumentu XML rozpoczniemy ko-
rzystając z funkcji xml_parse() , jako jej
parametry podając: instancję parsera (za-
sób $xml_parser ), źródło dokumentu w
wersji tekstowej (np. odczytane z pliku; my
użyjemy zmiennej $xml , w której umieści-
my fragment kodu z Listingu 1. Na koniec,
zwalniamy zasób $xml_parser korzystając
z funkcji xml_parser_free() .
Rysunek 1. Okno programu Ganttproject: po lewej stronie wykres Gantta
Instalacja
Aby można było uruchomić przykłady z tego artykułu, zalecane jest posiadanie PHP
5.1.4 lub nowszego. Pod systemem Windows możemy w tym celu skorzystać z ze-
stawu typu AMP (Apache, MySQL, PHP) czy też 3 w 1 o nazwie WampServer ( http:
//www.wampserver.com ). Jego instalacja jest trywialna i odbywa się przy użyciu pro-
stego wizarda.
Listing 1. Dokument XML Simple (opis książki)
< document id= "12" >
< author > Guillaume Ponçon < /author >
< title > Best practices PHP 5 < /title >
< chapter >
< title > Strumienie XML < /title >
< paragraph type= "introduction" > ... < /paragraph >
< /chapter >
< /document >
Listing 2. Przeglądamy dokument XML-owy przy użyciu SAX (wyświetlanie
znaczników i zawartości)
function startElement ( $parser , $name , $attrs ) { echo $name . " \n " ; }
function endElement ( $parser , $name ) { echo $name . " \n " ; }
function dataHandler ( $parser , $data ) { echo '-> ' . trim ( $data ) . " \n " ; }
$xml_parser = xml_parser_create () ;
$xml =' < document id= "12" >< author > Guillaume Ponçon < /author >< /document > ';
xml_set_element_handler($xml_parser, "startElement", "endElement");
xml_set_character_data_handler($xml_parser, ' dataHandler' ) ;
xml_parse ( $xml_parser , $xml , true ) ;
xml_parser_free ( $xml_parser ) ;
Listing 3. Przykład odczytu dokumentu XML przy użyciu DOMXML (wyświetlanie
informacji zawartych na Listingu 1)
$dom = new DOMDocument () ;
$dom - > LoadXML ( $xml ) ;
$title = $dom - > getElementsByTagName ( 'title' ) ;
echo "Rozdziały książki " . $title - > item ( 0 ) - > nodeValue . " : \n " ;
foreach ( $dom - > getElementsByTagName ( 'chapter' ) as $element ) {
$titles = $element - > getElementsByTagName ( 'title' ) ;
echo " \n - " . $titles - > item ( 0 ) - > nodeValue . " \n " ;
$paragraphs = $element - > getElementsByTagName ( 'paragraph' ) ;
foreach ( $paragraphs as $paragraph ) {
echo ' * ' . $paragraph - > nodeValue . " \n " ;
}
}
DOM-XML
Rozszerzenie DOM-XML umożliwia prze-
twarzanie plików XML w PHP zgodnie ze
standardem DOM (skrót od Document
Object Model ). DOM-XML pozwala za-
PHP Solutions Nr 5/2006
www.phpsolmag.org
63
 
440386032.004.png 440386032.005.png
Dla zaawansowanych
Rysunek 2. Skrypt odczytujący dokument utworzony przez program Ganttproject i wy-
świetlający jego strukturę
Należy wiedzieć, że omówiona meto-
da getElementsByTagName() odnajdu-
je wszystkie węzły określone daną parą
znaczników (np. <title>...</title>) i spo-
rządza ich listę, więc nawet, gdy istnieje
tylko jeden węzeł o wybranej nazwie (jak
u nas), musimy go wskazać (np. używa-
jąc metody item(), choć istnieją też inne
sposoby). Analogicznie wyświetlimy listę
rozdziałów (element chapter ) i akapitów
( paragraph ). Tekst zapisany w danym
węźle odczytamy i zmodyikujemy korzy-
stając z atrybutu nodeValue .
Utworznie nowego węzła nastę-
puje poprzez użycie aż dwóch metod:
createElement() , która pozwala na utwo-
rzenie obiektu węzła o określonej nazwie
(u nas category ) i zawartości (u nas PHP ),
który go reprezentuje oraz appendChild() ,
która z kolei pozwala dodać ten element w
odpowiednim miejscu drzewa węzłów. W
naszym przypadku, element ten będzie
podrzędny wobec pierwszego odnalezio-
nego elementu drzewa ( title ), niższego
o jeden poziom od korzenia drzewa (u nas
document ). Wreszcie, do zapisu gotowe-
go dokumentu XML w pliku służy metoda
save() obiektu $dom .
Jak widać, rozwiązanie DOM jest sku-
teczne i spójne logicznie, ale niestety bar-
dzo rozwlekłe i wymagające dużo kodu.
Dlatego też jest relatywnie rzadko sto-
sowane, choć zawiera bardzo pożytecz-
ne narzędzia, takie jak np. XSLT (połą-
czenie dokumentu XML i arkusza stylów
XSL) czy XPath (język zapytań umożli-
wiający wyszukiwanie elementów i warto-
ści w dokumentach XML, będący niejako
XML-owym odpowiednikiem SQL-a).
RSS – podstawy
RSS (Really Simple Syndication, znane dawniej jako Rich Site Summary czy RDF
Site Summary ) to popularny i prosty format strumienia przesyłania newsów (prze-
ważnie krótkich) w Internecie. Zestawy newsów są dostępne w postaci plików okre-
ślanych jako kanały (ang. channels ), strumienie lub feeds . Każdy news zawiera na
ogół tytuł, krótki opis, rozwinięcie i link do dłuższego artykułu. RSS opiera się na
standardzie XML. Sajty udostępniające wiadomości w postaci RSS (głównie gazety,
magazyny i portale internetowe, takiej jak Yahoo!, Slashdot ( http://rss.slashdot.org/
Slashdot/slashdot ) czy freshmeat.net ( http://rss.freshmeat.net/freshmeat/feeds/fm-re-
leases-global )) są zwykle oznaczone ikonką zawierającą skrót RSS, RDF lub XML
na stronie głównej.
Newsy RSS mogą być następnie pobierane i wyświetlane przez czytnik umiesz-
czony na komputerze klienta lub na dowolnej witrynie internetowej, takiej jak np. pry-
watna strona domowa czy blog, a także niektóre programy pocztowe (np. Thunder-
bird). Wyświetlanie zawartości kanałów RSS jest możliwe również przy użyciu prze-
glądarki internetowej: po wpisaniu adresu RSS powinna się w niej pojawić pełna
struktura i zawartość pliku XML z newsami.
równo na odczyt, jak i zapis (tworzenie i
modyikowanie) dokumentów XML. Stan-
dard DOM znajduje zastosowanie nie tyl-
ko w PHP, ale także w innych językach
(m.in. Python, Java, JavaScript). Głów-
ną ideą DOM jest to, że struktura XML
jest traktowana jako hierarchiczne drze-
wo węzłów (ang. nodes ), z których każ-
dy jest reprezentowany jako obiekt języka
PHP (lub innego języka, dla którego istnie-
je implementacja DOM). W PHP obsługę
standardu DOM umożliwiają rozszerzenia
DOM-XML (PHP4, http://www.php.net/
domxml ) i DOM (PHP5). Jak już powie-
dzieliśmy, skorzystamy z tego pierwszego.
Na Listingu 3 przedstawiamy przy-
kład odczytu, a na Listingu 4 przykład
zapisu dokumentu XML za pomocą
DOM. W obu przypadkach zaczynamy
tworząc obiekt $dom klasy DOMDocument
(musimy go utworzyć), do którego bę-
dziemy się odwoływać przy wykonywa-
niu operacji na dokumencie. Następnie
ładujemy kod XML w wersji tekstowej (ze
zmiennej łańcuchowej $xml ) korzysta-
jąc z metody LoadXML obiektu $dom . Aby
odczytać lub zmodyikować dany wę-
zeł, musimy go najpierw odnaleźć meto-
getElementsByTagName() , tworząc no-
wy obiekt (najlepiej o nazwie odpowiada-
jącej nazwie węzła). Następnie używamy
atrybutów i metod tego obiektu, umożli-
wiających odczytywanie i zapisywanie
danych w zaznaczonym węźle. My wy-
korzystamy omówioną metodę do zna-
lezienia węzła title (element pomię-
dzy znacznikami <title> i </title> ; pa-
miętajmy, że posługujemy się cały czas
przykładowym kodem XML z Listingu 1).
SimpleXML
SimpleXML ( http://www.php.net/simplexml )
to rozszerzenie, które pojawiło się wraz
z PHP5. Jest bardzo łatwe w obsłudze i
Listing 4. Modyikujemy dokument XML-owy korzystając z DOM-XML (dodanie
węzła category w dokumencie XML z Listingu 1)
$dom = new DOMDocument () ;
$dom - > LoadXML ( $xml ) ;
$title = $dom - > getElementsByTagName ( 'title' ) ;
$title - > item ( 0 ) - > nodeValue = "Best practices in PHP5" ;
$element = $dom - > createElement ( 'category' , 'PHP' ) ;
$rootElement = $dom - > getElementsByTagName ( 'document' ) ;
$rootElement - > item ( 0 ) - > appendchild ( $element ) ;
$dom - > save ( '/tmp/document.xml' ) ;
echo ile_get_contents ( '/tmp/document.xml' ) ;
64
www.phpsolmag.org
PHP Solutions Nr 5/2006
440386032.006.png 440386032.007.png
Dla zaawansowanych
Czym jest Ganttproject?
Ganttproject (Rysunek 1) jest napisanym w Javie opensourcowym programem do
sporządzania wykresów Gantta. Możemy go pobrać spod adresu http://ganttproje
ct.sourceforge.net . Zgodnie ze specyiką wykresów Gantta, Ganttproject pozwa-
la na wizualizację organizacji zadań i zasobów przydzielonych do wybranego pro-
jektu w czasie. Jedną z podstawowych funkcji programu Ganttproject jest tworze-
nie zadań, które możemy układać w kategorie. Narzędzie to pozwala nam również
na śledzenie postępu zadań, sporządzanie listy zasobów (osób pracujących nad
projektem), wyświetlanie wykresu strat oraz wykonywanie wielu innych użytecz-
nych operacji.
plik RSS, a na Listingu 8 skrypt odczy-
tujący strumień RSS spod adresu http:
//rss.freshmeat.net/freshmeat/feeds/fm-
releases-global , czyli informacje o no-
wych projektach programistycznych, któ-
re zostały zamieszczone na witrynie fre-
shmeat.net . Ładowanie zestawu wiado-
mości następuje poprzez zwykłe załado-
wanie pliku znajdującego się pod wspo-
mnianym adresem, po czym przystępu-
jemy do ich wyświetlania w oknie prze-
glądarki: zaczynamy od wypisania tytułu
kanału (element <title> , podrzędny wo-
bec <channel> ). Następnie iterujemy wia-
domości, z których każda jest elemen-
tem podrzędnym wobec <channel> ozna-
czonym jako <item> i wyświetlamy ich
elementy potomne: <description> oraz
<date> . Korzeń (root) dokumentu XML
jest oznaczony jako <rss> (czasem też
jako <RDF> ) i jest reprezentowany przez
sam obiekt $rss .
Po uruchomieniu tego skryptu zoba-
czymy zestaw wiadomości – zauważmy,
że niektóre z nich zawierają również gra-
ikę.
Rysunek 3. Przykład pliku tekstowego stworzonego w edytorze OpenOfice.org Writer
umożliwia zarówno odczyt (w PHP 5.0),
jak i zapis (w PHP 5.1.4) dokumentów
XML. Jest domyślnie skompilowane w
każdej z tych dystrybucji PHP.
Na Listingu 5 pokazujemy, jak od-
czytywać zawartość dokumentu XML,
a na Listingu 6, jak ją modyikować. W
obu przypadkach korzystanie z Simple-
XML zaczynamy od utworzenia obiek-
tu $simpleXml , do czego służy funkcja
simplexml_load_string() , która tworzy
dokument w oparciu o kod XML w po-
staci tekstowej (zawarty w zmiennej łań-
cuchowej). Podobnie, jak w przypadku
DOM, w SimpleXML struktura dokumen-
tu XML jest reprezentowana przez ze-
staw obiektów języka PHP, tyle, że są
one tworzone automatycznie i mają na-
zwy odpowiadające nazwom węzłów
(elementów) naszego dokumentu, a ko-
rzystanie z nich jest znacznie prostsze,
co możemy sami zobaczyć porównując
długość kodu w obu przypadkach: pod-
czas, gdy w DOM trzeba było tworzyć
rozwlekły skrypt, w SimpleXML wystar-
czy parę linijek! Co więcej, z elementów
dokumentu XML korzystamy przeważnie
(zarówno do odczytu, jak i zapisu) uży-
wając atrybutów (pól) obiektów poszcze-
gólnych węzłów. Pola te mogą zawierać
zarówno treść tekstową, jak i listy ele-
mentów podrzędnych, które możemy ite-
rować korzystając z instrukcji foreach .
Znacznie prostsze niż w DOM jest rów-
nież dodawanie nowych węzłów: musimy
jedynie skorzystać z metody addChild()
i gotowe.
Odczyt strumienia RSS
za pomocą SimpleXML
RSS to standard przesyłania wiadomo-
ści w Internecie, o którym więcej mówi-
my w Ramce RSS – podstawy . Na Li-
stingu 7 przedstawiamy przykładowy
Manipulujemy
wykresami Gantta za
pomocą SimpleXML
oraz Ganttproject
Wykres Gantta (ang. Gantt chart ) to po-
pularna metoda wizualizacji etapów i po-
Listing 5. Odczyt dokumentu przy wykorzystaniu SimpleXML (wyświetlanie infor-
macji zawartych na Listingu 1)
$simpleXml = simplexml_load_string ( $xml ) ;
echo '+ ' . $simpleXml - > title . " \n " ;
echo ' by ' . $simpleXml - > author. " \n\n " ;
foreach ( $simpleXml - > chapter as $chapter ){
echo '- ' . $chapter - > title . " \n " ;
foreach ( $chapter - > paragraph as $paragraph ){
echo ' -> ' . $paragraph . " \n " ;
}
echo " \n " ;
}
Listing 6. Przykład modyikacji dokumentu XML-oweog za pomocą SimpleXML
(dodanie rozdziału do dokumentu XML z Listingu 1)
$simpleXml = simplexml_load_string ( $xml ) ;
$simpleXml - > title = "Dobre wprawki w PHP 5" ;
$newChapter = $simpleXml - > addChild ( 'chapter' ) ;
$newChapter - > addChild ( 'title' , 'Programowanie obiektowe' ) ;
$newChapter - > addChild ( 'paragraph' , 'Programowanie zorientowane obiektowo jest
wspaniałe ...' ) ;
echo $simpleXml - > asXml () ;
PHP Solutions Nr 5/2006
www.phpsolmag.org
65
440386032.008.png 440386032.009.png
Dla zaawansowanych
Czym jest przestrzeń nazw?
Przestrzeń nazw umożliwia podzielenie dużych plików XML na kategorie, co uła-
twia zorientowanie się w jego zawartości i manipulowanie nią. Z użyciem przestrzeni
nazw mamy do czynienia, gdy znacznik w pliku XML-owym składa się z dwóch czę-
ści oddzielonych dwukropkiem ( : ), np. <text:p>...</text:p> . Identyikatorem prze-
strzeni nazw jest słowo kluczowe znajdujące się przed dwukropkiem. Przykładowo,
każdy znacznik zawarty w pliku Open Ofice content.xml o nazwie text:p (więc nale-
żący do przestrzeni nazw text ), odpowiada jednemu akapitowi tekstu.
kolejne zadania w hierarchii zadań. Na
Rysunku 2 przedstawiamy efekt działa-
nia naszego skryptu: wylistowaną w linii
poleceń hierarchię zadań wraz ze wspo-
mnianymi informacjami (datą początko-
wą, czasem trwania i tytułem).
Modyikujemy zadanie
utworzone w Ganttproject
Modyikacja istniejącego zadania pliku da-
nych Ganttproject z użyciem SimpleXML
jest równie prosta: jak widzimy na Listingu
11, potrzebujemy do tego zaledwie trzech
linijek kodu! W naszym przykładzie zmie-
nimy nazwę (parametr name ) pierwszego
zadania na wykresie Gantta.
Rysunek 4. Zawartość pliku tekstowego model.odt
Dodajemy zadanie
Aby dodać zadanie do wykresu Gantta,
musimy umieścić nowy element <task> w
pliku XML (Listing 12). W przypadku Sim-
pleXML służy do tego metoda addChild() ,
o której już mówiliśmy. Zaczniemy od za-
ładowania pliku XML ( openofice.xml ).
Aby dodać nowe zadanie, będziemy mu-
sieli nadać mu identyikator będący nu-
merem większym o jeden od ID ostatnio
stępów wykonania projektu, często sto-
sowana w irmach i innych organiza-
cjach. Istnieje wiele narzędzi służących
do sporządzania takich wykresów; jed-
nym z nich jest opensourcowy program
Ganttproject, o którym mówimy więcej
w Ramce Czym jest Ganttproject? . Po-
nieważ dane programu Ganttproject są
gromadzone w postaci plików XML, więc
korzystanie z nich w skryptach PHP jest
całkiem proste.
Każdemu wykresowi przypisany
jest jeden plik XML, w którym zbierane
są dotyczące go dane, takie jak np. ko-
lor przypisany do każdego zadania. Ko-
rzeniem (rootem) tego pliku jest element
o nazwie <project> . Jego atrybuty za-
wierają różne informacje, takie jak da-
ta ostatniego odczytu czy wersja pliku.
Podrzędne wobec <project> elementy
pierwszego poziomu stanowią kategorie
informacyjne: kalendarze, zadania, za-
soby, przypisanie zasobów, zwolnienia,
role i różne kategorie ustawień. Elemen-
ty drugiego i następnych poziomów za-
wierają informacje związane z każdą ka-
tegorią.
każdym z nich: datę początkową, czas
trwania i tytuł. Potrzebujemy na to około
dziesięciu linii kodu. Jak widzimy, nasz
algorytm składa się z funkcji rekurencyj-
nej, dzięki której możemy przetwarzać
Listing 7. Struktura strumienia RSS
< rss >
< channel >
< title >
Tytuł strumienia wiadomości
< /title >
(...)
< item >
< title >
Tytuł pierwszej wiadomości
< /title >
< description >
Opis pierwszej wiadomości
< /description >
(...)
< /item >
< item >
(...)
< /item >
(...)
< /channel >
< /rss >
Listing 8. Odczyt strumienia wiadomości RSS przy użyciu SimpleXML
Odczytujemy wykres Gantta z
programu Ganttproject
Aby odczytać dokument programu Gant-
tproject, napiszemy niewielki skrypt
działający w linii poleceń i korzystają-
cy z SimpleXML (Listing 10). Odczyta
on wszystkie zadania zawarte w pliku,
którego nazwę podajemy jako parametr
w linii poleceń i wyświetli informacje o
$rss = simplexml_load_ile ( ' http://rss.freshmeat.net/freshmeat/feeds/
fm-releases-global ' ) ;
echo ' < h1 > '.$rss->channel->title.' < /h1 > ';
foreach ($rss->channel->item as $item) {
echo ' < h3 > ' . $item->date . ' : ' . $item->title . ' < /h3 > ';
echo ' < p > ' . $item- > description . ' < /p > ';
}
66
www.phpsolmag.org
PHP Solutions Nr 5/2006
440386032.010.png
Zgłoś jeśli naruszono regulamin