【问题标题】:Search for specific value in a deep nested JsonArray/JsonObject在深度嵌套的 JsonArray/JsonObject 中搜索特定值
【发布时间】:2021-06-15 18:36:11
【问题描述】:

我有一个像这样的深层嵌套 JsonObject,在这个对象中搜索特定值(本例中为 null)的最佳方法是什么?

{
  "monitors" : ["monitor1"],
  "index" : [{
    "patterns" : [ "*" ],
    "masked" : [ "abcd", "*ip_dest*::/[0-9]{1,3}$/::XXX"],
    "allowed" : [ "123", null ]
  }],
  "permissions" : [ ]
}

对于这个例子,我有一个键列表,我想获取这些键的值,检查该值是否具有 Array 类型,如果是,则搜索该数组中是否有任何 null。这是我的代码:

for (Entry<String, DataType> allowedKey : allowedKeys.entrySet()) {
            DataType dataType = allowedKey.getValue();
            JsonNode value = contentAsNode.get(allowedKey.getKey());
            if (dataType == DataType.ARRAY && value != null) {
                try {
                      List contentArray = DefaultObjectMapper.objectMapper.convertValue(value, java.util.List.class);
                      if (contentArray.contains(null)) {
                          this.errorType = ErrorType.NULL_ARRAY_ELEMENT;
                          return false;
                      }
                } catch (Exception e) {
                        this.errorType = ErrorType.BODY_NOT_PARSEABLE;
                        return false;
                 }
           }
    }

但是contains() 在这种情况下找不到null,因为我有一个嵌套数组。由于 Json 对象的结构每次都可能不同(它可能有嵌套数组或映射或只是一个数组),我想知道解析深层嵌套 JsonObject 以找到特定值的最佳方法是什么?

进一步说明:在上面的Json例子中,我感兴趣的key是index,这个key的值,是一个map(但也可以是数组或者嵌套数组,我们不知道事先),我想检查index 值中是否有任何null(在这种情况下,有一个空值)

【问题讨论】:

  • 如果“允许”数组包含空值,你想提取哪个值?
  • 如果该键的值中有任何null,我需要if 语句返回True
  • 你可以使用任何第三方 jar 像 Jsonpath 吗?它将为您提供灵活的使用方式。
  • 可能没有,我想知道是否有任何方法可以直接使用JsonObjectJsonArray,因为它们都可供我使用。
  • 哦,好吧,虽然已经贴出来了,如果你不能用,请告诉我,我可以改变它

标签: java arrays json


【解决方案1】:

使用 JSONPath 的一个可行的简单解决方案

public static void main(String[] args) {
    String json = "{\r\n" + 
            "  \"monitors\" : [\"monitor1\"],\r\n" + 
            "  \"index\" : [{\r\n" + 
            "    \"patterns\" : [ \"*\" ],\r\n" + 
            "    \"masked\" : [ \"abcd\", \"*ip_dest*::/[0-9]{1,3}$/::XXX\"],\r\n" + 
            "    \"allowed\" : [ \"123\", null ]\r\n" + 
            "  }],\r\n" + 
            "  \"permissions\" : [ ]\r\n" + 
            "}" ;
    
    String path = "$.index[?(null in @.allowed)]"; //Check if allowed List has null value i.e. index->allowed
    DocumentContext jsonContext = JsonPath.parse(json);
    List<?> list = jsonContext.read(path);
    if(list.isEmpty()) { //Based on empty List u can return true or false
        System.out.println("Not found");
    }else {
        System.out.println("Found");
    }       
}

根据 OP 要求,另一种解决方案以递归方式迭代 JsonObject

public static void main(String[] args) {
    String json = "{\r\n" + 
            "  \"monitors\" : [\"monitor1\"],\r\n" + 
            "  \"index\" : [{\r\n" + 
            "    \"patterns\" : [ \"*\" ],\r\n" + 
            "    \"masked\" : [ \"abcd\", \"*ip_dest*::/[0-9]{1,3}$/::XXX\"],\r\n" + 
            "    \"allowed\" : [ \"123\", null ],\r\n" + 
            "    \"country\" : \"India\"\r\n" + 
            "  }],\r\n" + 
            "  \"permissions\" : [ ]\r\n" + 
            "}" ;
    try {
        iterateJson(new JSONObject(json));
    } catch (Exception e) {
        e.printStackTrace();
    }   
}

public static void iterateJson(JSONObject jsonObject) throws Exception {
    ObjectMapper mapper = new ObjectMapper();
    Iterator<String> iterator = jsonObject.keys();
    while(iterator.hasNext()) {
        String key = iterator.next();
        if(jsonObject.get(key) instanceof JSONArray) {
            JSONArray jsonArray = jsonObject.getJSONArray(key);
            for(int i=0; i<jsonArray.length(); i++) {
                if(jsonArray.get(i) instanceof JSONObject) {
                    iterateJson(jsonArray.getJSONObject(i));
                }else if(jsonArray.get(i) instanceof String){
                    List<String> list = mapper.readValue(jsonArray.toString(), new TypeReference<List<String>>() {});
                    System.out.println(key+" :: "+list);
                    System.out.println("Contains null :: "+list.contains(null));
                    System.out.println();
                    break;
                }
            }
        }else if(jsonObject.get(key) instanceof JSONObject) {
            iterateJson(jsonObject.getJSONObject(key));
        }
    }
}

输出

masked :: [abcd, *ip_dest*::/[0-9]{1,3}$/::XXX]
Contains null :: false

allowed :: [123, null]
Contains null :: true

patterns :: [*]
Contains null :: false

monitors :: [monitor1]
Contains null :: false

【讨论】:

  • 感谢您的解决方案,很遗憾我无法使用JsonPath,有什么方法可以使用JsonObjectJsonArray?我们可以将它们展平,以便它也可以在嵌套结构中找到 null 吗?
  • 发布了另一个解决方案,看看这是否适用于 u ,它检查 index 是否为 JsonArray 类型并且“allowed”也是 jsonArray 类型,然后它有一个空值。
  • 感谢您发布此信息。有没有办法将List contentArray = DefaultObjectMapper.objectMapper.convertValue(value, java.util.List.class); 转换为JSONArray?我试过这个:JSONArray jsArray = new JSONArray(contentArray)`,但它给了我一个错误。
  • 你的 contentArray 是什么?
  • @user1080814 如果我理解正确,请检查更新,已使用 ObjectMapper 将允许的值转换为 List
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-10
  • 2021-08-09
  • 2017-07-30
  • 2018-04-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多