Menu

快速學會使用 PHP 開發 XML 系統

本系列文章分為三部分,這是第一部分;介紹了 PHP5 的 XML 實現,幫助那些不熟悉使用 PHP 處理 XML 的新手使用 PHP 環境中的 DOM 和 SimpleXML 讀取、解析、操作並編寫簡單短小的 XML 文件。

簡介

如今的應用程序開發環境很難忽視 XML 的重要性。如果原來從未在 PHP 中處理過 XML,或者沒有接觸 PHP5,這份關於 PHP5 新增 XML 功能的入門指南可以告訴您處理 XML 是多麼簡單。本系列文章分為三部分,這是第一部分,主要介紹了能夠快速入門的 API,通過例子說明對於簡單的、可預測的和相對較小的 XML 文檔,使用 SimpleXML,在必要的時候結合 DOM,是一種理想的辦法。這些恰恰是 Ajax 應用程序中所傳遞的那些文檔,比如提交表單的內容或者 Web 服務應用程序編程接口(API)如 weather.com 的響應。




XML 基礎

請訪問 面向 Perl 和 PHP 開發人員的 XML:您可以通過該專題來瞭解更多與 Perl 和 PHP 相關的 XML 技術。

對 XML 有初步的瞭解可以幫助您理解 XML 對於 PHP 開發人員的重要性,理解和創建簡單的 XML 文檔。

關於 XML

可擴展標記語言(XML)被稱為標記語言和基於文本的數據存儲格式,這要看對誰來說。它是標準通用標記語言(SGML)的一個子集,採用文本方式應 用和描述信息的樹狀結構。XML 是很多語言/格式的基礎,如 Really Simple Syndication (RSS)、Mozilla 的 XML User Interface Language (XUL)、Macromedia 的 Maximum eXperience Markup Language (MXML)、Microsoft 的 eXtensible Application Markup Language (XAML) 以及開放源代碼的 Java XML UI Markup Language (XAMJ)。既然 XML 到處都存在,說明它確實很重要。每個人都想跟上 XML 的潮流。




編寫 XML

XML 的基本數據單位是元素。元素使用起始標記,如 和結束標記,如 分隔開。有起始標記必須有結束標記。如果缺少結束標記,XML 文檔就不是結構良好的,解析器就不能正確地解析文檔。標記的名稱通常反映元素所包含內容的類型。可以設想,book 元素應該包含圖書的標題,比如 Great American Novel(如清單 1 所示)。標記之間的內容,包括空白,稱為字符數據。


清單 1. XML 示例文檔
<books>
<book>
<title>Great American Novel</title>
<characters>
<character>
<name>Cliff</name>
<desc>really great guy</desc>
</character>
<character>
<name>Lovely Woman</name>
<desc>matchless beauty</desc>
</character>
<character>
<name>Loyal Dog</name>
<desc>sleepy</desc>
</character>
</characters>
<plot>
Cliff meets Lovely Woman. Loyal Dog sleeps, but wakes up to bark
at mailman.
</plot>
<success type="bestseller">4</success>
<success type="bookclubs">9</success>
</book>
</books>

XML 元素和屬性名可以包含大寫字母 A-Z、小寫字母 a-z、數字 0-9、一些特殊字符和非英文字符以及三種標點符號:連字符、下劃線和句點。名字中不能出現其他標點符號。

XML 是大小寫敏感的。這個例子中, 和 描述了兩種不同的元素。兩種形式都允許。使用 和 描述兩種不同的元素可能不是一種好辦法,因為很容易出現筆誤。

每個 XML 文檔都有且只有一個根元素。根元素是 XML 文檔中惟一沒有父元素的元素。上例中的根元素是 。多數 XML 文檔包含父元素和孩子元素。 元素只有一個子元素,即 。 元素有四個子元素,、 和 。 元素有三個子元素,都是 元素。每個 元素都有兩個子元素,即 和 。

除了形成父子關係的元素嵌套之外,XML 元素還可以具有屬性。屬性是附加到元素起始標記上的名值對。名稱和值之間用等號 「=」 分開。值用單引號或雙引號括起來。上面的清單 1 中, 元素有兩個屬性,"bestseller" 和 "bookclubs"。關於屬性的用法在 XML 開發者之間有不同的考慮。多數包含在屬性的信息也可以放在子元素中。一些開發者堅持認為屬性信息應該是元數據,即關於數據的信息,而不是數據本身。數據本 身應該包含在元素中。是否使用屬性實際上取決於數據的性質以及如何從 XML 中提取數據。

