PHP解析XML

前言

這篇文章的面向對象是所有對PHP5的XML新功能感興趣的各個水平的PHP開發者。我們假定讀者掌握XML的基本知識。然而,如果你已經在你的PHP當中使用了XML,那麼這篇文章也會讓你受益非淺。

介紹

在當今的互聯網世界,XML已經不再是一個時髦詞了,它已經被廣泛的接受和規範的使用了。因此相對於PHP4,PHP5對於XML的支持更受到了重視。在PHP4中你面對的幾乎都是非標準,API中斷,內存泄漏以及其它不完全的功能。儘管有些不足已經在PHP4.3中得到改進,開發者們還是決定拋棄原有的代碼,在PHP5重寫全部代碼。

這篇文章將對PHP5中關於XML的所有令人激動的新特性逐一介紹。

PHP4 的 XML

早期的PHP版本就已經開始支持XML了,而這只是一個基於SAX的接口,它可以輕鬆的解析任何XML文檔。隨着PHP4中加入了DOMXML擴展模塊,XML被更好的支持了。後來XSLT做爲補充被加了進來。在整個PHP4的階段,其它一些功能如HTML,XSLT和DTD驗證也被加到了DOMXML擴展中,不幸的是,由於XSLT和DOMXML擴展始終處於實驗階段,API部分也被不止一次的修改,它們還是不能以默認方式安裝。此外,DOMXML擴展沒有遵循W3C制定的DOM標準,而有自己的命名方法。雖然在PHP4.3中這部分得到了改善並且許多內存泄漏和其它一些功能也得以修復,但它始終沒有發展到一個穩定的階段,一些深入的問題已經幾乎不可能修復。只有SAX擴展被已默認方式安裝,其它的一些擴展從未得到廣泛的使用。

基於所有這些原因,PHP的XML開發者決定在PHP5重寫全部代碼,並遵循使用標準。

PHP5的XML
在PHP5中所有支持XML的部分幾乎全部重新編寫.現在的所有XML擴展都是基於GNOME項目的LIBXML2庫。這將允許在不同的擴展模塊之間互相操作,核心開發者只需要在一個底層的庫上進行開發。例如,複雜的內存管理只實現一次就可以讓所有XML相關擴展得到改善。

除了繼承PHP4中聞名的SAX解析器之外,PHP5還支持遵循W3C標準的DOM和基於LIBXSLT引擎的XSLT。同時還加入了PHP獨有的SimpleXML擴展和符合標準的SOAP擴展。隨着XML越來越被重視,PHP開發者決定在默認安裝方式中加入更多對XML的支持。這就意味着你現在可以使用SAX,DOM和SimpleXML,而這些擴展將會在更多的服務器上安裝。然後對於XSLT和SOAP的支持,還需要在PHP編譯時被顯式的配置。

數據流的支持

現在所有的XML擴展都支持PHP數據流,即使你不從PHP中直接訪問。例如,在PHP5中你可以從一個文件或從一條指令訪問數據流。基本上你能夠在任何可以訪問普通文件的地方訪問PHP數據流。

PHP4.3中簡要的介紹了數據流,在PHP5中已經得到了進一步的提高,包含文件存取,網絡存取和其它操作,如共享一套功能函數。你甚至可以使用PHP代碼來實現你自己的數據流,這樣數據存取將變得非常簡單。關於這部分的更多細節請參考PHP文檔。

SAX

SAX的全稱是Simple API for XML,它是用於解析XML文檔的接口,是基於回調形式的。從PHP3開始就已經支持了SAX,到現在也沒有太大的變化。在PHP5中,API接口並沒有改變,所以你的代碼仍然可以運行。唯一不同的是它不再基於EXPAT庫,而是基於LIBXML2庫。

這個變化帶來了一些對命名空間支持上的問題,這個問題在LIBXML2.2.6版本中已經得到解決。但是LIBXML2以前的版本中並沒有解決,因此如果你使用了xml_parse_create_ns();強烈建議在你的系統上安裝LIBXML2.2.6。

DOM

DOM (文檔對象模型)是由W3C制定的一套訪問XML文檔樹的標準。在PHP4可以使用DOMXML來對此進行操作,DOMXML的最主要問題是它不符合標準的命名方法。而且在很長一段時間內還存在內存泄漏問題(PHP4.3已經修復了這個問題)。

新的DOM擴展是基於W3C標準完成的,包含方法和屬性名稱。如果你在其它語言中熟悉DOM,例如在JavaScript中,那麼在PHP中編寫類似的功能將變得非常容易。你不必每次都查看文檔,因爲方法和參數都是相同的。

由於使用了新的W3C標準,基於DOMXML的代碼將不能運行。在PHP中的API有很大的不同。但是如果你的代碼中使用了類似W3C標準的方法命名方式,移植並不是很困難。你只需要將載入函數和保存函數修改,刪除函數名中的下劃線(DOM標準使用首字母大寫)。其它各處的調節當然也是必須的,但是主要邏輯部分可以保持不變。

