PHP使用XMLReader解析XML里面的CDATA
之前,我在《使用xmlreader读取xml数据》例举了一个方法,是用XMLReader来解析XML的。在实践中,我发现XML里面常常有一些CDATA代码无法被解析,这类方法在取值时无法被找到,从而出现了错误提示。
通过这两天网上的搜索发现,无法读取CDATA还是比较头疼的问题,并且也没找到较简单的XMLReader解析CDATA的方法。这很让我迷惑。
举例来说
我有一个网站:厘米屋,它的RSS地址为:http://blog.limiwu.com/feed。我想把<item>
下的title、link、description和pubDate解析出来。现在遇到是问题是description上有一个CDATA层级,导致我在上一篇上所写的$description
值失效了。
附上XML:
<?xml version="1.0" encoding="UTF-8"?> <rss version="2.0"> <channel> <title>厘米屋</title> <atom:link href="http://blog.limiwu.com/feed" rel="self" type="application/rss+xml" /> <link>http://limiwu.com</link> <description>家具木制品的故事</description> <lastBuildDate>Mon, 26 Dec 2016 04:52:12 +0000</lastBuildDate> <language>zh-CN</language> <sy:updatePeriod>hourly</sy:updatePeriod> <sy:updateFrequency>1</sy:updateFrequency> <generator>https://wordpress.org/?v=4.6.1</generator> <item> <title>按家装风格搭配自己的入户鞋柜</title> <link>http://blog.limiwu.com/220.html</link> <comments>http://blog.limiwu.com/220.html#respond</comments> <pubDate>Mon, 26 Dec 2016 04:51:30 +0000</pubDate> <dc:creator><![CDATA[紫铜炉]]></dc:creator> <category><![CDATA[家居木制品]]></category> <guid isPermaLink="false">http://blog.limiwu.com/?p=220</guid> <description><![CDATA[一进入别人家里,映入眼帘的就是鞋柜或者入门装饰柜,这个柜子的风格 决定您家整体的风格品味,所以在这方便还需要下点 […]]]></description> <wfw:commentRss>http://blog.limiwu.com/220.html/feed</wfw:commentRss> <slash:comments>0</slash:comments> </item> ... </channel> </rss>
解决方法
经过我多次尝试,终于发现XMLReader是可以自行阅读CDATA里面的内容的。(这也太扯淡了吧)。只要将对应的nodeType值去匹配XMLReader::CDATA
就可以了。
下面就是我的解决方法:
<?php
$indexUrl = 'http://blog.limiwu.com/feed';
$reader = new XMLReader();
$reader->open($indexUrl);
$titles = $links = $descriptions = $pubDates = array();
while ($reader->read()){
if($reader->nodeType == XMLReader::ELEMENT){
$nodeName = $reader->name;
}
if($reader->nodeType == XMLReader::TEXT && !empty($nodeName) && $reader->depth == '4'){
switch($nodeName){
case 'title':
$title = $reader->value;
array_push($titles,$title);
break;
case 'link':
$link = $reader->value;
array_push($links,$link);
break;
case 'description':
$description = $reader->value;
array_push($descriptions,$description);
echo $description.'<br />';
break;
case 'pubDate':
$pubDate = $reader->value;
array_push($pubDates,$pubDate);
break;
}
}
if($reader->nodeType == XMLReader::CDATA && !empty($nodeName) && $reader->depth == '4'){
switch($nodeName){
case 'title':
$title = $reader->value;
array_push($titles,$title);
break;
case 'link':
$link = $reader->value;
array_push($links,$link);
break;
case 'description':
$description = $reader->value;
array_push($descriptions,$description);
break;
case 'pubDate':
$pubDate = $reader->value;
array_push($pubDates,$pubDate);
break;
}
}
}
$reader->close();
echo $title.'<br />';
echo $link.'<br />';
echo $description.'<br />';
echo $pubDate.'<br />';
echo count($titles).'<br />';
echo count($links).'<br />';
echo count($descriptions).'<br />';
echo count($pubDates);
?>
我这里分了两个if的判断来做,不明白的朋友可以看之前的那个XMLReader常量的常量,那里面赫然标注了一个方法。我显然是没有弄明白那个意思,所以走了很多弯路。
现在看来,XMLReader解析CDATA是异常的简单啊。