复杂JSON数据的扁平化解析_Java实现

Ashe / 2024-01-22 / 原文

在工作中遇到了解析JSON数据的场景,但是此岗位传统的做法是通过Python脚本来实现的,而且是非常不合理的手动解析——每对应不同的JSON数据结构,都需要手动改动很多脚本文件,工作量与JSON数据结构的复杂程度成正比!(很难想象这是一个做开发的人想出来的方案)

因此最开始接触此工作内容的时候,我就忍不住吐槽该实现的各种繁琐之处,遂萌生了使用Java语言实现自动化解析复杂JSON数据的想法。

需求:

将复杂JSON数据解构为扁平化数据,插入数据库对应的一张表上,供业务更直观地查询/阅览数据。

思路:

使用Jackson将数据转成JsonNode对象,然后通过递归解构至JsonNode不在为对象为止,然后put到一个LinkedHashMap中去,以此实现数据结构的扁平化变换。

核心代码:

public void print(JsonNode jsonNode) {
        Map<String, String> map = recursiveParse(jsonNode, new LinkedHashMap<>(), null);
        map.forEach((key, value) -> System.err.prinln(key + ":" + value));
    }

    private Map<String, String> recursiveParse(JsonNode jsonNode, Map<String, String> map, String parentKey) {
        if(jsonNode.isObject()){
            jsonNode.fields().forEachRemaining(entry -> {
                String currentKey = parentKey != null ? parentKey + "_" + entry.getKey() : entry.getKey();
                recursiveParse(jsonNode, map, currentKey);
            })
        }
        // 此前的经验:当JSON数据过于复杂时或Array的元素个数非常多时,Array结构若继续解析会导致一张表的字段数量过千
        // 为避免此情况,因此遇到Array结构不再解析,而是单独对此Array解析到另一张表
        else if(jsonNode.isArray()) {
            map.put(parentKey, jsonNode.toString());
        }
        else {
            map.put(parentKey, jsonNode.asText());
        }
    }

测试类验证:

    @Autowired
    private ObjectMapper objectMapper
    @Autowired
    private Xxxx xxxx;

    @Test
    public void testSth() {
        JsonNode jsonNode = objectMapper.readValue(Temp.class.getClassLoader().getResourceAsStream("xx.json"), JsonNode.class);
        xxxx.print(jsonNode);
    }

 经测试验证,和传统方式解析的效果一致,因此可以认为我的思路是对的,后续可以根据Map输出建表语句,然后由人工修改字段长度(这是无法避免的,除非你使用的数据库,字符串长度是可伸缩的)。

建好表以后,再拟定一个定时任务,读取JSON数据,解析,插入。(因为一些原因——守旧?,笔者的实现很可能无法应用于工作,因此后续的代码就没写了)