如何解析包含Java数组的Json

如何解决如何解析包含Java数组的Json

我有一个Json,其中包含Arrays的数组,现在我需要解析Json并计算元素,达到一定限制后,我需要将其放入结果Json。我能够解析到一个级别并计算元素。如何解析多个级别并以相同格式获取对象:

这是我尝试解析一个不包含元素数量的级别的示例代码:

private void handleJson(Object jsonObj,CountObject c,JSONObject jsonObj) {
        Map<String,Object> map= new HashMap<>();

        if (jsonObj instanceof JSONObject) {

            parseJson(inputJSON,c,map,jsonObj);

        } 

        }

    }


private void parseJson(Object inputObj,Map<String,Object> map,JSONObject jsonObj) {
        JSONObject nodeJson = (JSONObject) inputJSON;
        Iterator<String> keyIter = nodeJson.keySet().iterator();

        while (keyIter.hasNext()) {
            String key = keyIter.next();
            Object value = nodeJson.get(key);

            if (value instanceof JSONObject) {
                int offSet = c.getOffSet();
                if(c.getLimit() == c.getOffSet()) {
                    break;
                }
            keyIter.remove(); 
            map.put(key,value); 
            c.setOffSet(++offSet);;
            } else {
                handleJSONArray(value,k,key);
            }
        }
        for (Entry<String,Object> entry : map.entrySet()) {
            jsonObj.put(entry.getKey(),entry.getValue());
}
    }


private void handleJSONArray(Object inputJSON,String key) {
        JSONArray nodeJsonArr = (JSONArray) inputJSON;
        int offSet = c.getOffSet();
        List<Object> ll = new ArrayList<>();
        for (int i = 0; i < nodeJsonArr.length(); i++) {
            Object value = nodeJsonArr.get(i);
            if (value instanceof JSONArray) {
                handleJSONArray(value,key2);
            } else {
                
                if (k.getLimit() == k.getOffSet()) {
                    break;
                }
                ll.add(value);
                ++offSet;
            }
        }
        map.put(key2,ll);
        c.setOffSet(offSet);
    }

这是我的Json:

{
"emails": [
{
"emails": [
{
"email": {
"id": "ac9e95cf-3338-4094-b465-e0e1deca23c4","value": "hello@gmail.com"
}
}
]
},{
"email": {
"id": "b61ffb48-ffc7-4ae6-81a2-78b632892fda","value": "hello1@gmail.com"
}
}
],"lastName": {
"id": "ffe19ece-819b-4680-8e0b-8566b34c973d","value": "FirstName"
},"firstName": {
"id": "4ed234f4-f679-40f3-b76b-41d9fdef7390","value": "LastName"
}
}

count对象是一个具有偏移量和Limit变量的Pojo,如果我将limit传递为3,那么我应该只获取前3个具有相同json格式的元素,如下所示:

