淺談PHP處理XML文檔的技術手段(一)——SAX解析器

前段時間自學了使用php代碼來實現相應的解析器,現在將其重點歸納一下。
**內容:
1.XML解析器介紹
2.SAX解析器的介紹及函數庫的使用
3.使用SAX解析器對XML進行處理**

這裏先來講一下XML解析器的概念。它其實是一個程序,能夠用來讀取、解析和驗證XML文檔。XML解析器爲程序員提供了二次開發的軟件包,程序員通過調用其提供的函數接口,從而對XML文檔執行各種操作。

如今各種主流的Web瀏覽器其實都包含內置的XML解析器,用來解析XML文檔,以便在瀏覽器中以指定的格式輸出XML文檔。

在php中,有多種技術能夠用來處理XML文檔。例如SAX解析器、DOM解析器、SimpleXML解析器、XMLReader類庫以及XSL處理函數。前四種用來讀取和解析XML文檔,同時完成對XML文檔的有效性檢驗,而XSL處理函數用來轉換XML文檔,以便在瀏覽器上顯示其內容。要在php中解析XML文檔,需要在其代碼中對解析器進行初始化,並調用其內置函數進行處理。

XML可分爲兩類:(1).基於事件驅動的XML解析器。(2).基於樹的XML解析器。

對於前者,它在內存中不斷處理XML數據和標籤,一次處理一個。對於這類的解析器,當它遇到XML文檔中任何XML元素或者數據時,它會產生一個事件,並調用相應的事件處理程序來進行處理。
這類解析器典型的代表有:SAX解析器。

SAX(Simple API for XML)解析器,它按照順序處理XML文檔,當它掃描到各類元素標籤時,調用相應的處理程序(這些處理程序爲程序員自己定義,也稱之爲回調函數)完成相應的處理,直至XML文檔結束。

SAX解析器是把XML文檔當成字符串進行處理,適合對一種元素進行重複處理。它的缺點也很明顯,因爲它是順序處理的,並且在解析時,它並沒有將整個XML文檔裝入內存中。因而,它不能隨機讀取任何一個元素,也不能實現複雜的搜索。對於內部結構交叉引用的文檔,它處理起來比較吃力。

接下來,將分析SAX解析器的函數庫:
1.創建新的XML解析器句柄
例如:

//對解析器進行初始化
$xparser=xml_parser_create("utf-8");

它的格式爲 int xml_parser_create([string encoding])
enconding參數爲解析後出去數據的編碼,php5及其以上版本默認的值爲UTF-8。
該函數執行成功會返回一個可被其他XML函數使用的XML解析器句柄。
2.註冊元素的開始標籤和結束標籤的回調函數
例如:

//註冊開始標籤和結束標籤的回調函數
xml_set_element_handler($xparser,"startHandler","endHandler");

第一個參數爲XML解析器句柄,第二第三個參數分別爲開始標籤和結束標籤的回調函數名,註冊成功則返回TRUE,註冊失敗則返回FALSE。這兩個回調函數都需要程序員自己定義。
例如:
開始標籤的回調函數:

/**
 * 開始標籤的回調函數
 * @param $xparser XML解析器語句句柄
 * @param $element_name 元素名稱
 * @param $attributes 包含這個元素所有屬性的關聯數組,數組元素的下表爲屬性名稱,元素的值爲屬性的值
 */
 function startHandler($xparser,$element_name,$attributes){
    if($element_name=="department"){
        echo'<center><table border="1" cellpadding="0" cellspacing="0">';
    }else if($element_name=="employee"){
        echo'<tr>';
    }else if($element_name=="name")
    {  /**
        *PHP的list()和each()函數訪問數組變量
        */
        list($key,$value)=each($attributes);
        echo "<td>".$value."</td><td>";            
    }else{
        echo"<td>";
    }
 }

結束標籤的回調函數:

/**
 *結束標籤的回調函數
 * @param unknown $xparser
 * @param unknown $element_name
 */
 function endHandler($xparser,$element_name)
 {
    if($element_name=="department"){
        echo"</table></center>";
    }else if ($element_name=="employee"){
        echo"</tr>";
    }else{
        echo"</td>";
    }
 }

一般來說,先定義好這個兩個回調函數,再調用xml_set_element_handler()函數註冊它們。
3.註冊字符處理數據回調函數
例如:

//註冊字符處理的回調函數
xml_set_character_data_handler($xparser, "cdataHandler");

第一個參數爲XML解析器句柄,第二個參數爲字符數據處理回調函數的名稱,需要在註冊前定義好它,該函數返回類型爲bool型。
字符數據處理的回調函數:
例如:

/**
 * 字符處理的回調函數
 * @param unknown $xparser
 * @param unknown $cdata XML文檔中元素的內容,爲一字符串
 */
 function cdataHandler($xparser,$cdata){
    echo $cdata;
 }

4.註冊指令處理的回調函數
例如:

//註冊指令處理的回調函數
xml_set_processing_instruction_handler($xparser,"xprocess");

第一個參數爲解析器句柄,第二個參數爲指令處理回調函數。該函數返回類型爲bool型。
指令處理函數爲:

function xprocess($xparse,"notepad","d:\demo.txt"){
...
}

