[轉] - 在PHP中開發XML應用程序之基礎篇


繁體及整理 : 傻心 - 窮等人家

一、XML簡介

XML(可擴展的標注語言)是一種W3C標準,主要用於Web應用程序和服務器之間實現容易的交互、數據的存儲與使用。
使用XML標準編碼的數據具有能容易被人和計算機解釋的意義和結構。XML數據是平台和應用程序獨立的。不用多說,這本身就使XML成為適合於互聯網的一個理想的數據交換格式(事實上,它正是因這一用途而被開發的)。最近,寬帶連接的增長及消費者對於越過任何媒體進行數據共享的應用軟件的需求意味著,XML Web服務和應用軟件正變得越來越豐富。
XML的發明正是為了解決描述網上豐富的數據的組織問題;而目前為止,這一問題僅能夠通過HTML的巧妙使用得到部分地解決。

下面是 XML 文檔的實例 :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0"?>
<party>
<location>My House</location>
<time>7pm</time>
<guest>
<name>John Bloggs</name>
<item>Crate of Fosters</item>
</guest>
<guest>
<name>Sara Bloggs</name>
<item>Umbrella</item>
</guest>
<guest>
<name>David Fig</name>
<item>Bombay Mix</item>
</guest>
</party>

如果你以前沒見過XML,那麼你可以認為它看起來像HTML。HTML是一種SGML應用程序,而XML是它的一個子集。然而,其相似性還包括它們具有相似的標注分隔符。

僅需看一下上面的XML片斷,我們就能看到,該數據是描述一個具有一些客人的聚會;其中,每一個客人相應於一項。用於描述數據的標籤名完全由作者來選擇。所有XML標準要求:數據必須是一致的並且用於描述數據的標籤為良構的。我們可以進一步用一種文檔類型聲明(DTD)或一個XML模式來強制數據的完整性。然而為簡化起見,我們在本文中將僅使用普通的XML。

二、XML應用程序

剛才,我們已經看到了如何使用XML來描述任何種類的數據。事實上,XML已經在今天的許多Web應用程序中得到廣泛使用,下面是一些著名的應用描述:

· XHTML-這是使用最廣泛的XML應用程序之一。它類似基於HTML的SGML-用於描述數據在網頁上的顯示方式。XHTML使用一DTD來確保所有的文檔遵循標準。XHTML的出現使Web程序員的開發稍微容易了一些;然而,一種完全兼容於CSS和XHTML標準的web瀏覽器尚未出現。
· XML-RPC-遠程過程調用(RPC),應用於分佈式應用程序中以調用遠程計算機上的過程。XML-RPC使用XML對關於過程調用的信息進行編碼,並且使用HTTP把它發送到接收計算機。然後,過程的返回值被再次用XML編碼並用HTTP連接發送回調用者計算機。
· RSS-真正簡單的聚合/豐富的站點摘要,它是一種用來聚合web站點內容(例如新聞、文章、共享價格和鏈接等)的方法,它用一個特殊的應用程序(一個聚合器)定期更新用戶PC上的RSS回饋。該RSS數據是使用XML進行編碼和傳輸的。
· AJAX-異步的JavaScript和XML,允許web開發者創建具有豐富特徵的事件驅動的運行在web瀏覽器上的web應用程序。其中,JavaScript用於把XML編碼的數據發送到服務器端腳本(或從服務器端接收XML編碼的數據),並允許局部的實時的頁面更新而不需要更新所有頁面內容。

上面僅僅是XML的可能的應用的一部分。在以後文章中,我們將分析如何在PHP中使用這些應用軟件。

三、在PHP中使用XML

自從PHP 5.0以來,PHP能與XML交互的可用選項顯著地增加。而PHP版本4所能提供的是不穩定的而且是非w3c兼容的DOM XML擴展。
下面,我將集中討論PHP 5所提供給我們的三個允許我們與XML交互的方法:DOM,簡單XML和XPath。在可能之處,我將建議最適合於每種方法的條件和數據。所有的示例代碼將使用XML數據源來描述一個庫及其中包含的書。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<xml version="1.0"?>
<library>
 <categories>
  <category cid="1">Web Development</category>
  <category cid="2">Database Programming</category>
  <category cid="3">PHP</category>
  <category cid="4">Java</category>
 </categories>
 <books>
 <book>
  <title>Apache 2</title>
  <author>Peter Wainwright</author>
  <publisher>Wrox</publisher>
  <category>1</category>
 </book>
 <book>
  <title>Advanced PHP Programming</title>
  <author>George Schlossnagle</author>
  <publisher>Developer Library</publisher>
  <category>1</category>
  <category>3</category>
 </book>
 <book>
  <title>Visual FoxPro 6 - Programmers Guide</title>
  <author>Eric Stroo</author>
  <publisher>Microsoft Press</publisher>
  <category>2</category>
 </book>
 <book>
  <title>Mastering Java 2</title>
  <author>John Zukowski</author>
  <publisher>Sybex</publisher>
  <category>4</category>
 </book>
</books>
</library>

四、DOM

