8

I'm trying to implement a function that given any JSONObject and a path String, would return the object's attribute corresponding to the path.

For example, given this json:

{
"name": "John", 
"friends": [
  {"name": "Paul",
   "age":42},
  {"name": "Peter",
   "age":24}
 ],
"address": {"city": "London"}
}
  • getAttribute(jsonObject, "name") should return "John"
  • getAttribute(jsonObject, "address.city") should return "London"
  • getAttribute(jsonObject, "friends[0].name") should return "Paul"

Note that this JSON is only an example, jsonObject has no predefined structure and could represent any valid json.

I wrote a first version implementing the first two cases, but handling arrays and multi-level arrays "foo[0][0].bar" brings a lot of complexity to this function.

Is there a recommended tool/library/method for getting an attribute from a JSONObject given a "complex" path?

PLNech
  • 3,087
  • 1
  • 23
  • 52
  • nope.... there are many many libs.. Gson, Jackson etc – ΦXocę 웃 Пepeúpa ツ Nov 24 '16 at 10:09
  • 1
    pls use GSON instead of getting values from path, here you will values directly from the entity class objects – Amrut Bidri Nov 24 '16 at 10:10
  • 1
    @ΦXocę웃Пepeúpaツ : I know those libraries exist, but I can't find how to get an attribute from an arbitrary `JSONObject` using those. If you know how to do so, feel free to answer the question! – PLNech Nov 24 '16 at 10:22
  • 1
    @AmrutBidri: I cannot create class objects as the JSON will vary dynamically. It seems `GSON` does not provide a solution for getting an attribute given such a json path, but please let me know if I'm wrong! – PLNech Nov 24 '16 at 10:24
  • i agree with @Krishnanunni P V answer it is easy to use with POJO generator http://www.jsonschema2pojo.org/ – Rajesh Nov 24 '16 at 10:25
  • 1
    @RajeshKushvaha: Please explain me how I could use POJOs when the JSON structure varies with every call. – PLNech Nov 24 '16 at 10:25
  • @PLNech if JSON structure is varies then it is not valid, i.e, some one call you using your name for indicating you. same you can not get result wiout prefix json structure, or find dynamic json structure helper. – Rajesh Nov 24 '16 at 10:31
  • @PLNech if you are looking for parsing dynamic JSON, take a look at [this answer](http://stackoverflow.com/a/22855546/5392118) – Burak Cakir Nov 24 '16 at 10:35
  • @RajeshKushvaha: The objects will **always be valid json**, but *won't have the same keys and nested attributes*. You tell me to `find a dynamic json structure helper`, but this is exactly what I'm asking for in this question. If you know a helper like this, don't hesitate to answer! – PLNech Nov 24 '16 at 10:36
  • check this and http://stackoverflow.com/questions/15029187/create-an-array-of-all-the-keys-in-a-jsonobject-android, you have to implement with as your requirement like this JSONObject json = new JSONObject("json object string"); JSONArray namearray=json.names(); //<<< get all keys in JSONArray – Rajesh Nov 24 '16 at 10:52
  • @RajeshKushvaha: Thank you, but this only gets the keys of the first level object, it won't list attributes of nested objects. it would work for getting `name`, but not `address.city` and especially not `friends[0].name`. – PLNech Nov 24 '16 at 10:59
  • by key you can get his value man like if(list.get(i))instance of JSONObject){ JSONObject obj=list.get(i).getJSON}else if (list.get(i))instance of JSONArray){etc..} – Rajesh Nov 24 '16 at 11:01

6 Answers6

5

the JSONPath standard by Stefan Goessner covers a more complex syntax, but it also handles the "classic javascript" JSON path syntax.

Using JayWay's implementation for Java, it is trivial to answer the question:

public String getAttribute(JSONObject json, String path) {
    return JsonPath.read(json.toString(), path);
}
PLNech
  • 3,087
  • 1
  • 23
  • 52
3

If I understand your question correctly, you could have potentially already been answered here

Alternatively, you can also try the following open source library:

https://github.com/jayway/JsonPath

Community
  • 1
  • 1
rares.urdea
  • 650
  • 3
  • 16
  • 26
  • 1
    Thanks! Although the question you linked is somewhat different, [the first answer](http://stackoverflow.com/a/29901800/3109189) hints at how I could use Jackson for solving this. Regarding JSONPath, I considered it but it seems it syntax covers a lot more than "classic" json path like in javascript, and I'm afraid of potential issues parsing these with it. – PLNech Nov 24 '16 at 10:50
  • 1
    No problem :). Hope it helps – rares.urdea Nov 24 '16 at 10:59
  • In the end JSONPath was the best way to go, thanks again! :) – PLNech Nov 25 '16 at 16:56
  • Glad it was useful ! – rares.urdea Nov 29 '16 at 14:32
1

How I solve the issee :

  import io.restassured.path.json.JsonPath;


String  id = JsonPath.given(Myobject).get(path).toString();

the benefit of using this library that even if your path have array , it can handle that

example : String path="Myobject[0].id"

Vladi
  • 1,662
  • 19
  • 30
1

The following native code might help you,

function getDeepValue (object, path, defaultValue) {
    let pathTokens = path.split('.')
    let v = object
    for(let p of pathTokens) {
        try {
            v = Object.prototype.hasOwnProperty.call(v,p)?v[p]:defaultValue
        } catch (catchedError) {
            v = defaultValue
            break
        }
    }
    return v
}


let o = {
    a: {
        b: {
            1:{
                x:9
            },
            c: [{x:1},{x:2}]
        }
    }
}

let path = 'a.b.c.1.x'
console.log(getDeepValue(o, path)) // prints 2
Point Networks
  • 1,071
  • 1
  • 13
  • 35
  • 1
    Thanks for the suggestion! However, this would not cover the cases with array reference syntax ("a.b[0].c"), but it could be a good starting point if someone wants to implement this from scratch. – PLNech Dec 03 '21 at 13:05
0

In 2022, with Kotlin, you can add the following extension

fun JSONObject.getFromPath(path: String, separator: String = ".") =
    path.split(separator).fold(this) { obj, name -> obj.getJSONObject(name)}
T D Nguyen
  • 7,054
  • 4
  • 51
  • 71
-1

You can use GSON library and parse your json string to a POJO class.

private final static Gson GSON = new GsonBuilder().create();

public static <T> T fromJSON(String json, Class<T> clazz) {
    try {
        return GSON.fromJson(json, clazz);
    } catch (JsonSyntaxException e) {
        LOGGER.warn("Could not deserialize object", e);
    }
    return null;
}

Design your model class according to your JSON structure.

Krishnanunni P V
  • 689
  • 5
  • 18
  • 32
  • 2
    Thanks, but as there is no predefined structure, I can't create a class matching it. The only assumption I can have is that the object will be valid JSON. – PLNech Nov 24 '16 at 10:20
  • 2
    Because as my comment explains, this does not answer the question: I cannot create a POJO class as the `JSONObject` will represent a different JSON structure everytime. – PLNech Nov 24 '16 at 10:37