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.

Pustíme sa teda do samotného vyhľadávania v stromovej štruktúre. Budeme uvažovať jednak vyhľadávanie v rámci dcérskych uzlov ako sme si to ukázali už v predchádzajúcom článku v implementácii metódy children($name) (tento kód si sem preberieme a metódu upravíme) avšak pridáme vyhľadávanie v celej hierarchii dcérskych uzlov, ktoré bude možné nastaviť pomocou parametra $recursive. Taktiež do vyhľadávanie zakomponujeme možnosť vyhľadávať na základe hodnoty atribútu. Vstupom v premennej $name teda bude môcť byť jednak len názov elementu ale i názov elementu s názvom a hodnotou atribútu. Z predchádzajúceho príkladu teda pre nájdenie elementu book s atribútom id=0 zadáme reťazec "book[id=0]".

Doplníme si teda metódu _find($name, $recursive=false) a upravíme existujúcu metódu children($name) takto:

XMLElement.php
  /* vrati dcerske elementy
* $name - pri nastaveni vracia pole dcerskych elementov daneho nazvu
* $name moze byt v tvare name[attr=value], kde name je nazov elementu,
* attr je nazov atributu a value jeho hodnota
* $recursive - pre true vyhladava v celom strome elementu
*/

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

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

return $children;
}else{
return $this->_find($name, $recursive);
}
}

// vyhladava rekurzivne v celom strome, ide len o volanie metody _find s $recursive=true
protected function _findAll($name){
return $this->_find($name, true);
}

/* vrati dcerske elementy s nazvom $name
* $name - pri nastaveni vracia pole dcerskych elementov daneho nazvu
* $name moze byt v tvare name[attr=value], kde name je nazov elementu,
* attr je nazov atributu a value jeho hodnota
* $recursive - pre true vyhladava v celom strome elementu
*/

protected function _find($name, $recursive=false){
$ret=array(); //zoznam najdenych elementov
$attr=NULL;
$attrVal=NULL;

//zisti, ci je nastaveny atribut
if (preg_match('/(w+)[(w+)=(w+)]/', $name, $matches)){
$name=$matches[1];
$attr=$matches[2];
$attrVal=$matches[3];

}

//vyhladavanie v strome
foreach ($this->_children[$name] as $child){
//nie je atibutove vyhladavanie alebo sa atribut musi rovnat
if (!$attr || $child->attr($attr) == $attrVal){

//rekurzivne volanie
if ($recursive){
$xret=$child->children($name, $recursive);

if (!empty($xret))
$ret=array_merge($xret, $ret);

}else{
$ret[]=$child;
}
}
}

return $ret;
}


Ako ste si mohli všimnúť, pridali sme aj chránenú metódu _findAll($name), ktorá vlastne predstavuje volanie metódy v tvare _find($name, true).

Vyhľadávanie v strome teda máme hotové a dostávame sa k otázke samotného parsovania XML reťazca. Parsovať budeme volaním statickej metódy, ktorej vstupom bude XML reťazec. Tá sa bude starať o vytvorenie koreňového uzla stromu a nastavenie hodnôt tohto objektu spracovaním reťazca pomocou regulárneho výrazu. Ten použijeme na rozsekanie XML reťazca na samotný element s jeho atribútmi a časť reťazca s dcérskymi elementami. Samotné nastavenie XML obsahu elementu prebehne v metóde content($xml=NULL), ktorú sme už spomínali v predchádzajúcom článku. V rámci nej pri nastavení parametru prebehne opäť parsovanie XML obsahu a nastavenie dcérskych elementov rovnakým spôsobom, pričom ale bude hľadať v reťazci nie jeden element, ale všetky dcérske elementy a následne ich atribúty. To sa bude vykonávať rekurzívne, tj. pri vytvorení dcérskeho elementu sa uňho opäť zavolá táto metóda.

XMLElement.php
  function content($xml=NULL){
if (!isset($xml))
return $this->_content;

if (self::$_saveContent)
$this->_content=$xml;

//najde vsetky dcerske elementy, ak nenaslo, konci
if (!preg_match_all('/<([w]+)([^>]*?)s*>(([^<]*?|(?R)|.)*?)</s*1s*>/is', $xml, $matches, PREG_SET_ORDER)){
if (!self::$_saveContent)
$this->_content=$xml;

return $this;
}

//spracuje dcerske elementy
foreach ($matches as $match){
$element=new XMLElement($match[1], $this);

//ziska a nastavi hodnoty atributov kazdeho elementu
if (isset($match[2]) && preg_match_all('/([^s>]+)s*=s*("|')(.*?)2/is', $match[2], $params, PREG_SET_ORDER)){
foreach ($params as $p)
$element->attr($p[1], $p[3]);
}

$element->content($match[3]);
$this->addChild($element);
}

return $this;
}

static function parse($xml, $debug=false){
//korenovy element
if (!preg_match('/<([w]+)([^>]*?)>(([^<]*?|(?R)|.)*?)</s*1s*>/is', $xml, $matches))
return false;

$parent=new XMLElement($matches[1]);

//jeho pripadne atributy
if (isset($matches[2]) && preg_match_all('/([^s>]+)s*=s*("|')(.*?)2/is', $matches[2], $params, PREG_SET_ORDER)){
foreach ($params as $p)
$parent->attr($p[1], $p[3]);
}

$parent->content($matches[3]);

return $parent;
}


Tak a náš XML parser je hotový. Nakoniec si ho ešte otestujeme na vstupe z predchádzajúceho článku

<?php
//$xml - obsahuje XML retazec z prechadzajuceho clanku

XMLElement::saveContent(true);
$library=XMLElement::parse($xml);

$book1=$library->children('book[id=1]')[0];
echo $book1 . PHP_EOL;
echo $library->children('title', true)[0] . PHP_EOL;
echo "----------" . PHP_EOL;
print_r($book1->childrenNames());
echo $library->childrenCount() . PHP_EOL;
echo "----------" . PHP_EOL;
echo $library->city . PHP_EOL;
echo $library->book[0]->title . PHP_EOL;
?>


Výstup kódu môžete vidieť tu:

  

<title>Tulák po hviezdach</title>
<author>Jack London</author>

Morský vlk
----------
Array
(
[0] => title
[1] => author
)
3
----------
Brno
Morský vlk


Samotnú triedu si môžete celú stiahnuť tu.


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