使用 XMLBeans 进行编程 XMLBeans 如何引发数据绑定的巨大变革
隨著企業應用程序的復雜性不斷加劇,XML 文檔的約束和規則變得越來越嚴格。此外,隨著業界越來越迅速地采用 Web 服務,XML 開始成為跨越多種平臺的不可忽視的重要角色。所有這一切意味著,應用程序迫切需要一種簡單而強大的機制來處理 XML。
XMLBeans 提供了這樣一種機制,可以將 XMLBeans 用于 XML 數據綁定。與其他只支持 W3C XML Schema 規范的某個子集的數據綁定技術不同,XMLBeans 支持完整的規范,從這方面來說,它非常強大。對于習慣于面向對象操作的開發人員來說,它還驚人地易用。
通過 XMLBeans,您可以使用 Java 類訪問和操縱 XML 文檔中包含的數據。
它是如何做到這些的呢?實際上,它包括兩個步驟:
一旦 XMLBeans 編譯器生成了和模式對應的一般 Java 類和接口,任何符合該模式的 XML 實例文檔都可以使用這些類和接口綁定。XMLBeans 比傳統的解析更進了一步,因為用戶不再需要進行以下操作:
- 導航內存中的數據樹中的每個節點。
- 編寫回調方法,從 XML 文檔中提取信息。(關于 XMLBeans 和解析的比較,請參閱本文后面的 XMLBeans 的優點。)
一個簡單的例子
這是一個簡單的例子:輸入一個模式,XMLBeans 編譯器會將其編譯成通用的接口。然后我會向您展示如何將符合該模式的具體 XML 文檔實例綁定到這些接口。
清單 1. 輸入模式(automobile-policy.xsd)
| <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="automobile-policy"> <xs:complexType> <xs:sequence> <xs:element name="insurance-date" type="xs:dateTime"/> <xs:element name="policyholder-information" type="policyholder-information" minOccurs="1"/> <xs:element name="insured-vehicle" type="insured-vehicle" minOccurs="1"/> <xs:element name="liability-coverage" type="liability-coverage" minOccurs="1"/> <xs:element name="third-party-coverage" type="third-party-coverage"/> </xs:sequence> </xs:complexType> </xs:element> <xs:complexType name="policyholder-information"> <xs:sequence> <xs:element name="name" type="xs:string"/> <xs:element name="social-security-number" type="xs:string"/> <xs:element name="address" type="xs:string"/> </xs:sequence> </xs:complexType> <xs:complexType name="insured-vehicle"> <xs:sequence> <xs:element name="year-of-manufacture" type="xs:string"/> <xs:element name="make" type="xs:string"/> <xs:element name="model" type="xs:string"/> <xs:element name="price" type="xs:double"/> </xs:sequence> </xs:complexType> <xs:complexType name="liability-coverage"> <xs:sequence> <xs:element name="coverage-limit" type="xs:double"/> <xs:element name="coverage-premium" type="xs:double"/> </xs:sequence> </xs:complexType> <xs:complexType name="third-party-coverage"> <xs:sequence> <xs:element name="coverage-limit" type="xs:double"/> <xs:element name="coverage-premium" type="xs:double"/> </xs:sequence> </xs:complexType> </xs:schema> |
?
清單 1中的模式描述的是一種汽車保險單,其中包括:
- 名為 automobile-policy 的全局根元素。
- 4 種復雜類型: policyholder-information 、 insured-vehicle 、 liability-coverage 和 third-party-coverage 。
- 一種簡單類型 insurance-date 。
編譯過程
在進入 清單 1所示模式的編譯過程之前,請下載并安裝 Apache XMLBeans version 1.03(請參閱 Resources)。釋放壓縮包中的文件,將 bin 目錄放到 path 下,并將 lib/xbean.jar 放到 classpath 中。
bin 目錄中包含執行一些有用動作的腳本,比如(在 Windows 平臺上):
- scomp.cmd 是將模式編譯成 XMLBeans 類和接口的模式編譯器。
- validate.cmd 對模式驗證 XML 實例文檔。
對于 UNIX 和 Linux 平臺,XMLBeans 提供了 scomp.sh 和 validate.sh 來執行上述操作。
xbean.jar 包含真正的 XMLBeans API 類。
將模式放在適當的文件夾中并設置好 path 與 classpath ,使用 下面的命令編譯模式:
| scomp -out automobile-policy.jar automobile-policy.xsd |
?
在上述命令中, scomp 是模式編譯器, -out 選項用于命名輸出的 jar 文件,這里使用的 automobile-policy.jar ; automobile-policy.xsd 是編譯的模式。
上述命令將 automobile-policy.xsd 編譯成 XMLBeans 接口和類,并將它們打包到 automobile-policy.jar 。編譯后將生成以下接口:
- AutomobilePolicyDocument ,表示文檔元素,該元素是由全局根元素生成的,在該例中是 automobile-policy 。
- AutomobilePolicyDocument$AutomobilePolicy ,表示全局根元素 automobile-policy 。
- PolicyholderInformation ,表示復雜類型 policyholder-information 。
- InsuredVehicle ,表示復雜類型 insured-vehicle 。
- LiabilityCoverage ,表示復雜類型 liability-coverage 。
- ThirdPartyCoverage ,表示復雜類型 third-party-coverage 。
生成的接口包名是從模式中使用名稱空間衍生出來的。因為該模式沒有包含名稱空間,所以這些接口將被放在包 noNamespace 中。
讓我們看一看這些接口。 AutomobilePolicyDocument 接口包含以下方法:
- getAutomobilePolicy() ,訪問 automobile-policy 元素。
- setAutomobilePolicy(AutomobilePolicy automobilePolicy) ,設置 automobile-policy 元素。
- addNewAutomobilePolicy() ,添加 automobile-policy 并返回新的空元素。
與此類似, AutomobilePolicyDocument$AutomobilePolicy 接口也包含以下方法:
- getPolicyholderInformation() ,訪問 policyholder-information 元素。
- getInsuredVehicle() ,訪問 insured-vehicle 元素。
其中的關鍵是將 XML Schema 結構作為 Java 接口復制,所有的基本操作,即添加新元素以及訪問、設置已有的元素,都是作為這些接口的方法來實現的。
此外,所有生成的接口都有一個包含靜態方法的工廠類,比如:
- newInstance() 創建了這種類型的新實例。
- parse() 用于解析真正的 XML 實例文檔。
綁定過程
將模式編譯成 XMLBeans 接口和類之后,需要將 XML 實例綁定到這些類。下面的代碼取自 AutomobilePolicyHandler.java ,它使用生成的接口,根據編譯后的模式處理真正的 XML 實例。
清單 2. AutomobilePolicyHandler.java
| import noNamespace.*; import java.io.File; import java.util.Calendar; public class AutomobilePolicyHandler{ public static void main(String args[]) { try { String filePath = "automobile-policy.xml"; java.io.File inputXMLFile = new java.io.File(filePath); AutomobilePolicyDocument autoPolicyDoc = AutomobilePolicyDocument.Factory.parse(inputXMLFile); AutomobilePolicyDocument.AutomobilePolicy autoPolicyElement = autoPolicyDoc.getAutomobilePolicy(); System.out.println("date is " + autoPolicyElement.getInsuranceDate()); } catch (Exception e) { e.printStackTrace(); } } } |
?
清單 2 的代碼接受輸入的 XML 實例,并使用 AutomobilePolicyDocument Factory 類的 parse() 方法獲得 AutomobilePolicyDocument 實例。
上述 AutomobilePolicyDocument 實例的 getAutomobilePolicy() 方法可以提供根元素 automobile-policy 的句柄。您可以使用簡單的 getter 和 setter 檢索 XML 中子元素的值。
下面的 XML 文件 automobile-policy.xml 符合模式 automobile-policy.xsd ,可以將它用于 清單 2中的方法。
清單 3. automobile-policy.xml
| <automobile-policy> <insurance-date>2004-09-05T14:12:22-05:00</insurance-date> <policyholder-information> <name>Alan</name> <social-security-number>1GBL7D1G3GV100770 </social-security-number> <address>171 Dormonth Street, Fairfield, OH</address> </policyholder-information> <insured-vehicle> <year-of-manufacture>1999</year-of-manufacture> <make>Chevy</make> <model>Optra</model> <price>1234</price> </insured-vehicle> <liability-coverage> <coverage-limit>1222</coverage-limit> <coverage-premium>12</coverage-premium> </liability-coverage> <third-party-coverage> <coverage-limit>2343</coverage-limit> <coverage-premium>14</coverage-premium> </third-party-coverage> </automobile-policy> |
|
?
?
XMLBeans 的層次結構
編譯生成的所有 XMLBeans 類都是從 org.apache.xmlbeans.XmlObject 派生的。這是所有 XMLBeans 類型的基本接口,包含一些所有 XMLBeans 類都提供的通用設施:
- 有一個從標準 DOM 樹或者 SAX 流復制 XMLObject 實例的方法。
- 有一個 validate() 方法,可以用它驗證該 XMLObject 下的 XML 子樹。
- 有一個 selectPath(java.lang.String) 方法,該方法使用相對 XPath 查找 XmlObject 子樹下的其他 XmlObject 。
在 XMLObject 層內,有用戶驅動的模式類型和內置模式類型。我已經說明了用戶驅動類型(如 automobile-policy 和 policyholder-information )的語義。如前所述,每個用戶驅動的模式類型都被表示成一個接口。
另一方面,對于 xs:int 和 xs:string 這類內置模式類型,XMLBeans 提供了 46 種 Java 類型,對應于 W3C XML Schema 規范定義的 46 種內置類型。比如,為了對應 XML Schema 中的 xs:string ,XMLBeans 提供了 XmlString 。
讓我們再回到模式,為了提取 policyholder-information 復雜類型中的 xs:string 類型的社會安全號,XMLBeans 提供了以下方法:
| org.apache.xmlbeans.XmlString xgetSocialSecurityNumber(); |
?
該方法返回 XmlString 。
當然,XMLBeans 也提供了返回純 Java 類型的方法:
| java.lang.String getSocialSecurityNumber(); |
?
注意,在返回 XMLBeans 類型的情況下,方法名是以 xget 開頭的。 xget 版本的方法在性能上要好于 get 版本,因為 get 需要將數據轉化成最適當的 Java 類型。
?
|
?
?
高級特性
通過這個簡單的例子,您已經發現使用 XMLBeans 是多么容易,而且也熟悉了 XMLBeans 的層次結構,現在來看一看 XMLBeans 的一些高級特性。這些特性才真正代表了 XMLBeans 的強大功能。
XML 游標
XML 游標定義了 XML 文檔中的一個位置。它最適合沒有可用模式的 XML 文檔。游標允許用戶通過改變自身的位置來遍歷整個文檔,還允許用戶刪除和插入 XML 片段,訪問和設置 XML 值等。
清單 4 是一個簡單的例子,說明了 XML 游標的用法。 CursorHandler.java 中的代碼將檢索 automobile-policy.xml 中已保險汽車的型號。
清單 4. CursorHandler.java
| import noNamespace.*; import java.io.File; import java.util.Calendar; import org.apache.xmlbeans.XmlCursor; public class CursorHandler { public static void main(String args[]) { try { String filePath = "automobile-policy.xml"; java.io.File inputXMLFile = new java.io.File(filePath); AutomobilePolicyDocument autoPolicyDoc = AutomobilePolicyDocument.Factory.parse(inputXMLFile); XmlCursor cursor = autoPolicyDoc.newCursor(); cursor.toFirstContentToken(); cursor.toChild(2); cursor.toChild(2); System.out.println(cursor.getTextValue()); System.out.println("Type of Token is: " + cursor.currentTokenType() + "\nText of Token is" + cursor.xmlText()); cursor.dispose(); } catch (Exception e) { e.printStackTrace(); } } } |
?
該例中的游標被定義在 XML 實例的開頭。方法 toFirstContentToken() 將游標移動到當前 START 或 STARTDOC 內容中的第一個標志上。從本質上說,這意味著將游標移到了根元素 automobile-policy 的起始位置上。
因此, cursor.getTextValue() 將打印 XML 文檔的全部內容。
因為我們的目的是查找已保險汽車的型號, cursor.toChild(2) 方法將游標移動到 automobile-policy 的第三個子元素,即 <insured-vehicle> 。現在游標移到了 <insured-vehicle> 元素上,再次調用 cursor.toChild(2) 方法可以將游標移動到相對于當前位置的第三個子元素上,即 <model> 元素。
然后用方法 cursor.getTextValue() 檢索型號值。
在完成游標的使用之后,不要忘記調用其 dispose() 方法。
XML 標志
XML 標志代表一類 XML 標記。實際上,XML 標志代表了 XML 文檔能夠包含的不同類型的部分。其中包括 XML 文檔的開始和結束、屬性和屬性值等。
在代碼中移動 XML 游標時,可以將它從一個標志移動到另一個標志。當您移動游標時,是將它移動到符合要求的標志。如果游標沒有發現可以移動到的適當標志,那么它將保留在原位,并返回“false”表示游標沒有移動。
每種標志類型都用 TokenType 類中的一個常數表示,其中包括:
- INT_STARTDOC ,表示 XML 文檔的開始(不含 XML 聲明)。
- INT_ENDDOC ,表示 XML 文檔的結束。
- INT_TEXT ,表示元素的內容。
標志本身不作為對象公開,但其類型和屬性可以通過游標方法來訪問。比如, CursorHandler.java 中的下列代碼片段將打印標志類型和標志值。
清單 5. 打印標志類型和標志文本的代碼
| System.out.println("Type of Token is: " + cursor.currentTokenType() + "\nText of Token is" + cursor.xmlText()); |
?
XQuery 表達式
XMLBeans 支持 XQuery 表達式。這種類 SQL 語法能夠遍歷 XML 文檔來訪問元素和屬性。XQuery 表達式和 XML 游標的結合大大增強了 XQuery 的能力。我們仍然使用上述從 automobile-policy.xml 中檢索已保險車輛型號的例子,清單 6 中的代碼片段就能夠完成這項工作。
清單 6. 使用 XQuery 表達式檢索 XML 元素值的代碼
| XmlCursor cursor = autoPolicyDoc.newCursor(); String modelQuery = $this/automobile-policy/insured-vehicle/model; //Note that execQuery creates a new cursor XMLCursor resultCursor = cursor.execQuery(modelQuery); System.out.println(resultCursor.getTextValue()); |
?
|
清單 6 中的代碼創建了一個到達所需元素的 XQuery 表達式。 execQuery() 方法運行該查詢表達式,并返回新的 resultCursor 。然后使用該 resultCursor 打印 model 元素的值。變量 $this 表示 XML 游標的當前位置。
?
|
?
?
XMLBeans 的優點
XMLBeans 面臨著傳統解析和綁定技術的競爭,如 DOM、SAX、JAXB 和 Castor,但 XMLBeans 有一些獨到之處。它們的比較如下:
- DOM 在內容中生成整個文檔的樹。如果文檔非常大,DOM 就會變得對內存非常敏感,并會顯著降低性能。通過增量解組(incremental unmarshalling)并提供 xget 方法來訪問內置的模式數據類型,XMLBeans 取得了較好的性能。
- 與 DOM 相比,SAX 對內存要求不高,但是 SAX 要求開發人員為事件處理程序編寫回調方法,而 XMLBeans 則不需要。
- 與 XMLBeans 類似,JAXB 和 Castor 也都是 XML/Java 綁定技術,但它們都沒有提供百分之百的模式支持。XMLBeans 最大的優勢之一是幾乎百分之百的支持 XML Schema。此外,XMLBeans 還能夠訪問完整的 XML Infoset,對于強調元素順序或者注釋的應用程序,這一點特別有用。
- XMLBeans 還提供了解析 XML 實例的即時驗證。
- XMLBeans 包括一些創新的特性,如 XML 游標和對 XQuery 的支持。
?
|
?
?
結束語
在 XML 和 Java 技術的發展前沿地帶,各種各樣的技術互相擁擠碰撞著,XMLBeans 在非常短的時間內站穩了腳跟。如果開發人員需要處理復雜的 XML 模式和需要更多的本機支持(比如訪問完整的 XML Infoset),那么 XMLBeans 是無可替代的。
性能的優勢和即時驗證支持,使 XMLBeans 成為用于各種 XML 和 Java 數據綁定場景的一種非常強大的工具。易于理解的 API 降低了開發人員的學習難度,也使其成為非常誘人的選擇。這是一項強大而激動人心的技術。
轉載于:https://www.cnblogs.com/guoxu/articles/1702556.html
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的使用 XMLBeans 进行编程 XMLBeans 如何引发数据绑定的巨大变革的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C++中的wchar_t(转)
- 下一篇: ie里的button标签的一个bug