您好,登錄后才能下訂單哦!
本數(shù)據(jù)綁定系列的第三部分演示了如何使用“JSR-031:數(shù)據(jù)綁定,Sun 數(shù)據(jù)綁定規(guī)范申請”中指定的方法,將 XML 元素和屬性轉(zhuǎn)換成 Java 對象。這部分主要講述從數(shù)據(jù)的 XML 表示移到應(yīng)用程序代碼易于使用的 Java 實例。第三部分論及通過將 XML 文檔中的嵌套元素取消編組成 Java 對象、測試和用某些實際示例來使用新的工具。
本系列的目標是演示如何將 XML 元素轉(zhuǎn)換成 Java 對象,然后可以使用 Java 語言 accessor 和 mutator 方法直接處理 XML 數(shù)據(jù)。 第一部分比較了數(shù)據(jù)綁定和 Java 應(yīng)用程序中其它處理 XML 數(shù)據(jù)的方法,分析了設(shè)計決策,還定義了示例 Web 服務(wù)配置文檔的 XML 模式。 第二部分說明了如何從 XML 模式生成接口和實現(xiàn),以便符合 XML 模式的 XML 文檔可以轉(zhuǎn)換成這些生成類的實例。
在第三部分(共四部分)中,將完成基礎(chǔ)知識的講解,并且描述了如何精心設(shè)計代碼以執(zhí)行取消編組,取消編組將完成將 XML 轉(zhuǎn)換成 Java 對象的過程。執(zhí)行了取消編組后,可以使用測試類(已包括在內(nèi))來檢查是否所有部分都已正確組合在一起。本系列的每一部分都建立在其它部分的基礎(chǔ)之上,所以如果您還沒有看過第一和第二部分,您也許會看不懂本文中的一些描述。如果要回顧專門的詞匯表,請參閱 術(shù)語解釋側(cè)欄。
使用第一部分中為 WebServiceConfiguration 定義的 XML 模式(請參閱 更新版本 )和第二部分中的接口,即將創(chuàng)建為配置數(shù)據(jù)的特定實例提供數(shù)據(jù)的 XML 文檔。任何符合模式的 XML 文檔都可以編組成 Java 對象。這些對象應(yīng)該是使用 SchemaMapper 類生成的類的實例。當然,最終結(jié)果就是數(shù)據(jù)綁定。
制作 XML 實例文檔
創(chuàng)建符合模式的 XML 文檔 -- 通常叫做 XML 實例-- 很簡單。文檔必須只提供與模式中定義的約束相匹配的數(shù)據(jù)值,如清單 1 所示。
清單 1. 符合示例 XML 模式的 XML 實例文檔
清單 1 中的示例完整地顯示了 WebServiceConfiguration 的實例。實例文檔包括了兩個名稱空間聲明。第一個是缺省名稱空間聲明,請參考 http://www.enhydra.org。這表示所有沒有前綴的元素會分配到此名稱空間。雖然,在本示例中不需要聲明缺省名稱空間,它還給予了文檔一些身份。這個缺省名稱空間有助于將該文檔與其它有相似或等同元素名稱的 XML 文檔區(qū)分出來。
定義的另一個名稱空間分配給 xsi 前綴,所以帶該前綴的所有元素都分配到此名稱空間。它 (http://www.w3.org/1999/XMLSchema/instance) 引用“XML 模式實例規(guī)范”的 URI。該規(guī)范依次定義了 XML 文檔如何引用文檔符合的 XML 模式。最后, schemaLocation 屬性引用 XML 模式。該屬性的第一個變量是受到約束的名稱空間(示例缺省名稱空間,它包括文檔中的每個元素)。第二個變量,用空格與第一個變量分開,引用 XML 模式的實際位置。本例中,模式 configuration.xsd 是一個本地文件,它與文檔在同一個目錄中。也可以通過使用 URL 來引用網(wǎng)絡(luò)上任意位置的模式。
在缺省名稱空間中,附加屬性(因為它們沒有前綴)定義了版本 (1.1) 和名稱 (Unsecured Web Listener)。
接著,聲明了模式中的 Port 對象,并定義了它的數(shù)據(jù):端口號為 80,協(xié)議是 http。正確取消編組成 Java 代碼后,該文檔就變成了 WebServiceConfigurationImpl類的實例。然后,Java 代碼可以使用本系列第二部分中設(shè)計的接口 WebServiceConfiguration,以使用基本 XML 文檔中的數(shù)據(jù)。(請注意,可能會在應(yīng)用程序中執(zhí)行驗證,如 模式驗證側(cè)欄中所概述的。)
模式驗證
較新的 XML 語法分析器,如 Apache Xerces 語法分析器的當前發(fā)行版,允許對 XML 實例文檔執(zhí)行模式驗證。驗證允許在程序格式上確保 XML 文檔符合它引用的 XML 模式。請與語法分析器供應(yīng)商聯(lián)系或參考文檔,以確定語法分析器是否支持模式驗證,其驗證范圍,以及如何打開驗證。
打開前門
正式開始之前,需要提供入口點以取消編組 XML 文檔,該文檔作為返回 Java 對象的方法的輸入。(由于您會憶起,本例中取消編組的結(jié)果只是 Java 對象。)然后,該對象可以轉(zhuǎn)換成適當?shù)慕涌冢鋵?,您已?jīng)生成了該接口(在本系列第二部分中)。
對于示例 SchemaMapper 類,允許傳入 URL 是最有意義的。由于可以使用網(wǎng)絡(luò)資源作為輸入,而不是只允許文件名,這就提供了更多選擇。知道了這一點后,下一步就從 URL 創(chuàng)建 JDOM 文檔對象 ( org.jdom.Document ),然后處理文檔。請查看清單 2 中執(zhí)行該操作的代碼。
清單 2. 將字符串映射成 Java 指定的類型
/** ** This method is the public entry point for unmarshalling an object from* an XML instance document. ** * @param instanceURL URL for the instance document.* @return Object - the created Java Object, or * null if problems occur in a waythat does not * generate an Exception. * @throws IOException when errors in binding occur.*/ public static Object unmarshall(URLinstanceURL) throws IOException { // Read in the document SAXBuilder builder = new SAXBuilder();try { Document doc =builder.build(instanceURL); Element rootElement = doc.getRootElement();Unmarshaller unmarshaller = new Unmarshaller(); returnunmarshaller.getJavaRepresentation(rootElement); } catch (JDOMException e){ throw new IOException (e.getMessage()); } }
清單 2 中的方法是靜態(tài)的,允許直接調(diào)用它而無需實例化類的實例。由于對 unmarshall 方法的多個調(diào)用之間沒有需要共享的數(shù)據(jù),因此該方法可以是靜態(tài)的。一旦處理了 XML,就將文檔的根元素(以 JDOM 表示)就被傳到執(zhí)行從 XML 到 Java 對象轉(zhuǎn)換的內(nèi)部方法。
轉(zhuǎn)換數(shù)據(jù)
我不打算逐行解釋取消編組中使用的完整代碼??梢圆榭?類的完整源碼清單 ,它基本上是不需加以說明的。但是,在入口點示例中,有一些值得強調(diào)的事情。如果創(chuàng)建了適當類的新實例,將使用 XML 文檔提供的值調(diào)用 mutator 方法(全都名為 setXXX )。當然,這將使 XML 數(shù)據(jù)在實例的 Java 方法中隨處都可用。清單 3 顯示了處理這種查找方法以及隨后調(diào)用的代碼片段。
清單 3. unmarshaller 類的入口點
// For each attribute, get its name and call mutator List attributes = rootElement.getAttributes(); Method[] methods = objectClass.getMethods(); for (Iterator i = attributes.iterator(); i.hasNext(); ) { Attribute att = (Attribute)i.next(); // Only want attributes for this namespace if ((!att.getNamespace().equals(ns)) && (!att.getNamespace().equals(Namespace.NO_NAMESPACE))) { continue; } // Determine method to call String methodName = new StringBuffer() .append("set") .append(BindingUtils.initialCaps(att.getName())) .toString(); // Find the method to call, and its parameter type for (int j=0; j
找到了根元素的屬性,并確定了每個屬性的適用方法。然后,就是處理實際的 java.lang.reflect.Method 對象。XML 屬性的值已確定,并作為調(diào)用的參數(shù)傳送到方法。但是,需要解決一個映射問題;XML 文檔中的所有數(shù)據(jù)都作為 String 抽取,但傳遞時必須是適當?shù)?Java 類型。清單 4 將一個方法添加到 DataMapping 輔助類中,以滿足轉(zhuǎn)換的需要。
清單 4 將字符串映射成 Java 特定的類型
/** ** This will take the Stringvalue supplied and convert it* to an Object of the type specified in paramType. ** * @param value String value to convert. * @param paramType Class with type to convert to.* @return Object - value in correct type.*/ public static Object getParameter(String value, Class paramType){ Object ob = null; String type = paramType.getName(); if(type.equals("java.lang.String ")) { ob = value; } else if ((type.equals("int")) ||(type.equals("java.lang.Integer"))){ ob = Integer.valueOf(value); } else if ((type.equals("long")) ||(type.equals("java.lang.Long"))) { ob = Long.valueOf(value); }else if ((type.equals("float")) || (type.equals"java.lang.Float"))){ ob = Float.valueOf(value); } else if ((type.equals("double"))|| (type.equals("java.lang.Double"))) { ob = Double.valueOf(value); }else if ((type.equals("boolean")) ||(type.equals("java.lang.Boolean"))) { ob = Boolean.valueOf(value); }return ob; }
在清單 4 中,值作為 String 傳入,并且還傳入了要轉(zhuǎn)換的類和處理類型轉(zhuǎn)換的方法。當然,這里包含的數(shù)據(jù)類型不多??梢蕴砑痈囝愋停ㄈ?java.util.Date )來支持更復(fù)雜的數(shù)據(jù)映射。
一旦數(shù)據(jù)轉(zhuǎn)換成適當?shù)念愋?,可以使用反射調(diào)用 accessor 方法,并可傳入已轉(zhuǎn)換的數(shù)據(jù)類型。這就使 XML 文檔中的所有屬性及其值可以在作為結(jié)果的 Java 實例中以方法變量和的值存儲。
遞歸對象樹
所剩下的將是生成嵌套對象(如 WebServiceConfiguration 對象中的 PortType 對象)。最后,將嵌套對象傳遞給 accessor 方法,然后將填充了成員變量值和對象引用的頂級對象返回給調(diào)用程序。這種方式生成了一棵對象樹,其中主對象是該樹的主干。每個嵌套對象都形成了本身必須填充的樹的分枝。這些分枝可以有它們自己的分枝,帶有本身必須填充的的嵌套對象。由此可知,這棵樹可能變得非常復(fù)雜。
在如果同一操作必須發(fā)生不知多少次的情況下,遞歸幾乎總是完成操作的最佳選擇。如果是 unmarshaller 類,則需要在將 XML 綁定到 Java 的完整過程上遞歸。一旦讀取了所有屬性并將它們分配給已創(chuàng)建的 Java 實例,就需要取出每個嵌套元素,然后再次執(zhí)行取消編組。
通過迭代所提供根的子元素,來完成 XML 文檔的處理,如清單 5 所示。這些子元素中的每一個都將成為另一個對象,這就表示必須以該元素作為根元素重新開始取消編組過程。
清單 5. 用遞歸處理嵌套元素
// Now do complex objects List elements = rootElement.getChildren(); for (Iterator i = elements.iterator(); i.hasNext(); ) { Element element = (Element)i.next(); // Only want elements for this namespace if ((!element.getNamespace().equals(ns)) && (!element.getNamespace().equals(Namespace.NO_NAMESPACE))) { continue; } // Determine method to call String methodName = new StringBuffer() .append("set") .append(BindingUtils.initialCaps(element.getName())) .toString(); // Find the method to call, and its parameter type for (int j=0; j
注:您也許注意到我在清單 5 中的取消編組中做了一個假設(shè),即成員變量總是由 XML 屬性表示,嵌套對象由 XML 元素表示。那么,這些元素可能有自己的屬性和嵌套元素。我的假設(shè)是唯一設(shè)置的限制,并且是合理的。這意味著取消編組過程不必查看引用的 XML 模式并確定特性是由元素表示,還是由屬性表示。這也會使編組過程變得更簡單,將在本系列的下一篇文章中出現(xiàn)。如果所有這一切對您沒有難度,那么只使用屬性作為變量,元素作為對象,不必考慮嵌套和遞歸。
清單 5 中的代碼看來很像上一段代碼,其主要區(qū)別是用紅色強調(diào)的幾行。這段代碼通過取消編組嵌套元素來獲取參數(shù),而不是使用 DataMapping 輔助類將文本值轉(zhuǎn)換成 Java 數(shù)據(jù)類型。然后,返回的對象提供給適當?shù)?mutator 方法(例如, setPort ),迭代繼續(xù)進行。一旦遞歸從底層到頂層解開,則創(chuàng)建的 Java 對象將返回到調(diào)用應(yīng)用程序。很快嗎!數(shù)據(jù)綁定完成了。
通過使用運行的 unmarshaller 類,實際上,它最終使用了數(shù)據(jù)綁定工具。通過使用 XML 模式、XML 文檔和一些簡單的 Java 代碼,訪問 XML 就象訪問 JavaBean 一樣簡單。
生成類
首先,確保已經(jīng)從 XML 模式生成了 Java 類,如清單 6 所示。
清單 6. 從示例模式生成 Java 類
/projects/dev/binding> export CLASSPATH=/projects/dev/jdom/lib/xerces.jar/projects/dev/binding> export CLASSPATH=$CLASSPATH:/projects/dev/jdom/build/jdom.jar/projects/dev/binding> export CLASSPATH=$CLASSPATH:/projects/dev/binding/projects/dev/binding> java org.enhydra.xml.binding.SchemaMapper xml/configuration.xsd/projects/dev/binding> javac -d . *.java
使用 unmarshaller
如果已經(jīng)從 XML 模式生成了類,并經(jīng)過編譯,則可以繼續(xù)。作為確保類是否工作的簡單測試,可以使用清單 7 中的類測試數(shù)據(jù)綁定的功能性(或 下載這個類)。
清單 7. 數(shù)據(jù)綁定測試類
import java.io.File;import org.enhydra.xml.binding.unmarshaller;public class TestMapper { public static void main(String[] args) { System.out.println("Starting unmarshalling..."); try { File file = new File("xml/example.xml"); Object o = unmarshaller. unmarshall(file.toURL()); System.out.println("Object class: " + o.getClass().getName()); System.out.println("Casting to WebServiceConfiguration..."); WebServiceConfiguration config = ( WebServiceConfiguration)o; System.out.println("Successful cast."); System.out.println("Name: " + config.getName()); System.out.println("Version: " + config.getVersion()); System.out.println("Port Number: " + config.getPort().getNumber()); System.out.println("Port Protocol: " + config.getPort().getProtocol()); } catch (Exception e) { e.printStackTrace(); } }}
編譯和運行該數(shù)據(jù)綁定測試類以查看結(jié)果,如清單 8 所示。
清單 8. 測試 unmarshaller
/projects/dev/binding> javac -d . TestMapper.java/projects/dev/binding> java TestMapperStarting unmarshalling...Object class: WebServiceConfiguration ImplCasting to WebServiceConfiguration ...Successful cast.Name: Unsecured Web ListenerVersion: 1.1Port Number: 80Port Protocol: http
啟動 Web 服務(wù)
作為一個更實用的示例,讓我們回顧已經(jīng)在幾篇文章中提到的 Web 服務(wù)示例。假設(shè)有一些可以編程啟動的 Java 類(叫做 WebService ),那么可簡單地使用數(shù)據(jù)綁定來獲取該類的配置信息?,F(xiàn)在,從一個 XML 文檔(或者甚至幾個)中讀取和啟動新的 Web 偵聽程序是非常容易的事 -- 這不需要任何 XML 特定 API 的知識,如清單 9 所示。將配置數(shù)據(jù)取消編組成 Java 對象,然后使用標準 Java accessor 方法(通常是 getXXX() 格式)來配置新的 Web 服務(wù)。
清單 9. XML 到 Web 偵聽程序
// Assume we have a List of URLs for (Iterator i = urls.iterator(); i.hasNext(); ) { WebServiceConfiguration config = unmarshaller.unmarshal((URL)i.next()); WebService newService = new WebService(); newService.setName(config.getName()); // Set up port information newService.setPortNumber(config.getPort().getNumber()); newService.setProtocol(config.getPort().getProtocol()); // Set up document root newService.setDocRoot(config.getDocument().getRoot()); newService.setErrorPage(config.getDocument().getError()); newService.start(); }
就那么簡單,即使是初級開發(fā)者也能寫出使用這個簡單 XML 文檔及其數(shù)據(jù)的 Java 程序,而他甚至還不知道正在使用 XML!有關(guān) XML 數(shù)據(jù)綁定代碼的更多用法,請關(guān)注 Enhydra 應(yīng)用服務(wù)器即將推出的新版本,在未來的發(fā)行版中將包含這里討論的數(shù)據(jù)綁定類(并將在下一篇文章中繼續(xù)討論)。完成了 unmarshaller 的代碼之后,就可以討論最終細節(jié)了。
跟上不斷發(fā)展的 API
就在一個月之前,我們看到 SchemaMapper 類,它從 XML 模式生成 Java 接口和實現(xiàn)。該代碼很大程度地使用了 JDOM API(主要是因為它很方便,是我編寫的?。?。然而 30 天時間只夠進行一屆曲棍球季后賽,對于 API,如仍在開發(fā)中的 JDOM,卻幾乎是一生一世。自上一篇文章以來,有幾個更改已經(jīng)在 JDOM API 中生效了,大多數(shù)反映了一些更新的方法名。有關(guān)更改及其原因的詳細信息,請訪問 JDOM 網(wǎng)站(請參閱 參考資料),可以在該網(wǎng)站上加入 JDOM-興趣郵件列表。但是,為了幫助您使用最新和最好的版本, SchemaMapper 類再次出現(xiàn)在因特網(wǎng)上,并且已更新成使用最新版本的 JDOM(直接來自 CVS)。還可以 下載源碼。強烈建議從 CVS 獲取最新的 JDOM,并使用更新版本的代碼。(在第四部分到來之前,可能仍有更多更改。)
JSR-031,數(shù)據(jù)綁定 API,在 Java 社區(qū)中仍是處在爭論和測試過程的建議書。在這個過程中,它還可能做一些更改。盡管它還未成熟,至今為止許多使用 XML 的 Java 開發(fā)者還是會使用它,因為它是執(zhí)行非常有用功能的方法。
結(jié)束語
通過使用本系列這部分中新的詳細信息,可以使用數(shù)據(jù)綁定代碼。使用 unmarshaller 類,就可以在 Java 代碼中方便地使用 XML 文檔,而不必直接借助于 XML API,如 DOM、SAX 或 JDOM。雖然示例建議使用數(shù)據(jù)綁定處理配置文件,您也許已經(jīng)有了在應(yīng)用程序中使用數(shù)據(jù)綁定的其它想法。也可以使用數(shù)據(jù)綁定代碼來進行消息傳遞、數(shù)據(jù)存儲和顯示等等。
本系列的第四篇,也就是最后一篇文章將主要講述編組,即利用 Marshaller 類得到 Java 類,并將它轉(zhuǎn)換成 XML 文檔。該文章將討論轉(zhuǎn)換原來經(jīng)過取消編組的 Java 對象,以及未經(jīng)過取消編組的 Java 對象。到那時,希望您喜歡迄今為止出現(xiàn)的數(shù)據(jù)綁定代碼,下次再見。
術(shù)語解釋
數(shù)據(jù)綁定。一種使用 JSP-031 訪問 Java 中 XML 數(shù)據(jù)的新方法。JSP-031 是一個仍在開發(fā)中的 API。
顯式類型。具有類型屬性的 complexType 元素。模式中的顯式類型成為生成的 Java 代碼中的接口名稱。
隱式類型。 不具有類型屬性的 complexType 元素。這種情況下,接口名稱由 SchemaMapper 生成。
JSR-031。Sun 公司仍在開發(fā)中的一種新的 Java 規(guī)范申請。它用于將 XML 文檔編譯成一個或多個 Java 類,而在 Java 應(yīng)用程序中可以方便地使用這些 Java 類。
編組。 將 Java 對象轉(zhuǎn)換為 XML 表示,擁有當前值。
取消編組。 根據(jù) XML 對象創(chuàng)建 Java 對象,通常是根據(jù)編組生成一個 Java 對象。
本文所有源代碼已經(jīng)包含在文檔開始處的源代碼包中。
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。