如何将带递归子节点结构的XML转换为Java对象?
这问题挺典型的,嵌套递归的XML转Java对象,核心就是把这种递归结构映射成对应的递归Java类,我给你一步步捋清楚:
1. 定义匹配递归结构的Java实体类
首先得对应XML的层级和递归关系来写类:
<template>对应根类Template,里面包含一个顶级的Condition<condition>对应Condition类:有name属性,必须包含Li标签,所以要定义一个非空的List<Li><li>对应Li类:可选value属性,可选的文本内容(比如<li value="BB">Value B</li>里的文本),还可以嵌套一个Condition(因为部分Li里会有子Condition)
用JAXB注解的实体类(Java自带,无需额外依赖)
import javax.xml.bind.annotation.*; import java.util.List; @XmlRootElement(name = "template") @XmlAccessorType(XmlAccessType.FIELD) public class Template { @XmlElement(name = "condition") private Condition condition; // Getters and Setters public Condition getCondition() { return condition; } public void setCondition(Condition condition) { this.condition = condition; } } @XmlAccessorType(XmlAccessType.FIELD) public class Condition { @XmlAttribute(name = "name") private String name; @XmlElement(name = "li") private List<Li> liList; // 必须包含Li,所以这个list不能为null/空 // Getters and Setters public String getName() { return name; } public void setName(String name) { this.name = name; } public List<Li> getLiList() { return liList; } public void setLiList(List<Li> liList) { this.liList = liList; } } @XmlAccessorType(XmlAccessType.FIELD) public class Li { @XmlAttribute(name = "value") private String value; @XmlValue private String textContent; // 对应<li>里的文本内容,比如"Value B" @XmlElement(name = "condition") private Condition nestedCondition; // 嵌套的子Condition,可选 // Getters and Setters public String getValue() { return value; } public void setValue(String value) { this.value = value; } public String getTextContent() { return textContent; } public void setTextContent(String textContent) { this.textContent = textContent; } public Condition getNestedCondition() { return nestedCondition; } public void setNestedCondition(Condition nestedCondition) { this.nestedCondition = nestedCondition; } }
用Jackson XML注解的实体类(更灵活,适合复杂场景)
如果你用Jackson来处理,需要先引入jackson-dataformat-xml依赖,实体类注解如下:
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; import java.util.List; @JacksonXmlRootElement(localName = "template") public class Template { @JacksonXmlProperty(localName = "condition") private Condition condition; // Getters and Setters public Condition getCondition() { return condition; } public void setCondition(Condition condition) { this.condition = condition; } } public class Condition { @JacksonXmlProperty(isAttribute = true) private String name; @JacksonXmlProperty(localName = "li") private List<Li> liList; // Getters and Setters public String getName() { return name; } public void setName(String name) { this.name = name; } public List<Li> getLiList() { return liList; } public void setLiList(List<Li> liList) { this.liList = liList; } } public class Li { @JacksonXmlProperty(isAttribute = true) private String value; @JacksonXmlProperty(isAttribute = false) private String textContent; @JacksonXmlProperty(localName = "condition") private Condition nestedCondition; // Getters and Setters public String getValue() { return value; } public void setValue(String value) { this.value = value; } public String getTextContent() { return textContent; } public void setTextContent(String textContent) { this.textContent = textContent; } public Condition getNestedCondition() { return nestedCondition; } public void setNestedCondition(Condition nestedCondition) { this.nestedCondition = nestedCondition; } }
2. 解析XML为Java对象的示例代码
用JAXB解析(Java自带)
import javax.xml.bind.JAXBContext; import javax.xml.bind.Unmarshaller; import java.io.StringReader; public class XmlParser { public static void main(String[] args) throws Exception { String xmlContent = """ <template> <condition name="A"> <li value="A"> <condition name="B"> <li value="BB">Value B</li> <li value="BBB">Value BBB</li> </condition> </li> <li> <condition name="C"> <li value="CC">Value CC</li> <li value="CCC">Value CCC</li> <li> <condition name="D"> <li value="DD">Value DD</li> <li value="DDD">Value DDD</li> </condition> </li> </condition> </li> </condition> </template> """; JAXBContext jaxbContext = JAXBContext.newInstance(Template.class); Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); Template template = (Template) unmarshaller.unmarshal(new StringReader(xmlContent)); // 验证解析结果,比如打印顶级Condition的name System.out.println("Top condition name: " + template.getCondition().getName()); } }
用Jackson XML解析
import com.fasterxml.jackson.dataformat.xml.XmlMapper; public class JacksonXmlParser { public static void main(String[] args) throws Exception { String xmlContent = """ <template> <condition name="A"> <li value="A"> <condition name="B"> <li value="BB">Value B</li> <li value="BBB">Value BBB</li> </condition> </li> <li> <condition name="C"> <li value="CC">Value CC</li> <li value="CCC">Value CCC</li> <li> <condition name="D"> <li value="DD">Value DD</li> <li value="DDD">Value DDD</li> </condition> </li> </condition> </li> </condition> </template> """; XmlMapper xmlMapper = new XmlMapper(); Template template = xmlMapper.readValue(xmlContent, Template.class); System.out.println("Top condition name: " + template.getCondition().getName()); } }
3. 额外注意点
- 因为要求Condition标签必须包含Li标签,可以在实体类里添加校验逻辑,比如用JSR-380的
@NotNull和@NotEmpty注解,或者在解析完成后手动检查Condition.getLiList()是否为空。 - 如果XML里的
<li>既有文本内容又有嵌套Condition,要确保注解能正确识别,JAXB的@XmlValue可以处理文本内容,Jackson也能自动映射(注意属性和文本的优先级)。
内容的提问来源于stack exchange,提问作者Joseph Move
相关产品推荐
相关产品推荐

