【问题标题】:Parsing JSON in Java without knowing JSON format在不知道 JSON 格式的情况下用 Java 解析 JSON
【发布时间】:2013-11-14 14:58:32
【问题描述】:

我正在尝试在 Java 中解析 JSON 字符串并找到键值对,以便我可以确定 JSON 对象的大致结构,因为 JSON 字符串的对象结构是未知的。

例如,一个执行可能有一个像这样的 JSON 字符串:

  {"id" : 12345, "days" : [ "Monday", "Wednesday" ], "person" : { "firstName" : "David", "lastName" : "Menoyo" } }

还有一个这样的:

  {"url" : "http://someurl.com", "method" : "POST", "isauth" : false }

如何循环浏览各种 JSON 元素并确定键及其值?我查看了jackson-coreJsonParser。我知道如何获取下一个“令牌”并确定它是什么类型的令牌(即字段名称、值、数组开始等),但是,我不知道如何获取实际令牌的值。

例如:

public void parse(String json)  {
  try {
     JsonFactory f = new JsonFactory();
     JsonParser parser = f.createParser(json);
     JsonToken token = parser.nextToken();
     while (token != null) {
        if (token.equals(JsonToken.START_ARRAY)) {
           logger.debug("Start Array : " + token.toString());
        } else if (token.equals(JsonToken.END_ARRAY)) {
           logger.debug("End Array : " + token.toString());
        } else if (token.equals(JsonToken.START_OBJECT)) {
           logger.debug("Start Object : " + token.toString());
        } else if (token.equals(JsonToken.END_OBJECT)) {
           logger.debug("End Object : " + token.toString());
        } else if (token.equals(JsonToken.FIELD_NAME)) {
           logger.debug("Field Name : " + token.toString());
        } else if (token.equals(JsonToken.VALUE_FALSE)) {
           logger.debug("Value False : " + token.toString());
        } else if (token.equals(JsonToken.VALUE_NULL)) {
           logger.debug("Value Null : " + token.toString());
        } else if (token.equals(JsonToken.VALUE_NUMBER_FLOAT)) {
           logger.debug("Value Number Float : " + token.toString());
        } else if (token.equals(JsonToken.VALUE_NUMBER_INT)) {
          logger.debug("Value Number Int : " + token.toString());
        } else if (token.equals(JsonToken.VALUE_STRING)) {
           logger.debug("Value String : " + token.toString());
        } else if (token.equals(JsonToken.VALUE_TRUE)) {
           logger.debug("Value True : " + token.toString());
        } else {
           logger.debug("Something else : " + token.toString());
        }
        token = parser.nextToken();
     }
  } catch (Exception e) {
     logger.error("", e);
  }
}

jackson 或其他库(gsonsimple-json)中是否有一个类可以生成一棵树,或者允许循环遍历 json 元素并获取除值之外的实际键名?

【问题讨论】:

  • 嗯,最简单的部分是解析成地图和列表——这是每一个合理的 JSON 解析器都可以做到的。当然,更难的部分是弄清楚数据的含义,如果每次都完全不同的话。
  • (如果您还没有这样做,请访问 json.org 并了解基本的 JSON 语法。所有值都是数字、布尔值、字符串、对象(映射)、数组或“null” -- 没有更复杂的了。)
  • 感谢您的建议和链接。我实际上对 JSON 很熟悉;只是在没有注释的情况下不解析和/或立即转换到现有的 pojo 结构。
  • 在世界其他地方,在 Java 之外,您就是这样做的。解析,取回一个通用对象,如有必要,请执行instanceOf 或其他任何操作以查看您得到的内容,然后从那里开始工作。您永远不会有完全未知的格式,但有时格式会因某些因素而异。

标签: java json parsing jackson


【解决方案1】:

看看Jacksons built-in tree model feature

您的代码将是:

public void parse(String json)  {
       JsonFactory factory = new JsonFactory();

       ObjectMapper mapper = new ObjectMapper(factory);
       JsonNode rootNode = mapper.readTree(json);  

       Iterator<Map.Entry<String,JsonNode>> fieldsIterator = rootNode.fields();
       while (fieldsIterator.hasNext()) {

           Map.Entry<String,JsonNode> field = fieldsIterator.next();
           System.out.println("Key: " + field.getKey() + "\tValue:" + field.getValue());
       }
}

