0

Have in mind that the JSON structure is not known before hand i.e. it is completely arbitrary, we only know that it is JSON format.

For example, The following JSON

{
  "id": 1,
  "name": "Foo",
  "price": 123,
  "tags": [
    {
    "Bar":"23",
    "Eek":"24"
  }
]
}

We can do this to traverse the tree and keep track of how deep we want to figure out dot notation property names.

How can we get the data only keys at compile time and values at run time.

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.ValueNode;
import java.io.File;
import java.io.IOException;
import java.util.*;

public class Main {
    public static void main(String[] args) {
        File file=new File("src/data.json");
        ObjectMapper mapper=new ObjectMapper();
        try {

            LinkedHashMap<String,String> map= new LinkedHashMap<String, String>();
            JsonNode node =mapper.readTree(file);
            getKeys("",node, map);

            for (Map.Entry<String, String> entry : map.entrySet()) {
                System.out.println("Key:"+entry.getKey() + ""+"   "+" value:" + entry.getValue());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public static void getKeys(String currentpath,JsonNode node,LinkedHashMap map){
        if(node.isObject()){
            ObjectNode objectNode=(ObjectNode) node;
            Iterator<Map.Entry<String, JsonNode>> it=objectNode.fields();
            String prefix=currentpath.isEmpty()?"":currentpath+".";
            while (it.hasNext()){
                SortedMap.Entry<String,JsonNode> iter=it.next();
                getKeys(prefix+iter.getKey(),iter.getValue(),map);
            }
        }else if (node.isArray()){
            ArrayNode arrayNode=(ArrayNode) node;
            for(int i=0; i<arrayNode.size(); i++){
                getKeys(currentpath+i,arrayNode.get(i),map);
            }
        }
        else if(node.isValueNode()) {
            ValueNode valueNode=(ValueNode) node;
            map.put(currentpath,valueNode.asText());
        }
    }
}



At Run time Only display the values what user wants.

like

input:Address.street output:"23fn3 london"

saqib riaz
  • 53
  • 1
  • 9

1 Answers1

3

It is uncommon to process a json structure that you do not know anything about. If you do not know what values you are looking for, how is this data ever going to be useful?

In the special cases you do want to go over the whole tree, you will have to use recursion. Because every field (field) can have a simple value ("field": 1), an object ("field": {"b": 1}) or an array ("field": [1, 2, 3]).

The below code shows how you could do this using the Jackson json library

public static void main(String[] args) throws IOException {
    File file = new File("data.json");
    ObjectMapper mapper = new ObjectMapper();

    JsonNode node = mapper.readTree(file);

    processNode(node);
}

private static void processNode(JsonNode node) {
    if(node.isArray()) {
        // if the node is a list of items,
        //  go through all the items and process them individually
        System.out.println("=== Array start ===");
        for (final JsonNode objInArray : node) {
            System.out.println("--- Array element start ---");
            // process the item in the array
            processNode(objInArray);
            System.out.println("--- Array element end ---");
        }
        System.out.println("=== Array end ===");
    } else if(node.isContainerNode()) {
        // if the node is an object,
        //  go through all fields within the object
        System.out.println("/// Object start ///");
        Iterator<Map.Entry<String, JsonNode>> it = node.fields();
        while (it.hasNext()) {
            Map.Entry<String, JsonNode> field = it.next();
            System.out.println("key: " + field.getKey());
            //process every field in the array
            processNode(field.getValue());
        }
        System.out.println("/// Object end ///");
    } else {
        // if node is a simple value (like string or int) so let's print it
        System.out.println("value: " + node);
    }
}

The example json you provided gives the following output:

=== Array start ===
--- Array element start ---
/// Object start ///
key: id
value: 1
key: name
value: "Leanne Graham"
key: username
value: "Bret"
key: email
value: "Sincere@april.biz"
key: address
/// Object start ///
key: street
value: " Light"
key: suite
value: "Apt. 556"
key: city
value: "Gwugh"
key: zipcode
value: "93874"
key: geo
/// Object start ///
key: lat
value: "-37.319"
key: lng
value: "81.146"
/// Object end ///
/// Object end ///
key: phone
value: "8031 x56442"
key: website
value: "hilded.org"
key: company
/// Object start ///
key: name
value: "Romra-Crona"
key: catchPhrase
value: " client-server neural-net"
key: bs
value: "harness markets"
/// Object end ///
/// Object end ///
--- Array element end ---
=== Array end ===

Process finished with exit code 0

Sijmen
  • 477
  • 6
  • 12
  • we not know the keys not all then how can we use ("company"). we have to find keys and values that can be dynamic every time and then make use of them – saqib riaz Apr 16 '20 at 12:09
  • 1
    @saqibriaz Sorry I missed that. Now added a bit on how to deal with unknown fields. – Sijmen Apr 17 '20 at 11:36