XML 的力量

XML 的優點之一是比較簡單,可以使用簡單的文本編輯器或者字處理程序來編寫 XML,不需要專門的工具或軟件。XML 的基本語法由嵌套元素組成,部分元素具有屬性和內容。元素通常包括兩個標記,一個起始標記和一個結束標記,分別用 和 < /tag > 表示。XML 大小寫敏感,而且空白是有意義的。看起來和眾所周知的 HTML 很相似,但和 HTML 不同的是 XML 允許用更具描述性的名稱命名標記。XML 的其他優點包括自描述、同時供人類和機器讀取、支持 Unicode(這使它支持不同語言的國際化)、嚴格的語法和解析要求。不幸的是,UTF-8 在 PHP5 中有問題,這一不足也是推動 PHP6 開發的動力之一。

XML 的弱點

XML 非常囉嗦,帶來的後果是存儲體積大,消耗帶寬多。儘管人們應該能夠讀取它,但是很難想像一個人會去閱讀包含 7 百萬個節點的 XML 文件。最基本的解析器功能支持的數據類型不多,因此處理不規則或少見的數據(經常會遇到這種情況)成為最主要的困難。

結構良好的 XML

符合全部 XML 語法規則的 XML 文檔是結構良好的。結構不良好的文檔從技術上講就不是 XML。
之類的 HTML 標記在 XML 中是不允許的,要想成為結構良好的 XML,必須寫成
。解析器不能正確解析結構不良好的 XML。此外,XML 文檔有且只能有一個根元素。可以將根元素看成是有無窮層的文件櫃。雖然只有一個文件櫃,但是在其中放什麼和放多少沒有什麼限制。有數不清的抽屜和夾子可以 存放信息。




PHP 基礎

本文的多數讀者曾經用過 PHP,但不一定清楚它的歷史和發展。

關於 PHP

超文本預處理器(PHP)是一種跨平台的腳本語言,用於編寫動態網頁和服務器端應用程序軟件。最初被稱為 Personal Home Page/Form Interpreter (PHP/FI),後來在 Suraski 和 Gutmans 的手中獲得了新生,這兩個人在 1998 年 6 月推出了 PHP3。他們的公司 Zend Technologies 仍然控制著 PHP 的發展。

PHP5 於 2004 年 7 月發佈,以 Zend Engine II 為基礎,提供了很多新特性,其中包括:

  • 對面向對象編程的全新支持
  • 更好地支持 MySQL
  • 更好地支持 XML,這正是我們所關心的

PHP5 和 XML

雖然 PHP 在以前的版本中就提供了 XML 支持,但是隨著 PHP5 的出現這種支持大大強化了。由於 PHP4 對 XML 的支持比較有限,比如默認情況下只提供基於 SAX 的解析器、PHP4 DOM 沒有實現 W3C 標準,對於 PHP5,可以說 PHP XML 開發人員是重新發明了輪子,符合常用的標準。

PHP5 新增 XML 特性

PHP5 包括徹底重新編寫的和新增加的擴展,如 SAX 解析器、DOM、SimpleXML、XMLReader、XMLWriter 和 XSLT 處理程序。所有這些擴展都以 libxml2 為基礎。

除了自 PHP4 改進的 SAX 支持以外,PHP5 還同時支持符合 W3C 標準的 DOM 和 SimpleXML 擴展。默認情況下同時支持 SAX、DOM 和 SimpleXML。如果熟悉其他語言中的 DOM,使用 PHP 實現類似的功能會更簡單。




PHP5 中讀取、操縱和寫入 XML

如果使用 PHP5 讀取、操作、編寫 XML,而且處理的 XML 文檔簡單、可預測、比較小,則 SimpleXML,必要的時候再加上 DOM,是最理想的選擇。

快速入門的 API

在 PHP5 眾多的 API 中 DOM 和 SimpleXML 是最為人所熟悉(DOM)和最簡單的(SimpleXML)。而且多數情況下,就像後面的例子一樣,也是功能最完善的。

DOM 擴展

