www.phpsolmag.org
38
Projekty
PHP Solutions Nr 6/2006
XML_FastCreate
www.phpsolmag.org
39
Projekty
PHP Solutions Nr 6/2006
F
ormat XML (eXtensible Markup
Language) jest coraz częściej uży-
wany na stronach internetowych,
gdzie zawitał przede wszystkim jako
XHTML – nowy, promowany przez W3C
standard zapisu stron WWW. Innym po-
pularnym zastosowaniem XML-a są for-
maty plików pakietów biurowych, w szcze-
gólności stosowane od dawna w OpenOf-
fice.org formaty SXW czy SXC oraz nowa-
torskie i uznane za standard przez wiele
firm instytucji ODT (tekst) czy ODG (grafi-
ka). XML jest również wykorzystywany ja-
ko format eksportu i importu danych wielu
programów czy też komunikacji pomiędzy
aplikacjami znajdującymi się na różnych
maszynach (klient-serwer), np. w pro-
tokołach typu SOAP czy XML-RPC. Ję-
zyk PHP dysponuje dużymi możliwościa-
mi tworzenia i przetwarzania dokumentów
XML. W artykule pokażemy, jak użycie
PEAR-owego pakietu XML_FastCreate
(XFC) poszerza tę funkcjonalność, pozwa-
lając m.in. na wymuszanie zgodności ge-
Technologia XML podbija świat, a PHP opiera
swój sukces na wsparciu dla czołowych
rozwiązań. Zastosowanie XML_FastCreate
pozwala poszerzyć i tak bardzo zaawansowane
możliwości PHP w dziedzinie tworzenia
i manipulacji dokumentami XML...
nerowanego kodu XML z zasadami okre-
ślonymi przez DTD, informowanie użyt-
kownika o niezgodności, szybką konwer-
sję na XHTML oraz bardzo łatwe tworze-
nie rozbudowanych dokumentów, również
jeśli chcemy je składać z wielu części.
Instalacja
Jak już powiedzieliśmy, XFC jest pakietem
należącym do repozytorium PEAR (PHP
Extension and Application Repository,
XML_FastCreate
Guillaume Lecanu
W SIECI
l
http://pear.php.net/
packages/XML_FastCreate
– klasa XML_FastCreate
l
http://xmlsoft.org – strona
główna projektu libxml
l
http://pear.php.net/
packages/Cache_Lite
– pakiet PEAR::Cache_Lite
l
http://lya.fr/pear/XML_
FastCreate/tests/ – przykła-
dy użycia XML_FastCreate
Stopień trudności: ll
l
Co należy wiedzieć...
Potrzebna będzie podstawowa znajo-
mość zagadnień programowania obiekto-
wego w PHP5. Przydatna będzie również
ogólna wiedza na temat standardu XML.
Co obiecujemy...
Pokażemy, jak za pomocą XML_Fast-
Create utworzyć prawidłowy kod XML.
Zademonstrujemy też, jak dokonywać
transformacji znaczników XML-a, wy-
muszać sprawdzanie DTD, wykrywać
błędy składni czy tworzyć dokumenty
w XHTML-u.
www.phpsolmag.org
38
Projekty
PHP Solutions Nr 6/2006
XML_FastCreate
www.phpsolmag.org
39
Projekty
PHP Solutions Nr 6/2006
http://pear.php.net). Aby go zainstalować,
wystarczy w linii poleceń systemu ope-
racyjnego użyć narzędzia pear. Jeżeli
takowego nie posiadamy, jego instalacja
jest bardzo prosta i została szczegółowo
opisana na stronach PEAR-a.
Mając narzędzie pear jesteśmy gotowi
do instalacji XFC. W tym celu wystarczy
wpisać
pear install XML_FastCreate
.
Pamiętajmy, że instalacja niektórych pa-
kietów opcjonalnych XML_FastCreate,
które są w wersji beta lub alpha, może
wymagać użycia dodatkowego parametru
narzędzia pear. Przykładowo, dla wersji
beta będzie to:
pear -d preferred_state=beta
install nazwa_pakietu
Jeżeli ta składnia nie działa (co ma
miejsce w przypadku starszych wersji
narzędzia pear), to musimy sprawdzić na
stronie pakietu, w jakiej fazie znajduje się
jego najnowsza wersja (stable, alpha lub
beta) i uwzględnić tę fazę, jeśli jest różna
od stable, w sposób następujący:
pear install nazwa_pakietu-faza
np.:
pear install XML_Tree-beta
Wśród pakietów opcjonalnych współ-
pracujących z XFC można wymienić np.
XML_Tree, XML_DTD, XML_Beautifier
czy XML_HTMLSax. Ich użycie jest zale-
cane w celu pełnego wykorzystania możli-
wości XML_FastCreate.
XFC: pierwsze kroki
Aby skorzystać z XML_FastCreate, do-
łączamy plik XML/FastCreate.php (zob.
Listing 1) i tworzymy obiekt
$x
, będący
instancją klasy
XML_FastCreate
(uwaga:
używamy w tym celu należącej do kla-
sy
XML_FastCreate
metody statycznej
factory()
). Zainicjowanie $x wymaga po-
dania dwóch parametrów: pierwszy z nich
określa format wygenerowanego XML-a.
My używamy formatu
Text
, co oznacza,
że po użyciu metody toXML() (którą omó-
wimy później) uzyskamy XML w formie
tekstu (zserializowanej). Drugi parametr
stanowi tablicę asocjacyjną opcji, którą
również omówimy później.
Wspomnijmy, że jedną z najistotniej-
szych spośród tych opcji jest właściwy na-
główek
doctype
, który zostanie następnie
umieszczony w pierwszej linii pliku XML
i będzie określał DTD, na którym oparto
dokument. Nagłówek ten możemy zdefi-
niować ręcznie, ale XML_FastCreate daje
nam do wyboru kilka gotowych definicji
odpowiadających najczęściej używanym
doctype
. My użyjemy:
XML_FASTCREATE_DOCTYPE_
XHTML_1_0_STRICT
co w rezultacie daje nagłówek:
XHTML 1.0 Strict.
Stwórzmy teraz najprostszy dokument
XML, który będzie stroną XHTML-ową
zawierającą napis Hello World! w akapicie
(
<p>
..
</p>
) oraz tekst XML_FastCreate ja-
ko tytuł (tag
<title>
..
</title>
) i korzysta-
jącą z innych tagów typowych dla HTML-a
i XHTML-a (
<html>
,
<head>
i
<body>
).
Patrząc na kod z Listingu 2 zauważymy,
że wykorzystane tam metody (oprócz
toXML()
) obiektu
$x
mają takie same
nazwy, jak użyte przez nas tagi XHTML-
a. Wstawienie każdej z tych metod do
skryptu powoduje automatyczne utworze-
nie znacznika o takiej samej nazwie. Jest
to wielką zaletą XML_FastCreate, która
ułatwia tworzenie nawet rozbudowanych
dokumentów.
Zwróćmy też uwagę na zagnieżdżenie
metod reprezentujących znaczniki: zaczy-
namy od metody:
$x->html()
której parametrem jest:
$x->head()
która z kolei zawiera wywołania
head()
i
body()
. W ten sposób tworzymy strukturę
znaczników w XML_FastCreate, która po
użyciu metody
toXML()
zostanie przekształ-
cona na gotowy dokument XML (zob. Listing
3). UWAGA: toXML() jedynie wypisuje XML
na ekran; aby zapisać dokument w zmien-
nej, trzeba użyć metody getXML(), np.:
$xml_out=$x->getXML();
W tym przykładzie nie określiliśmy atrybutów
znaczników. Aby je dodać do określonego
znacznika, wystarczy umieścić je w tablicy
asocjacyjnej przekazanej jako pierwszy ar-
gument metody reprezentującej ten znacz-
nik. Przykładowo, aby utworzyć link (tag
<a
href>
...
</a>
) prowadzący do strony głównej
repozytorium PEAR, wpisujemy:
$x->a(array(‘href’=>’http://
pear.php.net’),’P.E.A.R.’)
Efektem będzie:
<a_href=”http://pear.php.net”>
P.E.A.R.</a>
Listing 1.
Tworzenie instancji XML_FastCreate
<?
php
require_once
'XML/FastCreate.php'
;
$x
=&XML_FastCreate::factory
(
'Text'
,
array
(
'doctype'
=
>
XML_FASTCREATE_DOCTYPE_XHTML_1_0_STRICT
)
)
;
?>
Listing 2.
Hello World! w XML-u przy użyciu XML_FastCreate
$x
-
>
html
(
$x
-
>
head
(
$x
-
>
title
(
'XML_FastCreate'
))
,
$x
-
>
body
(
$x
-
>
p
(
'Hello World !'
))
)
;
$x
-
>
toXML
()
;
Rysunek 1.
Przykład błędu polegające-
go na niezgodności XML-a z jego DTD
XML_FastCreate
www.phpsolmag.org
40
Projekty
PHP Solutions Nr 6/2006
Już na podstawie tych przykładów może-
my się przekonać, jak łatwe i szybkie jest
tworzenie XML-a przy użyciu XML_Fast-
Create.
Wymuszanie
i weryfikacja
zgodności z DTD
Tworząc lub modyfikując dowolny doku-
ment XML powinniśmy się upewnić, czy
będzie on zgodny ze standardem DTD,
do czego często używamy dodatkowych
narzędzi. Użycie XML_FastCreate pozwa-
la nam zaoszczędzić czas dzięki funkcji
automatycznego wyświetlania błędów
składni XML-a.
Aby wymusić sprawdzanie DTD, mu-
simy mieć odpowiedni plik zawierający de-
finicje DTD (niektóre z nich, np. XHTML,
znajdują się w katalogu dtd zainstalowane-
go XML_FastCreate) i uruchomić jego ła-
dowanie podczas tworzenia instancji klasy
XML_FastCreate
. To drugie wykonamy do-
dając opcję
dtd
do wspomnianej wcześniej
tablicy asocjacyjnej (Listing 4). My załadu-
jemy plik xhtml_1_0_strict.dtd, będący defi-
nicją standardu XHTML 1.0 w wersji strict.
Jeżeli w składni XML-a wystąpi nie-
zgodność z DTD, komunikat o błędzie
zostanie wyświetlony podczas wywołania
wspomnianej już metody
toXML()
. Po-
zwala to np. na wyświetlenie go na końcu
strony WWW.
Na Listingu 5 podajemy przykład skryp-
tu generującego stronę XHTML-ową, w któ-
rej celowo wstawiliśmy błąd polegający na
pominięciu atrybutu
alt
w znaczniku
<img
src>
(co było dopuszczalne w HTML-u, ale
jest zabronione w XHTML-u). Po utworze-
niu strony, konwertujemy ją do postaci do-
kumentu XML jako zmienną
$err
. Następ-
nie korzystając z metody statycznej
PEAR:
:isError()
sprawdzamy, czy zmienna ta
zawiera komunikat o błędzie: jeżeli tak, to
go wypisujemy przy pomocy metody
$err-
>getMessage()
. Przykład wykonania tego
skryptu przedstawiamy na Rysunku 1.
Manipulacja
dokumentami XML
Przejdźmy teraz do omówienia rozmaitych
metod generowania i manipulacji doku-
mentami XML.
Jak już wiemy, użycie argumentu
Text
podczas tworzenia instancji klasy
XML_FastCreate powoduje, że skutkiem
użycia metody
toXML()
będzie wygenero-
wanie XML-a w formie tekstowej (zseriali-
zowanej). Gdybyśmy zamiast
Text
podali
XML_Tree
, utworzony zostałby obiekt klasy
XML_Tree
, która jest dostępna jako osobny
pakiet PEAR-owy.
Co więcej, możemy złożyć dokument
XML z kilku mniejszych bloków, co się
często przydaje, np. gdy generujemy jego
elementy korzystając z pętli czy instrukcji
warunkowych. Jest to wręcz zalecane,
gdyż umożliwia zachowanie przejrzysto-
ści – zarówno kodu aplikacji generującej
XML, jak i samego XML-a.
Bez ograniczeń możemy łączyć blo-
ki wygenerowane z użyciem parametru
Text
podczas tworzenia instancji doku-
mentu. Nie będzie również problemu, je-
żeli format jest inny (np.
XML_Tree
), o ile
wszystkie bloki są tego samego formatu.
Spójrzmy na Listing 6: łączymy na nim
dwa bloki typu
Text
, wygenerowane przy
użyciu utworzonej wcześniej instancji
$x
klasy
XML_FastCreate
(nie musimy po-
dawać żadnych parametrów oprócz ty-
pu XML-a).
Transformacje XML
XFC posiada opcję szybkiej transforma-
cji, której zadaniem jest zamiana wy-
branych znaczników na inne. Przykła-
Listing 3.
Rezultat XHTML przykładu z Listingu 2
<
?xml version=
"1.0"
encoding=
"UTF-8"
standalone=
"no"
?
>
<
!DOCTYPE html PUBLIC
"-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/
xhtml1/DTD/xhtml1-strict.dtd"
>
<
html
><
head
><
title
>
XML_FastCreate
<
/title
><
/head
>
<
body
><
p
>
Hello World !
<
/p
><
/body
><
/html
>
Listing 4.
Tworzymy instancję XML_FastCreate sprawdzającą zgodność XML
z jego DTD
$x
=& XML_FastCreate::factory
(
'Text'
,
array
(
'doctype'
=
>
XML_FASTCREATE_DOCTYPE_XHTML_1_0_STRICT,
'dtd'
=
>
'xhtml_1_0_strict.dtd'
)
)
;
Listing 5.
Sprawdzamy zgodność XML z jego DTD
<?
php
require_once
'XML/FastCreate.php'
;
$x
=& XML_FastCreate::factory
(
'Text'
,
array
(
'doctype'
=
>
XML_FASTCREATE_DOCTYPE_XHTML_1_0_STRICT,
'dtd'
=
>
'xhtml_1_0_strict.dtd'
)
)
;
$x
-
>
html
(
$x
-
>
head
(
$x
-
>
title
(
'XML_FastCreate'
))
,
$x
-
>
body
(
$x
-
>
p
(
$x
-
>
img
(
array
(
'src'
=
>
'soleil.png'
))
)
)
)
;
if
(
PEAR::isError
(
$err
=
$x
-
>
toXML
()))
{
echo
nl2br
(
htmlSpecialChars
(
$err
-
>
getMessage
()))
;
}
?>
Listing 6.
Przykład konkatenacji (łączenia) dwóch tagów
$hello
=
$x
-
>
p
(
'Hello'
)
;
$world
=
$x
-
>
p
(
'World'
)
;
$body
=
$x
-
>
body
(
$hello
,
$world
,
)
;
$x
-
>
html
(
$x
->
head
(
$x
-
>
title
(
'XML_FastCreate'
))
,
$body
)
;
Rysunek 2.
Entytki umożliwiające zako-
dowanie znaków specjalnych w doku-
mentach XML
XML_FastCreate
www.phpsolmag.org
42
Projekty
PHP Solutions Nr 6/2006
dowo, możemy w ten sposób uprościć
sobie składnię XML-a czy XHTML-a,
oznaczając tagi po swojemu, w spo-
sób dostosowany do naszych prefe-
rencji czy potrzeb programu, który z
tych danych korzysta. Transformacja z
XFC przyda się również przy konwersji
z XML-a na HTML-a. Spójrzmy na Li-
sting 7: przy tworzeniu instancji klasy
Listing 7.
Przykład zastosowania opcji ‘translate’
<?
php
require_once
'XML/FastCreate.php'
;
$x
=& XML_FastCreate::factory
(
'Text'
,
array
(
'doctype'
=
>
XML_FASTCREATE_DOCTYPE_XHTML_1_0_STRICT,
'dtd'
=
>
'xhtml_1_0_strict.dtd'
,
'translate'
=
>
array
(
'news'
=
>
array
(
'div'
)
,
'desc'
=
>
array
(
'p'
)
,
'title'
=
>
array
(
'
<
h1 class=
"title"
><
span
>
', '
<
/span
><
/h1
>
'
)
,
'date'
=>
array
(
'
<
span class
=
"date"
>
'
,
'
<
/span
>
'
)
)
)
)
;
$x
->
html
(
$x
->head
(
$x
->
_title
(
'XML_FastCreate'
))
,
$x
->
body
(
$x
->
news
(
$x
->
title
(
'News'
)
,
$x
->
date
(
'10-12-2005'
)
,
$x
->
desc
(
'blah blah blah'
)
)
)
)
;
if
(
PEAR::isError
(
$err
=
$x
->
toXML
()))
{
echo
nl2br
(
htmlSpecialChars
(
$err
->
getMessage
()))
;
}
?>
Listing 8.
Wariant cytowany w Listing 7 bez opcji ‘translate’
$x
-
>
div
(
$x
-
>
h1
(
array
(
'class'
=
>
'title'
)
,
$x
-
>
span
(
'News'
))
,
$x
-
>
span
(
array
(
'class'
=
>
'date'
)
,
'10-12-2005'
)
,
$x
-
>
p
(
'blah blah blah'
)
)
;
Listing 9.
Przykład zastosowania metody cdata()
$x
-
>
style
(
array
(
'type'
=>
'text/css'
,
'media'
=>
'all'
)
,
$x
-
>
cdata
(
"@import url
(
'example.css'
)
;
"
)
)
;
Listing 10.
Tworzymy instancję XML_FastCreate sprawdzającą zgodność XML
z jego DTD poprzez program zewnętrzny
$x
=& XML_FastCreate::factory
(
'Text'
,
array
(
'doctype'
=
>
XML_FASTCREATE_DOCTYPE_XHTML_1_0_STRICT,
'dtd'
=
>
'xhtml_1_0_strict.dtd'
,
'file'
=
>
'/tmp/XFC.xml'
,
'exec'
=
>
'xmllint --valid --noout /tmp/XFC.xml 2>&1'
,
)
)
;
XML_FastCreate
w tablicy asocjacyjnej
wpisujemy opcję
translate
, która z ko-
lei otwiera tablicę znaczników do tłuma-
czenia.Mamy tam tagi opisujące notkę
informacyjną (
<news>
,
<desc>
,
<title>
i
<date>
), które będą zamienione na
oryginalne znaczniki XML-a. Zwróć-
my szczególną uwagę na znacznik
<title>
: zostanie on przekonwertowany
na cały zestaw tagów (
<h1><span>...</
span></h1>
).
Gdybyśmy nie korzystali z XFC w ce-
lu ułatwienia konwersji znaczników, aby
osiągnąć ten sam efekt co na Listingu 7
musielibyśmy ręcznie wstawić wartości do
odpowiednich tagów XML-a, jak na Listin-
gu 8. Wracając do Listingu 7 zauważmy,
że po zdefiniowaniu tablicy transformacji
tworzymy kod XML metodą tradycyjną.
Tam również wystąpi znacznik
<title>
,
tyle że nie jest on tytułem naszej wiado-
mości, lecz standardowym tagiem
<title>
oznaczającym tytuł strony WWW i znanym
z HTML-a oraz XHTML-a. Aby uniknąć je-
go konwersji (która nastąpiłaby zgodnie
z regułami przetwarzania znaczników
naszych wiadomości), poprzedzamy jego
nazwę podkreśleniem (
_title
). Dzięki
temu generowany będzie standardowy
znacznik
<title>
..
</title>
.
Opcje i metody XFC
XFC zawiera kilka dodatkowych, przydat-
nych metod:
comment()
– pozwala na dodawanie
komentarzy w kodzie XML; ogranicz-
nikami komentarza są oczywiście tagi
<!--
i
-->
. Przykładowo, następujące
użycie tej metody:
$x->comment($x->p(‘Hello
World
!’))
spowoduje wygenerowanie kodu:
<!-- Hello World! -->
.
cdata()
–otacza wybraną zawartość
znacznikami
CDATA
. Jest to niezbędne,
kiedy musimy wprowadzić zawar-
tość, która niekoniecznie jest zgodna
z DTD, np. kod typu JavaScript czy
jakiś rodzaj importu stylów w ramach
strony XHTML. Bez
CDATA
zwyczajnie
nie da się umieścić takiej zawartości
w dokumencie XML. Przykład użycia
cdata()
przedstawiamy na Listingu 9.
quote()
– metody tej używamy, aby
przekonwertować wybrane znaki na
entytki (ang. entities). Jest to koniecz-
ne, gdyż umieszczenie pewnych zna-
ków (np.
&
) w dokumentach XML jest
niemożliwe i wygeneruje błąd. Metody
quote()
możemy używać w sposób
zautomatyzowany, jeżeli zadeklaruje-
my ją podczas definiowania obiektu
klasy XML_FastCreate jako
true
.
W takiej sytuacji, jeśli nie chcemy
używać tej opcji wobec określonych
części dokumentu, możemy wywołać
opcję
noquote()
(Rysunek 2). UWA-
XML_FastCreate
Projekty
GA: jeżeli tworzymy dokument
XHTML, wyszukiwarka Microsoft In-
ternet Explorer (wersja 6 i niższe) nie
rozpoznaje encji
&apos
;. Aby uniknąć
jej konwersji, musimy umieścić opcję
apos
w
false
.
Należy też pamiętać o tym, że:
Kod XML jest generowany bez for-
matowania. Oznacza to, że wszystkie
znaczniki są wklejane i zagnieżdżane
bez przechodzenia do nowej linii czy
stosowania tabulacji. Jeżeli chcemy
uczynić kod XML bardziej czytelnym,
dodajmy opcję
indent
do
true
. Takie
formatowanie może jednak sprawić,
że dokumenty XML będą niezgodne
z DTD.
Niektóre nowe DTD, jak na przykład
XHTML 1.1, bazujące na kilku kar-
totekach, jeszcze nie są tolerowane.
Mimo to, za pomocą opcji
file
może-
my wydać XFC polecenie utworzenia
pliku tymczasowego i wykonania pro-
gramu zewnętrznego za pomocą opcji
exec
, przeznaczonej do takiej analizy.
Program xmllint doskonale sobie radzi
z takimi problemami, a przykład jego
użycia w ramach naszej aplikacji pre-
zentujemy na Listingu 10.
XFC ma kilka własnych, wbudowa-
nych metod, co przy specyficznym
sposobie traktowania znaczników (me-
toda ma taką samą nazwę, jak znacz-
nik, do którego się odnosi) powoduje
problemy, jeżeli chcemy zdefiniować
znaczniki o nazwach pokrywających
się z nazwami tych metod. Aby unik-
nąć tego problemu i zmusić XFC do
traktowania metody jako odnoszącej
się do znacznika, przed nazwą tagu
wstawiamy znak podkreślenia, np.
_quote()
.
Wygoda
użytkowania XFC
Aby uprościć tworzenie projektu korzy-
stającego z XML_FastCreate, zalecane
jest, aby inicjowanie instancji tej klasy
odbywało się w pliku, który będziemy do-
łączać do każdej ze stron. Inną opcją jest
generowanie tego obiektu wewnątrz funk-
cji, która będzie wywoływana na końcu
każdej strony.
Pamiętajmy też, że generowanie
XML-a zajmuje czas, przez co korzystanie
z XML_FastCreate będzie wolniejsze, niż
używanie gotowych, zapisanych na dysku
(czy w bazie danych) dokumentów XML.
Aby przyspieszyć dostęp do nich (tylko
w przypadku plików), możemy użyć narzę-
dzia keszującego, np. PEAR::Cache_Lite.
Konwersja
dokumentów HTML
Konwersję dokumentu HTML na XML uła-
twi załączony w pakiecie XML_FastCreate
skrypt HTML2XFC.php. Za jego pomo-
cą możemy przekształcić cały plik (skrypt
wywołujemy wtedy w linii poleceń) albo
wybrany fragment – uruchamiamy wte-
dy HTML2XFC.php jako makro w wybra-
nym edytorze programistycznym. W przy-
Guillaume Lecanu jest autorem pakie-
tu programów XML FastCreate, rozwija-
nego od przeszło 12 lat. Jego pasja pro-
gramowania zaczęła się od asemblera,
którego nauczył go na domowym kom-
puterze brat, twórca programów typu de-
mo. Niedawno Lecanu stworzył własną
firmę Noovea, która prezentuje pełnię je-
go możliwości.
Kontakt z autorem:
guillaume@lya.fr
O autorze
padku edytora vim wystarczy umieścić
w ~/.vimrc linię:
map ,fc :!HTML2XFC.php<CR>
wybrać do konwersji kod HTML i urucho-
mić makro wpisując
,fc
.
Podsumowanie
W tym artykule pokazaliśmy najciekaw-
sze spośród podstawowych zastosowań
XML_FastCreate. Jak widzimy, użycie tej
biblioteki znacznie upraszcza tworzenie,
manipulację i konwersję dokumentów
XML. Nie bez znaczenia jest również to,
że należy ona do repozytorium PEAR,
do którego trafiają wyłącznie sprawdzone
i działające projekty. Wraz z dodatkami ty-
pu XML_Tree, XML_FastCreate powinna
zająć miejsce wśród niezbędnych narzę-
dzi każdego programisty, który korzysta
z XML-a.
n
R
E
K
L
A
M
A