使用 XMLBeans 进行编程 XMLBeans 如何引发数据绑定的巨大变革
隨著企業(yè)應(yīng)用程序的復(fù)雜性不斷加劇,XML 文檔的約束和規(guī)則變得越來越嚴(yán)格。此外,隨著業(yè)界越來越迅速地采用 Web 服務(wù),XML 開始成為跨越多種平臺(tái)的不可忽視的重要角色。所有這一切意味著,應(yīng)用程序迫切需要一種簡(jiǎn)單而強(qiáng)大的機(jī)制來處理 XML。
XMLBeans 提供了這樣一種機(jī)制,可以將 XMLBeans 用于 XML 數(shù)據(jù)綁定。與其他只支持 W3C XML Schema 規(guī)范的某個(gè)子集的數(shù)據(jù)綁定技術(shù)不同,XMLBeans 支持完整的規(guī)范,從這方面來說,它非常強(qiáng)大。對(duì)于習(xí)慣于面向?qū)ο蟛僮鞯拈_發(fā)人員來說,它還驚人地易用。
通過 XMLBeans,您可以使用 Java 類訪問和操縱 XML 文檔中包含的數(shù)據(jù)。
它是如何做到這些的呢?實(shí)際上,它包括兩個(gè)步驟:
一旦 XMLBeans 編譯器生成了和模式對(duì)應(yīng)的一般 Java 類和接口,任何符合該模式的 XML 實(shí)例文檔都可以使用這些類和接口綁定。XMLBeans 比傳統(tǒng)的解析更進(jìn)了一步,因?yàn)橛脩舨辉傩枰M(jìn)行以下操作:
- 導(dǎo)航內(nèi)存中的數(shù)據(jù)樹中的每個(gè)節(jié)點(diǎn)。
- 編寫回調(diào)方法,從 XML 文檔中提取信息。(關(guān)于 XMLBeans 和解析的比較,請(qǐng)參閱本文后面的 XMLBeans 的優(yōu)點(diǎn)。)
一個(gè)簡(jiǎn)單的例子
這是一個(gè)簡(jiǎn)單的例子:輸入一個(gè)模式,XMLBeans 編譯器會(huì)將其編譯成通用的接口。然后我會(huì)向您展示如何將符合該模式的具體 XML 文檔實(shí)例綁定到這些接口。
清單 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中的模式描述的是一種汽車保險(xiǎn)單,其中包括:
- 名為 automobile-policy 的全局根元素。
- 4 種復(fù)雜類型: policyholder-information 、 insured-vehicle 、 liability-coverage 和 third-party-coverage 。
- 一種簡(jiǎn)單類型 insurance-date 。
編譯過程
在進(jìn)入 清單 1所示模式的編譯過程之前,請(qǐng)下載并安裝 Apache XMLBeans version 1.03(請(qǐng)參閱 Resources)。釋放壓縮包中的文件,將 bin 目錄放到 path 下,并將 lib/xbean.jar 放到 classpath 中。
bin 目錄中包含執(zhí)行一些有用動(dòng)作的腳本,比如(在 Windows 平臺(tái)上):
- scomp.cmd 是將模式編譯成 XMLBeans 類和接口的模式編譯器。
- validate.cmd 對(duì)模式驗(yàn)證 XML 實(shí)例文檔。
對(duì)于 UNIX 和 Linux 平臺(tái),XMLBeans 提供了 scomp.sh 和 validate.sh 來執(zhí)行上述操作。
xbean.jar 包含真正的 XMLBeans API 類。
將模式放在適當(dāng)?shù)奈募A中并設(shè)置好 path 與 classpath ,使用 下面的命令編譯模式:
| scomp -out automobile-policy.jar automobile-policy.xsd |
?
在上述命令中, scomp 是模式編譯器, -out 選項(xiàng)用于命名輸出的 jar 文件,這里使用的 automobile-policy.jar ; automobile-policy.xsd 是編譯的模式。
上述命令將 automobile-policy.xsd 編譯成 XMLBeans 接口和類,并將它們打包到 automobile-policy.jar 。編譯后將生成以下接口:
- AutomobilePolicyDocument ,表示文檔元素,該元素是由全局根元素生成的,在該例中是 automobile-policy 。
- AutomobilePolicyDocument$AutomobilePolicy ,表示全局根元素 automobile-policy 。
- PolicyholderInformation ,表示復(fù)雜類型 policyholder-information 。
- InsuredVehicle ,表示復(fù)雜類型 insured-vehicle 。
- LiabilityCoverage ,表示復(fù)雜類型 liability-coverage 。
- ThirdPartyCoverage ,表示復(fù)雜類型 third-party-coverage 。
生成的接口包名是從模式中使用名稱空間衍生出來的。因?yàn)樵撃J經(jīng)]有包含名稱空間,所以這些接口將被放在包 noNamespace 中。
讓我們看一看這些接口。 AutomobilePolicyDocument 接口包含以下方法:
- getAutomobilePolicy() ,訪問 automobile-policy 元素。
- setAutomobilePolicy(AutomobilePolicy automobilePolicy) ,設(shè)置 automobile-policy 元素。
- addNewAutomobilePolicy() ,添加 automobile-policy 并返回新的空元素。
與此類似, AutomobilePolicyDocument$AutomobilePolicy 接口也包含以下方法:
- getPolicyholderInformation() ,訪問 policyholder-information 元素。
- getInsuredVehicle() ,訪問 insured-vehicle 元素。
其中的關(guān)鍵是將 XML Schema 結(jié)構(gòu)作為 Java 接口復(fù)制,所有的基本操作,即添加新元素以及訪問、設(shè)置已有的元素,都是作為這些接口的方法來實(shí)現(xiàn)的。
此外,所有生成的接口都有一個(gè)包含靜態(tài)方法的工廠類,比如:
- newInstance() 創(chuàng)建了這種類型的新實(shí)例。
- parse() 用于解析真正的 XML 實(shí)例文檔。
綁定過程
將模式編譯成 XMLBeans 接口和類之后,需要將 XML 實(shí)例綁定到這些類。下面的代碼取自 AutomobilePolicyHandler.java ,它使用生成的接口,根據(jù)編譯后的模式處理真正的 XML 實(shí)例。
清單 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 實(shí)例,并使用 AutomobilePolicyDocument Factory 類的 parse() 方法獲得 AutomobilePolicyDocument 實(shí)例。
上述 AutomobilePolicyDocument 實(shí)例的 getAutomobilePolicy() 方法可以提供根元素 automobile-policy 的句柄。您可以使用簡(jiǎn)單的 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 的層次結(jié)構(gòu)
編譯生成的所有 XMLBeans 類都是從 org.apache.xmlbeans.XmlObject 派生的。這是所有 XMLBeans 類型的基本接口,包含一些所有 XMLBeans 類都提供的通用設(shè)施:
- 有一個(gè)從標(biāo)準(zhǔn) DOM 樹或者 SAX 流復(fù)制 XMLObject 實(shí)例的方法。
- 有一個(gè) validate() 方法,可以用它驗(yàn)證該 XMLObject 下的 XML 子樹。
- 有一個(gè) selectPath(java.lang.String) 方法,該方法使用相對(duì) XPath 查找 XmlObject 子樹下的其他 XmlObject 。
在 XMLObject 層內(nèi),有用戶驅(qū)動(dòng)的模式類型和內(nèi)置模式類型。我已經(jīng)說明了用戶驅(qū)動(dòng)類型(如 automobile-policy 和 policyholder-information )的語義。如前所述,每個(gè)用戶驅(qū)動(dòng)的模式類型都被表示成一個(gè)接口。
另一方面,對(duì)于 xs:int 和 xs:string 這類內(nèi)置模式類型,XMLBeans 提供了 46 種 Java 類型,對(duì)應(yīng)于 W3C XML Schema 規(guī)范定義的 46 種內(nèi)置類型。比如,為了對(duì)應(yīng) XML Schema 中的 xs:string ,XMLBeans 提供了 XmlString 。
讓我們?cè)倩氐侥J?#xff0c;為了提取 policyholder-information 復(fù)雜類型中的 xs:string 類型的社會(huì)安全號(hào),XMLBeans 提供了以下方法:
| org.apache.xmlbeans.XmlString xgetSocialSecurityNumber(); |
?
該方法返回 XmlString 。
當(dāng)然,XMLBeans 也提供了返回純 Java 類型的方法:
| java.lang.String getSocialSecurityNumber(); |
?
注意,在返回 XMLBeans 類型的情況下,方法名是以 xget 開頭的。 xget 版本的方法在性能上要好于 get 版本,因?yàn)?get 需要將數(shù)據(jù)轉(zhuǎn)化成最適當(dāng)?shù)?Java 類型。
?
|
?
?
高級(jí)特性
通過這個(gè)簡(jiǎn)單的例子,您已經(jīng)發(fā)現(xiàn)使用 XMLBeans 是多么容易,而且也熟悉了 XMLBeans 的層次結(jié)構(gòu),現(xiàn)在來看一看 XMLBeans 的一些高級(jí)特性。這些特性才真正代表了 XMLBeans 的強(qiáng)大功能。
XML 游標(biāo)
XML 游標(biāo)定義了 XML 文檔中的一個(gè)位置。它最適合沒有可用模式的 XML 文檔。游標(biāo)允許用戶通過改變自身的位置來遍歷整個(gè)文檔,還允許用戶刪除和插入 XML 片段,訪問和設(shè)置 XML 值等。
清單 4 是一個(gè)簡(jiǎn)單的例子,說明了 XML 游標(biāo)的用法。 CursorHandler.java 中的代碼將檢索 automobile-policy.xml 中已保險(xiǎn)汽車的型號(hào)。
清單 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(); } } } |
?
該例中的游標(biāo)被定義在 XML 實(shí)例的開頭。方法 toFirstContentToken() 將游標(biāo)移動(dòng)到當(dāng)前 START 或 STARTDOC 內(nèi)容中的第一個(gè)標(biāo)志上。從本質(zhì)上說,這意味著將游標(biāo)移到了根元素 automobile-policy 的起始位置上。
因此, cursor.getTextValue() 將打印 XML 文檔的全部內(nèi)容。
因?yàn)槲覀兊哪康氖遣檎乙驯kU(xiǎn)汽車的型號(hào), cursor.toChild(2) 方法將游標(biāo)移動(dòng)到 automobile-policy 的第三個(gè)子元素,即 <insured-vehicle> 。現(xiàn)在游標(biāo)移到了 <insured-vehicle> 元素上,再次調(diào)用 cursor.toChild(2) 方法可以將游標(biāo)移動(dòng)到相對(duì)于當(dāng)前位置的第三個(gè)子元素上,即 <model> 元素。
然后用方法 cursor.getTextValue() 檢索型號(hào)值。
在完成游標(biāo)的使用之后,不要忘記調(diào)用其 dispose() 方法。
XML 標(biāo)志
XML 標(biāo)志代表一類 XML 標(biāo)記。實(shí)際上,XML 標(biāo)志代表了 XML 文檔能夠包含的不同類型的部分。其中包括 XML 文檔的開始和結(jié)束、屬性和屬性值等。
在代碼中移動(dòng) XML 游標(biāo)時(shí),可以將它從一個(gè)標(biāo)志移動(dòng)到另一個(gè)標(biāo)志。當(dāng)您移動(dòng)游標(biāo)時(shí),是將它移動(dòng)到符合要求的標(biāo)志。如果游標(biāo)沒有發(fā)現(xiàn)可以移動(dòng)到的適當(dāng)標(biāo)志,那么它將保留在原位,并返回“false”表示游標(biāo)沒有移動(dòng)。
每種標(biāo)志類型都用 TokenType 類中的一個(gè)常數(shù)表示,其中包括:
- INT_STARTDOC ,表示 XML 文檔的開始(不含 XML 聲明)。
- INT_ENDDOC ,表示 XML 文檔的結(jié)束。
- INT_TEXT ,表示元素的內(nèi)容。
標(biāo)志本身不作為對(duì)象公開,但其類型和屬性可以通過游標(biāo)方法來訪問。比如, CursorHandler.java 中的下列代碼片段將打印標(biāo)志類型和標(biāo)志值。
清單 5. 打印標(biāo)志類型和標(biāo)志文本的代碼
| System.out.println("Type of Token is: " + cursor.currentTokenType() + "\nText of Token is" + cursor.xmlText()); |
?
XQuery 表達(dá)式
XMLBeans 支持 XQuery 表達(dá)式。這種類 SQL 語法能夠遍歷 XML 文檔來訪問元素和屬性。XQuery 表達(dá)式和 XML 游標(biāo)的結(jié)合大大增強(qiáng)了 XQuery 的能力。我們?nèi)匀皇褂蒙鲜鰪?automobile-policy.xml 中檢索已保險(xiǎn)車輛型號(hào)的例子,清單 6 中的代碼片段就能夠完成這項(xiàng)工作。
清單 6. 使用 XQuery 表達(dá)式檢索 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 中的代碼創(chuàng)建了一個(gè)到達(dá)所需元素的 XQuery 表達(dá)式。 execQuery() 方法運(yùn)行該查詢表達(dá)式,并返回新的 resultCursor 。然后使用該 resultCursor 打印 model 元素的值。變量 $this 表示 XML 游標(biāo)的當(dāng)前位置。
?
|
?
?
XMLBeans 的優(yōu)點(diǎn)
XMLBeans 面臨著傳統(tǒng)解析和綁定技術(shù)的競(jìng)爭(zhēng),如 DOM、SAX、JAXB 和 Castor,但 XMLBeans 有一些獨(dú)到之處。它們的比較如下:
- DOM 在內(nèi)容中生成整個(gè)文檔的樹。如果文檔非常大,DOM 就會(huì)變得對(duì)內(nèi)存非常敏感,并會(huì)顯著降低性能。通過增量解組(incremental unmarshalling)并提供 xget 方法來訪問內(nèi)置的模式數(shù)據(jù)類型,XMLBeans 取得了較好的性能。
- 與 DOM 相比,SAX 對(duì)內(nèi)存要求不高,但是 SAX 要求開發(fā)人員為事件處理程序編寫回調(diào)方法,而 XMLBeans 則不需要。
- 與 XMLBeans 類似,JAXB 和 Castor 也都是 XML/Java 綁定技術(shù),但它們都沒有提供百分之百的模式支持。XMLBeans 最大的優(yōu)勢(shì)之一是幾乎百分之百的支持 XML Schema。此外,XMLBeans 還能夠訪問完整的 XML Infoset,對(duì)于強(qiáng)調(diào)元素順序或者注釋的應(yīng)用程序,這一點(diǎn)特別有用。
- XMLBeans 還提供了解析 XML 實(shí)例的即時(shí)驗(yàn)證。
- XMLBeans 包括一些創(chuàng)新的特性,如 XML 游標(biāo)和對(duì) XQuery 的支持。
?
|
?
?
結(jié)束語
在 XML 和 Java 技術(shù)的發(fā)展前沿地帶,各種各樣的技術(shù)互相擁擠碰撞著,XMLBeans 在非常短的時(shí)間內(nèi)站穩(wěn)了腳跟。如果開發(fā)人員需要處理復(fù)雜的 XML 模式和需要更多的本機(jī)支持(比如訪問完整的 XML Infoset),那么 XMLBeans 是無可替代的。
性能的優(yōu)勢(shì)和即時(shí)驗(yàn)證支持,使 XMLBeans 成為用于各種 XML 和 Java 數(shù)據(jù)綁定場(chǎng)景的一種非常強(qiáng)大的工具。易于理解的 API 降低了開發(fā)人員的學(xué)習(xí)難度,也使其成為非常誘人的選擇。這是一項(xiàng)強(qiáng)大而激動(dòng)人心的技術(shù)。
轉(zhuǎn)載于:https://www.cnblogs.com/guoxu/articles/1702556.html
與50位技術(shù)專家面對(duì)面20年技術(shù)見證,附贈(zèng)技術(shù)全景圖總結(jié)
以上是生活随笔為你收集整理的使用 XMLBeans 进行编程 XMLBeans 如何引发数据绑定的巨大变革的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C++中的wchar_t(转)
- 下一篇: SQL--XML