跳到主要内容

Java XML与JSON转换

在现代应用开发中,XML和JSON是两种最常用的数据交换格式。作为Java开发者,掌握这两种格式之间的转换技术非常重要,因为它可以帮助我们处理各种系统集成场景。本文将详细介绍如何在Java中实现XML和JSON之间的相互转换。

XML与JSON概述

在深入转换技术之前,让我们先简单回顾一下这两种格式:

XML (可扩展标记语言)

  • 基于标签的格式
  • 有严格的结构规范
  • 支持属性、命名空间
  • 较为冗长,但表达能力强

JSON (JavaScript对象表示法)

  • 基于键值对
  • 结构简洁,易于阅读
  • 原生支持数组和对象嵌套
  • 在Web应用中广泛使用

转换的必要性

为什么我们需要在XML和JSON之间进行转换?主要原因包括:

  1. 系统集成:旧系统可能使用XML,而新系统使用JSON
  2. API兼容性:需要同时支持XML和JSON格式的API
  3. 数据迁移:从一种数据存储格式迁移到另一种
  4. 前后端交互:后端可能处理XML,而前端偏好JSON

Java 中的转换方法

使用JAXB和Jackson库

最常用的转换方案是结合使用JAXB (Java Architecture for XML Binding) 和Jackson库。

所需依赖

xml
<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类来表示我们的数据:

java
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的步骤:

java
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的步骤:

java
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对象:

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格式向现代前端应用提供数据:

java
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接口无缝集成。

处理复杂数据结构

当处理嵌套对象和列表时,转换会更加复杂。让我们看一个包含产品列表的购物车示例:

复杂数据模型

java
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方法
// ...
}

处理这类复杂对象的转换示例:

java
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文件时,性能是一个重要因素:

性能优化技巧
  1. 流处理:对大型文件使用流式处理而不是一次性加载到内存
  2. 缓存JAXBContext:JAXBContext创建成本较高,应该重用
  3. 选择适当的解析器:对于大型文件,考虑使用SAX或StAX而不是DOM
  4. 使用压缩:处理大数据时考虑使用GZIP压缩

示例代码-使用StAX处理大型XML:

java
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命名空间

java
@XmlRootElement(namespace = "http://example.org/book")
@XmlAccessorType(XmlAccessType.FIELD)
public class BookWithNamespace {
@XmlElement(namespace = "http://example.org/book")
private String title;
// 其他字段...
}

2. 自定义日期格式

java
import com.fasterxml.jackson.annotation.JsonFormat;

public class BookWithDate {
// 设置日期格式
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
private Date publishDate;
// 其他字段...
}

3. 处理不规则的JSON字段

java
import com.fasterxml.jackson.annotation.JsonProperty;

public class Book {
@JsonProperty("book_title")
private String title;

@JsonProperty("book_author")
private String author;
// 其他字段...
}

总结

本文介绍了Java中XML和JSON之间转换的多种方法:

  1. 使用JAXB和Jackson:通过Java对象作为中间层实现转换
  2. 直接使用Jackson:不需要中间Java对象的更简单方法
  3. 处理复杂结构:嵌套对象和集合的转换
  4. 性能优化:处理大型文件时的最佳实践

掌握XML和JSON之间的转换技术对于系统集成、API开发和数据迁移项目至关重要。随着微服务架构的普及,这种转换能力将变得更为重要。

练习与延伸

  1. 尝试创建一个带有嵌套对象和列表的复杂类,并在XML和JSON之间转换。
  2. 优化XML到JSON的转换流程,确保正确处理特殊字符和CDATA。
  3. 扩展示例代码,增加对XML Schema验证的支持。
  4. 比较不同转换库(如JAXB+Jackson、GSON、org.json等)的性能差异。

参考资源

继续学习,将帮助你更好地处理各种数据交换格式,提升你的Java开发技能!