PHP中有两种主要的XML解析器
1)基于树的解析器。它是把整个文档存储为树的数据结构中,即需要把整个文档都加载到内存中才能工作。所以,当处理大型XML文档时候,性能剧减。SimpleXML和DOM扩展属于此类型解析器。
2)基于流的解析器。它不会一次把整个文档加载到内存中,而是每次分别读取其中的一个节点并允许实时与之交互(当移向下一个节点时,上一个节点是被丢弃,但也设置为保留)。很明显,其效率要高且占内存少,不便之处代码量大点。
所以,PHP中处理大型XML文档可以用XMLReader扩展方案(基于流的解析器)。它在PHP 5.1中默认是启用的。
下面是我结合手册与代码整理出来的笔记,希望多交流交流。
博客地址:http://blogforit.sinaapp.com/View/index/b_id/304.html
<?php class xmlRead { // ================================================================== // // 前三个属性用来保存RSS频道信息,$items数组保存来自指定频道的所有RSS项目,$xml // 保存频道的原始XML源 // // ------------------------------------------------------------------ public $channelTitle = ''; public $channelDesc = ''; public $test = ''; public $items = array(); public $xml; public function __construct($url = NULL) { if($url !== NULL) { $this->load($url); } } public function load($url) { // $this->xml = file_get_contents($url); $this->xml = $url; //我们使用XMLReader来解析XML数据 $xr = new XMLReader(); $xr->XML($this->xml); while ($xr->read()) { // ================================================================== // // XMLReader::ELEMENT常量通过PHP手册知道这个代表节点的开始(值是1),所以当 // $xr->nodeType也是1(即节点的开始),我们就可以通过localName属性得到节点的名字: // 如<channel>是一个开始节点,nodeType = 1,并且localName = channel.这里我们 // 打印所有节点属性如下(如果要看所有节点,一定要注释掉switch,不然它会执行相应函数,就 // 不能输出已经在函数里执行过的属性了)。 // // ------------------------------------------------------------------ // echo '<pre>'; // var_dump($xr->nodeType.' '.$xr->localName.' '.$xr->depth.' '.$xr->value); // echo '</pre>'; if(XMLReader::ELEMENT == $xr->nodeType) { // 这里我们得到$xr->nodeType=1,即所有的开始标签如<channel>. // echo '<pre>'; // var_dump($xr->nodeType.' '.$xr->localName.' '.$xr->depth.' '.$xr->value); // echo '</pre>'; // ================================================================== // // 这里需要特别注意一下,为什么你把switch注释与不注释,var_dump出来的值不同呢,原因 // 就是因为XMLReader是类似游标一行一行读取的,读取完了之后会销毁已经读过的,所以当你 // 开启了switch执行代码后,由于执行到了channel时,会跳转到函数_getChannelInfo($xr) // 继续执行函数里面的代码,我们在函数里面就把RSS的title,description读过了,所以 // 打印出来就不存在那些属性了,如果把switch注释掉,由于没有任何执行,则会一行一行输出 // 所有的开始标签如<title>,<descrition>.。 // // ------------------------------------------------------------------ switch ($xr->localName) { //如果是channel,我们就得到它的下级属性值,如title,description等 case 'channel': $this->_getChannelInfo($xr); break; //如果是item(即RSS文摘的开始属性),我们就得到所有的文章内容并存入到数组中 case 'item': $this->_getItemInfo($xr); break; } } } } /** * 获取channel类型的数据,比如标题,描述等 */ protected function _getChannelInfo($xr) { // ================================================================== // // depth代表节点树的深度,最开始是0即<rss version="2.0">,当出现了第一个存在深度 // 为3的节点时,while循环就结束了。这里指明一下,由于在<xiaozhe>下面的文本值是属于 // 3节点,由于下面循环到了xiaozhe时,我读取了那个值节点(深度是3),所以while循环才能 // 继续执行。当执行到pubDate时,由于没有得到它的值节点(在函数内部没有将那个节点读取, // while循环就会读取到那个节点),即读取的节点深度就是3(pubDate的值节点)。 // 所以循环结束,并且此节点已经被读取下次就不会输出出来了。永远记住,read()一次,游标 // 向下走一个节点。 // // ------------------------------------------------------------------ while ( ($xr->read()) && ($xr->depth == 2) ) { // echo '<pre>'; // print_r($xr->nodeType.' '.$xr->localName.' '.$xr->depth); // echo '</pre>'; if(XMLReader::ELEMENT == $xr->nodeType) { switch ($xr->localName) { case 'title': //这里使用read继续读取下个游标,即属性值 $xr->read(); $this->channelTitle = $xr->value; break; case 'description': $xr->read(); $this->channelDesc = $xr->value; break; case 'xiaozhe': $xr->read(); $this->test = $xr->value; break; } } } } /** * 获取Item数据,一个Item在一个RSS里面相当于一篇文章 */ protected function _getItemInfo($xr) { $title = ''; $link = ''; $desc = ''; while( ($xr->read()) && ($xr->depth > 2) ) { if(XMLReader::ELEMENT == $xr->nodeType) { switch ($xr->localName) { case 'title': $xr->read(); $title = $xr->value; break; case 'description': $xr->read(); $desc = $xr->value; break; case 'link': $xr->read(); $link = $xr->value; break; } } } //将数据放入数组中,因为一个RSS可能会有很多的item //当调用一次这个函数,就增加一次数据 $this->items[] = array( 'title' => $title, 'link' => $link, 'desc' => $desc, ); } } // $url = 'http://blog.sina.com.cn/rss/2022595450.xml'; //$url = 'http://www.huxiu.com/rss/0.xml'; $url = "<rss> <channel> <title>feed title</title> <description>feed description</description> <xiaozhe>123</xiaozhe> <pubDate>Mon, 29 Oct 2012 13:30:00 +0100</pubDate> <copyright>123</copyright> <item> <title>item title</title> <description>item description</description> <link>http://itemlink</link> </item> <item> <title>item title</title> <description>item description</description> <link>http://bla</link> </item> </channel> </rss>"; $obj = new xmlRead($url); // echo '<pre>'; // print_r($obj->items); // echo '</pre>'; ?>
作者:andybegin 发表于2013-3-27 0:43:50 原文链接
阅读:137 评论:0 查看评论