C#发现之旅第十讲 文档对象模型

C#发现之旅第十讲 文档对象模型

袁永福 2008-5-15

系列课程说明

    为了让大家更深入的了解和使用C#,我们将开始这一系列的主题为“C#发现之旅”的技术讲座。考虑到各位大多是进行WEB数据库开发的,而所谓发现就是发现我们所不熟悉的领域,因此本系列讲座内容将是C#在WEB数据库开发以外的应用。目前规划的主要内容是图形开发和XML开发,并计划编排了多个课程。在未来的C#发现之旅中,我们按照由浅入深,循序渐进的步骤,一起探索和发现C#的其他未知的领域,更深入的理解和掌握使用C#进行软件开发,拓宽我们的视野,增强我们的软件开发综合能力。

课程说明

    本课程专门讲述文档对象模型的概念,理论性比较强,需要仔细思考,而且没有演示程序,本课程是C#发现之旅系列课程的终结篇,不过不排除我今后推出C#发现之旅续集的可能性。
本系列课程已发布的文章有
C#发现之旅第一讲 C#-XML开发
C#发现之旅第二讲 C#-XSLT开发
C#发现之旅第三讲 使用C#开发基于XSLT的代码生成器
C#发现之旅第四讲 Windows图形开发入门
C#发现之旅第五讲 图形开发基础篇
C#发现之旅第六讲 C#图形开发中级篇
C#发现之旅第七讲 C#图形开发高级篇
C#发现之旅第八讲 ASP.NET图形开发带超链接的饼图
C#发现之旅第九讲 ASP.NET验证码技术
C#发现之旅第十讲 文档对象模型


文档对象模型定义

    文档对象模型英文名为 Document Object Model , 简称DOM,它是一种比较重要的软件设计模式,不是编程技巧。可以这么说,平生不认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.

    以我个人的英文水平翻译如下

文档对象模型是一种平台或语言中立的接口,程序或脚本能利用它来访问和更新结构化的文档。这些文档可以被进一步的处理,处理结果可以组成一个有效页面。这是W3Cweb上的文档对象模型原理的一般看法。

文档

    我们来逐步理解这个定义。首先什么是文档。文档就是以一种结构组织在一起的数据包。比如MS Word 文档就是一种文档,它包含了很多字符,图片,段落数据,并使用特定的组织结构保存在一个二进制文件中。 比如HTML文档,它也包含了文字,图片,链接,表单数据,并可以按照公开的HTML语法组成一种层次结构保存在一个字符串或文本文件中。

结构化文档

    其次,什么是结构化的文档,很多文档它的内容组织呈现一种层次化的结构。即它的内容抽象化可以组成一种树状结构,比如HTML文档,XML文档。

    对于普通的文本文档,从开发者看来,它就是一个字符串,其中各个字符或子字符串之间是没有相互关系的。此时普通文本文档就不是结构化的文档,若将某种支持层次结构的语法分析强加到这个文本文档时,则该文本文档就成了一个层次化的文档。

    HTML文档若没有进行HTML语法解释,则它就是一个平淡无奇的纯文本文档,就是一个普通的字符串,若将HTML语法强加到这个字符串,则这个纯文本文档立即成为具有相当复杂度的结构化文档。同样的道理,XML文件,SQL语句等纯文本文档,在它没有解释前是一个普通的字符串,解释之后就成为大有用途的XMLDOMSQLDOM

编程接口

    DOM是一种接口或平台,对于软件开发者来说,这种所谓的接口或平台就是编程接口(API),API有很多种,有直接调用函数的接口方式,比如传统Win32API函数,还有一种是暴露可编程对象,编程对象有公开的属性方法或事件,比如COM接口或.NET类库接口。还有基于WEBWebService的编程接口。一般而言,对于DOM,编程接口就表现为可编程对象的编程接口,就是DOM向外发布若干个可编程对象,别的应用程序或者脚本语言可以调用这些可编程对象的公开成员。

    DOM的一个重要特性就是应用程序或者脚本程序能利用它来访问和更新结构化文档。这个意思是说,DOM向外提供若干个可编程对象,这些对象内部使用种种手段,保证它和结构化文档中的某个部分保持对应关系,特别是对象的属性和文档片断的属性保持映射关系。而外部程序获得可编程对象的属性,经过DOM内部的映射关系,实际上就等价于获得某个文档片断的某个属性,外部程序修改可编程对象的属性,经过内部的映射关系,最终导致某个文档片断的属性的修改。因此DOM是应用软件和结构化文档之间的代理,应用软件使用DOM透视出文档的内容,也通过DOM“隔山打牛”的方式修改文档内容。

