使用JAXB将XML Schema绑定到Java类
http://blog.csdn.net/zsyspace/article/details/1786079
Java Architecture for XML Binding (JAXB) 是一項可以根據XML 模式產生Java類的Java技術。該過程中,JAXB也提供了將XML實例文檔反編組到Java內容樹的方法,并能將Java內容樹編組回XML實例文檔。從另一方面來講,JAXB提供了快速而簡便的方法將XML模式綁定到Java表示,從而使得Java開發(fā)者在Java應用程序中能方便地結合XML數據和處理函數。
這意味著你不需要處理甚至不需要知道XML編程技巧就能在Java應用程序中利用平臺核心XML數據的靈活性。而且,可以充分利用XML的優(yōu)勢而不用依賴于復雜的XML處理模型如SAX或DOM。JAXB 隱藏了細節(jié)并且取消了SAX和DOM中沒用的關系——生成的JAXB類僅描述原始模型中定義的關系。其結果是結合了高度可移植Java代碼的高度可移植的XML數據,其中這些代碼可用來創(chuàng)建靈活、輕便的應用程序和Web服務。
本章介紹了JAXB體系結構、函數和核心概念。在學習第十章之前必須先閱讀本章。第十章給出了示例代碼和逐步使用JAXB的過程。
JAXB 體系結構
本節(jié)主要討論JAXB處理模型中的組件和交互。在給出了總的概述之后,本節(jié)將詳細討論核心的JAXB特性。本節(jié)中的主題主要包括:
- 體系結構概述
- JAXB綁定過程
- JAXB 綁定框架
- 關于javax.xml.bind的更多信息
- 關于反編組的更多信息
- 關于編組的更多信息
- 關于驗證的更多信息
體系結構概述
圖 9-1 給出了構成JAXB實現的組件。
圖 9-1 JAXB體系結構概述
如圖9-1所示,JAXB實現包含下列八個核心組件:
| 表 9-1 JAXB實現中的核心組件 | |
| 組件 | 描述 |
| XML Schema | XML模式使用XML語法描述XML文檔中元素、屬性和實體之間的關系。XML模式的目標是定義一個XML文檔類,該類必須堅持特定的結構規(guī)則和數據約束。例如,你可能希望給面向章的書、在線采購系統或個人數據庫定義不同的模式。在JAXB上下文中,將包含數據的受到XML模式約束的XML文檔叫做文檔實例,并且將文檔實例中的結構和數據叫做內容樹 |
| Binding | 默認情況下,JAXB綁定編譯器根據JAXB規(guī)范第5節(jié)“將XML Schema綁定到Java表示”中定義的規(guī)則將Java類和包綁定到原始XML模式。多數情況下,利用默認的規(guī)則已經能夠從大量的模式中產生一組強壯的模式派生類。但是,有的時候,默認的綁定規(guī)則就不夠用了。JAXB支持通過綁定聲明自定義或覆蓋默認的綁定規(guī)則。這些綁定聲明或者是內部源模式的注釋或者是傳遞給JAXB綁定編譯器的外部綁定自定義文件中的語句。注意,自定義的JAXB綁定聲明也允許擺脫XML模式中特定于XML的束縛,來自定義生成的JAXB類,以包含特定于Java的改進,如類和包名映射 |
| Binding | JAXB綁定編譯器是JAXB處理模型的核心。它的功能是將源XML模式轉換或綁定到Java編程語言中的一組JAXB內容類。基本上,可以通過將一個XML模式 (可以選擇使用自定義綁定聲明)用作輸入來運行JAXB綁定編譯器。綁定編譯器產生Java類,這些Java類映射到了源XML 模式中的約束條件 |
| Binding | JAXB綁定框架實現是運行時API,它提供了反編組、編組和驗證Java應用程序中的XML內容的接口。綁定框架包括javax.xml.bind包中的接口 |
| Schema-Derived | 這些是JAXB編譯器產生的模式派生類。根據輸入的模式將采用不同的類 |
| Java | 在JAXB上下文中,Java應用程序是客戶端應用程序,它使用JAXB綁定框架來反編組XML數據,驗證并修改Java內容對象,并將Java內容編組成XML數據。特別是,JAXB綁定框架包裝在一個能提供UI功能、XML轉換功能、數據處理或其他所需要的功能的大型Java應用程序中 |
| XML Input | 這是反編組出來用作JAXB綁定框架輸入的XML內容——即XML實例文檔,從這里將產生內容樹形式的Java表示。實際上,術語“文檔”不再是傳統意義上的文檔了,因為XML實例文檔不一定要是形式完整的、自立的文檔文件;相反它具有流的形式,這些流可以是應用程序之間傳遞的數據、數據庫字段集合、XML信息集合,其中信息塊包含了描述它們在模式結構中的位置的足夠信息。 ? 在JAXB中,反編組過程支持根據源模式定義的約束驗證XML輸入文檔。然而該驗證過程是可選的,在某些情況下你可能通過其他途徑知道輸入文檔是有效的,出于對性能的考慮你可能選擇在反編組過程中跳過驗證。但是,無論在哪種情況下,反編組之前(通過第三方應用程序)或之后驗證都很重要,這是因為它確保了關于源模式編組過程中產生的XML文檔也是有效的。在本章的后面部分將詳細介紹驗證 |
| XML Output | 這是編組到XML文檔的XML內容。在JAXB中,編組包括解析XML內容對象樹并寫出一個XML文檔,該文檔是原始XML文檔的精確表示并且相對于原始模式來說是有效的。JAXB能夠將XML數據編組成XML 文檔、SAX內容處理程序和DOM節(jié)點。 |
JAXB綁定過程
圖9-2顯示了JAXB的綁定過程。
圖 9-2 JAXB綁定過程步驟
JAXB數據綁定過程的常用步驟是:
1.?????? 生成類。將XML模式放入JAXB綁定編譯器,以產生基于該模式的JAXB類。
2.?????? 編譯類。必須編譯所有生成的類、源文件和應用程序代碼。
3.?????? 反編組。JAXB綁定框架反編組根據原始模式中的約束編寫的XML文檔。注意JAXB也支持反編組來自除了文件/文檔之外XML數據,如DOM節(jié)點、字符串緩沖、SAX Source等等。
4.?????? 生成內容樹。反編組過程產生從生成的JAXB類實例化而來的數據對象內容樹,該內容樹代表了源XML文檔的結構和內容。
5.?????? 驗證(可選)。反編組過程中,可以在生成內容樹之前驗證源XML文檔。注意,如果在第6步中修改內容樹,下面,你也能使用JAXB驗證操作在將內容編組到XML文檔之前驗證變化。
6.?????? 處理內容。客戶端應用程序通過綁定編譯器產生的接口方法可以修改Java內容樹表示的XML數據。
7.?????? 編組。將處理過的內容樹編組到一個或多個XML輸出文檔中。在編組之前要驗證內容。
總而言之,使用JAXB涉及到兩個獨立的活動集:
- 根據源模式生成并編譯JAXB類,并且建立一個實現這些類的應用程序。
- 在JAXB綁定框架中運行應用程序,以反編組、處理、驗證和編組XML內容。
通常分時間分階段執(zhí)行這兩個步驟。典型地,例如,需要在應用程序開發(fā)階段生成并編譯JAXB類,并且建立綁定實現,接著是部署階段,在該階段使用生成的JAXB類在“現場”產品環(huán)境中處理XML內容。
注意:反編組不是創(chuàng)建內容樹的唯一的方法。模式派生的內容類通過直接調用合適的工廠方法也支持按計劃構建內容樹。一旦創(chuàng)建了,任何時候都可以重新驗證內容樹的一部分或全部。查看示例應用程序 3 中的使用ObjectFactory 類直接給內容樹添加內容的例子。
JAXB綁定框架
JAXB綁定框架由三個Java包實現:
- javax.xml.bind 包定義直接和內容類一起使用的抽象類和接口。
javax.xml.bind 包定義Unmarshaller、Validator和Marshaller 類,它們是提供各自操作的輔助對象。
JAXBContext 類是Java應用程序到JAXB框架的入口點。JAXBContext 實例為反編組、編組和驗證操作使用的JAXB實現將XML元素名綁定到Java內容接口。
javax.xml.bind 包也定義了編組或反編組錯誤出現時、違反約束時及出現其他類型的錯誤時使用的豐富的驗證事件和異常類的層次結構。
- javax.xml.bind.util 包包含工具類,客戶端應用程序可以使用它們來管理編組、反編組和驗證事件。
- javax.xml.bind.helper 包為一些javax.xml.bind 接口提供了部分默認的實現。JAXB的實現能夠擴展這些類并且實現抽象方法。使用JAXB體系結構的應用程序不能直接使用這些API。
下面將詳細介紹JAXB綁定框架中的主要的包javax.bind.xml。
關于javax.xml.bind的更多信息
主要綁定框架包javax.xml.bind提供的三個核心功能是編組、反編組和驗證。到綁定框架的主要的客戶端入口點是JAXBContext 類。
JAXBContext 提供了一個抽象,該抽象可以管理實現反編組、編組和驗證操作必要的XML/Java綁定信息。客戶端應用程序通過newInstance(contextPath)方法得到該類的新實例。例如:
JAXBContext jc = JAXBContext.newInstance( "com.acme.foo:com.acme.bar" );contextPath 參數包含一個Java包名,這些包包含模式派生的接口—特別是JAXB綁定編譯器產生的接口。該參數值初始化JAXBContext 對象,使得它能夠管理模式派生的接口。為此目的,JAXB提供程序實現必須提供一個包含下列特征的實現類:
public static JAXBContext createContext( String contextPath, ClassLoader classLoader ) ??????throws JAXBException;注意:在每個包含模式派生類的包中,JAXB提供程序實現必須生成一個jaxb.properties 文件。該屬性文件必須包含一個叫做javax.xml.bind.context.factory 的屬性,它的值是實現createContext API的類的名字。
不一定要將提供程序提供的類分配給javax.xml.bind.JAXBContext,它只是必須提供一個實現 createContext API的類。允許指定多個Java包,JAXBContext 實例允許同時管理多個模式。
關于反編組的更多信息
javax.xml.bind 包中的Unmarshaller 類使得客戶端應用程序能夠將XML數據轉換成Java內容對象樹。模式的unmarshal 方法(在命名空間內)允許將模式中聲明的任何全局XML元素反編組成實例文檔的根。JAXBContext 對象允許在一組模式內合并全局元素(列在contextPath中)。由于模式集中的每個模式屬于不同的命名空間,將模式統一到反編組上下文中是獨立于命名空間的。這意味著客戶端應用程序能夠反編組contextPath 中列出的任何模式的實例XML文檔。例如:
JAXBContext jc = JAXBContext.newInstance( ??"com.acme.foo:com.acme.bar" ); ? Unmarshaller u = jc.createUnmarshaller(); ? FooObject fooObj = ??(FooObject)u.unmarshal( new File( "foo.xml" ) ); // ok ? BarObject barObj = ??(BarObject)u.unmarshal( new File( "bar.xml" ) ); // ok ? BazObject bazObj = ??(BazObject)u.unmarshal( new File( "baz.xml" ) ); ??// error, "com.acme.baz" not in contextPath客戶端應用程序也能明顯地生成Java內容樹而不是反編組現有XML數據。這樣做,應用程序必須能夠存取并了解contextPath 中的每個Java包中模式派生的ObjectFactory 類。對于每個模式派生Java類,將有一個靜態(tài)工廠方法能產生該類型的對象。例如,假設編譯了模式之后,得到一個包含PurchaseOrder 模式派生接口的包com.acme.foo 。要創(chuàng)建這類對象,客戶端應用程序將使用下列工廠方法:
ObjectFactory objFactory = new ObjectFactory(); ? com.acme.foo.PurchaseOrder po = ??objFactory.createPurchaseOrder();注意:由于當contextPath 上有多個包時,會產生多個ObjectFactory 類,所以如果你有多個contextPath上的包,在引用某個包中的ObjectFactory 類時,必須使用完整的包名。
一旦客戶端應用程序有模式派生對象的實例,它就能使用賦值方法來設置它的內容。
注意:JAXB 提供程序實現必須在每個包中生成一個類,這些包包含ObjectFactory 包的必要的對象工廠方法和newInstance( javaContentInterface ) 方法。
關于編組的更多信息
javax.xml.bind 包中的Marshaller 類使得客戶端應用程序能夠將Java內容樹轉換成XML數據。編組一個使用工廠方法人為創(chuàng)建的內容樹和反編組操作得到的內容樹之間沒有什么區(qū)別。客戶端能夠將Java內容樹編組回到java.io.OutputStream 或java.io.Writer的XML數據中。編組過程能夠在注冊的ContentHandler 中生成SAX2 事件流或生成DOM Node 對象。
下面是一個簡單的例子,它反編組一個XML文檔,然后在將它編組回去:
JAXBContext jc = JAXBContext.newInstance( "com.acme.foo" ); ? // unmarshal from foo.xml Unmarshaller u = jc.createUnmarshaller(); FooObject fooObj = ??(FooObject)u.unmarshal( new File( "foo.xml" ) ); ? // marshal to System.out Marshaller m = jc.createMarshaller(); m.marshal( fooObj, System.out );默認情況下,在java.io.OutputStream 或 java.io.Writer中生成XML數據時,Marshaller使用UTF-8 編碼。使用setProperty API 改變編組操作中輸出的編碼。客戶端應用程序提供W3C XML 1.0 推薦中定義的有效的字符編碼名(http://www.w3.org/TR/2000/REC-xml-20001006#charencoding) 并且你的Java平臺支持它。
在調用編組API之前,不要求客戶端應用程序驗證Java內容樹。同樣,也不要求根據源模式驗證Java內容樹以便將它編組回XML數據。不同的JAXB提供程序支持編組不同層的無效Java內容樹,然而,所有的JAXB提供程序必須能夠將有效的內容樹編組成XML數據。當JAXB提供程序由于無效的內容而不能完成編組操作時必須拋出MarshalException 。一些JAXB提供程序將完全支持編組無效內容,而其他一些將在遇到第一個驗證錯誤后就失效。
表 9-2 列出了Marshaller 類支持的屬性
| 表 9-2? ?Marshaller 屬性 | |
| 屬性 | 描述 |
| jaxb.encoding | 值必須是java.lang.String;這是編組XML數據時使用的輸出編碼。默認情況下,如果沒有指定它的屬性,Marshaller將使用"UTF-8" |
| jaxb.formatted.output | 值必須是java.lang.Boolean。它控制Marshaller是否使用行分隔和縮進格式化結果XML數據。如果它的值為true表示易讀縮進的XML數據,如果值為false表示未格式化的XML數據。如果沒有指定該屬性,Marshaller的默認值為false (unformatted) |
| jaxb.schemaLocation | 值必須是java.lang.String;它允許客戶端應用程序指定生成的XML數據中的xsi:schemaLocation屬性。W3C XML Schema部分0:入門的第5.6節(jié)中通過一種易于理解的、非標準的形式介紹了schemaLocation屬性值的格式,并且在W3C XML Schema Part 1:結構的第2.6節(jié)中規(guī)定了該屬性值的格式 |
| jaxb.noNamespaceSchemaLocation | 值必須是java.lang.String;允許客戶端應用程序指定生成的XML數據中的xsi:noNamespaceSchemaLocation屬性 |
關于驗證的更多信息
javax.xml.bind 包中的Validator 類主要用來在運行時控制對內容樹的驗證。當反編組過程結合了驗證,并且驗證成功,沒有產生任何驗證錯誤,那么就能確保輸出的文檔和結果內容樹是有效的。相對比,編組過程中并不進行驗證。如果僅僅編組有效的內容樹,這就能保證相對于源模式來說,生成的XML文檔總是有效的。
一些XML解析器如SAX和DOM允許取消模式驗證功能,并且在一些情況下,為了提高處理速度并且/或者為了處理包含無效或不完整的內容的文檔,你可能希望取消模式驗證。通過在能使用JAXB的應用程序中選澤的異常處理程序,JAXB支持這些處理方案。總的說來,如果一個JAXB實現不能確切完成反編組或編組,它將拋出一個異常,終止處理。
注意:Validator 類負責管理On-Demand驗證(如下所示)。Unmarshaller 類負責管理反編組操作中的 Unmarshal-Time 驗證。雖然沒有正式的方法能夠在編組操作中啟動驗證,Marshaller 可以監(jiān)測錯誤,將它報告給它上面注冊的ValidationEventHandler 。
JAXB客戶端可以實現兩類驗證:
- Unmarshal-Time 驗證 使得客戶端應用程序能夠接收將XML數據反編組到Java內容樹時監(jiān)測到的驗證錯誤消息和警告,并且跟驗證的其他類型完全正交。使用Unmarshaller.setValidating方法來啟動或終止它。所有的JAXB提供程序都要支持該操作。
- On-Demand 驗證 使得客戶端應用程序能夠接收Java內容樹中監(jiān)測到的驗證錯誤和警告。這點上,客戶端應用程序能夠在Java內容樹(或者它的任何子樹)上調用Validator.validate 方法。所有的JAXB提供程序都要支持該操作。
如果客戶端應用程序沒有在調用驗證、反編組或編組方法之前就在它的Validator 、Unmarshaller或 Marshaller 上設置事件處理程序,那么默認的事件處理程序將接收遇到的任何錯誤通知。在遇到第一個錯誤或致命錯誤后,默認的事件處理程序將掛起當前操作 (但是在接收到警告后將繼續(xù)該操作)
有三種方法能夠處理反編組、驗證和編組操作過程中遇到的事件:
- 使用默認的事件處理程序。
如果沒有通過Validator、Unmarshaller或Marshaller上的setEventHandler API設置事件處理程序,將會使用默認的事件處理程序。
- 實現并注冊一個自定義的事件處理程序。
需要復雜的事件處理的客戶端應用程序能夠實現ValidationEventHandler 接口并使用Unmarshaller 和/或 Validator注冊它。
- 使用ValidationEventCollector 工具。
為了方便,提供一個特定的事件處理程序,該處理程序僅僅收集反編組、驗證和編組操作中創(chuàng)建的ValidationEvent 對象,并且將它們作為java.util.Collection返回給客戶端應用程序。
根據客戶端應用程序的配置,使用不同的方法來處理驗證事件。然而,在一些情況下,JAXB提供程序不能正確地監(jiān)測并報告錯誤。在這些情況下,JAXB提供程序將ValidationEvent 的驗證性設置成 FATAL_ERROR ,表明將終止反編組、驗證和編組操作。在收到致命錯誤的通知后,默認的事件處理程序和ValidationEventCollector工具類必須終止處理。接收到致命錯誤的通知后,支持它們自己的ValidationEventHandler 客戶端應用程序必須也終止處理。如果不終止處理,將會出現意想不到的情況。
XML Schema
由于XML模式是JAXB處理模型的一個重要的組件——并且由于其他數據綁定性能如JAXP使用DTD而不用模式——因此在這里了解一下XML模式的基本概念和它們的工作原理很有用。
XML Schema是描述XML文檔中允許的元素、屬性、實體和關系的強大的方法。DTD的一個更加強壯的選擇,XML模式的目標是定義XML文檔的類,該類必須遵守一組特定的結構和數據約束——也就是說,你可能希望為面向章的書、在線采購系統或個人數據庫定義不同的模式。在JAXB上下文中,將包含受到XML模式約束的XML文檔稱作文檔實例,并且將文檔實例內部的結構和數據叫做內容樹。
注意:實際上,術語“文檔”并不總是精確的,因為XML實例文檔不一定要是形式完整的、自立的文檔文件;相反它具有流的形式,這些流可以是應用程序之間傳遞的數據、數據庫字段集合、XML信息集合,其中信息塊包含了描述它們在模式結構中的位置的足夠信息。
下面的例子代碼來自于W3C Schema 部分 0:入門(http://www.w3.org/TR/2001/REC-xmlschema-0-20010502/),顯示了一個XML文檔po.xml,是一個簡單的購買訂單。
<?xml version="1.0"?>
<purchaseOrder orderDate="1999-10-20">
??<shipTo country="US">
????<name>Alice Smith</name>
????<street>123 Maple Street</street>
????<city>Mill Valley</city>
????<state>CA</state>
????<zip>90952</zip>
??</shipTo>
??<billTo country="US">
????<name>Robert Smith</name>
????<street>8 Oak Avenue</street>
????<city>Old Town</city>
????<state>PA</state>
????<zip>95819</zip>
??</billTo>
<comment>Hurry, my lawn is going wild!</comment>
??<items>
????<item partNum="872-AA">
??????<productName>Lawnmower</productName>
??????<quantity>1</quantity>
??????<USPrice>148.95</USPrice>
??????<comment>Confirm this is electric</comment>
????</item>
????<item partNum="926-AA">
??????<productName>Baby Monitor</productName>
??????<quantity>1</quantity>
??????<USPrice>39.98</USPrice>
??????<shipDate>1999-05-21</shipDate>
????</item>
??</items>
</purchaseOrder>
根元素purchaseOrder包含子元素shipTo, billTo、comment和items。除了comment之外的所有子元素包含其他子元素。樹的葉子是子元素,如name, street、city和state,它們不包含任何子元素。包含其他子元素或能接受屬性的元素叫做復合類型。僅包含PCDATA并且沒有子元素的元素叫做簡單類型。
下面的采購模式中定義了po.xml中的復雜類型和一些簡單類型。同樣,該例子模式來自于W3C Schema 部分 0:入門(http://www.w3.org/TR/2001/REC-xmlschema-0-20010502/).
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="purchaseOrder" type="PurchaseOrderType"/>
<xsd:element name="comment" type="xsd:string"/>
<xsd:complexType name="PurchaseOrderType">
??<xsd:sequence>
????<xsd:element name="shipTo" type="USAddress"/>
????<xsd:element name="billTo" type="USAddress"/>
????<xsd:element ref="comment" minOccurs="0"/>
????<xsd:element name="items" type="Items"/>
??</xsd:sequence>
??<xsd:attribute name="orderDate" type="xsd:date"/>
</xsd:complexType>
?
<xsd:complexType name="USAddress">
??<xsd:sequence>
????<xsd:element name="name" type="xsd:string"/>
????<xsd:element name="street" type="xsd:string"/>
????<xsd:element name="city" type="xsd:string"/>
????<xsd:element name="state" type="xsd:string"/>
????<xsd:element name="zip" type="xsd:decimal"/>
??</xsd:sequence>
??<xsd:attribute name="country" type="xsd:NMTOKEN"
??????fixed="US"/>
</xsd:complexType>
?
<xsd:complexType name="Items">
??<xsd:sequence>
????<xsd:element name="item" minOccurs="1"
??????????????maxOccurs="unbounded">
??????<xsd:complexType>
????????<xsd:sequence>
??????????<xsd:element name="productName"
????????????????????type="xsd:string"/>
??????????<xsd:element name="quantity">
????????????<xsd:simpleType>
??????????????<xsd:restriction base="xsd:positiveInteger">
????????????????<xsd:maxExclusive value="100"/>
??????????????</xsd:restriction>
????????????</xsd:simpleType>
??????????</xsd:element>
??????????<xsd:element name="USPrice" type="xsd:decimal"/>
??????????<xsd:element ref="comment" minOccurs="0"/>
??????????<xsd:element name="shipDate" type="xsd:date"
????????????????????minOccurs="0"/>
????????</xsd:sequence>
????????<xsd:attribute name="partNum" type="SKU"
????????????????????use="required"/>
??????</xsd:complexType>
????</xsd:element>
??</xsd:sequence>
</xsd:complexType>
?
<!-- Stock Keeping Unit, a code for identifying products -->
<xsd:simpleType name="SKU">
??<xsd:restriction base="xsd:string">
????<xsd:pattern value="/d{3}-[A-Z]{2}"/>
??</xsd:restriction>
</xsd:simpleType>
?
</xsd:schema>
在本例中,模式同DTD一樣包含main或根schema元素和幾個子元素element、complexType和simpleType。和DTD不同,該模式也被指定成屬性數據類型,如decimal、date、fixed和string。模式也受到如pattern value、minOccurs和positiveInteger的約束。在DTD中,只能指定文本數據(PCDATA和CDATA)的數據類型, XML模式支持更加復雜的文本和數值數據類型和約束,這些在Java語言中都有直接對應部分。
注意,本模式中的每個元素都有前綴xsd:,它和W3C XML Schema 命名空間相關。為此,命名空間聲明,xmlns:xsd="http://www.w3.org/2001/XMLSchema", 聲明的是schema元素的一個屬性。
支持命名空間是XML Schema的另一個重要的特征,因為它為區(qū)分根據不同模式書寫的元素提供了一個方法或有其他不同的用途,但是它們可能和文檔中的其他元素有相同的名字。例如,假設你在你的模式中定義兩個命名空間,一個是foo,另外一個是bar。結合兩個XML 文檔,一個來自于開賬單數據庫,另一個來自于運送數據庫,每個都建立在不同的模式下。通過在模式中指定命名空間,你可以區(qū)分foo:address和bar:address。
表示XML內容
本節(jié)介紹JAXB 如何將XML內容表示成Java對象。本節(jié)主題如下:
·?? 將XML名字綁定到Java標識符
·?? XML模式的Java表示
將XML名字綁定到Java標識符
XML模式語言使用XML名字——與XML1.0(第二版本) (http://www.w3.org/XML/)中定義的用來標識模式組件的名字產品匹配的字符串。該字符串集合比有效的Java類、方法和約束標識符的集合大。要解決該差異,JAXB使用幾個名字-映射算法。
JAXB名字-映射算法根據標準Java API設計指南將XML名字映射到Java標識符,生成保留了到相應模式連接的標識符,并且不太可能產生沖突。
參考第10章,查看如何改變默認XML名字映射。查看JAXB規(guī)范附錄C中關于JAXB命名算法的完整細節(jié)。
XML模式的Java表示
JAXB支持組合Java包中生成的類和接口。一個包包括:
·?? 名字,直接來自于XML命名空間URI或由XML命名空間URI綁定自定義指定。
·?? 一組Java內容接口,表示模式中聲明的內容模型。
·?? 一組Java元素接口,表示模式中出現的元素聲明。
·?? 包含如下內容的一個ObjectFactory類:
o????? 每個Java內容接口的實例工廠方法和包中的Java元素接口,例如,給定一個叫做Foo的Java內容接口,取得的工廠方法是:
????public Foo createFoo() throws JAXBException;o????? 動態(tài)實例工廠分配器,創(chuàng)建指定的Java內容接口的一個實例,例如:
?? ??????public Object newInstance(Class javaContentInterface) ???????? throws JAXBException;o????? getProperty和setProperty API ,它們允許操縱指定提供程序的屬性。
·?? typesafe 枚舉類集合
·?? 包 javadoc
綁定XML Schema
本節(jié)介紹了JAXB使用的默認的XML-到-Java綁定。通過自定義綁定聲明可以通過自定義的綁定聲明全局覆蓋或逐層覆蓋所有這些綁定。本節(jié)主題如下:
·?? 簡單類型定義
·?? 默認的數據類型綁定
·?? 默認的綁定規(guī)則摘要
查看JAXB 規(guī)范,以獲得JAXB綁定的完整信息。
簡單類型定義
使用簡單類型定義的模式組件通常和Java 屬性綁定。由于有多種這類模式組件,下列Java特征屬性(在模式組件中很常見)包括:
·?? 基本類型
·?? 集合類型,如果有的話
·?? 謂詞
其他Java特征屬性是使用simple 類型定義在模式組件中指定的。
默認的數據類型綁定
Java語言提供了比XML模式更加豐富的數據類型集。表 9-3 列出了XML數據類型到JAXB中的Java數據類型的映射。
| 表 9-3 ?XML模式內置數據類型的JAXB映射 | |
| XML Schema 類型 | Java數據類型 |
| xsd:string | java.lang.String |
| xsd:integer | java.math.BigInteger |
| xsd:int | int |
| xsd.long | long |
| xsd:short | short |
| xsd:decimal | java.math.BigDecimal |
| xsd:float | float |
| xsd:double | double |
| xsd:boolean | Boolean |
| xsd:byte | byte |
| xsd:Qname | javax.xml.namespace.QName |
| xsd:dateTime | java.util.Calendar |
| xsd:base64Binary | byte[] |
| xsd:hexBinary | byte[] |
| xsd:unsignedInt | long |
| xsd:unsignedShort | int |
| xsd:unsignedByte | short |
| xsd:time | Java.util.Calendar |
| xsd:date | Java.util.Calendar |
| xsd:anySimpleType | Java.lang.String |
默認的綁定規(guī)則摘要
JAXB綁定模型遵守下列默認的綁定規(guī)則:
·?? 將下列內容綁定到Java包:
o????? XML 命名空間URI
·?? 將下列XML模式組件綁定到Java內容接口:
o????? 命名的復雜類型
o????? 元素聲明中匿名的內部類型定義
·?? 綁定到類型安全枚舉類:
o????? 一個命名的簡單類型定義,它有來自"xsd:NCName" 的基本類型,并且有枚舉面。
·?? 將下列XML Schema組件綁定到Java Element接口:
o????? Element 接口的全局元素聲明
o????? 能夠插入到全局內容列表的本地元素聲明
·?? 綁定到Java屬性:
o????? 使用的屬性
o????? 元素引用或本地元素聲明的術語微粒
·?? 將重復出現和復雜的類型定義的模型組和混合的{content type}綁定到:
o????? 通用內容屬性;具有Java實例表示元素信息項和字符數據項的列表內容屬性。
自定義JAXB綁定
使用自定義的綁定聲明可以在全局范圍或逐層地覆蓋默認的JAXB綁定。如前面所介紹的,JAXB 使用默認的綁定規(guī)則,可以通過下面兩種方法可以自定義這些綁定規(guī)則:
·?? 源XML模式的內部注釋
·?? 傳遞給JAXB綁定編譯器的外部綁定自定義文件中的聲明
自定義JAXB綁定聲明也能不受XML schema中的XML規(guī)范約束自定義生成的JAXB類,讓它包括特定于Java改進,如類和包名映射。
你不需要為模式中的每個聲明提供一個綁定指令來生成Java類。例如,綁定編譯器使用通用的名字影射算法將XML名字綁定到Java編程語言能夠接受的名字。然而,如果在類中想要使用不同的名字模式,你可以明確自定義綁定聲明讓綁定編譯器生成不同的名字。在綁定聲明中可以進行許多其他自定義,包括:
·?? 命名包、衍生類和方法
·?? 給衍生類中的方法分配類型
·?? 選擇將哪個元素綁定到類
·?? 確定如何將屬性和元素聲明綁定到適當內容類的屬性
·?? 選擇每個屬性值或內容規(guī)范的類型
注意: 依賴于默認的JAXB綁定行為而不是為Java表示的每個XML Schema組件作出綁定聲明使得它能夠方便地跟上源模式中的變化。在多數情況下, 默認的規(guī)則非常強壯,所以不需要任何自定義的綁定聲明就能產生可用的綁定。
第10章中給出了自定義JAXB綁定的代碼例子。
作用域
當在綁定聲明中定義自定義值時,就涉及到作用域。自定義值的作用域就是應用它的模式元素集合。如果將一個自定義值應用到一個模式元素,那么該模式元素就在自定義值的作用域內。
表 9-4 列出了自定義的綁定的四個作用域。
| 表9-4 自定義綁定的作用域 | |
| 作用域 | 描述 |
| Global | <globalBindings>中定義的自定義值具有全局作用域。全局作用域覆蓋了源模式中的所有模式元素和(遞歸的)源模式中包括或導入的任何模式 |
| Schema | <schemaBindings>中定義的自定義值具有模式作用域。模式作用域覆蓋了模式的目標命名空間的所有模式元素 |
| Definition | 類型定義的綁定聲明中的自定義值和全局聲明具有定義作用域。定義作用域覆蓋了引用類型定義或全局聲明的所有模式元素 |
| Component | 如果自定義值僅應用到綁定聲明注釋的模式元素,綁定聲明中的自定義值具有組件作用域 |
作用域繼承
不同的作用域形成了一個分類系統。該分類系統定義了自定義值的繼承和覆蓋語義。一個作用域內的自定義值被另一個作用域的綁定聲明繼承使用,下面是繼承的層次關系:
·?? 模式作用域內的模式元素繼承全局作用域內定義的自定義值。
·?? 定義作用域內的模式元素繼承模式或全局作用域內定義的自定義值。
·?? 組件作用域內的模式元素繼承定義、模式或全局作用域內定義的自定義值。
相似的,一個作用域內的自定義值能夠覆蓋繼承自另一個作用域的自定義值,如下所示:
·?? 模式作用域內的值覆蓋繼承自全局作用域的值。
·?? 定義作用域內的值覆蓋繼承自模式作用域或全局作用域的值。
·?? 組件作用域的值覆蓋繼承自定義、模式或全局作用域的值。?
?
?
==============================
用JAXB生成一個XML文檔
開發(fā)者在線 Builder.com.cn 更新時間:2008-04-14
本文關鍵詞:文檔 xml JAXB JAVA
?一個XML 模式(Schema)用XML語法表達了一個XML文檔的結構。J2EE的開發(fā)者也許會需要一個符合XML模式的XML文檔。Java XML綁定架構(JAXB)提供了一個綁定編譯器,xjc,來從一個XML模式中生成Java類。用JAXB的xjc生成的Java類代表了在XML模式中不同的元素和復雜類型(complexType)。(一個復雜類型通過指定屬性和元素內的元素來提供對一個元素的限定)。一個符合XML模式的XML文檔可以從這些Java類中構建出來。
??????在這篇教程中,作者使用了JAXB用來從一個XML模式中生成Java類。這些Java類將會生成一個范例XML文檔。這篇文章由以下幾個部份組成:
1.預設置
2.概述
3.從XMl模式中生成Java類
4.從Java類中生成一個XML文檔
????? 預設置
????? 為了用JAXB從一個XML模式中生成Java類,JAXB API類庫和xjc工具應該存在CLASSPATH環(huán)境變量中。將Java Web服務開發(fā)包 (JWSDP) 1.5裝入一個安裝目錄中。將下列的.jar文件加入CLASSPATH環(huán)境變量中。
·<JWSDP>/jaxb/lib/jaxb-api.jar
·<JWSDP>/jaxb/lib/jaxb-impl.jar
·<JWSDP>/jaxb/lib/jaxb-libs.jar
·<JWSDP>/jaxb/lib/jaxb-xjc.jar
·<JWSDP>/jwsdp-shared/lib/namespace.jar
·<JWSDP>/jwsdp-shared/lib/jax-qname.jar
·<JWSDP>/jwsdp-shared/lib/relaxngDatatype.jar
????? <JWSDP>是Java Web服務開發(fā)包1.5的安裝目錄。把<JWSDP>/jaxb/bin加入PATH環(huán)境變量中。<JWSDP>/jaxb/bin目錄中包含了xjc編譯器。把<JWSDP>/jwsdp-shared/bin目錄加入到PATH環(huán)境變量中。<JWSDP>/jwsdp-shared/bin目錄中包含了setenv的批處理文件,它設置了JAVA_HOME, ANT_HOME和JWSDP_HOME這幾個環(huán)境變量。
?????? 概述
????? JAXB生成對應著XML頂層元素和頂層復雜類型元素的Java類和接口。在一個XML模式中,一個元素由<xs:element/>表示,一個復雜類型元素由<xs:complexType/>表示。這篇教程列舉了一個能夠表示一篇在科學雜志上發(fā)表的文章的示例模式,同時這個示例模式將會被JAXB綁定編譯器編譯。XML模式,catalog.xsd,如下:
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="catalog" type="catalogType"/>
<xsd:complexType name="catalogType">?
<xsd:sequence>??
<xsd:element ref="journal"? minOccurs="0" maxOccurs="unbounded"/>?
</xsd:sequence>?
<xsd:attribute name="section" type="xsd:string"/>?
<xsd:attribute name="publisher" type="xsd:string"/>
</xsd:complexType>
<xsd:element name="journal" type="journalType"/>
<xsd:complexType name="journalType">?
<xsd:sequence>??
<xsd:element ref="article"? minOccurs="0" maxOccurs="unbounded"/>?
</xsd:sequence>
</xsd:complexType>
<xsd:element name="article" type="articleType"/>
<xsd:complexType name="articleType">?
<xsd:sequence>??
<xsd:element name="title" type="xsd:string"/>??
<xsd:element name="author" type="xsd:string"/>?
</xsd:sequence>?
<xsd:attribute name="level" type="xsd:string"/>?
<xsd:attribute name="date" type="xsd:string"/>
</xsd:complexType></xsd:schema>
????? 一些XML模式的構造不被JAXB支持。如果這些不被支持的構造包含在了模式中,那么當你試圖用xjc來生成Java類時將會報錯。下列模式元素不被支持:xs:any, xs:anyAttribute, xs:notation, xs:redefine, xs:key, xs:keyref, 和 xs:unique. 下列模式的屬性不被支持: complexType.abstract, element.abstract, element.substitutionGroup, xsi:type, complexType.block, complexType.final, element.block, element.final, schema.blockDefault, 和 schema.finalDefault.
生成Java類
????? xjc工具基于此模式來綁定一個模式到Java類。針對本文的示例模式來進行綁定的命令是:
>xjc catalog.xsd
????? xjc命令行接口的一些選項列如下:
-nv??????? 對于輸入的模式不執(zhí)行嚴格的XML驗證
-b <file>??????? 指定外部的綁定文件
-d <dir>??????? 指定生成的文件的存放路徑
-p <pkg>??????? 指定目標包
-classpath <arg>???????? 指定classpath
-use-runtime <pkg>??????? impl.runtime包不被生成
-xmlschema??????? 輸入的模式是一個W3C XML模式(默認)
?????? 對于示例模式catalog.xsd來說,xjc將會生成45個類,顯示在如下xjc的輸出中:
parsing a schema...
compiling a schema...
generatedimplruntimeErrorHandlerAdaptor.java
generatedimplruntimeMSVValidator.java
generatedimplruntimeNamespaceContext2.java
generatedimplruntimeUnmarshallableObject.java
generatedimplruntimeMarshallerImpl.java
generatedimplruntimeValidationContext.java
generatedimplruntimeUnmarshallerImpl.java
generatedimplruntimeDefaultJAXBContextImpl.java
generatedimplruntimeContentHandlerAdaptor.java
generatedimplruntimeGrammarInfoFacade.java
generatedimplruntimeUnmarshallingContext.java
generatedimplruntimeUnmarshallingEventHandlerAdaptor.java
generatedimplruntimeXMLSerializable.java
generatedimplruntimeDiscarder.java
generatedimplruntimePrefixCallback.java
generatedimplruntimeSAXMarshaller.java
generatedimplruntimeNamespaceContextImpl.java
generatedimplruntimeUnmarshallingEventHandler.java
generatedimplruntimeGrammarInfo.java
generatedimplruntimeInterningUnmarshallerHandler.java
generatedimplruntimeValidatableObject.java
generatedimplruntimeGrammarInfoImpl.java
generatedimplruntimeValidatingUnmarshaller.java
generatedimplruntimeValidatorImpl.java
generatedimplruntimeSAXUnmarshallerHandlerImpl.java
generatedimplruntimeXMLSerializer.java
generatedimplruntimeUtil.java
generatedimplruntimeSAXUnmarshallerHandler.java
generatedimplruntimeAbstractUnmarshallingEventHandlerImpl.java
generatedimplArticleImpl.java
generatedimplArticleTypeImpl.java
generatedimplCatalogImpl.java
generatedimplCatalogTypeImpl.java
generatedimplJAXBVersion.java
generatedimplJournalImpl.java
generatedimplJournalTypeImpl.java
generatedArticle.java
generatedArticleType.java
generatedCatalog.java
generatedCatalogType.java
generatedJournal.java
generatedJournalType.java
generatedObjectFactory.java
generatedbgm.ser
generatedjaxb.properties
?? 對于示例XML模式中的每個頂層xs:element和頂層xs:complexType,都對應地生成了一個Java接口和一個Java類。同時也創(chuàng)建了一個工廠類(ObjectFactory.java),包含了創(chuàng)建接口對象的方法。可以在在篇文章的示例代碼文件jaxb-java-resources.zip中找到ObjectFactory.java類。
????? Catalog.java是對應頂層元素catalog生成的接口。從模式的元素中生成的接口擴展了javax.xml.bin.Elemnt類。
????? Catalog.java:
package generated;
public interface Catalog??
extends javax.xml.bind.Element, generated.CatalogType{}
????? CatalogType.java是對應頂層復雜元素catalogType生成的接口。CatalogType接口對應catalog元素的每個屬性指定了setter和getter方法,還有對應catalog元素中的journal元素的一個getter方法。
????? CatalogType.java:
package generated;
public interface CatalogType
{???
java.lang.String getSection();???
void setSection(java.lang.String value);???
java.util.List getJournal();???
java.lang.String getPublisher();???
void setPublisher(java.lang.String value);
}
?
????? CatalogImpl.java 和CatalogTypeImpl.java是分別對應Catalog.java 和 CatalogType.java接口的實現類。
????? 從Java類中創(chuàng)建一個XML文檔
????? 這一節(jié)中,一個示例XMl文檔將會通進JAXB從Java類被創(chuàng)建。示例XML文檔,catalog.xml,如下顯示:
<?xml version="1.0" encoding="UTF-8"?>
<catalog xmlns="http://www.w3.org/2001/XMLSchema-Instance"??????? section="Java Technology"??????? publisher="IBM? developerWorks">????
<journal>????????????????
<article level="Intermediate"? date="January-2004" >?????????
<title>Service Oriented Architecture Frameworks </title>??????????
<author>Naveen Balani</author>??????
</article>?????
<article level="Advanced" date="October-2003"? >?????????
<title>Advance DAO Programming</title>??????????
<author>Sean Sullivan</author>??????
</article>??????
<article level="Advanced" date="May-2002"? >?????????
<title>Best Practices in EJB Exception Handling? </title>?????????
<author>Srikanth Shenoy??? </author>??????
</article>???
</journal>
</catalog>
????? 從Java類中創(chuàng)建一個CatalogImpl類, 并且使用一個Marshaller(排列者)將CatalogImpl序列化來生成一個XML文檔。
????? 創(chuàng)建Marshaller(排列者)
????? 首先,導入javax.xml.bind包,其中包含了Marshaller, UnMarshaller, 和 JAXBContext類。Marshaller類用來將一個Java類轉換為XML數據。UnMarshaller類轉換一個XML文檔成Java對象。
import javax.xml.bind.*;
? 創(chuàng)建一個JAXBContext
????? 一個JAXBContext對象被用來實現JAXB綁定框架的操作:marshal, unmarshal和validate。應用使用靜態(tài)方法newInstance(String contextPath)來創(chuàng)建一個新實例(對象)。contextPath指明一組由模式生成的接口的包名。
JAXBContext jaxbContext=JAXBContext.newInstance("generated");
????? 目錄generated包含了JAXB生成的類和接口
????? 使用createMarshaller方法創(chuàng)建一個Marshaller。Marshaller類重載了marshal方法,可以將Java對象序列化(也就是,轉換一個Java對象到XML數據)成SAX2事件,文檔對象模型(DOM),OutputStream, javax.xml.transform.Result或者java.io.Writer對象。
Marshaller marshaller=jaxbContext.createMarshaller();
????? 為XML文檔創(chuàng)建一個Java對象:CatalogImpl
????? 為了創(chuàng)建一個Java對象,首選生成一個ObjectFactory。ObjectFactory將會創(chuàng)建一個實現類的實例。對于每一個模式生成的Java類,ObjectFactory中定義了一個靜態(tài)方法來創(chuàng)建一個它的對象。
ObjectFactory factory=new ObjectFactory();
????? 使用ObjectFactory類中的createCatalog來創(chuàng)建一個catalog元素。CatalogImpl是Catalog接口的實現類。
CatalogImpl catalog=(CatalogImpl)(factory.createCatalog());
????? 使用CatalogImpl類中的setSection方法來設置catalog元素的section屬性。
catalog.setSection("Java Technology");
??????用setPublisher方法來設置catalog元素的publisher屬性。
catalog.setPublisher("IBM developerWorks");
????? 為XML文檔創(chuàng)建一個Java對象:JournalImpl和ArticleImpl
????? 用ObjectFactory類中的createJournal方法來創(chuàng)建一個jounal元素。JournalImpl是Journal接口的實現類。
JournalImpl journal=(JournalImpl)(factory.createJournal());
????? 將journal元素加入catalog元素。從CatalogImpl得到JournalImpl的java.util.List,并把journal元素加入到List中。
java.util.List journalList=catalog.getJournal();journalList.add(journal);
????? 使用ObjectFactory類的createArticle方法來創(chuàng)建journal中的article元素。ArticleImpl是Article接口的實現類。
ArticleImpl article=(ArticleImpl)(factory.createArticle());
????? 使用ArticleImpl類中的setLevel方法來設置article元素的level屬性。
article.setLevel("Intermediate");
????? 用setDate方法設置article的date屬性
article.setDate("January-2004");
????? 用setTitle方法創(chuàng)建article元素的title屬性
article.setTitle("Service Oriented Architecture Frameworks");
????? 用setAuthor方法創(chuàng)建article元素的author屬性
article.setAuthor("Naveen Balani");
????? 將article元素加入journal元素中。從JournalImpl中得到ArticleImpl的java.util.List,并將article元素加入List中。
java.util.List? articleList=journal.getArticle(); articleList.add(article);
????? 與創(chuàng)建article元素的過程相類似,其它article元素也將被創(chuàng)建用來生成示例XML文檔catalog.xml
????? 將Java對象序列化為一個XML文檔
????? 用Marshaller類中的marshal方法來將CatalogImpl對象序列化為一個XML文檔。CatalogImpl對象被序列化為一個OutputStream
marshaller.marshal(catalog, new FileOutputStream(xmlDocument));
????? xmlDocument是輸出的XML的java.io.File對象,它代表的是本節(jié)一開始所展示的XML文檔。JAXBConstructor.java,這個程序用來從Java類中生成一個XML文檔,也在這篇文章的示例代碼文件中。
????? 總結
????? JAXB提供了一個綁定編譯器xjc, 從一個模式中生成Java對象,然后這些Java對象可以序列化為一個XML文檔。但是,JAXB有一個限制:它不支持所有的XML模式結構。
JAXB(Java Architecture for XML Binding) 是一個業(yè)界的標準,是一項可以根據XML Schema產生Java類的技術。該過程中,JAXB也提供了將XML實例文檔反向生成Java對象樹的方法,并能將Java對象樹的內容重新寫到XML實例文檔。從另一方面來講,JAXB提供了快速而簡便的方法將XML模式綁定到Java表示,從而使得Java開發(fā)者在Java應用程序中能方便地結合XML數據和處理函數。
編輯本段使用
“xjc”工具可以用來將XML模式或其他類型模式文件(Java 1.6試驗性地支持RELAX NG,DTD以及WSDL)轉換為Java類。Java類使用javax.xml.bind.annotation包下的Java 標注,例如@XmlRootElement和@XmlElement。XML列表序列表示為java.util.List類型的屬性,通過JAXBContext可以創(chuàng)建Marshallers(將Java對象轉換成XML)和Unmarshallers(將XML解析為Java對象)。
此外,JAXB包括了一個“schemagen”工具,能夠執(zhí)行“xjc”的反向操作,通過一組標注的Java類創(chuàng)建一個XML模式。
編輯本段缺省的數據類型綁定
下面的表格列出了JAXB中XML數據類型和Java數據類型的映射。
| XML Schema類型 | Java數據類型 |
| xsd:string | java.lang.String |
| xsd:positiveInteger | java.math.BigInteger |
| xsd:int | int |
| xsd:long | long |
| xsd:short | short |
| xsd:decimal | java.math.BigDecimal |
| xsd:float | float |
| xsd:double | double |
| xsd:boolean | boolean |
| xsd:byte | byte |
| xsd:QName | javax.xml.namespace.QName |
| xsd:dateTime | javax.xml.datatype.XMLGregorianCalendar |
| xsd:base64Binary | byte[] |
| xsd:hexBinary | byte[] |
| xsd:unsignedInt | long |
| xsd:unsignedShort | int |
| xsd:unsignedByte | short |
| xsd:time | javax.xml.datatype.XMLGregorianCalendar |
| xsd:date | javax.xml.datatype.XMLGregorianCalendar |
| xsd:g | javax.xml.datatype.XMLGregorianCalendar |
| xsd:anySimpleType | java.lang.Object |
| xsd:anySimpleType | java.lang.String |
| xsd:duration | javax.xml.datatype.Duration |
| xsd:NOTATION | javax.xml.namespace.QName |
?
?
總結
以上是生活随笔為你收集整理的使用JAXB将XML Schema绑定到Java类的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JDK1.5 与 JDK1.6的新特性
- 下一篇: jaxb int convert to