现在大家踊跃发言,博客园人气蒸腾,大家都在汗流浃背的贴着文章。我今天也来出把力,就说说文档对象模型,这个大家平时没怎么注意但却很重要的计算机软件开发技术。
文档对象模型英文名为 Document Object Model , 简称DOM,它是一种比较重要的软件设计和编制规范。可以这么说,平生不认DOM,便称英雄也枉然,很多时候它是我们眼皮底下的新大陆。
文档对象模型是面向对象编程技术的集中体现,若没有完整的面向对象编程思想,是不可能理解和开发文档对象模型,若开发者能开发出文档对象模型,那就说明他/她比较完整的理解和掌握了面向对象编程思想。
什么是文档对象模型,文档对象模型英文名为 Document Object Model , 简称DOM,W3C国际组织对文档对象模型是这样定义的(摘自 http://www.w3.org/DOM/ )
The Document Object Model is a platform- and language-neutral interface that will allow programs and scripts to dynamically access and update the content, structure and style of documents. The document can be further processed and the results of that processing can be incorporated back into the presented page. This is an overview of DOM-related materials here at W3C and around the web.
以我个人的英文水平翻译如下
文档对象模型是一种语言中立的接口或平台,程序或脚本能利用它来访问和更新结构化的文档。这些文档可以被进一步的处理,处理结果可以组成一个有效页面。这是W3C对web上的对文档对象模型原理的一般看法。
我们来逐步理解这个定义。首先什么是文档。文档就是以一种结构组织在一起的数据包。比如MS Word 文档就是一种文档,它包含了很多字符,图片,段落数据,并使用特定的组织结构保存在一个二进制文件中。 比如HTML文档,它也包含了文字,图片,链接,表单数据,并可以按照公开的HTML语法组成一种层次结构保存在一个字符串或文本文件中。
其次,什么是结构化的文档,很多文档它的内容组织呈现一种层次化的结构。即它的内容抽象化可以组成一种树状结构,比如HTML文档,XML文档。比如普通的文本文档,它就是一个字符串,其中各个字符或子字符串之间是没有关系的。此时普通文本文档就不是结构化的文档,若将某种支持层次结构的语法分析强加到这个文本文档时,则该文本文档就成了一个层次化的文档。
HTML文档若没有进行HTML解释,则它就是一个平淡无奇的纯文本文档,就是一个普通的字符串,若将HTML语法强加到这个字符串,则这个纯文本文档立即成为具有复杂的结构化文档。同样的道理,XML文件,SQL语句等纯文本文档,在它没有解释前是一个普通的字符串,解释之后就成为大有用途的XMLDOM,SQLDOM。
DOM是一种接口或平台,对于软件开发者来说,这种所谓的接口或平台就是编程接口(API),API有很多种,有直接调用函数的接口方式,比如传统Win32API函数,还有一种是暴露可编程对象,编程对象有公开的属性方法或事件,比如COM接口或.NET类库接口。还有基于WEB的WebService的编程接口。一般而言,对于DOM,编程接口就是可编程对象的编程接口。就是DOM向外发布若干个可编程对象,别的应用程序或者脚本语言可以调用这些可编程对象的公开成员。
DOM的一个重要特性就是应用程序或者脚本程序能利用它来访问和更新结构化文档。这个意思是说,DOM向外提供若干个可编程对象,这些对象使用种种手段,保证它和结构化文档中的某个部分保持对应关系,特别是对象的属性和文档片断的属性保持映射关系。而外部程序获得可编程对象的属性,经过DOM内部的映射关系,实际上就等价于获得某个文档片断的某个属性,外部程序修改可编程对象的属性,经过内部的映射关系,最终导致某个文档片断的属性的修改。因此DOM是应用系统和结构化文档之间的代理,应用系统使用DOM透视出文档的内容,也通过DOM“隔山打牛”的方式修改文档内容。
最后结构化文档处理后,可以形成一种有效页面,也就是结构化文档可以展示在用户界面上。一般的应用程序借助DOM,可以在用户界面上绘制结构化文档的内容。比如WEB浏览器,借助HTML DOM,在用户界面上绘制出HTML文档的样式。一些结构化文档没有用户界面,比如XML文档,但它具有可编程用户界面,其他的应用系统可以使用这个可编程用户界面来获知XML文档中到底有什么内容。
文档对象模型可以是语言中立的,也就是说跨语言跨平台,比如HTML和XML的文档对象模型,在W3C国际标准组织的努力下,已经是最典型的跨语言跨平台的文档对象模型,我们可以使用任何平台和语言来使用相同的方式和接口来访问XML和HTML,比如无论是Linux下的JAVA,Windows下的VB或各种浏览器中的JavaScript,甚至是MS Office 中的VBA,他们访问XML DOM的过程必然是类似的,很容易使用相同的处理流程来实现相同的功能。这样做的好处就是大大的方便程序的移植和各种系统之间交流数据。
可以这么认为,若文档具有生命,则它在保存在文件时,它就处于休眠状态,就差不多是死的,但一旦被DOM附体,它就是活的,可以任由开发人员支配,可以发挥任何应有的功能。
以上是我个人对文档对象模型的理论认识,接下来说说如何在软件开发中理解和文档对象模型。
文档对象模型是一种规范,在微软.NET框架类库中实现了两种种DOM,CodeDom和XMLDom。名称空间 System.CodeDom下定义了CodeDom,名称空间System.Xml下定义了XML Dom,这里使用大家比较熟悉的XML Dom 来讲解一番。首先是简单说明一下XML文档结构。以下是一个XML文档的样本。
2 <reportdocument unit="Document" version="1.0">
3 <width>1881</width>
4 <height>1729</height>
5 <name>PieDemo</name>
6 <title>图表演示报表</title>
7 <pageleftmargin>300</pageleftmargin>
8 <pagetopmargin>300</pagetopmargin>
9 <pagerightmargin>300</pagerightmargin>
10 <pagebottommargin>300</pagebottommargin>
11 <paperwidth>2481</paperwidth>
12 <paperheight>3507</paperheight>
13 <author>袁永福</author>
14 <ReportItems>
15 <reportpie sourceindex="0">
16 <id>reportpie1</id>
17 <left>169</left>
18 <top>775</top>
19 <width>1363</width>
20 <height>954</height>
21 <borderwidth>1</borderwidth>
22 <leftborder>0</leftborder>
23 <topborder>0</topborder>
24 <rightborder>0</rightborder>
25 <bottomborder>0</bottomborder>
26 <roundradio>30</roundradio>
27 <datasource>Region</datasource>
28 <thickness>60</thickness>
29 <ReportItems>
30 <reportpieitem sourceindex="1">
31 <value>41</value>
32 <id>pieitem0</id>
33 <text>华北 41</text>
34 </reportpieitem>
35 <reportpieitem sourceindex="2">
36 <value>20</value>
37 <id>pieitem0</id>
38 <text>华南 20</text>
39 </reportpieitem>
40 <reportpieitem sourceindex="3">
41 <value>16</value>
42 <id>pieitem0</id>
43 <text>华东 16</text>
44 </reportpieitem>
45 <reportpieitem sourceindex="4">
46 <value>7</value>
47 <id>pieitem0</id>
48 <text>西南 7</text>
49 </reportpieitem>
50 <reportpieitem sourceindex="5">
51 <value>2</value>
52 <id>pieitem0</id>
53 <text>西北 2</text>
54 </reportpieitem>
55 </ReportItems>
56 </reportpie>
57 </ReportItems>
58 </reportdocument>
类型System.Xml.XmlDocument就用来表示整个XML文档,XmlDocument是XML文档对象模型中的顶级对象,没有任何其他类型包含着XmlDocument,XmlDocument同时也是应用程序访问XML文档对象模型的唯一入口点。
XmlDocument可以包含若干个XML指令片断,例如这里包含了一个"<?xml ?>"指令,XMLDOM使用类型System.Xml.XmlDeclaratio来映射XML指令片断。
XML文档中充满了成对的尖括号,其中两个尖括号包含的文档片断是XML元素,XMLDom使用类型System.XML.XmlElement来映射XML元素,一个XmlElement包含一个名称,若干个属性,还可以包含若干个子节点。
没有被尖括号包含的文档片断就解释为纯文本数据,XMLDOM使用类型System.Xml.XmlText来映射纯文本数据。
根据各种映射关系,我们可以使用各种名称空间System.Xml下的对象类型来映射XML文档中所有部分。而且这些对象根据XML的层次结构组成一个对象树状结构,该对象树的根节点就是XmlDocument类型,于是我们可以很方便的访问往这个XML对象树状结构来获得XML文档中的任何数据,也可以新增,修改或删除对象来修改XML文档结构。如此我们就可以很容易通过编程来操作XML文档。我们使用XmlDocument.Load来加载XML对象树,使用XmlDocument.Save将XML文档保存为文件。
如果我们不用XMLDOM,我们如何编程来访问XML文档?很显然,这时的XML文档就是一个字符串,我们需要对这个包含XML内容的字符串进行很复杂的字符串操作,程序复杂而低效率,XML技术由于难以开发和使用而必然得不到推广。
我们深入研究System.Xml名称空间,看看微软.NET框架是如何实现XMLDom的。我们可以发现,其中比较重要的对象类型有 XmlNode , XmlElement , XmlText ,XmlAttribute, XmlDocument。
其中XmlNode是最重要的类型,它是所有其他XML文档类型的基础类型,它定义了所有XML文档对象类型的通用的接口,它的ChildNodes属性就包含了所有子节点对象,因此ChildNodes属性就是XML对象树状列表的组织基础,同时XmlNode是抽象类型,不可能存在XmlNode类型的对象实例。
XmlElement表示XML文档中的一个元素,可以包含若干个子节点,因此它的ChildNodes属性是有效的,子节点的类型可以是所有从XmlNode派生的类型,因此各个子节点的对象类型可以不一样。此外XmlElement是某个XML对象的子节点,比如其他XmlElement或XmlDocument。
一般情况下我们进行编程,同一个列表中保存的对象,它们的类型是一样的,可以放心大胆的使用强制类型转换来获得列表中的任意元素。但在XML文档对象类型中,同一个列表中的对象类型可能不一致,无条件的强制类型转换是不可靠的,容易出错,因此强制转换前需要进行类型判断。而且这种现象普遍存在于其他的文档对象模型中,比如HMTLDOM中,一个HTML节点的子节点也存在类似情况,因此针对文档对象模型编程时需要注意这点。
XmlText表示XML文档中的一段纯文本数据,它没有子节点,因此它的ChildNodes属性是无效的,同时它必然是其他Xml对象的子节点。
XmlAttribute表示XML节点的一个属性值,它没有子节点,因此它的ChildNodes属性是无效的,同时它必然是其他某个XmlElement的子节点。它保存在XmlElemenet的Attributes列表中,而不保存在ChildNodes中。
XmlDocument表示整个XML文档,是XMLDOM的顶级节点。它没有任何父节点。它可以包含若干个子节点,其中最多能有一个XMLElement子节点,它的DocumentElement属性就表示它那个唯一的XMLElement子节点。
根据上述,我们可以很容易的理解一个XML对象树状结构,这个结构的根节点是XmlDocument,它有若干个子节点,其中只有一个XmlElement子节点,我们称为DocumentElement,从DocumentElement开始,所有的XmlElement有若干个子节点,包括XmlText,XmlAttribute,其他XmlElment。我们要访问这个树状结构的某个节点,首先从根节点XmlDocument类型,使用逐层遍历查找或者使用XPath来查找我们所需的节点。通过修改节点的属性来修改XML文档。所有的操作完成后,调用XmlDocument.Save可以保存修改后的XML文档。
实际上XMLDOM比上述内容复杂的多,它内部存在很多的层次结构,内部定义了大量的XML文档成员类型和接口。成员类型之间存在很多派生关系,充分使用了面向对象编程思想中的封装,继承,重载,多态,抽象类和接口。比如存在以下派生关系链表XmlNode->XmlLinkedNode->XmlCharacterData->XmlText,为什么要设计如此的派生链表,每层应当实现什么样的功能,预留什么样的接口,每层又如何扩展上层类型的成员。所有的这些都是考验开发者的面向对象编程技术的基本功和软件设计思想,因此若一个开发者能理解和设计比较复杂而合理的DOM,则此人必是软件设计高手。
XMLDOM体现了DOM的基本的编程特性,
- 所有的文档对象类型都是从一个基础类型派生的,文档对象类型都在基础类型上实现了各种特性。
- 每个文档对象都映射了文档中某个片断,修改文档对象就等价于修改文档片断本身。
- 文档对象可以有子节点,由此构成一个多层次对象树状结构。
- 存在一个顶级对象,用来表示整个文档。可以宏观控制整个文档,也是应用程序访问文档对象树状结构的唯一入口。
- 可以将整个文档结构保存到一个文件中,也可以从一个文件中再现整个文档结构。这算对象序列化。
- 文档对象模型是可编程的,应用程序通过访问文档对象模型来访问结构化文档。
我们可以发现,其他的DOM都基本上实现了上述编程特性,比如名称空间System.CodeDom支持下的CodeDom,HTML DOM。
当然上述是严谨的DOM的编程特性,在实际应用中,可以根据各种需要进行简化,例如在笔者开发的“CHM文档生成器”(http://www.xdesigner.cn/_chmbuilder.aspx)中,实现了CHM DOM,它是一种很简单的自定义DOM。
在微软.NET标准库中,实现了XMLDOM和CodeDom两种比较标准的DOM模型,实际上还有很多地方存在着许多不严谨的DOM结构。比如名称空间System.IO下的FileSystemInfo , FileInfo , DirectoryInfo组成了文件系统DOM;名称空间System.Reflection下的类型组成了以Assembly为根节点的程序集DOM;名称空间System.Windows.Forms下的类型组成了以Form为文档对象,以Control为基础类型的WinFormDOM;名称空间System.Web.UI及其子名称空间下的类型组成了以Page为文档对象,以Control为基础类型的ASP.NET页面DOM。可以说,一般的对象树状结构都可以看作不严谨的DOM结构。
我们学习了XMLDOM后,就可以模仿着设计自己的DOM,比如上面提到的"CHM文档生成器“里面实现了很简单的CHM DOM,笔者在XDesignerLib中实现了一套比较复杂的设计文档对象模型,在自行开发的报表工具中实现了一套报表文档对象模型。在开源网站 http://sourceforge.net 上,使用关键字 DOM 进行查找,会找出很多开源项目,这些开源项目大多都和各种各样的DOM有关系。
文档就是数据,DOM处理文档,实际上就是处理数据,因此更进一步,我们开发开发各种应用系统中,都可以借鉴一下DOM的设计思想,比如开发WinForm或ASP.NET中,这些用户界面控件时也可以看作DOM。做电子病历时,可以设计出电子病历文档对象模型,做客户关系管理系统时,可以设计出客户文档对象模型。总之做XX系统时,可以考虑设计出XX文档对象模型。
文档对象模型是一种比较复杂的软件设计技术,但它功能强大,层次分明,逻辑清晰,好的文档对象模型合情合理,符合人们想当然的思想。大家有兴趣可以学习学习,研究研究,将来必有用途。
袁永福 ( http://www.xdesigner.cn ) 2007-6-7
来源:https://www.cnblogs.com/xdesigner/archive/2007/06/07/774487.html