指令處理函數格式爲:
handler(int parser,string target,string data)
函數名可任意,第二個參數爲處理指令的目標程序,即應用程序名。第三個參數誒傳給目標程序的參數,比如地址等等。
5.註冊註釋聲明處理函數
例如:

//註冊註釋聲明處理回調函數
xml_set_notation_decl_handler($xparser,"notationHandler");

第二個參數爲註釋聲明處理回調函數的名稱,該函數返回類型爲bool型。
其格式爲:handler(int parser,string notation_name,string base,string system_id,string public_id)
第二個參數爲註釋聲明定義中的註釋名稱,第三個base通常設置爲空字符串,第四個參數爲外部註釋聲明的系統標識符,第五個參數爲外部註釋聲明的公共標識符。
例如:

function xnotation($xparser,"gif",",","file:///user/bin/",""){
...
}

6.註冊默認回調函數
例如:

//註冊默認回調函數
xml_set_default_handler($xparser,"defaultHandler");

第二個參數爲默認回調函數名,該函數返回類型爲bool型。
默認回調函數的格式爲:
default_handler(int parser,string data)
其中,data參數爲掃描到無法處理的全部數據,它的內容可以是XML聲明、實體名、文檔類型聲明等等。
7.解析XML文檔的函數
格式爲:int xml_parse(int parser,string data,[,bool is Final])
data參數爲需要解析的數據集,可以通過改變data參數的內容,多次調用這個函數來處理文檔。isFinal參數是可選的,如果其值爲true,則是最後一次調用該函數。此時data值爲解析中的最後一段數據。如果成功返回TRUE,失敗返回FALSE。
8.獲取XML解析器錯誤代碼:
格式爲:int xml_get_error_code(resource parser)
9.獲取XML解析器錯誤信息:
格式爲:string xml_error_string(int code)
以上三個函數經常放在一起使用
例如:

include "AddInfoToXML.php";
//指示所要解析的XML文檔的路徑
$xfile=Addbook($xmlfile,"S0003","張三","21","廣州市","數據分析師");
...
//打開xml文檔
if(!($fp=fopen($xfile,"r"))){
    die("打開文件錯誤:$xfile");
}
//每次讀取4KB的內容進行解析
while($data=fread($fp, 4096)){
    if(!xml_parse($xparser, $data,feof($fp))){
        $err=xml_get_error_code($xparser);
        die("XML解析錯誤:xml_error_string($err)");
    }
}

10.釋放XML解析器函數
例如:

//釋放XML解析器
xml_parser_free($xparser);

以上便是SAX解析器常用的函數。
瞭解了上述函數之後,我們可以通過SAX解析器的來對XML進行分析、轉換等等操作。
例如我們可以通過SAX將XML文檔轉換爲HTML文檔,使其在瀏覽器上能夠以你想要的格式顯示。

<html>
<head>
    <meta http-equiv="content-type" content="text/html;charset=utf-8">
    <title>Simple API for XML example</title>
</head>
<body>
<?php
/**
 * 開始標籤的回調函數
 * @param $xparser XML解析器語句句柄
 * @param $element_name 元素名稱
 * @param $attributes 包含這個元素所有屬性的關聯數組,數組元素的下表爲屬性名稱,元素的值爲屬性的值
 */
function startHandler($xparser,$element_name,$attributes){
    if($element_name=="department"){
        echo'<center><table border="1" cellpadding="0" cellspacing="0">';
    }else if($element_name=="employee"){
        echo'<tr>';
    }else if($element_name=="name")
    { /**
       *PHP的list()和each()函數訪問數組變量
       */
        list($key,$value)=each($attributes);
        echo "<td>".$value."</td><td>";
    }else{
        echo"<td>";
    }
}
/**
 *結束標籤的回調函數
 * @param unknown $xparser
 * @param unknown $element_name
 */
function endHandler($xparser,$element_name)
{
    if($element_name=="department"){
        echo"</table></center>";
    }else if ($element_name=="employee"){
        echo"</tr>";
    }else{
        echo"</td>";
    }

}
/**
 * 字符處理的回調函數
 * @param unknown $xparser
 * @param unknown $cdata XML文檔中元素的內容,爲一字符串
 */
function cdataHandler($xparser,$cdata){
    echo $cdata;
}

//指示所要解析的XML文檔的路徑
$xfile="Company.xml";
//對解析器進行初始化
$xparser=xml_parser_create("utf-8");
//註冊開始標籤和結束標籤的回調函數
xml_set_element_handler($xparser,"startHandler","endHandler");
//註冊字符處理的回調函數
xml_set_character_data_handler($xparser, "cdataHandler");
//打開xml文檔
if(!($fp=fopen($xfile,"r"))){
    die("打開文件錯誤:$xfile");
}
//每次讀取4KB的內容進行解析
while($data=fread($fp, 4096)){
    if(!xml_parse($xparser, $data,feof($fp))){
        $err=xml_get_error_code($xparser);
        die("XML解析錯誤:xml_error_string($err)");
    }
}
//釋放XML解析器
xml_parser_free($xparser);
?>
</body>
</html>

對SAX解析器的就先收到這,對於其他的XML解析器將在之後的文章中進行淺談。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章