序列化、TrAX 和數據綁定:哪種方法更適合您?
級別: 初級
Brett D. McLaughlin, Sr.
(
brett@newInstance.com
), 作家兼編輯, O'Reilly Media, Inc.
2007 年 10 月 22 日
使用 XML 可以實現各種有趣的功能,但是如果無法將其持久化保存到文件中,那么一切都將是徒勞而已。Brett McLaughlin 將討論實現 XML 持久化存儲的各種不同的技巧,并分別比較其優點和缺點。<!--START RESERVED FOR FUTURE USE INCLUDE FILES--><!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters --><!--END RESERVED FOR FUTURE USE INCLUDE FILES-->
XML 是一種偉大的數據格式 — 顯而易見,整個 IBM developerWorks 專區都在專注于研究這個主題。2007 年,關于 XML 的討論多半是 Web 服務,或者 XML 和 Java? 對象之間的轉換,或者讀取 XML 配置文件,或者甚至是使用 XML 格式的數據庫代替關系或面向對象的數據庫。
目前,我們還沒有聽到有人在談論如何將所使用的內存表示 — DOM、JDOM 等等 — 中的 XML 保存到靜態文件中去,并在其中填滿尖括號和引號。坦白的說,獲取 XML 并將其寫入文件算不上激動人心 — 不過這卻是有必要的。試問,編程領域若永遠都不能將 XML 持久化存儲到文件中會是怎樣一番情境?您可以在內存中創建 XML 文檔,并且甚至可以將其發送給應用程序中的其他組件(或者其他應用程序的組件);但是卻無法存儲這些 XML。您可以使用 XML 存儲配置數據,同時編寫各種工具來讀取該數據,但是實際上卻無法存儲配置文件本身。您甚至還可以讀取 SOAP 信封的內容 — 但是卻無法將這些內容存儲在磁盤上,以供應用程序離線時使用。
顯然,將 XML 寫入文件非常重要。事實上,如果只是想將數據停留在內存中并且不需要擔心數據的存儲方式,您可以想象得到不需要存儲 XML 的編程世界是什么樣子,毫無疑問這在如今的編程領域中是不可能的。
因此,問題十分簡單:如何將 XML 持久化存儲到文件中去?我假定本文的讀者需要自己處理這一任務。換句話說,如果您在編程中從未涉及到持久化存儲 XML,那么本文將使您受益匪淺。(但是,了解如何執行這些任務會更利于對文章的理解)對于那些確實關注持久性存儲的人,我總結了三種相當常用的主流方法:
- 使用 DOM 和 JDOM 之類的 API 將 XML 數據結構直接寫入文件
- 使用 Transformation API for XML (TrAX) 和標識轉換(identity transformation)持久化存儲您的 XML
- 使用 JAXB 之類的較高級別的 API 處理持久化存儲
如果使用一個或多個 API 讀取 XML,那么很明顯的一個方法就是使用與之相同的 API 將 XML 寫入文件。比如說,如果您使用 JDOM API 和一個 JDOM
Document
對象操作 XML,那么可以編寫以下代碼:
XMLOutputter outputter = new XMLOutputter(); outputter.setFormat(Format.getPrettyFormat()); outputter.output(myDocument, new FileWriter("outputFile.xml")); |
與此類似,在 DOM Level 3 中可以使用新的 Load 和 Save API:
DOMWriter writer = new org.apache.xml.serialize.XMLSerializer(); writer.setNewLine("\r\n"); writer.setEncoding("UTF-8"); writer.writeNode(new FileOutputStream(new File("outputFile.xml")), myDocument); |
注意,使用新 DOM API 的方法多種多樣,其中有一些具有較低的供應商獨立性。上面的示例代碼中含有一個特定于 Xerces 的類,但是其他方法不會像它一樣與某個特定的供應商類緊密綁定在一起。從學習的角度來說,那些方法都不夠直觀,因此我保留了特定于供應商的代碼。
這種方法的優勢是可以相當直接地與您的 API 進行交互,從而實現良好和全面的控制。您可以設置新行,您可以處理首行縮進,您可以控制輸出文件的各個方面。此外,還可以盡可能拉近您與文件之間的距離;即沒有包裝器 API 也沒有間接層,您可以直接編寫 XML。如果您對 JDOM 和 DOM 比較熟悉,那么它們將是輸出 XML 的不二選擇。
任何方法有優點就必然有缺點。雖然您可以全面地控制輸出的各種細節,但是如果輸出配置不當則會導致諸多混亂的問題。換行錯誤,編寫錯誤和 I/O 錯誤都是這種方法產生的一些常用問題。除此之外,您還工作于一個非常低的層次,并沒有大量的輔助工具(JDOM 在
Format.getPrettyFormat()
和
Format.getCompactFormat()
方法中提供了一些:而 DOM 幾乎是一毛不拔)。這意味著您必須要理解編碼、輸出格式、縮進格式,以及對輸出有影響的任何內容。
另一個流行的選擇是使用 TrAX 和標識轉換。TrAX 是 Transformation API for XML 的縮寫,它現在是 JAXP 的一部分,而 Java 平臺的每一個發行版中都含有 JAXP(除了 Micro Edition)。TrAX 允許您使用 XSL 樣式表對 XML 進行轉換。由于 XML 經常需要結合 SAX 和 DOM 一起使用,因此 TrAX 可以接收 SAX 事件和 DOM
Document
作為輸入,并能夠輕易地產生輸出文件。此外,TrAX 還可以輕松地對這些格式進行相互轉換。比如說,您可以使用以 DOM 表示的 XML 文檔作為輸入,并對它進行轉換,然后再將輸出發送到文件中。或者您也可以讀取文件中的內容,并對它進行轉換操作,然后再將結果文檔存儲到 DOM
Document
中。
這種方法的另外一個作用是,您可以使用一個不含任何文檔操作的樣式表,并使用某種格式作為輸入,然后將這種格式輸出為任意其他的格式。使用不具轉換功能的樣式表 — 實際上指不執行任何操作但回轉所接收的輸入內容的樣式表 — 稱作
標識轉換(identity transformation)
。因此您可以從文件中獲得文檔,然后應用標識轉換,最終在 DOM
Document
中生成相同的 XML。如果您采用相反的方式 — 從 DOM 到文件 — 那么實際上可以實現持久化存儲 XML。這種方法類似于以下過程:
Source domSource = new DOMSource(myDOMDocument); Result fileResult = new StreamResult(new File("outputFile.xml")); TransformerFactory factory = TransformerFactory.newInstance(); Transformer transformer = factory.newTransformer(); transformer.transform(domSource, fileResult); |
此處,DOM 文檔中的 XML 最終轉換為了一個 outputFile.xml 文件。
TrAX 最大的優點就是易于使用。擁有 Java 平臺訪問權的任何人都可以使用它,并且不需要對 SAX 或 DOM 有深入的了解。因此,這對于只有基本 XML 編程技能的開發人員來說是一個極具吸引力的選擇。此外,不熟悉 SAX 或 DOM 的初級程序員也可以使用 TrAX — 只需要了解 10 到 20 行函數代碼 — 快速將 XML 持久化存儲到文件中,或者甚至是 DOM
Document
s 和 SAX 事件中。
使用 TrAX 的最大缺點是:雖然可以很容易執行標識轉換,但是處理輸出細節卻需要很高的技巧。換行、編碼、空格和縮進 — 所有這些都是 TrAX 提供的配置選項,但是它并不像使用 DOM 或 JDOM 直接配置那樣簡單。在大多數情況下,TrAX 為普通任務所提供的易用性常常伴隨著較低的靈活性,至少不能開箱即用。
注意:在輸出方面,使用 TrAX 和標記轉換幾乎可以實現 JDOM 或 DOM 可以完成的所有任務;只是不夠簡單或直觀而已。您只需要了解一些 XSLT 和 TrAX API 的知識,這兩者與所執行的實際輸出任務并沒有密切的聯系。
將 XML 轉換為靜態格式的另一種方法 — 特別是您希望這種格式是位于磁盤上的文件 — 是使用 JAXB 之類的數據綁定 API。雖然通常人們不會考慮使用數據綁定來實現持久化存儲,但是它可以有效地實現:讀取內存中表示的 XML 文檔并將其寫入文件。
我沒有太多時間詳細介紹數據綁定的概念(您可以在 developerWorks 網站上閱讀一些這方面的文章);下面這段簡短的代碼使用了 JAXB 方式的數據綁定實現持久性存儲:
FileOutputStream stream = new FileOutputStream("outputFile.xml"); Marshaller marshaller = myJaxbContext.createMarshaller(); marshaller.marshal(myJavaObject, stream); |
您可以設置一些選項,比如說輸出文件的編寫,所有設置都在
Marshaller
對象中。事實上,JAXB 在設置輸出屬性方面的靈活性與前面兩種方法是不相上下的。
JAXB 的最大優點就是:它具有極大的易用性,特別是對于一些簡單的任務。同時,雖然人們仍然認為 SAX 和 DOM 是主流方法(至少在普通 Java 編程領域是如此),但是 JAXB 對于使用 Java 語言的任何人來說都是家常便飯。這意味著我們可以找到更多 JAXB 方面的文章和教程(2007 發布的一篇調查文章將證實這一點)。此外,對 JAXB 的支持也要優于 DOM 和 SAX。SAX 和 DOM 是 Java 平臺標準版本的一部分,而 JAXB 在很大程度上是由 Sun Microsystems, Inc. 發明的。因此,JAXB 的支持稍高一籌也不足為奇了。
此外,使用 JAXB 基本不需要掌握任何 XML 知識。您可以操作普通 Java 對象 — 不是特定于 XML 的對象,如 DOM 的
Node
或
Text
接口 — 并將這些對象直接表示為 XML。這意味著較低的入門門檻,并且任何人都希望可以在很短的時間內掌握它,尤其是當老板在辦公室對著您頤指氣使的時候。
有其利必有其弊。JAXB 的不足之外在于我們不需要過多了解 XML 便可以使用它。這看上去似乎是我剛剛提到的優點,但是它同時也潛藏著缺點。對 XML 的了解越少,要合理使用 JAXB 就愈加顯得困難。您可以輕松地生成一個 XML 文件,但是卻會發現這個文件的格式并不可用,或者它只含有一部分需要持久化存儲的對象,或者其中的對象與您所編制的對象并不相同。
所有這些常常會導致開發人員將 JAXB 放在一旁,或者大量學習 XML、SAX 和 DOM 方面的知識。這樣一來,許多開發人員都會繼續使用 SAX 和 DOM 實現持久性存儲,而使用 JAXB 只是為實現其最簡單的功能:在 XML 和 Java 對象之間相互轉換。
我特意將最后一種選擇留給大家思考:將 XML 作為一系列比特、節點和字符串直接寫入
FileOutputStream
或
FileWriter
。毫無疑問,這種方法可以將 XML 寫入文件,并且這種方法的采用也相當多;但是在本例中,持久化存儲已有 XML 數據并沒有從
非 XML
格式的數據中創建 XML 那么頻繁。您可以認出這種代碼,它們通常類似于以下形式:
String xmlString = setupXMLBuffer( new StringBuffer("<firstName>") .append(customer.firstName) .append("</firstName>") .append("<lastName>") .append(customer.lastName) .append("</lastName>") // etc... .toString() ); bufferedWriter.write(xmlString); // other file I/O code |
這段代碼并沒有任何錯誤;我們只是將數據持久化存儲于 XML 中,所有操作都在一步之內完成。因此,關于如何持久化存儲數據,以及哪種方式是最佳的,這些問題都無關緊要。寫入數據并將其存入 XML 的操作是無法分開的,因此再多的討論也無濟于事。
我們應該如何處理 XML 持久性存儲呢?并沒有完全正確的答案。也就是說,Java 和 XML 開發人員都需要經過仔細討論才能做出選擇。您趨向于使用一致的方法解決通用問題嗎?有沒有一種持久性存儲方法可以在磁盤上生成易于讀取、使用并能發送給其他應用程序的 XML 文檔呢?
對于大多數技巧,我的觀點是人們應該重點關注這些技巧是否能夠真正奏效。如果您發現某個技巧更適用于其他人,那么您應該能夠提高自己的編程技巧 — 至少,這是基本思想!因此,請花幾分鐘逛逛 developerWorks 網站的 Java 和 XML 論壇(請參閱 參考資料 獲得訪問鏈接),并讓我們知道您所使用的持久性存儲方法。如果需要基于一些特定的功能,也請告訴我們。我希望能在論壇中見到您的身影。
學習
-
您可以參閱本文在 developerWorks 全球網站上的
英文原文
。
-
Sun's online
Java 和 XML 總部
:說到 JAXP,您將發現沒有比 Sun 公司的在線頁面更佳的地方了。
-
核 心 API 文檔
用于 Java 5.0 技術:獲取有關 JAXP JavaDoc 的信息,現在已集成在這一規范中。
-
SAX Web 站點
:找到更多有關 JAXP 的 API。開始了解用于 Java 環境的 SAX 2。
-
W3C Web 站點
:有關 SAX 支持的 XML 的另一看法,請了解 DOM。
-
Apache Xerces
解析器:了解 Sun 在他們的 JDK 5.0 實現中所使用的解析器。
-
XML 入門
(Doug Tidwell,developerWorks,2002 年 11 月):想了解 XML 的基礎知識嗎?請閱讀這篇教程和一些
其他培訓服務
,其中介紹的都是最基本的內容。
- IBM XML 認證 :看看如何才能成為一名 IBM 認證的 XML 及相關技術的開發人員。
討論
-
參與論壇討論
。
-
developerWorks blogs
:查閱這些 blog 并參與
developerWorks 社區
。
-
developerWorks XML 專區:分享您的想法:
閱讀本文之后,請在此論壇上發表您的評論和想法。該論壇由 XML 專區的編輯管理,他們隨時歡迎您提出寶貴的意見。
Brett McLaughlin 從 Logo 時代就開始使用計算機。(還記得那個小三角嗎?)近年來他已經成為 Java 技術和 XML 社區最知名的作家和程序員之一。他曾經在 Nextel Communications 實現過復雜的企業系統,在 Lutris Technologies 編寫應用程序服務器,最近在 O'Reilly Media, Inc. 繼續撰寫和編輯這方面的圖書。在他的新書 Head Rush Ajax 中,Brett 與暢銷書作家 Eric 及 Beth Freeman 為 Ajax 帶來了獲獎的創新方法 Head First。他的上一本書 Java 1.5 Tiger: A Developer's Notebook 是第一本可獲得的關于最新版本 Java 技術的書籍,而他的經典著作 Java and XML 仍然是在 Java 語言中使用 XML 技術的權威圖書。
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
