php5 and xml示例

NO IMAGE

http://trash.chregu.tv/phpconf2003/examples/
PHP5的XML新特性
作者 Christian Stocker 翻譯 ice_berg16(尋夢的稻草人)
面向的讀者
這篇文章的物件導向是所有對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的文件加入書籤…糠只舊舷嗤?/a>
在這篇文章的大多數例子中我們將使用同一個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標題的文字結點,然後我們將所有的結點連結起來,把文字結點加到title元素上,把title元素加到item元素上,最後我們把item元素插入到articles根元素上。現在,我們的XML文件中有一個新的文章列表了。
擴充套件類(class)
好了,上面的例子都可以在PHP4下面用DOMXML擴充套件來做(只是API有一些不同),能夠自己擴充套件DOM類是PHP5的一個新特性,這使得書寫更多可讀性強的程式碼變得可能。下面是用DOMDocument類重新寫的整個例子:
class Articles extends DomDocument { 
function __construct() { 
//必須呼叫! 
parent::__construct(); 

function addArticle($title) { 
$item = $this->createElement(“item”); 
$titlespace = $this->createElement(“title”); 
$titletext = $this->createTextNode($title); 
$titlespace->appendChild($titletext); 
$item->appendChild($titlespace); 
$this->documentElement->appendChild($item); 


$dom = new Articles(); 
$dom->load(“articles.xml”); 
$dom->addArticle(“XML in PHP5”); 
print $dom->save(“newfile.xml”); 
HTML
PHP5中一個經常不被注意到的特性是libxml2庫對HTML的支援,你不僅可以使用DOM擴充套件載入結構良好(well-formed)的XML文件,還可以載入非結構良好的(not-well-formed)HTML文件,把它當做標準的DOMDocument物件,使用所有能用的方法和特性,比如XPath和SimpleXML。
當你需要訪問一個你無法控制站點的內容時,HTML的效能就顯示十分有用了。在 XPath, XSLT 或 SimpleXML的幫助下,你省掉了許多程式碼,像使用正規表示式比較字串或者SAX解析器。當HTML文件結構不是很好的時候,這個辦法尤其有用(這是個頻繁的問題!)。
下面的程式碼獲得並解析php.net的首頁,將返第一個title元素的內容。
$dom = new DomDocument(); 
$dom->loadHTMLFile(“http://www.php.net/”); 
$title = $dom->getElementsByTagName(“title”); 
print $title->item(0)->textContent; 
請注意當指定元素沒有找到時,你的輸出可能會包含錯誤。如果你的網站還在使用PHP輸出HTML4程式碼,有一個好訊息要告訴你,DOM擴充套件不僅能載入HTML文件,而且還能將他們儲存為HTML4格式的檔案。在你新增完DOM文件後,使用$dom->saveHTML()來儲存。要注意的是,為了使輸出的HTML程式碼符合W3C標準,最好不用使用 整齊的擴充套件?(tidy extension)。Libxml2 庫支援的HTML並不會考慮到每個可能發生的事情,也不能很好的處理非通用格式的輸入。
驗證
XML文件的驗證越來越重要了。例如,如果你從一些國外資源中獲得了一個XML文件,在你處理之前你需要檢驗它是否符合某個確定的格式。幸運的是你不需要在PHP中寫自己的驗證程式,因為你可以使用三個應用最廣泛的標準之一(DTD,XML Schema 或RelaxNG)來完成它。. 
DTD是一個產生於SGML時代的標準,缺少一些XML的新特性(如名稱空間),而且由於它不是用XML寫的,它也很難被解析和轉換。 
XML Schemai是由W3C制定的一個標準,它應用廣泛,幾乎包含了所有驗證XML文件所需要的內容。 
RelaxNG 是複雜的XML Schema標準的對頭,是由自由者組織建立的,由於它比XML Schema更容易實現,越來越多的程式開始支援RelaxNG了
如果你沒有遺留下來的計劃文件或者非常複雜的XML文件,那麼使用RelaxNG吧。它書寫和閱讀都比較簡單,越來越多的工具也支援它。甚至還有一個工具叫Trang,它可以從XML範本中自動建立一個RelaxNG文件。而且只有RelaxNG(和老化的DTDS)被libxml2完全支援,儘管libxml2也即將完全支援ML Schema。
驗證XML文件的語法相當簡單:
$dom->validate(‘articles.dtd’); 
$dom->relaxNGValidate(‘articles.rng’); 
$dom->schemaValidate(‘articles.xsd’); 
目前,所有這些都只會簡單的返回true或false,錯誤會被做為PHP警告輸出。顯然想返回給使用者友好的資訊這並不是一個好主意,在PHP5.0以後的版本里會有所改善。到底該怎麼實現目前還在討論之中,但是錯誤報告肯定會處理的更好。
SimpleXML
SimpleXML 是PHP的XML家族中最後一個被加入的成員,加入SimpleXML擴充套件的目的是為了提供一個使用標準物件屬性和迭代器訪問XML文件的更簡單的方法。該擴充套件沒有太多的方法,雖然如此它還是相當強大的。從我們的文件的取得所有title節點比原來需要更少的程式碼。
$sxe = simplexml_load_file(“articles.xml”); 
foreach($sxe->item as $item) { 
print $item->title .”\n”; 

這是在幹什麼?首先將articles.xml載入到一個SimpleXML物件。然後取得所有$sxe中的item元素,最後$item->title返回title元素的內容,就是這樣。你也可以使用關聯陣列查詢屬性,使用: $item->title[‘id’]。
看到了吧,這後面真是太神奇了,有許多不同的辦法可以得到我們想要的結果,例如, $item->title[0]返回和例子中相同的結果,另一方面,foreach($sxe->item->title as $item)只返回第一個title,並不是所有在文件中的title元素。(就像我在XPath中預期的那樣)。
SimpleXML 實際上是使用了Zend引擎2新特性的第一個擴充套件。因此也成了這些新特性的測試點,你要知道在開發階段bugs和不可預料的錯誤可不是少數。
除了上面例子中所使用的遍歷所有節點的方法,在SimpleXML中也有一個XPath介面,它為訪問單個結點提供了更簡單的辦法。
foreach($sxe->xpath(‘/articles/item/title’) as $item) { 
print $item . “\n”; 

不可否認,這段程式碼也不比前面例子中的短,但是提供了更復雜或更深的巢狀XML文件,你會發現和SimpleXML一起使用XPath會節省你很多的輸入。
向 SimpleXML 文件寫入資料
你不僅可以解析和讀取SimpleXML,而且還可以改變SimpleXML文件。至少我們加入一些擴充套件:
$sxe->item->title = “XML in PHP5 “; //title元素的新內容。 
$sxe->item->title[‘id’] = 34; // title元素的新屬性。
$xmlString = $sxe->asXML(); // 將SimpleXML物件做為序列化的XML字串返回
print $xmlString; 
互用協作性
由於SimpleXML也是基於libxml2庫的,你可以在幾乎不影響速度的情況下輕鬆的將SimpleXML物件轉化成DomDocument物件。(文件不用進行內部複製),由於這個機制,你擁有了二個物件的最好部分,使用一個適合你手頭工作的工具吧,它是這樣使用的:
$sxe = simplexml_import_dom($dom); 
$dom = dom_import_simplexml($sxe); 
XSLT
XSLT是用來將XML文件轉換為其它XML文件的語言,XSLT本身是用XML編寫的,屬於功能性語言家族,在程式處理上和麵對物件語言(像PHP)有所不同。PHP4中有二種XSLT處理器:Sablotron(在廣泛使用的XSLT擴充套件中)和Libxslt(在domxml擴充套件中),這兩種API不互相相容,並且使用方法也不相同。PHP5只支援libxslt處理器,之所以選擇它是因為它是基於Libxml2的,因此也更符合PHP5的XML概念。
理論上將Sablotron繫結到PHP5上也是可能的,但是不幸的是沒人來做。因此,如果你正在使用Sablotron,你不得不在PHP5中切換到libxslt處理器。Libxslt 是帶有Javascript異常處理支援的Sablotron,甚至可以使用PHP強大的資料流來重新實現Sablotron獨有的計劃處理(scheme handlers)。此外,libxslt 是 最快的XSLT處理器之一,所以你還免費得到了速度的提升。(執行速度是Sablotron的二倍)。
和本文討論的其它擴充套件一樣,你可以在XSL擴充套件,DOM擴充套件和vice versa之間交換XML文件,實際上,你必須得這麼做,因為EXT/XSL擴充套件並沒有載入和儲存XML文件的介面,只能使用DOM擴充套件。一開始學習XSLT轉換,你不需要掌握太多的內容,這裡也不存在W3C標準,因為這個API中從Mozilla“借”過來的。
首先你需要一個XSLT樣式表,將下列文字貼上到一個新檔案並且儲存灰articls.xsl
然後用PHP指令碼呼叫它:: 
/* 將XML和XSL文件載入到DOMDocument物件*/ 
$xsl = new DomDocument(); 
$xsl->load(“articles.xsl”); 
$inputdom = new DomDocument(); 
$inputdom->load(“articles.xml”);
/* 建立XSLT處理器,並匯入樣式表*/ 
$proc = new XsltProcessor(); 
$xsl = $proc->importStylesheet($xsl); 
$proc->setParameter(null, “titles”, “Titles”); 
/* 轉換並輸出XML文件 */ 
$newdom = $proc->transformToDoc($inputdom); 
print $newdom->saveXML(); 
?> 
上面的例子首先使用DOM的方法load()載入XSLT樣式表articles.xsl,然後建立了一個新的XsltProcessor物件,該物件導到了後面要使用了XSLT樣式表物件,引數可以這樣設定setParameter(namespaceURI, name, value),最後XsltProcessor物件使用transformToDoc($inputdom)開始轉換並返回一個新的DOMDocument物件。
. 這個API的優點在於你可以使用同一個樣式錶轉換許多XML文件,只需要將它載入一次然後重複使用它,因為transormToDoc()函式可以應用於不同的XML文件。
除了transormToDoc(),還有二個用於轉換的方法:transformToXML($dom)返回一個字串,transformToURI($dom, $uri)將轉換之後的文件儲存到檔案或一個PHP資料流。注意如果你想使用XSLT的一個語法如 或 indent=”yes”,你不能使用transformToDoc(),因為DOMDocument物件 不能儲存該資訊,只能當你將轉換後的結果直接儲存到字串或檔案中時才能這樣做。
呼叫PHP函式
XSLT擴充套件最後一個新加的特性是能夠在XSLT 樣式表內部呼叫任何PHP函式,主張正統的XML支持者一定不會喜歡這個功能(這樣的樣式表有點複雜,很容易混淆邏輯和設計),在某些地方卻是十分有用的。當涉及到函式時XSLT就變得很有限,即使想實現用不同的語言輸出一個日期也是非常麻煩的。但是使用這個功能,處理這些就和只使用PHP一樣容易。下面是向XSLT新增一個函式的程式碼:
function dateLang () { 
return strftime(“%A”); 

$xsl = new DomDocument(); 
$xsl->load(“datetime.xsl”); 
$inputdom = new DomDocument(); 
$inputdom->load(“today.xml”); 
$proc = new XsltProcessor(); 
$proc->registerPhpFunctions(); 
// 載入文件並使用$xsl來處理 
$xsl = $proc->importStylesheet($xsl); 
/* 轉換並輸出XML文件 */ 
$newdom = $proc->transformToDoc($inputdom); 
print $newdom->saveXML(); 
?> 
下面是XSLT樣式表datetime.xsl,它會呼叫這個函式。
下面是要使用樣式錶轉換的XML文件,today.xml(同理,articles.xml也會得到同樣結果)。
上面的樣式表,PHP指令碼和所有的XML檔案會用當前系統設定的語言輸出星期的名字。你可以給php:function()新增更多的引數,新增的引數會被傳遞給PHP函式。這裡有一個函式php:functionString(),這個函式自動將所有輸入的引數轉換為字串,所以你不需要在PHP裡進行轉換。
注意你需要在轉換之前呼叫$xslt->registerPhpFunctions(),否則PHP函式呼叫將因為安全原因不會被執行(你始終相信你的XSLT樣式表嗎?)。目前訪問系統還沒有實現,也許在將來PHP5的版本中會實現這個功能。
摘要
PHP對XML的支援已經向前邁進了一大步,它符合標準,功能強大,互用協作性強,被作為預設選項安裝,已被授權使用。新加入的SimpleXML擴充套件提供了簡單快速訪問XML文件的方法,可以節省你很多的程式碼,尤其是當你有結構化文件或者可以使用強大的XPath時。
感謝libxml2—PHP5 XML擴充套件所使用的底層庫,使用DTD,RelaxNG或XML Schema驗證XML文件現在已經被支援了。
XSL支援也得到了翻新,現在使用Libxslt庫,比原來的Sablotron庫在效能上有很大提高,而且,在XSLT樣式表內部呼叫PHP函式可以讓你寫出更強大的XSLT程式碼。
如果你已經在PHP4或其它語言中使用了XML,你會喜歡PHP5的XML特性的,XML在PHP5中有了很大的變化,符合標準,和其它工具,語言是同等的。
連結
PHP 4 相關
Domxml 擴充套件: http://www.php.net/domxml/ 
Sablotron 擴充套件: http://www.php.net/xslt/ 
Libxslt: http://www.php.net/manual/en/functi…-stylesheet.php 
PHP 5 相關
SimpleXML: http://www.php.net/simplexml/ 
Streams: http://www.php.net/manual/en/ref.stream.php 
標準
DOM: http://www.w3.org/DOM 
XSLT: http://www.w3.org/TR/xslt 
XPath: http://www.w3.org/TR/xpath 
XML Schema: http://www.w3.org/XML/Schema 
RelaxNG: http://relaxng.org/ 
Xinclude: http://www.w3.org/TR/xinclude/ 
工具
Libxml2, the underlying library: http://xmlsoft.org/ 
Trang, a Schema/RelaxNG/etc converter: http://www.thaiopensource.com/relaxng/trang.html 
關於作者
Christian Stocker是蘇黎士Bitflux GmbH公司的創始人和CEO,他是XSL,DOM和imagick擴充套件的維護人員,德語書籍PHP de Luxe的合作作者,同時致力於其它開源專案,如Bitflux Editor和Popoon.。可以通用[email protected]和他聯絡。

您可能感興趣的文章:

PHP5中使用DOM控制XML實現程式碼用 PHP5 輕鬆解析 XMLPHP5的XML新特性PHP XML操作的各種方法解析(比較詳細)php的SimpleXML方法讀寫XML介面檔案例項解析php解析xml方法例項詳解PHP用SAX解析XML的實現程式碼與問題分析PHP 以POST方式提交XML、獲取XML,解析XML詳解及例項使用PHP DOM-XML建立和解析XML檔案解析php DOMElement 操作xml 文件的實現程式碼php解析xml 的四種簡單方法(附例項)PHP XML資料解析程式碼PHP4和PHP5版本下解析XML文件的操作方法例項分析