Tengo una Cadena Json con valores duplicados:

Cadena json = "{\"Sign_In_Type\":\"la Acción\",\"Sign_In_Type\":\"la Acción\"}"; 

que correctamente, se produce una excepción cuando intento crear un JSONObject:

 
try { 
JSONObject json_obj = new JSONObject(json); 
Tipo de cadena = json_obj.getString("Sign_In_Type"); 
} catch (JSONException e) { 
throw new RuntimeException(e); 
} 

De Error:

Excepción en el thread "main" java.lang.RuntimeException: org.json.JSONException: clave Duplicada "Sign_In_Type" 
en com.campanja.app.Subir.principal(Subir.java:52) 
Causado por: org.json.JSONException: clave Duplicada "Sign_In_Type" 
en org.json.JSONObject.putOnce(JSONObject.java:1076) 
en org.json.JSONObject.(JSONObject.java:205) 
en org.json.JSONObject.(JSONObject.java:402) 
en com.campanja.app.Subir.principal(Subir.java:49) 

¿Hay una forma inteligente de extracción o la comprobación de duplicados antes de convertirlo a un JSONOBject?
He intentado crear:

 Set = new HashSet(Matrices.asList(json)); 

pero que me da:

[{"Sign_In_Type":"Acción","Sign_In_Type":"Acción"}] 

Cualquier sugerencia sobre la bienvenida, gracias!

OriginalEl autor C.A | 2013-09-25

