XML pro web aneb od teorie k praxi, 16.díl - XML parser v PHP

Podpora XML v PHP má několik tváří. Dnešní díl seriálu bude věnován zřejmě "služebně nejstaršímu" způsobu, který nám dovoluje pracovat s XML daty v PHP - funkcím XML parseru. Oproti DOM rozhraní, kterému jsme se ve spojitosti s Javascriptem věnovali v předchozích kapitolách, dnes poznáme zpracování XML doslova nízkoúrovňové.

Dříve, než se začneme věnovat konkrétním funkcím, které řídí parsování XML dokumentu v PHP, bude možná na místě krátké seznámení s principem tohoto XML parseru. Při analyzování prochází parser určený XML dokument od začátku do konce - pokaždé, když narazí na určitou specifickou část XML dokumentu (začátek elementu, konec elementu, znaková data...), předá příslušná data ke zpracování zaregistrovaným funkcím. Tyto funkce mohou být zcela libovolné, záleží jen na naší potřebě, kterak hodláme zpracovávat data XML dokumentu. Tomuto přístupu analyzování dokumentu se říká událostně-řízené (event-driven).

Oproti událostně řízeným parserům stojí DOM parsery. Abychom mohli využívat DOM rozhraní, musí parser napřed vytvořit DOM reprezentaci XML dokumentu - to obnáší analýzu celého dokumentu a rekonstrukci celé hierarchické struktury dokumentu. Je asi jasné, že použití DOM rozhraní je obecně paměťově náročnější a také pomalejší, než prostá událostně řízená analýza. Tuto nevýhodu vyvažuje velice komfortní práce s DOM pomocí standardních metod a vlastností a také to, že s XML dokumentem již jednou načteným můžeme dále libovolně pracovat a měnit jej bez nutnosti nového parsování.

V PHP si můžeme vybrat, který způsob práce s XML dokumentem zvolíme (událostně orientovaný parser, nebo DOM objektové rozhraní, o kterém bude řeč v příštích dílech), proto využívejme každý ze způsobů tam, kde oceníme jeho silné stránky. Pokud potřebujeme pouze získat data z XML dokumentu, máme zvýšené požadavky na výkon aplikace, nebo potřebujeme zpracovávat XML dokument velmi specifickým způsobem, zvolíme funkce XML parseru. Pokud potřebujeme vytvářet či modifikovat XML dokument "za chodu", přistupovat k němu opakovaně, nebo potřebujeme řešit jednoduchou úlohu během pár řádků kódu (aniž bychom vytvářeli XML parser kvůli zjištění textového obsahu dvou elementů) a aplikace není kriticky zatěžována, použijeme DOM XML funkce.

Vytvoření XML parseru

XML parser v PHP vytvoříme pomocí funkce xml_parser_create(). Funkce přijímá jediný volitelný argument, kterým je kódování zdrojového XML dokumentu. Přípustná jsou tato kódování: UTF-8, ISO-8859-1 a US-ASCII. Výchozí kódování je ISO-8859-1. Funkce vrací identifikátor XML parseru (resource), který poté použijeme u dalších funkcí XML parseru.

$XmlP = xml_parser_create(`UTF-8`);

Registrace zpracovávacích funkcí (ovladačů)

Obsluha elementů

Po vytvoření parseru můžeme zaregistrovat funkce, které budou obsluhovat analýzu - tyto námi vytvořené funkce budou dostávat data od XML parseru. Obsluhu elementů zaregistrujeme funkcí xml_set_element_handler(). Této funkci předáme tři parametry. První je identifikátor XML parseru, druhým je název naší funkce, která se bude starat o obsluhu počátečního tagu elementu a třetí je název funkce, která bude zpracovávat koncový element.

xml_set_element_handler($XmlP, `funkceProObsluhuStartTagu`, funkceProObsluhuEndTagu`);

Funkce, které registrujeme pro obsluhu počátečního a koncového tagu elementu, musíme definovat v kódu dříve, než bude parser spuštěn. Tyto funkce nemohou být úplně libovolné - musí splňovat určitá kriteria. Tyto podmínky jsou dány tím, že naše funkce bude od XML parseru dostávat přesně určená data. Funkce pro obsluhu počátečního tagu musí přijímat tři parametry - identifikátor XML parseru, jméno elementu (string) a asociativní pole všech atributů (název atributu => hodnota atributu). Funkce pro obsluhu koncového tagu musí akceptovat dva parametry - identifikátor XML parseru a jméno elementu. Uveďme si příklady těchto obslužných funkcí.

function funkceProObsluhuStartTagu($XmlP, $name, $attrs)
{
	echo `jmeno tagu: `.$name.`<br>`;
	if(count($attrs)>0)
	{
		echo `atributy:<br>`;
		foreach($attrs as $a_name => $a_value)
		{
			echo `jmeno: `.$a_name.`, `;
			echo `hodnota: `.$a_value.`<br>`
		}
	}
}

function funkceProObsluhuEndTagu($XmlP, $name)
{
	echo `konec elementu `.$name.`, radek: `;
	echo xml_get_current_line_number($XmlP);
}

Funkce uvedené v příkladu neprovádějí nic složitého - první z nich pouze vypisuje jméno elementu a jména a hodnoty všech atributů. Druhá ukazuje použití funkce xml_get_current_line_number(), která vrací aktuální čídlo řádku XML dokumentu, který je parsován. Jako parametr je nutné udat identifikátor XML parseru.

Obsluha znakových dat

Kromě samotných elementů, které jsou nosným pilířem struktury celého XML dokumentu, asi budeme potřebovat zpracovávat také text obsažený v elementech. Obslužnou funkci pro znaková data (textový obsah elementu) zaregistrujeme pomocí funkce xml_set_character_data_handler() a pomocí dvou parametrů - prvním je identifikátor XML parseru a druhým je název obslužné funkce.

xml_set_character_data_handler($XmlP, `funkceProObsluhuTextu`);

Stejně jako u obslužných funkcí pro element, i uživatelská funkce, která obsluhuje textová data, musí přijímat určité parametry - není těžké uhodnout, že v tomto případě bude prvním paramterem opět identifikátor XML parseru a druhým budou samotná textová data.

function funkceProObsluhuTextu($XmlP, $text)
{
	echo `<em>`.$text.`</em><br>`;
}

Obsluha procesních instrukcí

Obsahuje-li XML dokument procesní instrukce (například blok PHP kódu), není problém ji "odchytit". Musíme ale zaregistrovat obslužnou funkci pro procesní instrukce. Tato funkce nese název xml_set_processing_instruction_handler() a přijímá klasické dva parametry - identifikátor XML parseru a název obslužné funkce.

xml_set_processing_instruction_handler($XmlP, `funkceProObsluhuProcInstr`);

Obslužná funkce musí mít tři paramtry - kromě obligátního identifikátoru XML parseru je to PI target (např. php v případě bloku PHP kódu) a samotný kód procesní instrukce. Pokud se jedná o procesní instrukci jazyka PHP, není problém tento kód vykonat pomocí eval().

function funkceProObsluhuProcInstr($XmlP, $PItarget, $code)
{
	if(strtolower($PItarget)==`php)
	{
		eval($code);
	}
}

