Jackson是Java生态中广泛使用的序列化反序列化工具,除了处理JSON数据外,通过扩展模块也支持XML格式的处理,针对任意深度嵌套的XML结构,不需要预先定义固定层级的实体类,可通过灵活的API完成反序列化操作。

依赖准备
要使用Jackson处理XML,需要引入核心依赖和XML扩展依赖,Maven项目可在pom.xml中添加如下配置:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>2.15.2</version>
</dependency>
使用JsonNode处理任意嵌套XML
Jackson的XmlMapper可以将XML直接反序列化为JsonNode树结构,这种方式不需要预先定义实体类,适合处理任意深度和未知结构的XML,JsonNode提供了遍历子节点、获取节点值的方法,可递归处理嵌套内容。
基础示例
假设有如下任意深度的嵌套XML:
<root>
<level1>
<level2>
<level3>
<value>测试内容</value>
</level3>
</level2>
</level1>
<other>额外节点</other>
</root>
反序列化并遍历的代码如下:
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import java.io.IOException;
public class XmlDeserializeDemo {
public static void main(String[] args) throws IOException {
String xmlContent = "<root>" +
"<level1>" +
"<level2>" +
"<level3>" +
"<value>测试内容</value>" +
"</level3>" +
"</level2>" +
"</level1>" +
"<other>额外节点</other>" +
"</root>";
XmlMapper xmlMapper = new XmlMapper();
JsonNode rootNode = xmlMapper.readTree(xmlContent);
// 递归遍历所有节点
traverseNode(rootNode, 0);
}
private static void traverseNode(JsonNode node, int depth) {
// 输出当前节点名称和值
if (node.isValueNode()) {
for (int i = 0; i < depth; i++) {
System.out.print(" ");
}
System.out.println("节点值: " + node.asText());
} else if (node.isContainerNode()) {
for (int i = 0; i < depth; i++) {
System.out.print(" ");
}
System.out.println("节点名: " + node.fieldNames().next());
// 遍历子节点
node.forEach(child -> traverseNode(child, depth + 1));
}
}
}
处理同名嵌套节点
如果XML中存在同名的多层嵌套节点,比如如下结构:
<items>
<item>
<item>
<item>深层内容</item>
</item>
</item>
</items>
可以通过JsonNode的path方法逐层获取,或者通过循环遍历所有子节点:
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import java.io.IOException;
public class NestedSameNameDemo {
public static void main(String[] args) throws IOException {
String xml = "<items>" +
"<item>" +
"<item>" +
"<item>深层内容</item>" +
"</item>" +
"</item>" +
"</items>";
XmlMapper xmlMapper = new XmlMapper();
JsonNode root = xmlMapper.readTree(xml);
JsonNode current = root.path("item");
int level = 1;
while (current.isContainerNode() && current.has("item")) {
System.out.println("第" + level + "层item节点");
current = current.path("item");
level++;
}
if (current.isValueNode()) {
System.out.println("最深层item内容: " + current.asText());
}
}
}
自定义反序列化器适配复杂嵌套
如果需要将嵌套XML转换为自定义的Java对象结构,可自定义反序列化器,在反序列化过程中动态处理任意深度的嵌套逻辑。首先需要定义一个通用的嵌套结构实体类:
import java.util.ArrayList;
import java.util.List;
public class NestedXmlNode {
private String name;
private String value;
private List<NestedXmlNode> children = new ArrayList<>();
// getter和setter方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public List<NestedXmlNode> getChildren() {
return children;
}
public void setChildren(List<NestedXmlNode> children) {
this.children = children;
}
}
然后自定义反序列化器:
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
public class NestedXmlDeserializer extends StdDeserializer<NestedXmlNode> {
protected NestedXmlDeserializer() {
super(NestedXmlNode.class);
}
@Override
public NestedXmlNode deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
JsonNode node = p.getCodec().readTree(p);
return parseNode(node);
}
private NestedXmlNode parseNode(JsonNode node) {
NestedXmlNode xmlNode = new NestedXmlNode();
if (node.isValueNode()) {
xmlNode.setValue(node.asText());
return xmlNode;
}
// 处理容器节点
Iterator<Map.Entry<String, JsonNode>> fields = node.fields();
if (fields.hasNext()) {
Map.Entry<String, JsonNode> entry = fields.next();
xmlNode.setName(entry.getKey());
JsonNode childNode = entry.getValue();
if (childNode.isContainerNode()) {
// 递归解析子节点
childNode.fields().forEachRemaining(childEntry -> {
NestedXmlNode child = parseNode(childEntry.getValue());
child.setName(childEntry.getKey());
xmlNode.getChildren().add(child);
});
} else {
xmlNode.setValue(childNode.asText());
}
}
return xmlNode;
}
}
最后注册反序列化器并使用:
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import java.io.IOException;
public class CustomDeserializerDemo {
public static void main(String[] args) throws IOException {
String xml = "<root>" +
"<a>" +
"<b>" +
"<c>内容</c>" +
"</b>" +
"</a>" +
"</root>";
XmlMapper xmlMapper = new XmlMapper();
SimpleModule module = new SimpleModule();
module.addDeserializer(NestedXmlNode.class, new NestedXmlDeserializer());
xmlMapper.registerModule(module);
NestedXmlNode result = xmlMapper.readValue(xml, NestedXmlNode.class);
System.out.println("根节点名: " + result.getName());
System.out.println("子节点数量: " + result.getChildren().size());
}
}
注意事项
- XmlMapper默认会将XML的属性和文本内容做特定映射,如果XML包含属性,需要在配置中开启对应支持,避免属性被忽略。
- 处理超大深度的嵌套XML时,递归遍历可能出现栈溢出,可将递归改为栈或队列的迭代方式实现。
- 如果XML结构中存在命名空间,需要在XmlMapper中配置对应的命名空间处理策略,否则可能出现节点解析错误。