标题PHP 和 XML: 使用expat函数
日期:    作者:爱好者   来源:php之家
文章打印自:
访问文章完全地址:
头部广告
PHP 和 XML: 使用expat函数
译者:limodou 可扩展标识语言(Extensible Markup Language )明显是大多数开发人员将想要将其加入到他们的工具箱
中的东西。XML是一种W3C的标准,它是开放的,语言中性的,API中性的,流式的,文本的,人类可读 的,
并且是一种将结构化数据带到web上的一种方法。XML是SGML的一个子集,它本身并不是一种标识 语言,但是
它允许作者来定义他们自已的标识语言,以便同分级数据保持更好的一致性。

 

现在,用PHP 分析XML文档已经不是一个象我以前在web和其它地方所看到的被覆盖得很深的专题了。 在
PHP手册中已经提供了一些对XML分析函数非常有用的信息,但是这个看上去好象就是我所能找到的 全部的信
息了。其它的语言看上去比PHP已经有了更多的关于XML的信息和工作实例,所以在这篇文章 中,我将试图为
改变这种情况作出我的一部分努力。

我将带领读者体验一个相当简单的XML的应用,那个应用是为我的网站所做的新闻系统的实现。我确实在
我的网站使用了这个应用,现在它工作的很好。如果你喜欢你可以自由地使用它。好了,让我们开始吧!

为了在PHP中使XML分析函数有效,你需要一个支持XML 的模块在你的web服务器上。这就意味着你将可能
不得不重新编译你的模块,以便可以支持XML,请参考这里来查看如何做到的更多的信息。XML 分析函数现在
真正地包含在一种SAX分析器expat中,它提供了 关于XML的简单的函数。另一种分析器是DOM分析器,它更容
易使用,关于它的一个例子就是微软的MSXML分析器组件,它可以让程序员通过操纵一种树状样式的对象来处
理结点和元素。expat分析器(或任意的SAX 分析器)允许你分析一个XML文档的实现方法是在对XML文档进行分
析的时候对不同的标记类型指定回调函数来完成的。当分析器开始分析你的XML文档并且遇上了一个标记,它
将调用你的函数,并且在继续往下 执行之前由你的函数对特定的标记进行处理。你可以把它看作是一种事件
驱动的方法。

让我们看一个使用'Newsboy'类来分析的XML文档

 

--------------------------------------------------------------------------------
mynews.xml

<?xml version="1.0" standalone="no"?>
<!DOCTYPE NewsBoy SYSTEM "NewsBoy.dtd">

<NewsBoy>

<story>
<date>03/31/2000</date>
<slug>Sooo Busy !</slug>
<text>
I haven't posted anything here for a while now as I have been busy with work(have to pay those
bills!). <newline></newline>
I have just finished a neat little script that stores a complete record set in a session
variable after <newline></newline>
doing an SQL query. The neat part is that an XML doc is stored in the session variable
an when paging <newline></newline>
through the results (often near 1000!) the script displays 50 results at a time from the
XML doc in the <newline></newline>
session variable instead of doing another query against the database. It takes a BIG load
off of the <newline></newline>
database server.
</text>
</story>

<story>
<date>03/25/2000</date>
<slug>NewsBoy Class</slug>
<text>
Converted Newsboy to a PHP class to allow better abstraction (as far as PHP allows.)
<newline></newline>
Guess that means this is version 0.02 ?!<newline></newline>
Newsboy will have a section of it's own soon on how to use and customize the class.
<newline></newline>
</text>
</story>

<story>
<date>03/24/2000</date>
<slug>NewsBoy is up!</slug>
<text>
I have just finished NewsBoy v0.01 !!! <newline></newline>
It looks quite promising. You may ask, ""What the heck is it?!".<newline>
</newline>
Well it's a simple news system for web-sites, written in PHP, that makes use of XML
for <newline></newline>
the news data format allowing easy updating and portability between platforms.
It uses the built in expat parser for Apache.
This is just the very first version and there will be loads of improvements as the
project progresses.
</text>
</story>

<story>
<date>03/24/2000</date>
<slug>Romeo must Die</slug>
<text>
Saw a really cool movie today at Mann called 'Romeo must Die' <newline></newline>
Nice fight scenes for a typical kung-fu movie with some 'Matrix' style effects.<newline>
</newline>
One particular cool effect was the 'X-Ray Vision' effect that occured in various
fight scenes. <newline></newline>
The hero, played by Jet Li, strikes a bad guy and you can see the bone in his arm
crack, in X-RAY vision. <newline></newline>
There were some funny scenes too when Jet has to play American football with the
bad guys. <newline></newline>
The official website for the movie is <A HREF='http://www.romeo-must-die.com'
> here </A> <newline></newline>
<newline></newline>
</text>
<IMG SRC="http://a1996.g.akamaitech.net/7/1996/25/e586077a88e7a4/
romeomustdie.net/images/image15.jpg" WIDTH=300 >
</story>