Výchozí obsluha

Chceme-li zachytit kteroukoliv část XML dokumentu, kterou neobsluhují žádné naše funkce, můžeme provést registraci funkce sloužící jako výchozí ovladač. Uděláme to pomocí funkce xml_set_default_handler(). Funkce přijímá dva parametry (identifikátor XML parseru a název obslužné funkce), stejně tak dva parametry se předávají obslužné funkci (identifikátor a data příslušné části XML dokumentu v podobě textového řetězce). Pokud jsme zaregistrovali výchozí obslužnou funkci, bude tato volána pokaždé, s výjimkou událostí příslušejících jiným obslužným funkcím, které byly registrovány pro obsluhu konkrétnějších událostí.

xml_set_default_handler($XmlP, `funkceProVychoziObsluhu`);

function funkceProVychoziObsluhu($XmlP, $data)
{
	//libovolny kod...
}

Možnosti registrace funkcí pro obsluhu událostí jsme tímto ještě nevyčerpali - pro začátek si s výše uvedenými vystačíme a zbývající si necháme na příště.

Analýza XML dokumentu

Samotné parsování se spouští za pomoci funkce xml_parse(). Funkce přijímá tři parametry - identifikátor XML parseru, kus dat XML dokumentu k analýze a volitelný boolean parametr, který je nutné nastavit na true, pokud se jedná o poslední blok dat k parsování. Následující kód ukazuje parsování dokumentu po blocích dat 4 kB velkých.

$fp = fopen(`dokument.xml`,`r`);
while ($data = fread($fp, 4096)) {
    xml_parse($XmlP, $data, feof($fp));     
}

Pomocí funkce xml_parser_free() uvolníme parser po proběhnutí analýzy. Jediným parametrem funkce je identifikátor parseru.

xml_parser_free($XmlP);

Použití funkcí XML parseru v objektu

Potřebujeme-li používat funkce XML parseru v objektu (docela výhodné může být vytvoření vlastní třídy pro parser), dostaneme se k problému, jakým způsobem zaregistrovat obslužné funkce, které jsou členskými metodami objektu. K tomuto účelu slouží funkce xml_set_object(), která má 2 parametry - identifikátor parseru a odkaz na objekt, jehož členské metody hodláme registrovat jako obslužné funkce. Poté už můžeme nerušeně registrovat názvy metod objektu jako obslužné funkce. Uveďme si krátký příklad (inspirovaný PHP manuálem).

class XML_parser
{
	var $XmlP;
	
	//konstruktor
	function XML_parser() {
		$this->XmlP = xml_parser_create();
		xml_set_object($this->XmlP, &$this);
		xml_set_element_handler($this->XmlP, "tag_open", "tag_close");
		xml_set_character_data_handler($this->XmlP, "cdata");
	}

	//obsluzne metody
	function tag_open($parser, $tag, $attributes) { 
		var_dump($parser, $tag, $attributes); 
	}
	
	function tag_close($parser, $tag) {
		var_dump($parser, $tag);
	}
	
	function cdata($parser, $cdata) {
		var_dump($parser, $cdata);
	}
	
	//parsovani
	function parse($data) { 
		xml_parse($this->parser, $data);
	}
}

Příště si ukážeme další možnosti XML parseru v PHP.

Váš názor Další článek: Internetové stránky televize Al-Džazíra hacknuty!

Témata článku: Software, Programování, PHP, Code, Pre, Element, První parametr, Určitý objekt, Echo, Kody, Parse, XML, Teorie, Jednoduchá rekonstrukce, Funkce, Doma, Specifický způsob

Určitě si přečtěte


Aktuální číslo časopisu Computer

Zachraňte nefunkční Windows

Jak nakupovat a prodávat kryptoměny

Otestovali jsme konvertibilní notebooky

Velký test 14 herních myší