Virtlab:Řídící server/XmlParser.php.inc

Z VirtlabWiki

(Rozdíly mezi verzemi)
Přejít na: navigace, hledání
Verze z 10:16, 22. 10. 2007
Vav166 (Diskuse | příspěvky)

← Předchozí porovnání
Verze z 11:39, 22. 10. 2007
Vav166 (Diskuse | příspěvky)

Následující porovnání →
Řádka 332: Řádka 332:
</pre> </pre>
 +[[Kategorie:Komponenty virtlabu]]
 +[[Kategorie:Server]]
 +[[Kategorie:Řídící server]]
[[Kategorie:PHP]] [[Kategorie:PHP]]
[[Kategorie:XML]] [[Kategorie:XML]]
[[Kategorie:Třída]] [[Kategorie:Třída]]
 +[[Kategorie:UNCOMPLETE]]

Verze z 11:39, 22. 10. 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
private 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.
public function parse($path) 
funkce naparsování souboru. Výsledné pole je uloženo do $this->output
public function parse_data($data) 
funkce pro naparsování řetězce s XML daty. Výsledné pole je uloženo do $this->output
private function startHandler($parser, $name, $attribs) 
funkce volaná pro otevírací značku XML elementu
private function dataHandler($parser, $data) 
funkce volaná pro data, které element obsahuje
private 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
?>
Osobní nástroje