從XML到Java代碼的數據綁定之一

        在這個由四部分組成的系列文章的第一部分,我們將弄清什麼是數據綁定,與在 Java 應用程序中處理 XML 數據的其它方法相比它有什麼優勢,以及如何開始使用它。這一部分將考查爲什麼使用數據綁定,以及如何爲各種約束建立模型,使 XML 文檔能轉換成 Java 對象。同時還涵蓋用於生成數據綁定類的輸入和輸出。
  
  您希望在您的 Java 應用程序中使用 XML 嗎?那麼好,同成千上萬的其他人一起上這條船吧。當您深入瞭解 XML 以後,也許您會發現 DOM 和 SAX API(請參閱參考資料)不過是唬人的東西。您可能認爲肯定存在某種簡單方法可以取得 XML 文檔,並通過 Java 應用程序訪問它,對嗎?不必通過回調或複雜的樹狀結構,而是使用像 setOwner(Stringowner) 和 int getNumOrders() 這樣的方法,對嗎?如果您曾經沿着這一思路考慮問題,那麼數據綁定就是您要尋找的解決方案。
  
  分析各種選擇
  當今各種 XML 和 XML 主義正氾濫成災(XSL、RDF、命名空間、RSS、XML Schema、XSLT...),您可能認爲現在會有很多方法去訪問 Java 應用程序中的 XML 數據。令人驚訝的是,如果您尋根究底,實際只存在三種訪問 XML 數據的方法。沒錯 -- 只有三種方法,其中的一種還是最近隨一種新的 Java API 纔出現的。
  
  應該這樣來看待這一問題:選擇範圍小使您更易於選出適合於您的方法。
  
  回調
  回調是作爲一種事件驅動模型工作的。當分析 XML 文檔時,某些事件 -- 如文檔的起始和某個元素中的字符數據的起始 -- 將觸發回調方法。通過使用執行邏輯所需的數據,您可以實現這些事件的 Java 代碼。要弄清這種方法不能全靠直覺;開發人員通常要花費一段時間來理解和掌握回調模型的使用。SAX,用於 XML 的一種簡單 API,是這種 XML 使用方法的事實上的標準。
  
  
  更常見、更流行的是這種 API,它們取得一個 XML 文檔,然後創建數據的樹狀結構。XML 文檔成爲樹首,充當一種容器。它有若干子級,如根元素。根元素又有其附加的子級,依此類推,直到(在某種意義上)獲得 XML 數據的一幅圖爲止。因爲幾乎每個大學生在某個階段肯定都處理過樹狀結構,所以這就可用作表示 XML 數據的一種非常直觀的方法。
  
  用於 XML 文檔樹狀表示的最流行的 API 就是 W3C 的推薦標準,即文檔對象模型 (DOM)。一種更新的 API,JDOM (這不是首字母縮寫詞)最近也正一直在推廣並流行開來。(雖然這個方案是我和 Jason Hunter 建立的,但我還得說實話。)另外,DOM 和 JDOM 都是 Spinnaker 方案設計的基本要求,Spinnaker 是一種新的 XML 分析器,它作爲 Apache XML 方案的一部分正在開發之中。
  
  雖然樹狀 API 看起來比事件驅動的 SAX 更易於使用,但它們並不總是合適的。非常大的文檔可能需要大量的內存(尤其是使用 DOM 時);當對樹結構執行轉換 (XSLT) 時,系統可能停止運轉甚至徹底崩潰。雖然更新的 API(如 JDOM)能處理這些問題,但如果您必須處理極大量的數據,它們仍將是一個問題。並且,有時開發人員寧願將 XML 文檔中的數據建模爲一個簡單的帶有值的讀寫方法的 Java 對象,而不用樹狀模型工作。例如,開發人員會寧願不去訪問名爲 skuNumber 的子節點並設置該節點的文本值,而只想調用 setSkuNumber("mySKU") 並繼續進行。
  
  用 Java 代碼訪問 XML 數據的最新方法要依賴於一套新的 Java 方法和相關的 API,這些 API 仍在開發之中。數據綁定是由 Sun 構建的一種“Java 規範要求”(JSR-031,見參考資料),它設計用於使 Java 對象綁定到 XML 文檔更加方便,這樣就使一種格式能夠容易地轉換爲另一種格式,反之亦然。綁定引用一個具有讀寫方法的 Java 對象,讀寫方法都會影響到底層的 XML 文檔,並且也都直接映射爲 XML 文檔中的元素及特徵的名稱。當您進入到本系列文章下一部分中的某些細節時,這一說明會更有意義,但在目前,只說一點就夠了:這樣做使 XML 文檔特徵 name 能夠通過一個稱爲 setName() 的方法,來更改它的值,就像我上面暗示的那樣。
  
  數據綁定
  這種訪問方式正在得到普及,並且當在 XML 文檔中存儲配置信息時特別有用。許多開發人員發現,它非常便於直接訪問所需的參數,而無須使用更復雜的樹狀結構。雖然這種訪問對於文檔轉換或消息傳送沒有什麼用處,但它對於簡單數據處理是極其方便的。它是我們在本文及本系列文章中關注的第三種使用 XML 的方法。
  
  (當然,任何方法隨後都會引出一系列新的術語,所以請查看術語解釋以瞭解這些新的行話。)
  
  是否任何 XML 文檔都可以轉換爲 Java 對象?還是僅有某些類型的 XML 文檔纔可以?問得好!您很可能只希望將滿足一組約束條件的文檔轉換爲 Java 對象。這與定義 Java 接口的方法類似:您確保只實例化和使用適應該接口的對象,允許就如何操作該對象作出假定。同樣,您只允許將滿足一組約束條件的 XML 對象轉換成 Java 對象;這使您能夠按希望的方式來使用所創建的對象。
  
  約束數據
  在研究代碼之前,您需要回答幾個有關如何表示 XML 數據的問題。這是數據綁定的最具挑戰性的方面之一。是爲每個文檔創建一個新類,還是創建某個現有類的一個實例?您要使用哪個現有類?並且最重要的是,您正在處理的文檔是否適宜轉換爲 Java 對象?
  
  那是一大堆問題,但您將在這裏找到全部答案。將這些問題看作一系列決策點,一系列選擇。首先,您必須確定您能否從該 XML 文檔創建 Java 對象(如前面所討論的那樣)。如果能,您就要決定轉換應該以新 Java 類的形式出現,還是僅以現有類的一個實例的形式出現。最後,如果選擇了現有類,那麼使用哪個類呢?結果就是各種各樣的決策樹。
  
  如果我們考察清單 1 中所示的一個示例 XML 文檔,然後再來處理這些問題,則決策樹的意義就更加清楚了。此示例文檔表示 Enhydra Application Server 中某個服務(具體說就是一個 web 容器)的配置。
  
  清單 1. 一個用於配置 Enhydra 中的 web 容器的 XML 文檔 <?