DOM PHP擴展名允許使用W3C DOM API在XML文檔上進行操作。在PHP 5出現之前,這是PHP能存取XML文檔的唯一方法。如果你在JavaScript中使用了DOM,那麼會認識到這些對像模型幾乎是一樣的。
由於DOM方法在遍歷和操作XML文檔時比較囉嗦,所以任何DOM兼容的代碼都有明顯的優點-與任何其它實現相同的W3C兼容的對象模型的API兼容。

在下面的實例代碼中,我們使用DOM來顯示關於每本書的信息。首先,我們遍歷一下列表目錄,把它們的Id和相應的名字裝載到一個索引數組中。然後,我們顯示每本書的一個簡短描述:

PHP:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<?php
// 這裡我們必須指定 XML 版本 : 也即是 1.0
$xml = new DomDocument('1.0');
$xml->load('xml/library.xml');

// 首先,創建一個目錄列表
$categories = array();
$XMLCategories = $xml->getElementsByTagName('categories')->item(0);
foreach($XMLCategories->getElementsByTagName('category') as $categoryNode) {

// 注意我們是如何得到屬性的
$cid = $categoryNode->getAttribute('cid');
$categories[$cid] = $categoryNode->firstChild->nodeValue;

}
?>
<html>
<head>
<title>XML Library</title>
</head>
<body>
<?php
foreach($xml->getElementsBytagName('book') as $book) {

$title = $book->getElementsByTagName('title')->item(0)->firstChild->nodeValue; // 查找標題
$author = $book->getElementsByTagName('author')->item(0)->firstChild->nodeValue; // 查找作者 - 為了簡化起見,我們假設只有一個作者
$bookCategories = $book->getElementsByTagName('category'); // 列出目錄
$catList = '';

foreach($bookCategories as $category) {
   $catList .= $categories[$category->firstChild->nodeValue] . ',';
  }

$catList = substr($catList,0,-2);
?>
<div>
<h2><?php echo($title) ?></h2>
<p><b>Author:</b>: <?php echo($author) ?></p>
<p><b>Categories: </b>: <?php echo($catList) ?></p>
</div>
<?php } ?>
</html>

再提一下,修改 XML 是較為麻煩的。例如,添加一個目錄的代碼如下 :

PHP:

1
2
3
4
5
6
7
8
9
10
<?php
function addCategory(DOMDocument $xml,$catID,$catName) {
$catName = $xml->createTextNode($catName); // 創建一個結點以儲存文本
$category = $xml->createElement('category'); // 創建一個目錄元素
$category->appendChild($catName); // 把文字添加到目錄元素上
$category->setAttribute('cid',$catID); // 設置目錄 ID
$XMLCategories = $xml->getElementsByTagName('categories')->item(0);
$XMLCategories->appendChild($category); // 添加新目錄
}
?>

五、保存XML

你可以使用save()和saveXML()方法之一來把DOM描述轉換回XML字符串描述。save()方法用一指定的命名把XML保存到一個文件中,而saveXML()從文檔的部分或整體中返回一個字符串。

1
2
3
4
<?php
$xml->save('xml/library.xml'); //保存全部文件
$categories=$xml->saveXML($XMLCategories); //設回一個包含種類的字符串
?>

為了說明把DOM兼容的代碼移植到另外的語言是如何容易,下面是用JavaScript形式實現的與以上功能相同的代碼:

JavaScript :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
function doXML(){
// 首先創建一個種類列表
var categories = Array();
var XMLCategories = xml.getElementsByTagName('categories')[0];
var theCategories = XMLCategories.getElementsByTagName('category');

for (var i = 0; i < theCategories.length; i++) {
// 注意我們是如何得到屬性的
var cid = theCategories[i].getAttribute('cid');
categories[cid] = theCategories[i].firstChild.nodeValue;
}

var theBooks = xml.getElementsByTagName('book');

for(var i = 0; i < theBooks.length; i++) {
var book = theBooks[i];

// 查找標題
var title = book.getElementsByTagName('title')[0].firstChild.nodeValue;

// 查找作者 - 為簡單起見,我們假定只有一個作者
var author = book.getElementsByTagName('author')[0].firstChild.nodeValue;

// 列出種類
var bookCategories = book.getElementsByTagName('category');

var catList = '';

for(var j = 0; j < bookCategories.length; j++) {
catList += categories[bookCategories[j].firstChild.nodeValue] + ',';
}

catList = catList.substring(0,catList.length -2);

document.open();
document.write("<h2>" + title + "</h2>");
document.write("<p><b>Author:</b>: " + author + "</p>");
document.write("<p><b>Categories: </b>: " + catList + "</p>");
}

document.close();
}

六、簡單XML

簡單XML確實簡單。它允許使用對像和數組存取方法來存取一個XML文檔及其元素和屬性。操作方式很簡單:

· 元素(Element)-這些被描述為SimpleXMLElement對象的單個屬性。當有多個作為文檔或元素的子元素存在時,每個元素能被使用數組索引標誌加以存取。

1
2
3
4
<?php
$xml->books; //返回元素"books"
$xml->books->book[0]; //返回在books元素中的第一本書
?>

