Mike75
Mike75

Reputation: 524

parse JSON Tree in java

I could not find out how to traverse a JSON-tree (nested structure) and decide on the keys of the elements what to expect next and traverse from node to node. Like this (pseudocode):

int  traverse(node) {
  if (node.key == ADD) {
    int res = 0; 
    for (child:node.children)  
     res = res + traverse(child);
  }
  if (node.key == "ADD") {
  int res = 0; 
  for (child:node.children) 
    res = res + traverse(children);
  }
  if (node.key == "MULT") {
    int res = 0; 
    for (child:node.children) 
      res = res * traverse(children);
  }

  if (node.key == "INT")  
    return node.value;
}

The json-string to parse could be like this:

 {"ADD":[{"INT":"1"},{"INT":"3"},{"INT":"4"}]}

or this:

 {"ADD":[{"INT":"1"},{"INT":"3"},{"ADD":[{"INT":"5"},{"INT":"6"}]},      
 {"INT":"4"}]}

How could I use JSON-Object or JSON-Arrays and inside the objects access the key and value variables to traverse through this tree recursively?

EDITED: After all the comments I try to put this as first running example (still looks a little uneasy to me, but it works):

public static int evaluate(javax.json.JsonObject node) {

  Set<?> keySet = node.keySet(); 
  Iterator<?> i = keySet.iterator(); 
  if (i.hasNext()) { 
    String key = i.next().toString();
        System.out.println("key: " + key);      
    if (key.equals("ADD"))  {
      JsonArray ja = node.getJsonArray("ADD");
      int  res = 0;
      for (JsonValue jvx: ja) {
    if (jvx.getValueType().toString().equals("OBJECT"))  {
      res = res + evaluate((JsonObject)jvx);        
            }  else{
      System.err.println("jvx should not be a " + jvx.getValueType().toString() + " here");
        }
      }
      return res;
    }
    if (key.equals("MULT"))  {
      JsonArray ja = node.getJsonArray("MULT");
      int  res = 1;
      for (JsonValue jvx: ja) {
    if (jvx.getValueType().toString().equals("OBJECT"))  {
      res = res * evaluate((JsonObject)jvx);        
            }  else{
      System.err.println("jvx should not be a " + jvx.getValueType().toString() + " here");
        }
      }
      return res;
    }
    if (key.equals("INT")) {
      String intStr = node.getString("INT");
      System.out.println ("found int = " + intStr);
      return Integer.parseInt(intStr);

        }
      }
      return 0; 
}


public static  void readJSON() {
  String jsonText =  "{\"ADD\":[{\"INT\":\"1\"},{\"INT\":\"3\"},{\"ADD\":[{\"INT\":\"5\"},{\"INT\":\"6\"}]},{\"INT\":\"4\"}]}";
      JsonReader reader = Json.createReader(new StringReader(jsonText));
      JsonObject obj = reader.readObject();
      reader.close();
      int res = evaluate(obj);
  System.out.println("res: " + res); 
}      

Upvotes: 1

Views: 5608

Answers (2)

Yamini
Yamini

Reputation: 792

JSON [{ "name": "com", "children": [ { "name": "project", "children": [ { "name": "server" }, { "name": "client", "children": [ { "name": "util" } ] } ] } ] }]

Try this:

public static JSONArray getNames(JSONArray inputArray, JSONArray outputArray) {
    for (int i = 0; i < inputArray.length(); i++) {
        JSONObject inputObject = inputArray.getJSONObject(i);

        JSONObject outputObject = new JSONObject();
        outputObject.put("name", inputObject.getString("name"));
        outputArray.put(outputObject);

        if (inputObject.has("children")) {
            JSONArray children = inputObject.getJSONArray("children");
            getNames(children, outputArray);
        }
    }

    return outputArray;
}

Upvotes: 0

Little Santi
Little Santi

Reputation: 8803

Your evaluating pseudocode is OK (just pay attention to the initial value when multiplying!). To adapt it to the javax.json hierarchy, you should code your evaluating method like this:

int evaluate(javax.json.JsonObject node):

  • Get each on of the admitted keys (ADD, MULT, INT, etc) through node.getJsonObject(key): In case it returns null, check the next admitted key, and stop at the first you find.
  • On each operation, a proper logic must be coded:
    1. In case the key is a constant value (INT), return its value immediately.
    2. In case the key is an operation, check the value's type (through node.getValueType()): If it is a single value, return it as is. If it is an array, iterate through its elements and call evaluate for each one of them, and perform the proper operation with the returned value (adding, multiplying, etc). Last, return the computation's result.

After your first edit

Your first real approach looks OK; I'd just suggest you some improvements to make the code more readable:

  1. Use an enhanced for.
  2. Replace the if-else chanin by a switch.
  3. Replace each case by a call to a private method.

    int result;
    Set<String> keySet = node.keySet(); 
    for (String key : keySet)
    {
        switch (key)
        {
            case "ADD":
                result=evaluateAdd(node.getJsonArray("ADD"));
                break;
            case "MULT":
                result=evaluateMult(node.getJsonArray("ADD"));
                break;
            case "INT":
                result=node.getInt("INT");
                break;
             ...
        }
    }
    

Upvotes: 1

Related Questions