65.9K
CodeProject 正在变化。 阅读更多。
Home

第 7 章 - 使用 XML 进行编程

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.81/5 (13投票s)

2002年10月13日

31分钟阅读

viewsIcon

141294

Erik Westermann 的《一周学会 XML》的示例章节。

标题 《一周学会 XML》
作者 Erik Westermann
出版社 Premier Press 出版社
出版日期 2002年10月
ISBN 159200010X
价格 29.99 美元
页数 400

引言

本文摘自《一周学会 XML》,特别是周日晚上的课程(第七章),名为《使用 XML 进行编程》。我选择这一章作为本书的示例章节,因为我认为它能代表本书整体讨论的流程,并展示每节课的重点。

本书包含七节课以及其他资源和信息,所有内容都专注于一件事:让你快速掌握 XML 及其相关技术和最新发展。课程安排在周末,从周五晚上开始,到周日晚上结束——是的,你可以在一个周末学会 XML。

我知道你会在想,市面上和网上书店里有那么多 XML 书籍,“这本书有什么特别之处?”。这本书很特别,因为它不仅解释了 XML 是什么以及如何使用它,还展示了 XML 的相关、实用且真实的用途。

本书重点介绍了 XPath、XSD、DTD 和 CSS 等相关 XML 技术,并解释了为什么 XDR 等其他技术在某些情况下可能不重要。本书还采取了实际方法来处理 XML。在学习了核心语法和其他规则后,我将向你展示如何使用市场上两款最好的 XML 编辑器:Excelon 的 Stylus Studio 和 Altova 的 XML Spy 来处理 XML,因为如果 XML 编辑器能够提供帮助甚至生成大量 XML,那么手动编写 XML 文档、模式和转换就没有多大意义了。

我还讨论了如何在 Internet Explorer、Microsoft Active Server Pages 中使用 XML,以及如何将 XML 与 Microsoft 的最新产品 .NET Framework 和 Visual C# .NET 编程语言结合使用。

这本书适合你,因为它简明扼要地描述了 XML 及其相关技术,只关注当今快速变化的市场中的相关内容。我帮助你做出选择,这些选择可能关系到解决方案的成败,因为使用了不相关、不兼容或过时的标准。

以下是每节课的概述

  • 周五晚上:一节简短的课程,重点介绍 XML,包括它是什么、为什么有用以及其他人如何使用 XML。
  • 周六上午:重点介绍在 Internet Explorer 中使用 HTML 和 XSL 处理 XML,以及在 Microsoft 的 Active Server Pages 中使用 XML。本节课的目的是让你了解 XML 的用途——如果你不是程序员或者不理解课程中使用的编程语言,请不用担心。目的是让你接触这些技术,从而更好地理解其他人如何使用 XML。
  • 周六下午:本节课侧重于 XML 的核心:如何遵循 XML 规则来编写 XML 文档。课程涵盖了基本的文档结构、属性、注释和 CDATA 部分。课程还涵盖了字符编码,这使得国际用户能够阅读你的 XML 文档,以及命名空间——一个功能,通过允许你与其他用户共享 XML 文档,使其更加有用。
  • 周六晚上:这是本书中最长的课程之一,重点介绍使用 DTD 和 XSD 进行文档建模。我建议你在完成周六下午的课程后尽快开始阅读本章,以便在一晚内完成课程。
  • 周日上午:本节课的重点是使用 XML Spy 和 Stylus Studio 创建和处理 XML 解决方案。课程还涵盖了使用 Stylus Studio 进行 XSL 调试——当你的 XSL 代码不如预期运行时,这可以为你节省数小时的沮丧。本节课还描述了 Microsoft 的 XML 解析器,称为 Microsoft XML Core Services,如何确定你的系统上安装的版本,以及如何获取最新更新。
  • 周日下午:本节课重点介绍使用 CSS 和 XSL 等表示技术在 Web 上显示数据。本节课研究如何使用 Stylus Studio 的图形 XSL 编辑器创建的 XSL 来重用 XML 文档。
  • 周日晚上:本节课的重点是展示如何将 XML 与 Internet Explorer 的数据源对象 (DSO)、XML 文档对象模型 (XML DOM) 以及 Microsoft 的 .NET Framework 结合使用。
  • 附录 A:提供 HTML 和 XPath 参考。
  • 附录 B:提供 XML 语法和结构的参考信息。
  • 术语表:定义本书中使用的术语。