</newsboy>

译者注:上面的代码中为了排版,我作了换行处理。


--------------------------------------------------------------------------------


好,如果你对XML文档不是很熟悉的话,那么这个看上去可能有一点令人吃惊,相当的不好理解。第一行
是一个XML的声明。'version'属性告诉分析器这篇文档是遵守W3C所定义的XML 1.0标准的。'standalone' 选
项表示分析这篇文档的分析器需要一个DTD定义来验证XML文档(在这个例子中,DTD存在于一个存立的 文件中,
名字是'NewsBoy.dtd',就是通过下一行DOCTYPE声明所指定的,但是如果你愿意你也可以在同 一个文档中来
定义它)。DOCTYPE声明指出了XML文档的根元素,在这个例子中是'NewsBoy'元素。同时它也 指出了DTD与XML
文档存在于同一目录下。请注意,我没有验证XML文档所对应的DTD,因为expat 不能验证一个XML文档。根据
expat的作者James Clark所说,原因是这个分析器是同W3C关于XML的分析器 的说明书一致的,那里面的分析
器不需要验证文档的有效性,但是程序员应该去处理它。

后面的部分就是包括了按我定义的NewsBoy类格式所建立的故事了。

转自PHPBuilder.com

 

PHP 和 XML: 使用expat函数
让我们看一下实际处理这个文档的PHP代码。

 

 


--------------------------------------------------------------------------------

