¿Cómo iterar sobre un objeto JSON?

312

Yo uso una biblioteca JSON llamada JSONObject (no me importa cambiar si es necesario).

Sé cómo iterar JSONArrays, pero cuando analizo datos JSON de Facebook no obtengo una matriz, solo una JSONObject, pero necesito poder acceder a un elemento a través de su índice, como JSONObject[0]para obtener el primero, y yo No puedo entender cómo hacerlo.

{
   "http://http://url.com/": {
      "id": "http://http://url.com//"
   },
   "http://url2.co/": {
      "id": "http://url2.com//",
      "shares": 16
   }
   ,
   "http://url3.com/": {
      "id": "http://url3.com//",
      "shares": 16
   }
}
Eric Hjalmarsson
fuente

Respuestas:

594

Tal vez esto ayude:

JSONObject jsonObject = new JSONObject(contents.trim());
Iterator<String> keys = jsonObject.keys();

while(keys.hasNext()) {
    String key = keys.next();
    if (jsonObject.get(key) instanceof JSONObject) {
          // do something with jsonObject here      
    }
}
Rickey
fuente
20
Tenga cuidado con todos, jObject.keys () devuelve el iterador con orden de índice inverso.
macio.Jun
77
@ macio.Jun Sin embargo, el orden no importa en los mapas de propiedades: las claves JSONObjectestán desordenadas y su afirmación fue un simple reflejo de una implementación privada;)
caligari
66
¿Qué usar cuando necesitamos todas las teclas secuencialmente?
interesado
11
Leve objeción: ¿esto no lleva a hacer la búsqueda de claves dos veces? Tal vez sea mejor hacer 'Object o = jObject.get (key)', luego verifique su tipo y luego úselo, sin tener que llamar a get (key) nuevamente.
Tom
1
Los bucles @Tom For-Each son útiles al iterar sobre una colección:for (String key : keys)
caligari
86

para mi caso encontré iterar bien el names()trabajo

for(int i = 0; i<jobject.names().length(); i++){
    Log.v(TAG, "key = " + jobject.names().getString(i) + " value = " + jobject.get(jobject.names().getString(i)));
}
AsambleaX
fuente
1
Aunque este ejemplo no se entiende realmente como Iteratingen Java, ¡funciona bastante bien! Gracias.
Tim Visée
57

Evitaré el iterador ya que pueden agregar / eliminar objetos durante la iteración, también para el uso de código limpio para el bucle. será simplemente limpio y menos líneas.

Usando Java 8 y Lamda [Actualización 4/2/2019]

import org.json.JSONObject;

public static void printJsonObject(JSONObject jsonObj) {
    jsonObj.keySet().forEach(keyStr ->
    {
        Object keyvalue = jsonObj.get(keyStr);
        System.out.println("key: "+ keyStr + " value: " + keyvalue);

        //for nested objects iteration if required
        //if (keyvalue instanceof JSONObject)
        //    printJsonObject((JSONObject)keyvalue);
    });
}

Uso a la antigua usanza [Actualización 4/2/2019]

import org.json.JSONObject;

public static void printJsonObject(JSONObject jsonObj) {
    for (String keyStr : jsonObj.keySet()) {
        Object keyvalue = jsonObj.get(keyStr);

        //Print key and value
        System.out.println("key: "+ keyStr + " value: " + keyvalue);

        //for nested objects iteration if required
        //if (keyvalue instanceof JSONObject)
        //    printJsonObject((JSONObject)keyvalue);
    }
}

Respuesta original

import org.json.simple.JSONObject;
public static void printJsonObject(JSONObject jsonObj) {
    for (Object key : jsonObj.keySet()) {
        //based on you key types
        String keyStr = (String)key;
        Object keyvalue = jsonObj.get(keyStr);

        //Print key and value
        System.out.println("key: "+ keyStr + " value: " + keyvalue);

        //for nested objects iteration if required
        if (keyvalue instanceof JSONObject)
            printJsonObject((JSONObject)keyvalue);
    }
}
maaz
fuente
55
Nunca dijeron que estaban usando org.json.simple (que es una biblioteca de google). Desafortunadamente, el estándar org.json.JSONObject te obliga a usar un iterador.
Amalgovinus
1
Me salvaste pero aquí!
Lukuluba
1
org.json.JSONObject no tiene keySet ()
Ridhuvarshan
38

