更好的創建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編寫器,你能超越標示到達一個面向節點的層面,其間不僅僅是字節在連續內存塊裡的堆砌,你還能夠結合節點和實體來創建理想的結構描述和信息集。