Klasa SimpleXML służy do przetwarzania dokumentów XML. Artykuł opisuje podstawowe wykorzystanie tej klasy oraz przedstawia dwa przykłady przetwarzania dokumentów XML dostępnych w internecie: kursów walut NBP oraz listy książek wydawnictwa Helion.
Klasa SimpleXML
Klasa SimpleXML służy do przetwarzania dokumentów XML. Obiekty SimpleXML tworzą drzewo, którego struktura odpowiada strukturze kodu XML. Każdemu elementowi XML odpowiada jeden obiekt SimpleXML, zaś atrybuty są zwracane w postaci tablicy asocjacyjnej.
Konstruktor {stala}SimpleXMLElement{/stala} oraz funkcje {stala}simplexml_load_file(){/stala} i {stala}simplexml_load_string(){/stala} tworzą drzewo obiektów SimpleXML na podstawie kodu XML podanego jako parametr. Metoda {stala}asXML(){/stala} działa w odwrotną stronę. Generuje kod XML drzewa obiektów dla którego została wywołana.
Do modyfikowania drzewa obiektów służą metody {stala}AddChild(){/stala} oraz {stala}AddAttribute(){/stala}. Pozwalają one na dodawanie węzłów i atrybutów.
Metoda {stala}xpath(){/stala} służy do wyszukiwania danych przy użyciu zapytań XPath, zaś funkcja {stala}simplexml_import_dom(){/stala} umożliwia konwersję formatu DOMDocument do formatu SimpleXML.
Pełne zestawienie metod klasy SimpleXML jest zawarte w załączonej tabeli.
Tworzenie obiektu SimpleXMLElement
Obiekt SimpleXMLElement możemy utworzyć na podstawie pliku XML lub napisu.
Funkcja {stala}simplexml_load_file(){/stala} pobiera jako parametr nazwę pliku XML. Podawany parametr może być adresem URL lub ścieżką lokalną:
1 |
$aparaty = simplexml_load_file(\'dane.xml\'); |
Funkcja {stala}simplexml_load_string(){/stala} tworzy obiekt {stala}SimpleXMLElement{/stala} na podstawie napisu. Dzięki temu kod XML może pochodzić z dowolnego źródła (np. z bazy danych), a nie tylko z pliku:
1 2 |
$str = file_get_contents(\'dane.xml\'); $aparaty = simplexml_load_string($str); |
Konstruktor klasy {stala}SimpleXMLElemen{/stala}t pozwala na korzystanie z obu powyższych metod. Aby utworzyć obiekt na podstawie pliku, konstruktor wywołujemy z trzema parametrami:
1 |
$aparaty = new SimpleXMLElement(\'dane.xml\', null, true); |
Jeśli natomiast przekazujemy do konstruktora napis, stosujemy jeden parametr:
1 2 3 4 5 6 7 |
$str = \' <?xml version=\"1.0\" encoding=\"utf-8\"?> <dane> ... </dane> \'; $aparaty = new SimpleXMLElement($str); |
Dostęp do węzłów drzewa
Plik o nazwie {stala}data.xml{/stala} ma zawartość:
1 2 3 4 5 6 |
<?xml version=\"1.0\" encoding=\"utf-8\"?> <data> <dzien>12</dzien> <miesiac>2</miesiac> <rok>2008</rok> </data> |
Po wywołaniu:
1 2 3 4 5 |
$d = simplexml_load_file(\'data.xml\'); // obiekt $d będzie zawierał składowe: $d->dzien $d->miesiac $d->rok |
o wartościach:
1 2 3 |
12 2 2008 |
Nazwę elementu głównego (tj. {html}…{/html}) zwraca metoda {stala}getName(){/stala}:
1 |
echo $d->getName(); |
Składowe możemy przetwarzać pętlą {stala}foreach{/stala}, wykorzystując metodę {stala}children(){/stala}, która zwraca tablicę obiektów {stala}SimpleXMLElement{/stala} reprezentujących elementy potomne:
1 2 3 |
foreach ($d->children() as $child) { echo $child; } |
Nazwę elementów {stala}$child{/stala} przetwarzanych w pętli możemy ustalić metodą getName():
1 |
$child->getName() |
lub korzystając z rozszerzonej składni pętli foreach:
1 2 3 4 5 |
foreach ($d->children() as $nazwa => $wartosc) { echo $nazwa; echo \' = \'; echo $wartosc; } |
Lista identycznych elementów
Jeśli kod XML zawiera listę identycznych elementów, wtedy wszystkie elementy o tej samej nazwie (i stojące w relacji rodzeństwo) zostaną umieszczone w jednej tablicy. Plik {stala}imiona.xml{/stala} zawiera listę elementów {stala}imie{/stala}:
1 2 3 4 5 6 7 |
<?xml version=\"1.0\" encoding=\"utf-8\"?> <imiona> <imie>Alicja</imie> <imie>Jan</imie> <imie>Aleksander</imie> ... </imiona> |
Po odczytaniu pliku:
1 |
$imiona = simplexml_load_file(\'imiona.xml\'); |
zmienna {stala}$imiona{/stala} będzie zawierała składową {stala}imie{/stala} (tj. {stala}$imiona->imie{/stala}). Składowa ta jest tablicą. Dostęp do pierwszego imienia (tj. Alicja) uzyskamy stosując indeks 0:
1 |
echo $imiona->imie[0]; |
Pod indeksem 2
1 |
echo $imiona->imie[2]; |
znajdziemy imię Aleksander itd. Całą tablicę możemy przetworzyć w pętli {stala}foreach{/stala}:
1 2 3 |
foreach ($imiona->imie as $imie) { echo $imie; } |
Dostęp do atrybutów
Atrybuty elementu są zwracane w postaci tablicy asocjacyjnej przez metodę {stala}attributes(){/stala}. Jeśli dokument {stala}aparaty.xml {/stala}ma postać:
1 2 3 4 5 |
<?xml version=\"1.0\" encoding=\"iso-8859-1\"?> <aparaty> <aparat producent=\"Canon\" megapixel=\"12.7\" matryca=\"CMOS\">EOS 5D</aparat> <aparat producent=\"Nikon\" megapixel=\"12.1\" matryca=\"CMOS\">D3</aparat> </aparaty> |
wówczas po utworzeniu obiektu {stala}$aparaty{/stala}:
1 |
$aparaty = simplexml_load_file(\'aparaty.xml\'); |
każdy element tablicy {stala}$aparaty->aparat{/stala} będzie zawierał własne atrybuty. Dostęp do nich uzyskamy wywołując metodę {stala}attributes(){/stala}.
Atrybuty pierwszego aparatu możemy przypisać do tablicy {stala}$atrs{/stala}:
1 |
$atrs = $aparaty->aparat[0]->attributes(); |
Indeksami w zwracanej tablicy są nazwy atrybutów, a wartościami – wartości atrybutów. Instrukcje:
1 2 |
echo $atrs[\'producent\']; echo $atrs[\'model\']; |
wydrukują napisy:
1 2 |
Canon 12.7 |
Wszystkie atrybuty elementu możemy przetworzyć w pętli {stala}foreach{/stala}:
1 2 3 4 |
$atrs = $aparaty->aparat[0]->attributes(); foreach ($atrs as $atr) { echo $atr; } |
Przetwarzanie wszystkich elementów i ich atrybutów
Wykorzystując pętlę {stala}foreach{/stala} dwukrotnie – raz do przetworzenia tablicy elementów, drugi raz do przetworzenia tablicy atrybutów – możemy dokument XML zamienić w dwupoziomową listę ul. Po odczytaniu z pliku {stala}pracownicy.xml{/stala} listy pracowników:
1 2 3 4 5 |
<?xml version=\"1.0\" encoding=\"utf-8\"?> <pracownicy> <pracownik ur=\"1965\" plec=\"M\" zatrudnienie=\"umowa\">Jan Kowalski</pracownik> <pracownik ur=\"1978\" plec=\"K\" zatrudnienie=\"zlecenie\">Anna Nowak</pracownik> </pracownicy> |
przetwarzamy wszystkie elementy i ich atrybuty:
1 2 3 4 5 6 7 8 9 10 |
$pracownicy = simplexml_load_file(\'pracownicy.xml\'); echo \'<ul>\'; foreach ($pracownicy->pracownik as $p) { echo \'<li>\' . $p . \'<ul>\'; foreach ($p->attributes() as $atr) { echo \'<li>\' . $atr . \'</li>\'; } echo \'</ul></li>\'; } echo \'</ul>\'; |
Wielokrotne zagnieżdżenia
Elementy XML mogą być zagnieżdżone wielokrotnie. W takiej sytuacji kolejne poziomy zagnieżdżeń stają się składowymi kolejnych składowych. Plik {stala}tcs.xml{/stala} o treści:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
<?xml version=\"1.0\" encoding=\"utf-8\"?> <turniejCzterechSkocznii> <zawody> <rok>1953</rok> <miejsce> <numer>1</numer> <sportowiec> <imie>Josef</imie> <nazwisko>Bradl</nazwisko> <kraj>Austria</kraj> </sportowiec> </miejsce> <miejsce> ... </miejsce> <miejsce> ... </miejsce> </zawody> <zawody> ... </zawody> ... </turniejCzterechSkocznii> |
zawiera dziewięć różnych elementów: {stala}turniejCzterechSkocznii{/stala}, {stala}zawody{/stala}, {stala}rok{/stala}, {stala}miejsce{/stala}, {stala}numer{/stala}, {stala}sportowiec{/stala}, {stala}imie{/stala}, {stala}nazwisko{/stala}, {stala}kraj{/stala}.
Po odczytaniu pliku obiekt {stala}$tcs{/stala}:
1 |
$tcs = simplexml_load_file(\'tcs.xml\'); |
będzie miał składową tablicową {stala}$tcs->zawody{/stala}. W elemencie {stala}$tcs->zawody[0]{/stala} będą dostępne dane pierwszych zawodów, w elemencie {stala}$tcs->zawody[1]{/stala} – drugich itd.
Każdy element tablicy {stala}$tcs->zawody{/stala} będzie zawierał składowe rok oraz miejsce, np.:
1 2 |
$tcs->zawody[0]->rok $tcs->zawody[0]->miejsce |
Składowa miejsce będzie tablicą zawierającą zwycięzców konkursu. Pierwszy zwycięzca będzie dostępny jako:
1 |
$tcs->zawody[0]->miejsce[0] |
drugi jako:
1 |
$tcs->zawody[0]->miejsce[1] |
Zwycięzca będzie dalej miał składowe {stala}numer{/stala} oraz {stala}sportowiec{/stala}, zaś składowa {stala}sportowiec{/stala} będzie zawierała składowe {stala}imie{/stala}, {stala}nazwisko{/stala} oraz {stala}kraj{/stala}.
Struktura składowych obiektu {stala}$tcs{/stala} jest przedstawiona na rysunku obok. Składowe będące tablicami zawierają oznaczenie {stala}[]{/stala}.
Imię i nazwisko pierwszego zwycięzcy pierwszego konkursu znajdziemy w składowych:
1 2 |
$tcs->zawody[0]->miejsce[0]->sportowiec->imie $tcs->zawody[0]->miejsce[0]->sportowiec->nazwisko |
Skrypt:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
echo \'<ul>\'; foreach ($tcs->zawody as $z) { echo \'<li>\'; echo $z->rok; echo \'<ul>\'; foreach ($z->miejsce as $m) { echo \'<li>Miejsce \'; echo $m->numer; echo \': \'; echo $m->sportowiec->imie; echo \' \'; echo $m->sportowiec->nazwisko; echo \' (\'; echo $m->sportowiec->kraj; echo \')</li>\'; } echo \'</ul></li>\'; } echo \'</ul>\'; |
przetwarza dane pochodzące z turnieju czterech skoczni z formatu XML w dwupoziomową listę wypunktowaną.
Język XPath
Metoda {stala}xpath(){/stala} pozwala na wydawanie zapytań XPath. Jeśli w dokumencie {stala}tcs.xml{/stala}, zawierającym dane turnieju czterech skoczni, zechcemy wybrać zwycięzców (czyli osoby, które zajęły pierwsze miejsce), to zadanie to zrealizuje zapytanie XPath w postaci:
1 |
zawody/miejsce[numer=1]/sportowiec |
Wystarczy odczytać dokument {stala}tcs.xml{/stala}, a następnie wydać zapytanie Xpath:
1 2 |
$tmp = simplexml_load_file(\'tcs.xml\'); $osoby = $tmp->xpath(\'zawody/miejsce[numer=1]/Sportowiec\'); |
Otrzymamy tablicę obiektów {stala}SimpleXMLElement{/stala} odpowiadających elementowi sportowiec w kodzie XML. Tablicę {stala}$osoby{/stala} możemy zamienić np. w listę ul:
1 2 3 4 5 6 7 8 9 10 11 |
echo \'<ul>\'; foreach ($osoby as $o) { echo \'<li>\'; echo $o->imie; echo \' \'; echo $o->nazwisko; echo \' (\'; echo $o->kraj; echo \')</li>\'; } echo \'</ul>\'; |
Przykładowe dokumenty XML dostępne w internecie
Kursy walut
Pod adresem http://www.nbp.pl/Kursy/KursyA.html znajdziemy zestawienie kursów walut publikowane przez Narodowy Bank Polski. Stosowany format XML jest następujący:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<?xml version=\"1.0\" encoding=\"ISO-8859-2\"?> <tabela_kursow typ=\"A\"> <numer_tabeli>29/A/NBP/2008</numer_tabeli> <data_publikacji>2008-02-11</data_publikacji> <pozycja> <nazwa_waluty>bat (Tajlandia)</nazwa_waluty> <przelicznik>1</przelicznik> <kod_waluty>THB</kod_waluty> <kurs_sredni>0,0756</kurs_sredni> </pozycja> <pozycja> <nazwa_waluty>dolar amerykański</nazwa_waluty> <przelicznik>1</przelicznik> <kod_waluty>USD</kod_waluty> <kurs_sredni>2,4906</kurs_sredni> </pozycja> ... </tabela_kursow> |
Przetwarzanie rozpoczynamy od odczytania dokumentu XML:
1 |
$kursy = simplexml_load_file(\'http://www.nbp.pl/kursy/xml/a029z080211.xml\'); |
Następnie na podstawie atrybutów elementu głównego oraz elementów {stala}data_publikacji{/stala} i {stala}numer_tabeli{/stala} uzyskujemy szczegółowy opis zestawienia:
1 2 3 4 5 6 7 |
$rob = $kursy->attributes(); echo \'Kurs z dnia: \'; echo $kursy->data_publikacji; echo \'Typ: \'; echo $rob[\'typ\']; echo \'Numer tabeli: \'; echo $kursy->numer_tabeli; |
Następnie przetwarzamy tablicę {stala}$kursy->pozycja{/stala}, która zawiera dane poszczególnych walut:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
echo \'<table>\'; foreach ($kursy->pozycja as $pozycja) { echo \'<tr>\'; echo \'<td>\'; echo $pozycja->nazwa _ waluty; echo \'</td>\'; echo \'<td>\'; echo $pozycja->przelicznik; echo \'</td>\'; echo \'<td>\'; echo $pozycja->kod _ waluty; echo \'</td>\'; echo \'<td>\'; echo $pozycja->kurs _ sredni; echo \'</td>\'; echo \'</tr>\'; } echo \'</table>\'; |
Książki wydawnictwa Helion
Pod adresem http://helion.pl/plugins/xml/lista.cgi wydawnictwo Helion publikuje zestawienie wszystkich dostępnych książek. W dokumencie tym dane poszczególnych książek są zawarte w atrybutach elementów item:
1 2 3 4 5 6 |
<?xml version=\'1.0\' encoding=\'iso-8859-2\'?> <details> <item isbn=\"83-246-0439-1\" tytul=\"GIMP. Praktyczne projekty\" autor=\"Włodzimierz Gajda\" cena=\"69\" /> <item isbn=\"83-246-0056-6\" tytul=\"Photoshop. Maskowanie i komponowanie\" autor=\"Katrin Eismann\" cena=\"117\" /> ... </details> |
Po odczytaniu dokumentu:
1 |
$h = simplexml_load_file(\'http://helion.pl/plugins/xml/lista.cgi\'); |
przetwarzamy tablicę {stala}$books->item{/stala}. Pobieramy wszystkie atrybuty kolejnej książki, po czym drukujemy autora, tytuł, numer ISBN oraz cenę:
1 2 3 4 5 6 7 8 9 10 11 12 |
foreach ($books->item as $book) { $tmp = $book->attributes(); echo \'<li>\'; echo $tmp[\'autor\']; echo \', <em>\'; echo $tmp[\'tytul\']; echo \'</em>, ISBN \'; echo $tmp[\'isbn\']; echo \', \'; echo $tmp[\'cena\']; echo \' zł</li>\'; } |
Może Cię zainteresować:







A jak określić ilość wyświetlanych rekordów/pętli z danego pliku xml? Jest to w ogóle możliwe?
Marek- xPath i position() mogą być pomocne. Można zrobić np. tak: nazwa[position()<10] co spowoduje pokazanie pierwszych 10 elementów.