XMLParser教程/文档
XMLParser是什么
XMLParser是我(Adam A Flynn)在花费了很大的工夫来处理PHP的XML扩展后设计的,因为一个客户需要这么个"能在PHP4和PHP5下都正确地工作"的东西。我最初的成果是一段段看起来就让人头疼的代码,而它们所做的工作,往往只用一行SimpleXML代码就能实现。为此,我决定在做下一个涉及XML的项目之前写一个能像SimpleXML一样工作的解析器,并且能够兼容PHP4和PHP5。这就是XMLParser。这个解析器有两个版本(准确的说是两个文件,每个包含一个类)。一个用于PHP4,一个用于PHP5。两者提供了完全一致的接口,因此你只需编写一种代码来使用这个解析器──只要你根据PHP的版本包含相应版本的解析文件,你的代码就能在两个PHP版本中都正确地工作。
使用XMLParser
因为我希望我的解析器和SimpleXML相似(从它最初的设计开始便或多或少地模仿了SimpleXML──只不过用了PHP4的函数来进行实现),因此我选择了PHP官方网站的SimpleXML文档页面上所使用的一系列例子和XML文件来演示XMLParser。我们的XML示例文件(example.xml)
<?xml version='1.0' standalone='yes' ?>
<movies>
<movie>
<title>PHP: Behind the Parser</title>
<characters>
<character>
<name>Ms. Coder</name>
<actor>Onlivia Actora</actor>
</character>
<character>
<name>Mr. Coder</name>
<actor>El Actor</actor>
</character>
</characters>
<plot>
So, this language. It's like, a programming language. Or is it a scripting language? All is revealed in this thrilling horror spoof of a documentary.
</plot>
<rating type="thumbs">7</rating>
<rating type="stars">5</rating>
</movie>
</movies>入门
开始使用解析器之前,你需要加载你想操作的XML文件。为此,我们将调用example.xml文件。和SimpleXML一样,XMLParser的构造函数将获取XML文件本身,而不仅仅是对其文件名的引用。这意味着在初始化XMLParser对象之前,我们需要使用file_get_contents()调用XML文件。当我们完成了对XMLParser的调用并给它填充了一些数据,接下来,我们就要让它施展魔力,做一些实际的解析工作。完成这步只需要轻松地调用一下Parse方法。
配置解析器
<?php
//Get the XML document loaded into a variable
$xml = file_get_contents('example.xml');
//Set up the parser object
$parser = new XMLParser($xml);
//Work the magic...
$parser->Parse();
?>
XML解析器包含一个错误处理函数,当对XML文档的解析出现问题时,它能触发一个PHP错误。这个函数叫trigger_error,是XMLParser类的一个方法。你能按照自己喜欢的方式自由地改变错误的显示方式;这些参数应该算是简单的。当然,如果我们的解析工作没有遇到问题,那么只管继续好了。
XMLParser对象的结构是非常简单明了的,当然,也需要花些时间来适应它。文档的根结点被包含在解析器的document成员中。也就是说在上面的例子中,$parser->document就是根标签,而不用去管这个标签的实际名称是什么。在根标签之下,每个子标签都被分配到一个以标签自身名称命名的数组中。按照上述规则,$parser->document->movie[0]指向第一个movie标签。$parser->document->movie是一个数组,而不是一个XMLTag对象。因此在大多数情况下,想通过$parser->document->movie来获取第一个movie对象是行不通的。
使用XMLParser
正如之前所说的,我们要按着SimpleXML文档的例子来进行演示,那么我们现在就回到SimpleXML的文档所用的例子。SimpleXML的示例2演示了输出第一个movie的plot,示例3演示了输出每个movie的plot。我将把示例2和示例3合并到下面这个例子中。这个例子的前提是你已经加载并解析了XML文档(参考前面的例子)。获取<plot>
<?php
//Echo the plot of the first <movie>
echo $parser->document->movie[0]->plot[0]->tagData;
//Echo the plot of each <movie>
foreach($parser->document->movie as $movie)
{
echo $movie->plot[0]->tagData;
}
?>
好吧, 我承认这语法看起来并不能像SimpleXML中的那么美。为了实现对PHP4的兼容,我不能使用__toString()函数来简化代码,毕竟,这个解析器最重要的目的就是实现对PHP4兼容。如果我们只想在PHP5的服务器中运行,那直接去看SimpleXML的文档就好了,而不必像现在这样来读我的这个"替代品"的文档,对吧?当然,如果你想要在PHP5版本的解析文件中通过__toString()方法实现输出标签的数据,尽管去做吧,但是对于这些例子,我能想象你所要走的是条漫长的道路。
那么,让我们分析一下上面的例子,首先,我们所做的是通过文档树找到我们所需要的plot对象,然后,我们将它的tagData成员输出。那么什么是tagData呢?tagData是PHP的XML解析器给定的字符数据(XML文档中所有标记符以外的内容,包括标记符之间的空格)。因为PHP解析XML文档看上去像是逐行进行的,所以这个值是级联的。在将数据送到tagData之前,我使用trim()函数。这过滤了空格和其他空白字符。因此,每个字符数据行的开头和结尾的空白字符已经被过滤了。假如你的软件在类似情况下出现bug,那么这就是原因了。
保留字
最后,在介绍属性(是的,这个解析器当然能处理属性)之前,有个小小的问题需要注意,为什么我要使用tagData这个名称而不是其他更短的名称呢。在版本1中,我使用了data做为字符数据这个成员的名称,因为它更短,更容易使用。然而,当我开始使用这个类之后,我注意到自己有好几次都用到一个叫做<data>的标签;同时,我也收到一些来自使用者的电子邮件,告诉我当用到叫做<data>的标签时会发生一些问题。当解析器试图为data数组增加成员或创建新数组时,这会导致一个问题,并返回一个PHP错误和一个不怎么准确的文档树。因此,为了修复了这个问题,我决定在版本1.1中重命名所有XMLTag类中的成员。它们都有前缀tag,因为我想不到任何一个人们非要将一个XML标签命名为<tagdata>或<tagattrs>不可的理由。如果,在某些非常偶然的情况下你需要使用下列名称中的一者做为XML标签的名称时,那么你可以选择a)不要这么做,或者b)重命名XMLTag中的成员──用查找替换来重命名类中所有出现这个词的地方。保留字列表如下:属性
属性非常容易使用。每个XMLTag对象都有一个关联数组成员叫做tagAttrs。在这个成员里面,键代表属性名称,而值代表属性值。我想我不必更进一步地深入讲解了,不过我将演示一个模仿SimpleXML的属性的例子。Accessing Attributes
<?php
//For each of the <rating> tags, display them
foreach($parser->document->movie[0]->rating as $rating)
{
//If the rating is in stars...
if($rating->tagAttrs['type'] == 'stars')
echo $rating->tagData.' stars';
//If the rating is in thumbs...
if($rating->tagAttrs['type'] == 'thumbs')
echo $rating->tagData.' thumbs up';
}
?>
如你所见,属性可以从tagAttrs访问,字符数据则从tagData。非常简单,不是吗?
值的设置与比较
我们不会去依靠PHP5中的任何新的面向对象特性来使这个解析器更容易使用(再次声明,这是为了兼容PHP4),尽管使用这些特性能让值的设置和比较变的容易得多。在SimpleXML中,你需要进行强制类型转换才能像使用string类型一样使用它们。相比之下,在XMLParser中,你不必再进行类型转换。直接使用 = 或者 == 就能让程序很好的运作了。要确保你正在使用的是tagData,tagAttrs,或者其他的XMLTag成员。如果不是以上情况,那么就成了对一个对象进行字符串操作,这会导致一个PHP错误。XMLTag的其它成员
如果你花了点时间看了源代码,那么你可能已经注意到XMLTag类中还有一些其他成员。它们的说明如下:| 成员 | 说明 |
| tagChildren | 这个成员是一个数组,包含了对给定对象的所有直接子标签的引用,并以它们在XML中出现的顺序为序。这只是为通过名称访问子标签的方法提供了一种替代方案,并常被用在名称可以是任意的或者是未知的情况下。 |
| tagParents | 这个成员包含了这个对象到文档根标签为止的祖先标签数量。这个成员通常只用于决定要使用多少个标签来更好的格式化XML文档的输出。/td> |
| tagName | 这个成员包含了当前标签的名称。同样,这也只用于解决XML文档的输出问题 |
输出XML文档
假如仅仅做到兼容PHP4和PHP5地对XML文档进行解析还不够的话,这个系统中还有一个函数来对XML文档进行输出。大多数情况下,这个函数仅仅是我用来确认这个系统能够解析整个XML树并且不必使用大量难以阅读的var_dump()声明,不过这个函数也能用来修改XML树并输出它,又或者是创建一个完全新的文档树,并得到它的XML文档。要访问这个函数,只需简单地输出XMLParser对象的GenerateXML()方法的返回值。就像下面所列的那么简单。输出XML文档
<?php
echo $parser->GenerateXML();
?>
这段代码将从根标签开始对XML进行输出。如果你希望从文档树的更深处开始输出,你可以调用任何你想要的XMLTag对象的GetXML()方法。