在深层嵌套的 JsonArray/JsonObject 中搜索特定值

时间:2021-06-15 18:36:11

标签: java arrays json

我有一个像这样的深度嵌套的 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中,我感兴趣的键是index,这个键的值是一个映射(但它也可以是一个数组或嵌套数组,我们做事先不知道),我想检查 null 值中是否有任何 index(在这种情况下,有一个空值)

1 个答案:

答案 0 :(得分:0)

使用 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