NOVINKA - Online rekvalifikační kurz Java programátor. Oblíbená a studenty ověřená rekvalifikace - nyní i online.
NOVINKA – Víkendový online kurz Software tester, který tě posune dál. Zjisti, jak na to!

Lekce 5 - Práce se soubory XML v PHP - Čtení

V předchozí lekci, Práce se soubory XML v PHP - Zápis, jsme se seznámili s prací se soubory ve formátu XML. Probrali jsme použití třídy XMLWriter, která slouží na zápis XML.

Dnes se opět inspirujeme článkem Čtení XML SAXem v C# a napíšeme si podobnou aplikaci v jazyce PHP. Použijeme XML data, která jsme si vygenerovali v lekci práce se soubory XML v PHP - Zápis:

<?xml version="1.0" encoding="UTF-8"?>
<uzivatele>
 <uzivatel vek="22">
  <jmeno>Pavel Slavík</jmeno>
  <registrovan>21.3.2000</registrovan>
 </uzivatel>
 <uzivatel vek="31">
  <jmeno>Jan Novák</jmeno>
  <registrovan>30.10.2012</registrovan>
 </uzivatel>
 <uzivatel vek="16">
  <jmeno>Tomáš Marný</jmeno>
  <registrovan>12.1.2011</registrovan>
 </uzivatel>
</uzivatele>

Tento soubor si uložíme do projektové složky.

Čtení XML metodou SAX – třída XMLReader

Tentokrát je úloha mnohem obtížnější, než generování XML metodou SAX. Musíme totiž číst jednotlivé tokeny a jejich posloupností řídit ukládání dat. Zájemcům doporučuji metodu použít pouze ve specifických případech, třeba když z obrovského XML souboru potřebují jen vybrat některá data. V ostatních případech je výhodnější použít metodu DOM.

Třída Uzivatel

Nejprve si definujeme třídy, které budou ve složce tridy/. Jako první si definujeme třídu Uzivatel:

class Uzivatel
{
    private string $jmeno;
    private int $vek;
    private string $registrovan;

    public function __construct(XMLReader $data)
    {
        $this->vek = $data->getAttribute('vek');

        while ($data->read()) {
            switch ($data->name) {
                case 'jmeno':
                    $data->read();
                    $this->jmeno = $data->value;
                    $data->read();
                    break;

                case 'registrovan':
                    $data->read();
                    $this->registrovan = $data->value;
                    $data->read();
                    break;

                // další elementy
                case '#text':
                    break;

                default:
                    return;
            }
        }
    }

    public function __toString(): string
    {
        return sprintf("%-20s %2d %10s", $this->jmeno, $this->vek, $this->registrovan);
    }
}

Nejkomplikovanější třída dnes bude nejspíš Uzivatel. Nejprve ji přečteme atribut vek elementu uzivatel. Poté ji přečteme i obsah elementů jmeno a registrovan. Pokud parser (cyklus while()) narazí na neznámý element, je konstruktor ukončen. Pseudoelement #text obsahuje bílé znaky, které jsou mezi elementy zdrojového XML a kterých se potřebujeme zbavit. Přečtené atributy XML si uložíme do příslušných atributů třídy.

Třída Uzivatele

Druhá třída bude Uzivatele, která bude reprezentovat seznam uživatelů:

class Uzivatele
{
    private array $seznam = array();

    public function __construct(XMLReader $data) {
        while ($data->read()) {
            switch ($data->name) {
                case 'uzivatel':
                    if ($data->nodeType == XMLReader::ELEMENT) {
                        $this->seznam[] = new Uzivatel($data);
                    }
                    break;
                case 'uzivatele':
                    return;
            }
        }
    }

    public function __toString(): string
    {
        $uzivatele = array();
        foreach ($this->seznam as $uzivatel) {
            $uzivatele[] = $uzivatel->__toString();
        }
        return implode("\n", $uzivatele);
    }
}

Soubor index.php

Nakonec stačí soubor index.php:

require('tridy/Uzivatel.php');
require('tridy/Uzivatele.php');

// přečteme soubor s XML daty
$data = new XMLReader();

// zde si případně upravte cestu k souboru XML
$data->open('../data.xml');

// projdeme elementy XML souboru a přetransformujeme je do třídy Uzivatele
while ($data->read()) {
    switch ($data->name) {
        case 'uzivatele':
            $uzivatele = new Uzivatele($data);
            break;
    }
}

