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); 
}      
3
  • java's built in JSON libraries are the quickets way to do so, but in my experience GSON is the best library for parsing a JSON into a POJO painlessly. Commented Apr 13, 2018 at 6:40
  • Don't do node.key == "MULT": stackoverflow.com/questions/513832/… Commented Apr 13, 2018 at 8:11
  • 1
    @BartKiers The OP said it was pseudo-code... Commented Apr 13, 2018 at 14:42

2 Answers 2

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;
             ...
        }
    }
    
Sign up to request clarification or add additional context in comments.

8 Comments

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 No, you are wrong: You are expecting that node is an OBJECT which returns node.getJsonArray("ADD")!=null.
you sayd "check the value's type (through node.getValueType()". What for should I test, to find out if it is a single value?
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?
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.
|
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;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.