background image

www.phpsolmag.org

62

PHP Solutions Nr 5/2006

Dla zaawansowanych

www.phpsolmag.org

63

PEAR

PHP Solutions Nr 5/2006

Dla zaawansowanych

XML i PHP w praktyce

Guillaume Ponçon

S

tandard  XML,  czyli  eXtensible 
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>

 

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

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...

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

•  http://www.w3.org/XML/ 

– oficjalna specyfikacja stan-

dardu XML

•  http://www.saxproject.org/ 

– strona projektu SAX

•  http://www.w3.org/DOM/ 

– oficjalna specyfikacja stan-

dardu DOM

•  http://books.evc-cit.info/

odbook/book.html – oficjalna 

specyfikacja formatu Open-

Document

Stopień trudności: ll

l

Co należy wiedzieć...

Przydatna będzie znajomość podstaw 
programowania obiektowego w PHP5.

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 
OpenOffice.org i dane programu Gant-
tproject.

background image

www.phpsolmag.org

62

PHP Solutions Nr 5/2006

Dla zaawansowanych

www.phpsolmag.org

63

PEAR

PHP Solutions Nr 5/2006

Dla zaawansowanych

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 modyfikacji 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  zdefiniujemy  najpierw  dwa 
podstawowe  uchwyty:  początku  (

startE-

lement()

) i końca (

endElement()

) każdego 

elementu  XML-owego,  uruchamiane  od-
powiednio, gdy parser natrafi 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 definiujemy 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()

.

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-

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

"

;

   

}

}

background image

www.phpsolmag.org

64

PHP Solutions Nr 5/2006

Dla zaawansowanych

równo  na  odczyt,  jak  i  zapis  (tworzenie  i 
modyfikowanie)  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  zmodyfikować  dany  wę-

zeł, musimy go najpierw odnaleźć meto-
dą 

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

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 zmodyfikujemy 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).

SimpleXML

