Tvorba XML parseru - 1.časť

___

V tejto sérii článkov sa pozrieme na to, ako vytvoriť triedu pre prácu s XML dokumentami. Konkrétne sa budeme zaoberať vytvorením triedy, ktorá sa bude starať o parsovanie XML dokumentu, a ktorej objekty budú reprezentovať tieto XML dáta a budú umožňovať prístup k dátam, sekvenčné prechádzanie dát či vyhľadávanie v štruktúre.

Začneme vytvorením triedy, ktorá bude reprezentovať XML element. Objekty tejto triedy budeme usporiadavať do stromovej štruktúry, kde jeden uzol stromu bude vždy zodpovedať jednému elementu spolu s jeho atribútmi. Pre vysvetlenie si zvoľme ukážkový XML súbor:

example.xml
<library capacity=100>
<book id="0">
<title>Morský vlk</title>
<author>Jack London</author>
<year>1904</year>
</book>
<book id="1">
<title>Tulák po hviezdach</title>
<author>Jack London</author>
</book>
<city>Brno</city>
</library>


Pri spracovaní sa teda vytvorí stromová štruktúra prvkov, kde koreň bude predstavovať objekt typu library s atribútom capacity.
Tento rodičovský objekt bude teda okrem spomenutého atribútu obsahovať aj pole objektov typu book a objekt typu city. Prvý objekt typu book bude obsahovať 3 elementy (id, title a author) bez dcérskych elementov. Obdobne bude vytvorený i druhý objekt typu book.

Našim cieľom bude čo najjednoduchšia práca s objektami, takže sa budeme snažiť čo najviac eliminovať množstvo volaných metód, či už metód na načítanie dcérskych elementov alebo atribútov. Taktiež zavedieme inteligentné rozpoznanie, či je možné vrátiť prvok ako objekt, alebo je nutné vrátiť pole elementov.

Navrhneme teda základ triedy s názvom XMLElement. Dcérske elementy pritom budeme ukladať do asociatívneho poľa, kde kľúč bude predstavovať typ elementu a hodnota bude pole týchto elementov (objektov či hodnôt). Urýchlime si tak prácu pri vyhľadávaní prvkov, či vyhľadávaní v strome. Pri atribútoch pôjde o asociatívne pole názov atribútu => hodnota. Súčasne pre účely prehľadávania štruktúry si vytvoríme odkaz na rodičovský element.