<?php
/*NewsBoy : News system for the web written in PHP by Justin Grant (Web: jusgrant.cjb.net or justin.host.za.net Mail: justin@glendale.net)25 March V0.0.2 Converted Newsboy to a PHP class, allowing the layout to be easily modified. Also added made the HTML that is genrated a little easier to read.24 March V0.0.1 Just completed the intial version, very rough and basic.*/
class newsboy { var $xml_parser; var $xml_file; var $html; var $open_tag ; var $close_tag ;
//Class Constructor
function newsboy() { $this->xml_parser = ""; $this->xml_file = ""; $this->html = ""; $this->open_tag = array(
//these are the default settings but they are quite easy to modify
"NEWSBOY" => "\n<!-- XML Starts here -->\n<TABLE COLS=1 CELLPADDING=5>", "STORY" => "<TR><TD BGCOLOR=#222222>", "DATE" => "<FONT COLOR=#BBBB00>", "SLUG" => "<FONT COLOR=#00AACC><B>  ", "TEXT" => "<FONT COLOR=#AAAAAA>", "PIC" => "", "NEWLINE" => "" ); $this->close_tag = array( "NEWSBOY" => "</TABLE>\n<!-- XML Ends here -->\n\n", "STORY" => "</TD></TR>", "DATE" => "</FONT>", "SLUG" => "</B></FONT><BR>", "TEXT" => "</FONT>\n", "PIC" => "<IMAGE SRC=", "NEWLINE" => "<BR>" ); }
//Class Destructor (has to be invoked manually as PHP does not support destructors)

function destroy() { xml_parser_free($this->xml_parser); }
//Class Members
function concat($str) { $this->html .= $str; }
function startElement($parser, $name, $attrs) { //global $open_tag; if ($format= $this->open_tag[$name]) { $this->html .= $format; } }
function endElement($parser, $name) { global $close_tag; if ($format= $this->close_tag[$name]) { $this->html .= $format; } }
function characterData($parser, $data) { $this->html .= $data; }
/* function PIHandler($parser, $target, $data) { //switch (strtolower($target)){ // case "php": eval($data); // break; //} }*/
function parse() { $this->xml_parser = xml_parser_create(); xml_set_object($this->xml_parser, &$this); // use case-folding so we are sure to find the tag in $map_array
xml_parser_set_option($this->xml_parser, XML_OPTION_CASE_FOLDING, true); xml_set_element_handler($this->xml_parser, "startElement", "endElement"); xml_set_character_data_handler($this->xml_parser, "characterData");//xml_set_processing_instruction_handler($this->xml_parser, "PIHandler");
if (!($fp = fopen($this->xml_file, "r"))) { die("could not open XML input"); } while ($data = fread($fp, 4096)) { if (!xml_parse($this->xml_parser, $data, feof($fp))) { die(sprintf("XML error: %s at line %d", xml_error_string(xml_get_error_code($this->xml_parser)), xml_get_current_line_number($this->xml_parser))); } } }}
?>

 

--------------------------------------------------------------------------------

在这个类的构造函数中,我创建了打开与关闭两个标记数组。数组的关键字与我后面将要分析的标记是
一样的,并且它们相应的值包含格式化打开与关闭标记的HTML代码。

我定义了一个简单的类析构函数用来当我们不再需要它时释放XML 分析器。这个函数不得不手工调用,
因为PHP不支持当一个对象释放时自动调用类的析构函数。

然后我定义了在XML文档中用来分析打开和关闭标记的主回调方法。我也定义了一个数据分析方法, 将
用于当打开和关闭标记中有数据时,对数据进行简单的格式化,后面我将向你演示如何将这些回调方法注册
到分析器中。

在startElement和closeElement(当分析到一个打开或关闭标专时被分别调用)中使用 标记的名字
作为索引键值对相应的数组进行查询。如果那个键值存在,则返回值并且追加到类的'html' 属性的后面。
'html'属性将在以后我们真正显示文档内容的时候使用。

characterData方法简单地将标记之间的值加到类的html属性的后面。

被注释起来的叫PIHandler的方法是一个回调函数,我还未曾实现它。如果它存在的话,它将直接在XML
文档中处理php脚本。

现在,让我解释一下主要的分析方法的调用,你猜一猜,parse()!!!

第一行调用了函数xml_parser_create(),它将返回一个expat的xml分析器的实例,并且被保存在类的
属性&this->xml_parser中。

下一步,我们需要用函数xml_set_object()来注册一个类方法的回调函数。

我是这样使用的,xml_set_object($this->xml_parser, &$this)。我在第一个参数中指定了用
来保存xml 分析器的类属性,然后在第二个参数,我指定了PHP对象的实例地址。这个可以让分析器 知道全
部将要注册的回调函数,是在那个地址上指定类的实际的方法。这就象c或c++中的一个'引用传递',也有人
简单地叫做'引用变量'。

在下一行,我调用了xml_parser_set_option()设置了一个xml分析器的属性,使用大小写折叠( case
folding)。大小写折叠只是告诉分析器知道,当我分析我的XML文档时我并不关心大小写敏感,但是 如果你
想使用大小写敏感来定义两个不同的标记,如<Story>或<story>,你可以不设置它。

通过使用xml_set_element_handler(),我指定了用于开始和结束标记的回调函数,名字是
"startElement"和"endElement"。

接着,我使用xml_set_character_data_handler()来指定字符数据的处理句柄为名为
characterData()的回调函数。被注释的函数调用,xml_set_processing_instruction_handler(),
是一个我用于注册函数 PIHandler()的调用。PIHandler可以被包括在XML文档中处理php代码。

其它的代码只是很简单地读XML文件并且分析它。如果一个错误发生,那么错误明细将返回,包括错误
发生的行号。

转自PHPBuilder.com
译者:limodou

PHP 和 XML: 使用expat函数
译者:limodou 如何在一个PHP 脚本中使用这个类呢?实际上非常简单。这里有一个例子:

 


首先类定义需要被包括在脚本中

require (CLASS_DIR."class.Newsboy.php");

然后,我们创建一个类的实例,并且设置文件性为我们的XML文档的实际链接。

$news = new newsboy();
$news->xml_file = "xml/mynews.xml";

$news->xml_file = "http://xmldocs.mysite.com/mynews.xml"

然后我们调用分析器来分析文档。

$news->parse();

然后我们打印html到屏幕上。

print ($news->html);

并且,在最后在完成时必须释放类。

$news->destroy();

这就是所有要做的事。

小节
在这篇简短的文件中,我们涉及了使用PHP来处理XML的流程:


简单的XML文档结构
为XML分析器定义简单的标记
设置XML分析器的简单选项
向XML分析器注册回调函数
通过一个PHP类来使用XML分析器
在另一个脚本中使用PHP类
我希望这个介绍能够帮助你通过PHP开始和探索XML的力量。下面列出一些可能对你有帮助的链接:

http://www.phpbuilder.com/manual/ref.xml.php (PHP XML函数参考)
http://www.jclark.com/xml/ (James Clark的XML资源)
http://www.ibm.com/developer/xml/ (IBM的XML站点)

转自PHPBuilder.com

 

责任编辑:semirock