SimpleXML  (http://www.php.net/simplexml)
to  rozszerzenie,  które  pojawiło  się  wraz 
z  PHP5.  Jest  bardzo  łatwe  w  obsłudze  i 

Rysunek 2. 

Skrypt odczytujący dokument utworzony przez program Ganttproject i wy-

świetlający jego strukturę

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.

Listing 4. 

Modyfikujemy 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

 file_get_contents

(

'/tmp/document.xml'

)

;

background image

www.phpsolmag.org

65

PHP Solutions Nr 5/2006

Dla zaawansowanych

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ą  modyfikować.  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 

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-
fikę.

Manipulujemy 

wykresami Gantta za 

pomocą SimpleXML 

oraz Ganttproject

Wykres Gantta (ang. Gantt chart) to po-
pularna metoda wizualizacji etapów i po-

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  specyfiką  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.

Rysunek 3. 

Przykład pliku tekstowego stworzonego w edytorze OpenOffice.org Writer

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 modyfikacji 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

()

;

background image

www.phpsolmag.org

66

PHP Solutions Nr 5/2006

Dla zaawansowanych

stępów  wykonania  projektu,  często  sto-
sowana  w  firmach  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ą.

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 

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ć 

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

Modyfikujemy zadanie 

utworzone w Ganttproject

Modyfikacja 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.

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  (openoffice.xml). 
Aby  dodać  nowe  zadanie,  będziemy  mu-
sieli  nadać  mu  identyfikator  będący  nu-
merem  większym  o  jeden  od  ID  ostatnio 

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>

. Identyfikatorem prze-

strzeni nazw jest słowo kluczowe znajdujące się przed dwukropkiem. Przykładowo, 
każdy znacznik zawarty w pliku Open Office content.xml o nazwie 

text:p

 (więc nale-

żący do przestrzeni nazw 

text

), odpowiada jednemu akapitowi tekstu.

Rysunek 4. 

Zawartość pliku tekstowego model.odt

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

$rss

 = simplexml_load_file

(

'

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

>

';

}

background image

www.phpsolmag.org

67

PHP Solutions Nr 5/2006

Dla zaawansowanych

zdefiniowanego  zadania.  Ponieważ  kolej-
ny  identyfikator  jest  zawsze  o  1  większy 
od  poprzedniego,  wystarczy  znaleźć  naj-
większe ID. W tym celu sporządzimy naj-
pierw listę wszystkich zadań korzystając z 
xpath,  a  następnie  odnajdziemy  najwięk-
szy  identyfikator  używając  funkcji 

max()

 

w pętli 

foreach

. Po wykonaniu tych czyn-

ności  musimy  wydłużyć  czas  trwania  za-
dania macierzystego, którym dla naszego 

nowego zadania (które umieścimy na tym 
samym  poziomie,  co 

tests

)  będzie 

Base

Teraz  dodamy  nowe  zadanie  przy  uży-
ciu metody 

addChild()

, która jest dostęp-

na dla każdego węzła drzewa dokumentu 
w  SimpleXML  oraz  nadamy  mu  atrybuty: 
indentyfikator,  nazwę,  datę  rozpoczęcia, 
okres  trwania  i  parametry  wyświetlania 
(m.in. kolor). Na koniec zapiszemy nasze 
modyfikacje  w  pliku  korzystając  z  funk-

cji  wbudowanej  PHP 

file_put_contents()

 

oraz  metody 

asXml()

  obiektu 

$project

który  reprezentuje  nasz  dokument  XML-
owy. Tak, jak w poprzednich przykładach, 
dzięki  zastosowaniu  SimpleXML  ograni-
czyliśmy  zestaw  czynności  do  niezbęd-
nych,  unikając  pisania  dodatkowego  ko-
du, które miałoby miejsce np. w przypad-
ku DOM.

Korzystamy z 

dokumentów 

OpenOffice.org za 

pomocą SAX

OpenOffice.org  to  opensourcowy  pa-
kiet  biurowy  o  ciągle  rosnącej  popular-
ności. Korzystają z niego m.in. firmy, in-
stytucje  publiczne,  organizacje  pozarzą-
dowe i osoby prywatne z całego świata. 
Wszystkie formaty dokumentów OpenOf-
fice.org  (edytora,  arkusza  kalkulacyjne-
go,  programu  do  tworzenia  prezentacji  i 
innych  są  oparte  na  XML-u.  W  wersji  2 
tego pakietu wprowadzono format Open-
Document,  którym  się  posłużymy  w  na-
szym artykule.

Kompozycja dokumentu 

OpenOffice.org

Każdy dokument OpenOffice.org to w rze-
czywistości skompresowane archiwum za-
wierające  pliki  XML.  Przykładowo,  archi-
wum  pliku  example.odt  utworzonego  w 
OO  Writer  (edytorze  tekstu)  będzie  za-
wierało  tekst  oraz  style  i  obrazy  osadzo-
ne w tekście.

Głównym  plikiem  tego  archiwum,  le-

żącym w jego katalogu głównym jest plik 
content.xml,  którego  przykładową  zawar-
tość  (fragment)  prezentujemy  na  Listingu 
13.  Zawiera  on  dane  naszego  dokumen-
tu i kilka deklaracji stylów. Zdefiniowane w 
dokumencie style tekstowe są zapisane w 
pliku styles.xml.

My  pokażemy  sposób  tworzenia  tytu-

łu i akapitu.

Odczyt i modyfikacja dokumentu 

OpenOffice.org

Zanim będziemy mogli odczytać lub zmo-
dyfikować dokument OpenOffice (test.odt), 
musimy  wydobyć  z  archiwum  plik  con-
tent.xml
 (Rysunek 3). W tym celu użyjemy 
biblioteki 

pclzip

 , którą pobierzemy spod 

adresu http://www.phpconcept.net/pclzip/.

Plik content.xml, którego fragment już 

przedstawiliśmy na Listingu 13 składa się 
ze  znacznika  korzenia 

office:document

 

oraz  pierwszego  poziomu  hierarchii  XML 

Rysunek 5. 

Dokument tekstowy OpenOffice.org Writer generowany przez skrypt napi-

sany w PHP

Listing 9. 

Zawartość dokumentu XML programu Ganttproject

<

?xml version=

"1.0"

 

encoding=

"UTF-8"

?

>

<

project name=

"OpenOfficeManager"

 

 

  

company=

"Anaska"

 

webLink=

"http://www.anaska.com"

 

(...)

>

   

<

description/

>

   

<

view zooming-state=

"default:3"

/

>

   

<

calendars

>

      

<!--  właściwości ogólne kalendarza (dni wolne, etc.) -->

   

<

/calendars

>

   

<

tasks color=

"#8cb6ce"

>

      

<

taskproperties

>

         

<!-- deklaracja typów zadań -->

      

<

/taskproperties

>

      

<

task id=

"0"

 

name=

"kernel"

 

(...) 

>

         

<

task id=

"1"

 

name=

"modelisation"

 

(...)

>

            

<

depend id=

"2"

 

type=

"2"

 

difference=

"0"

 

hardness=

"Strong"

/

>

         

<

/task

>

      

<

task id=

"2"

 

name=

"development"

 

(...)

>

         

<

depend id=

"3"

 

type=

"2"

 

difference=

"0"

 

hardness=

"Strong"

/

>

      

<

/task

>

      

<

task id=

"3"

 

(...)/

>

      

<

/task

>

   

<

/tasks

>

   

<

resources/

>

   

<

allocations/

>

   

<

vacations/

>

   

<

taskdisplaycolumns

>

      (...)
   

<

/taskdisplaycolumns

>

   

<

previous/

>

   

<

roles roleset-name=

"Default"

/

>

<

/project

>

background image

www.phpsolmag.org

68

PHP Solutions Nr 5/2006

Dla zaawansowanych

przedstawiającego  kategorie  zawartości. 
W  kategorii 

office:body

  zawarte  są  dane 

naszego dokumentu.

Odczytamy plik content.xml przy uży-

ciu SAX oraz zmodyfikujemy go korzysta-
jąc  z  SimpleXML  i  dodając  tytuł  i  akapit. 
Gotowy skrypt przedstawiamy na Listingu 
14 – składa się on z 4 części:

•   wydobycie  pliku  content.xml  zawiera-

jącego  zawartość  naszego  dokumen-
tu z archiwum,

•   odczyt  pliku  content.xml  za  pomocą 

SAX,

•   dodanie  tytułu  i  akapitu  przy  użyciu 

SimpleXML,

•   zapis pliku na dysk.

Zaczniemy  od  dołączenia  biblioteki  pcl-
zip  (pclzip.lib.php)  i  utworzenia  obiek-
tu 

$zip

  klasy 

PclZip

,  któremu  jako  pa-

rametr  konstruktora  przekazujemy  na-
zwę  archiwum,  które  chcemy  rozpako-
wać  (test.odt).  Następnie  korzystając  z 
metody 

listContent()

 tego obiektu prze-

szukamy  listę  plików  zawartych  w  archi-
wum,  aż  natrafimy  na  content.xml.  Je-
go ekstrakcji dokonamy używając metody 

extractByIndex()

 obiektu 

$zip

. Mając plik 

content.xml  poza  archiwum,  skorzystamy 
z  PHP-owej  funkcji 

file_get_contents()

aby go załadować.

Czas  na  przetwarzanie  odczytanego 

źródła  XML  przy  pomocy  SAX.  Dużą  za-
letą  tego  rozwiązania  jest  jego  szybkość 
i  prostota,  co  zdążyliśmy  już  częściowo 
poznać. Tworzymy więc parser SAX przy 
użyciu 

xml_parser_create()

 i przy pomo-

cy  funkcji  rozszerzenia  SAX 

xml_parse_

into_struct()

  przekształcimy  odczyta-

ną  zawartość  pliku  XML-owego  w  tabli-
cę.  Następnie  użyjemy  na  tej  tablicy  pę-
tli 

foreach

,  aby  wyekstrahować  z  niej  ty-

tuły i akapity.

Teraz  utworzymy  obiekt 

$xml

,  repre-

zentujący ten dokument w SimpleXML. W 
tym celu skorzystamy z funkcji 

simplexml_

load_file()

  i  załadujemy  ponownie  ten 

sam plik (content.xml).

Następnie  użyjemy  metody 

xpath()

 

obiektu 

$xml

,  aby  wydobyć  węzeł 

office:

text

, który obejmuje zawarty w pliku tekst. 

Węzeł  ten  zawiera  ciąg  deklaracji  akapi-
tów,  a  pobierzemy  go  z  pierwszego  ele-
mentu tablicy zwróconej przez 

xpath()

 (o 

indeksie 

0

).

Dodamy  teraz  nowy  tytuł  i  akapit. 

W  tym  celu  musimy  utworzyć  dwa  wę-
zły 

text:p

  potomne  wobec  węzła 

office:

text

 korzystając ze znanej już nam meto-

dy 

addChild()

. Dla każdego węzła poda-

jemy jego nazwę (

text:p

), zawartość (No-

wy tytuł i Nowy akapit) i przestrzeń nazw 
(

text

).  Po  dodaniu  obu  węzłów  dodamy 

akapitowi  atrybut 

text:style-name

,  który 

określa styl (u nas 

Standard

).

Przejdźmy  teraz  do  zapisywania  pli-

ku.  Tak  jak  poprzednio,  użyjemy  meto-
dy 

asXml()

  aby  uzyskać  tekstową  wer-

sję  dokumentu  XML,  którą  zapiszemy 
w  pliku  content.xml  przy  użyciu  funkcji 

file_put_contents()

.

Pozostała  nam  już  tylko  czwarta 

część: usunięcie starego pliku content.xml 
z  archiwum  test.odt  przy  pomocy  pclzip  i 
zastąpienie  go  zmodyfikowanym  przez 
nas  oraz  skasowanie  pliku  content.xml  z 
bieżącego  katalogu  (

unlink()

).  Oczywi-

ście, tę ostatnią funkcję musimy wywołać 

Listing 10. 

Odczyt listy zadań z dokumentu aplikacji Ganttproject

// Pobieranie pliku 

do

 przetwarzania

$file

 = 

$_SERVER

[

'argv'

][

1

]

;

// Otwieranie pliku przy użyciu SimpleXML

$xml

 = simplexml_load_file

(

$file

)

;

// Funkcja rekurencyjna odczytująca zadania

function

 display_tasks

(

&

$xml

$level

 = 0

)

 

{

   

$prefix

 = str_repeat

(

'|'

$level

)

.

'+-> '

;

   

foreach

 

(

$xml

-

>

task as 

$task

)

 

{

      

echo

 

$task

[

'start'

]

.

' '

;

      

echo

 

(

$task

[

'duration'

]

 

>

 9 

?

 

''

 : 

'0'

)

.

$task

[

'duration'

]

;

      

echo

 

' day(s) '

.

$prefix

.

" "

.utf8_decode

(

$task

[

'name'

])

.

"

\n

"

;

      display_tasks

(

$task

$level

 + 1

)

;

   

}

}

// Wywołanie funkcji rekurencyjnej display_tasks()

display_tasks

(

$xml

-

>

tasks

)

;

Listing 11. 

Zmiana nazwy pierwszego zadania w pliku programu Ganttproject 

(kernel staje się Base)

$project

 = simplexml_load_file

(

'openoffice.xml'

)

;

$project

-

>

tasks-

>

task

[

0

][

'name'

]

 = 

'Base'

;

file_put_contents

(

'openoffice.xml'

$project

-

>

asXml

())

;

Listing 12. 

Dodanie zadania w pliku programu Ganttproject za pomocą 

SimpleXML

$project

 = simplexml_load_file

(

'openoffice.xml'

)

;

// Poszukiwanie identyfikatora największego zadania

$xpath

 = 

$project

-

>

xpath

(

"//task/@id");

$maxId

 = 0;

foreach

 

(

$xpath

 as 

$item

)

 

{

   

$maxId

 = 

max

 

((

int

)

 

$item

[

'id'

]

$maxId

)

;

}

// Modyfikacja trwania zadania macierzystego

$project

-

>

tasks-

>

task

[

0

][

'duration'

]

 = 11;

// Dodanie nowego zadania

$newTask

 = 

$project

-

>

tasks-

>

task

[

0

]

-

>

addChild

(

'task'

)

;

$newTask

[

'id'

]

 = 

$maxId

 + 1;

$newTask

[

'name'

]

 = 

"preprod_tests"

;

$newTask

[

'color'

]

 = 

'#0066ff'

;

$newTask

[

'meeting'

]

 = 

'false'

;

$newTask

[

'start'

]

 = 

'2006-12-03'

;

$newTask

[

'duration'

]

 = 

'5'

;

$newTask

[

'complete'

]

 = 

'0'

;

$newTask

[

'priority'

]

 = 

'1'

;

$newTask

[

'expand'

]

 = 

'true'

;

// Zapisywanie modyfikacji

file_put_contents

(

'openoffice.xml'

$project

-

>

asXml

())

;

background image

www.phpsolmag.org

69

PHP Solutions Nr 5/2006

Dla zaawansowanych

na samym końcu, gdy już dodamy ten plik 
do archiwum.

Generujemy dokument 

OpenOffice.org Writer na 

podstawie szablonu

Utworzymy  teraz  dokument  OO  Writera 
przy  użyciu  szablonu,  czyli  istniejącego 
dokumentu, który posłuży nam jako model 
(trochę  podobnie  jak  w  przypadku  syste-
mów  szablonów  HTML-owych,  takich  jak 
np. Smarty). Będzie to wymagało wydoby-
cia  pliku  content.xml  z  archiwum  szablo-
nu (u nas będzie to model.odt) i wykorzy-
stania  go  w  celu  utworzenia  nowego  pli-
ku  content.xml,  zawierającego  dane,  któ-
re dodamy. Na koniec umieścimy ten no-
wy  plik  w  archiwum  będącym  kopią  na-
szego szablonu.

Wbudowane  do  PHP  rozszerzenie 

ZIP nie pozwala niestety na zapisanie pli-
ku:  będziemy  więc  wywoływać  programy 
zip oraz unzip korzystając z funkcji 

shell_

exec()

. Nic nie stoi również na przeszko-

dzie,  abyśmy  użyli  biblioteki  pclzip,  którą 
poznaliśmy w poprzednim przykładzie.

Naszemu  szablonowi  (Rysunek  4) 

nadamy  nazwę  model.odt,  a  następnie 
użyjemy systemu szablonów Smarty (http:/
/smarty.php.net
) w celu wygenerowania do-
kumentu ze strumienia RSS (Rysunek 5).

Nasz  przykład  (Listing  15)  jest  prze-

znaczony  dla  PHP5;  wymaga  również 
dostępu do plików  zip (używanego w ce-
lu dodania pliku do archiwum) i unzip (słu-
żącego do wydobycia pliku z archiwum) w 
systemie operacyjnym. 

Główną częścią naszego skryptu ge-

nerującego  plik  OpenOffice  Writera  na 
podstawie szablonu jest klasa 

OpenOffice

która  dziedziczy  ze 

Smarty

,  co  pozwala 

nam  używać  metod  i  atrybutów  tej  dru-
giej.  W  rzeczywistości,  klasa  OpenOffi-
ce będzie więc stanowiła API posiadają-
ce silnik szablonów do generowania do-
kumentów  OpenOffice.  Przykładowo, 
metoda 

assign()

  należy  do 

Smarty

,  zaś  

mergeAndRight()

 do 

OpenOffice

.

W  ramach  waszych  dalszych  działań 

i rozwinięć, możecie umieścić klasę Ope-
nOffice w osobnym pliku, aby móc ją do-
dać  do  innych  przetwarzań.  Korzystanie 
z tej klasy okazuje się bardzo proste, jak 
tego  dowodzą  cztery  linijki  z  Listingu  15. 
Musimy  tylko  po  prostu  instancjonować 
nowy  obiekt  podając  w  parametrze  na-
zwę pliku OpenOffice Writer, który zamie-
rzamy  stworzyć.  Następnie,  dokonujemy 
przypisań i zakańczamy przez wywołanie 

Listing 13. 

Plik content.xml obejmujący zawartość dokumentu OO Writera

<

office:document-content office:version=

"1.0"

>

<

office:scripts/

>

   

<!-- Specyficzne style dokumentu -->

   

<

office:font-face-decls

>(

...

)<

/office:font-face-decls

>

   

<

office:automatic-styles/

>

   

<!-- Zawartość dokumentu-->

   

<

office:body

>

      

<

office:text

>

         

<

text:sequence-decls

>(

...

)<

/text:sequence-decls

>

         

<

text:p text:style-name=

"Heading"

>

Tytuł

<

/text:p

>

         

<

text:p text:style-name=

"Standard"

>

Paragraf...

<

/text:p

>

      

<

/office:text

>

   

<

/office:body

>

<

/office:document-content

>

Listing 14. 

Manipulacja danymi w dokumencie OpenOffice.org Writer

include

 

"pclzip.lib.php"

;

$zip

 = 

new

 PclZip

(

'test.odt'

)

;

foreach

 

(

$zip

-

>

listContent

()

 as 

$file

)

 

{

   

if

 

(

$file

[

'filename'

]

 == 

'content.xml'

)

 

{

      

$zip

-

>

extractByIndex

(

$file

[

'index'

])

;

      

$xml_txt

 = file_get_contents

(

'content.xml'

)

;

      

break

;

   

}

}

if

 

(

!

isset

(

$xml_txt

)){

   

exit

;

}

// Parsing dokumentu przy użyciu SAX i wyświetlanie danych

$p

 = xml_parser_create

()

;

xml_parse_into_struct

(

$p

$xml_txt

$vals

$index

)

;

xml_parser_free

(

$p

)

;

foreach

 

(

$vals

 as 

$value

)

 

{

   

if

 

(

isset

(

$value

[

'value'

]))

 

{

      

switch

(

$value

[

'tag'

])

 

{

         

case

 

'TEXT:H'

 :

            

echo

 '

<

h1

>

'.utf8_decode($value['

value'

])

."

<

/h1

>

\n"; 

            

break

;

         

case

 

'TEXT:P'

 :

            

echo

 '

<

p

>

'.utf8_decode($value['

value'])."

<

/p

>

\n"; 

            

break

;

      

}

   

}

}

