JustPaste.it

SimpleXML nadchodzi!

Oto rewolucja w dziedzinie przetwarzania XML'a za pomocą PHP. Nowy moduł wersji 5 - SimpleXML uczynił to zadanie tak prostym, jak nigdy dotąd!

Oto rewolucja w dziedzinie przetwarzania XML'a za pomocą PHP. Nowy moduł wersji 5 - SimpleXML uczynił to zadanie tak prostym, jak nigdy dotąd! Naucz się go wykorzystywać, korzystając z tego artykułu!

Możliwe, że korzystałeś z dotychczasowego parsera XML'a dostarczanego razem z PHP 4 i prawdopodobnie zwróciłeś uwagę na jego wprost niewiarygodną toporność. Owszem, była alternatywa w postaci modelu DOM (Document Object Model), lecz jest to prawdziwy kombajn, tak skomplikowany, że niezdatny do wielu zastosowań. Na szczęście w PHP 5 to wszystko się zmieni, a to za sprawą modułu SimpleXML czyniącego zadanie tak prostym, jak nigdy dotąd!

SimpleXML działa trochę inaczej, niż dwa pozostałe parsery. Poprzez wywołanie jednej funkcji otrzymujesz drzewko obiektów i tablic. Każdy element drzewa daje Ci dostęp do tablicy swoich "potomków", tablicy asocjacyjnej z atrybutami, oraz do przechowywanego przez siebie tekstu. I to jest esencja zarówno prostoty tego rozwiązania, gdyż całą resztę robisz przy użyciu najzwyklejszych w świecie pętli! To jednak nie wszystko - jeśli jesteś trochę bardziej wymagający, możesz skorzystać z takich kwiatków, jak XPath, czy konwersji drzewa z powrotem do postaci XML'a. A więc co? Zaczynamy?

Przy pisaniu tego artykułu założyłem, że wiesz:

  • Czym jest programowanie obiektowe.
  • Jak ono działa w PHP 5.
  • Jak działa pętla foreach()
  • Czym jest referencja
  • Jak zbudowane są pliki XML

Dlatego tych spraw nie będę tu omawiał.

Instalacja

Moduł ten jest dostępny wyłącznie w PHP 5, gdyż wymaga do działania nowości wprowadzonych w Zend Engine 2. Jedyne, co musisz zrobić, aby go mieć, to zainstalować PHP 5. Żadne dodatkowe dyrektywy, modyfikacje php.ini i temu podobne nie są wymagane.

Przetwarzanie pliku XML

Zanim zaczniemy całą zabawę, musimy mieć pod ręką jakiś plik XML, na którym będziemy eksperymentować. Abyś nie musiał go sam wymyślać, możesz posłużyć się czymś takim:

<?xml version="1.0" encoding="iso-8859-2"?>
<klienci>
<klient>
<nazwa>Klopex Sp. z z.o.o.</nazwa>
<adres>Uliczna 123 00-000 Wysoko</adres>
<zamowienie>
<produkt sztuk="3">Jednostronna szyba</produkt>
<produkt sztuk="1">Rakieta balistyczna</produkt>
</zamowienie>
</klient>
<klient>
<nazwa>Rzad Iranski</nazwa>
<adres>Al-khaidy 11/9, Teheran</adres>
<zamowienie>
<produkt sztuk="10000">Karabin jednorazowego uzytku</produkt>
<produkt sztuk="500">Czolg na korbe</produkt>
<produkt sztuk="5">Rakieta balistyczna</produkt>
</zamowienie>
</klient>
</klienci>

Jest to prosta lista klientów pewnej firmy. Załóżmy, że chcemy ją zaprezentować w postaci HTML tak, by mogła być przejrzana w zwykłej przeglądarce. Jak to zrobić? Na przykład tak:

<?php
echo 'Charakterystyka klientów: <br/>';
 
$klienci = simplexml_load_file('plix.xml');
 
foreach($klienci -> klient as $klient){
echo 'Nazwa klienta: '.$klient -> nazwa.'; Adres: '.$klient -> adres.'<br/>';
echo 'Szczegóły zamówienia: <br/>';
foreach($klient -> zamowienie -> produkt as $produkt){
echo '&nbsp;&nbsp;&nbsp;&nbsp;'.$produkt['sztuk'].' sztuk produktu o nazwie "'.$produkt.'"<br/>';
}
echo '<hr/>';
}
?>

Do utworzenia drzewa służy funkcja simplexml_load_file(). Zwraca ona referencję do obiektu reprezentującego główny element pliku XML, czyli w naszym przypadku <klienci>. Jest on korzeniem naszego drzewa i teraz zamierzam wyjaśnić, jak jest ono zbudowane.

Każdy znacznik naszego pliku XML jest reprezentowany przez obiekt SimpleXML. W zależności, jak się będziemy się odwoływać do tego obiektu, możemy pobrać różne dane ze znacznika. Oto możliwe warianty:

