明輝手游網(wǎng)中心:是一個免費提供流行視頻軟件教程、在線學習分享的學習平臺!

PHP中的XML應用(二)

[摘要]如何對文檔進行解析?   在完成所有的準備工作后,現(xiàn)在腳本終于可以解析XML文檔: Xml_parse_from_file(),一個自定義的函數(shù),打開參數(shù)中指定的文件,并以4kb的大小進行解析 xml_parse(),和xml_parse_from_file()一樣,當發(fā)生錯誤時,即XML文檔...
如何對文檔進行解析?
  在完成所有的準備工作后,現(xiàn)在腳本終于可以解析XML文檔:

Xml_parse_from_file(),一個自定義的函數(shù),打開參數(shù)中指定的文件,并以4kb的大小進行解析
xml_parse(),和xml_parse_from_file()一樣,當發(fā)生錯誤時,即XML文檔的格式不完全時,將會返回false。

  我們可以使用xml_get_error_code()函數(shù)來得到最后一個錯誤的數(shù)字代碼。將此數(shù)字代碼傳遞給xml_error_string()函數(shù)即可得到錯誤的文本信息。輸出XML當前的行數(shù),使得調(diào)試更容易。

  當解析文檔時,對于Expat需要強調(diào)問題的是:如何保持文檔結(jié)構(gòu)的基本描述?

  如前所述,基于事件的解析器本身并不產(chǎn)生任何結(jié)構(gòu)信息。不過標簽(tag)結(jié)構(gòu)是XML的重要特性。例如,元素序列<book><title>表示的意思不同于<figure><title>。書名和圖名是沒有關(guān)系的,雖然它們都用到"title"這個術(shù)語。因此,為了更有效地使用基于事件的解析器處理XML,必須使用自己的棧(stacks)或列表(lists)來維護文檔的結(jié)構(gòu)信息。

  為了產(chǎn)生文檔結(jié)構(gòu)的鏡像,腳本至少需要知道目前元素的父元素。用Exapt的API是無法實現(xiàn)的,它只報告目前元素的事件,而沒有任何前后關(guān)系的信息。因此,需要建立自己的棧結(jié)構(gòu)。

  腳本范例使用先進后出(FILO)的棧結(jié)構(gòu)。通過一個數(shù)組,棧將保存全部的開始元素。對于開始元素處理函數(shù),目前的元素將被array_push()函數(shù)推到棧的頂部。相應的,結(jié)束元素處理函數(shù)通過array_pop()將最頂?shù)脑匾谱摺?

  對于序列<book><title></title></book>,棧的填充如下:

開始元素book:將"book"賦給棧的第一個元素($stack[0])。
開始元素title:將"title"賦給棧的頂部($stack[1])。
結(jié)束元素title:從棧中將最頂部的元素移去($stack[1])。
結(jié)束元素title:從棧中將最頂部的元素移去($stack[0])。

  PHP3.0通過一個$depth變量手動控制元素的嵌套來實現(xiàn)范例,這就使腳本看起來比較復雜。PHP4.0通過array_pop()和array_push()兩個函數(shù)來使腳本看起來更簡潔。

如何收集XML文檔中的元素信息?

  為了收集每個元素的信息,腳本需要記住每個元素的事件。通過使用一個全局的數(shù)組變量$elements來保存文檔中所有不同的元素。數(shù)組的項目是元素類的實例,有4個屬性(類的變量)

$count -該元素在文檔中被發(fā)現(xiàn)的次數(shù)
$chars -元素中字符事件的字節(jié)數(shù)
$parents -父元素
$childs - 子元素

  注意:PHP的一個特性是你可以通過while(list() = each())loop遍歷整個類結(jié)構(gòu),如同你遍歷整個相應的數(shù)組一樣。所有的類變量(當你用PHP3.0時還有方法名)都以字符串的方式輸出。

  當發(fā)現(xiàn)一個元素時,我們需要增加其相應的記數(shù)器來跟蹤它在文檔中出現(xiàn)多少次。在相應的$elements項中的記數(shù)元素也要加一。

  我們同樣要讓父元素知道目前的元素是它的子元素。因此,目前元素的名稱將會加入到父元素的$childs數(shù)組的項目中。最后,目前元素應該記住誰是它的父元素。所以,父元素被加入到目前元素$parents數(shù)組的項目中。

顯示統(tǒng)計信息
  剩下的代碼在$elements數(shù)組和其子數(shù)組中循環(huán)顯示其統(tǒng)計結(jié)果。這就是最簡單的嵌套循環(huán),盡管輸出正確的結(jié)果,但代碼既不簡潔又沒有任何特別的技巧,它僅僅是一個你可能每天用他來完成工作的循環(huán)。

  腳本范例被設計為通過PHP的CGI方式的命令行來調(diào)用。因此,統(tǒng)計結(jié)果輸出的格式為文本格式。如果你要將腳本運用到互聯(lián)網(wǎng)上,那么你需要修改輸出函數(shù)來產(chǎn)生HTML格式。

如何用PHP&XML編制一個迷你搜索引擎實例?
  讓我們首先來熟悉一下我們程序中用到的那個XML(保存為xyz.xml)。

