天天看点

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/