PHP中的XML拉模式剖析

PHP中的XML拉模式剖析

PHP5引入了新的类XMLReader,用于读取可扩展标记语言(Extensible Markup Language,XML)。与SimpleXML或文档对象模型(Document Object Model,DOM)不同,XMLReader以流模式进行操作。即它从头到尾读取文档。在文档后面的内容编译完成之前,可以先处理已编译好的文档前面的内容,从而实现非常快速、非常高效、非常节省地使用内存。需要处理的文档越大,这个特点就越发重要。

libxml

这里所说的XMLReader API位于Gnome Project中用于C和C++的libxml库之上。实际上XMLReader只是在libxml的XmlTextReader API之上的很薄的PHP层。XmlTextReader本身是模仿.NET的XmlTextReader类和XmlReader类,尽管并不具有与这些类相似的代码。

与Simple API for XML(SAX)不同,XMLReader是推解析器,而不是拉解析器。这意味着程序是可以控制的。您将告诉解析器何时获取下一个文档片段,而不是在解析器看到文档后告诉您所看到的内容。您将请求内容,而不是对内容进行反应。从另一个角度来考虑这个问题:XMLReader是Iterator设计模式的实现,而不是Observer设计模式的实现。

示例问题

先从简单例子开始讨论。假定正在编写PHP脚本,用来接收XML-RPC请求并生成响应。更具体一些,假定请求如清单1所示。文档的根元素是methodCall,它包含methodName元素和params元素。方法的名称是sqrt。params元素包含一个param元素,param元素包含double,double的平方根是希望得到的值。没有使用名称空间。

清单1.XML-RPC请求

sqrt

36.0

下面是PHP脚本需要完成的工作:检查方法名,如果不是sqrt(它是该脚本懂得如何处理的惟一方法),则生成错误响应。找到参数,如果参数不存在或参数类型错误,则生成错误响应。另外,计算平方根。在表单中返回结果,如清单2所示。

清单2.XML-RPC响应

6.0

下面我们逐步展开说明。

初始化解析器并载入文档

第一步是创建新的解析器对象。创建操作很简单:

$reader=new XMLReader();

接着,需要为它提供一些用于解析的数据。对于XML-RPC,这是超文本传输协议(Hypertext Transfer Protocol,HTTP)请求的原始主体。然后可以将该字符串传递到读取器的XML()函数:

填充原始发送数据

如果发现$HTTP_RAW_POST_DATA是空的,则将以下代码行添加到php.ini文件:

always_populate_raw_post_data=On

$request=$HTTP_RAW_POST_DATA;

$reader->XML($request);

可以解析任何字符串,无论它是从何处获取的。例如,可以是程序中的一串文字或从本地文件读取。还可以使用open()函数从外部URL载入数据。例如,下面的语句准备解析其中一个Atom提要:

$reader->XML(‘http://www.cafeaulait.org/today.atom‘);

无论是从何处获取原始数据,现在已建立了阅读器并为解析做好准备。

读取文档

read()函数使解析器前进到下一个标记。最简单的方法是在while循环中遍历整个文档:

while($reader->read()){

//processing code goes here...

}

完成遍历后,关闭解析器以释放它所持有的任何资源,并且重置解析器以便用于下一个文档:

$reader->close();

在循环内部,将解析器放置在特殊节点上:元素的起点、元素的终点、文本节点、注释等等。通过检查以下属性,可以发现解析器正在查看的内容:localName是本地的、未带前缀的节点名。name是可能的节点前缀名。对于像注释这种没有名称的节点,包括#comment、#text、#document等等,与DOM中的一样。namespaceURI是节点名称空间的统一资源标识符(Uniform Resource Identifier,URI)。nodeType是代表节点类型的整数