// výstup si necháme vypsat do prohlížeče pro kontrolu
header("Content-Type: text/plain; charset=UTF-8");
echo($uzivatele . "\n");

Pozornější programátoři si všimli, že v konstrukci switch používáme jen 1× case místo kratšího zápisu if. Je tomu tak proto, že pro čtení používáme metodiku regulárního automatu, u které je použití switch obvyklé. Při parsování složitějšího dokumentu jistě oceníme snadnou rozšiřitelnost.

Výstup

Po spuštění skriptu obdržíme následující výsledek:

Čtení XML - XMLReader
localhost

Uvedený příklad není naprogramován úplně nejčistěji. Určitě by se našla kombinace validních vstupních dat, která by neprošla. Měla to být jen ukázka, že i v PHP je možné použít metodu SAX pro čtení dokumentů XML.

Čtení XML třídou SimpleXML

Mluvili jsme o tom, že čtení XML metodou SAX není pro běžné použití vhodné. Nyní si ukážeme ten lepší způsob pomocí třídy SimpleXML.

Třída SimpleXML je určena pro jednoduchou konverzi dokumentu XML do objektů v PHP. Na rozdíl od třídy XMLReader však dokument nečteme v cyklu po jednotlivých elementech, ale načteme ho celý do objektové struktury. To je velmi výhodné, protože nejpomalejší úkon provádí standardní knihovna, která je pro tento účel optimalizována.

Použijeme opět stejná data:

<?xml version="1.0" encoding="UTF-8"?>
<uzivatele>
 <uzivatel vek="22">
  <jmeno>Pavel Slavík</jmeno>
  <registrovan>21.3.2000</registrovan>
 </uzivatel>
 <uzivatel vek="31">
  <jmeno>Jan Novák</jmeno>
  <registrovan>30.10.2012</registrovan>
 </uzivatel>
 <uzivatel vek="16">
  <jmeno>Tomáš Marný</jmeno>
  <registrovan>12.1.2011</registrovan>
 </uzivatel>
</uzivatele>

Třída Uzivatele

Zde nám oproti metodě SAX stačí vytvořit pouze jednu třídu Uzivatele:

class Uzivatele
{
    private SimpleXMLElement $seznam;

    public function __construct(string $souborXML)
    {
        $this->seznam = new SimpleXMLElement($souborXML, null, true);
    }

    public function __toString(): string
    {
        $uzivatele = array();

        foreach ($this->seznam as $uzivatel) {
            $uzivatele[] = sprintf("%-20s %2d %10s", $uzivatel->jmeno, $uzivatel['vek'], $uzivatel->registrovan);
        }

        return implode("\n", $uzivatele);
    }
}

Soubor index.php

Skript vypisující data je velmi krátký

require('tridy/Uzivatele.php');

// zde si případně upravte cestu k souboru XML
$data = new Uzivatele('../data.xml');

header("Content-Type: text/plain; charset=UTF-8");
echo($data . "\n");

Podle potřeby můžeme samozřejmě doplnit metody pro vyhledání uživatele, ověření hesla apod. Pro náš účel postačí pouhý výpis seznamu uživatelů.

Výstup

Po spuštění skriptu se v prohlížeči objeví:

Čtení XML - SimpleXML
localhost

Jak vidíme, čtení dokumentu třídou SimpleXMLElement je mnohem jednodušší, než čtení metodou SAX. Tato třída je také asi 10× rychlejší, než XMLReader a lépe zdokumentovaná. Pro zpracování běžných dokumentů XML je proto mnohem výhodnější.

Kompletní kód všech příkladů z této lekce najdete jako vždy ke stažení dole pod článkem :-)

V následujícím cvičení, Řešené úlohy k 3.-5. lekci práce se soubory v PHP, si procvičíme nabyté zkušenosti z předchozích lekcí.


 

Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.

Stáhnout

Stažením následujícího souboru souhlasíš s licenčními podmínkami

Staženo 11x (5.35 kB)
Aplikace je včetně zdrojových kódů v jazyce PHP

 

Předchozí článek
Práce se soubory XML v PHP - Zápis
Všechny články v sekci
Soubory a práce s nimi v PHP
Přeskočit článek
(nedoporučujeme)
Řešené úlohy k 3.-5. lekci práce se soubory v PHP
Článek pro vás napsal Samuel Hél
Avatar
Uživatelské hodnocení:
6 hlasů
Autor se věnuje hlavně programování, nejvíce z oblasti webových technologií, dělá občasné video edity ze svých dovolených. Má rád memes, svou gf a elektroniku
Aktivity