日期:2012-09-12  浏览次数:20446 次

在.NET里更好的创建XML文档

作者: BUILDER.COM

创建XML文档不是一件特别困难的事,但是却是很让人乏味的,尤其是在你必须总是创建类型相似的文档的时候。使用代码来处理这些重复性的任务是行得通的。但是利用机器自动编程来创建XML文档到底有多难或者有多容易?这取决于你所使用的方法。

编写标示语言是令人乏味的任务
  
对于这个问题过于简单化的回答是:创建XML文档和创建文本文档是一样简单的。毕竟,XML文档只是一个文本文档。但是一个更加现实的回答是:编写标示语言可能会是令人头疼的,因为你不得不顾及引号的丢失、标签和注意大小写敏感。换句话说,你不得不去承担编写标记语言的负担。

而且,XML文档从本质上说是分等级的,这意味着你要逐层深入地来编写——进行基于堆栈的操作。在编写的时候,你要打开标签,编辑属性,增加子层,但是需要不断跟踪所打开的最里层元素。根据XML的句法,你必须为遵照不重叠规则而首先关掉最里层元素。

以DOM的方式编写XML
XML文档对象模型(XML DOM)允许你用合成法创建XML文档。你使用一组制造方法(CreateElement、CreateComment、CreateProcessingInstruction以及其他)来创建节点对象的实例,然后把它们相关联起来,构成一个树形结构。但是,这些方法是在内存里创建文档的。那么你如何保持一个新文档呢?

直到W3C XML DOM第二层为止,官方的API还没有提供对I/O的支持。一对Load和Save方法将会成为官方标准XML DOM第三层所推荐的方法的一部分,当前第三层的制定正在其最后阶段。缺乏对I/O的支持倒不一定代表着它用于真实世界里的应用程序时会有问题,但是要记住:你现在对类似XML DOM的结构所使用的任何Save方法都是对W3C DOM专有的扩展。微软的XML核心服务库(MSXML)从第一版开始就对文档的持久性提供了支持。

XML DOM关键性的优势是提供了一个抽象层,使你这个可怜程序员能够免于对付结构严谨的XML的各种限制。其主旨是由你定义结构,而由框架来负责内容到XML文档翻译的细节。XML DOM方法的不足之处是其内存占用的问题,它会随着文档内容的增加而变大。在保存到存储介质上以前,文档是完全保留在内存里的。正如你可以猜到的,如果你正在处理大型文档,从性能的角度来看,这不是一个最佳的方法。


.NET的流模型
微软的.NET Framework提供了一个更加多产的、有效,甚至更加典雅的方法来让程序自动编写XML代码。在XML编写器组件的基础上,这种方法代表着我在前一篇文章里所讨论的基于流的剖析模型方法所对应的编写方法。

XML编写器代表着一个组件,它提供了把XML数据输出到流或文件快速和只能向前的方法。更重要的是,XML编写器保证了——从设计上——它所生成的XML数据都遵从于W3C XML 1.0和命名空间所推荐的规则。

XML编写器和XML DOM对象是不同的,因为前者所缓冲的信息要少得多。XML编写器并不在内存里表示正在编辑的或者已创建的文档。XML编写器只是一个简单的编写工具,它只在内部汇集各种已创建的元素所产生的XML文本。与XML DOM不同,编写器内部缓存里的数据能在任何时候被送到物理流里——本地磁盘文件、远程的URL或者流对象。

从某种程度上说,你可以把XML编写器组件看作是一个建立在数据流顶部的抽象API。XML并没有方法来编写字符串或者一组字节,它提供的方法是用来编写XML元素和属性的。让我们来看个实例。

XML目录列表
假设你必须编写一个要把目录列表灌入XML的类,在Listing A里的代码显示了这一过程应该如何进行。这段代码创建了一个新的XmlTextWriter,并开始添加元素。使用DirectoryInfo类及其GetDirectories方法能够取回目录信息。

XmlTextWriter类是你用来在磁盘文件里创建一个XML文档的工具。传递给类构造器的空变元显示的是用于文档的缺省编码结构描述(UTF-8)。Formatting属性设置的是文档每行自动缩进的大小。

WriteStartDocument和WriteEndDocument是给文档的编写加括号的。前一个方法将XML版本和编码信息插入到标准XML初构里。后一个方法关闭掉所有的搁置元素,并把编写器对象的内部状态复位。在这两个调用之间,你可以使用其他的WriteXXX方法来创建专门的XML元素,例如节点、属性和注解。

元素节点是通过连续调用WriteStartElement和WriteEndElement来包装的。WriteStartElement对应于打开标签;WriteEndElement对应于关闭标签。当前打开元素(堆栈的顶部)的属性是用WriteAttributeString方法来设置的。最后,WriteString把纯文本插入到元素节点的主体里。

缺省地,文档只有在WriteEndDocument方法被调用的时候才被送到底层的流里。但是,如果你要编写一个大型文档,Flush方法能让你优化内存的占用。Flush能在文档创建过程中的任何时候被调用,它会清空内部缓存,更新底层的流。底层的流在XML编写器完成编写以前都是锁定的。

XML编写器是一个很有用的帮助工具,但是它并不是完美的。它不把内容同结构描述或者DTD文档进行比较查验,也不更正你所忽略的错误信息。例如,如果你把同样的属性添加了两次,它不会提示其错误。

超越标示
阅读器和编写器是.NET Framework里进行每项XML I/O操作的基础。使用XML阅读器,你可以以一种更划算的方法剖析文档。使用XML编写器,你能超越标示到达一个面向节点的层面,其间不仅仅是字节在连续内存块里的堆砌,你还能够结合节点和实体来创建理想的结构描述和信息集。