You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Jackson反序列化任意深度的递归嵌套XML?

用Jackson注解处理递归嵌套XML结构并收集带完整组链的对象

一、先修正XML拼写错误

你提供的XML存在两处拼写错误,会导致解析失败,需先修正:

  • <gropup> → <group>
  • </goups> → </groups>

修正后的XML示例:

<root>
  <groups>
    <group>
      <group_data>...group data level 1...</group_data>
      <object>object 1-1</object>
      <object>object 1-2</object>
      <groups>
        <group>
          <group_data>...group data level 2...</group_data>
          <object>object 2-1</object>
          <groups>
            <group>
              <group_data>...group data level 3-1...</group_data>
              <object>object 3-1-1</object>
              <object>object 3-1-2</object>
            </group>
            <group>
              <group_data>...group data level 3-2...</group_data>
              <object>object 3-2-1</object>
            </group>
          </groups>
        </group>
      </groups>
    </group>
  </groups>
</root>

二、引入Jackson XML依赖

需添加Jackson的XML解析模块,Maven依赖示例:

<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-xml</artifactId>
    <version>2.15.2</version> <!-- 使用最新稳定版 -->
</dependency>

三、用Jackson注解完善Java类结构

1. Root类(对应XML根节点)

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 java.util.List;

@JacksonXmlRootElement(localName = "root")
public class Root {
    @JacksonXmlElementWrapper(localName = "groups")
    @JacksonXmlProperty(localName = "group")
    private List<Group> groups;

    // Getter & Setter
    public List<Group> getGroups() { return groups; }
    public void setGroups(List<Group> groups) { this.groups = groups; }
}

2. Group类(递归核心类)

修正字段命名规范并添加XML映射注解:

import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import java.util.List;

public class Group {
    @JacksonXmlProperty(localName = "group_data")
    private String groupData;

    @JacksonXmlElementWrapper(localName = "groups")
    @JacksonXmlProperty(localName = "group")
    private List<Group> groups;

    @JacksonXmlElementWrapper(useWrapping = false) // 直接映射<object>节点,无需外层包装
    @JacksonXmlProperty(localName = "object")
    private List<Item> items;

    // Getter & Setter
    public String getGroupData() { return groupData; }
    public void setGroupData(String groupData) { this.groupData = groupData; }
    public List<Group> getGroups() { return groups; }
    public void setGroups(List<Group> groups) { this.groups = groups; }
    public List<Item> getItems() { return items; }
    public void setItems(List<Item> items) { this.items = items; }
}

3. Item与ItemData类

用@JacksonXmlText映射XML节点的文本内容:

import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlText;

public class Item {
    private ItemData item;

    // Getter & Setter
    public ItemData getItem() { return item; }
    public void setItem(ItemData item) { this.item = item; }
}

class ItemData {
    @JacksonXmlText
    private String itemName;

    // Getter & Setter
    public String getItemName() { return itemName; }
    public void setItemName(String itemName) { this.itemName = itemName; }
}

四、解析XML并收集带完整组链的对象

解析完成后,递归遍历Group结构,为每个Item收集从根到当前Group的完整groupData链:

import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import java.io.File;
import java.util.ArrayList;
import java.util.List;

public class XmlParser {
    public static void main(String[] args) throws Exception {
        XmlMapper xmlMapper = new XmlMapper();
        Root root = xmlMapper.readValue(new File("your-xml-file.xml"), Root.class);

        List<ItemWithGroupChain> result = new ArrayList<>();
        if (root.getGroups() != null) {
            for (Group rootGroup : root.getGroups()) {
                traverseGroup(rootGroup, new ArrayList<>(), result);
            }
        }

        // 输出结果示例
        for (ItemWithGroupChain itemChain : result) {
            System.out.println("组链:" + String.join(" → ", itemChain.getGroupDataChain()));
            System.out.println("对象:" + itemChain.getItemData().getItemName());
            System.out.println("---");
        }
    }

    private static void traverseGroup(Group currentGroup, List<String> parentChain, List<ItemWithGroupChain> result) {
        List<String> currentChain = new ArrayList<>(parentChain);
        currentChain.add(currentGroup.getGroupData());

        // 收集当前组下的所有对象
        if (currentGroup.getItems() != null) {
            for (Item item : currentGroup.getItems()) {
                result.add(new ItemWithGroupChain(currentChain, item.getItem()));
            }
        }

        // 递归遍历子组
        if (currentGroup.getGroups() != null) {
            for (Group subGroup : currentGroup.getGroups()) {
                traverseGroup(subGroup, currentChain, result);
            }
        }
    }

    // 辅助类:存储对象与对应组链
    static class ItemWithGroupChain {
        private List<String> groupDataChain;
        private ItemData itemData;

        public ItemWithGroupChain(List<String> groupDataChain, ItemData itemData) {
            this.groupDataChain = groupDataChain;
            this.itemData = itemData;
        }

        public List<String> getGroupDataChain() { return groupDataChain; }
        public ItemData getItemData() { return itemData; }
    }
}

关键注解说明

  • @JacksonXmlRootElement:指定Java类对应的XML根节点名称
  • @JacksonXmlElementWrapper:处理集合的包装节点,useWrapping=false表示集合元素直接作为父节点的子节点
  • @JacksonXmlProperty:映射Java字段与XML节点名称,解决命名风格差异
  • @JacksonXmlText:将XML节点的文本内容绑定到Java字段

内容的提问来源于stack exchange,提问作者r00tGER

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 18:17:53