1. echo $element;
2. echo $element -> element_pochodny;
3. echo $element -> element_pochodny[0];
4. echo $element['atrybut'];

Pierwszego wariantu używamy, gdy chcemy pobrać tekst z danego znacznika (<x>tekst do pobrania</x>). Wszystkie elementy potomne są reprezentowane jako pola naszego obiektu i noszą takie same nazwy, jakie miały w pliku XML (no i także są obiektami SimpleXML, czyli możemy także do nich zastosować to, co teraz piszę). Jeśli dany element pochodny pojawił się w danym znaczniku tylko raz, sprawa jest prosta (wariant 2). Gdy jest ich więcej, pole w obiekcie będzie tablicą, której każdy element będzie odwoływał nas do kolejnych egzemplarzy danego znacznika. Należy tylko pamiętać, że jak zawsze numerujemy od zera. Nawiązując do pliku XML podanego w tym rozdziale, mogę podać taki przykład: chcąc sprawdzić, jaki jest pierwszy produkt w zamówieniu drugiego klienta, użyłbym konstrukcji $klienci -> klient[1] -> zamowienie -> produkt[0]. Ostatniego wariantu używamy do pobrania interesującego nas atrybutu elementu. Przykładowo - chcę pobrać informację o ilości zamówionych sztuk produktu drugiego u pierwszego klienta. Biorąc pod uwagę zaprezentowane tu dane, ułożyłbym takie odwołanie: $klienci -> klient[0] -> zamowienie -> produkt[0]['sztuk']. Dlaczego na końcu zrobiłem tak? Ponieważ nasz obiekt reprezentujący jeden z produktów jest zapisany właśnie pod produkt[0], a nie pod produkt. Gdybym nie dał tego [0], PHP nie wyświetliłby nic.

Taka budowa drzewa SimpleXML gwarantuje, że na każdym znaczniku możemy wykonać ten sam zestaw operacji, oraz że drzewo możemy przeglądać przy pomocy zwykłych pętli (w naszym przypadku - foreach()).

SimpleXML i XPath

XPath jest specjalną specyfikacją określającą, jak należy tworzyć "odnośniki" do interesujących nas elementów w pliku XML. Wspiera ją bardzo wiele bibliotek, oraz aplikacji XML. Wspomnę tylko, że wykorzysują ją intensywnie arkusze XSL/XSLT, więc jeśli ich używałeś, powinieneś czuć się, jak w domu.

Adresy XPath przypominają ścieżki dostępu do plików. Oto próbka: /element_glowny/a/b/c/d. Oznacza ona znalezienie elementu "d" leżącego w "c" leżącego w "b" leżącego w "a" leżącego w "element_glowny". Gdybyśmy chcieli znaleźć jakiś atrybut elementu "d", napisalibyśmy /element_glowny/a/b/c/d/@jakis_atrybut.

Przedstawione powyżej przykłady to absolutny wierzchołek góry lodowej. XPath jest bardzo rozbudowaną specyfikacją i daje on dostęp do m.in mnóstwa operatorów, oraz do odwołań względnych (czyli względem aktualnego elementu). Jeśli chciałbyś poznać go lepiej, zapraszam pod adres http://www.w3schools.com/xpath/default.asp.

Aby wykorzystać XPath w SimpleXML, należy skorzystać z metody xpath(), którą posiada każdy obiekt SimpleXML. Oto przykład wykorzystujący ją do pobrania wszystkich zamówionych produktów z naszego pliku XML:

<?php
$klienci = simplexml_load_file('plix.xml');
 
echo 'Zamówione produkty: <br/>';
 
$produkty = $klienci -> xpath('/klienci/klient/zamowienie/produkt');
 
foreach($produkty as $produkt){
echo 'Nazwa: '.$produkt.' (sztuk '.$produkt['sztuk'].')<br/>';
}
?>

Wywołałem metodę xpath() na korzeniu drzewa i zleciłem jej pobranie listy obiektów reprezentujących znacznik "produkt". Tym samym oszczędziłem PHP'kowi paru pętli, które inaczej musiałbym napisać, by dostać się do potrzebnych mi informacji. Zauważ, że w wyniku dwa razy powtarza się "Rakieta balistyczna". Jest to spowodowane tym, że jedna z nich należy do klienta pierwszego, a druga do drugiego. Możesz spróbować tak przerobić ten przykład, by sumował ilości zamówionych sztuk w przypadku, gdy produkt powtarza się.

UWAGA: W wersji alpha PHP 5 występowała w tym przypadku (podobnie, jak teraz) metoda xpath(). Jednak w którejś tam wersji beta zmieniono jej nazwę na xsearch(), natomiast obecnie, w dobie wersji Release Candidate, nosi ona z powrotem nazwę xpath(). Nic, tylko utłuc kogoś za to niezdecydowanie :).

Inny sposób dostępu do atrybutów

