专注于互联网--专注于架构

最新标签
网站地图
文章索引
Rss订阅

首页 »PHP教程 » php函数:php的xml分析函数 »正文

php函数:php的xml分析函数

来源: 发布时间:星期一, 2009年1月12日 浏览:31次 评论:0
  首先我得承认我喜欢计算机标准如果每个人都遵从这个行业标准互联网将会是个更好媒体使用标准化数据交换格式才能使开放和独立于平台计算模式切实可行这就是我作为XML爱好者原因

  幸运我最喜爱脚本语言不但支持XML而且对其支持正不断加强PHP可以让我迅速将XML文档发布到互联网上收集XML文档统计信息将XML文档转换成其它格式例如我时常用PHPXML处理能力来管理我用XML所写文章和书

  本文中我将讨论任何用PHP内建Expat解析器来处理XML文档通过范例我将演示Expat处理思路方法同时范例可以告诉你如何:

  建立你自己处理 

  将XML文档转换成你自己PHP数据结构

  介绍Expat

  XML解析器同样称为XML处理器可以使访问XML文档结构和内容Expat是PHP脚本语言XML解析器它同时也运用在其它项目中例如Mozilla、Apache和Perl

  什么是基于事件解析器?

  XML解析器两种基本类型:

  基于树型解析器:将XML文档转换成树型结构这类解析器分析整篇文章同时提供个API来访问所产生树每个元素其通用标准为DOM(文档对象模式) 

  基于事件解析器:将XML文档视为系列事件个特殊事件发生时解析器将开发者提供来处理 

  基 于事件解析器有个XML文档数据集中视图也就是说它集中在XML文档数据部分而不是其结构这些解析器从头到尾处理文档并将类似于-元素 开始、元素结尾、特征数据开始等等-事件通过回调(callback)报告给应用以下是个"Hello-World"XML文档范例:

  <greeting> 

  Hello World 

  </greeting> 

  基于事件解析器将报告为 3个事件:

  开始元素:greeting 

  CDATA项开始值为:Hello World 

  结束元素:greeting 

  不像基于树型解析器基于事件解析器不产生描述文档结构在CDATA项中基于事件解析器不会让你得到父元素greeting信息

  然而它提供个更底层访问这就使得可以更好地利用资源和更快地访问通过这种方式就没有必要将整个文档放入内存;而事实上整个文档甚至可以大于实际内存值

  Expat就是这样种基于事件解析器当然如果使用Expat必要时它样可以在PHP中生成完全原生树结构

  上面Hello-World范例包括完整XML格式但它是无效既没有DTD(文档类型定义)和其联系也没有内嵌DTD

  对于Expat这并没有区别:Expat是个不检查有效性解析器因此忽略任何和文档联系DTD但应注意是文档仍然需要完整格式否则Expat(和其他符合XML标准解析器样)将会随着出错信息而停止

  作为不检查有效性解析器Exapt快速性和轻巧性使其十分适合互联网

  编译Expat

  Expat可以编译进PHP3.0.6版本(或以上)中从Apache1.3.9开始Expat已经作为Apache部分在Unix系统中通过-with-xml选项配置PHP你可以将其编译入PHP

  如果你将PHP编译为Apache模块而Expat将默认作为Apache部分在Windows中你则必须要加载XML动态连接库

  XML范例:XMLstats

  了解Expat个办法就是通过范例我们所要讨论范例是使用Expat来收集XML文档统计数据

  对于文档中每个元素以下信息都将被输出:

  该元素在文档中使用次数 

  该元素中数据数量 

  元素父元素 

  元素子元素 

  注意:为了演示我们利用PHP来产生个结构来保存元素父元素和子元素

  准备

  用 于产生XML解析器例子为xml_parser_create该例子将用于以后所有这个思路非常类似于PHP中MySQL连接 标记在解析文档前基于事件解析器通常要求你注册回调-用于特定事件发生时Expat没有例外事件它定义了如下 7个可能事件:

  对象 XML解析 描述

  元素 xml__element_handler 元素开始和结束

  数据 xml__character_data_handler 数据开始

  外部实体 xml__external_entity_ref_handler 外部实体出现

  未解析外部实体 xml__unparsed_entity_decl_handler 未解析外部实体出现

  处理指令 xml__processing_instruction_handler 处理指令出现

  记法声明 xml__notation_decl_handler 记法声明出现

  默认 xml__default_handler 其它没有指定处理事件

  所有回调必须将解析器例子作为其第个参数(此外还有其它参数)

  对于本文最后范例脚本你需要注意是它既用到了元素处理又用到了数据处理元素回调处理通过xml__element_handler来注册

  这个需要 3个参数:

  解析器例子 

  处理开始元素回调名称 

  处理结束元素回调名称 

  当开始解析XML文档时回调必须存在它们必须定义为和PHP手册中所描述原型

  例如Expat将 3个参数传递给开始元素处理在脚本范例中其定义如下:

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

  第个参数是解析器标示第 2个参数是开始元素名称第 3参数为包含元素所有属性和值

  旦你开始解析XML文档Expat在遇到开始元素是都将start_element并将参数传递过去

  XMLCase Folding选项

  用xml_parser__option 将Case folding选项关闭这个选项默认是打开使得传递给处理元素名自动转换为大写但XML对大小写是敏感(所以大小写对统计XML文档是非 常重要)对于我们范例 folding选项必须关闭

  解析文档

  在完成所有准备工作后现在脚本终于可以解析XML文档:

  Xml_parse_from_file个自定义打开参数中指定文件并以4kb大小进行解析 

  xml_parse和xml_parse_from_file当发生即XML文档格式不完全时将会返回false 

  你可以使用xml_get_error_code来得到最后数字代码将此数字代码传递给xml_error_即可得到文本信息 

  输出XML当前行数使得调试更容易 

  在解析过程中回调 

  描述文档结构

  当解析文档时对于Expat需要强调问题是:如何保持文档结构基本描述?

  如前所述基于事件解析器本身并不产生任何结构信息

  不 过标签(tag)结构是XML重要特性例如元素序列<book><title>表示意思区别于< figure><title>也就是说任何作者都会告诉你书名和图名是没有关系虽然它们都用到"title"这个术语因此 为了更有效地使用基于事件解析器处理XML你必须使用自己栈(stacks)或列表(lists)来维护文档结构信息

  为了产生文档结构镜像脚本至少需要知道目前元素父元素用ExaptAPI是无法实现它只报告目前元素事件而没有任何前后关系信息因此你需要建立自己栈结构

  脚本范例使用先进后出(FILO)栈结构通过栈将保存全部开始元素对于开始元素处理目前元素将被.gif' />_push推到栈顶部相应结束元素处理通过.gif' />_pop将最顶元素移走

  对于序列<book><title></title></book>填充如下:

  开始元素book:将"book"赋给栈个元素($stack[0]) 

  开始元素title:将"title"赋给栈顶部($stack[1]) 

  结束元素title:从栈中将最顶部元素移去($stack[1]) 

  结束元素title:从栈中将最顶部元素移去($stack[0]) 

  PHP3.0通过个$depth变量手动控制元素嵌套来实现范例这就使脚本看起来比较复杂PHP4.0通过.gif' />_pop.gif' />_push两个来使脚本看起来更简洁

  收集数据

  为了收集每个元素信息脚本需要记住每个元素事件通过使用个全局变量$elements来保存文档中所有区别元素项目是元素类例子有4个属性(类变量)

  $count -该元素在文档中被发现次数 

  $chars -元素中事件字节数 

  $parents -父元素 

  $childs - 子元素 

  正如你所看到将类例子保存在中是轻而易举

  注意:PHP个特性是你可以通过while(list = each)loop遍历整个类结构如同你遍历整个相应所有类变量(当你用PHP3.0时还有思路方法名)都以方式输出

  当发现个元素时我们需要增加其相应记数器来跟踪它在文档中出现多少次在相应$elements项中记数元素也要加

  我们同样要让父元素知道目前元素是它子元素因此目前元素名称将会加入到父元素$childs项目中最后目前元素应该记住谁是它父元素所以父元素被加入到目前元素$parents项目中

  显示统计信息

  剩下代码在$elements和其子中循环显示其统计结果这就是最简单嵌套循环尽管输出正确结果但代码既不简洁又没有任何特别窍门技巧它仅仅是个你可能每天用他来完成工作循环

  脚本范例被设计为通过PHPCGI方式命令行来因此统计结果输出格式为文本格式如果你要将脚本运用到互联网上那么你需要修改输出来产生HTML格式

  整理总结

  Exapt是PHPXML解析器作为基于事件解析器它不产生文档结构描述但通过提供底层访问这就使得可以更好地利用资源和更快地访问

  作为个不检查有效性解析器Expat忽略和XML文档连接DTD但如果文档格式不完整它将会随着出错信息而停止

  提供事件处理来处理文档 

  建立自己事件结构例如栈和树来获得XML结构信息标记优点 

  每天都有新XML出现而PHP对XML支持也不断加强(例如增加了支持基于DOMXML解析器LibXML)

  有了PHP和Expat你就可以为即将出现有效、开放和独立于平台标准作准备

  范例

  <? 

  /***************************************************************************** 

  * 名称:XML解析范例:XML文档信息统计

  * 描述 

  * 本范例通过PHPExpat解析器收集和统计XML文档信息(例如:每个元素出现次数、父元素和子元素 

  * XML文件作为个参数 ./xmlstats_PHP4.php3 test.xml 

  * $Requires: Expat 要求:Expat PHP4.0编译为CGI模式 

  *****************************************************************************/ 

