Convertir el objeto JSON con claves duplicadas a la matriz JSON

Tengo una cadena JSON que obtengo de una base de datos que contiene claves repetidas. Quiero eliminar las claves repetidas combinando sus valores en una matriz.

Por ejemplo

Entrada

{ "a":"b", "c":"d", "c":"e", "f":"g" } 

Salida

 { "a":"b", "c":["d","e"], "f":"g" } 

Los datos reales son un archivo grande que puede estar nested. No sabré de antemano qué o cuántos pares hay.

Necesito usar Java para esto. org.json lanza una excepción debido a las claves repetidas, gson puede analizar la cadena pero cada tecla repetida sobrescribe la última. Necesito guardar todos los datos.

Si es posible, me gustaría hacer esto sin editar ningún código de biblioteca

A partir de hoy, la biblioteca org.json versión 20170516 proporciona el método accumulate() que almacena las entradas de clave duplicadas en JSONArray

 JSONObject jsonObject = new JSONObject(); jsonObject.accumulate("a", "b"); jsonObject.accumulate("c", "d"); jsonObject.accumulate("c", "e"); jsonObject.accumulate("f", "g"); System.out.println(jsonObject); 

Salida:
{
“a”: “b”,
“c”: [“d”, “e”],
“f”: “g”
}

Quiero eliminar las claves repetidas combinando sus valores en una matriz.

Piensa en otra cosa que no sea la biblioteca de análisis JSON. Es un progtwig Java muy simple que usa el método String.split() que convierte Json String en Map> sin usar ninguna biblioteca .

Código de muestra:

 String jsonString = ... // remove enclosing braces and double quotes jsonString = jsonString.substring(2, jsonString.length() - 2); Map> map = new HashMap>(); for (String values : jsonString.split("\",\"")) { String[] keyValue = values.split("\":\""); String key = keyValue[0]; String value = keyValue[1]; if (!map.containsKey(key)) { map.put(key, new ArrayList()); } map.get(key).add(value); } 

salida:

 { "f": ["g"], "c": ["d","e"], "a": ["b"] } 

Para lograr lo que desea, necesita crear algún tipo de clase personalizada, ya que JSON técnicamente no puede tener 2 valores en una sola clave. A continuación se muestra un ejemplo:

 public class SomeClass { Map> values = new HashMap>(); public void add(String key, Object o) { List value = new ArrayList(); if (values.containsKey(key)) { value = values.get(key); } value.add(o); values.put(key, value); } public JSONObject toJson() throws JSONException { JSONObject json = new JSONObject(); JSONArray tempArray = null; for (Entry> en : values.entrySet()) { tempArray = new JSONArray(); for (Object o : en.getValue()) { tempArray.add(o); } json.put(en.getKey(), tempArray); } return json; } } 

Luego, puede recuperar los valores de la base de datos, llamar a la función .add(String key, Object o) con el nombre de la columna de la base de datos y el valor (como parámetro de Object ). Luego llame a .toJson() cuando haya terminado.

Gracias a Mike Elofson y Braj por ayudarme en la dirección correcta. Solo quería que las claves con múltiples valores se convirtieran en matrices, así que tuve que modificar un poco el código. Eventualmente quiero que funcione también para JSON nested, ya que actualmente asume que es plano. Sin embargo, el siguiente código funciona para lo que necesito en este momento.

 public static String repeatedKeysToArrays(String jsonIn) throws JSONException { //This assumes that the json is flat String jsonString = jsonIn.substring(2, jsonIn.length() - 2); JSONObject obj = new JSONObject(); for (String values : jsonString.split("\",\"")) { String[] keyValue = values.split("\":\""); String key = keyValue[0]; String value = ""; if (keyValue.length>1) value = keyValue[1]; if (!obj.has(key)) { obj.put(key, value); } else { Object Oold = obj.get(key); ArrayList newlist = new ArrayList(); //Try to cast as JSONArray. Otherwise, assume it is a String if (Oold.getClass().equals(JSONArray.class)) { JSONArray old = (JSONArray)Oold; //Build replacement value for (int i=0; i(Arrays.asList(new String[] {(String)Oold})); newlist.add(value); JSONArray newarr = new JSONArray( newlist ); obj.put(key,newarr); } } return obj.toString(); }