
在spring boot应用中处理xml数据是常见的任务,jackson库通过其jackson-dataformat-xml模块提供了强大的xml解析能力。然而,对于初学者来说,当xml中包含多个同名且需要被解析为java list集合的元素时,可能会遇到只解析到最后一个元素的问题。本教程将通过一个具体的示例,详细阐述如何正确配置jackson注解来解决这一问题。
考虑以下XML结构:
<?xml version="1.0" encoding="UTF-8" ?>
<cpe-list>
<cpe-item name="John">
<title>xmlread</title>
</cpe-item>
<cpe-item name="Jack">
<title>testtitle</title>
</cpe-item>
</cpe-list>我们的目标是将<cpe-list>下的所有<cpe-item>元素解析到一个Java对象的List<CpeItem>中。
首先,我们需要定义与XML结构相对应的Java POJO(Plain Old Java Object)。
CpeItem代表XML中的<cpe-item>元素。它有一个属性name和一个子元素title。
package com.dependency.demo;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import lombok.Data;
@Data
@JacksonXmlRootElement(localName = "cpe-item")
public class CpeItem {
@JacksonXmlProperty(localName = "name", isAttribute = true)
private String name;
private String title; // Jackson默认会将其映射到同名子元素
}CpeList类代表XML的根元素<cpe-list>,它需要包含一个CpeItem的列表。这是解析多个同名元素的关键。
错误的尝试(仅解析最后一个元素):
最初的尝试可能像这样:
// 错误示例:仅解析最后一个cpe-item
package com.dependency.demo;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import lombok.Data;
import java.util.List; // 即使这里是List,但注解配置不当也会出错
@Data
@JacksonXmlRootElement(localName = "cpe-list")
public class CpeList {
// 假设这样可以,但实际上会失败或只解析最后一个
@JacksonXmlElementWrapper(localName = "cpe-item") // 这里是问题所在
private CpeItem cpeItems; // 或者 List<CpeItem> cpeItems; 但JacksonXmlElementWrapper的配置错误
}上述代码中,如果cpeItems是CpeItem类型,Jackson会尝试将所有<cpe-item>元素映射到这一个字段,结果就是只有最后一个元素被保留。即使将cpeItems改为List<CpeItem>,@JacksonXmlElementWrapper(localName = "cpe-item")的配置也可能导致问题,因为它期望cpe-item是一个包装器元素,而不是列表中的实际元素。
正确的 CpeList 类配置:
为了正确解析XML中的多个<cpe-item>元素到一个List中,我们需要使用@JacksonXmlElementWrapper和@JacksonXmlProperty的组合。
package com.dependency.demo;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import lombok.Data;
import java.util.List;
@Data
@JacksonXmlRootElement(localName = "cpe-list")
public class CpeList {
@JacksonXmlElementWrapper(useWrapping = false) // 关键:不使用额外的包装元素
@JacksonXmlProperty(localName = "cpe-item") // 关键:指定列表元素的名称
private List<CpeItem> cpeItems; // 将多个cpe-item映射到此列表
}在Spring Boot中,我们通常会创建一个REST控制器来处理HTTP请求并执行解析逻辑。
package com.dependency.demo;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import java.io.IOException;
import java.io.InputStream;
@RestController
public class XmlController {
@GetMapping("/parse-cpe-list") // 定义一个GET请求路径
public CpeList parseCpeList() throws XMLStreamException, IOException {
// 从classpath加载XML文件
InputStream xmlResource = XmlController.class.getClassLoader().getResourceAsStream("test.xml");
if (xmlResource == null) {
throw new IOException("XML file 'test.xml' not found in classpath.");
}
// 创建XMLStreamReader
XMLInputFactory xmlInputFactory = XMLInputFactory.newFactory();
XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(xmlResource);
// 创建XmlMapper实例
XmlMapper mapper = new XmlMapper();
// 可选:配置DeserializationFeature,例如如果XML中有未知字段不报错
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
// 执行反序列化
CpeList cpeList = mapper.readValue(xmlStreamReader, CpeList.class);
// 打印解析结果以验证
System.out.println("解析到的CPE列表:");
if (cpeList != null && cpeList.getCpeItems() != null) {
for (CpeItem cpeItem : cpeList.getCpeItems()) {
System.out.println(" Name: " + cpeItem.getName() + ", Title: " + cpeItem.getTitle());
}
} else {
System.out.println(" 列表为空或解析失败。");
}
// 关闭资源
xmlStreamReader.close();
xmlResource.close();
return cpeList;
}
}将以下内容保存到src/main/resources/test.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<cpe-list>
<cpe-item name="John">
<title>xmlread</title>
</cpe-item>
<cpe-item name="Jack">
<title>testtitle</title>
</cpe-item>
<cpe-item name="Jane">
<title>another_title</title>
</cpe-item>
</cpe-list>启动Spring Boot应用,并通过浏览器或Postman访问 http://localhost:8080/parse-cpe-list。
预期输出:
在控制台,您将看到类似以下内容的日志:
解析到的CPE列表: Name: John, Title: xmlread Name: Jack, Title: testtitle Name: Jane, Title: another_title
HTTP响应体将是:
<CpeList>
<cpeItems name="John">
<title>xmlread</title>
</cpeItems>
<cpeItems name="Jack">
<title>testtitle</title>
</cpeItems>
<cpeItems name="Jane">
<title>another_title</title>
</cpeItems>
</CpeList>这表明所有<cpe-item>元素都被成功解析并存储在CpeList对象的cpeItems列表中。
通过本文的详细指导和示例,您应该能够熟练地使用Jackson在Spring Boot中解析包含重复元素的XML文件,避免只解析到最后一个元素的常见陷阱。理解@JacksonXmlElementWrapper和@JacksonXmlProperty的正确用法是掌握Jackson XML解析能力的重要一步。
以上就是使用Jackson在Spring Boot中解析XML列表的教程的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号