自定义Json模板解析

概要

之前有从边缘网关采集数据的需求,但是不同边缘网关上报格式不同,大部分是自定义Json模板进行采集,因此实现一个简单的Json解析工具类。主要用于特定设备上报Json模板,从中解析数据

实现思路

通过深度优先遍历到模板中$开头的字段,同时纪录路径,到json中递归寻找对应结果

实现代码

    /**
     * 使用深度优先搜索方法匹配模板和传入 JSON 的字段
     * @param template 模板 JSON 对象或数组
     * @param inputObj 传入 JSON 对象
     * @param result 结果对象
     * @param path 当前路径
     */
    private static void matchFields(Object template, JSONObject inputObj, Map<String,Object> result, String path) {
        if (template instanceof JSONObject) {
            JSONObject templateObj = (JSONObject) template;
            for (String templateKey : templateObj.keySet()) {
                String currentPath = path.isEmpty() ? templateKey : path + "." + templateKey;
                Object templateValue = templateObj.get(templateKey);

                if (templateValue instanceof JSONObject || templateValue instanceof JSONArray) {
                    // 如果模板值是嵌套的 JSON 对象或数组,则继续递归匹配
                    matchFields(templateValue, inputObj, result, currentPath);
                } else if (templateValue instanceof String && ((String) templateValue).startsWith("$")) {
                    // 如果模板值是 "$"开头,则提取对应的传入 JSON 字段的值
                    Object inputValue = getValueByPath(inputObj, currentPath);
                    // 去除$开头
                    result.put(((String) templateValue).substring(1), inputValue);
                }
            }
        } else if (template instanceof JSONArray) {
            JSONArray templateArray = (JSONArray) template;

            for (int i = 0; i < templateArray.size(); i++) {
                String currentPath = path + ".[" + i + "]";
                Object templateElement = templateArray.get(i);

                if (templateElement instanceof JSONObject || templateElement instanceof JSONArray) {
                    // 如果模板元素是嵌套的 JSON 对象或数组,则继续递归匹配
                    matchFields(templateElement, inputObj, result, currentPath);
                } else if (templateElement instanceof String && templateElement.toString().startsWith("$")) {
                    // 如果模板元素是 "$"开头,则提取对应的传入 JSON 字段的值
                    Object inputValue = getValueByPath(inputObj, currentPath);
                    // 去除$开头
                    result.put(((String) templateElement).substring(1),inputValue);
                }
            }
        }
    }

深度优先搜索方法,不断递归同时记录当前路径,当遇到没有嵌套json同时开头为$时将值加入结果集

    /**
     * 根据路径获取 JSON 字段的值
     * @param json 传入 JSON 对象
     * @param path 路径
     * @return JSON 字段的值
     */
    private static Object getValueByPath(JSONObject json, String path) {
        String[] keys = path.split("\\.");
        Object currentObj = json;

        // 遍历路径
        for (String key : keys) {
            if (currentObj instanceof JSONObject) {
                JSONObject jsonObject = (JSONObject) currentObj;
                if (jsonObject.containsKey(key)) {
                    currentObj = jsonObject.get(key);
                } else {
                    // 如果路径中的字段不存在,则返回 null 或抛出异常,根据需要进行处理
                    return null;
                }
            } else if (currentObj instanceof JSONArray) {
                JSONArray jsonArray = (JSONArray) currentObj;
                int index = getIndexFromKey(key);
                if (index >= 0 && index < jsonArray.size()) {
                    currentObj = jsonArray.get(index);
                } else {
                    // 如果索引越界,则返回 null 或抛出异常,根据需要进行处理
                    return null;
                }
            } else {
                // 当前路径无法继续匹配
                return null;
            }
        }

        return currentObj;
    }

获取实际结果值方法,传入json和路径获取值

    /**
     * 从路径中获取索引
     * @param key 传入路径中的字段名
     * @return 索引
     */
    private static int getIndexFromKey(String key) {
        // 获取路径中的索引
        try {
            // 去除索引括号
            key = key.replaceAll("[\\[\\]]", "");
            return Integer.parseInt(key);
        } catch (NumberFormatException e) {
            return -1;
        }
    }

获取索引方法,判断索引位置

使用示例

    public static void main(String[] args) {
        // 示例:假设一个名为 template 的模板 JSON 对象或数组,以及一个名为 inputJson 的传入 JSON 字符串
        String templateJson = "{\"a\": {\"b\": {\"c\": \"$value1\"}}, \"d\": [{\"e\": \"$value2\"}]}";
        String inputJson = "{\"a\": {\"b\": {\"c\": 123}}, \"d\": [{\"e\": \"hello\"}, {\"e\": \"world\"}]}";

        // 解析模板和传入的 JSON 字符串
        Object template = parseTemplate(templateJson);
        JSONObject inputObj = JSONObject.parseObject(inputJson);

        // 创建结果对象
        Map<String,Object> result = new JSONObject();

        // 使用深度优先搜索方法匹配模板和传入 JSON 的字段
        matchFields(template, inputObj, result, "");

        // 打印结果
        System.out.println(result);
    }

对于边缘网关中,可以把结果集的Key定义为属性名,Value定义为具体数值,在实际业务中通过Key属性名关联设备属性等数据,同时存储采集值

总结

这篇文章仅记录一个简单的模板解析器,更快的实现部分功能。更复杂的解析暂不支持。

  • 16
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值