// 第个参数是XML文件
$file = $argv[1]; 
  
// 变量
$elements = $stack = .gif' />; 
$total_elements = $total_chars = 0; 
  
// 元素基本类
element 
{ 
var $count = 0; 
var $chars = 0; 
var $parents = .gif' />; 
var $childs = .gif' />; 
} 
  
// 解析XML文件
function xml_parse_from_file($parser, $file) 
{ 
(!file_exists($file)) 
{ 
die("Can't find file "$file"."); 
} 
  
(!($fp = @fopen($file, "r"))) 
{ 
die("Can't open file "$file"."); 
} 
  
while($data = fread($fp, 4096)) 
{ 
(!xml_parse($parser, $data, feof($fp))) 
{ 
(false); 
} 
} 
  
fclose($fp); 
  
(true); 
} 
  
// 输出结果(方框形式)
function pr_box($title, $value) 
{ 
prf("n+%'-60s+n", ""); 
prf("|%20s", "$title:"); 
prf("%14s", $value); 
prf("%26s|n", ""); 
prf("+%'-60s+n", ""); 
} 
  
// 输出结果(行形式)
function pr_line($title, $value) 
{ 
prf("%20s", "$title:"); 
prf("%15sn", $value); 
} 
  
// 排序
function my_sort($a, $b) 
{ 
(is_object($a) && is_object($b) ? $b->count - $a->count: 0); 
} 
  
