Virtlab:Řídící server/XmlParser.php.inc
Z VirtlabWiki
Verze z 10:01, 12. 1. 2007 Vav166 (Diskuse | příspěvky) (→Popis parseru) ← Předchozí porovnání |
Verze z 22:52, 18. 2. 2007 Vav166 (Diskuse | příspěvky) Následující porovnání → |
||
Řádka 218: | Řádka 218: | ||
) | ) | ||
</pre> | </pre> | ||
+ | |||
=== Překvapující chovaní parseru === | === Překvapující chovaní parseru === | ||
Ve výpisu pole získaného z XML dokumentu si povšimněte, že na několika místech je <code>[content] => </code>. S překvapením jsem zjistil, že parser zpracuje i bílé znaky sloužící jen ke strukturování XML dokumentu (jde o znaky \n, \t, mezery, ...). | Ve výpisu pole získaného z XML dokumentu si povšimněte, že na několika místech je <code>[content] => </code>. S překvapením jsem zjistil, že parser zpracuje i bílé znaky sloužící jen ke strukturování XML dokumentu (jde o znaky \n, \t, mezery, ...). | ||
Proto je potřeba před vlastním spuštěním spuštěním parseru tyto znaky odstranit. Napsal jsem protu funkci, která toto zařídí: | Proto je potřeba před vlastním spuštěním spuštěním parseru tyto znaky odstranit. Napsal jsem protu funkci, která toto zařídí: | ||
+ | |||
<pre> | <pre> | ||
function ClearWhitespaceInXML($data) { | function ClearWhitespaceInXML($data) { | ||
Řádka 231: | Řádka 233: | ||
== Popis funkcí parseru == | == Popis funkcí parseru == | ||
- | ; function xmlParser() : konstruktor třídy xmlParser. Vytváří SAX parser, který je v PHP již implementován a registruje funkce pro zpětné volání | + | ; function __construct($validation=0) : konstruktor třídy v PHP5 |
+ | ; function virtlabXmlParser($validation=0) : konstruktor třídy virtlabXmlParser. Vytváří SAX parser, který je v PHP již implementován a registruje funkce pro zpětné volání. Parametrem lze nastavit, jestli se má XML ověřovat podle DTD v něm uvedeném - implementované ověření lze použít ''JEN'' v PHP5. | ||
; function parse($path) : funkce naparsování '''souboru'''. Výsledné pole je uloženo do <code>$this->output</code> | ; function parse($path) : funkce naparsování '''souboru'''. Výsledné pole je uloženo do <code>$this->output</code> | ||
; function parse_data($data) : funkce pro naparsování '''řetězce s XML daty'''. Výsledné pole je uloženo do <code>$this->output</code> | ; function parse_data($data) : funkce pro naparsování '''řetězce s XML daty'''. Výsledné pole je uloženo do <code>$this->output</code> | ||
Řádka 241: | Řádka 244: | ||
<pre> | <pre> | ||
<? | <? | ||
- | class xmlParser{ | + | class virtlabXmlParser { |
- | var $xml_obj = null; | + | private $xml_obj = NULL; |
- | var $output = array(); | + | private $attrs; |
- | var $attrs; | + | private $valid = 0; |
+ | public $output = array(); | ||
- | function xmlParser() { | + | function __construct($validition=0) { |
+ | $this->virtlabXmlParser($validition); | ||
+ | }//konstruktor PHP5 | ||
+ | |||
+ | private function virtlabXmlParser($validition=0) { | ||
$this->xml_obj = xml_parser_create(); | $this->xml_obj = xml_parser_create(); | ||
xml_set_object($this->xml_obj,$this); | xml_set_object($this->xml_obj,$this); | ||
xml_set_character_data_handler($this->xml_obj, "dataHandler"); | xml_set_character_data_handler($this->xml_obj, "dataHandler"); | ||
xml_set_element_handler($this->xml_obj, "startHandler", "endHandler"); | xml_set_element_handler($this->xml_obj, "startHandler", "endHandler"); | ||
- | }//function | + | $this->valid = $validition; |
+ | }//function | ||
- | function parse($path) { | + | public function parse($path) { |
if(!($fp = fopen($path, "r"))) { | if(!($fp = fopen($path, "r"))) { | ||
die("Cannot open XML data file: $path"); | die("Cannot open XML data file: $path"); | ||
return false; | return false; | ||
+ | } | ||
+ | if($this->validition) | ||
+ | { | ||
+ | $dom = new DOMDocument; | ||
+ | $dom->load($path); | ||
+ | if(!($dom->validate())) | ||
+ | die($path . " document is INvalid!\n"); | ||
+ | print("document is VALID"); | ||
} | } | ||
while ($data = fread($fp, 4096)) { | while ($data = fread($fp, 4096)) { | ||
Řádka 269: | Řádka 286: | ||
}//function | }//function | ||
- | function parse_data($data) { | + | public function parse_data($data) { |
+ | if($this->validition) { | ||
+ | $dom = new DOMDocument; | ||
+ | $dom->loadXML($data); | ||
+ | if(!($dom->validate())) | ||
+ | die("Document is INvalid!\n"); | ||
+ | } | ||
$new = utf8_encode($data); | $new = utf8_encode($data); | ||
if(!xml_parse($this->xml_obj, $data, 1)) { | if(!xml_parse($this->xml_obj, $data, 1)) { | ||
Řádka 275: | Řádka 298: | ||
xml_error_string(xml_get_error_code($this->xml_obj)), | xml_error_string(xml_get_error_code($this->xml_obj)), | ||
xml_get_current_line_number($this->xml_obj))); | xml_get_current_line_number($this->xml_obj))); | ||
- | } | + | } |
xml_parser_free($this->xml_obj); | xml_parser_free($this->xml_obj); | ||
return true; | return true; | ||
}//function | }//function | ||
- | /* funkce pro obluhu oteviraciho tagu | + | private function startHandler($parser, $name, $attribs) { |
- | * vytvari asociativni pole s polozkami "name" (obsahujici | + | |
- | * jmeno tagu) a polozku "attribs", ktera se naplni atributy | + | |
- | * tagu (asociativni pole - indexy jsou nazvy atributu) | + | |
- | */ | + | |
- | function startHandler($parser, $name, $attribs) { | + | |
$_content = array(); | $_content = array(); | ||
$_content['name'] = $name; | $_content['name'] = $name; | ||
Řádka 293: | Řádka 311: | ||
}//function | }//function | ||
- | /* funkce pro obsluhu dat tagu | + | private function dataHandler($parser, $data) { |
- | * vytvori asociativni polozku pole s nazvem "content" | + | |
- | */ | + | |
- | function dataHandler($parser, $data) { | + | |
if(!empty($data) && $data!="\n") { | if(!empty($data) && $data!="\n") { | ||
$_output_idx = count($this->output) - 1; | $_output_idx = count($this->output) - 1; | ||
Řádka 303: | Řádka 318: | ||
}//function | }//function | ||
- | /* funkce pro obsluhu uzaviraciho tagu | + | private function endHandler($parser, $name) { |
- | * vezme posledni polozku "zasobniku" a umisti ji do predchoziho | + | |
- | * prvku "zasobniku" do acociativni polozky "child" | + | |
- | */ | + | |
- | function endHandler($parser, $name) { | + | |
if(count($this->output) > 1) { | if(count($this->output) > 1) { | ||
$_data = array_pop($this->output); | $_data = array_pop($this->output); | ||
Řádka 320: | Řádka 331: | ||
?> | ?> | ||
</pre> | </pre> | ||
+ | |||
+ | [[Kategorie:PHP]] | ||
+ | [[Kategorie:Třída]] | ||
+ | [[Kategorie:Diplomová práce]] | ||
+ | [[Kategorie:Jan Vavříček]] |
Verze z 22:52, 18. 2. 2007
Obsah |
Popis základní myšlenky
Tato třída zajišťuje převod XML souborů na asociativní pole metodou SAX.
Tvorba pole probíha na principu "zásobníku". Postupně se při otevíracích značkách tvoří pole, která mají jen položku attribs vyplněnou polem atributu. Pokud se zpracovávají data značky, tak se vloží do položky pole content posledniho prvku (pole) "zásobniku". Funkce pro obsluhu uzavírací značky vyzvedne poslední položku "zásobníku" a vloží ji do předchozí položky zásobníku pod položku child. Tímto postupem se postupně tvoří strom polí, které obsahujé data z XML (pro výpis celé struktury lze použít funkci print_r).
Ukázka
Vzorová XML data
<?xml version="1.0" encoding="utf-8" ?> <equipment> <device type="router" name="r1" serial_number="12345-54321" platform="7200"> <os> <major>12</major> <minor>8</minor> </os> <interfaces> <interface technology="serial" connect_group="1" name="s0/1/1"> <max_bps>128000</max_bps> <int_feature>+++</int_feature> </interface> <interface technology="ethernet" ether_type="legacy" connect_group="2" name="e0"> <int_feature>802.1q</int_feature> </interface> </interfaces> <special> <feature>mpls</feature> <feature>+++</feature> <feature>***</feature> </special> </device> <device type="router" name="r3" serial_number="2345-5432"> <os> <major>12</major> <minor>6</minor> <other>321-ipsec:XXX</other> </os> <interfaces> <interface technology="serial" connect_group="1" name="s0"> <max_bps>64000</max_bps> </interface> <interface technology="ethernet" ether_type="fast" connect_group="3" name="fa0/0"> </interface> <interface technology="ethernet" ether_type="fast" connect_group="3" name="fa0/1"> </interface> </interfaces> </device> </equipment>
Výstup parseru (vytištěno pomocí funkce print_r)
Array ( [0] => Array ( [name] => EQUIPMENT [content] => [child] => Array ( [0] => Array ( [name] => DEVICE [attribs] => Array ( [TYPE] => router [NAME] => r1 [SERIAL_NUMBER] => 12345-54321 [PLATFORM] => 7200 ) [content] => [child] => Array ( [0] => Array ( [name] => OS [content] => [child] => Array ( [0] => Array ( [name] => MAJOR [content] => 12 ) [1] => Array ( [name] => MINOR [content] => 8 ) ) ) [1] => Array ( [name] => INTERFACES [content] => [child] => Array ( [0] => Array ( [name] => INTERFACE [attribs] => Array ( [TECHNOLOGY] => serial [CONNECT_GROUP] => 1 [NAME] => s0/1/1 ) [content] => [child] => Array ( [0] => Array ( [name] => MAX_BPS [content] => 128000 ) [1] => Array ( [name] => INT_FEATURE [content] => +++ ) ) ) [1] => Array ( [name] => INTERFACE [attribs] => Array ( [TECHNOLOGY] => ethernet [ETHER_TYPE] => legacy [CONNECT_GROUP] => 2 [NAME] => e0 ) [content] => [child] => Array ( [0] => Array ( [name] => INT_FEATURE [content] => 802.1q ) ) ) ) ) [2] => Array ( [name] => SPECIAL [content] => [child] => Array ( [0] => Array ( [name] => FEATURE [content] => mpls ) [1] => Array ( [name] => FEATURE [content] => *** ) ) ) ) ) [1] => Array ( [name] => DEVICE [attribs] => Array ( [TYPE] => router [NAME] => r3 [SERIAL_NUMBER] => 2345-5432 ) [content] => [child] => Array ( [0] => Array ( [name] => OS [content] => [child] => Array ( [0] => Array ( [name] => MAJOR [content] => 12 ) [1] => Array ( [name] => MINOR [content] => 6 ) ) ) [1] => Array ( [name] => INTERFACES [content] => [child] => Array ( [0] => Array ( [name] => INTERFACE [attribs] => Array ( [TECHNOLOGY] => ethernet [ETHER_TYPE] => fast [CONNECT_GROUP] => 3 [NAME] => fa0/1 ) [content] => ) ) ) ) ) ) ) )
Překvapující chovaní parseru
Ve výpisu pole získaného z XML dokumentu si povšimněte, že na několika místech je [content] =>
. S překvapením jsem zjistil, že parser zpracuje i bílé znaky sloužící jen ke strukturování XML dokumentu (jde o znaky \n, \t, mezery, ...).
Proto je potřeba před vlastním spuštěním spuštěním parseru tyto znaky odstranit. Napsal jsem protu funkci, která toto zařídí:
function ClearWhitespaceInXML($data) { $pattern = "/>\s+</"; $replacement = "><"; return preg_replace($pattern, $replacement, $data); }//function
Popis funkcí parseru
- function __construct($validation=0)
- konstruktor třídy v PHP5
- function virtlabXmlParser($validation=0)
- konstruktor třídy virtlabXmlParser. Vytváří SAX parser, který je v PHP již implementován a registruje funkce pro zpětné volání. Parametrem lze nastavit, jestli se má XML ověřovat podle DTD v něm uvedeném - implementované ověření lze použít JEN v PHP5.
- function parse($path)
- funkce naparsování souboru. Výsledné pole je uloženo do
$this->output
- function parse_data($data)
- funkce pro naparsování řetězce s XML daty. Výsledné pole je uloženo do
$this->output
- function startHandler($parser, $name, $attribs)
- funkce volaná pro otevírací značku XML elementu
- function dataHandler($parser, $data)
- funkce volaná pro data, které element obsahuje
- function endHandler($parser, $name)
- funkce volaná pro uzavírací značku XML elementu
Zdrojový kód
<? class virtlabXmlParser { private $xml_obj = NULL; private $attrs; private $valid = 0; public $output = array(); function __construct($validition=0) { $this->virtlabXmlParser($validition); }//konstruktor PHP5 private function virtlabXmlParser($validition=0) { $this->xml_obj = xml_parser_create(); xml_set_object($this->xml_obj,$this); xml_set_character_data_handler($this->xml_obj, "dataHandler"); xml_set_element_handler($this->xml_obj, "startHandler", "endHandler"); $this->valid = $validition; }//function public function parse($path) { if(!($fp = fopen($path, "r"))) { die("Cannot open XML data file: $path"); return false; } if($this->validition) { $dom = new DOMDocument; $dom->load($path); if(!($dom->validate())) die($path . " document is INvalid!\n"); print("document is VALID"); } while ($data = fread($fp, 4096)) { if(!xml_parse($this->xml_obj, $data, feof($fp))) { die(sprintf("XML error: %s at line %d", xml_error_string(xml_get_error_code($this->xml_obj)), xml_get_current_line_number($this->xml_obj))); } } xml_parser_free($this->xml_obj); return true; }//function public function parse_data($data) { if($this->validition) { $dom = new DOMDocument; $dom->loadXML($data); if(!($dom->validate())) die("Document is INvalid!\n"); } $new = utf8_encode($data); if(!xml_parse($this->xml_obj, $data, 1)) { die(sprintf("XML error: %s at line %d", xml_error_string(xml_get_error_code($this->xml_obj)), xml_get_current_line_number($this->xml_obj))); } xml_parser_free($this->xml_obj); return true; }//function private function startHandler($parser, $name, $attribs) { $_content = array(); $_content['name'] = $name; if(!empty($attribs)) $_content['attribs'] = $attribs; array_push($this->output, $_content); }//function private function dataHandler($parser, $data) { if(!empty($data) && $data!="\n") { $_output_idx = count($this->output) - 1; $this->output[$_output_idx]['content'] .= $data; } }//function private function endHandler($parser, $name) { if(count($this->output) > 1) { $_data = array_pop($this->output); $_output_idx = count($this->output) - 1; $add = array(); if(!$this->output[$_output_idx]['child']) $this->output[$_output_idx]['child'] = array(); array_push($this->output[$_output_idx]['child'], $_data); } }//function }//class ?>
Kategorie: PHP | Třída | Diplomová práce | Jan Vavříček