Obiekty SimpleXML posiadają też inną ciekawą metodę - attributes(), która za każdym wywołaniem zwraca kolejny atrybut danego znacznika. Możemy to wykorzystać, gdy nie wiemy, jakie atrybuty posiada nasz element! Zobacz na to:

<?php
$kod = '<?xml version="1.0" encoding="iso-8859-2"?>
<zbior>
<element nazwa="PC" typ="komputer" procesor="Athlon 1700+" ram="256" graficzna="GeForce" monitor="CRT-17"/>
<element nazwa="PHP" typ="jezyk skryptowy" oop="tak" funkcji="okolo 1000"/>
<element nazwa="Yamaha PSR-300" typ="organy elektryczne" sampli="100" podkladow="50" przykladow="15" midi="tak"/>
</zbior>'
;
 
$xml = simplexml_load_string($kod);
 
foreach($xml -> element as $element){
echo 'Charakterystyka elementu:<br/>';
foreach($element -> attributes() as $nazwa=>$wartosc){
echo '&nbsp;&nbsp;&nbsp;'.$nazwa.': '.$wartosc.'<br/>';
}
echo '<hr/>';
}
?>

Metody attributes() najlepiej używać właśnie w połączeniu z pętlą foreach(), co widać na przykładzie. Przy okazji demonstruje on, że można utworzyć drzewo SimpleXML także na podstawie ciągu tekstowego, używając funkcji simplexml_load_string(). Jako ciekawostkę dodam, że mamy także możliwość zbudowania takiego drzewka na podstawie... obiektu DOM przy pomocy funkcji simplexml_load_dom().

Inny sposób dostępu do elementów podrzędnych

Może się też zdarzyć, że nie będziesz wiedział, jakie znaczniki potomne zawiera nasz element. W takim przypadku przydatna okaże się zwyczajna pętla foreach! Wystarczy, że potraktujesz nią element, z którego chcesz pobrać pod-elementy.

Do przykładu demonstrującego nam tę metodę potrzebny nam będzie nowy plik XML:

<?xml version="1.0" encoding="iso-8859-2"?>
<menu>
<item link="index.html" name="Indeks">
<item link="produkty.html" name="Produkty">
<cat link="prod-programy.html" name="Programy"/>
<cat link="prod-sprzet.html" name="Sprzet"/>
<cat link="prod-patch.html" name="Aktualizacje"/>
</item>
<item link="klienci.html" name="Klienci">
<cat link="kl-niekom.html" name="Niekomercyjni"/>
<cat link="kl-kom.html" name="Komercyjni"/>
<cat link="kl-part.html" name="Partnerzy"/>
</item>
<item link="historia.html" name="Historia"/>
<item link="kontakt.html" name="Kontakt"/>
</item>
<item link="serwis.html" name="Serwis">
<item link="forum.html" name="Forum dyskusyjne"/>
<item link="nowosci.html" name="Nowosci"/>
<item link="bugtracker.html" name="Zglos blad!"/>
</item>
</menu>

A oto kod PHP przykładu:

<?php
function rysuj($element){
echo '<ul>';
foreach($element as $tag => $potomek){
switch($tag){
case 'item': echo '<li><b><a href="'.$potomek['link'].'">'.$potomek['name'].'</a></b>'; break;
case 'cat': echo '<li><i><a href="'.$potomek['link'].'">'.$potomek['name'].'</a></i>'; break;
}
rysuj($potomek);
echo '</li>';
}
echo '</ul>';
}
 
$menu = simplexml_load_file('plix2.xml');
 
echo '<ul>';
foreach($menu -> item as $element){
echo '<li><a href="'.$element['link'].'">'.$element['name'].'</a>';
rysuj($element);
echo '</li>';
}
echo '</ul>';
?>

Gdybyśmy spróbowali zrobić to bez pętli, nie moglibyśmy w pliku przemieszać ze sobą elementów <item> i <cat>. Skrypt wyświetliłby je po prostu posortowane. Tutaj natomiast mamy pewność, że pojawią się one tak, jak je wprowadziliśmy do pliku i bez względu na to, jak się nazywają. Foreach() wrzuca do drugiej zmiennej obiekt tagu, a do pierwszej - jego nazwę, co umożliwia nam jego identyfikację.

Zakończenie

Mam nadzieję, że artykuł ten przekonał Cię do zastąpienia starego parsera przez SimpleXML. Łatwość jego użycia, oraz potęga możliwości sprawi, że twoje skrypty powstaną szybciej, oraz że poświęcisz mniej czasu na ich debugowanie. Możesz także odwiedzić manual: http://www.php.net/manual/en/ref.simplexml.php, jednak póki co jest on lekko nieaktualny, a po drugie to już została zawarta większość tego, co tam jest napisane. W każdym razie - miłego XML'owania.

Autor: Tomasz "Zyx" Jędrzejewski, www.zyxist.com

 

Źródło: http://webcity.pl/webcity/simplexml_nadchodzi

Licencja: Creative Commons - użycie niekomercyjne - bez utworów zależnych