文檔對象模型(DOM)是表示 HTML 和 XML 文檔的 W3C 標準對象集合,將這些對象結合起來的標準模型以及訪問和操縱它們的標準接口。很多廠商支持 DOM 作為其私有數據結構和 API 的接口,由於開發人員對其比較熟悉,給 DOM 模型增加了不少權威色彩。DOM 很容易理解和使用,因為其內存結構模仿了原始 XML 文檔。為了把信息傳遞給應用程序,DOM 創建和 XML 文件元素樹完全相同的對象樹,每個 XML 元素都用樹中的一個節點表示。DOM 是基於樹的解析器。因為 DOM 要構造整個文檔樹,要花費大量的內存和處理器時間。因此,性能問題決定了使用 DOM 很難處理大型文檔。本文中主要把 DOM 擴展用於導入 SimpleXML 格式(作為字符串)和輸出 DOM 格式的 XML(作為 XML 文件)或者相反。

SimpleXML

我們選擇 SimpleXML 擴展解析 XML 文檔。SimpleXML 擴展需要 PHP5 并包括和 DOM 的互操作性,以便編寫 XML 文件和內置的 XPath 支持。SimpleXML 最適合簡單的、類似記錄的數據,比如從同一個應用程序其他部分傳遞來的 XML 文檔或字符串。如果 XML 文檔不是很複雜,嵌套不太深,沒有混合內容,使用 SimpleXML 要比 DOM 簡單得多,就像其名字所說的那樣。如果使用已知的文檔結構就更可靠。

簡單的例子

這些例子使用 DOM 和 SimpleXML 處理較小的、一般的 XML 文件。




使用 DOM

DOM 是在瀏覽器中使用的、用 JavaScript 操作的 W3C DOM 規範。方法都是一樣的,因此可以使用熟悉的編碼技術。清單 2 示範了使用 DOM 創建 XML 字符串和 XML 文檔並設置格式以便查看。


清單 2. 使用 DOM
 <?php

//Creates XML string and XML document using the DOM
$dom = new DomDocument('1.0');

//add root - <books>
$books = $dom->appendChild($dom->createElement('books'));

//add <book> element to <books>
$book = $books->appendChild($dom->createElement('book'));

//add <title> element to <book>
$title = $book->appendChild($dom->createElement('title'));