xml version="1.0"?>
  
  <webServiceConfiguration version="1.0" name="My Web Container" >
  
  <port number="80" protocol="http" protected="false" />
  
  <document root="/usr/local/enhydra/html" index="*.html,*.
xml" error="error.html" />
  
  </webServiceConfiguration>
  
  此配置文檔包含有關服務本身的版本和名稱的信息,以及幾個嵌套的項目,每個項目都表示有關該 web 容器服務的一些附加信息。它給出了有關端口的詳細信息(包括端口號、協議和安全性),也給出了文檔服務信息(包括文檔根、用於索引頁的默認擴展名以及錯誤頁)。所有這些合在一起,就是配置一個新的 web 容器服務所需的全部信息。
  
  記住這個示例,您就可以開始回答數據表示的各個問題了。
  
  是否適合轉換?
  絕對適合!只要看一看清單 1 中的 XML 文檔就會發現,它表示一個對象(總體配置對象),具有若干特徵或變量。其中某些變量又是另外的對象(端口和文檔),這些對象又具有它們自己的特徵。實際上,這是適合轉換爲 Java 對象的 XML 文檔的一個極好例子。爲了進一步保證此對象是可用的,稍後我將向您展示一種方法來約束文檔中的數據。但是,還是先讓我們繼續沿着決策樹往下走。
  
  轉換成類還是實例?
  解決適宜性問題以後,現在就可以作出決定,是將每個 XML 配置文檔都變爲一個全新的 Java 類呢,還是簡單地將其變爲某個現有類的一個新實例。換句話說,就是到底應該生成新代碼,還是利用現有的代碼。照這樣來看,這就變成了一個簡單的可重用性問題。更容易且更明智的做法是,爲每個 XML 文檔生成現有類的新實例。如果您一定要嘗試一下從每個文檔創建一個新的 Java 類,則得到的各個類之間可能沒有兼容性 -- 即兩個完全相同的文檔可能導致兩個不同的 Java 類!
  
  不用這個可能引起混亂的方法,您可以採用一組 XML 約束條件(由一個 DTD 或 XML 方案表示,將在下面講述),並根據這些約束條件來生成一個 Java 類(或多個類,根據需要)。這個生成的類將表示符合這些約束條件的任何 XML 文檔;這些 XML 文檔中的每一個都將被解包到生成的類的一個實例中。在這種情況下,就可以爲表示 web 服務配置的文檔定義約束條件。這些約束條件將被映射爲一個 Java 類,我們將稱之爲 WebServiceConfiguration。然後您就可以獲得任何一種表示特定 web 服務配置的 XML 文檔,並假定此文檔符合我們的約束條件,由它而創建出前面生成的類的一個實例。這將允許應用程序將不同的 XML 文檔用作相同類型的對象,只要這些文檔中的數據對於該對象設計時要達到目的來說是有效的即可。
  
  新類還是現有的類?
  現在您也已經有條件回答下一個問題了:您希望創建一個現有類即 WebServiceConfiguration 類的一個實例。剩下需要弄清的全部事情是,這個類是如何預先生成的。所以,現在請將您的注意力集中在這樣一個問題上:如何獲得一組約束條件,用 XML 實現它們,並保證文檔符合這些約束?再一個問題就是,您如何再從這些約束條件生成一個可重用的 Java 類?
  
  利用文檔約束條件
  既然您知道此文檔將轉換成一個 Java 實例,這就產生了另一個問題:要考慮到必須以某種方式保證可將此文檔正確地解包到一個選定的 Java 類中。缺少變量或數據類型不正確都可能導致在解包過程中出錯 -- 或者甚至在客戶機訪問配置錯誤的容器時出現運行時異常。
  
  最好的情況是,在實際的解包過程開始之前,文檔的作者能夠保證,配置文檔對於他們選擇用來表示數據的類是“合法的”。
發佈了13 篇原創文章 · 獲贊 4 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章