如何动态解析嵌套 JSON 字符串并自动拼接内层值

本文介绍一种无需硬编码键名的通用方案,使用 josson 库遍历任意结构的 json 对象,对值为 json 字符串的字段自动反序列化并拼接其所有内部值,最终生成标准化的扁平化 json 结果。

在实际开发中,数据库常以字符串形式存储动态 JSON 数据(如 {"be003": "{\"1\":\"ABC\",\"2\":\"DEF\",\"3\":\"DEF\"}"}),且顶层键名数量庞大、不可预知。若采用传统 JSONObject.optString("key") 方式逐个提取,不仅代码冗余,更难以维护和扩展。

推荐使用轻量级 JSON 转换库 Josson ——它支持声明式路径表达式,可高效完成“无键遍历 + 条件解析 + 值聚合”三步操作。

✅ 核心处理逻辑(分步解析)

  1. entries():将顶层对象转为键值对数组 [{"key":"ad002","value":"..."}, ...];
  2. .field(value.if(startsWith('{'), json().entries().value.@join(), ?))
    • 判断 value 是否以 { 开头(即是否为 JSON 对象字符串);
    • 若是,则解析该字符串为 JSON → 提取所有 entries() → 获取每个子项的 value → 用 @join() 拼接为单个字符串;
    • 否则保留原值(如 "5601087282462117");
  3. .map(key::value) + .mergeObjects():将键值对数组还原为标准 JSON 对象。

? 完整示例代码

import com.octomix.josson.Josson;
import com.fasterxml.jackson.databind.JsonNode;

public class JsonFlattener {
    public static void main(String[] args) {
        String jsonInput = "{" +
                "    \"ad002

\": \"5601087282462117\"," + " \"be003\": \"{\\\"1\\\":\\\"ABC\\\",\\\"2\\\":\\\"DEF\\\",\\\"3\\\":\\\"DEF\\\"}\"," + " \"ze024\": \"18\"" + "}"; Josson josson = Josson.fromJsonString(jsonInput); JsonNode result = josson.getNode( "entries()" + ".field(value" + " .if(startsWith('{')," + " json().entries().value.@join()," + " ?)" + " )" + ".map(key::value)" + ".mergeObjects()" ); System.out.println(result.toPrettyString()); // 输出: // { // "ad002" : "5601087282462117", // "be003" : "ABCDEFDEF", // "ze024" : "18" // } } }

⚠️ 注意事项

  • 确保嵌套 JSON 字符串严格符合 JSON 语法(双引号、正确转义),否则 json() 函数会抛出解析异常;
  • @join() 默认以空字符串拼接,如需分隔符(如逗号),可改用 @join(', ');
  • 若存在多层嵌套(如 be003 的值本身还包含 JSON 字符串),需递归应用逻辑,可通过自定义函数或多次 .getNode() 实现;
  • 引入依赖(Maven):
    
        com.octomix.josson
        josson
        1.7.1
    

该方案彻底摆脱了对键名的依赖,适用于日志分析、配置中心、动态表单等场景,兼具灵活性与可读性。