java - para - manipular json con gson
Aplanar una cadena JSON para hacer que la clave, incluido el valor de cada clave de nivel, se asigne a Map<String, String> con Gson o Jackson (2)
Puede obtener el JSON como JsonNode
y recorrer todos los campos recursivamente y agregar clave y campo de valor a un Mapa. Cuando un valor es un objeto en lugar de una cadena, puede agregar el nombre del campo a la Lista para unirlo con los períodos cuando finalmente se encuentra una cadena. Primero crea (para la legibilidad) un método separado que agrega campos Json a un Map
:
void mapAppender(Map<String, String> result, Entry<String, JsonNode> node, List<String> names) {
names.add(node.getKey());
if (node.getValue().isTextual()) {
String name = names.stream().collect(joining("."));
result.put(name, node.getValue().asText());
} else {
node.getValue().fields()
.forEachRemaining(nested -> mapAppender(result, nested, new ArrayList<>(names)));
}
}
y úsalo así:
ObjectMapper mapper = new ObjectMapper();
Map<String, String> result = new HashMap<>();
mapper.readTree(json).fields()
.forEachRemaining(node -> mapAppender(result, node, new ArrayList<String>()));
Donde fields()
devuelve un Iterator
. Tenga cuidado con StackOverflowErrors
y quizás bajo rendimiento para JSON profundamente anidado.
Tengo una pregunta mejorada sobre cómo aplanar una cadena JSON para mapear usando Gson o Jackson .
Mi escenario incluía claves duplicadas, por lo que la solución en la pregunta anterior hará que se sobrescriban algunas claves duplicadas. Así que estoy pensando en construir claves combinando las claves de cada nivel.
Entonces, ¿cómo lograr eso?
Por ejemplo:
{
"id" : "123",
"name" : "Tom",
"class" : {
"subject" : "Math",
"teacher" : "Jack"
}
}
Quiero obtener el mapa:
"id" : "123",
"name" : "Tom",
"class.subject" : "Math",
"class.teacher" : "Jack"
************************ Solución de actualización ************************ *************
Basado en la respuesta de @Manos Nikolaidis, puedo lograr la siguiente solución al considerar ArrayNode.
public void processJsonString(String jsonString) throws Exception {
ObjectMapper mapper = new ObjectMapper();
ArrayNode arrayNode = (ArrayNode) mapper.readTree(jsonString);
processArrayNode(arrayNode);
}
private void processObjectNode(JsonNode jsonNode) {
Map<String, String> result = new HashMap<>();
Iterator<Map.Entry<String, JsonNode>> iterator = jsonNode.fields();
iterator.forEachRemaining(node -> mapAppender(result, node, new ArrayList<String>()));
}
private void processArrayNode(ArrayNode arrayNode) {
for (JsonNode jsonNode : arrayNode) {
processObjectNode(jsonNode);
}
}
private void mapAppender(Map<String, String> result, Map.Entry<String, JsonNode> node, List<String> names) {
names.add(node.getKey());
if (node.getValue().isTextual()) {
String name = names.stream().collect(Collectors.joining("."));
result.put(name, node.getValue().asText());
} else if (node.getValue().isArray()) {
processArrayNode((ArrayNode) node.getValue());
} else if (node.getValue().isNull()) {
String name = names.stream().collect(Collectors.joining("."));
result.put(name, null);
} else {
node.getValue().fields()
.forEachRemaining(nested -> mapAppender(result, nested, new ArrayList<>(names)));
}
}
Resolví esto usando código simple abajo, solo creo que es necesario descargar Jettison y flattener.JsonFlattener library
import java.util.Map;
import org.codehaus.jettison.json.JSONObject;
import com.github.wnameless.json.flattener.JsonFlattener;
public class test {
public static void main(String[] args) {
String jsonString = "{/"id/" : /"123/",/"name/" : /"Tom/",/"class/" : {/"subject/" : /"Math/",/"teacher/" : /"Jack/"}}";
JSONObject jsonObject = new JSONObject();
String flattenedJson = JsonFlattener.flatten(jsonString);
Map<String, Object> flattenedJsonMap = JsonFlattener.flattenAsMap(jsonString);
System.out.println(flattenedJsonMap);
}
}
Enlace de referencia: https://github.com/wnameless/json-flattener