No puedo creer que no haya una solución más simple y segura que usar un iterador en estas respuestas ...

El names ()método JSONObject devuelve una JSONArrayde las JSONObjectclaves, por lo que simplemente puede recorrerlo en bucle:

JSONObject object = new JSONObject ();
JSONArray keys = object.names ();

for (int i = 0; i < keys.length (); ++i) {

   String key = keys.getString (i); // Here's your key
   String value = object.getString (key); // Here's your value

}
Acuna
fuente
1
¿Qué es el objeto aquí?
RCS
1
Es JSONObject. Algo así como JSONObject object = new JSONObject ("{\"key1\",\"value1\"}");. Pero no ponga JSON prima a ella, añadir elementos en ella con put ()el método: object.put ("key1", "value1");.
Acuña
18
Iterator<JSONObject> iterator = jsonObject.values().iterator();

while (iterator.hasNext()) {
 jsonChildObject = iterator.next();

 // Do whatever you want with jsonChildObject 

  String id = (String) jsonChildObject.get("id");
}
aviomaksim
fuente
jsonChildObject = iterator.next();probablemente debería definir jsonChildObject, como JSONObject jsonChildObject = iterator.next();, no?
kontur
1
Me gusta esta solución, pero declarar Iterator<JSONObject>dará una advertencia. Lo reemplazaría con el genérico <?>y haría un reparto en la llamada a next(). Además, usaría en getString("id")lugar de get("id")guardar haciendo un elenco.
RTF
9

org.json.JSONObject ahora tiene un método keySet () que devuelve ay se puede enlazar Set<String>fácilmente con un for-each.

for(String key : jsonObject.keySet())
Burrito
fuente
Creo que esta es la solución más conveniente. Gracias por el consejo :)
Yurii Rabeshko
1
¿Podrías completar tu ejemplo?
abismo
6

Primero pon esto en alguna parte:

private <T> Iterable<T> iteratorToIterable(final Iterator<T> iterator) {
    return new Iterable<T>() {
        @Override
        public Iterator<T> iterator() {
            return iterator;
        }
    };
}

O si tiene acceso a Java8, solo esto:

private <T> Iterable<T> iteratorToIterable(Iterator<T> iterator) {
    return () -> iterator;
}

Luego, simplemente repita las claves y valores del objeto:

