2010-03-08 20 views
38

Estoy consumiendo algunos JSON de dos fuentes diferentes, termino con dos JSONObject sy me gustaría combinarlos en uno solo.Merge (Concat) Multiple JSONObjects

datos:

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

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

Código, usando http://json.org/java/ biblioteca:

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

Así que en esta situación me gustaría combinar Obj1 y Obj2, ya sea para hacer una totalmente nueva JSONObject o uno concat al otro. ¿Alguna idea además de separarlas y agregarlas individualmente por put s?

Respuesta

37

Si usted quiere un nuevo objeto con dos llaves, Object1 y Object2, que puede hacer:

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

Si desea fusionarlos, por ejemplo, un objeto de nivel superior tiene 5 teclas (Stringkey1, ArrayKey, StringKey2, StringKey3, StringKey4), yo creo que hay que hacerlo manualmente:

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

Esto sería mucho más fácil si JSONObject implementado Map, y apoyado putAll.

+0

Estoy tratando de usar su segundo fragmento de código en Android, pero no veo una función estática getNames en JSONObject. ¿Se agregó esto en una versión más nueva de la biblioteca org.json? –

+2

@AustynMahoney, no estoy seguro sobre la historia, pero para Android puede usar el método de instancia ['JSONObject.names'] (http://developer.android.com/reference/org/json/JSONObject.html#names%28 % 29). –

+0

@AustynMahoney No estaba allí en la biblioteca de android json ya lo intenté. No fue mencionado en la documentación de Android también. Solo se mencionó aquí http://www.json.org/javadoc/org/json/JSONObject.html – kishore

19

se puede crear una nueva JSONObject así:

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)); 
    } 
} 

Con este código, si tiene alguna claves repetidas entre Obj1Obj2 y el valor en Obj2 permanecerá. Si desea que los valores que se le mantenga Obj1 que debe invertir el orden de la matriz en la línea 2.

+0

Yo no sabía nada de las JSONObject.getNames método estático, que hace que el código mucho más simple, véase la respuesta de Mateo a continuación que reduce el código que lo usa. –

+0

En la primera línea agrega 'new' antes de' JSONObject() ', no se permite la edición para menos de 6 caracteres. –

16

En algunos casos, necesita una fusión profunda, es decir, combinar el contenido de campos con nombres idénticos (al igual que al copiar carpetas en Windows). Esta función puede ser útil:

/** 
* 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

¿Qué pasa si un valor dentro de 'fuente' es del tipo JSONArray ?. En este caso, necesitaríamos fusionar esta matriz con el JSONArray equivalente del objeto de destino. – pgoldweic

3

Este método de envoltura ayudará:

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

Además de la respuesta de @ erel, que tenía que hacer esta edición (estoy usando org.json.simple) al exterior else para tratar con 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

Gracias a Erel. Aquí hay una versión de 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

He utilizado una cadena para concatenar un nuevo objeto a un objeto existente.


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

Un método listo para combinar cualquier número de 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; 
}