周日晚上 - 使用 XML 进行编程

你在很短的时间内取得了很大的进步。恭喜!掌握了 XML 的基本要素后,你现在可以开始处理 XML 了。本课分为三个主要部分

  • XML 数据绑定与 Internet Explorer。
  • 在 Internet Explorer 中使用 XML DOM。
  • 使用 Microsoft .NET Framework 处理 XML。

第一部分几乎不需要编程经验,而最后两部分则涉及大量的编程。你不一定非要是专业的程序员才能理解本课的内容。很多人只知道 enough 编程来为自己编写应用程序,而另一些人则对编程感兴趣但没有机会自己探索。如果后者描述了你的情况,那么本节将对你有所帮助。即使你没有任何编程经验,你也至少应该浏览一下本节,从另一个角度了解 XML。

最后三个主要部分的示例使用了以下编程语言:C#(发音为“see-sharp”)、JavaScript 和 VBScript。你不一定需要了解这些编程语言中的任何一种,但一些编程经验将有助于你更轻松地理解示例。对 .NET Framework 的讨论解释了它是什么以及它如何使用 XML。

Internet Explorer 中的 XML 数据绑定

数据绑定是一个通用术语,用于将数据源与能够显示数据的控件连接起来。数据源描述了任何充当数据来源的内容,例如数据库或 XML 文档。控件是另一个通用术语,用于描述用于在屏幕上布局信息的视觉元素,例如表格。

Internet Explorer 可以在没有编程的情况下将 HTML 表格绑定到 XML 数据源,从而让你轻松地在 HTML 页面上的表格中显示格式化的 XML 数据。这是通过一种称为数据源对象 (DSO) 的机制实现的。DSO 不需要任何编程,并且非常易于使用。它通常能满足大多数人的需求。使用 DSO 的唯一缺点是它仅适用于 Internet Explorer 4.0 及更高版本。

你只能使用 HTML 表格来显示通过 DSO 获取的数据,而 DSO 能够处理相对简单的数据结构。第一个示例(如图 7.1 所示)演示了如何使用 DSO 生成一个包含书籍、作者以及每本书国会图书馆 (LOC) 分类列表的表格。

图 7.1 - 在 HTML 表格中显示 XML 数据。

国会图书馆 (LOC) 分类系统的类和子类信息显示在表格的最后两列。有关国会图书馆分类系统的更多信息,请访问其网站:http://www.loc.gov/

该列表基于 books.xml 文档中的信息,该文档位于 \XMLInAWeekend\chapter07 文件夹中。页面本身名为 dso1.htm。它由 HTML 代码组成,还包括描述表格数据来源以及哪些单元格包含数据的标签。以下列表呈现了页面的大部分内容,相关部分以粗体显示

<html>
  <head>
    <title>Data Source Object Demo #1</title>
  </head>
  <body>
    <XML ID="xmldata" src="books.xml"></XML>
    <table datasrc="#xmldata" id="ListOfBooks" 
      width="80%" align="center" cellpadding="0" 
      cellspacing="0" border="1">
      <tr>
        <thead>
          <tr>
            <th>Title</th>
            <th>Author</th>
            <th>Class</th>
            <th>Subclass</th>
        </thead>
        <td valign="top"><div datafld="title"></div></td>
        <td valign="top"><div datafld="author"></div></td>
        <td valign="top"><div datafld="loc_class"></div></td>
        <td valign="top"><div datafld="loc_subclass"></div></td>
      </tr>
    </table>
    <br>
    <hr>
  </body>
</html>

附录 A 包含 HTML 参考,该参考描述了构成表格的所有元素,并演示了如何创建表格,因此我在此不再赘述。

列表的第一个粗体部分是 xml 元素。这个 xml 元素与你在 XML 文档声明中看到的 xml 元素大不相同。它分隔了所谓的 XML数据岛,它允许 XML 文档直接存在于 HTML 文档中或引用 XML 文档。ID 属性是必需的,因为它用于分配数据岛的名称。稍后,你将使用数据岛的名称将 HTML 表格绑定到它。与让 XML 文档内联显示其余 HTML 不同,本示例引用了位于单独文件中的 XML 文档,如 src 属性所示。请注意,xml 元素必须有一个结束标记。