{
"emails": [
{
"emails": [
{
"email": {
"id": "ac9e95cf-3338-4094-b465-e0e1deca23c4","value": "FirstName"
}

在这里我给出了一个示例JSON文件,并且Json可以包含任何数量的内部元素数组,逻辑应该能够解析任何类型的Json。 在这里,我还应该对Json元素进行分页,这意味着如果我通过offSet和limit,则应该相应地获取元素。在上面的示例中,CountObject包含limit和offSet,它基于该元素应获取元素。 要给出更多的解释,如果我将offSet设置为10并限制为10,则应该从第10个元素到第20个元素中提取元素,依此类推。

解决方法

这是使用Jackson的一种方法(我使用的是2.11.1版)。

此处的“ 项目”被定义为源JSON中的ID /值对之一,例如:

{
  "id": "b61ffb48-ffc7-4ae6-81a2-78b632892fda","value": "hello1@gmail.com"
}

我将任务分为两部分:

  1. 通过删除后续项,在达到所需限制时切断数据。

  2. 清理所有生成的空对象或数组。

这是我的输入测试数据(基于问题中提供的数据):

    private static final String JSON = "{\n"
            + " \"emails\": [{\n"
            + "         \"emails\": [{\n"
            + "             \"email\": {\n"
            + "                 \"id\": \"ac9e95cf-3338-4094-b465-e0e1deca23c4\",\n"
            + "                 \"value\": \"hello@gmail.com\"\n"
            + "             }\n"
            + "         }]\n"
            + "     },\n"
            + "     {\n"
            + "         \"email\": {\n"
            + "             \"id\": \"b61ffb48-ffc7-4ae6-81a2-78b632892fda\",\n"
            + "             \"value\": \"hello1@gmail.com\"\n"
            + "         }\n"
            + "     }\n"
            + " ],\n"
            + " \"lastName\": {\n"
            + "     \"id\": \"ffe19ece-819b-4680-8e0b-8566b34c973d\",\n"
            + "     \"value\": \"LastName\"\n"
            + " },\n"
            + " \"firstName\": {\n"
            + "     \"id\": \"4ed234f4-f679-40f3-b76b-41d9fdef7390\",\n"
            + "     \"value\": \"FirstName\"\n"
            + " }\n"
            + "}";

代码:

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.util.Iterator;

public class JsonReducer {

    // get the first n "id/value" items:
    private final int limit = 2;
    // tracks how close we are to the cutoff limit:
    private int counter = 0;

    public void doParsing() throws JsonProcessingException {
        ObjectMapper mapper = new ObjectMapper();
        JsonNode json = mapper.readValue(JSON,JsonNode.class);
        
        // show the input JSON formatted,just for this demo:
        System.out.println(json.toPrettyString());

        // a copy of the original - we will use this when cleaning up:
        JsonNode prevJson = json.deepCopy();
        // remove unwanted items from the JSON
        json = reduce(json);

        // clean up empty nodes resulting from removals:
        while (!json.equals(prevJson)) {
            prevJson = json.deepCopy();
            json = stripEmpty(json);
        }

        System.out.println("---------------------------------");
        System.out.println(json.toPrettyString());
    }

    private JsonNode reduce(JsonNode json) {
        for (JsonNode node : json) {
            if (node.isObject()) {
                counter++;
                //System.out.println("obj " + counter + " - " + node.toString());
                if (counter > limit) {
                    ((ObjectNode) node).removeAll();
                } else {
                    reduce(node);
                }
            } else if (node.isArray()) {
                ArrayNode arrayNode = (ArrayNode) node;
                //System.out.println("array - " + arrayNode.toString());
                arrayNode.forEach((item) -> {
                    // assume each item is a JSON object - no arrays of arrays:
                    ObjectNode objectNode = (ObjectNode) item;
                    reduce(objectNode);
                });
            } //else if (node.isTextual()) {
            //System.out.println("text  - " + node.asText());
            //}
        }
        return json;
    }

    private JsonNode stripEmpty(JsonNode json) {
        Iterator<JsonNode> it = json.iterator();
        while (it.hasNext()) {
            JsonNode child = it.next();
            if (child.isContainerNode() && child.isEmpty()) {
                it.remove(); // remove empty arrays [],and objects {}
            } else {
                stripEmpty(child);
            }
        }
        return json;
    }

    private static final String JSON = ... // as shown above.

}

reduce()方法递归地遍历JSON,跟踪收集到的项目数量-然后删除超出所需数量的项目。

但是,这可能会在JSON中留下空的[]数组或{}对象,因此stripEmpty()方法会对此进行处理。

因为我们要从上到下,从外到内依次遍历JSON,所以可能需要多次stripEmpty()方法。可能有一种更有效的方法,只需要通过一次,但这至少是简单的方法。

结果示例:

对于限制= 2:

{
  "emails" : [ {
    "emails" : [ {
      "email" : {
        "id" : "ac9e95cf-3338-4094-b465-e0e1deca23c4","value" : "hello@gmail.com"
      }
    } ]
  },{
    "email" : {
      "id" : "b61ffb48-ffc7-4ae6-81a2-78b632892fda","value" : "hello1@gmail.com"
    }
  } ]
}

对于限制= 1:

{
  "emails" : [ {
    "emails" : [ {
      "email" : {
        "id" : "ac9e95cf-3338-4094-b465-e0e1deca23c4","value" : "hello@gmail.com"
      }
    } ]
  } ]
}

限制= 0:

{ }

附加点:

非通用

该方法假定在其他数组内直接嵌套任何数组-因此都没有:[ [ {...} ] ]。换句话说,这不是100%的通用解析器,但确实与问题中的样本数据相符。

考虑使用POJO

此解决方案未定义将数据加载到其中的任何POJO Java对象-但这样做通常可以更轻松地获得所需的内容:

  • 将数据加载(反序列化)到一个或多个POJO中。
  • 从POJO中删除不需要的数据。
  • 将剩余数据序列化回JSON。

如果该示例比问题中的示例更复杂,我想我愿意这样做,而不是仅操作JsonNode数据。

更新

鉴于问题的变化,我认为我建议的最佳方法是将每个“ 项目”(请参见上面的定义)解析为一个POJO,该POJO仅包含3个字段:

String attribute;
String id;
String value;

执行此操作的代码如下:

    private void traverse(JsonNode json) {
        Iterator<Map.Entry<String,JsonNode>> it = json.fields();
        while (it.hasNext()) {
            Map.Entry<String,JsonNode> entry = it.next();
            String name = entry.getKey();
            JsonNode node = entry.getValue();

            if (node.isArray()) {
                ArrayNode arrayNode = (ArrayNode) node;
                arrayNode.forEach((item) -> {
                    // assume each item is a JSON object - no arrays of arrays:
                    ObjectNode objectNode = (ObjectNode) item;
                    traverse(objectNode);
                });
            } else {
                String id = node.get("id").asText();
                String value = node.get("value").asText();
                
                System.out.println("attr : " + name);
                System.out.println("id   : " + id);
                System.out.println("value: " + value);
                System.out.println("---");
            }
        }
    }

您可以创建一个新的POJO实例,而不是println()语句,并将其添加到ArrayList中。

现在您有了一个包含所有数据的标准列表-您可以根据用户界面的需要访问项目1-100,然后101- 200 ...,依此类推。

您当然需要将原始POJO数据转换回UI需要/期望的任何格式。

使用问题中的示例JSON,上述方法将显示以下内容:

attr : email
id   : ac9e95cf-3338-4094-b465-e0e1deca23c4
value: hello@gmail.com
---
attr : email
id   : b61ffb48-ffc7-4ae6-81a2-78b632892fda
value: hello1@gmail.com
---
attr : lastName
id   : ffe19ece-819b-4680-8e0b-8566b34c973d
value: LastName
---
attr : firstName
id   : 4ed234f4-f679-40f3-b76b-41d9fdef7390
value: FirstName

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-