讀取DOM

我不會在這篇文章中解釋DOM擴展的所有特性,那也是沒有必要的。或許你應該將HTTP://www.w3.org/DOM的文檔加入書籤。它與PHP5的DOM部分基本上相同。

在這篇文章的大多數例子中我們將使用同一個XML文件,zend.com上有非常簡單的RSS版本。將下面的文本粘貼到一個文本文件中並保存爲articles.xml。





http://www.zend.com/zend/week/week172.php



http://www.zend.com/zend/tut/tut-hatwar3.php



要將這個例子載入到一個DOM對象,首先要創建一個DOMDocument對象,然後載入XML文件。

$dom = new DomDocument();
$dom->load("articles.xml");

正像上面所提及的,你可以使用PHP的數據流來載入一個XML文檔,你應該這樣寫:

$dom->load("file:///articles.xml");

(或者其它類型的數據流)

如果你想將XML文檔輸出到瀏覽器或做爲標準標出,使用:

print $dom->saveXML();

如果你想把它保存成文件,請使用:

print $dom->save("newfile.xml");

(注意這樣做會將文件大小發送到stdout)

當然這個例子沒有太多的功能,讓我們來做些更有用的。我們來取得所有的title元素。有很多方法可以辦到,最簡單的就是使用getElementsByTagName($tagname):

$titles = $dom->getElementsByTagName("title");
foreach($titles as $node) {
print $node->textContent . "/n";
}

textContent屬性並不是W3C標準,它可以讓我們很方便的快速讀取一個元素的所有文本節點,使用W3C的標準讀取是下面這樣:

$node->firstChild->data;

(這時候你要確保firstChild結點是你需要的文本結點,否則你還得遍歷所有子結點來查找)。

另外一個要注意的問題是getElementsByTagName()返回一個DomNodeList,對象,而不是像PHP4中get_elements_by_tagname()那樣返回一個數組,但是正像你在這個例子中看到的那樣,你可以使用foreach語句輕鬆的遍歷它。你也可以直接使用$titles->item(0)來訪問結點。該方法將返回第一個title元素。

另一個取得所有title元素的辦法是從根結點遍歷,你可以看到,這個方法更復雜,但是如果你需要的不只是title元素的時候,這個方法也就更靈活。

foreach ($dom->documentElement->childNodes as $articles) {
//如果節點是一個元素(nodeType == 1)並且名字是item就繼續循環
if ($articles->nodeType == 1 && $articles->nodeName == "item") {
foreach ($articles->childNodes as $item) {
//如果節點是一個元素,並且名字是title就打印它.
if ($item->nodeType == 1 && $item->nodeName == "title") {
print $item->textContent . "/n";
}
}
}
}

XPath
XPaht 就像是XML的SQL,使用XPath你可以在一個XML文檔中查詢符合一些模式語法的特定結點。想使用XPath獲得所有title結點,只需要這麼做:


$xp = new domxpath($dom);
$titles = $xp->query("/articles/item/title");
foreach ($titles as $node) {
print $node->textContent . "/n";
}
?>

這樣和使用getElementsByTagName()方法差不多,但是Xpath要強大的多,例如,如果我們有一個title元素是article的子元素(而不是item的子元素),getElementsByTagName()就會將它返回。而使用/articles/item/title語法,我們只會得到在指定深度和位置的title元素。這只是一個簡單的例子,再深入一點可能是這樣:

/articles/item[position() = 1]/title 返回第一個item元素的所有

/articles/item/title[@id = '23'] 返回所有含有id屬性並且值爲23的title

/articles//title 返回所有articles元素下面的title(譯者注://代表任意深度)

你也可以查詢含有特殊兄弟元素的點,含有特殊文本內容的元素,或者使用命名空間等等。如果你必須大量的查詢XML文檔,適當的學習使用XPath會節省你很多時間,它使用簡單,執行速度快,比標準的DOM需要更少的代碼。

向DOM中寫入數據
文檔對象模型並不是只能讀取和查詢,你也可以操作和寫入。(DOM標準有點冗長,因爲編寫者想盡量支持能夠想像到的每一個環境,但是它工作的非常好)。看看下面這個例子,它在我們的article.xml文件中添加了一個新元素。

$item = $dom->createElement("item");
$title = $dom->createElement("title");
$titletext = $dom->createTextNode("XML in PHP5");
$title->appendChild($titletext);
$item->appendChild($title);
$dom->documentElement->appendChild($item);
print $dom->saveXML();

首先,我們創建了所有需要的結點,一個item元素,一個title元素和一個包含item標題的文本結點,然後我們
 

發佈了145 篇原創文章 · 獲贊 16 · 訪問量 35萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章