//  Dodanie tytułu i akapitu za pomocą SimpleXML

$xml

 = simplexml_load_file

(

'content.xml'

)

;

$contentPart

 = 

$xml

-

>

xpath

(

'/office:document-content/office:body/office:text/'

)

;

$contentPart

 = 

$contentPart

[

0

]

;

$title

 = 

$contentPart

-

>

addChild

(

'text:p'

'New title'

'text'

)

;

$title

[

'text:style-name'

]

 = 

'Heading'

;

$paragraph

 = 

$contentPart

-

>

addChild

(

'text:p'

'New paragraph...'

'text'

)

;

$paragraph

[

'text:style-name'

]

 = 

'Standard'

;

file_put_contents

(

'content.xml'

$xml

-

>

asXml

())

;

//  Zapisywanie modyfikacji

$zip

-

>

deleteByIndex

(

$file

[

'index'

])

;

$zip

-

>

add

(

'content.xml'

)

;

unlink

(

'content.xml'

)

;

background image

www.phpsolmag.org

70

PHP Solutions Nr 5/2006

Dla zaawansowanych

metody 

mergeAndWrite

 , która stworzy do-

kument, łącząc w całość dane zapisane i 
model model.odt.

Na  początku  tej  klasy  zdeklarujemy 

stałe 