XML 数据岛声明紧接着是一个 HTML 表格。大多数表格使用通用属性,但 datasrcID 属性除外。datasrc 属性通过名称将表格与 XML 数据岛相关联。请注意,名称前缀为井号 (#)。表格的 ID 属性为表格分配了一个名称。这可以省略,但提供名称是一个好习惯,因为你可能希望利用下一个示例中演示的附加功能。

你希望在特定单元格中显示的 XML 元素的名称出现在表格声明的后面。表格中的每个字段都必须包含在一个 HTML div 元素中,如前面的列表所示。datafld 属性的值必须与你希望在单元格中显示的 XML 元素的值名称完全匹配。你还可以在 datafld 属性中指定属性名称。DSO 能够匹配 XML 属性名称,并且通常可以处理相当复杂的 XML 文档。但是,DSO 似乎不喜欢根元素声明中的属性。

你可以直接在 Internet Explorer 中打开页面查看最终结果。根据你的系统速度,你可能会看到 Internet Explorer 读取 XML 文档并用数据填充表格时,表格正在被格式化。DSO 异步读取 XML 数据,这意味着 Internet Explorer 在 DSO 准备好时会获取新数据,而 DSO 会尽可能快地继续读取数据。此功能提高了整体性能,并使用户感觉 Internet Explorer 保持响应,即使在加载大型数据集时也是如此。

虽然结果很有趣,但还可以更好。屏幕上的信息量很大,上下滚动可能会变得很麻烦。DSO 提供了一种通过几个按钮和少量代码分页浏览数据集的方法。

分页浏览长数据集

DSO 为较长的数据集提供了分页支持。这是对用户的主要好处,因为他们可以轻松地逐页浏览数据集(参见图 7.2)。

图 7.2 - 分页浏览长数据集的导航控件。

示例文件名为 dso2.htm,也位于 \XMLInAWeekend\chapter07 文件夹中。直接在 Internet Explorer 中打开它并尝试导航按钮。

分页数据集的另一个优点是响应能力。我之前提到过 DSO 和 Internet Explorer 异步工作以获取和显示数据。当你第一次加载 dso2.htm 时,表格似乎在你用 Internet Explorer 打开页面的同时就被填充了。当你操作导航控件或只是查看屏幕上的信息时,DSO 和 Internet Explorer 正在努力工作,继续用 XML 文档中的信息填充表格。因此,尽管它正在努力使表格完全填充,Internet Explorer 仍然感觉响应迅速。

dso2.htm 文件与 dso1.htm 基本相同,只有一些小改动,所以我将只关注文档的新部分。以下列表从 HTML body 标记开始,并在表格的第一个 HTML tr 标记之后结束

<body>
  <XML ID="xmldata" src="books.xml"></XML>
  <center>

    <input type="button" value="FIRST Page" 
      onclick="ListOfBooks.firstPage();"> 

    <input type="button" value="&lt;&lt; Previous" 
      onclick="ListOfBooks.previousPage();">

    <input type="button" value="Next &gt;&gt;" 
      onclick="ListOfBooks.nextPage();"> 

    <input type="button" value="LAST Page" 
      onclick="ListOfBooks.lastPage();">

  </center>
  <hr>
  <br>

  <table datasrc="#xmldata" datapagesize="5" id="ListOfBooks"
      border="1" width="80%" align="center" 
      cellpadding="0" cellspacing="0" >

    <tr>
列表在 HTML body 元素之后开始,这是熟悉的 XML 元素,与你之前看到的相同。紧随该声明之后的是一个 HTML center 元素,它将开始和结束标签内的所有内容居中。

页面上有四个按钮,由 HTML input 元素描述。所有 input 元素的 type 属性都使其呈现为按钮,而 value 属性声明了按钮上显示的标题。value 属性使用预定义的 HTML 实体引用来表示小于号(< - &lt;)和大于号(> - &gt;),以避免与 HTML 标签混淆,因为附近有很多 HTML 标签。

onclick 属性的值是为用户提供导航支持的关键因素。每个 onclick 属性的名称来自属性捕获的事件。当用户单击一个按钮时,Internet Explorer 会评估 onclick 属性的值。属性的值使用显示数据的表格名称,如表格的 ID 属性(ListOfBooks)所示。后面跟着一个点,然后是你想要导航到的页面名称。有四个命名的页面可供导航:firstPage()lastPage()nextPage()previousPage()。每个页面名称后面的拼写、大小写和括号很重要,必须完全按照所示显示。

table 元素有一个新的属性 datapagesize,它描述了你希望表格在给定页面上显示多少行。使用数值指定每页的项目数,可以选择加上引号,如前面的列表所示。

虽然分页支持很有帮助,但你可以更进一步,允许用户定义他们希望每页显示多少项。

动态更改每页的项目数

允许用户更改每页显示的项目数可以提高解决方案的可用性,因为它有助于适应屏幕较小或分辨率较低而无法显示更多信息的用户的需求。此选项还通过允许用户自定义显示以满足其偏好来使解决方案更具交互性。

此解决方案在前一个解决方案的基础上进行了扩展,添加了另外两个 HTML input 元素和一些简单的 JavaScript 代码。输入元素捕获用户请求的每页项目数,JavaScript 代码动态地重新配置 DSO 并在每次更改后重置显示。整体效果如图 7.3 所示。

图 7.3 - 允许用户更改每页的项目数。

要感受此功能的工作原理,请使用 Internet Explorer 打开 dso3.htm 文件,该文件位于 \XMLInAWeekend\chapter07 文件夹中。导航到数据集中的另一页,然后更改页面数量。项目数量会发生变化,并且页面会重置为数据集的第一页。更改每页的项目数可能会使你很难确定你在数据集中的位置,但将显示重置为第一页可以最大限度地减少这种影响。

页面的第一个变化是引入了另外两个 HTML input 元素,如以下列表中的粗体行所示

<center>

  <input type="button" value="FIRST Page" 
    onclick="ListOfBooks.firstPage();"> 

  <input type="button" value="<< Previous" 
    onclick="ListOfBooks.previousPage();">

  <input type="button" value="Next >>" 
    onclick="ListOfBooks.nextPage();"> 

  <input type="button" value="LAST Page" 
    onclick="ListOfBooks.lastPage();">

  <input type="text" maxlength="2" size="2" id="itemsPerPage">
  <input type="button" value="change" onclick="changePageSize();">

</center>

第一个新的 input 元素是一个文本输入字段,用于捕获用户偏好的每页项目数。声明的关键部分是 ID 属性,它为字段分配了一个名称(itemsPerPage)。第二个 input 元素是一个按钮,用户单击它来执行请求的更改。与其他页面上的按钮一样,此按钮具有 onclick 属性。这次,该属性引用了一个应用更改的 JavaScript 函数的名称。在创建自己的页面时,你可以使用任何喜欢的名称,但请务必使用描述性名称,暗示 JavaScript 函数的作用。

页面尚未完成,因为处理新按钮单击事件的 JavaScript 代码不属于页面。JavaScript 代码通常驻留在 script 元素中,该元素又位于 HTML 页面的 head 开始和结束标记之间(这些标记出现在 html 元素之后,但在 body 元素之前),如下面的列表所示

<html>
  <head>
    <title>Data Source Object Demo #3</title>

    <script language="JavaScript">

    function Initialize()
    {
      itemsPerPage.value = ListOfBooks.dataPageSize;
    }
    
    function changePageSize()
    {
      ListOfBooks.dataPageSize = itemsPerPage.value;
      ListOfBooks.firstPage();
    }

    </script>

  </head>

  <body onload="Initialize();">

    <XML ID="xmldata" src="loc_classes.xml"></XML>
    <!-- rest of page... -->

此列表中有很多内容,所以让我们从列表末尾附近比较熟悉的 body 标签开始。body 标签有一个名为 onload 的属性,你在周六上午的课程中已经看到过。Internet Explorer 在加载完文档但尚未显示它时,会评估 onload 属性的值。因此,onload 属性通常引用一个执行初始化任务的函数,这些任务会使页面准备好显示。

JavaScript 是一种流行的编程语言,大多数 Web 开发人员至少都熟悉它。它之所以如此受欢迎,是因为它易于使用,并且得到包括 Internet Explorer 在内的主要浏览器的支持。HTML 页面上的 JavaScript 代码必须出现在 script 元素内,该元素的声明包括其中代码使用的编程语言名称。Internet Explorer 能够很好地识别脚本元素中出现的编程语言,因此 language 属性的值是可选的。但是,指定你使用的编程语言的名称是一个好习惯。对于 Internet Explorer,script 元素的 language 属性的有效设置为 JavaScriptJScriptVBScript

body 元素的 onload 属性引用 script 元素的起始标记之后立即出现的名为 Initialize() 的函数。你可以将此函数放在任何位置,只要它出现在 script 元素内。通常,将此函数放在 script 标签之后或 script 标签之前是很好的做法。

Initialize() 函数将 itemsPerPage 输入字段中显示的值设置为等于表格(ListOfBooks)显示的每页项目数,以便让用户知道表格开始时每页有多少项。函数中的单行代码引用输入字段的名称 itemsPerPage,后跟字段中保存你在屏幕上看到的值的属性(value),后跟一个等号。到目前为止,语句表示“为 itemsPerPage 字段分配一个值”。等号后面的代码描述了要分配给输入字段的内容:表格显示的页数的值。

下一个函数 changePageSize() 处理 input 字段旁边的按钮的 onclick 事件。函数的第一行将 itemsPerPage 输入字段中的值赋给 ListOfBooks dataPageSize 属性。下一行将表格的页面重置回数据集的第一页。

在设计使用 DSO 的自己的页面时,请记住以下几点

  • 根 XML 元素不能有属性。
  • XML 文档可以相当复杂。
  • DSO 能够处理属性。只需按名称引用它们。
  • 使用 ID 属性为所有按钮、表格和文本输入字段分配名称。
  • 创建分页数据集时,为显示数据集的表格的 dataPageSize 属性赋值,以获得最佳性能。

下一个示例使用 VBScript 和 XML DOM 来探索 XML 文档的结构并将其内容写入屏幕。

使用 XML DOM 探索 XML 文档

XML DOM(文档对象模型)提供了一种以编程方式创建和操作 XML 文档的方法。DOM 通过将 XML 文档读入计算机内存,然后将它的每个方面表示为一个独立的对象来公开(呈现)它。对象是一个逻辑元素(意味着它实际上不存在),它代表 XML 文档的某个部分、字符串,甚至是一个文件。对象不仅引用某个内容,还通过公开适合该对象的函数来提供操作它的方法。例如,代表字符串的对象(简称为字符串)公开了允许程序员比较、添加和操作字符串的函数。代表 XML 文档一部分的对象可以公开允许你导航到文档的另一部分、使用 XSL 转换它或向其添加新信息的函数。

虽然 XML 文档主要使用元素来传达有关文档结构和内容的信息,但 XML DOM 将 XML 文档表示为节点对象的集合。XML 文档有几种类型的元素,因此 XML DOM 有几种类型的节点,如表 7.1 所示。

表 7.1 XML 节点类型

类型 描述
文档 表示从 XML 声明开始的文档。该文档只有一个子节点(一个元素),代表文档的根元素。
documentFragment 表示 XML 文档的片段。
element 表示一个 XML 元素。
文本 表示元素和属性的(文本)内容。
attribute 表示元素的属性。
cdatasection 表示元素的 CDATA 数据。
processinginstruction 表示一个处理指令。
comment 表示一个注释。
entity 表示由文档的 DTD 定义的实体。
entityreference 表示由文档的 DTD 定义的实体引用。
documenttype 表示文档的 DTD。
notation 表示文档 DTD 中的节点表示法。

XML DOM 中的每个节点都公开一个名为 nodeType 的属性,该属性描述节点的类型,使你能够根据节点类型来处理它们。本节中的示例根据 XML 文档 nodeType 属性的值处理属性和元素,你很快就会看到。

XML DOM 的一个有趣功能是它允许你遍历整个文档,而无需按名称引用节点,这与你在上一课中使用 XPath 表达式看到的情况非常相似。本课的示例是一个包含 VBScript 代码的 HTML 页面,它使用 XML DOM 探索 XML 文档的结构,然后将结构和数据写入屏幕。图 7.4 显示了页面的输出外观。

图 7.4 - 使用 XML DOM 探索 XML 文档。

示例是位于 \XMLInAWeekend\chapter07 文件夹中的 XML-DOM.htm 文件。如果你按照 Preface 中的说明提取了本书配套的 ZIP 文件内容,那么你就准备好了。否则,你必须编辑该页面以更改示例所依赖的 XML 文档的位置。该示例使用了上一课中的 carparts.xml 文档,因为你现在可能已经熟悉它的结构和内容了。打开文档查看其结果。Internet Explorer 有可能询问你是否要继续运行该页面。回答“是”以允许页面中的代码继续处理完整的文档。

该页面大约由 95% 的 VBScript 代码组成,其余 5% 是支持性的 HTML 代码,因此我在此不描述 HTML 代码。

代码由三个函数组成,都用 VBScript 编写。Initialize 函数充当起点,在首次加载页面时被调用。它的作用是加载 XML 文档到 DOM,并通过调用 walk_elements 函数来启动处理。walk_elements 函数通过递归调用自身来遍历 XML DOM 中的元素,以显示每个元素的内容。当 walk_elements 遇到带有属性的元素时,它会调用 walk_attributes 函数,该函数显示元素所有属性的内容。代码并不复杂,除了 walk_elements 调用自身的部分。当一个函数调用自身时,它被称为递归。递归编程是处理多种逻辑结构的有效方法。我将逐步讲解代码在处理 XML 文档时如何执行,而不是一次性展示页面上所有 95 行代码。

页面加载时发生的第一个事件是执行以下行

indent = 0
此行创建了一个数字全局变量,页面上的所有代码都可以访问它,并将其初始值设置为 0。此变量控制页面布局的一个关键因素:每行的缩进。接下来,由于 HTML 文档的 body 元素的 onload 属性设置,调用了熟悉的 Initialize 函数。以下列表显示了 Initialize 函数的大部分内容
Function Initialize()
  Dim root
  Dim xmlDoc
  Dim child
  Dim indent

  indent=0
  Set xmlDoc = CreateObject("Msxml.DOMDocument")
  xmlDoc.async = False
  xmlDoc.validateOnParse=False

  xmlDoc.load("\XMLInAWeekend\chapter06\carparts.xml")

  If xmlDoc.parseError.errorcode = 0 Then
    Document.Write("
")
    walk_elements(xmlDoc)
    Document.Write("
")
  Else
    ' code omitted for brevity...
  End If
End Function

在声明一些局部变量的初始 Dim 语句之后,该函数开始使用 VBScript 的 CreateObject 函数创建 XML DOM 对象的一个实例。XML DOM 公开了一些控制其处理 XML 文档时行为的属性。接下来的两行将 DOM 对象的 asyncvalidateOnParse 属性设置为 False,实际上禁用了这两个选项(异步加载文档和在解析时验证文档)。If 语句通过评估 DOM 对象的 errorCode 属性的值来确定加载文档时是否发生任何错误。如果没有错误,该函数将调用 walk_elements 来开始处理文档。

walk_elements 函数接受一个参数:一个节点。当 Initialize 第一次调用 walk_elements 时,它将 XML DOM 的实例传递给函数,该实例本质上是一种特殊的节点,代表整个 XML 文档。(参见表 7.1 了解节点类型。)该函数首先初始化一个 For 循环,该循环对每个子节点执行一次,如下面的列表所示

function walk_elements(node)
  dim nodeName
  dim count
  count = 1
  indent=indent+2

  For Each child In node.childNodes
    For i = 1 To indent
        Document.Write(" ")
    Next

接下来,它通过使用 &nbsp; 预定义的 HTML 实体引用写入多个不间断空格字符来缩进即将写入的行。下一块代码写入节点的类型和名称,如下面的列表所示

    Document.Write("+--")
    Document.Write("<u>" & child.nodeTypeString & "</u>: ")
    If child.nodeType < 3 Then
      Document.Write "<b><" & child.nodeName _ 
        & "></b>  [#" & count & "]<br>")
      count = count + 1
    End If

child.nodeTypeString 表示节点的类型为字符串值,如表 7.1 的“类型”列所示。child.nodeType 属性表示节点的类型为数值。元素的 nodeType 值为 1,属性的 nodeType 值为 2。因此,If 语句确保屏幕上仅显示元素和属性。

下一块代码检查当前节点是否为元素,然后检查它是否有属性

    If (child.nodeType = 1) Then
      If (child.attributes.length > 0) Then
        indent=indent+1
        walk_attributes(child)
        indent=indent-1
      End If
    End If

如果节点具有任何属性(由 attributes.length 属性的值确定),则函数调用 walk_attributes 函数,并将当前节点传递给它以生成属性列表。walk_attributes 函数将在稍后讨论。walk_elements 函数的最后一步是调用自身来处理任何子节点并管理 indent 变量的值,通过减小其值

    If (child.hasChildNodes) Then
      walk_elements(child)
    Else
      Document.Write  child.text & "
"
End If Next indent=indent-2 End Function

walk_attributes 函数比 walk_elements 函数简单得多,因为属性使用简单的名称-值对结构,如周六下午的课程中所述。walk_attributes 函数如下所示

Function walk_attributes(node)
  For Each attrib In node.attributes
    For i=1 to indent
      Document.Write(" ")
    next
    Document.Write("o--" & attrib.nodeTypeString & "")
    Document.Write(": " & attrib.name & " -- {" _
      & attrib.nodeValue & "}
"
) Next End Function

此函数与 walk_elements 函数的行为类似。它通过 indent 变量的值描述的空格数缩进每一行,写入 nodeType 属性的字符串表示,并写入属性的值。函数的代码驻留在 For 循环中,该循环对每个属性执行一次。

通过更改 Initialize 函数中 xmlDoc.load 调用参数的值,你可以尝试将此示例与其他的、相对较短的 XML 文档一起使用。

Microsoft .NET Framework 是一组技术,它提供了一个统一的编程模型,用于基于全面的类库构建的传统 Windows 应用程序和 Web 应用程序,该类库公开了系统功能。.NET Framework 在许多方面都使用 XML,包括在系统之间传输信息。下一节将简要介绍 .NET Framework,并演示一个使用 C# 编程语言的应用程序。

XML 和 .NET Framework

.NET Framework 由三个关键元素组成

  • 公共语言运行时
  • .NET 类库
  • 统一组件

公共语言运行时是一个逻辑层,它将应用程序与执行它的平台分开,提供内存管理、错误处理和线程管理等执行服务。它抽象了操作系统、处理器架构以及它与特定编程语言之间的接口的细节。这使得开发人员更容易创建应用程序,也使得应用程序更容易协同工作。公共语言运行时的关键优势之一是它支持多种编程语言,包括 Visual C++ .NET、Visual Basic .NET、JScript .NET 和 Visual C# .NET。

.NET 类库提供了一个一致的编程模型,因为其功能可以通过 .NET Framework 支持的所有编程语言访问。它使开发人员能够轻松访问文件和数据库访问、高级绘图支持、输入和输出操作以及互操作性功能(如网络系统之间的数据交换)等系统功能。

.NET Framework 的功能通过一组统一组件公开,包括 ASP.NET、Windows Forms 和 Visual Studio .NET。ASP.NET 是 Microsoft Active Server Pages (ASP) 的下一代产品,支持对创建传统 Windows 应用程序的开发人员来说很熟悉的编程模型。ASP.NET 还支持 Web 服务,这是一种暴露供人们通过应用程序和网站使用的新服务方式。Windows Forms 是跨所有支持的编程语言创建具有图形用户界面的传统 Windows 应用程序的统一方式。Visual Studio .NET 是一个与 .NET Framework 紧密集成的开发环境,使其成为开发和部署以网络为中心和网络感知的应用程序和服务的绝佳工具。

.NET Framework 在各个方面都使用 XML,从配置文件到 ADO.NET(一种数据访问技术)中对 XML 的原生支持,再到与其他系统的信息交换。.NET 类库提供了许多处理 XML 的类,使得创建 XML 感知的应用程序更加容易。

本讨论的示例是一个传统的 Windows 应用程序,用 Visual C# .NET 编写,它读取 XML 文档并将其显示在 Windows Forms TreeView 控件中,如图 7.5 所示。

图 7.5 - 一个显示 XML 文档内容的 Windows Forms 应用程序。

你的系统必须安装 .NET Framework 才能编译和使用此应用程序。.NET Framework 可从 Microsoft 的 MSDN 网站免费获取:http://msdn.microsoft.com。系统要求也发布在那里。请在下载 .NET Framework 之前查看它们,因为它是一个大型下载。如果你已经安装了 .NET Framework 但没有 Visual Studio .NET,我在本书的源代码发行版中提供了一个已编译的示例代码版本。你应该可以直接启动应用程序来尝试。应用程序的名称是 xmlTreeView,位于 \XMLInAWeekend\chapter07\dotNET 文件夹中。应用程序的可执行文件名为 xmlTreeView.exe。

该应用程序的控件很简单。单击按钮以打开文件选择对话框并开始读取要查看的 XML 文档。在选择文件之前,请使用“展开树”复选框,以便在加载文件时自动将其内容展开到树视图中。自动展开所有元素可能会花费很长时间,如果文档很大或结构复杂,因此请谨慎使用此功能。应用程序的一个不明显的特点是,你可以拖动窗口的左边框和底边框,这将同时拖动树视图控件的左边框和底边框。这使得无需水平或上下滚动即可在树视图控件中查看更长或更宽的 XML 文档。

与前一个示例(使用 XML DOM 探索 XML 文档的结构和内容)不同,本示例使用一个仅前进、只读的数据流来快速读取 XML 文档。(如果你熟悉 XML 解析器编程模型,则此编程模型类似于 SAX(XML 的简单 API)提供的模型。不同之处在于解析器在读取 XML 文档时不会引发事件。相反,应用程序会通知解析器何时从 XML 文档读取下一块信息。)该应用程序将文档显示在 System.Windows.Forms.TreeView 控件中,这使得用户可以使用熟悉的界面轻松检查文档,同时占用屏幕空间相对较少。

管理显示的代码相当复杂,超出了本书的范围,因此我在此不进行介绍。我将描述运行应用程序时的大部分代码。代码比前面的示例简单得多,因为它侧重于读取 XML 文档并将信息添加到树视图控件。.NET 类库处理其余的细节。

应用程序首先显示一个文件对话框,允许用户选择要查看的文件。以下列表显示了应用程序如何创建对话框实例并与其进行交互

OpenFileDialog oFileDlg = new OpenFileDialog();
oFileDlg.Filter = "XML files (*.xml;*.xsl)|*.xml;*.xsl|All files (*.*)|*.*";
oFileDlg.FilterIndex = 1;
oFileDlg.RestoreDirectory = true;
populateTreeView(oFileDlg.FileName);

Visual C# .NET 与 C++ 类似,非常容易学习。前面的列表中的代码只是捕获用户想要查看的文件名,并将其传递给另一个名为 populateTreeView 的函数,该函数是应用程序核心功能的所在地。

populateTreeView 函数的作用是从 XML 文档中读取 XML 数据,并将该信息传输到 TreeView 控件进行显示。该函数使用 System.Xml.XmlTextReader 对象,该对象提供对 XML 文档的快速、仅前进访问,而不会在读取文档时对其进行验证。该函数首先根据 System.IO.FileStream 对象打开 XML 文档,如下面的列表所示

XmlTextReader xmlReader;
// strFile contains the name of the file the user wants to open
fileStreamObject = new FileStream(strFile, FileMode.Open, FileAccess.Read);
xmlReader = new XmlTextReader(fileStreamObject);

代码通过一个循环读取 XML 文档,该循环持续到 XmlTextReader 能够成功从 XML 文档中读取信息。该应用程序使用 switch 语句来确定它正在处理哪种类型的节点,因为某些节点(如注释、CDATA 部分和处理指令)的显示方式与元素节点略有不同。以下列表显示了处理元素节点的应用程序部分

switch(xmlReader.NodeType)
{
  // code omitted for brevity...
  case XmlNodeType.Element:

    xmlNode = new TreeNode("<" + xmlReader.Name + ">");
    emptyElement = xmlReader.IsEmptyElement;

    while(xmlReader.MoveToNextAttribute())
    {
      TreeNode attNode = new TreeNode("Attribute");
      attNode.Nodes.Add(xmlReader.Name + "='" + xmlReader.Value + "'");
      xmlNode.Nodes.Add(attNode);
    }
  continue;
  // code omitted for brevity...
}
xmlTree.Nodes.Add(xmlNode);

此应用程序创建了一个 TreeNode 对象实例,其中包含元素的名称及其属性。属性被添加为元素节点的子节点,以利用 TreeView 控件的显示功能。在继续处理下一个节点之前,代码会将之前创建的 TreeNode 对象添加到 TreeView 控件(列表的最后一行)。

这结束了对 .NET Framework 和 Windows Forms 应用程序的简要介绍。如果你有兴趣了解更多关于 .NET Framework 或本课中使用的各种编程语言的信息,请参阅本书的资源部分,其中提供了一些有趣的网站地址,或者访问我的网站(http://www.designs2solutions.com)。我拥有相同的资源,只是我保持链接的更新,以防它们发生更改。

摘要

你这个周末取得了长足的进步,现在你已经准备好运用你新获得的对 XML 及其相关技术的理解了。XML 技术正在迅速发展,以满足行业不断变化的需求。你应该努力跟上最新发展,定期访问万维网联盟 (W3C) 的网站(http://www.w3c.org),并订阅一些主要的 XML 门户网站上提供的优秀新闻通讯。XML 是一项伟大的技术,它正在渗透到计算行业的各个领域,并反映了行业通过开放、公开可用的标准来解决一些长期存在的问题的驱动力。

© . All rights reserved.