Brian Randell
DevelopMentor
1999 年 10 月
摘要:本文讨论当 XML 文档被 Microsoft(R) XML Parser 显露之后,如何通过执行 XML DOM 来访问和操作 XML 文档。(共 10 页)
目录
前言
DOM 的确切定义是什么?
如何使用 XML Dom?
如何加载文档?
处理故障
在 XML 文档中检索信息
如何在文档中来回移动?
现在做什么?
假如您是 Visual Basic(R) 开发人员,您收到一些“可扩展的标记语言 (XML)” 文档格式的数据。此时您一定希望得到 XML 文档中的信息,并将这些数据结合到 Visual Basic 的解决方案中。您必然会自己编写代码来分析 XML 文件的内容,该文件不过是个文本文件而已。但这决不是多快好省的办法,而且抹煞了 XML 的优点:表现数据的结构化方法。
检索 XML 文件中的信息的较好方法是使用 XML 分析程序。十分简单,XML 分析程序是个软件,它读 XML 文件并使其中的数据成为可用的。作为 Visual Basic 的开发人员,希望使用支持 XML“文档对象模型 (DOM)”的分析程序。DOM 定义了分析程序应当显露的标准命令集,使您能够在程序中访问 HTML 和 XML 文档内容。支持 DOM 的 XML 分析程序取出 XML 文档中的数据,并通过一组可以对它编程的对象来显露它。在这篇文章中,您将学会当 XML 文档被 Microsoft(R) XML Parser 显露之后,如何通过执行 XML DOM 来访问和操作它 (Msxml.dll)。
在往下阅读之前,应当看一下原始的 XML 文件,以便对分析程序如何使您的生活更加轻松有个概念。下面的代码显露了含有压缩盘项目的文件 Cds.xml 的内容。每一项都含有诸如艺术家、标题和曲目等信息。
<?xml version="1.0"?>
<!DOCTYPE compactdiscs SYSTEM "cds.dtd">
<compactdiscs>
<compactdisc>
<artist type="individual">Frank Sinatra</artist>
<title numberoftracks="4">In The Wee Small Hours</title>
<tracks>
<track>In The Wee Small Hours</track>
<track>Mood Indigo</track>
<track>Glad To Be Unhappy</track>
<track>I Get Along Without You Very Well</track>
</tracks>
<price>$12.99</price>
</compactdisc>
<compactdisc>
<artist type="band">The Offspring</artist>
<title numberoftracks="5">Americana</title>
<tracks>
<track>Welcome</track>
<track>Have You Ever</track>
<track>Staring At The Sun</track>
<track>Pretty Fly (For A White Guy)</track>
</tracks>
<price>$12.99</price>
</compactdisc>
</compactdiscs>
以上文档的第二行涉及外部的 DTD,或者叫做“文档类型定义”文件。DTD 定义了特定类型 XML 文档的布局和预期内容。XML 分析程序可以使用 DTD 来确定文档是否有效。DTD 仅是一种方法,可以使用它帮助分析程序验证文档。还有一个越来越流行的验证文档的方法就是“XML 架构”。和 DTD 不同的是,我们使用 XML 定义架构,而 DTD 则使用它们自己“有趣的”语法。
下面的代码显示了 Cds.xml 使用的 Cds.dtd 的内容:
<!ELEMENT compactdiscs (compactdisc*)>
<!ELEMENT compactdisc (artist, title, tracks, price)>
<!ENTITY % Type "individual | band">
<!ELEMENT artist (#PCDATA)>
<!ATTLIST artist type (%Type;) #REQUIRED>
<!ELEMENT title (#PCDATA)>
<!ATTLIST title numberoftracks CDATA #REQUIRED>
<!ELEMENT tracks (track*)>
<!ELEMENT price (#PCDATA)>
<!ELEMENT track (#PCDATA)>
这篇文章并不打算深入探讨 DTD 和“XML 架构”。XML 架构语言(英文)是基于 XML 数据(英文)注释(符合 W3C)的。
XML 的 DOM 是个对象模型,它显露 XML 文档的内容。W3C 的文档对象模型 (DOM) 1 级规格 通常定义了 DOM 应当显露为什么属性、方法和事件。Microsoft 的 DOM 执行方法完全支持 W3C 标准,它的一些其他特性更便于在程序中使用 XML 文件。
通过创建 XML 分析程序的实例来使用 XML DOM。为此,Microsoft 通过 Msxml.dll 中的一组标准 COM 界面来显露 XML DOM。Msxml.dll 含有使用 XML 文档时用到的类库和执行代码。如果您正在使用有脚本的客户程序,如 Internet Explorer 中的 VBScript 执行,则通过用 CreateObject 方法创建分析程序对象的实例,来使用 DOM。
Set objParser = CreateObject( "Microsoft.XMLDOM" )如果您正在使用来自 Active Server Page(ASP) 的 VBScript,则应当使用 Server.CreateObject。
Set objParser = Server.CreateObject( "Microsoft.XMLDOM" )如果您正在使用 Visual Basic,可以通过设置对 MSXML 类库(在 Msxml.dll 中提供)的引用来访问 DOM。从 Visual Basic 6.0 内部使用 MSXML 的步骤为:
Dim xDoc As MSXML.DOMDocument
Set xDoc = New MSXML.DOMDocument
从何处可以找到 Msxml.dll?获得 MSXML 类库的办法有两种:
在 Visual Basic 项目中引用了类库之后,就可以调用分析程序,加载文档,使用文档中的数据。
也许您现在正在疑惑—;我现在使用的是什么?如果您打开了 MSXML 类库,并用 Visual Basic 6.0 对象浏览器检查它的对象模型,就会发现,对象模型是如此丰富。这篇文章示范了如何使用 DOMDocument 类和 IXMLDOMNode 接口来访问 XML 文档。
图 1. MSXML 分析程序对象模型
要加载 XML 文档,首先必须创建 DOMDocument 类的实例:
Dim xDoc As MSXML.DOMDocument Set xDoc = New MSXML.DOMDocument
当获得了有效的引用之后,使用加载方法打开文件。MSXML 分析程序能从本地磁盘上加载 XML 文档,在网上则用 UNC 引用或通过 URL 加载文档。
若要从磁盘加载文档,请使用加载方法创建下面的构造:
If xDoc.Load("C:/My Documents/cds.xml") Then
' 文档加载成功。
' 现在做一些有趣的事情。
Else
' 文档加载不成功。
End If
用完该文档之后,需要将您的对象引用释放给它。MSXML 分析程序并不显露明确的关闭方法。最好的方法是将引用明确设置为Nothing
。
Set xDoc = Nothing
当要求分析程序加载文件时,在默认情况下,它是非同步执行的。改变该文档的布尔 Async 属性可以改变这个特性。重要的是检查文档的 ReadyState 属性,保证文档在开始检查它的内容之前就已经就绪。ReadyState 属性可能返回的值为下列 5 种之一:
状态 | 值 |
尚未初始化:加载尚未开始。 | 0 |
正在加载:正在执行加载方法。 | 1 |
已经加载:加载方法已经完成。 | 2 |
交互:对于只读检查有足够的 DOM 可用,数据仅被部分分析。 | 3 |
完成:数据已被加载和分析,并可用于读取/写入操作。 | 4 |
MSXML 分析程序显露了在加载大的文档时可以跟踪加载进程状态的事件。当在 Internet 上从 URL 非同步加载文档时,这些事件也有用。
若要从 URL 打开文件,请使用完整格式的 URL 指定文件的位置。在文件位置前面必须加 http:// 前缀。
这里是从 URL 加载文件的例子:
xDoc.async = False
If xDoc.Load("http://www.develop.com/hp/brianr/cds.xml") Then
' 文档加载成功。
' 现在做一些有趣的事情。
Else
' 文档加载不成功。
End If
将文档的 Async 属性设置为 False
,分析程序在文档被完全加载并可以对其进行操作之前,不将控制返回到您的代码。如果将其设置为True
,您必须在访问该文档之前先检查其 ReadyState 属性,或者利用 DOMDocument 的事件,在文档就绪时通知您的代码。
由于各种各样的原因,文档加载很可能失败。其中最常见的原因可能是传送到加载方法的文档名无效。另一个原因可能是 XML 文档本身是无效的。
在默认情况下,MSXML 分析程序将验证在您的文档中是否指定了 DTD 或架构。如果在调用加载方法之前设置了 DOMDocument 对象引用的 ValidateOnParse 属性,就令分析程序不验证文档。
Dim xDoc As MSXML.DOMDocument
Set xDoc = New MSXML.DOMDocument
xDoc.validateOnParse = False
If xDoc.Load("C:/My Documents/cds.xml") Then
' 文档加载成功。
' 现在做一些有趣的事情。
Else
' 文档加载不成功。
End If
但要事先警告您:在制作应用程序时关闭分析程序的验证特性并不是好方法。不正确的文档因各种理由导致程序的失败。至少,它会向用户提供无效的数据。
不管何种故障的类型,都可以通过访问 ParseError 对象,要求分析程序向您提供故障信息。若要利用 ParseError 对象的属性,请将引用设置为文档自身的 IXMLDOMParseError 界面。IXMLDOMParseError 界面显露了 7 种属性,可以用来研究错误的原因。
下面的例子显示一个消息框,以及 ParseError 对象给出的所有错误信息。
Dim xDoc As MSXML.DOMDocument
Set xDoc = New MSXML.DOMDocument
If xDoc.Load("C:/My Documents/cds.xml") Then
' 文档加载成功。
' 现在做一些有趣的事情。
Else
' 文档加载不成功。
Dim strErrText As String
Dim xPE As MSXML.IXMLDOMParseError
' 获得 ParseError 对象
Set xPE = xDoc.parseError
With xPE
strErrText = "Your XML Document failed to load" & _
"due the following error." & vbCrLf & _
"Error #: " & .errorCode & ": " & xPE.reason & _
"Line #: " & .Line & vbCrLf & _
"Line Position: " & .linepos & vbCrLf & _
"Position In File: " & .filepos & vbCrLf & _
"Source Text: " & .srcText & vbCrLf & _
"Document URL: " & .url
End With
MsgBox strErrText, vbExclamation
End If
Set xPE = Nothing
可用 ParseError 对象显露的信息,将该信息显示给用户,将它记录到错误文件中,或者自己试着纠正错误。
加载文档之后,下一步就是从文档中检索信息。虽然文档对象是重要的,但仍可发现,在大部分时间里都在使用 IXMLDOMNode 接口。利用 IXMLDOMNode 接口来读写单独的节点元素。在做任何事情之前,必须了解 MSXML 分析程序通常支持的 13 种节点类型。下表列出了几种最常遇见的节点类型。
DOM 节点类型 | 实例 |
NODE_ELEMENT | <artist type="band">Offspring</artist> |
NODE_ATTRIBUTE | <artist type="band">Offspring</artist> |
NODE_TEXT | <artist type="band">Offspring</artist> |
NODE_PROCESSING_INSTRUCTION | <?xml version="1.0"?> |
NODE_DOCUMENT_TYPE | <!DOCTYPE compactdiscs SYSTEM "cds.dtd"> |
通过 IXMLDOMNode 接口显露的两个属性来访问节点类型。NodeType 属性显露了 DOMNodeType 项目的枚举(其中有些已列入上面的表中)。此外,还可以用 NodeTypeString 来检索节点类型的文本串。
当有了文档的引用之后,就可以开始在节点的层次中来回移动了。从您的文档引用可以访问 ChildNodes 属性,它提供了从上到下的入口,可以到达文档中的所有节点。ChildNodes 属性显露了 IXMLDOMNodeList,它支持 Visual Basic For/Each 构造。因此,您可以枚举 ChildNodes 属性的所有单个节点。此外,ChildNodes 属性显露 Level 属性,它可以返回现有子节点的数量。
文档对象不仅显露了 ChildNodes 属性,还显露了所有单个节点。这样,与 IXMLDOMNode 的 HasChildNodes 属性联合起来,就使得在节点层次中来回移动来检查元素、属性和值,变得十分简单。
需要提醒的一件事情就是,文档元素和元素值之间的主从关系。例如,在 CD XML 文档中,元素<标题>
显露了一首歌的标题。要检索<标题>
元素的实际值,需要寻找 NODE_TEXT 类型的节点。当找到了具有感兴趣数据的节点之后,就可以检查属性,甚至通过 ParentNode 属性到达并访问其主节点。
在 XML 文档中,可以在一组被文档对象显露的节点中来回移动。因为 XML 文档本来就是分层的,所以编写在整个文档中来回移动的递归例程要相对容易些。
LoadDocument 例程打开 XML 文档。然后 LoadDocument 调用另一个例程 DisplayNode,它在文档中真正地来回移动。LoadDocument 将引用当作参数和整数值传递到当前打开的 XML 文档的 ChildNodes 属性,指定从何处开始缩排级。代码使用缩排参数,在文档结构的 Visual Basic“快速窗口”中,将文本的显示格式化。
DisplayNode 函数在文档中来回移动,寻找特定于 NODE_TEXT 类型的节点。当代码找到了 NODE_TEXT 类型的节点之后,它用 NodeValue 属性来检索该节点的文本。此外,当前节点的 ParentNode 属性被用来获得 NODE_ELEMENT 类型节点的回溯引用。NODE_ELEMENT 类型的节点显露了 NodeName 属性。NodeName 和 NodeValue 的内容被显示。
如果通过检查 HasChildNodes 属性,确定该节点有子节点,则 DisplayNode 递归调用其自身,直到到达该文档的末尾。
DisplayNode 例程用 Debug.Print 将信息写入 Visual Basic 的“快速窗口”:
Public Sub LoadDocument()
Dim xDoc As MSXML.DOMDocument
Set xDoc = New MSXML.DOMDocument
xDoc.validateOnParse = False
If xDoc.Load("C:/My Documents/sample.xml") Then
' 文档加载成功。
' 现在做一些有趣的事情。
DisplayNode xDoc.childNodes, 0
Else
' 文档加载不成功。
' 查看前面列出的错误信息。
End If
End Sub
Public Sub DisplayNode(ByRef Nodes As MSXML.IXMLDOMNodeList, _
ByVal Indent As Integer)
Dim xNode As MSXML.IXMLDOMNode
Indent = Indent + 2
For Each xNode In Nodes
If xNode.nodeType = NODE_TEXT Then
Debug.Print Space$(Indent) & xNode.parentNode.nodeName & _
":" & xNode.nodeValue
End If
If xNode.hasChildNodes Then
DisplayNode xNode.childNodes, Indent
End If
Next xNode
End Sub
DisplayNode 用 HasChildNodes 属性来确定它是否应当再调用其自身。您还应当用节点的 Level 属性并检查大于 0 的值。
本文只作为入门之用。现在您可以深入学习,增进对 XML 和 MSXML 分析程序的了解。可以做许多有趣的事情,如更新独立节点项的值、在文档中搜索、创建自己的文档,等等。如果需要更多的实例、文章和下载,请访问 MSDN Online XML Developer Center。