//add <title> text node element to <title>
$title->appendChild($dom->createTextNode('Great American
Novel'));

//generate xml
$dom->formatOutput = true; // set the formatOutput attribute of
domDocument to true
// save XML as string or file
$test1 = $dom->saveXML(); // put string in test1
$dom -> save('test1.xml'); // save as file
?>

生成的輸出文件如清單 3 所示。


清單 3. 輸出文件
  <?xml version="1.0"?>
<books>
<book>
<title>Great American Novel</title>
</book>
</books>

清單 4 在 DOMElement 對象中導入了 SimpleXMLElement 對象,示範了 DOM 和 SimpleXML 的互操作。


清單 4. 互操作性,第 1 部分 —— DOM 導入 SimpleXML
 <?php

$sxe = simplexml_load_string('<books><book><title>Great American
Novel</title></book></books>');

if ($sxe === false) {
echo 'Error while parsing the document';
exit;
}

$dom_sxe = dom_import_simplexml($sxe);
if (!$dom_sxe) {
echo 'Error while converting XML';
exit;
}

$dom = new DOMDocument('1.0');
$dom_sxe = $dom->importNode($dom_sxe, true);
$dom_sxe = $dom->appendChild($dom_sxe);

echo $dom->saveXML('test2.xml');

?>

清單 5 中的函數將 DOM 文檔中的節點轉化成 SimpleXML 節點。然後可以作為真正的 SimpleXML 元素來使用這個新的對象。如果出現錯誤則返回 FLASE。


清單 5. 互操作性,第 2 部分 —— SimpleXML 導入 DOM
 <?php
$dom = new domDocument;
$dom->loadXML('<books><book><title>Great American
Novel</title></book></books>');
if (!$dom) {
echo 'Error while parsing the document';
exit;
}

$s = simplexml_import_dom($dom);

echo $s->book[0]->title; // Great American Novel
?>




使用 SimpleXML

我們選擇 SimpleXML 擴展來解析 XML 文檔。SimpleXML 擴展包括與 DOM 的互操作性,用於編寫 XML 文件和內置的 XPath 支持。SimpleXML 比 DOM 更容易使用,就像名稱所預示的那樣。

如果不熟悉 PHP,清單 6 對測試 XML 文件進行格式化,可供後面復用。


清單 6. 將測試 XML 文件格式化成 PHP include 文件 example.php 以備後面使用
 <?php
$xmlstr = <<<XML
<?xml version='1.0' standalone='yes'?>
<books>
<book>
<title>Great American Novel</title>
<characters>
<character>
<name>Cliff</name>
<desc>really great guy</desc>
</character>
<character>
<name>Lovely Woman</name>
<desc>matchless beauty</desc>
</character>
<character>
<name>Loyal Dog</name>
<desc>sleepy</desc>
</character>
</characters>
<plot>
Cliff meets Lovely Woman. Loyal Dog sleeps, but wakes up to bark
at mailman.
</plot>
<success type="bestseller">4</rating>
<success type="bookclubs">9</rating>
</book>
</books>
XML;
?>

在 Ajax 應用程序中,可能需要從 XML 文檔提取郵政編碼和查詢數據庫。清單 7 從上面的示例 XML 中直接提取 。


清單 7. 提取節點 —— 有多麼簡單?
 
<?php

include 'example.php';

$xml = new SimpleXMLElement($xmlstr);

echo $xml->book[0]->plot; // "Cliff meets Lovely Woman. Loyal
Dog..."
?>

另一方面,也許還要提取分為多行的地址。當一個元素的多個實例是一個父元素的子元素,通常需要使用迭代技術。如清單 8 所示。


清單 8. 提取元素的多個實例
 <?php

include 'example.php';

$xml = new SimpleXMLElement($xmlstr);

/* For each <book> node, echo a separate <plot>. */
foreach ($xml->book as $book) {
echo $book->plot, '
';
}

?>

除了讀取元素名稱及其值以外,SimpleXML 也能訪問元素的屬性。清單 9 中就像訪問數組成員一樣訪問元素的屬性。


清單 9. SimpleXML 訪問元素的屬性
 
//Input XML file repeated for your convenience

<?php
$xmlstr = <<<XML
<?xml version='1.0' standalone='yes'?>

<books>
<book>
<title>Great American Novel</title>
<characters>
<character>
<name>Cliff</name>
<desc>really great guy</desc>
</character>
<character>
<name>Lovely Woman</name>
<desc>matchless beauty</desc>
</character>
<character>
<name>Loyal Dog</name>
<desc>sleepy</desc>
</character>
</characters>
<plot>
Cliff meets Lovely Woman. Loyal Dog sleeps, but wakes up to bark
at mailman.
</plot>
<success type="bestseller">4</rating>
<success type="bookclubs">9</rating>
</book>
</books>
XML;
?>

<?php
include 'example.php';

$xml = new SimpleXMLElement($xmlstr);

/* Access the <success> nodes of the first book.
* Output the success indications, too. */
foreach ($xml->book[0]->success as $success) {
switch((string) $success['type']) { // Get attributes as element indices
case 'bestseller':
echo $success, ' months on bestseller list';
break;
case 'bookclubs':
echo $success, ' bookclub listings';
break;
}
}
?>

要把元素或屬性和字符串進行比較,或者將其傳遞給需要字符串參數的函數,必須使用(string)強制轉換成字符串。否則,默認情況下 PHP 將元素看作對象,如清單 10 所示。


清單 10. 調用字符串或丟棄
  <?php

include 'example.php';

$xml = new SimpleXMLElement($xmlstr);

if ((string) $xml->book->title == 'Great American Novel') {
print 'My favorite book.';
}

htmlentities((string) $xml->book->title);
?>

SimpleXML 中的數據不一定是常數。清單 11 生成了一個新的 XML 文檔(如後所示),和原來的相同,只不過新的 XML 文件中把 Cliff 換成了 Big Cliff。


清單 11. 使用 SimpleXML 修改文本節點
  <?php
$xmlstr = <<<XML
<?xml version='1.0' standalone='yes'?>
<books>
<book>
<title>Great American Novel</title>
<characters>
<character>
<name>Big Cliff</name>
<desc>really great guy</desc>
</character>
<character>
<name>Lovely Woman</name>
<desc>matchless beauty</desc>
</character>
<character>
<name>Loyal Dog</name>
<desc>sleepy</desc>
</character>
</characters>
<plot>
Cliff meets Lovely Woman. Loyal Dog sleeps, but wakes up to bark
at mailman.
</plot>
<success type="bestseller">4</rating>
<success type="bookclubs">9</rating>
</book>
</books>
XML;
?>

<?php

include 'example.php';
$xml = new SimpleXMLElement($xmlstr);

$xml->book[0]->characters->character[0]->name = 'Big Cliff';

echo $xml->asXML();
?>

自 PHP 5.1.3 以後,SimpleXML 就能夠方便地添加子元素和屬性了。清單 12 根據原始文檔輸出一個 XML 文檔,包含新的字符和描述符。


清單 12. 使用 SimpleXML 添加子元素和文本節點
  <?php
$xmlstr = <<<XML
<?xml version='1.0' standalone='yes'?>
<books>
<book>
<title>Great American Novel</title>
<characters>
<character>
<name>Cliff</name>
<desc>really great guy</desc>
</character>
<character>
<name>Lovely Woman</name>
<desc>matchless beauty</desc>
</character>
<character>
<name>Loyal Dog</name>
<desc>sleepy</desc>
</character>
<character>
<name>Yellow Cat</name>
<desc>aloof</desc>
</character>
</characters>
<plot>
Cliff meets Lovely Woman. Loyal Dog sleeps, but wakes up to bark
at mailman.
</plot>
<success type="bestseller">4</rating>
<success type="bookclubs">9</rating>
</book>
</books>
XML;
?>

<?php
include 'example.php';
$xml = new SimpleXMLElement($xmlstr);

$character = $xml->book[0]->characters->addChild('character');
$character->addChild('name', 'Yellow Cat');
$character->addChild('desc', 'aloof');

$success = $xml->book[0]->addChild('success', '2');
$success-> $rating->addAttribute('type', 'reprints');

echo $xml->asXML();
?>




結束語

本系列文章分為三部分,這是第一部分,主要介紹了能夠快速入門的 API,通過例子說明如果處理的 XML 文檔簡單、可預測而且相對較小,那麼使用 SimpleXML,必要的時候再結合 DOM,是一種理想的辦法。PHP5 大大增強了開發人員在 PHP 中處理 XML 的能力。第 2 部分將討論高級 XML 解析技術。



參考資料

學習
  • 您可以參閱本文在 developerWorks 全球站點上的 英文原文
  • 面向 Perl 和 PHP 開發人員的 XML:您可以通過該專題來瞭解更多與 Perl 和 PHP 相關的 XML 技術。
  • 用 PHP 讀取和編寫 XML DOM(Jack Herrington,developerWorks,2006 年 2 月):用三種方法讀取 XML:DOM 庫、SAX 解析器和正則表達式。此外,還可以瞭解到使用 DOM 和 PHP 文本模板寫入 XML。
  • PHP 中的 SimpleXML 處理(Elliotte Rusty Harold,developerWorks,2006 年 10 月):試一試 SimpleXML 擴展,能夠幫助 PHP 頁面實現查詢、搜索、修改和重新發佈 XML。
  • PHP V5 遷移指南(Jack Herrington,developerWorks,2006 年 12 月):將 PHP V4 開發的代碼遷移到 V5,大大改善代碼的可維護性和穩定性。
  • 關於 SimpleXML 的系列文章的第一部分 Introducing Simple XML in PHP5(Alejandro Gervasio,Dev Shed,2006 年 6 月):通過 PHP 5 中的 simplexml 擴展節約開發時間,這個庫主要用於解析簡單的 XML 文件。
  • PHP Cookbook, Second Edition( Adam Trachtenberg 和 David Sklar,O'Reilly Media,2006 年 8 月):學習如何建立可在任何 Web 瀏覽器上工作的動態 Web 應用程序。
  • XML.com:關於 XML 世界的詳盡介紹請訪問 O'Reilly 的 XML 站點。
  • W3C XML Information:閱讀 XML 規範。
  • PHP 開發官方站點:學習這種被廣泛採用的、特別適合 Web 開發的通用腳本語言。
  • Planet PHP:請訪問 PHP 開發者社區新聞資源站。
  • IBM XML 認證:瞭解如何才能成為一名 IBM 認證的 XML 及相關技術的開發人員。
  • XML 技術文檔庫:developerWorks XML 專區提供了大量技術文章和技巧、教程、標準以及 IBM 紅皮書。
  • developerWorks 技術活動 網絡廣播:隨時關注技術的最新進展。

獲得產品和技術

討論