ZIP_EXECUTABLE

  i 

UNZIP_EXECUTABLE

którym przypiszemy nazwy programów zip 
i unzip, co pozwala je zmienić wedle po-
trzeb  (np.  w  ramach  dostosowywania  do 
innego  niż  Linux  systemu  operacyjnego). 
Następnie zainicjujemy zmienne prywatne 

$OoFile

  i 

$OoModel

  i  przejdziemy  do  two-

rzenia  konstruktora,  w  którym  zdefiniuje-
my parametry (nasze dwie zmienne i usta-
wienia Smarty'ego). Ostatnim krokiem bu-
dowania  naszej  klasy  będzie  utworze-
nie  metody  publicznej  mergeAndWrite(), 

której  zadaniem  będzie  tworzenie  doku-
mentu,  w  którym  połączymy  dane  otrzy-
mane z pliku podanego w 

$this->OoFile

 

oraz  szablonu.  Rozpoczniemy  ją  kopiu-
jąc  archiwum  szablonu  (model.odt)  jako 
test.odt.  Następnie  wydobędziemy  z  te-
go archiwum plik content.xml i potraktuje-
my  go  jako  szablon  używając  w  tym  ce-
lu odziedziczonej po klasie 

Smarty()

 me-

tody 

fetch()

,  która  zwraca  skompilowa-

ny dokument powstający przy użyciu sza-
blonu. Otrzymany dokument przypiszemy 
do  zmiennej 

$content

,  a  następnie  zwol-

nimy  zasób  zajmowany  przez  skompilo-
waną  wersję  szablonu  używając  metody 

$this->clear_compiled_tpl()

.  Pozostało 

jeszcze  zapisać  otrzymany  dokument  ja-
ko content.xml oraz dodać ten plik do ar-
chiwum test.odt, zastępując nim poprzed-
nio istniejący.

Pobierzemy  teraz  dane  ze  strumie-

nia  RSS  (z  portalu  Yahoo!),  wykorzystu-
jąc  do  tego,  jak  poprzednio,  SimpleXML. 
Pozostało  jeszcze  utworzenie  obiektu 

$oo

 klasy 

OpenOffice

, któremu przez para-

metr konstruktora przekażemy nazwę pli-
ku  test.odt.  Następnie  korzystając  z  me-
tod  klasy  Smarty  przypiszemy  zmiennym 

news

 i 

name

 załadowanego szablonu odpo-

wiednio  treść  odczytanych  newsów  (któ-
re  przetworzymy  w  pętli 

foreach

)  oraz 

nazwisko  twórcy  dokumentu  (Guillaume 
Ponçon
).  Na  koniec  wywołamy  metodę 

mergeAndWrite()

 obiektu 

$oo

, aby zapisać 

zmieniony plik. Nasza praca z dokumenta-
mi OpenOffice.org jest zakończona.

Podsumowanie

Pokazaliśmy,  jak  łatwo  i  bezproblemo-
wo korzystać z XML-a w PHP przy użyciu 
technik SAX, DOM i SimpleXML. Ta ostat-
nia  metoda  okazała  się  szczególnie  war-
ta  uwagi,  ze  względu  na  połączenie  sze-
rokich możliwości (włącznie z wykorzysta-
niem XPath) z prostotą tworzenia oparte-
go na niej kodu. Warto pamiętać, że cza-
sami  najlepsze  może  się  okazać  połą-
czenie kilku technik, jak to ukazaliśmy na 
przykładzie  aplikacji  przetwarzającej  do-
kumenty  edytora  OpenOffice.org  Writer. 
Bądźmy  również  świadomi,  że  możliwo-
ści  pracy  skryptów  PHP  z  dokumentami 
XML-owymi nie kończą się na SAX, DOM 
i SimpleXML: istnieją i wciąż powstają no-
we  rozszerzenia  i  biblioteki,  np.  wysoko-
poziomowe API  do  łatwiejszego  przetwa-
rzania  wiadomości  RSS  czy  danych  pa-
kietu  biurowego,  czy  też  pakiety  ułatwia-
jące  tworzenie  dokumentów  XML  według 
wzorca. W każdym przypadku, dobre opa-
nowanie  obsługi  XML-a  utoruje  nam  dro-
gę  do  tworzenia  nowoczesnych  aplika-
cji, które mogą współpracować z przyjęty-
mi standardami, nie będziemy więc skaza-
ni na izolację naszych rozwiązań od resz-
ty świata. n

Guillaume  Ponçon  jest  architektem 

PHP  i  autorem  Best  practices  PHP  5,

francuskiej  książki  wydanej  nakładem 

wydawnictwa Eyrolles.

O autorze

Listing 15. 

Tworzenie pliku edytora OpenOffice.org Writer w oparciu o szablon

include

 

'smarty/Smarty.class.php'

;

class

 OpenOffice 

extends

 Smarty 

{

   const ZIP_EXECUTABLE = 

'zip'

;

   const UNZIP_EXECUTABLE = 

'unzip'

;

   private 

$vars

 = 

array

()

;

   private 

$OoFile

 = 

''

;

   private 

$OoModel

 = 

''

;

   public 

function

 __construct

(

$oo_file

$oo_model

 = 

'model.odt'

)

 

{

      

$this

-

>

OoFile = 

$oo_file

;

      

$this

-

>

OoModel = 

$oo_model

;

      

$this

-

>

left_delimiter = 

'{{'

;

      

$this

-

>

right_delimiter = 

'}}'

;

      

$this

-

>

Smarty

()

;

      

$this

-

>

template_dir = 

dirname

(

__FILE__

)

.

'/'

;

      

$this

-

>

compile_dir = 

$this

-

>

template_dir;

      

$this

-

>

config_dir = 

$this

-

>

template_dir;

      

$this

-

>

cache_dir = 

$this

-

>

template_dir;

      

$this

-

>

caching = false;

   

}

  

 //  Tworzy dokument, łącząc w całość przesłane dane i szablon

   public 

function

 mergeAndWrite

(

)

 

{

      

copy

(

$this

-

>

OoModel, 

$this

-

>

OoFile

)

;

      shell_exec

(

self::UNZIP_EXECUTABLE.

' '

.

$this

-

>

OoFile.

' content.xml'

)

;

      

$content

 = 

$this

-

>

fetch

(

'content.xml'

)

;

      

$this

-

>

clear_compiled_tpl

(

'content.xml'

)

;

      file_put_contents

(

'content.xml'

$content

)

;

      shell_exec

(

self::ZIP_EXECUTABLE.

' '

.

$this

-

>

OoFile.

' -mq content.xml'

)

;

   

}

}

//  Pobieranie danych ze strumienia RSS

$news

 = 

array

()

;

$xml_news

 = simplexml_load_file

(

'http://rss.news.yahoo.com/rss/world'

)

;

foreach

 

(

$xml_news

-

>

channel-

>

item as 

$item

)

 

{

   

$news

[]

 = 

(

string

)

 

$item

-

>

title;

}

// utworzenie i użycie obiektu OpenOffice 
// do stworzenia nowego dokumentu "test.odt".

$oo

 = 

new

 OpenOffice

(

'test.odt'

)

;

$oo

-

>

assign

(

'news'

$news

)

;

$oo

-

>

assign

(

'name'

"Guillaume Ponçon"

)

;

$oo

-

>

mergeAndWrite

()

;