6 Comentarios

  1. 3

    Dos opciones que puedo pensar de buenas a primeras:

    • Analizar la cadena utilizando marchitan regex o tokens, agregue cada par clave-valor a un hashmap, y en el fin de recrear su documento JSON con los duplicados eliminados. En este caso, aunque yo sólo eliminar los pares clave-valor que es exactamente el mismo.
    • Descargar el código fuente de org.json.JSONObject , y hacer una ligera modificación en el código automáticamente para dejar fuera de duplicados. Esto es un poco peligroso si. Otra opción es crear una versión modificada que simplemente valida y se modifica.

    La Ampliación De JSONObject Ejemplo De Trabajo

    El código de abajo, le permite crear un JSONOBbject con una cadena que contiene un duplicado de las llaves. Se producen excepciones sólo cuando se tienen dos valores clave que tienen la misma clave, pero con diferentes valores. Esto era porque yo creo que sería un problema para elegir al azar cuál de los dos debe ser asignado (por ejemplo, el valor posterior?). Por supuesto, esto puede ser cambiado para que funcione como se desea (por ejemplo, mantener el último valor de múltiples teclas).

    Modificado Clase

    import org.json.JSONException;
    import org.json.JSONObject;
    
    
    public class JSONObjectIgnoreDuplicates extends JSONObject {
    
         public JSONObjectIgnoreDuplicates(String json) {
            super(json);
        }
    
        public JSONObject putOnce(String key, Object value) throws JSONException {
                Object storedValue;
                if (key != null && value != null) {
                    if ((storedValue = this.opt(key)) != null ) {
                        if(!storedValue.equals(value))                          //Only through Exception for different values with same key
                            throw new JSONException("Duplicate key \"" + key + "\"");
                        else
                            return this;
                    }
                    this.put(key, value);
                }
                return this;
            }
    }

    Principal método de

    String json = "{\"Sign_In_Type\":\"Action\",\"Sign_In_Type\":\"Action\"}";
               try {
                    JSONObject json_obj = new JSONObjectIgnoreDuplicates(json);
                    String type = json_obj.getString("Sign_In_Type");
                } catch (JSONException e) {
                    throw new RuntimeException(e);
                }   
    Tal vez heredan de la modificación de la clase de JSONObject y sobrescribir sólo putOnce(…), a continuación, utilizar el objeto heredado?
    Exáctamente! Lo que estoy haciendo ahora mismo…
    Gracias, va a hacer ahora!
    Acaba de actualizar mi respuesta así que incluir el código. No está seguro de qué versión tienes, aunque, JSONObject fue actualizado hace 3 meses pero putOnce no parecen haber cambiado: github.com/douglascrockford/JSON-java/archive/master.zip

    OriginalEl autor Menelaos Bakopoulos

  2. 0

    Suponiendo que
    Cadena json = «{\»Sign_In_Type\»:\»la Acción\»,\»Sign_In_Type\»:\»la Acción\»}»;
    es una ficción para las pruebas, puedo preguntar si la creación de los datos como una Cadena es la mejor opción en el primer lugar? ¿Por qué no un HashMap, o alguna otra estructura que sobrescribe los datos de la posterior reutiliza de un nombre o los ignora o se produce un error al agregar? No espere hasta que la conversión a JSON para que sus datos válidos.

    Hola Dan, estoy leyendo desde una DB por lo que en realidad viene así. BR
    Lo siento, perdí el comentario antes. Puede la base de datos de la consulta se persuadió a pasar valores únicos?

    OriginalEl autor Dan

  3. 0

    Me ampliado Menelaos Bakopoulos respuesta, de manera que si los valores internos son también con los duplicados, no crear problemas. la primera solución trabajado en el primer nivel solamente.

    public class JSONObjectIgnoreDuplicates extends JSONObject {
    public JSONObjectIgnoreDuplicates(JSONTokener x) throws JSONException {
    super(x);
    }
    @Override
    public JSONObject putOnce(String key, Object value) throws JSONException {
    Object storedValue;
    if (key != null && value != null) {
    if ((storedValue = this.opt(key)) != null) {
    if (!storedValue.toString().equals(value.toString())) //Only throw Exception for different values with same key
    throw new JSONException("Duplicate key \"" + key + "\"");
    else
    return this;
    }
    this.put(key, value);
    }
    return this;
    }
    }
    private class JsonDupTokener extends JSONTokener {
    public JsonDupTokener(String s) {
    super(s);
    }
    @Override
    public Object nextValue() throws JSONException {
    char c = this.nextClean();
    switch (c) {
    case '\"':
    case '\'':
    return this.nextString(c);
    case '[':
    this.back();
    return new JSONArray(this);
    case '{':
    this.back();
    return new JSONObjectIgnoreDuplicates(this);
    default:
    StringBuffer sb;
    for (sb = new StringBuffer(); c >= 32 && ",:]}/\\\"[{;=#".indexOf(c) < 0; c = this.next()) {
    sb.append(c);
    }
    this.back();
    String string = sb.toString().trim();
    if ("".equals(string)) {
    throw this.syntaxError("Missing value");
    } else {
    return JSONObject.stringToValue(string);
    }
    }
    }
    }

    OriginalEl autor Asaf Bartov

  4. 0

    Lo siento, no puedo comentar sobre Menelaos Bakopoulos’ respuesta debido a la reputación<50… Estúpido sistema de

    Su solución por desgracia no funciona aquí:

    SEVERE: ERROR converting JSON to XML org.json.JSONException: Duplicate key "id"
    org.json.JSONObject.putOnce(JSONObject.java:1076)
    org.json.JSONObject.<init>(JSONObject.java:205)
    org.json.JSONTokener.nextValue(JSONTokener.java:344)
    org.json.JSONArray.<init>(JSONArray.java:125)
    org.json.JSONTokener.nextValue(JSONTokener.java:348)
    org.json.JSONObject.<init>(JSONObject.java:205)
    JSONUtilities.JSONObjectIgnoreDuplicates.<init>(JSONUtilities.java:38)

    Parece que llamar a super(json) en JSONObjectIgnoreDuplicates‘s constructor envía el código en un bucle dentro de JSONObject, no JSONObjectIgnoreDuplicates ;{

    Actualmente estoy tratando de Asaf Bartov la solución, pero no hay ninguna llamada de JSONObjectIgnoreDuplicates a JsonDupTokener, por lo que además de sobrecargar el constructor de JSONObjectIgnoreDuplicates de la siguiente manera, no veo cómo se podría trabajar:

        public JSONObjectIgnoreDuplicates(String json) throws JSONException {
    this(new JSONDupTokener(json));
    }

    EDIT: me puede confirmar esto funciona :))))

    Gracias a todos!!!!

    OriginalEl autor user2115112

  5. 0

    Con Google Gson usted puede decidir qué hacer con duplicados en la cadena de entrada. Usted necesita registrar su propio TypeAdapter responsable de la serialización/deserialización de objetos. Tendría este aspecto:

    //this implementation converts the json string to a Map<String, String>,
    //saving only the first duplicate key and dropping the rest
    class NoDuplicatesAdapter extends TypeAdapter<HashMap<String, String>> {
    @Override
    public void write(JsonWriter out, HashMap<String, String> value) throws IOException {
    out.beginObject();
    for (Map.Entry<String, String> e: value.entrySet()) {
    out.name(e.getKey()).value(e.getValue());
    }
    out.endObject();
    }
    @Override
    public HashMap<String, String> read(JsonReader in) throws IOException {
    final HashMap<String, String> map = new HashMap<>();
    in.beginObject();
    while (in.hasNext()) {
    String name = in.nextName();
    //putting value to the map only if this key is not present;
    //here you can actually find duplicate keys and decide what to do with them
    map.putIfAbsent(name, in.nextString());
    }
    in.endObject();
    return map;
    }
    }

    A continuación, usted puede analizar su cadena:

    String json = "{\"Sign_In_Type\":\"Action\",\"Sign_In_Type\":\"Action\"}";
    Type mapType = new TypeToken<Map<String, String>>() {}.getType();
    Map<String, String> map = new GsonBuilder()
    .registerTypeAdapter(mapType, new NoDuplicatesAdapter())
    .create()
    .fromJson(str, mapType);

    El mapa contendrá sólo la primera "Sign_In_Type".

    OriginalEl autor Kirill Simonov

Dejar respuesta

Please enter your comment!
Please enter your name here