for (String key : iteratorToIterable(object.keys())) {
    JSONObject entry = object.getJSONObject(key);
    // ...
Ebrahim Byagowi
fuente
He votado a favor de esto, pero "Clave de cadena: ...." no se compila, y no parece haber una forma de evitar una advertencia de lanzamiento no verificada en el iterador. Estúpidos iteradores.
Amalgovinus
2

Hice una pequeña función recursiva que atraviesa todo el objeto json y guarda la ruta clave y su valor.

// My stored keys and values from the json object
HashMap<String,String> myKeyValues = new HashMap<String,String>();

// Used for constructing the path to the key in the json object
Stack<String> key_path = new Stack<String>();

// Recursive function that goes through a json object and stores 
// its key and values in the hashmap 
private void loadJson(JSONObject json){
    Iterator<?> json_keys = json.keys();

    while( json_keys.hasNext() ){
        String json_key = (String)json_keys.next();

        try{
            key_path.push(json_key);
            loadJson(json.getJSONObject(json_key));
       }catch (JSONException e){
           // Build the path to the key
           String key = "";
           for(String sub_key: key_path){
               key += sub_key+".";
           }
           key = key.substring(0,key.length()-1);

           System.out.println(key+": "+json.getString(json_key));
           key_path.pop();
           myKeyValues.put(key, json.getString(json_key));
        }
    }
    if(key_path.size() > 0){
        key_path.pop();
    }
}
Skullbox
fuente
2

Usamos el siguiente conjunto de código para iterar sobre los JSONObjectcampos

Iterator iterator = jsonObject.entrySet().iterator();

while (iterator.hasNext())  {
        Entry<String, JsonElement> entry = (Entry<String, JsonElement>) iterator.next();
        processedJsonObject.add(entry.getKey(), entry.getValue());
}
Sanchi Girotra
fuente
1

Una vez tuve un json que tenía identificadores que debían incrementarse en uno ya que estaban indexados en 0 y eso estaba rompiendo el autoincremento Mysql.

Entonces, para cada objeto que escribí este código, podría ser útil para alguien:

public static void  incrementValue(JSONObject obj, List<String> keysToIncrementValue) {
        Set<String> keys = obj.keySet();
        for (String key : keys) {
            Object ob = obj.get(key);

            if (keysToIncrementValue.contains(key)) {
                obj.put(key, (Integer)obj.get(key) + 1);
            }

            if (ob instanceof JSONObject) {
                incrementValue((JSONObject) ob, keysToIncrementValue);
            }
            else if (ob instanceof JSONArray) {
                JSONArray arr = (JSONArray) ob;
                for (int i=0; i < arr.length(); i++) {
                    Object arrObj = arr.get(0);
                    if (arrObj instanceof JSONObject) {
                        incrementValue((JSONObject) arrObj, keysToIncrementValue);
                    }
                }
            }
        }
    }

uso:

JSONObject object = ....
incrementValue(object, Arrays.asList("id", "product_id", "category_id", "customer_id"));

esto también se puede transformar para trabajar para JSONArray como objeto padre

Michail Michailidis
fuente
1

La mayoría de las respuestas aquí son para estructuras JSON planas, en caso de que tenga un JSON que podría haber anidado JSONArrays o Nested JSONObjects, surge la verdadera complejidad. El siguiente fragmento de código se ocupa de dicho requisito comercial. Toma un mapa hash y un JSON jerárquico con ambos JSONArrays anidados y JSONObjects y actualiza el JSON con los datos en el mapa hash

public void updateData(JSONObject fullResponse, HashMap<String, String> mapToUpdate) {

    fullResponse.keySet().forEach(keyStr -> {
        Object keyvalue = fullResponse.get(keyStr);

        if (keyvalue instanceof JSONArray) {
            updateData(((JSONArray) keyvalue).getJSONObject(0), mapToUpdate);
        } else if (keyvalue instanceof JSONArray) {
            updateData((JSONObject) keyvalue, mapToUpdate);
        } else {
            // System.out.println("key: " + keyStr + " value: " + keyvalue);
            if (mapToUpdate.containsKey(keyStr)) {
                fullResponse.put(keyStr, mapToUpdate.get(keyStr));
            }
        }
    });

}

Debe notar aquí que el tipo de retorno de esto es nulo, pero los objetos de tamaño se pasan como referencia, este cambio se refelece a la persona que llama.

Shekhar
fuente
0

El siguiente código funcionó bien para mí. Por favor, ayúdame si se puede hacer el ajuste. Esto obtiene todas las claves incluso de los objetos JSON anidados.

public static void main(String args[]) {
    String s = ""; // Sample JSON to be parsed

    JSONParser parser = new JSONParser();
    JSONObject obj = null;
    try {
        obj = (JSONObject) parser.parse(s);
        @SuppressWarnings("unchecked")
        List<String> parameterKeys = new ArrayList<String>(obj.keySet());
        List<String>  result = null;
        List<String> keys = new ArrayList<>();
        for (String str : parameterKeys) {
            keys.add(str);
            result = this.addNestedKeys(obj, keys, str);
        }
        System.out.println(result.toString());
    } catch (ParseException e) {
        e.printStackTrace();
    }
}
public static List<String> addNestedKeys(JSONObject obj, List<String> keys, String key) {
    if (isNestedJsonAnArray(obj.get(key))) {
        JSONArray array = (JSONArray) obj.get(key);
        for (int i = 0; i < array.length(); i++) {
            try {
                JSONObject arrayObj = (JSONObject) array.get(i);
                List<String> list = new ArrayList<>(arrayObj.keySet());
                for (String s : list) {
                    putNestedKeysToList(keys, key, s);
                    addNestedKeys(arrayObj, keys, s);
                }
            } catch (JSONException e) {
                LOG.error("", e);
            }
        }
    } else if (isNestedJsonAnObject(obj.get(key))) {
        JSONObject arrayObj = (JSONObject) obj.get(key);
        List<String> nestedKeys = new ArrayList<>(arrayObj.keySet());
        for (String s : nestedKeys) {
            putNestedKeysToList(keys, key, s);
            addNestedKeys(arrayObj, keys, s);
        }
    }
    return keys;
}

private static void putNestedKeysToList(List<String> keys, String key, String s) {
    if (!keys.contains(key + Constants.JSON_KEY_SPLITTER + s)) {
        keys.add(key + Constants.JSON_KEY_SPLITTER + s);
    }
}



private static boolean isNestedJsonAnObject(Object object) {
    boolean bool = false;
    if (object instanceof JSONObject) {
        bool = true;
    }
    return bool;
}

private static boolean isNestedJsonAnArray(Object object) {
    boolean bool = false;
    if (object instanceof JSONArray) {
        bool = true;
    }
    return bool;
}
Ramji Sridaran
fuente
-1

Esta es otra solución de trabajo para el problema:

public void test (){

    Map<String, String> keyValueStore = new HasMap<>();
    Stack<String> keyPath = new Stack();
    JSONObject json = new JSONObject("thisYourJsonObject");
    keyValueStore = getAllXpathAndValueFromJsonObject(json, keyValueStore, keyPath);
    for(Map.Entry<String, String> map : keyValueStore.entrySet()) {
        System.out.println(map.getKey() + ":" + map.getValue());
    }   
}

public Map<String, String> getAllXpathAndValueFromJsonObject(JSONObject json, Map<String, String> keyValueStore, Stack<String> keyPath) {
    Set<String> jsonKeys = json.keySet();
    for (Object keyO : jsonKeys) {
        String key = (String) keyO;
        keyPath.push(key);
        Object object = json.get(key);

        if (object instanceof JSONObject) {
            getAllXpathAndValueFromJsonObject((JSONObject) object, keyValueStore, keyPath);
        }

        if (object instanceof JSONArray) {
            doJsonArray((JSONArray) object, keyPath, keyValueStore, json, key);
        }

        if (object instanceof String || object instanceof Boolean || object.equals(null)) {
            String keyStr = "";

            for (String keySub : keyPath) {
                keyStr += keySub + ".";
            }

            keyStr = keyStr.substring(0, keyStr.length() - 1);

            keyPath.pop();

            keyValueStore.put(keyStr, json.get(key).toString());
        }
    }

    if (keyPath.size() > 0) {
        keyPath.pop();
    }

    return keyValueStore;
}

public void doJsonArray(JSONArray object, Stack<String> keyPath, Map<String, String> keyValueStore, JSONObject json,
        String key) {
    JSONArray arr = (JSONArray) object;
    for (int i = 0; i < arr.length(); i++) {
        keyPath.push(Integer.toString(i));
        Object obj = arr.get(i);
        if (obj instanceof JSONObject) {
            getAllXpathAndValueFromJsonObject((JSONObject) obj, keyValueStore, keyPath);
        }

        if (obj instanceof JSONArray) {
            doJsonArray((JSONArray) obj, keyPath, keyValueStore, json, key);
        }

        if (obj instanceof String || obj instanceof Boolean || obj.equals(null)) {
            String keyStr = "";

            for (String keySub : keyPath) {
                keyStr += keySub + ".";
            }

            keyStr = keyStr.substring(0, keyStr.length() - 1);

            keyPath.pop();

            keyValueStore.put(keyStr , json.get(key).toString());
        }
    }
    if (keyPath.size() > 0) {
        keyPath.pop();
    }
}
Huy Thành Trương
fuente