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方法便可达到目的。