天天看點

php 處理 xml 之 解析

XML解析器的兩種基本類型:

基于樹型的解析器:将XML文檔轉換成樹型結構。這類解析器分析整篇文章,同時提供一個API來通路所産生樹的每個元素。其通用的标準為DOM(文檔對象模式)。

基于事件的解析器:将XML文檔視為一系列的事件。當一個特殊事件發生時,解析器将調用開發者提供的函數來處理。

不像基于樹型的解析器,基于事件的解析器不産生描述文檔的結構。在CDATA項中,基于事件的解析器不會讓你得到父元素的資訊。

然而,它提供一個更底層的通路,這就使得可以更好地利用資源和更快地通路。通過這種方式,就沒有必要将整個文檔放入記憶體;而事實上,整個文檔甚至可以大于實際記憶體值。

用于産生XML解析器執行個體的函數為xml_parser_create()。該執行個體将用于以後的所有函數。這個思路非常類似于PHP中MySQL函數的連 接标記。在解析文檔前,基于事件的解析器通常要求你注冊回調函數-用于特定的事件發生時調用。

它定義了如下七個可能事件:

對象 XML解析函數 描述 元素 xml_set_element_handler() 元素的開始和結束

字元資料 xml_set_character_data_handler() 字元資料的開始

外部實體 xml_set_external_entity_ref_handler() 外部實體出現

未解析外部實體 xml_set_unparsed_entity_decl_handler() 未解析的外部實體出現

處理指令 xml_set_processing_instruction_handler() 處理指令的出現

記法聲明 xml_set_notation_decl_handler() 記法聲明的出現

預設 xml_set_default_handler() 其它沒有指定處理函數的事件

所有的回調函數必須将解析器的執行個體作為其第一個參數(此外還有其它參數)。

元素的回調處理函數通過xml_set_element_handler()來注冊。

這個函數需要三個參數:

解析器的執行個體

處理開始元素的回調函數的名稱

處理結束元素的回調函數的名稱

當開始解析XML文檔時,回調函數必須存在。它們必須定義為與PHP手冊中所描述的原型一緻。

範例

<?  

// 第一個參數是XML檔案

$file = $argv[1];  

// 變量的初始化

$elements = $stack = array();  

$total_elements = $total_chars = 0;  

// 元素的基本類

class element  

{  

var $count = 0;  

var $chars = 0;  

var $parents = array();  

var $childs = array();  

}  

// 解析XML檔案的函數

function xml_parse_from_file($parser, $file)  

{  

if(!file_exists($file))  

{  

die("Can't find file "$file".");  

}  

if(!($fp = @fopen($file, "r")))  

{  

die("Can't open file "$file".");  

}  

while($data = fread($fp, 4096))  

{  

if(!xml_parse($parser, $data, feof($fp)))  

}  

fclose($fp);  

return(true);  

}  

// 輸出結果函數(方框形式)

function print_box($title, $value)  

{  

printf("

+%'-60s+

", "");  

printf("|%20s", "$title:");  

printf("%14s", $value);  

printf("%26s|

", "");  

printf("+%'-60s+

", "");  

}  

// 輸出結果函數(行形式)

function print_line($title, $value)  

{  

printf("%20s", "$title:");  

printf("%15s

", $value);  

}  

// 排序函數

function my_sort($a, $b)  

{  

return(is_object($a) && is_object($b) ? $b->count - $a->count: 0);  

}  

function start_element($parser, $name, $attrs)  

{  

global $elements, $stack;  

// 元素是否已在全局$elements數組中?

if(!isset($elements[$name]))  

{  

// 否-增加一個元素的類執行個體

$element = new element;  

$elements[$name] = $element;  

}  

// 該元素的記數器加一

$elements[$name]->count++;  

// 是否有父元素?

if(isset($stack[count($stack)-1]))  

{  

// 是-将父元素賦給$last_element

$last_element = $stack[count($stack)-1];  

// 如果目前元素的父元素數組為空,初始化為0

if(!isset($elements[$name]->parents[$last_element]))  

{  

$elements[$name]->parents[$last_element] = 0;  

}  

// 該元素的父元素記數器加一

$elements[$name]->parents[$last_element]++;  

// 如果目前元素的父元素的子元素數組為空,初始化為0

if(!isset($elements[$last_element]->childs[$name]))  

{  

$elements[$last_element]->childs[$name] = 0;  

}  

// 該元素的父元素的子元素記數器加一

$elements[$last_element]->childs[$name]++;  

}  

// 将目前的元素加入到棧中

array_push($stack, $name);  

}  

function stop_element($parser, $name)  

{  

global $stack;  

// 從棧中将最頂部的元素移去

array_pop($stack);  

}  

function char_data($parser, $data)  

{  

global $elements, $stack, $depth;  

// 增加目前元素的字元數目

$elements[$stack][count($stack)-1]]->chars += strlen(trim($data));  

}  

// 産生解析器的執行個體

$parser = xml_parser_create();  

// 設定處理函數

xml_set_element_handler($parser, "start_element", "stop_element");  

xml_set_character_data_handler($parser, "char_data");  

xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);  

// 解析檔案

$ret = xml_parse_from_file($parser, $file);  

if(!$ret)  

{  

die(sprintf("XML error: %s at line %d",  

xml_error_string(xml_get_error_code($parser)),  

xml_get_current_line_number($parser)));  

}  

// 釋放解析器

xml_parser_free($parser);  

// 釋放協助元素

unset($elements["current_element"]);  

unset($elements["last_element"]);  

// 根據元素的次數排序

uasort($elements, "my_sort");  

// 在$elements中循環收集元素資訊

while(list($name, $element) = each($elements))  

{  

print_box("Element name", $name);  

print_line("Element count", $element->count);  

print_line("Character count", $element->chars);  

printf("

%20s

", "* Parent elements");  

// 在該元素的父中循環,輸出結果

while(list($key, $value) = each($element->parents))  

{  

print_line($key, $value);  

}  

if(count($element->parents) == 0)  

{  

printf("%35s

", "[root element]");  

}  

// 在該元素的子中循環,輸出結果

printf("

%20s

", "* Child elements");  

while(list($key, $value) = each($element->childs))  

{  

print_line($key, $value);  

}  

if(count($element->childs) == 0)  

{  

printf("%35s

", "[no childs]");  

}  

$total_elements += $element->count;  

$total_chars += $element->chars;  

}  

// 最終結果

print_box("Total elements", $total_elements);  

print_box("Total characters", $total_chars);  

?>

http://phpup.com/phparticle/show-article-688/