function start_element($parser, $name, $attrs) 
{ 
global $elements, $stack; 
  
// 元素是否已在全局$elements中?
(!is($elements[$name])) 
{ 
// 否-增加个元素类例子
$element = element; 
$elements[$name] = $element; 
} 
  
// 该元素记数器加
$elements[$name]->count; 
  
// 是否有父元素?
(is($stack[count($stack)-1])) 
{ 
// 是-将父元素赋给$last_element
$last_element = $stack[count($stack)-1]; 
  
// 如果目前元素父元素为空化为0
(!is($elements[$name]->parents[$last_element])) 
{ 
$elements[$name]->parents[$last_element] = 0; 
} 
  
// 该元素父元素记数器加
$elements[$name]->parents[$last_element]; 
  
// 如果目前元素父元素子元素为空化为0
  
(!is($elements[$last_element]->childs[$name])) 
{ 
$elements[$last_element]->childs[$name] = 0; 
} 
  
// 该元素父元素子元素记数器加
$elements[$last_element]->childs[$name]; 
} 
  
// 将目前元素加入到栈中
.gif' />_push($stack, $name); 
} 
  
function stop_element($parser, $name) 
{ 
global $stack; 
  
// 从栈中将最顶部元素移去
.gif' />_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__element_handler($parser, "start_element", "stop_element"); 
xml__character_data_handler($parser, "char_data"); 
xml_parser__option($parser, XML_OPTION_CASE_FOLDING, 0); 
  
// 解析文件
$ret = xml_parse_from_file($parser, $file); 
(!$ret) 
{ 
die(sprf("XML error: %s at line %d", 
xml_error_(xml_get_error_code($parser)), 
xml_get_current_line_number($parser))); 
} 
  
// 释放解析器
xml_parser_free($parser); 
  
// 释放协助元素
un($elements["current_element"]); 
un($elements["last_element"]); 
  
// 根据元素次数排序
uasort($elements, "my_sort"); 
  
// 在$elements中循环收集元素信息
while(list($name, $element) = each($elements)) 
{ 
pr_box("Element name", $name); 
  
pr_line("Element count", $element->count); 
pr_line("Character count", $element->chars); 
  
prf("n%20sn", "* Parent elements"); 
  
// 在该元素父中循环输出结果
while(list($key, $value) = each($element->parents)) 
{ 
pr_line($key, $value); 
} 
(count($element->parents) 0) 
{ 
prf("%35sn", "[root element]"); 
} 
  
// 在该元素子中循环输出结果
prf("n%20sn", "* Child elements"); 
while(list($key, $value) = each($element->childs)) 
{ 
pr_line($key, $value); 
} 
(count($element->childs) 0) 
{ 
prf("%35sn", "[no childs]"); 
} 
  
$total_elements $element->count; 
$total_chars $element->chars; 
} 
  
// 最终结果
pr_box("Total elements", $total_elements); 
pr_box("Total characters", $total_chars); 
?>


0

相关文章

读者评论

发表评论

  • 昵称:
  • 内容: