1

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); 
}      
Mike75
  • 504
  • 3
  • 18

2 Answers2

1

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;
             ...
        }
    }
    
Little Santi
  • 8,563
  • 2
  • 18
  • 46
  • String testJSON = "{\"ADD\":[{\"INT\":\"1\"},{\"INT\":\"3\"},{\"ADD\":[{\"INT\":\"5\"},{\"INT \":\"6\"}]},{\"INT\":\"4\"}]}"; getValueType for this is OBJECT. I would have expected ADD or ARRAY. – Mike75 Apr 13 '18 at 09:29
  • @Mike75 No, you are wrong: You are expecting that `node` is an OBJECT which returns `node.getJsonArray("ADD")!=null`. – Little Santi Apr 13 '18 at 10:06
  • you sayd "check the value's type (through node.getValueType()". What for should I test, to find out if it is a single value? – Mike75 Apr 13 '18 at 10:11
  • For clarification let me ask the other way around: I would like to get the first key ("ADD") from the String testJSON and decide what to do next on this key. How can I get the key from the JSONObject? – Mike75 Apr 13 '18 at 10:15
  • there is a method KeySet(), but it seems to be a map, I would need it ordered to really get the first key (or in general: an ordered list of the keys). So I think get("ADD") could be too ambigious in some more general cases. – Mike75 Apr 13 '18 at 10:18
  • You can get the "ADD" value executing `JSonObject nodeAdd=getJsonObject("ADD")`. Then check if it is null, otherwise check which type it is: `nodeAdd.getValueType()`, which shall return `NUMBER` or `ARRAY`. – Little Santi Apr 13 '18 at 10:27
  • O.k. If I don't want to retrieve ("ADD") directly, I tried this: `Set> s = node.keySet(); Iterator> i = s.iterator(); String key = i.next().toString();` But this seems a little uneasy to me. – Mike75 Apr 13 '18 at 10:39
  • I edited the question and pasted a running example of the code. – Mike75 Apr 13 '18 at 12:14
0

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;
}
Yamini
  • 732
  • 7
  • 11