XML a PHP - parsování V kapitole je ukázáno několik možných přístupů k parsování XML z PHP Klíčové pojmy: Parsování, parser, sekvenční zpracování, DOM, SAX, SimpleXML
XML a PHP - parsování Parsování XML provede rozdělení XML do jednotlivých částí. Nástrojům, které to umí, se říká parsery a bývají součástí každého moderního programovacího jazyka. Parser by měl umět: • číst XML dokument a kontrolovat jeho strukturu, validovat podle DTD nebo XSD • během čtení extrahovat názvy a hodnoty elementů a atributů • nabízí abstraktní model XML dokumentu = infoset • parsery se dělí podle zvoleného způsobu zpracování, základní dělení: ◦ proudové čtení ◦ stromová prezentace dokumentu Proudové čtení • Typickým představitelem je SAX = Simple API for XML • Pro každou ucelenou část (začátek dokumentu, elementu, vnitřek elementu, konec elementu, dokumentu) vyvolává událost, naším úkolem je napsat obsluhy těchto událostí. • Výhody: ◦ velká rychlost ◦ malá paměťová náročnost • Nevýhody: ◦ dokument se zpracovává sekvenčně, při čtení se nelze vracet ◦ načtené zpracovává nebo někam ukládá Stromová prezentace dokumentu • Celý dokument se načte naráz do stromové struktury v paměti. • Typickým představitelem je DOM = Document Object Model. • Výhody: ◦ celý infoset je najednou dostupný v paměti ◦ načtený dokumet se může měnit ◦ dobrá spolupráce s jazykem XPath = XML Path Language • Nevýhody: ◦ malá rychlost načítání ◦ velká paměťová náročnost 2012-06-28
XML a PHP - parsování
1/5
SAX • • • •
jedno z nejstarších rozhraní zpracovává xml soubor sekvenčně vytvoříme parser: $parser = xml_parser_create("utf-8") nastavení funkcí pro obsluhu elementů - začátek a konec function startElementHandler($parser, $jmeno, $atributy) function endElementHandler($parser, $jmeno)
•
nastavení funkcí pro obsluhu obsahu elementů
function cdataHandler($parser, $data)
•
zaregistrujeme obsluhu koncové a počáteční značky
xml_set_element_handler($parser, "startElementHandler", "endElementHandler");
•
zaregistrujeme obsluhu dat
xml_set_character_data_handler($parser, "cdataHandler");
•
otevřeme dokument xml
$soubor = "./rozvrhVala.xml"; if (!($fp = fopen($soubor,"r"))) die("nelze otevřít soubor $soubor");
•
čteme bloky 4KB a předáváme ho parseru
while ($data = fread($fp, 4096)) { if (!xml_parse($parser, $data, feof($fp))) die(sprintf("Chyba XML %d %d", xml_get_current_line_number($parser), xml_get_current_column_number($parser))); }
SimpleXML • modelování pomocí objektů • celý XML se načte do paměti do struktury objektů • názvy objektů = názvy elementů • vytvoření struktury elementů: $xml = simplexml_load_file(nazev_dokumentu_xml) • k obsahu elementu title (obsahuje jen text): $xml->clanek->title • když neobsahuje jen text, vrací pole objektů • ke druhé položce elementu přistupujeme jako k $xml->clanek->kapitola[1] • atributy jsou reprezentovány asociativním polem • příklad na použití některých funkcí SimpleXML '; echo "*** Čtení rozvrhu pomocí SimpleXML ***
"; var_dump($xml); echo "
"; echo '*** htmlspecialchars($xml->asXML())
'; echo htmlspecialchars($xml->asXML()); echo "
"; /* vypis atributu urciteho elementu */ echo "*** attributes() .... výpis atributů určitého objektu - kniha->rok
"; foreach ($xml->kniha as $kniha) { echo "$kniha->autor: $kniha->nazev $kniha->rok ... ".$kniha->rok->attributes()."
";
2012-06-28
XML a PHP - parsování
2/5
} echo "
"; /* children() - dceřinné uzly určitého uzlu - př. kniha) */ echo "*** children() .... výpis dceřiných uzlů určitého uzlu - kniha
"; foreach ($xml->kniha[1]->children() as $atribut) { echo "vnořený element knihy... ".$atribut."
"; } echo "
"; /* ziskavani uzlu XML z cesty-path */ echo "*** $xml->xpath(uzel) .... ziskavani uzlu XML z cesty-path
"; $hodnota = $xml->xpath("/seznam/kniha/nazev"); foreach ($hodnota as $i) { echo "- $i
"; }
DOM • Document Object Modelování je standardem • vytvoří se v paměti stromová struktura pro každý uzel: element, atribut, textový uzel, ... • objekt pro každý uzel • u každého uzlu můžeme zjišťovat: ◦ $uzel->childNodes ... vrací pole potomků uzlu ◦ $uzel->parentNode ... vrací objekt rosičovského uzlu ◦ $prvek->nodeType ... vrací typ prvku/uzlu (XML_TEXT_NODE, XML_ELEMENT_NODE) ◦ $prvek->nodeValue ... vrací obsah prvku/uzlu ◦ $prvek->nodeName ... vrací název prvku/uzlu ◦ $prvek->getAttributeNode(jmeno_atributu)->value ... vrací obsah atributu prvku s daným jménem ◦ $prvek->getElementsByTagName(jmeno_elementu) ... vrací seznam uzlů odpovídající elementům s daným názvem ◦ $prvek->getElementsByTagName(jmeno_atributu)->item(i) ... vrací i-tý prvek v seznamu vnořených uzlů • dokument je v paměti reprezentován jako objekt, instance třídy DOMDocument: • • •
$dom = new DOMDocument(); načtení xml souboru do paměti: $dom->load(nazev_dokumentu_xml) načtení kořenového uzlu dokumentu DOM: $koren = $dom->documentElement; získánní pole potomků uzlu: $potomci = $uzel->childNodes;
2012-06-28
XML a PHP - parsování
3/5
Příklad na čtení a parsování souboru rozvrh.xml: určete, kdo má kolik hodin jakého předmětu
7:00-7:45 7:55-8:40 8:50-9:35 9:50-10:35 10:45-11:30 12:00-12:45 13:00-13:45 14:00-14:45 <jmeno>Jakub <den nazev="po"> <predmet hodina="1">Z <predmet hodina="2">F <predmet hodina="3">Mcv <predmet hodina="4">M <predmet hodina="5">Aj <predmet hodina="6">Vv <predmet hodina="7">Vv <den nazev="ut"> <predmet hodina="2">D <predmet hodina="3">Bi <predmet hodina="4">Ch <predmet hodina="5">Aj <predmet hodina="6">Hv ... "; /* vytvoření objektu DOM */ $dom = new DomDocument(); /* vytvoření dokumentu DOM */ $dom->load("./rozvrh.xml") or die("nelze přečíst soubor"); /* načtení kořenového uzlu dokumentu DOM */ $koren = $dom->documentElement; zpracovat_potomky($koren); /* zpracování potomků */ function zpracovat_potomky($uzel) { $potomci = $uzel->childNodes; foreach($potomci as $prvek) { /* uzlem je text, vypíšu jeho obsah */ if ($prvek->nodeType == XML_TEXT_NODE) { if (strlen(trim($prvek->nodeValue))) echo trim($prvek->nodeValue)."
"; } /* uzlem je element, zpracovávám jeho potomky */ else if ($prvek->nodeType == XML_ELEMENT_NODE) zpracovat_potomky($prvek); }
} ?> /*** Proměnné a metody DomDocument * $dom->documentElement ... vrací objekt kořenového uzlu dokumentu, třídy DomElement */
2012-06-28
XML a PHP - parsování
4/5
/*** Proměnné a metody DomElement * $uzel->childNodes ... vrací pole potomků uzlu * $prvek->nodeType ... vrací typ prvku/uzlu (XML_TEXT_NODE, XML_ELEMENT_NODE) * $prvek->nodeValue ... vrací obsah prvku/uzlu * $prvek->nodeName ... vrací název prvku/uzlu * $prvek->getAttributeNode(jmeno_atributu)->value ... vrací obsah atributu prvku s daným jménem * $prvek->getElementsByTagName(jmeno_atributu)->item(i) ... vrací i-tý prvek v seznamu vnořených uzlů */ "; /*** Funkce ovladačů informující parser, co má dělat, když najde určitý typ uzlu */ /* počáteční značka elementu */ function startElementHandler($parser, $jmeno, $atributy) echo "*element $jmeno "; if ($atributy) { echo "s atributy: "; foreach ($atributy as $a) { echo "$a "; } } echo "
"; } /* koncová značka elementu */ function endElementHandler($parser, $jmeno) echo "*/element $jmeno
"; }
{
{
/* uvnitř elementu = data*/ function cdataHandler($parser, $data) { echo "--- uvnitř elementu: $data
"; } /*** Vytvoříme parser */ $parser = xml_parser_create(); /* zaregistrujeme obsluhu koncové a počáteční značky */ xml_set_element_handler($parser, "startElementHandler", "endElementHandler"); /* zaregistrujeme obsluhu dat */ xml_set_character_data_handler($parser, "cdataHandler"); /* otevřeme dokument xml */ $soubor = "./rozvrh.xml"; if (!($fp = fopen($soubor,"r"))) die("nelze otevřít soubor $soubor pro čtení"); /* čteme bloky 4KB a předáváme ho parseru */ while ($data = fread($fp, 4096)) { if (!xml_parse($parser, $data, feof($fp))) die(sprintf("Chyba XML %d %d", xml_get_current_column_number($parser))); }
xml_get_current_line_number($parser),
?>
2012-06-28
XML a PHP - parsování
5/5