2010-03-08 4 views
38

Я потребляю некоторые JSON из двух разных источников, в итоге получаю два JSONObject и я хотел бы объединить их в один.Merge (Concat) Несколько JSONObjects

данных:

"Object1": { 
    "Stringkey":"StringVal", 
    "ArrayKey": [Data0, Data1] 
} 

"Object2": { 
    "Stringkey":"StringVal", 
    "Stringkey":"StringVal", 
    "Stringkey":"StringVal", 
} 

код, используя http://json.org/java/ библиотека:

// jso1 and jso2 are some JSONObjects already instantiated 
JSONObject Obj1 = (JSONObject) jso.get("Object1"); 
JSONObject Obj2 = (JSONObject) jso.get("Object2"); 

Так что в этой ситуации я хотел бы объединить Obj1 и Obj2, либо сделать совершенно новый JSONObject или Concat один к другому. Любые идеи, помимо вытягивания их всех и индивидуального добавления в put s?

ответ

37

Если вы хотите новый объект с двумя ключами, Object1 и Object2, вы можете сделать:

JSONObject Obj1 = (JSONObject) jso1.get("Object1"); 
JSONObject Obj2 = (JSONObject) jso2.get("Object2"); 
JSONObject combined = new JSONObject(); 
combined.put("Object1", Obj1); 
combined.put("Object2", Obj2); 

Если вы хотите объединить их, то, например, верхний объект уровня имеет 5 ключей (Stringkey1, ArrayKey, StringKey2, StringKey3, StringKey4), я думаю, что вы должны сделать это вручную:

JSONObject merged = new JSONObject(Obj1, JSONObject.getNames(Obj1)); 
for(String key : JSONObject.getNames(Obj2)) 
{ 
    merged.put(key, Obj2.get(key)); 
} 

Это было бы намного проще, если JSONObject реализована Map и поддерживается putAll.

+0

Я пытаюсь использовать ваш второй фрагмент кода в Android, но я не вижу статической функции getNames в JSONObject. Было ли это добавлено в более новую версию библиотеки org.json? –

+2

