Java XML与JSON转换
在现代应用开发中,XML和JSON是两种最常用的数据交换格式。作为Java开发者,掌握这两种格式之间的转换技术非常重要,因为它可以帮助我们处理各种系统集成场景。本文将详细介绍如何在Java中实现XML和JSON之间的相互转换。
XML与JSON概述
在深入转换技术之前,让我们先简单回顾一下这两种格式:
XML (可扩展标记语言)
- 基于标签的格式
- 有严格的结构规范
- 支持属性、命名空间
- 较为冗长,但表达能力强
JSON (JavaScript对象表示法)
- 基于键值对
- 结构简洁,易于阅读
- 原生支持数组和对象嵌套
- 在Web应用中广泛使用
转换的必要性
为什么我们需要在XML和JSON之间进行转换?主要原因包括:
- 系统集成:旧系统可能使用XML,而新系统使用JSON
- API兼容性:需要同时支持XML和JSON格式的API
- 数据迁移:从一种数据存储格式迁移到另一种
- 前后端交互:后端可能处理XML,而前端偏好JSON
Java 中的转换方法
使用JAXB和Jackson库
最常用的转换方案是结合使用JAXB (Java Architecture for XML Binding) 和Jackson库。
所需依赖
<dependencies>
<!-- JAXB API -->
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>3.0.1</version>
</dependency>
<!-- JAXB 实现 -->
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>3.0.1</version>
</dependency>
<!-- Jackson核心库 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.14.2</version>
</dependency>
<!-- Jackson XML模块 -->
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>2.14.2</version>
</dependency>
</dependencies>
定义数据模型
首先,我们需要创建一个JavaBean类来表示我们的数据:
import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType;
import jakarta.xml.bind.annotation.XmlElement;
import jakarta.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "book")
@XmlAccessorType(XmlAccessType.FIELD)
public class Book {
@XmlElement
private String title;
@XmlElement
private String author;
@XmlElement
private int year;
@XmlElement
private double price;
// 默认构造函数(JAXB需要)
public Book() {}
// 带参数构造函数
public Book(String title, String author, int year, double price) {
this.title = title;
this.author = author;
this.year = year;
this.price = price;
}
// Getter和Setter方法
public String getTitle() { return title; }
public void setTitle(String title) { this.title = title; }
public String getAuthor() { return author; }
public void setAuthor(String author) { this.author = author; }
public int getYear() { return year; }
public void setYear(int year) { this.year = year; }
public double getPrice() { return price; }
public void setPrice(double price) { this.price = price; }
}
XML转JSON
以下是将XML转换为JSON的步骤:
import jakarta.xml.bind.JAXBContext;
import jakarta.xml.bind.JAXBException;
import jakarta.xml.bind.Unmarshaller;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.StringReader;
public class XmlToJsonConverter {
public static String convertXmlToJson(String xml) throws Exception {
// 第1步:XML转换为Java对象
JAXBContext jaxbContext = JAXBContext.newInstance(Book.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
Book book = (Book) unmarshaller.unmarshal(new StringReader(xml));
// 第2步:Java对象转换为JSON
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.writeValueAsString(book);
}
public static void main(String[] args) {
try {
String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<book>\n" +
" <title>Java编程思想</title>\n" +
" <author>Bruce Eckel</author>\n" +
" <year>2006</year>\n" +
" <price>128.0</price>\n" +
"</book>";
String json = convertXmlToJson(xml);
System.out.println("转换后的JSON:");
System.out.println(json);
} catch (Exception e) {
e.printStackTrace();
}
}
}
输出结果:
转换后的JSON:
{"title":"Java编程思想","author":"Bruce Eckel","year":2006,"price":128.0}
JSON转XML
下面是将JSON转换为XML的步骤:
import jakarta.xml.bind.JAXBContext;
import jakarta.xml.bind.JAXBException;
import jakarta.xml.bind.Marshaller;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.StringWriter;
public class JsonToXmlConverter {
public static String convertJsonToXml(String json) throws Exception {
// 第1步:JSON转换为Java对象
ObjectMapper objectMapper = new ObjectMapper();
Book book = objectMapper.readValue(json, Book.class);
// 第2步:Java对象转换为XML
JAXBContext jaxbContext = JAXBContext.newInstance(Book.class);
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
StringWriter sw = new StringWriter();
marshaller.marshal(book, sw);
return sw.toString();
}
public static void main(String[] args) {
try {
String json = "{\"title\":\"Java编程思想\",\"author\":\"Bruce Eckel\",\"year\":2006,\"price\":128.0}";
String xml = convertJsonToXml(json);
System.out.println("转换后的XML:");
System.out.println(xml);
} catch (Exception e) {
e.printStackTrace();
}
}
}
输出结果:
转换后的XML:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<book>
<title>Java编程思想</title>
<author>Bruce Eckel</author>
<year>2006</year>
<price>128.0</price>
</book>
使用Jackson直接转换
Jackson库提供了更直接的XML与JSON转换方法,不需要中间Java对象:
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
public class DirectConverter {
public static String xmlToJson(String xml) throws Exception {
// XML转JSON
XmlMapper xmlMapper = new XmlMapper();
JsonNode node = xmlMapper.readTree(xml.getBytes());
ObjectMapper jsonMapper = new ObjectMapper();
return jsonMapper.writeValueAsString(node);
}
public static String jsonToXml(String json) throws Exception {
// JSON转XML
ObjectMapper jsonMapper = new ObjectMapper();
JsonNode node = jsonMapper.readTree(json);
XmlMapper xmlMapper = new XmlMapper();
return xmlMapper.writeValueAsString(node);
}
public static void main(String[] args) {
try {
String xml = "<root><name>张三</name><age>28</age><skills><skill>Java</skill><skill>XML</skill></skills></root>";
String json = xmlToJson(xml);
System.out.println("XML转换为JSON: " + json);
String newXml = jsonToXml(json);
System.out.println("JSON转回XML: " + newXml);
} catch (Exception e) {
e.printStackTrace();
}
}
}
输出结果:
XML转换为JSON: {"name":"张三","age":"28","skills":{"skill":["Java","XML"]}}
JSON转回XML: <ObjectNode><name>张三</name><age>28</age><skills><skill>Java</skill><skill>XML</skill></skills></ObjectNode>
使用Jackson直接转换在处理复杂XML结构时可能会有限制,特别是当XML包含属性、命名空间或特殊格式时。
实际应用场景:Web服务集成
下面是一个更复杂的实际应用示例,展示如何在Web服务中处理XML和JSON格式转换:
场景:对接旧系统XML接口并提供REST API
假设我们需要对接一个提供XML数据的旧系统,但我们的新系统需要以JSON格式向现代前端应用提供数据:
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import java.util.List;
@RestController
@RequestMapping("/api/products")
public class ProductController {
private final RestTemplate restTemplate;
private final XmlToJsonConverter converter;
public ProductController(RestTemplate restTemplate, XmlToJsonConverter converter) {
this.restTemplate = restTemplate;
this.converter = converter;
}
@GetMapping
public String getProducts() {
try {
// 从旧系统获取XML格式的产品数据
String xmlResponse = restTemplate.getForObject(
"http://legacy-system.example.com/products",
String.class
);
// 将XML转换为JSON并返回给前端
return converter.convertXmlToJson(xmlResponse);
} catch (Exception e) {
return "{\"error\":\"" + e.getMessage() + "\"}";
}
}
@PostMapping
public String addProduct(@RequestBody String jsonProduct) {
try {
// 将接收到的JSON转换为XML
String xmlProduct = converter.convertJsonToXml(jsonProduct);
// 将XML发送给旧系统
String response = restTemplate.postForObject(
"http://legacy-system.example.com/products",
xmlProduct,
String.class
);
// 将响应转换为JSON并返回
return converter.convertXmlToJson(response);
} catch (Exception e) {
return "{\"error\":\"" + e.getMessage() + "\"}";
}
}
}
这个控制器实现了一个适配器模式,将新系统的JSON接口与旧系统的XML接口无缝集成。
处理复杂数据结构
当处理嵌套对象和列表时,转换会更加复杂。让我们看一个包含产品列表的购物车示例:
复杂数据模型
import jakarta.xml.bind.annotation.*;
import java.util.List;
@XmlRootElement(name = "cart")
@XmlAccessorType(XmlAccessType.FIELD)
public class ShoppingCart {
@XmlElement
private String customerId;
@XmlElement(name = "product")
@XmlElementWrapper(name = "products")
private List<Product> products;
@XmlElement
private double totalPrice;
// 构造函数、getter和setter方法
// ...
}
@XmlAccessorType(XmlAccessType.FIELD)
public class Product {
@XmlElement
private String id;
@XmlElement
private String name;
@XmlElement
private double price;
@XmlElement
private int quantity;
// 构造函数、getter和setter方法
// ...
}
处理这类复杂对象的转换示例:
import jakarta.xml.bind.JAXBContext;
import jakarta.xml.bind.Marshaller;
import jakarta.xml.bind.Unmarshaller;
import com.fasterxml.jackson.databind.ObjectMapper;
public class ComplexConverter {
public static String convertComplexObjectToJson(ShoppingCart cart) throws Exception {
// 使用ObjectMapper将Java对象转换为JSON
ObjectMapper mapper = new ObjectMapper();
return mapper.writeValueAsString(cart);
}
public static String convertComplexObjectToXml(ShoppingCart cart) throws Exception {
// 使用JAXB将Java对象转换为XML
JAXBContext context = JAXBContext.newInstance(ShoppingCart.class);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
StringWriter writer = new StringWriter();
marshaller.marshal(cart, writer);
return writer.toString();
}
}
性能优化考虑
在处理大型XML或JSON文件时,性能是一个重要因素:
- 流处理:对大型文件使用流式处理而不是一次性加载到内存
- 缓存JAXBContext:JAXBContext创建成本较高,应该重用
- 选择适当的解析器:对于大型文件,考虑使用SAX或StAX而不是DOM
- 使用压缩:处理大数据时考虑使用GZIP压缩
示例代码-使用StAX处理大型XML:
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamReader;
import java.io.StringReader;
public class LargeFileProcessor {
public static void processLargeXml(String xmlFilePath) {
try {
XMLInputFactory factory = XMLInputFactory.newInstance();
XMLStreamReader reader = factory.createXMLStreamReader(
new FileReader(xmlFilePath));
// 逐元素处理XML
while (reader.hasNext()) {
if (reader.next() == XMLStreamReader.START_ELEMENT) {
// 处理元素...
String elementName = reader.getLocalName();
// 根据元素名称进行处理
}
}
reader.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
处理常见问题
在进行XML与JSON转换时,可能会遇到一些常见问题,下面是解决方案:
1. 处理XML命名空间
@XmlRootElement(namespace = "http://example.org/book")
@XmlAccessorType(XmlAccessType.FIELD)
public class BookWithNamespace {
@XmlElement(namespace = "http://example.org/book")
private String title;
// 其他字段...
}
2. 自定义日期格式
import com.fasterxml.jackson.annotation.JsonFormat;
public class BookWithDate {
// 设置日期格式
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
private Date publishDate;
// 其他字段...
}
3. 处理不规则的JSON字段
import com.fasterxml.jackson.annotation.JsonProperty;
public class Book {
@JsonProperty("book_title")
private String title;
@JsonProperty("book_author")
private String author;
// 其他字段...
}
总结
本文介绍了Java中XML和JSON之间转换的多种方法:
- 使用JAXB和Jackson:通过Java对象作为中间层实现转换
- 直接使用Jackson:不需要中间Java对象的更简单方法
- 处理复杂结构:嵌套对象和集合的转换
- 性能优化:处理大型文件时的最佳实践
掌握XML和JSON之间的转换技术对于系统集成、API开发和数据迁移项目至关重要。随着微服务架构的普及,这种转换能力将变得更为重要。
练习与延伸
- 尝试创建一个带有嵌套对象和列表的复杂类,并在XML和JSON之间转换。
- 优化XML到JSON的转换流程,确保正确处理特殊字符和CDATA。
- 扩展示例代码,增加对XML Schema验证的支持。
- 比较不同转换库(如JAXB+Jackson、GSON、org.json等)的性能差异。
参考资源
继续学习,将帮助你更好地处理各种数据交换格式,提升你的Java开发技能!