级别: 中级 Cliff Morgan (cliffmorgan@webproducer.us), 自由撰稿人, Freelance
2007 年 4 月 06 日
本系列文章分为三部分,这是第一部分;介绍了 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 基础 对 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 的基本数据单位是元素。元素使用起始标记,如 <book> 和结束标记,如 </book> 分隔开。有起始标记必须有结束标记。如果缺少结束标记,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 是大小写敏感的。这个例子中,<Book> 和 <book> 描述了两种不同的元素。两种形式都允许。使用 <Book> 和 <book> 描述两种不同的元素可能不是一种好办法,因为很容易出现笔误。 每个 XML 文档都有且只有一个根元素。根元素是 XML 文档中惟一没有父元素的元素。上例中的根元素是 <books>。多数 XML 文档包含父元素和孩子元素。<books> 元素只有一个子元素,即 <book>。<book> 元素有四个子元素,<title>、<characters>、<plot> 和 <success>。<characters> 元素有三个子元素,都是 <character> 元素。每个 <character> 元素都有两个子元素,即 <name> 和 <desc>。 除了形成父子关系的元素嵌套之外,XML 元素还可以具有属性。属性是附加到元素起始标记上的名值对。名称和值之间用等号 “=” 分开。值用单引号或双引号括起来。上面的清单 1 中,<success> 元素有两个属性,"bestseller" 和 "bookclubs"。关于属性的用法在 XML 开发者之间有不同的考虑。多数包含在属性的信息也可以放在子元素中。一些开发者坚持认为属性信息应该是元数据,即关于数据的信息,而不是数据本身。数据本 身应该包含在元素中。是否使用属性实际上取决于数据的性质以及如何从 XML 中提取数据。 XML 的力量 XML 的优点之一是比较简单,可以使用简单的文本编辑器或者字处理程序来编写 XML,不需要专门的工具或软件。XML 的基本语法由嵌套元素组成,部分元素具有属性和内容。元素通常包括两个标记,一个起始标记和一个结束标记,分别用 <tag > 和 < /tag > 表示。XML 大小写敏感,而且空白是有意义的。看起来和众所周知的 HTML 很相似,但和 HTML 不同的是 XML 允许用更具描述性的名称命名标记。XML 的其他优点包括自描述、同时供人类和机器读取、支持 Unicode(这使它支持不同语言的国际化)、严格的语法和解析要求。不幸的是,UTF-8 在 PHP5 中有问题,这一不足也是推动 PHP6 开发的动力之一。 XML 的弱点 XML 非常罗嗦,带来的后果是存储体积大,消耗带宽多。尽管人们应该能够读取它,但是很难想象一个人会去阅读包含 7 百万个节点的 XML 文件。最基本的解析器功能支持的数据类型不多,因此处理不规则或少见的数据(经常会遇到这种情况)成为最主要的困难。 结构良好的 XML 符合全部 XML 语法规则的 XML 文档是结构良好的。结构不良好的文档从技术上讲就不是 XML。<br> 之类的 HTML 标记在 XML 中是不允许的,要想成为结构良好的 XML,必须写成 <br />。解析器不能正确解析结构不良好的 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 中直接提取 <plot>。 清单 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, '<br />'; } ?>
| 除了读取元素名称及其值以外,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 解析技术。
参考资料 学习
获得产品和技术
讨论
关于作者
| | | Cliff Morgan 是一位独立的顾问,设计和实现 Web 应用程序与网站。 | |