Java爲處理XML文件和結構提供了多種選擇,目前應用最爲普遍的是JAXB工具庫。JAXB表明了Java處理XML文件的事實上標準,它提供了Java對象與XML文本之間互相轉換的功能。從JRE6開始,JAXB就已經成爲了JRE的內置模塊。java
在JAXB以前,Java處理XML的方式只能是使用DOM解析,而採用這種方式並非一個最優的解決方案,由於DOM解析幾乎不能將XML與Java對象映射起來,全部的值類型都只能映射爲String字符串。JAXB爲XML節點和屬性提供了各類面向對象的處理方式,能夠基於自定義類型、註解等方式將XML轉換成Java對象。api
Java對象能夠經過特定的註解或者依照規範被轉換爲XML,這種轉換成爲映射(mapping)。本教程將經過案例向讀者介紹如下內容:app
本部分將介紹如何將Java對象轉換爲XML以及轉換過程當中的注意事項,這項操做被稱之爲Marshaling. 首先,咱們將業務對象的中的Java域與XML中的元素作一一對應。框架
@XmlType( propOrder = { "name", "capital", "foundation", "continent" , "population"} ) @XmlRootElement( name = "Country" ) public class Country { @XmlElement (name = "Country_Population") public void setPopulation( int population ) { this.population = population; } @XmlElement( name = "Country_Name" ) public void setName( String name ) { this.name = name; } @XmlElement( name = "Country_Capital" ) public void setCapital( String capital ) { this.capital = capital; } @XmlAttribute( name = "importance", required = true ) public void setImportance( int importance ) { this.importance = importance; } ...
這個類中包含了幾個註解,這些註解明確指出了咱們將會建立哪些XML節點。工具
@XmlRootElement
表示root元素@XmlElement
與setter方法結合使用@XmlAttribute
用於爲XML節點添加屬性。這些屬性能夠經過設置required的值來表示是否爲必備的。那麼,如何將具體的Java對象轉換爲XML呢?對此,咱們能夠建立一個JAXBContext並使用其marshal方法來作個demo。ui
Country spain = new Country(); spain.setName( "Spain" ); spain.setCapital( "Madrid" ); spain.setContinent( "Europe" ); spain.setImportance( 1 ); spain.setFoundation( LocalDate.of( 1469, 10, 19 ) ); spain.setPopulation( 45000000 ); /* init jaxb marshaler */ JAXBContext jaxbContext = JAXBContext.newInstance( Country.class ); Marshaller jaxbMarshaller = jaxbContext.createMarshaller(); /* set this flag to true to format the output */ jaxbMarshaller.setProperty( Marshaller.JAXB_FORMATTED_OUTPUT, true ); /* marshaling of java objects in xml (output to file and standard output) */ jaxbMarshaller.marshal( spain, new File( "country.xml" ) ); jaxbMarshaller.marshal( spain, System.out );
基本上來講,這個例子的核心就是JAXBContext,JAXBContext提供了marshal、unmarshal的方法,是咱們使用JAXB API的入口。 在咱們的例子中,咱們提供爲JAXBContext實例提供了須要marshal的類,經過如下代碼實現:this
JAXBContext jaxbContext = JAXBContext.newInstance( Country.class ); Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
以上例子的輸出結果應該是這樣的:spa
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <Country importance="1"> <Country_Name>Spain</Country_Name> <Country_Capital>Madrid</Country_Capital> <Country_Foundation_Date></Country_Foundation_Date> <Country_Continent>Europe</Country_Continent> <Country_Population>45000000</Country_Population> </Country>
上面這個例子咱們實現了基本數據類型轉換爲XML的功能,Fundation_Date元素是空的,咱們接下來會介紹如何解決這個問題。code
看上去並不難,JAXB提供了將各類Java對象轉換爲XML的方法,好比將一個List的country轉換爲XML:orm
@XmlRootElement( name = "Countries" ) public class Countries { List countries; /** * element that is going to be marshaled in the xml */ @XmlElement( name = "Country" ) public void setCountries( List countries ) { this.countries = countries; } }
經過設置一個List來把集合轉換爲XML。該例子的輸出結果爲:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <Countries> <Country importance="1"> <Country_Name>Spain</Country_Name> <Country_Capital>Madrid</Country_Capital> <Country_Foundation_Date></Country_Foundation_Date> <Country_Continent>Europe</Country_Continent> <Country_Population>0</Country_Population> </Country> <Country importance="0"> <Country_Name>USA</Country_Name> <Country_Capital>Washington</Country_Capital> <Country_Foundation_Date></Country_Foundation_Date> <Country_Continent>America</Country_Continent> <Country_Population>0</Country_Population> </Country> </Countries>
處理集合框架的方式有好幾種:
javax.xml.bind.annotation.XMLElementWrapper
註解提供了一種XML包裝器,這個包裝器能夠放置Java集合。javax.xml.bind.annotation.XMLElements
或者javax.xml.bind.annotation.XMLRefs
等表示Java集合的註解,可是這種方式缺少靈活性。這一小節將介紹上一節的逆操做——將XML解析爲Java對象。 假設如下XML是咱們要解析的文本:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <Countries> <Country> <Country_Name>Spain</Country_Name> <Country_Capital>Madrid</Country_Capital> <Country_Continent>Europe</Country_Continent> </Country> <Country> <Country_Name>USA</Country_Name> <Country_Capital>Washington</Country_Capital> <Country_Continent>America</Country_Continent> </Country> <Country> <Country_Name>Japan</Country_Name> <Country_Capital>Tokyo</Country_Capital> <Country_Continent>Asia</Country_Continent> </Country> </Countries>
接下來建立一個程序來讀取這個XML的內容並解析爲Java對象:
File file = new File( "countries.xml" ); JAXBContext jaxbContext = JAXBContext.newInstance( Countries.class ); /** * the only difference with the marshaling operation is here */ Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller(); Countries countres = (Countries)jaxbUnmarshaller.unmarshal( file ); System.out.println( countres );
以上的代碼與上一章提供的Java轉爲XML的代碼並無太多的不一樣。經過JAXBContent建立一個Unmarshaller對象,將XML直接轉換爲Java對象。 這個例子中使用到了Country類,其代碼以下:
@XmlType( propOrder = { "name", "capital", "foundation", "continent" , "population"} ) @XmlRootElement( name = "Country" ) public class Country { @XmlElement (name = "Country_Population") public void setPopulation( int population ) { this.population = population; } @XmlElement( name = "Country_Name" ) public void setName( String name ) { this.name = name; } @XmlElement( name = "Country_Capital" ) public void setCapital( String capital ) { this.capital = capital; } @XmlAttribute( name = "importance", required = true ) public void setImportance( int importance ) { this.importance = importance; } ...
與上一章節中的Country類是如出一轍的。 以上Java代碼的輸出結果以下:
Name: Spain Capital: Madrid Europe Name: USA Capital: Washington America Name: Japan Capital: Tokyo Asia
同理,咱們能夠使用相同的方式Unmarshalling其餘的原始數據類型或者集合類型。
處理沒法直接使用的複雜數據類型的解析和映射時,咱們須要使用適配器的方式來告訴JAXB如何處理這些特定的類型。這裏簡單經過解析和映射java.time.LocalDate
的例子來展現JAXB在處理複雜數據類型上的強大功能。
public class DateAdapter extends XmlAdapter{ public LocalDate unmarshal( String date ) throws Exception { return LocalDate.parse( date ); } public String marshal( LocalDate date ) throws Exception { return date.toString(); } }
以上代碼展現瞭如何經過javax.xml.bind. annotation.adapters.XmlAdapter
對特定的類型進行marshal和unmarshal,在Java代碼中經過如下代碼作映射:
@XmlElement( name = "Country_Foundation_Date" ) @XmlJavaTypeAdapter( DateAdapter.class ) public void setFoundation( LocalDate foundation ) { this.foundation = foundation; }
運行的結果:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <Country importance="1"> <Country_Name>Spain</Country_Name> <Country_Capital>Madrid</Country_Capital> <Country_Foundation_Date>1469-10-19</Country_Foundation_Date> <Country_Continent>Europe</Country_Continent> <Country_Population>45000000</Country_Population> </Country>
經過這種方式,咱們能夠將複雜的類型映射爲XML,咱們只須要實現XmlAdapter接口,並複寫其中的marshal和unmarshal方法便可達到目的。