XMLElement.php
class XMLElement{
protected $_name;
protected $_attributes;
protected $_children;
protected $_parent;
protected $_content;

static protected $_saveContent=false;


Nakoniec sme pripojili statický atribút, ktorý nám umožní nastaviť, či pri každom elemente chceme ukladať jeho obsah (v XML formáte) alebo budeme uchovávať tento obsah len pri listových (koncových) elementov stromu. K správe tohto atribútu si pripravíme metódu saveContent($save=NULL), ktorá na základe toho, či je parameter metódy nastavený, bude rozlišovať, či ide o nastavenie hodnoty, alebo jej získanie.

Do triedy si doplníme konštruktor, ktorý nastaví názov elementu a súčasne inicializuje polia atribútov a dcérskych elementov. Súčasťou bude tiež nastavenie rodiča elementu, pričom, samozrejme, pri koreňovom uzly ponecháme hodnotu nenastavenú. Rovno si pripravíme i metódu na získanie tejto hodnoty rodiča.

XMLElement.php
  /* vytvori objekt typu XMLElement
* $name - nazov elementu
* $parent - rodicovsky element
*/

function __construct($name, $parent=NULL){
$this->_name=$name;
$this->_attributes=array();
$this->_children=array();
$this->_parent=$parent;
$this->_content='';
}

//vrati rodicovsky element
function getParent(){
return $this->_parent;
}

/* nastavi, ci sa bude ukladat cely XML obsah daneho elementu
* pre false sa uklada len v listovych uzloch stromu
* $save - ukladat obsah? [true/false]
*/

function saveContent($save=NULL){
if (!isset($save))
return self::$_saveContent;
else
self::$_saveContent=$save;
}


V ďaľšom kroku sa pozrieme na magické metódy PHP tried. Pre získanie obsahu elementu vo formáte XML si uľahčíme prácu tak, že nebude nutné volať metódu, ktorá obsah vráti, ale jednoducho bude stačiť zavolať echo na daný objekt. To zvládneme pomocou magickej metódy __toString() v ktorej využijeme práve metódu na získanie obsahu elementu (pripravíme si ju nižšie).

Ďaľšie magické metódy ktoré použijeme sú __get() a __set(), pomocou ktorých získame prístup k atribútom a elementom objektu bez volania akejkoľvek metódy, ale len prostým použitím atribútu objektu. Napríklad pre objekt elementu library sa k elementu city dostaneme ako

$library->city;
//vypis hodnoty vdaka magickej metode __toString():
echo $library->city;
//eqvivalentne no komplikovane volanie, ako si ukazeme nizsie:
echo $library->children('city')->content();


V implementácii využijeme metódu children($name), ktorú si pripravíme nižšie, a bude sa starať o vyhľadávanie atribútov v strome. Samotná implementácia bude vyzerať takto:

XMLElement.php
  //magicka metoda umoznuje volat echo na cely objekt, vrati XML obsah elementu
function __toString(){
return $this->content();
}

/* magicka metoda pri volani atribudu objektu vrati atribut elementu alebo
* dcersky element (XMLElement) ci elementy (array) podla nazvu $name
* $name - nazov dcerskeho elementu alebo atributu
*/

function __get($name){
if (isset($this->_attributes[$name]))
return $this->_attributes[$name];

$find=$this->children($name);
if (count($find) > 1)
return $find;
else
return $find[0];
}

/* magicka metoda pri volani atribudu objektu nastavi atribut elementu
* metoda neumoznuje nastavi dcersky element pomocou tohto volania, vzdy
* nastavuje len atribut
* $name - nazov atributu
* $value - hodnota
*/

function __set($name, $value){
if (isset($this->_attributes[$name]))
$this->attr($name, $value);
else
return;
}


Následne si pripravíme metódy k nastaveniu a získaniu hodnôt elementu. Rovnako, ako u metódy getContent() bude jedna metóda realizovať setter aj getter daného atribútu. Ďaľšia metóda sa bude starať o správu atribútov. Definujeme si ju attr($name, $value=NULL), kde na základe nastavenia druhého parametru budeme rozpoznávať, či hodnotu atribútu získavame alebo nastavujeme. Pripravíme si tiež metódu addChild($child), ktorá pridá objekt XMLElement k nášmu elementu ako dcérsky uzol. Ako sme si vyššie povedali, pridá ho do asociatívneho poľa. Samotná implementácia metód bude vyzerať nasledovne

XMLElement.php
  //vrati nazov elementu, pripadne pri nastaveni parametra $name ho na tuto hodnotu nastavi
function name($name=NULL){
if (!isset($name))
return $this->_name;
else
$this->_name=$name;

return $this;
}

//vrati hodnotu atributu $name, pripadne pri nastaveni parametra $value ho na tuto hodnotu nastavi
function attr($name, $value=NULL){
if (!isset($value)){
if (isset($this->_attributes[$name]))
return $this->_attributes[$name];
else
return NULL;

}else{
$this->_attributes[$name]=$value;
return $this;
}
}

//prida element $child ako dcersky element
function addChild($child){
if (isset($this->_children[$child->name()]))
$this->_children[$child->name()][]=$child;
else
$this->_children[$child->name()]=array($child);
}


Nakoniec sa v tomto diely pozrieme na metódy, ktoré sa starajú o prístup k dcérskym elementom a k údajom o nich. Vytvoríme si metódu children($name=NULL), ktorá nám pri nastavení parametra vráti všetky dcérske elementy s daným tagom, alebo vráti úplne všetky elementy. Ďaľšie dve metódy nám budú slúžiť na získanie názvov dcérskych elementov (childrenNames()), a počtu dcérskych elementov celkovo, alebo daného názvu metódou childrenCount($name=NULL).

XMLElement.php
  //vrati nazvy dcerskych elementov
function childrenNames(){
$names=array();

return array_keys($this->_children);
}

/* vrati pocet dcerskych elementov
* $name - pri nastaveni vracia pocet dcerskych elementov daneho mena
*/

function childrenCount($name=NULL){
$names=array();

if (isset($name))
return count($this->_children[$name]);

$count=0;
foreach ($this->_children as $childSet)
$count+=count($childSet);

return $count;
}

/* vrati dcerske elementy
* $name - pri nastaveni vracia pole dcerskych elementov daneho nazvu
*/

function children($name=NULL, $recursive=false){
if (!isset($name)){
$children=array();

foreach ($this->_children as $childSet)
$children=array_merge($children, $childSet);

return $children;
}else{
if (!isset($this->_children[$name]))
return false;

return $this->_children[$name];
}
}


V ďaľšom diely sa pozrieme na to, ako v stromovej štruktúre vyhľadávať, ako parsovať XML súbory do tejto štruktúry, a prípadne na nejaké rozšírenia tried. Ostáva nám taktiež definovanie metódy content($name=NULL), ktorá sa bude starať o získavanie a nastavenie XML obsahu elementu.


Posledné príspevky

___

miniature-article

Verejná databáza emailov, tel. čísel a adries alebo CKM SYTS

Asi každý poznáme karty ISIC, ITIC či Euro26. A väčšina z nás ju aj vlastní či vlastnila, ak sme študovali na VŠ či aktuálne študujeme na SŠ/VŠ. Všetko to má pod palcom združenie CKM SYTS, ktoré vlastní licencie na vydávanie týchto preukazov. Čo ma ale zaujalo, resp. je správnejšie povedať - pohoršilo - je spôsob, akým toto združenie umožňuje každému, kto pozná Vaše meno a dátum narodenia prístup k Vašim osobným údajom. ..čítať ďalej!

miniature-article

Tvorba XML parseru - 2.časť

Tak a je tu pokračovanie článku v ktorom si ukážeme, ako vytvoriť XML parser. V minulom článku sme si ukázali, ako vytvoriť základnú triedu XML elementu. V tomto článku sa pozrieme na vyhľadávanie vo vytvorenej stromovej štruktúre a nakoniec samozrejme, ako takýto XML dokument previesť do stromovej štruktúry objektov nášho typu XMLElement. ..čítať ďalej!

miniature-article

NAS server na Raspberry Pi - konfigurácia a Samba - 2.časť

V tomto druhom článku série článkov o vytvorení NAS servra na Raspberry Pi sa pozrieme priamo na konfiguráciu Raspberry, pripravíme úložisko a nakonfigurujeme Sambu. ..čítať ďalej!

miniature-article

Tvorba XML parseru - 1.časť

V tejto sérii článkov sa pozrieme na to, ako vytvoriť triedu pre prácu s XML dokumentami. Konkrétne sa budeme zaoberať vytvorením triedy, ktorá sa bude starať o parsovanie XML dokumentu, a ktorej objekty budú reprezentovať tieto XML dáta a budú umožňovať prístup k dátam, sekvenčné prechádzanie dát či vyhľadávanie v štruktúre. ..čítať ďalej!

miniature-article

NAS server na Raspberry Pi - hardware a výroba obalu - 1.časť

Túto sériu článkov zameranú na komplenté vytvorenie NAS serveru pomocou Raspberry Pi začnem netradične výrobou obalu. Obal na Raspberry Pi je na internete často riešená téma, pričom sa dá nájsť množstvo kreatívnych riešení. My sa ale pozrieme, ako vyrobiť obal tak, aby nám nakoniec vzniklo púzdro na celý mini server, nie len obal na samotné Raspberry. Taktiež si v krátkosti povieme, čo budeme potrebovať ako základ mimo samotného Raspberry. ..čítať ďalej!

miniature-article

Ako nastaviť práva na LAMP servry s FTP prístupom

Jedným z prvých problémov pri vytváraní LAMP servra na RaspberryPi bolo vyriešenie problému práv pri prácu so súbormip omocou FTP (konkrétne vsftpd). Následne s týmito súbormi alebo v týchto zložkách pracoval Apache čím dochádzalo ku konfliktom, pokiaľ sme nenastavili práva čítať a zapisovať rovnako pre všetkých (čo ale s najväčšou pravdepodobnosťou nechceme:) ). V tomto článku vytvetlím, ako tento problém vyriešiť. ..čítať ďalej!

miniature-article

Mini obrazovka k Raspberry Pi

Nedávno som sa zamýšľal nad ďalším možným využitím Raspberry Pi a napadlo ma využitie ako monitorovacej / informačnej stanice, kde pomocou obrazovky budem môcť nonstop sledovať údaje o stave webového serveru, ktorý mi na ňom beží, návštevnosti ale i stav emailovej schránky či informácií o počasí. Pokiaľ Vás takéto či podobné využitie Vášho Raspberry zaujalo, tak v tomto článku Vám poviem, čo (a ako) si zohnať všetko potrebné a ako si Raspberry nakonfigurovať. ..čítať ďalej!

Navrch Navrch stránky