有效页面

    最后结构化文档处理后,可以形成一种有效页面,也就是结构化文档可以展示在用户界面上。一般的应用程序借助DOM,可以在用户界面上绘制结构化文档的内容。比如WEB浏览器,借助HTML DOM,在用户界面上绘制出HTML文档的样式。一些结构化文档没有用户界面,比如XML文档,但它具有可编程用户界面,其他的应用系统可以使用这个可编程用户界面来获知XML文档中到底有什么内容。

    文档对象模型可以是语言中立的,也就是说跨语言跨平台,比如HTMLXML的文档对象模型,在W3C国际标准组织的努力下,已经是最典型的跨语言跨平台的文档对象模型,我们可以使用任何平台和语言来使用相同的方式和接口来访问XMLHTML,比如无论是Linux下的JAVAWindows下的.NETVB或各种浏览器中的JavaScript,甚至是MS Office 中的VBA,他们访问XML DOM的过程必然是类似的,很容易使用相同的处理流程来实现相同的功能。这样做的好处就是大大的方便程序的移植和各种系统之间交流数据。

    可以这么认为,若文档具有生命,则它在保存在文件时,它就处于休眠状态,就差不多是死的,但一旦被DOM附体,它被唤醒了,就是活的,可以任由应用软件调遣,可以发挥任何应有的功能。

    以上是我个人对文档对象模型的理论认识,接下来说说如何在软件开发中理解文档对象模型。

理解文档对象模型

    文档对象模型是一种规范,在微软.NET框架类库中实现了两种DOMCodeDomXMLDom。名称空间 System.CodeDom下定义了CodeDom,名称空间System.Xml下定义了XML Dom,这里使用大家比较熟悉的XML Dom 来讲解一番。

XmlDom结构研究

    这个图是XML文档和XML对象之间的映射关系图。

    C#发现之旅第十讲 文档对象模型

    大家经过以前的课程的学习,已经掌握了基本的XML语法,因此这里不再详细说明这个XML文档的语法结构了。在这个映射关系图中,我们使用XmlDocument对象来影射整个XML文档;使用XmlDeclaration来影射<?  ?>定义的XML声明,;类似的我们使用XmlElement对象来影射一个XML元素;使用XmlText来影射XML文档中的纯文本数据;使用XmlAttribute来影射XML属性片断;使用XmlComment来影射XML注释。

    经过上述影射,开发者可以通过编程调用各个XML对象来修改XML文档中对应的部分。比如我们调用XmlText类型的Value属性,就能很方便的获得和修改XML文档中的纯文本数据片断。