<?xml version="1.0" encoding="gb2312" ?>
<links>采用PHP和XML技術(shù)構(gòu)建的搜索引擎
<web memo="memo1" url="">name1</web>
<sub>電腦網(wǎng)絡
<web memo="nemo2">name2</web>
<sub>程序設計
<web memo="memo3">name3</web>
<sub>PHP
<web url="http://www.phpbuilder.com/" memo="[英文]PHP開發(fā)資源。">
www.phpbuilder.com</web>
<web url="http://www.fokus.gmd.de" memo="[英文]PHP開發(fā)手冊。 ">
PHP Manual</web>
</sub>
</sub>
</sub>
</links>

它的結(jié)構(gòu)相當簡單,根元素就是links,sub代表著一個類別,web就是一個網(wǎng)站的信息,其中包含著屬性,url代表網(wǎng)站的聯(lián)接,memo為備注信息,<web>??</web> 、<sub>??</sub>中包含的為元素的數(shù)據(jù)在這里就是類別和網(wǎng)站的名稱,這是符合上面的規(guī)定的。

現(xiàn)在我們來回答上面提出的問題:為什么要用XML來編制搜索引擎?
第一個原因就是有時候由于各種原因我們可能不能用到數(shù)據(jù)庫(MySQL或者其他);
其次,對于小數(shù)據(jù)量的搜索引擎來說,它的數(shù)據(jù)量很小,如果用數(shù)據(jù)庫來做,效率未必有多高;

最重要的一點是,這個搜索引擎維護起來相當?shù)暮唵,并且不用編寫繁瑣的?shù)據(jù)庫的維護的程序。例如,我們要添加一個類別或者網(wǎng)頁,只要編輯文本的文件,加上一福紈eb>???</web>或是<sub>????</sub>就可以了,而且,如果想把一個類別移動到另一個地方的話,我們只要將這一部分的sub復制過去就行了。

下面一個最簡單的用PHP顯示XML的范例。

下面的程序是將解析XML并按照樹形結(jié)構(gòu)輸出至瀏覽器,并顯示每層的元素總數(shù)。

<?php
$file = "demo.xml";// XML文件
function xml_parse_from_file($parser, $file) {// 解析XML文件的函數(shù) }
function start_element($parser, $name, $attrs) {//遇到了開元素標記如<a href="link">就執(zhí)行這一段}
function stop_element($parser, $name) {//遇到了開元素標記如</body>就執(zhí)行這一段}
function data($parser, $data) {……}
function showcount(){ //顯示每一層的元素總數(shù)}

global $level,$levelcount,$maxlevel;
$level = -1;
$parser = xml_parser_create();// 產(chǎn)生解析器的實例
xml_set_element_handler($parser, "start_element", "stop_element"); // 設置處理函數(shù)
xml_set_character_data_handler($parser, "data");
xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
$ret = xml_parse_from_file($parser, $file); // 解析文件
if(!$ret) {
die(sprintf("XML error: %s at line %d", xml_error_string(xml_get_error_code($parser)), xml_get_current_line_number($parser)));
}
xml_parser_free($parser); // 釋放解析器
showcount();
?>

在上面的程序的基礎(chǔ)上,可以顯示一段子樹,我們依照元素的層數(shù)和他在該層的第幾號來對他進行定位

例如:

links (0,1)
+----web (1,1)
+----sub (1,2)
 +----web (2,1)
 +----sub (2,2)
 +----web (3,1)
 +----sub (3,2)
:
:
:
下面的代碼是我們的搜索引擎的基礎(chǔ)。因為,要顯示出一個子類別(如程序設計->PHP->)的信息就要用到他。

<?php
……
function start_element($parser, $name, $attrs) {
global $level,$levelcount,$maxlevel,$hide,$lev,$num,$PHP_SELF;
$level += 1;
if($level>$maxlevel)
$maxlevel=$level;
$levelcount[$level]+=1;

if($hide){ //判斷是否在子樹的范圍內(nèi),$hide==FALSE 為在
if($level==$lev&&$levelcount[$level]==$num)
$hide=FALSE;
}else{
if($level<=$lev)$hide=TRUE;
}

if(!$hide){
……//輸出
}
}
function data($parser, $data) {
global $level,$hide;
if(!$hide){
if(trim($data)!=""){ echo trim($data); }
}
}
……
global $hide,$lev,$num,$PHP_SELF;
$level = -1;
$hide = TRUE;
echo "<p><a href=$PHP_SELF>Root</a></p>";
if($lev==""){
$lev=0;$num=1;
}
……
?>

mini的搜索引擎到底如何做呢?

作了若干的鋪墊,下面我們就來看一下我們的搜索引擎的主要文件。

第一段為仿sina,yahoo的按照類別查詢
第二段為搜索查詢部分(把整個樹遍歷一遍)顯示符合的內(nèi)容。

xml3.php

關(guān)鍵字匹配采用eregi函數(shù),我們假設輸入的文字都是不會導致錯誤的。

<全文完>



相關(guān)文章