I want to iterate through all nodes of a json object, and write out a plain key-value map, as follows:
{
"name": [
{
"first": "John",
"last": "Doe",
"items": [
{
"name": "firstitem",
"stock": 12
},
{
"name": "2nditem",
"stock:" 23
}
]
}],
"company": "John Company"
}
Should result in:
name-first-1=John
name-last-1=Doe
name-items-name-1-1=firstitem (meaning the list index is always appended at the end of the name)
name-items-name-1-2=2nditem
company=John Company
This is how to get the json string as a json object:
ObjectMapper mapper = new ObjectMapper(); //using jackson
JsonNode root = mapper.readTree(json);
//TODO how loop all nodes and subnodes, and always get their key + value?
But how can I now iterate through all nodes and extract their key and content?
This will work for you :
ObjectMapper mapper = new ObjectMapper();
JsonNode root = mapper.readTree(json);
Map<String, String> map = new HashMap<>();
addKeys("", root, map, new ArrayList<>());
map.entrySet()
.forEach(System.out::println);
private void addKeys(String currentPath, JsonNode jsonNode, Map<String, String> map, List<Integer> suffix) {
if (jsonNode.isObject()) {
ObjectNode objectNode = (ObjectNode) jsonNode;
Iterator<Map.Entry<String, JsonNode>> iter = objectNode.fields();
String pathPrefix = currentPath.isEmpty() ? "" : currentPath + "-";
while (iter.hasNext()) {
Map.Entry<String, JsonNode> entry = iter.next();
addKeys(pathPrefix + entry.getKey(), entry.getValue(), map, suffix);
}
} else if (jsonNode.isArray()) {
ArrayNode arrayNode = (ArrayNode) jsonNode;
for (int i = 0; i < arrayNode.size(); i++) {
suffix.add(i + 1);
addKeys(currentPath, arrayNode.get(i), map, suffix);
if (i + 1 <arrayNode.size()){
suffix.remove(arrayNode.size() - 1);
}
}
} else if (jsonNode.isValueNode()) {
if (currentPath.contains("-")) {
for (int i = 0; i < suffix.size(); i++) {
currentPath += "-" + suffix.get(i);
}
suffix = new ArrayList<>();
}
ValueNode valueNode = (ValueNode) jsonNode;
map.put(currentPath, valueNode.asText());
}
}
For the json
you gave the output will be :
name-items-name-1-2=2nditem
name-items-name-1-1=firstitem
name-items-stock-1-1=12
name-first-1=John
name-items-stock-1-2=23
company=John Company
name-last-1=Doe
elements() gives you an iterator for subnodes and fields() gives you the properties.
With that, you can code a recursive function that walks through all nodes.
Here is working sample, input is String
public static void main(String[] args) throws IOException {
JsonNode node = om.readTree(input);
LOG.info(node.toString());
process("", node);
}
private static void process(String prefix, JsonNode currentNode) {
if (currentNode.isArray()) {
ArrayNode arrayNode = (ArrayNode) currentNode;
Iterator<JsonNode> node = arrayNode.elements();
int index = 1;
while (node.hasNext()) {
process(!prefix.isEmpty() ? prefix + "-" + index : String.valueOf(index), node.next());
index += 1;
}
}
else if (currentNode.isObject()) {
currentNode.fields().forEachRemaining(entry -> process(!prefix.isEmpty() ? prefix + "-" + entry.getKey() : entry.getKey(), entry.getValue()));
}
else {
LOG.info(prefix + ": " + currentNode.toString());
}
}
You can convert JSON object to HashMap so you will get key and value pairs
here i use GSON library
code snippet
Gson gson = new Gson();
Type type = new TypeToken<Map<String, String>>(){}.getType();
Map<String,String> map = gson.fromJson(json, type);
so you can iterate this map for your purpose.