XmlDocument类型定义了很多以Create开头的函数来创建一个新的Xml对象,比如我们可以使用CreateElement函数创建一个XmlElement对象,然后添加到某个已有的XmlElementChildNodes列表中,这样的操作就相当于向XML文档新增元素的操作;我们也可以删除某个已有的XmlElementChildNodes中的对象,这相当于从XML文档中删除了一个片断。

    通过编程对象和XML文档的映射关系,我们就将操作XML文档的操作转化为对一个个编程对象的操作。我们就能比较方便的使用编程来处理具有复杂语法结构的XML文档。

    考察XmlDocuementXmlElementXmlText等等XML文档组成元素,可以发现它们都是从XmlNode这种类型派生的,XmlNode中定义了Xml对象通用的编程接口,而其他Xml类型都从XmlNode派生的,并根据各自对应的XML片断类型进行了扩展。这样我们可以很方便的使用XmlNode作为强类型来遍历XML文档。

    事实上,名称空间System.Xml下面存在比较复杂的对象继承关系,比如存在这样的派生关系链表XmlNode->XmlLinkedNode->XmlCharacterData->XmlText。为什么要设计如此的长的派生链表,每层应当实现什么样的功能,预留什么样的接口,每层又如何扩展上层类型的成员。所有的这些都是考验开发者的面向对象编程技术的基本功和软件设计思想,因此若一个开发者能理解和设计比较复杂而合理的DOM,则此人必是软件设计高手。

    一般情况下我们进行编程,同一个列表中保存的对象,它们的类型是一样的,可以放心大胆的使用强制类型转换来获得列表中的任意元素。但在XML文档对象类型中,同一个列表中的对象类型可能不一致,无条件的强制类型转换是不可靠的,容易出错,因此强制转换前需要进行类型判断。而且这种现象普遍存在于其他的文档对象模型中,比如HMTLDOM中,一个HTML节点的子节点也存在类似情况,因此针对文档对象模型编程时需要注意这点。但由于所有的Xml对象类型都是从XmlNode上派生的,因此我们可以可靠的使用XmlNode类型来遍历XML文档结构。

     XmlDom中包含了一个以XmlReader为基础的XML文档解析器,我们调用XmlDocumentLoad方法,系统就能从一个文件中加载文本数据并解析,自动构造出一个以XmlDocument为根节点的Xml对象树状结构。XmlDom中还包含了一个以XmlWriter为基础的XML文档书写器,当我们修改了XML对象树状结构后,调用XmlDocumentSave方法就能把修改过的Xml文档保存到一个文件中。这样就完成了对Xml文档的修改。

    如果我们不用XMLDOM,我们如何编程来访问XML文档?很显然,这时的XML文档就是一个字符串,我们需要对这个包含XML内容的字符串进行很复杂的字符串操作,软件开发过程复杂而低效率,XML技术由于难以开发和使用而必然得不到推广。

DOM概念内涵

    经过XMLDOM的研究,我们可以归纳出DOM的一些基本的编程特性:

  1. 所有的文档对象类型都是从一个基础类型派生的,文档对象类型都在基础类型上实现了各种特性。
  2. 每个文档对象都映射了文档中某个片断,修改文档对象就等价于修改文档片断本身。
  3. 文档对象可以有子节点,由此构成一个多层次对象树状结构。
  4. 存在一个顶级对象,用来表示整个文档。可以宏观控制整个文档,也是应用程序访问文档对象树状结构的唯一入口。
  5. 文档对象模型是可编程的,应用程序通过访问文档对象模型来访问结构化文档。
  6. 大部分类型的DOM可以将整个文档结构保存到一个文件中,也可以从一个文件中再现整个文档结构。这算对象序列化。但也可能有例外。

    我们可以发现,其他的DOM都基本上实现了上述编程特性,比如名称空间System.CodeDom支持下的CodeDomHTML DOM

DOM概念外延

    XMLDOM是严谨的DOM的编程特性,但我们在实际开发应用中,可以根据各种需要进行简化,开发各种不够严谨的DOM 比如在微软.NET标准库中,存在着许多不严谨的DOM结构。比如名称空间System.IO下的FileSystemInfo FileInfoDirectoryInfo组成了文件系统DOM;名称空间System.Reflection下的类型组成了以Assembly为根节点的程序集DOM;名称空间System.Windows.Forms下的类型组成了以Form为文档对象,以Control为基础类型的WinFormDOM;名称空间System.Web.UI及其子名称空间下的类型组成了以Page为文档对象,以Control为基础类型的ASP.NET页面DOM。可以说,一般的对象树状结构都可以看作不严谨的DOM结构。

    我们学习了XMLDOM后,就可以模仿着设计自己的DOM,在开源网站 http://sourceforge.net 上,使用关键字 DOM 进行查找,会找出很多开源项目,这些开源项目大多都和各种各样的DOM有关系。

    文档就是数据,DOM处理文档,实际上就是处理数据,因此更进一步,我们开发开发各种应用系统中,都可以借鉴一下DOM的设计思想,比如开发WinFormASP.NET中,这些用户界面控件时也可以看作DOM。做电子病历时,可以设计出电子病历文档对象模型,做客户关系管理系统时,可以设计出客户文档对象模型。总之做XX系统时,可以考虑设计出XX文档对象模型。

小结

    文档对象模型是一种比较复杂的软件设计技术,但它功能强大,层次分明,逻辑清晰,好的文档对象模型合情合理,符合人们想当然的思想,是业务逻辑数据的高度抽象。大家应当好好学习,多多研究学习学习,这对提高软件设计能力,树立自己的面向对象的编程思想都大有好处。

你可能感兴趣的:(C#)