【讨论】:

  • 是的,这就是我需要的。谢谢你。对于阅读本文的其他人,我发现this answer 也可能有所帮助。
  • 在任何其他语言中,这将被简单地称为“解析的 JSON”,并且是您经常使用的。
  • 在 #readTree 调用周围需要尝试 catch,因为 ti 会抛出检查的 JsonProcessingException
  • 在 "Key:"field.getKey() 中缺少一个 + :)
【解决方案2】:

如果其他库适合您,您可以尝试org.json

JSONObject object = new JSONObject(myJSONString);
String[] keys = JSONObject.getNames(object);

for (String key : keys)
{
    Object value = object.get(key);
    // Determine type of value and do something with it...
}

【讨论】:

  • 很高兴知道,因为我并不局限于杰克逊图书馆。谢谢。
  • 这才是真正的解决方案:简单而优雅。谢谢。
  • object.getName() is not a member of 'value getNames is not a member of org.json.JSONObject'
  • @AshishRatan 你是对的。 getNames() 是 JSONObject 的静态方法。我修复了代码。
  • 如果您不知道嵌套层数,这将如何工作?你不需要使用递归吗?
【解决方案3】:

找到以下代码,使用 Gson 库解析未知 Json 对象。

public class JsonParsing {
static JsonParser parser = new JsonParser();

public static HashMap<String, Object> createHashMapFromJsonString(String json) {

    JsonObject object = (JsonObject) parser.parse(json);
    Set<Map.Entry<String, JsonElement>> set = object.entrySet();
    Iterator<Map.Entry<String, JsonElement>> iterator = set.iterator();
    HashMap<String, Object> map = new HashMap<String, Object>();

    while (iterator.hasNext()) {

        Map.Entry<String, JsonElement> entry = iterator.next();
        String key = entry.getKey();
        JsonElement value = entry.getValue();

        if (null != value) {
            if (!value.isJsonPrimitive()) {
                if (value.isJsonObject()) {

                    map.put(key, createHashMapFromJsonString(value.toString()));
                } else if (value.isJsonArray() && value.toString().contains(":")) {

                    List<HashMap<String, Object>> list = new ArrayList<>();
                    JsonArray array = value.getAsJsonArray();
                    if (null != array) {
                        for (JsonElement element : array) {
                            list.add(createHashMapFromJsonString(element.toString()));
                        }
                        map.put(key, list);
                    }
                } else if (value.isJsonArray() && !value.toString().contains(":")) {
                    map.put(key, value.getAsJsonArray());
                }
            } else {
                map.put(key, value.getAsString());
            }
        }
    }
    return map;
}
}

