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

如何从含数组的JSON中获取带父键前缀的嵌套键值对

解决JSON嵌套结构(含数组)转带前缀键值对问题

原代码问题分析

  • 处理JSON数组时,错误地将整个数组直接存入Map,同时递归遍历数组元素,导致键冲突或冗余数据
  • 数组元素的键未添加索引标识,无法区分数组中不同位置的元素
  • 键分隔符使用下划线_,不符合需求中的点.分隔格式(如Group.class)

修复优化后的实现(基于org.json)

import org.json.JSONArray;
import org.json.JSONObject;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.IntStream;

public class JsonFlattener {
    public static Map<String, String> flattenJson(Object json) {
        Map<String, String> result = new HashMap<>();
        flatten(json, null, result);
        return result;
    }

    private static void flatten(Object object, String parentKey, Map<String, String> result) {
        if (object instanceof JSONObject) {
            JSONObject jsonObject = (JSONObject) object;
            jsonObject.keySet().forEach(childKey -> {
                String newKey = parentKey != null ? parentKey + "." + childKey : childKey;
                flatten(jsonObject.get(childKey), newKey, result);
            });
        } else if (object instanceof JSONArray) {
            JSONArray jsonArray = (JSONArray) object;
            // 遍历数组元素,用父键+索引作为元素前缀
            IntStream.range(0, jsonArray.length())
                    .forEach(index -> {
                        String newKey = parentKey != null ? parentKey + "." + index : String.valueOf(index);
                        flatten(jsonArray.get(index), newKey, result);
                    });
        } else {
            // 基础类型直接存入Map,跳过无父键的无效情况
            if (parentKey != null) {
                result.put(parentKey, object.toString());
            }
        }
    }
}

关键修改说明

  1. 数组逻辑修复:移除存入整个数组的代码,改为遍历每个元素,用父键.索引作为元素的前缀键,比如数组students的第一个元素键为students.0
  2. 分隔符调整:将下划线_改为点.,匹配需求中的嵌套键格式
  3. 调用简化:对外提供flattenJson入口方法,无需手动初始化Map,调用更便捷
  4. 边界处理:避免无父键的基础类型存入Map,减少无效数据

调用示例

public static void main(String[] args) {
    String jsonStr = "{\"Group\":{\"class\":\"A\",\"students\":[{\"name\":\"Alice\",\"age\":18},{\"name\":\"Bob\",\"age\":19}]}}";
    JSONObject jsonObject = new JSONObject(jsonStr);
    Map<String, String> flatMap = JsonFlattener.flattenJson(jsonObject);
    
    flatMap.forEach((k, v) -> System.out.println(k + " = " + v));
}

输出结果:

Group.class = A
Group.students.0.name = Alice
Group.students.0.age = 18
Group.students.1.name = Bob
Group.students.1.age = 19

更简洁的实现(基于Jackson)

如果项目已引入Jackson库,可利用其树遍历功能更高效实现:

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.HashMap;
import java.util.Map;

public class JacksonJsonFlattener {
    private static final ObjectMapper mapper = new ObjectMapper();

    public static Map<String, String> flattenJson(String jsonStr) throws Exception {
        Map<String, String> result = new HashMap<>();
        JsonNode root = mapper.readTree(jsonStr);
        flatten(root, null, result);
        return result;
    }

    private static void flatten(JsonNode node, String parentKey, Map<String, String> result) {
        if (node.isObject()) {
            node.fields().forEachRemaining(entry -> {
                String newKey = parentKey != null ? parentKey + "." + entry.getKey() : entry.getKey();
                flatten(entry.getValue(), newKey, result);
            });
        } else if (node.isArray()) {
            for (int i = 0; i < node.size(); i++) {
                String newKey = parentKey != null ? parentKey + "." + i : String.valueOf(i);
                flatten(node.get(i), newKey, result);
            }
        } else if (node.isValueNode()) {
            if (parentKey != null) {
                result.put(parentKey, node.asText());
            }
        }
    }
}

该实现无需依赖org.json库,Jackson树模型对复杂JSON的处理性能更优,代码也更简洁。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 12:10:50