PHP: Čtení XML metodou SAX

PHP Práce se soubory PHP: Čtení XML metodou SAX

Opět jsem se nechal inspirovat článkem http://www.itnetwork.cz/…ni-xml-saxem a napsal jsem podobnou aplikaci v PHP. Opět jsem použil 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>

Tentokrát byla úloha mnohem obtížnější, než generování XML metodou SAX. Je nutné čí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, pokud z obrovského dokumentu XML potřebují jen vybrat některá data. V ostatních případech bývá výhodnější použití metody DOM.

$data=new XMLreader();
$data->open('data.xml');
while($data->read()) {
  switch($data->name) {
    case 'uzivatele':
      $uzivatele=new Uzivatele($data);
      break;;
  }
}
echo $uzivatele,"\n";

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

class Uzivatele {
  private $seznam=array();

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

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

Ani zde použití switch nevypadá příliš vábně, při použití složitější struktury XML však jistě oceníte snadnost přidání dalších elementů.

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

  function __construct($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;;
        case '#text':
          break;;
        default:
          return;
      }
    }
  }
  function __toString() {
    return sprintf("%-20s %2d %10s",$this->jmeno,$this->vek,$this->registrovan);
  }
}

Nakonec třída Uzivatel je nejkomplikovanější. Nejprve je přečten atribut vek elementu uzivatel. Poté je přečten i obsah elementů jmeno a registrovan. Pokud parser 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.

Metody __toString() jsou určeny k diagnostickému výstupu. Po spuštění skriptu obdržíme následující výsledek:

Pavel Slavík        22  21.3.2000
Jan Novák           31 30.10.2012
Tomáš Marný         16  12.1.2011

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.


 

  Aktivity (1)

Článek pro vás napsal Kit
Avatar
Jsem spokojeným uživatelem operačních systémů založených na linuxovém jádře. Zejména openSUSE a Ubuntu. Pro psaní veškerých textů a programů používám vynikající textový editor Vim. Aplikace se snažím psát vždy v tom nejvhodnějším programovacím jazyk...

Jak se ti líbí článek?
Ještě nikdo nehodnotil, buď první!


 


Miniatura
Všechny články v sekci
Práce se soubory v PHP
Miniatura
Následující článek
PHP: Generování XML metodou SAX

 

 

Komentáře

Avatar
David Čápka
Tým ITnetwork
Avatar
David Čápka:

Pěkné a opět dobře řešené předáním elementu třídě Uzivatel.

V .NETu to nejde takto ladně, protože čtení value elementu z nevysvětlitelného důvodu vykoná přesunutí čtečky na další element a naruší tak běh while cyklu 8| Rozumoval jsem nad tím opravdu dlouho a stále mi uniká, jak je to myšleno.

Odpovědět 18.8.2012 10:56
Miluji svou práci a zdejší komunitu, baví mě se rozvíjet, děkuji každému členovi za to, že zde působí.
Avatar
Kit
Redaktor
Avatar
Odpovídá na David Čápka
Kit:

V .NETu je to chápáno jako tokenizer. XMLreader jen posouvá čtecí hlavu po dokumentu, čtení obstarávají další metody. Obojí má své pro a proti. Marně jsem v XMLreader hledal metodu pro získání seznamu atributů elementu, dokumentace je mizerná.

Ve třídě Uzivatel jsem si to značně zjednodušil, do stavového automatu to má daleko. Správně by se metoda read() měla v každé metodě vyskytovat pouze 1× a zbytek řešit pomocí stavů. Pak by to správně přečetlo každý validní dokument. Bylo by to však o dost delší.

Zkusil jsem si i výkonnostní test. Načtení 75000 uživatelů (soubor měl 8 MB) trvalo na mém PC 10 sekund. Výsledek nic moc, ale to je dáno pomalostí PHP v cyklech. DOM by byl určitě o hodně rychlejší.

V PHP bych XMLreader už asi nikdy nepoužil. Je to pracné a výsledek je mizerný. Ještě mohu vyzkoušet SimpleXML, vypadá o něco lépe. Ovšem ta už s metodou SAX nesouvisí.

Odpovědět 18.8.2012 11:46
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
albertpatera
Redaktor
Avatar
albertpatera:

muze se takhle udelat databaze?

 
Odpovědět 22.8.2012 12:07
Avatar
Kit
Redaktor
Avatar
Odpovídá na albertpatera
Kit:

Může, ale nedoporučuji to. Pro čtení malého množství delších záznamů (např. článků) by to ještě možná šlo, ale při zápisu by se musel znovu zapisovat celý soubor a řešit kolize. To by bylo velmi nepraktické.

SimpleXML je pro čtení mnohem výhodnější, ale seznam ulic v ČR už v něm číst moc nedoporučuji. Pokud potřebuješ i zapisovat, použij raději nějakou skutečnou databázi. Vyřeší za tebe spoustu starostí.

Uvědom si, že programy pracující s XML vždy sekvenčně čtou celý soubor a při modifikaci ho zase celý přepisují.

Odpovědět 22.8.2012 12:28
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
David Čápka
Tým ITnetwork
Avatar
Odpovídá na albertpatera
David Čápka:

Proč se každý bojí jednoduché databáze a chce raději používat složité soubory?

Odpovědět 22.8.2012 12:33
Miluji svou práci a zdejší komunitu, baví mě se rozvíjet, děkuji každému členovi za to, že zde působí.
Avatar
albertpatera
Redaktor
Avatar
albertpatera:

diky..chci udělat seznam uživatelů na webu pomocí databáze, aby každý nový uživatel, který se na webu zaregistruje, tak aby se automaticky zapsal i na seznam registrovaných uzivatelů...pres co to mam teda udelt, díky

 
Odpovědět 22.8.2012 12:45
Avatar
Kit
Redaktor
Avatar
Odpovídá na albertpatera
Kit:

Odpovědí jsi už dostal dost: Použij databázi.

Pokud se ti nelíbí síťová databáze MySQL, použij souborovou databázi SQLite.

Odpovědět 22.8.2012 12:49
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
albertpatera
Redaktor
Avatar
albertpatera:

jj diky

 
Odpovědět 22.8.2012 12:54
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 8 zpráv z 8.