【讨论】:

    【解决方案4】:

    JSON 格式未知到HashMap

    JSONJson

    public static JsonParser parser = new JsonParser();
    public static void main(String args[]) {
         writeJson("JsonFile.json");
         readgson("JsonFile.json");
    }
    public static void readgson(String file) {
        try {
            System.out.println( "Reading JSON file from Java program" );
    
            FileReader fileReader = new FileReader( file );
            com.google.gson.JsonObject object = (JsonObject) parser.parse( fileReader );
    
            Set <java.util.Map.Entry<String, com.google.gson.JsonElement>> keys = object.entrySet();
            if ( keys.isEmpty() ) {
                System.out.println( "Empty JSON Object" );
            }else {
                Map<String, Object> map = json_UnKnown_Format( keys );
                System.out.println("Json 2 Map : "+map);
            }
    
        } catch (IOException ex) {
            System.out.println("Input File Does not Exists.");
        }
    }
    public static Map<String, Object> json_UnKnown_Format( Set <java.util.Map.Entry<String, com.google.gson.JsonElement>> keys ){
        Map<String, Object> jsonMap = new HashMap<String, Object>();
        for (Entry<String, JsonElement> entry : keys) {
            String keyEntry = entry.getKey();
            System.out.println(keyEntry + " : ");
            JsonElement valuesEntry =  entry.getValue();
            if (valuesEntry.isJsonNull()) {
                System.out.println(valuesEntry);
                jsonMap.put(keyEntry, valuesEntry);
            }else if (valuesEntry.isJsonPrimitive()) {
                System.out.println("P - "+valuesEntry);
                jsonMap.put(keyEntry, valuesEntry);
            }else if (valuesEntry.isJsonArray()) {
                JsonArray array = valuesEntry.getAsJsonArray();
                List<Object> array2List = new ArrayList<Object>();
                for (JsonElement jsonElements : array) {
                    System.out.println("A - "+jsonElements);
                    array2List.add(jsonElements);
                }
                jsonMap.put(keyEntry, array2List);
            }else if (valuesEntry.isJsonObject()) {             
                 com.google.gson.JsonObject obj = (JsonObject) parser.parse(valuesEntry.toString());                    
                 Set <java.util.Map.Entry<String, com.google.gson.JsonElement>> obj_key = obj.entrySet();
                 jsonMap.put(keyEntry, json_UnKnown_Format(obj_key));
            }
        }
        return jsonMap;
    }
    @SuppressWarnings("unchecked")
    public static void writeJson( String file ) {
    
        JSONObject json = new JSONObject();
    
        json.put("Key1", "Value");
        json.put("Key2", 777); // Converts to "777"
        json.put("Key3", null);
        json.put("Key4", false);
    
            JSONArray jsonArray = new JSONArray();
            jsonArray.put("Array-Value1");
            jsonArray.put(10); 
            jsonArray.put("Array-Value2");
    
        json.put("Array : ", jsonArray); // "Array":["Array-Value1", 10,"Array-Value2"]
    
            JSONObject jsonObj = new JSONObject();
            jsonObj.put("Obj-Key1", 20);
            jsonObj.put("Obj-Key2", "Value2");
            jsonObj.put(4, "Value2"); // Converts to "4"
    
        json.put("InnerObject", jsonObj);
    
            JSONObject jsonObjArray = new JSONObject();
                JSONArray objArray = new JSONArray();
                objArray.put("Obj-Array1");
                objArray.put(0, "Obj-Array3");
            jsonObjArray.put("ObjectArray", objArray);
    
        json.put("InnerObjectArray", jsonObjArray);
    
            Map<String, Integer> sortedTree = new TreeMap<String, Integer>();
            sortedTree.put("Sorted1", 10);
            sortedTree.put("Sorted2", 103);
            sortedTree.put("Sorted3", 14);
    
        json.put("TreeMap", sortedTree);        
    
        try {
            System.out.println("Writting JSON into file ...");
            System.out.println(json);
            FileWriter jsonFileWriter = new FileWriter(file);
            jsonFileWriter.write(json.toJSONString());
            jsonFileWriter.flush();
            jsonFileWriter.close();
            System.out.println("Done");
    
        } catch (IOException e) { 
            e.printStackTrace();
        }
    
    }
    

    【讨论】:

      【解决方案5】:

      这是我写的一个示例,展示了我如何解析 json 并弄乱其中的每个数字:

      public class JsonParser {
      
          public static Object parseAndMess(Object object) throws IOException {
              String json = JsonUtil.toJson(object);
              JsonNode jsonNode = parseAndMess(json);
              if(null != jsonNode)
                  return JsonUtil.toObject(jsonNode, object.getClass());
      
              return null;
          }
      
          public static JsonNode parseAndMess(String json) throws IOException {
              JsonNode rootNode = parse(json);
              return mess(rootNode, new Random());
          }
      
          private static JsonNode parse(String json) throws IOException {
              JsonFactory factory = new JsonFactory();
              ObjectMapper mapper = new ObjectMapper(factory);
              JsonNode rootNode = mapper.readTree(json);
              return rootNode;
      
          }
      
          private static JsonNode mess(JsonNode rootNode, Random rand) throws IOException {
              if (rootNode instanceof ObjectNode) {
                  Iterator<Map.Entry<String, JsonNode>> fieldsIterator = rootNode.fields();
                  while (fieldsIterator.hasNext()) {
                      Map.Entry<String, JsonNode> field = fieldsIterator.next();
                      replaceObjectNode((ObjectNode) rootNode, field, rand);
                  }
              } else if (rootNode instanceof ArrayNode) {
                  ArrayNode arrayNode = ((ArrayNode) rootNode);
                  replaceArrayNode(arrayNode, rand);
              }
              return rootNode;
          }
      
          private static void replaceObjectNode(ObjectNode rootNode, Map.Entry<String, JsonNode> field, Random rand)
                  throws IOException {
              JsonNode childNode = field.getValue();
              if (childNode instanceof IntNode) {
                  (rootNode).put(field.getKey(), rand.nextInt(1000));
              } else if (childNode instanceof LongNode) {
                  (rootNode).put(field.getKey(), rand.nextInt(1000000));
              } else if (childNode instanceof FloatNode) {
                  (rootNode).put(field.getKey(), format(rand.nextFloat()));
              } else if (childNode instanceof DoubleNode) {
                  (rootNode).put(field.getKey(), format(rand.nextFloat()));
              } else {
                  mess(childNode, rand);
              }
          }
      
          private static void replaceArrayNode(ArrayNode arrayNode, Random rand) throws IOException {
              int arrayLength = arrayNode.size();
              if(arrayLength == 0)
                  return;
              if (arrayNode.get(0) instanceof IntNode) {
                  for (int i = 0; i < arrayLength; i++) {
                      arrayNode.set(i, new IntNode(rand.nextInt(10000)));
                  }
              } else if (arrayNode.get(0) instanceof LongNode) {
                  arrayNode.removeAll();
                  for (int i = 0; i < arrayLength; i++) {
                      arrayNode.add(rand.nextInt(1000000));
                  }
              } else if (arrayNode.get(0) instanceof FloatNode) {
                  arrayNode.removeAll();
                  for (int i = 0; i < arrayLength; i++) {
                      arrayNode.add(format(rand.nextFloat()));
                  }
              } else if (arrayNode.get(0) instanceof DoubleNode) {
                  arrayNode.removeAll();
                  for (int i = 0; i < arrayLength; i++) {
                      arrayNode.add(format(rand.nextFloat()));
                  }
              } else {
                  for (int i = 0; i < arrayLength; i++) {
                      mess(arrayNode.get(i), rand);
                  }
              }
          }
      
          public static void print(JsonNode rootNode) throws IOException {
              System.out.println(rootNode.toString());
          }
      
          private static double format(float a) {
              return Math.round(a * 10000.0) / 100.0;
          }
      }
      

      【讨论】:

        【解决方案6】:

        您对来自 Jackson 的 Map 满意吗?

        ObjectMapper objectMapper = new ObjectMapper();
        Map<String, Object> map = objectMapper.readValue(jsonString, new TypeReference<HashMap<String,Object>>(){});
        

        或者可能是JsonNode

        JsonNode jsonNode = objectMapper.readTree(String jsonString) 
        

        【讨论】:

          【解决方案7】:

          要将 JSON 快速导入 Java 对象(地图),然后您可以“钻取”并使用它,您可以使用 json-io (https://github.com/jdereg/json-io)。这个库可以让你读入一个 JSON 字符串,并返回一个“地图的地图”表示。

          如果您的 JVM 中有相应的 Java 类,您可以读取 JSON,它会直接将其解析为 Java 类的实例。

          JsonReader.jsonToMaps(String json)
          

          其中 json 是包含要读取的 JSON 的字符串。返回值是一个 Map,其中的键将包含 JSON 字段,值将包含关联的值。

          JsonReader.jsonToJava(String json) 
          

          将读取相同的 JSON 字符串,返回值将是序列化为 JSON 的 Java 实例。如果您的 JVM 中有由

          编写的类,请使用此 API
          JsonWriter.objectToJson(MyClass foo).
          

          【讨论】:

          • 这没有提供问题的答案 - 在不知道 JSON 格式的情况下用 Java 解析 JSON。假设 OP 在他的 JVM 中有 Java 类 已转换为 JSON,这意味着他知道格式并且该格式并不像他所要求的那样动态。
          • json-io 不假定您的 JVM 中有这些类。 JsonReader.jsonToMaps() 将读取任何 JSON。结果是 Maps 表示的 Map。然后可以以这种 Map of Maps 格式操作此 Map of Map 的表示形式,甚至可以重新写回。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-02-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-08-14
          相关资源
          最近更新 更多