2010-03-08 6 views
38

Sto consumando del JSON da due fonti diverse, finisco con due JSONObject s e mi piacerebbe combinarli in uno solo.Unisci (Concat) Multiple JSONObjects

dati:

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

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

codice, utilizzando http://json.org/java/ libreria:

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

Quindi, in questa situazione, mi piacerebbe combinare Obj1 e Obj2, sia per fare una totalmente nuova JSONObject o concat uno all'altro. Qualche idea oltre a metterli tutti a parte e aggiungerli individualmente entro il put s?

risposta

37

Se si desidera un nuovo oggetto con due chiavi, Object1 e Object2, si può fare:

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

Se si desidera unirli, ad es un oggetto di livello superiore ha 5 tasti (Stringkey1, ArrayKey, StringKey2, StringKey3, StringKey4), io penso che si debba farlo manualmente:

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

questo sarebbe molto più facile se JSONObject implementato Map, e sostenuto putAll.

+0

Sto cercando di utilizzare il tuo secondo snippet di codice in Android, ma non vedo una funzione getNames statica su JSONObject. È stato aggiunto in una versione più recente della libreria org.json? –

+2

@AustynMahoney, non sono sicuro della cronologia, ma per Android è possibile utilizzare il metodo di istanza ['JSONObject.names'] (http://developer.android.com/reference/org/json/JSONObject.html#names%28 % 29). –

+0

@AustynMahoney Non era lì nella libreria di Android json l'ho provato già. Non è stato menzionato anche nella documentazione di Android. È stato menzionato solo qui http://www.json.org/javadoc/org/json/JSONObject.html – kishore

19

È possibile creare un nuovo JSONObject come questo:

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 questo codice, se si dispone di eventuali chiavi ripetute tra Obj1 e Obj2 rimarrà il valore in Obj2. Se si desidera che i valori in Obj1 da conservare è necessario invertire l'ordine della matrice in linea 2.

+0

non sapevo circa le JSONObject.getNames metodo statico, rende il codice molto più semplice, vedere la risposta di Matteo di seguito che riduce il codice che lo utilizza. –

+0

Nella prima riga aggiungi 'new' prima di' JSONObject() ', la modifica non è consentita per meno di 6 caratteri. –

16

In alcuni casi è necessaria un'unione profonda, ovvero unire il contenuto dei campi con nomi identici (proprio come quando si copiano le cartelle in Windows). Questa funzione può essere utile:

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

Cosa succede se un valore all'interno di "origine" è di tipo JSONArray ?. In questo caso, avremmo bisogno di unire questo array con l'equivalente JSONArray dell'oggetto target. – pgoldweic

3

Questo metodo involucro aiuterà:

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

Oltre a @ di Erel risposta, ho dovuto fare questa modifica (sto usando org.json.simple) per l'esterno else per trattare 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

Grazie a Erel. Ecco una versione 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

ho usato stringa per concatenare nuovo oggetto a un oggetto esistente.


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

Metodo pronto per unire qualsiasi numero di 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; 
}