9.3 PHP与XML技术
XML中文为可扩展标记语言,是由万维网联盟在1998年2月推出的。它是由SGML(Standard Generalized Markup Language,标准通用标记语言)发展而来的,并对其语法进行了修改,使之更加简洁、规范。
9.3.1 XML语法
XML语言功能十分强大,继承了SGML的特点,打破了HTML的局限性,拥有以下特点。
(1)简单性、平台无关性、广泛性,可用于Internet上的各种应用。
(2)兼容SGML,多数SGML应用都可转化为XML。
(3)易于创建,只需要新建文档重命名为XML文档即可。
(4)结构简单,可以更加灵活地进行编程。
(5)结构严谨,易于解析。
(6)将用户界面与结构化数据分开,可以集成来自不同源的数据。
9.3.2 XML文档结构
XML文档由一个声明语句开始,该语句用于指定该文档所遵循的XML规范,使用编码集等信息。声明语句如下。
<?xml version="1.0" encoding="GBK"?>
version说明该文档使用XML 1.0规范,通过参数encoding指定文档使用的编码集为GBK。
声明之后需要加入文档的根元素,根元素用于描述文档的功能,它的标签名支持自定义,并可以在根元素中加入该文档,并且可以在根元素中加入对该文档信息的一些配置。
根元素定义完毕后,就可以在其中加入XML内容了,这些内容可以定义XML文档中的功能和属性,格式如下。
<标签> 内容<标签>
标签支持自定义,也支持嵌套。
<?xml version="1.0" encoding="GBK"?> <song> <name>superstar</name> <desc> <singer>S.H.E</singer> </desc> </song>
上例中,通过声明语句定义了XML版本为1.0版,文档的编码为GBK,使用song定义根路径,标签name的内容为superstar,在desc标签中嵌套了标签singer,singer标签的内容为S.H.E。
9.3.3 使用PHP创建XML文档
使用PHP语言创建输出XML文档时,需要使用数组存放XML标签名与内容,二者分别作为数组元素的键名与键值,通过PHP创建XML文档,代码如下。
<?php error_reporting(7); //设置错误提示级别 $array=array(array('song'=>'superstar'),array('desc'=>array('singer'=>' S.H.E'))); //设置文档内容 header('Content_Type:application/xml;charset=gbk'); //设置页面解析方式 $xml=records_to_xml($array,"sunyang"); //调用方法,传递文档内容参数 echo $xml; //将文档内容输出 function records_to_xml($array,$xmlname){ //将记录转换为XML文档方法 $xml.='<?xml version="1.0" encoding="gbk"?>'."\n"; //XML文档声明语句 $xml.="<$xmlname>"."\n"; //XML文档根元素 foreach($array as $key=>$value){ //遍历文档内容数组 if(is_array($value)){ //如果数组元素的值仍为数组 foreach($value as $k=>$v){ //再次对其循环遍历 if(is_array($v)){ //如果数组元素的值仍为数组 foreach($v as $kk=>$vv){//继续对其循环遍历 $xml.="<$k>\n<$kk>$vv</$kk>\n</$k>\n";//设置该元素 } }else{ $xml.="<$k>$v</$k>\n"; //若非数组则直接设置该元素 } } }else{ $xml.="<$key>$value</$key>\n"; //若非数组则直接设置该元素 } } $xml.="</$xmlname>"."\n"; //根元素结束 return $xml; //返回文档内容 } ?>
运行结果如图9-5所示。
9.3.4 使用SimpleXML创建和解析XML
9.3.3节中使用PHP生成了XML文件,但实现方式相对烦琐。除了上面最原始的方式操作XML文件以外,PHP还提供了多种处理XML的方法。
SimpleXML是PHP提供的用于解析XML文档的函数库,它可以将XML内容转化为一个对象,然后对其进行相应的处理。SimpleXML通过simplexml_load_string()函数将XML文档中的标签内容转换为对象数组,该对象数组的键名为XML文档中的标签名,值为标签体的内容,如果在标签内包含另一个标签则使用多维数组方式来处理。
simplexml_load_string()函数的语法如下。
object simplexml_load_string(string $data[,string $class_name])
涉及的参数及说明如下。
data:指定XML文档的内容。
class_name:指定将文档内容转换为指定类型的对象。
下面使用SimpleXML生成如下内容的XML文件。
<?xml version="1.0" encoding="utf-8"?> <country> <province> <name people="100000" feature="首都">北京</name> <city> <name>海淀</name> <name>朝阳</name> </city> </province> <province> <name people="200000" feature="省份">河北省</name> <city> <name>石家庄</name> <name>衡水市</name> </city> </province> </country>
使用SimpleXML实现输出以上XML内容的代码如下。
<?php //载入一个xml格式的字符串并将其解析为SimpleXMLElement对象 //此处simplexml_load_string方法实际作用等同于new SimpleXMLElement $xml = simplexml_load_string( "<?xml version=\"1.0\" encoding=\"utf-8\"?><country></country>"); //添加省份节点province $province = $xml->addChild('province'); //设置province添加子节点name,值为"北京" $name = $province->addChild('name','北京'); //为name节点设置属性people,值为100000 $name->addAttribute('people',100000); //为name节点设置属性feature,值为"首都" $name->addAttribute('feature','首都'); //为province节添加子节点city $city = $province->addChild('city'); //添加的city的子节点name,值为"海淀" $city->addChild('name','海淀'); //添加的city的子节点name,值为"朝阳" $city->addChild('name','朝阳'); $province = $xml->addChild('province'); $name = $province->addChild('name','河北省'); $name->addAttribute('people',200000); $name->addAttribute('feature','省份'); $city = $province->addChild('city'); $city->addChild('name','石家庄'); $city->addChild('name','衡水市'); //将SimpleXMLElement对象$xml转换成一个XML格式并写入zh_cn.xml文件 $xml->asXML('zh_cn.xml'); ?>
使用SimpleXML解析上例生成的XML文件代码如下。
<?php //载入一个zh_cn.xml文件并解析为SimpleXMLElement对象 $xml = simplexml_load_file('zh_cn.xml'); foreach ($xml as $v) { //输出地区名称 echo 'name:'.$v->name,"\n"; //输出属性(people,feature) $attr = $v->name->attributes(); echo 'people:'.$attr['people'],"\n"; echo 'feature:'.$attr['feature'],"\n"; //循环输出小地区 foreach ($v->city->name as $name) { echo "city:".$name,"\n"; } }
输出结果如图9-6所示。
如果只想输出某一层级的节点内容,可使用SimpleXML提供的xpath方法。例如,只取出city节点的内容,代码如下。
<?php $xml = simplexml_load_file('zh_cn.xml'); //此处是关键 $city = $xml->xpath('/country/province/city/name'); //循环输出city foreach ($city as $v) { echo $v,"\n"; } ?>
输出结果如图9-7所示。
SimpleXML的优点是开发简单,缺点是它会将整个XML载入内存后再进行处理,所以在解析超多内容的XML文档时可能会力不从心。如果是读取小文件,SimpleXML是很好的选择。在PHP中除了使用SimpleXML可以解析与生成XML文件以外,还可以使用其他方法来操作XML。
XML解析器也是处理XML不错的选择,它不是将整个XML文档载入内存后再处理,而是边解析边处理,所以性能上要好于SimpleXML。目前,网上已有基于XML解析器做进一步封装使用起来更方便的XML类库。
XMLReader也可以用来处理XML,它是PHP 5之后的扩展,它就像游标一样在文档流中移动。XMLReader和XML Parser类似,都是边读边操作,但使用XMLReader可以随意从读取器提取节点,可控性更好。由于XMLReader基于libxml,所以有些函数要参考文档看看是否适用于你的libxml版本。
DOMDocument也是处理XML的一个方式,它是一次性将XML载入内存,所以内存问题同样需要注意。
PHP提供了多种XML的处理方式,开发人员应根据具体的需求来选择最适合的解析方式。
9.3.5 XML的应用——RSS
RSS的全称为Really Simple Syndication(真正的简单联合),是一种描述和同步网站内容的格式,是当前使用最广泛的XML应用之一。RSS是将用户及其订阅的内容传送给他们的通信协同格式,目前广泛应用于网上新闻类的信息。
RSS是Web 2.0的一种典型应用,它将被动的信息获取变成了主动信息获取,把以网站运营为中心的信息发布变成以用户为中心的信息定制,还可以将网络上的闲散信息聚合起来形成聚合平台。
RSS实际上是一种XML,因此它遵循XML的相关规范。
RSS文档的根元素是<rss>,并且包含一个表示其版本的version属性,例如,<rss version="2.0">。整个RSS文档都必须包含在<rss>标签中,其中包括文档频道元素<channel>及其子元素。其中,频道元素为RSS文档的基础元素,它除了可以表示频道内容本身之外,还可以通过项<item>的形式包含表示频道元数据的元素,项是频道的主要元素,它用于设置频道中经常变化的部分。
1.频道
频道使用<channel>标签来定义,它一般包含以下三个主必要元素。
(1)<title>:频道的标题。
(2)<link>:与该频道有关的站点的URL。
(3)<description>:频道的简介。
以上三个元素提供关于频道本身的信息。
(1)<image>:指定与频道同时显示的图片。
(2)<language>:频道的语言(如en-us、cn)。
(3)<copyright>:频道的版权信息。
(4)<managingEditor>:负责编辑该频道内容人员的E-mail。
(5)<webMaster>:负责有关频道技术发布人员的E-mail。
(6)<pubDate>:频道内容的发布日期。
(7)<lastBuildDate>:频道内容最后修改的日期。
(8)<category>:产生该频道的类别。
(9)<generator>:产生该频道的系统名称。
(10)<docs>:指明该RSS文档所使用的文本格式。
(11)<ttl>:以分钟数据指明该频道的存活时间。
(12)<rating>:关于该频道的PICS评价。
(13)<textInput>:定义与频道一起显示的输入框。
其中<image>元素是经常需要使用的,它还包括以下几个子元素。
(1)<url>:必需元素,表示该<image>元素所指定图像的URL。
(2)<title>:必需元素,图像的标题。
(3)<link>:必需元素,站点的URL。
(4)<width>:表示图像的宽度,最大值为188,默认值为88。
(5)<height>:表示图像的高度,最大值为400,默认值为31。
(6)<description>:包含文本,图片的title属性。
2.项
项是使用<item>标签来定义的,用于指定RSS文档中所包含的信息,项有以下三个必需的子元素。
(1)<title>:定义项的标题。
(2)<link>:定义项所代表网页的地址。
(3)<descripiton>:项的简介。
上述三个元素用于提供项本身的信息。
项还可以包括如下几个可选子元素。
(1)<author>:记录项作者的E-mail地址。
(2)<category>:定义项所属类别。
(3)<comment>:关于项的注释页URL。
(4)<encloseure>:与该项有关的媒体文件。
(5)<guid>:为项定义一个唯一标识符。
(6)<pubDate>:该项的发布时间。
(7)<source>:为该项指定一个第三方来源。
下面列出了一个简单的RSS文档。
<?xml version="1.0" encoding="utf-8" ?> <rss version="2.0"> //RSS文档根元素 <channel> //频道元素 <title>HBSI</title> //频道名 <link>http://www.HBSI.net</link> //频道地址 <description>HBSI官方动态频道</description> //频道简介 <item> //定义项 <title>HBSI创业版商城新版本发布</title> //项名称 <link>http://www.HBSI.net</link> //项地址 <description>HBSI创业版商城V1.3版本发布了</description>//项简介 </item> </channel> </rss>
将上述代码放入rss.php,如下。
<?php header("Content-type: text/html; charset=utf-8"); $xml = <<<EOF <?xml version="1.0" encoding="utf-8" ?> <rss version="2.0"> <channel> <title>HBSI</title> <link>http://www.HBSI.net</link> <description>HBSI官方动态</description> <item> <title>HBSI创业版商城新版本发布</title> <link>http://www.HBSI.net</link> <description>HBSI创业版商城V1.3版本发布</description> </item> </channel> </rss> EOF; echo $xml; ?>
RSS订阅文件URL路径为http://127.0.0.1/rss.php。
在RSS阅读器中将上述URL路径添加到订阅频道中,下面是使用看天下阅读器的订阅效果,如图9-8所示。