@AustynMahoney, не уверен в истории, но для Android вы можете использовать метод экземпляра ['JSONObject.names'] (http://developer.android.com/reference/org/json/JSONObject.html#names%28 % 29). –

+0

@AustynMahoney Этого не было в библиотеке Android json, я уже пробовал. Он также не упоминался в документации по Android. Это упоминалось только здесь http://www.json.org/javadoc/org/json/JSONObject.html – kishore

19

Вы можете создать новый JSONObject так:

JSONObject merged = new JSONObject(); 
JSONObject[] objs = new JSONObject[] { Obj1, Obj2 }; 
for (JSONObject obj : objs) { 
    Iterator it = obj.keys(); 
    while (it.hasNext()) { 
     String key = (String)it.next(); 
     merged.put(key, obj.get(key)); 
    } 
} 

С помощью этого кода, если у вас есть какие-либо повторяющиеся ключи между Obj1 и Obj2 значение в Obj2 останется. Если вы хотите, чтобы значения в Obj1, чтобы быть вы должны инвертировать порядок массива в строке 2.

+0

Я не знал о статических JSONObject.getNames метод, это делает код намного проще, см ответа Мэтью ниже который уменьшает используемый код. –

+0

В первой строке добавить 'new' перед' JSONObject() ', редактировать не разрешено для менее 6 символов. –

16

В некоторых случаях требуется глубокое слияние, т. Е. Объединить содержимое полей с одинаковыми именами (так же, как при копировании папок в Windows). Эта функция может быть полезной:

/** 
* Merge "source" into "target". If fields have equal name, merge them recursively. 
* @return the merged object (target). 
*/ 
public static JSONObject deepMerge(JSONObject source, JSONObject target) throws JSONException { 
    for (String key: JSONObject.getNames(source)) { 
      Object value = source.get(key); 
      if (!target.has(key)) { 
       // new value for "key": 
       target.put(key, value); 
      } else { 
       // existing value for "key" - recursively deep merge: 
       if (value instanceof JSONObject) { 
        JSONObject valueJson = (JSONObject)value; 
        deepMerge(valueJson, target.getJSONObject(key)); 
       } else { 
        target.put(key, value); 
       } 
      } 
    } 
    return target; 
} 



/** 
* demo program 
*/ 
public static void main(String[] args) throws JSONException { 
    JSONObject a = new JSONObject("{offer: {issue1: value1}, accept: true}"); 
    JSONObject b = new JSONObject("{offer: {issue2: value2}, reject: false}"); 
    System.out.println(a+ " + " + b+" = "+JsonUtils.deepMerge(a,b)); 
    // prints: 
    // {"accept":true,"offer":{"issue1":"value1"}} + {"reject":false,"offer":{"issue2":"value2"}} = {"reject":false,"accept":true,"offer":{"issue1":"value1","issue2":"value2"}} 
} 
+0

Что делать, если значение в 'source' имеет тип JSONArray ?. В этом случае нам нужно объединить этот массив с эквивалентным JSONArray целевого объекта. – pgoldweic

3

Этот метод обертка поможет:

private static JSONObject merge(JSONObject... jsonObjects) throws JSONException { 

    JSONObject jsonObject = new JSONObject(); 

    for(JSONObject temp : jsonObjects){ 
     Iterator<String> keys = temp.keys(); 
     while(keys.hasNext()){ 
      String key = keys.next(); 
      jsonObject.put(key, temp.get(key)); 
     } 

    } 
    return jsonObject; 
} 
0

В дополнение к @ EREL Ответим, я должен был сделать это изменение (я использую org.json.simple) к наружному else для работы с JSONArray's:

  // existing value for "key" - recursively deep merge: 
      if (value instanceof JSONObject) { 
       JSONObject valueJson = (JSONObject)value; 
       deepMerge(valueJson, (JSONObject) target.get(key)); 
      } 

      // insert each JSONArray's JSONObject in place 
      if (value instanceof JSONArray) { 
       ((JSONArray) value).forEach(
        jsonobj -> 
        ((JSONArray) target.get(key)).add(jsonobj)); 
      } 
      else { 
       target.put(key, value); 
      } 
0

Благодаря Erel. Вот версия Gson.

/** 
* Merge "source" into "target". If fields have equal name, merge them recursively. 
* Null values in source will remove the field from the target. 
* Override target values with source values 
* Keys not supplied in source will remain unchanged in target 
* 
* @return the merged object (target). 
*/ 
public static JsonObject deepMerge(JsonObject source, JsonObject target) throws Exception { 

    for (Map.Entry<String,JsonElement> sourceEntry : source.entrySet()) { 
     String key = sourceEntry.getKey(); 
     JsonElement value = sourceEntry.getValue(); 
     if (!target.has(key)) { 
      //target does not have the same key, so perhaps it should be added to target 
      if (!value.isJsonNull()) //well, only add if the source value is not null 
      target.add(key, value); 
     } else { 
      if (!value.isJsonNull()) { 
       if (value.isJsonObject()) { 
        //source value is json object, start deep merge 
        deepMerge(value.getAsJsonObject(), target.get(key).getAsJsonObject()); 
       } else { 
        target.add(key,value); 
       } 
      } else { 
       target.remove(key); 
      } 
     } 
    } 
    return target; 
} 



/** 
* simple test 
*/ 
public static void main(String[] args) throws Exception { 
    JsonParser parser = new JsonParser(); 
    JsonObject a = null; 
    JsonObject b = null; 
    a = parser.parse("{offer: {issue1: null, issue2: null}, accept: true, reject: null}").getAsJsonObject(); 
    b = parser.parse("{offer: {issue2: value2}, reject: false}").getAsJsonObject(); 
    System.out.println(deepMerge(a,b)); 
    // prints: 
    // {"offer":{},"accept":true} 
    a = parser.parse("{offer: {issue1: value1}, accept: true, reject: null}").getAsJsonObject(); 
    b = parser.parse("{offer: {issue2: value2}, reject: false}").getAsJsonObject(); 
    System.out.println(deepMerge(a,b)); 
    // prints: 
    // {"offer":{"issue2":"value2","issue1":"value1"},"accept":true} 

} 
0

Я использовал строку, чтобы связать новый объект с существующим объектом.


private static void concatJSON() throws IOException, InterruptedException { 

    JSONParser parser = new JSONParser(); 
    Object obj = parser.parse(new FileReader(new File(Main.class.getResource("/file/user.json").toURI()))); 


    JSONObject jsonObj = (JSONObject) obj; //usernameJsonObj 

    String [] values = {"0.9" , Date.from(Calendar.getInstance().toInstant()).toLocaleString()}, 
      innermost = {"Accomplished", "LatestDate"}, 
      inner = {"Lesson1", "Lesson2", "Lesson3", "Lesson4"}; 
    String in = "Jayvee Villa"; 

    JSONObject jo1 = new JSONObject(); 
    for (int i = 0; i < innermost.length; i++) 
     jo1.put(innermost[i], values[i]); 

    JSONObject jo2 = new JSONObject(); 
    for (int i = 0; i < inner.length; i++) 
     jo2.put(inner[i], jo1); 

    JSONObject jo3 = new JSONObject(); 
    jo3.put(in, jo2); 

    String merger = jsonObj.toString().substring(0, jsonObj.toString().length()-1) + "," +jo3.toString().substring(1); 

    System.out.println(merger); 
    FileWriter pr = new FileWriter(file); 
    pr.write(merger); 
    pr.flush(); 
    pr.close(); 
} 
2

Готовый способом объединить любое количество JSONObjects:

/** 
* Merges given JSONObjects. Values for identical key names are merged 
* if they are objects, otherwise replaced by the latest occurence. 
* 
* @param jsons JSONObjects to merge. 
* 
* @return Merged JSONObject. 
*/ 
public static JSONObject merge(
    JSONObject[] jsons) { 

    JSONObject merged = new JSONObject(); 
    Object parameter; 

    for (JSONObject added : jsons) { 

    for (String key : toStringArrayList(added.names())) { 
     try { 

     parameter = added.get(key); 

     if (merged.has(key)) { 
      // Duplicate key found: 
      if (added.get(key) instanceof JSONObject) { 
      // Object - allowed to merge: 
      parameter = 
       merge(
       new JSONObject[]{ 
        (JSONObject) merged.get(key), 
        (JSONObject) added.get(key)}); 
      } 
     } 

     // Add or update value on duplicate key: 
     merged.put(
      key, 
      parameter); 

     } catch (JSONException e) { 
     e.printStackTrace(); 
     } 
    } 

    } 

    return merged; 
} 

/** 
* Convert JSONArray to ArrayList<String>. 
* 
* @param jsonArray Source JSONArray. 
* 
* @return Target ArrayList<String>. 
*/ 
public static ArrayList<String> toStringArrayList(JSONArray jsonArray) { 

    ArrayList<String> stringArray = new ArrayList<String>(); 
    int arrayIndex; 

    for (
    arrayIndex = 0; 
    arrayIndex < jsonArray.length(); 
    arrayIndex++) { 

    try { 
     stringArray.add(
     jsonArray.getString(arrayIndex)); 
    } catch (JSONException e) { 
     e.printStackTrace(); 
    } 
    } 

    return stringArray; 
} 
Смежные вопросы