在前两章我们介绍了Jackson库解析和生成JSON文档的使用方法。在本章中,我们继续介绍如何使用Jackson库解析和生成XML文档。因为Jackson对象映射(Object Mapping)的方法使用非常方便,所以,我们本章重点介绍这种方法。
如果使用Maven管理项目,需要将如下依赖关系加入项目的pom.xml文件中。在解析和生成XML文档时,Jackson代码库依赖于stax2-api和jackson-module-jaxb-annotation代码库。所以,我们需要把它们也添加进来。
<dependency>
<groupId>org.codehaus.woodstox</groupId>
<artifactId>stax2-api</artifactId>
<version>4.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-jaxb-annotations</artifactId>
<version>2.11.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.11.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.11.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.11.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>2.11.1</version>
</dependency>
如果使用Gradle管理项目,需要将如下依赖加入项目的build.gradle文件中。
repositories {
mavenCentral()
}
dependencies {
implementation 'org.codehaus.woodstox:staw2-api:4.2'
implementation 'com.fasterxml.jackson.module:jackson-module-jaxb-annotations:2.11.1'
implementation 'com.fasterxml.jackson.core:jackson-core:2.11.1'
implementation 'com.fasterxml.jackson.core:jackson-databind:2.11.1'
implementation 'com.fasterxml.jackson.core:jackson-annotations:2.11.1'
implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.11.1'
}
XML文档生成的方法与生成JSON文档非常相似。在解析和生成XML时,我们需要使用XmlMapper类。XmlMapper类继承自ObjectMapper类,所以,在解析和生成XML时使用的函数接口是一致的。
例如,我们计划生成如下的XML字符串,根节点的名称为Person。根节点包含name和age两个节点。
<Person>
<name>David</name>
<age>22</age>
</Person>
为了生成上述的XML文档,我们可以创建一个Person类。Person类中包含name和age两个成员变量。在main()函数中,我们在创建了新的XmlMapper对象和Person对象之后,调用writeValueAsString()方法将Person对象转换为相应的XML文档。
import java.io.IOException;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
public class Person {
private String name = null;
private Integer age = null;
public Person(String name, Integer age) {
this.name = name;
this.age = age;
}
// Getters and Setters
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public static void main(String[] args) {
try {
XmlMapper mapper = new XmlMapper();
Person person = new Person("David", 22);
// 生成XML字符串
System.out.println(mapper.writeValueAsString(person));
} catch (IOException ex) {
System.out.println(ex.getMessage());
}
}
}
上述的程序输出为:
<Person xmlns=""><name>David</name><age>22</age></Person>
Jackson库也支持生成多级XML文档。例如,在如下的XML文档中,根节点Person包含department节点;Department节点包含name和code节点。
<Person>
<name>David</name>
<age>22</age>
<department>
<name>Computer Science</name>
<code>CS</code>
</department>
</Person>
为了生成上述的XML文档,我们可以在Person类中添加一个Department类对象的成员变量。
import java.io.IOException;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
public class Department {
private String name = null;
private String code = null;
public Department(String name, String code) {
this.name = name;
this.code = code;
}
// Getters and Setters
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
}
public class Person {
private String name = null;
private Integer age = null;
private Department department = null;
public Person(String name, Integer age, Department department) {
this.name = name;
this.age = age;
this.department = department;
}
// Getters and Setters
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Department getDepartment() {
return this.department;
}
public void setDepartment(Department department) {
this.department = department;
}
public static void main(String[] args) {
try {
XmlMapper mapper = new XmlMapper();
Person person = new Person("David", 22, new Department("Computer Science", "CS"));
// 生成XML字符串
System.out.println(mapper.writeValueAsString(person));
} catch (IOException ex) {
System.out.println(ex.getMessage());
}
}
}
上述的程序输出如下。因为这个XML字符串是以“紧凑”格式输出的。读者可将其拷贝至XML格式化页面,格式化之后阅读其结构和内容。
<Person xmlns=""><name>David</name><age>22</age><department><name>Computer Science</name><code>CS</code></department></Person>
如果无法使得程序中的变量和XML文档中标签的名称保持一致的话,可以使用标签@JacksonXmlProperty来指定标签名称。例如,如果我们将标签名称name和age修改为Name和Age(首字母大写),我们可以在变量的声明处添加标注JacksonXmlProperty。
import java.io.IOException;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
public class Person {
@JacksonXmlProperty(localName = "Name")
private String name = null;
@JacksonXmlProperty(localName = "Age")
private Integer age = null;
public Person(String name, Integer age) {
this.name = name;
this.age = age;
}
// Getters and Setters
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public static void main(String[] args) {
try {
XmlMapper mapper = new XmlMapper();
Person person = new Person("David", 22);
// 生成XML字符串
System.out.println(mapper.writeValueAsString(person));
} catch (IOException ex) {
System.out.println(ex.getMessage());
}
}
}
上述的程序输出为:
<Person xmlns=""><Name>David</Name><Age>22</Age></Person>
标签@JacksonXmlProperty还能用于声明XML标签的属性。例如,我们在下面的XML文档中添加一个属性ns。
<Person ns="namespace">
<name>David</name>
<age>22</age>
</Person>
在Person类中,新增一个成员变量ns,并使用标注@JacksonXmlProperty来标识这个变量是XML标签的一个属性(Attribute)。
import java.io.IOException;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
public class Person {
@JacksonXmlProperty(isAttribute = true)
private String ns = null; // 新增属性ns
private String name = null;
private Integer age = null;
public Person(String ns, String name, Integer age) {
this.ns = ns;
this.name = name;
this.age = age;
}
// Getters and Setters
public String getNs() {
return ns;
}
public void setNs(String ns) {
this.ns = ns;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public static void main(String[] args) {
try {
XmlMapper mapper = new XmlMapper();
Person person = new Person("namespace", "David", 22);
// 生成XML字符串
System.out.println(mapper.writeValueAsString(person));
} catch (IOException ex) {
System.out.println(ex.getMessage());
}
}
}
上述的程序输出为:
<Person xmlns="" ns="namespace"><name>David</name><age>22</age></Person>
与JSON文档不同的是,XML文档不支持数组类型。但是,一个XML元素可以包含多个相同名字的标签。例如,在如下的XML文档中,根节点可能包含两个phone节点来标识这个Person对象包含两个电话号码。
<Person>
<name>David</name>
<age>22</age>
<phone>13900000000</phone>
<phone>13901234567</phone>
</Person>
在源代码中,如果我们使用标注@JacksonXmlElementWrapper来标识phone成员变量,那么,Jackson会将链表phone中的数据一一列出,放在节点Person里面。如果useWrapping的值为true的话,Jackson会在phone节点上额外添加一个节点phone,以保持内容的等级结构。如下所示:
<Person>
<name>David</name>
<age>22</age>
<phone>
<phone>13900000000</phone>
<phone>13901234567</phone>
</phone>
</Person>
这与我们的目标XML文档的结构不一致,因此,我们需要将useWrapping设置为false。
import java.util.List;
import java.util.Arrays;
import java.io.IOException;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
public class Person {
private String name = null;
private Integer age = null;
@JacksonXmlElementWrapper(useWrapping = false) // 设置为false
private List<String> phone = null;
public Person(String name, Integer age, List<String> phone) {
this.name = name;
this.age = age;
this.phone = phone;
}
// Getters and Setters
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public List<String> getPhone() {
return this.phone;
}
public void setPhone(List<String> phone) {
this.phone = phone;
}
public static void main(String[] args) {
try {
XmlMapper mapper = new XmlMapper();
Person person = new Person("David", 22, Arrays.asList("13900000000", "13901234567"));
// 生成XML字符串
System.out.println(mapper.writeValueAsString(person));
} catch (IOException ex) {
System.out.println(ex.getMessage());
}
}
}
上述程序的输出如下。读者可将其拷贝至XML格式化页面,格式化之后阅读其结构和内容。
<Person xmlns=""><name>David</name><age>22</age><phone>13900000000</phone><phone>13901234567</phone></Person>
XML解析的过程是XML生成的逆过程。因此,在定义了数据类之后,就能很容易的将XML字符串转换成Java对象。在XML解析过程中,标注的使用方法与XML生成过程中的使用方法保持一致。例如:
import java.io.IOException;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
public class Person {
private String name = null;
private Integer age = null;
public Person(){
}
public Person(String name, Integer age) {
this.name = name;
this.age = age;
}
// Getters and Setters
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public static void main(String[] args) {
try {
XmlMapper mapper = new XmlMapper();
String xmlStr = "<Person><name>David</name><age>22</age></Person>";
// 解析XML字符串
Person person = mapper.readValue(xmlStr, Person.class);
System.out.println("name=" + person.getName());
System.out.println("age=" + person.getAge());
} catch (IOException ex) {
System.out.println(ex.getMessage());
}
}
}
上述的程序输出为:
name=David
age=22
本章介绍了如何使用Jackson对象映射的方法解析和生成XML文档。因为Jackson库的底层提供了灵活的、可扩展的接口,Jackson自身能够适配解析JSON、XML、YAML和一些常用的文档格式,并且为应用程序提供了简洁的序列化和反序列化接口。使用Jackson代码库,能帮助开发人员在几行代码中完成文档的格式转换,非常方便。
注册用户登陆后可留言