文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>PHP和XML:使用expat函数

PHP和XML:使用expat函数

时间:2007-02-17  来源:PHP爱好者

可扩展标识语言(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 wit

h work(have to pay those bills!). <newline></newline>

I have just finished a neat little script that stores a complete recor

d 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 a

s 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 customi

ze 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?!&qu

ot;.<newline></newline>

Well it's a simple news system for web-sites, written in PHP, that mak

es use of XML for <newline></newline>

the news data format allowing easy updating and portability between pl

atforms. It uses the built in expat parser for Apache. This is just th

e very first version and there will be loads of improvements as the pr

oject 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 footbal

l with the bad guys. <newline></newline>

The official website for the movie is <A HREF='http://www.romeo-mus

t-die.com'> here </A> <newline></newline><newline></newline>

</text>

<IMG SRC="http://a1996.g.akamaitech.net/7/1996/25/e586077a88e7

a4/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类格式所建立的故事了。

  让我们看一下实际处理这个文档的PHP代码。

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

<?php

/*NewsBoy : News system for the web written in PHP by Justin Grant (We

b:jusgrant.cjb.net or justin.host.za.net Mail: [email protected]) 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 littl

e easier to read.24 March V0.0.1 Just completed the intial version, ve

ry 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=#BBBB

00>",

"SLUG" => "<FONT COLOR=#00AACC><B>  ",

"TEXT" => "<FONT COLOR=#AAAAAA>", "PIC" => "",

"NEWLINE" => ""

);

$this->close_tag = array(

"NEWSBOY" => "</TABLE>n<!-- XML Ends here -->nn",

"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 suppor

t 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, tr

ue);

xml_set_element_handler($this->xml_parser, "startElement", "endEleme

nt");

xml_set_character_data_handler($this->xml_parser,"characterData");

//xml_set_processing_instruction_handler($this->xml_parser,"PIHandle

r");

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_er

ror_code($this->xml_parser)),xml_get_current_line_number($this->xml_pa

rser)));

}

}

}

}

?>

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

  在这个类的构造函数中,我创建了打开与关闭两个标记数组。数组的关键

字与我后面将要分析的标记是一样的,并且它们相应的值包含格式化打开与关

闭标记的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文件并且分析它。如果一个错误发生,那么

错误明细将返回,包括错误发生的行号。

  如何在一个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站点)
php爱好者站 http://www.phpfans.net dreamweaver|flash|fireworks|photoshop.
相关阅读 更多 +
排行榜 更多 +
辰域智控app

辰域智控app

系统工具 下载
网医联盟app

网医联盟app

运动健身 下载
汇丰汇选App

汇丰汇选App

金融理财 下载