· 屬性(Attribute)-元素的屬性是通過關聯數組標誌來存取和設置的,此時每一個索引對應於一個屬性名。

1
2
3
<?php
$category['cid']; //返回cid屬性的值
?>

· 元素數據(Element Data)-為了檢索包含在一個元素內的文本數據,必須使用(string)顯式地把它被轉換為一個字符串或使用print或echo輸出它。如果一個元素包含多個文本結點,那麼它們將按被找到的順序連接起來。

1
2
3
<?php
echo ($xml->books->book[0]->title); //顯示第一本書的標題
?>

下面是使用簡單XML進行轉換的原來的實例。為了裝載XML文件,我們使用simplexml_load_file()函數,由它來分析該XML文件並且把它裝載進一個SimpleXMLElement對像中:

PHP:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<?php
$xml = simplexml_load_file('xml/library.xml');

// 把一個列表的目錄裝載到一個數組中
$categories = array();
foreach($xml->categories->category as $category) {
$categories[(string) $category['cid']] = (string) $category;
}
?>
<html>
<head>
<title>XML Library</title>
</head>
<body>
<?php
foreach($xml->books->book as $book) {

// 列舉目錄
$catList = '';
foreach($book->category as $category) {
$catList .= $categories[((string) $category)] . ',';
}
$catList = substr($catList,0,-2);
?>
<div>
<h2><?php echo($book->title) ?></h2>
<p><b>Author:</b>: <?php echo($book->author) ?></p>
<p><b>Categories: </b>: <? php echo($catList) ?></p>
</div>
<? php } ?>
</html>

七、修改XML

儘管文本數據和屬性值可以通過使用簡單XML加以設置,但是不能新建這些對象。然而, SimpleXM的確提供了一種方法來實現DomElement對像和DomElement對像之間的轉換。為此,我修改了addCategory()函數來說明如何使用simplexml_import_dom()函數以添加目錄和把該文檔轉換回簡單的XML格式:

PHP:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
function addCategory(SimpleXMLElement &$sXML,$catID,$catName) {
$xml = new DOMDocument;
$xml->loadXML($sXML->asXML());
$catName = $xml->createTextNode($catName); //創建一個結點來存放該文本
$category = $xml->createElement('category'); //創建一個目錄元素
$category->appendChild($catName); //把文本添加到目錄元素
$category->setAttribute('cid',$catID); //設置目錄id
$XMLCategories = $xml->getElementsByTagName('categories')->item(0);
$XMLCategories->appendChild($category); //添加新目錄
$sXML = simplexml_import_dom($xml);
return $sXML;
}
?>

同樣,SimpleXMLElement對象的asXML()函數可以用來檢索XML字符串並把它保存回一個文件中。

八、xPath

毫無疑問,Xpath是”XML蛋糕之上的櫻桃”。XPath允許你使用象SQL一樣的查詢來查找一個XML文檔中的特定信息。DOM和SimpleXML都有內置的對XPath的支持,如SQL,可以被用來提取你想從一XML文檔中提取的任何內容。

· /category-查找所有的在文檔中出現的任何category。
· /library/books-查找所有作為library的孩子出現的books
· /library/categories/category[@cid]-查找所有作為library/categories的孩子出現且屬性為cid的category。
· /library/categories/category[@att=’2’]-查找所有作為library/categories的孩子且具有屬性cid的值為2出現的category。
· /library/books/book[title=’Apache 2’]-查找所有作為/library/books的孩子且其標題元素有一個值為Apache 2出現的book。

其實,這僅是xPath冰山之一角。你可以使用xPath來創建大量複雜的查詢以便從你的文檔中提取幾乎任何信息。我再次修改了示例代碼來向你展示使用xPath是多麼輕鬆愉快的事情。

PHP:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php
$xml = simplexml_load_file('xml/library.xml');
?>
<html>
<head>
<title>XML Library</title>
</head>
<body>
<?php
foreach(((array)$xml->xpath("/library/books/book")) as $book) {
// 列表目錄
$catList = '';
foreach($book->category as $category) {
// 得到具有這個ID的目錄
$category = $xml->xpath("/library/categories/category[@cid='$category']");
$catList .= (string) $category[0] . ',';
}
$catList = substr($catList,0,-2);
?>
<div>
<h2><?php echo($book->title) ?></h2>
<p><b>Author:</b>: <?php echo($book->author) ?></p>
<p><b>Categories: </b>: <?php echo($catList) ?></p>
</div>
<?php } ?>
</html>

九、DOM和XPath

在DOM中計算XPath查詢需要創建一個DOMXPath對象,下面的evaluate()函數返回一個DOMElement數組。

1
2
3
4
<?php
$xPath = new DOMXPath($xml);
$xPath->evaluate("/library/books/book[title='Apache 2']");
?>

十、結論

現在,我們學習了如何使用了PHP提供給我們的工具來與XML交互。至此,我們已經被”武裝起來”並準備好深入鑽研XML應用程序了。在下一篇文章中,我們將討論AJAX及其如何應用於象Google這樣的站點開發的。