I have problems accessing data in a JSON string. What am I doing wrong?
Working:
JSONObject obj = new JSONObject("JSON-STRING");
JSONArray arr = obj.getJSONArray("weather");
System.out.println(arr.getJSONObject(0).get("description"); >> clear sky
Not working:
JSONObject obj = new JSONObject("JSON-STRING");
JSONArray arr = obj.getJSONArray("main");
System.out.println(arr.getJSONObject(0).get("temp"); >> 285.15
Exception:
org.json.JSONException: JSONObject["main"] is not a JSONArray.
at org.json.JSONObject.getJSONArray(JSONObject.java:622)
at main.SmartHomeBot.onUpdateReceived(SmartHomeBot.java:47)
at org.telegram.telegrambots.updatesreceivers.DefaultBotSession$HandlerThread.run(DefaultBotSession.java:274)
The JSON-String:
{
"coord": {
"lon": 6.55,
"lat": 51.27
},
"weather": [{
"id": 800,
"main": "Clear",
"description": "clear sky",
"icon": "01d"
}
],
"base": "stations",
"main": {
"temp": 285.15,
"pressure": 1034,
"humidity": 30,
"temp_min": 285.15,
"temp_max": 285.15
},
"visibility": 10000,
"wind": {
"speed": 2.6
},
"clouds": {
"all": 0
},
"dt": 1492705200,
"sys": {
"type": 1,
"id": 4909,
"message": 0.2825,
"country": "DE",
"sunrise": 1492662386,
"sunset": 1492713582
},
"id": 2808559,
"name": "Willich",
"cod": 200
}
You get the error because weather is the array of the multiple weather and main is the single object.
Difference between both is shown below:
"weather": [{
"id": 800,
"main": "Clear",
"description": "clear sky",
"icon": "01d"
}
],
and
"main": {
"temp": 285.15,
"pressure": 1034,
"humidity": 30,
"temp_min": 285.15,
"temp_max": 285.15
},
So in the JSON "weather" : [{....}, {....}, {....}] [] show that weather is the array.
In your parent json value for key "weather" represents a JSONArray but value for key "main" represents a JSONObject not JSONArray.
To fetch the data from JsonObject you should do like below
JSONObject mainObj = obj.getJSONObject("main");
System.out.println(mainObj.get("temp"));
String jsonobj = "{\n \"coord\": {\n \"lon\": 6.55,\n \"lat\": 51.27\n },\n \"weather\": [{\n \"id\": 800,\n \"main\": \"Clear\",\n \"description\": \"clear sky\",\n \"icon\": \"01d\"\n }\n ],\n \"base\": \"stations\",\n \"main\": {\n \"temp\": 285.15,\n \"pressure\": 1034,\n \"humidity\": 30,\n \"temp_min\": 285.15,\n \"temp_max\": 285.15\n },\n \"visibility\": 10000,\n \"wind\": {\n \"speed\": 2.6\n },\n \"clouds\": {\n \"all\": 0\n },\n \"dt\": 1492705200,\n \"sys\": {\n \"type\": 1,\n \"id\": 4909,\n \"message\": 0.2825,\n \"country\": \"DE\",\n \"sunrise\": 1492662386,\n \"sunset\": 1492713582\n },\n \"id\": 2808559,\n \"name\": \"Willich\",\n \"cod\": 200\n}";
JSONObject obj = new JSONObject(jsonobj);
JSONObject jsonObject = obj.getJSONObject("main");
System.out.println(jsonObject.get("temp"));
Related
I am a newbie to Rest-Assured api using Java. I want to extract the number of days the temperature of a city is above 18 . Using openweathermap.org.
The url is api.openweathermap.org/data/2.5/forecast?q=Sydney&units=metric&appid={APP KEY}
I get :
{
"cod": "200",
"message": 0.0067,
"cnt": 40,
"list": [
{
"dt": 1557727200,
"main": {
"temp": 20.88,
"temp_min": 20.88,
"temp_max": 21.05,
"pressure": 1025.56,
"sea_level": 1025.56,
"grnd_level": 1021.14,
"humidity": 57,
"temp_kf": -0.17
},
"weather": [
{
"id": 803,
"main": "Clouds",
"description": "broken clouds",
"icon": "04d"
}
],
"clouds": {
"all": 55
},
"wind": {
"speed": 3.45,
"deg": 43.754
},
"sys": {
"pod": "d"
},
"dt_txt": "2019-05-13 06:00:00"
},
{
"dt": 1557738000,
"main": {
"temp": 18.45,
"temp_min": 18.45,
"temp_max": 18.58,
"pressure": 1026.06,
"sea_level": 1026.06,
"grnd_level": 1021.28,
"humidity": 73,
"temp_kf": -0.13
},
"weather": [
{
"id": 804,
"main": "Clouds",
"description": "overcast clouds",
"icon": "04n"
}
],
"clouds": {
"all": 100
},
"wind": {
"speed": 3.84,
"deg": 28.267
},
"sys": {
"pod": "n"
},
"dt_txt": "2019-05-13 09:00:00"
}, {
"dt": 1557759600,
"main": {
"temp": 14.31,
"temp_min": 14.31,
"temp_max": 14.35,
"pressure": 1026.29,
"sea_level": 1026.29,
"grnd_level": 1021.87,
"humidity": 80,
"temp_kf": -0.04
},
"weather": [
{
"id": 802,
"main": "Clouds",
"description": "scattered clouds",
"icon": "03n"
}
],
"clouds": {
"all": 28
},
"wind": {
"speed": 1.66,
"deg": 279.19
},
"sys": {
"pod": "n"
},
"dt_txt": "2019-05-13 15:00:00"
},
}
I am unsure how do i proceed with the iterations. It would be a great help if someone can help me through.
I am able to get the data but not sure how do I get the element from each array
Now, I want to extract the temperatures which are above 18 degrees
I have attempted the below:
public class WeatherForecast {
public static Response resp;
#Test
public void getWeatherForecastForCity()
{
RestAssured.baseURI = "https://api.openweathermap.org";
resp = given().
param("q", "Sydney").
param("units", "metric").
param("appid", "670473f82ba0969a884be548c75236a4").
when().
get("/data/2.5/forecast").
then().
extract().response();
List<String> temperatures = resp.getBody().jsonPath().getList("list");
//String value = temperatures.getString()
int count = temperatures.size();
for(int i=0;i<=count;i++)
{
}
System.out.println("List Size: "+temperatures.size());
//assertEquals(temperatures, greaterThanOrEqualTo(20.00F));
//String responseString = resp.asString();
//System.out.println("Response String: "+responseString);
//JsonPath js = new JsonPath(responseString);
//Get the number of records for the city
//int size = js.getList("list").size();
//int temperature = Integer.parseInt(js.get("count"));
//System.out.println("Temperature Value: "+js.getString("list[1].main.temp"));
}
}
RestAssureduses a powerful library called JsonPath which you already used.
The difference of what you already creates is how to get JSONObject/Array inside other JSONObject/Array
You used resp.getBody().jsonPath().getList("list"); which is almost a good starting point. Instead of using List<String> you should use List<HashMap<String, Object>>
Each HashMap<> will be a JSON Object.
Then you can just iterate over the Array to get each object and temperatures.
How to do that:
List<HashMap<String, Object>> list = resp.getBody().jsonPath().getList("list");
for (HashMap<String, Object> jsonObject : list) {
/**
* Now, in order to get temperature, we have to get access to `main` element in JSON and then get access to the temperature
**/
HashMap<String, Object> mainElements = (HashMap<String, Object>) jsonObject.get("main");
//No we have JSONObject as HashMap. We can access any temperature
float temperature = (float) mainElements.get("temp");
System.out.println(temperature);
}
The above code will print all temperatures. Now you just have to compare float values, save them, assert them or do whatever you want :)
You can access any value with this approach
EDIT:
Extract the above code to a method like this:
private List<HashMap<String, Object>> getJsonObjectsWithTempGreaterThan(JsonPath path, float degrees) {
List<HashMap<String, Object>> desiredJsonObjects = new ArrayList<>();
List<HashMap<String, Object>> list = path.getList("list");
for (HashMap<String, Object> jsonObject : list) {
HashMap<String, Object> mainElements = (HashMap<String, Object>) jsonObject.get("main");
float temperature = (float) mainElements.get("temp");
if (temperature > degrees) {
desiredJsonObjects.add(jsonObject);
}
}
return desiredJsonObjects;
}
Above code will store each of JSON Object in a List and then return it. The list will contain JSON Objects with a temperature greater than degrees passed in the parameter.
Then, you can access those elements like this:
List<HashMap<String, Object>> objects = getJsonObjectsWithTempGreaterThan(path, 20);
This is our list of desired objects.
If you just want the temperatures, all you have to do is:
for (HashMap<String, Object> jsonObject : objects) {
HashMap<String, Object> mainElements = (HashMap<String, Object>) jsonObject.get("main");
//No we have JSONObject as HashMap. We can access any temperature
float temperature = (float) mainElements.get("temp");
System.out.println(temperature);
}
This can be achieved much more easily and readable with Java Streams.
Currently I'm using rest-assured to hit an endpoint and in turn store any JSON data matches via an ArrayList and HashMap.
I can see that I'm receiving a response back, but how do I loop over an ArrayList when it contains an internal HashMap?
As you can see from the JSON data below, I'm expecting to output all values / matches stored within the ArrayList.
My Code:
public void apiTest() {
String position = "Attacker";
String role = "PLAYER";
Response response = given()
.spec(footballCompetitions_requestSpecification)
.when().get(EndPoint.TEAMS + EndPoint.SQUAD);
ArrayList<Map<String, ?>> allPlayers = response.path
("squad.findAll { it.role == '%s' }.findAll { it.position == '%s' }", position, role);
Example JSON Data:
{
"id": 66,
"area": {
"id": 2072,
"name": "England"
},
"activeCompetitions": [
{
"id": 2021,
"area": {
"id": 2072,
"name": "England"
},
"name": "Premier League",
"code": "PL",
"plan": "TIER_ONE",
"lastUpdated": "2019-01-03T23:39:45Z"
},
{
"id": 2001,
"area": {
"id": 2077,
"name": "Europe"
},
"name": "UEFA Champions League",
"code": "CL",
"plan": "TIER_ONE",
"lastUpdated": "2018-12-13T18:55:02Z"
}
],
"name": "Manchester United FC",
"shortName": "Man United",
"tla": "MNU",
"crestUrl": "http://upload.wikimedia.org/wikipedia/de/d/da/Manchester_United_FC.svg",
"address": "Sir Matt Busby Way Manchester M16 0RA",
"phone": "+44 (0161) 8688000",
"website": "http://www.manutd.com",
"email": "enquiries#manutd.co.uk",
"founded": 1878,
"clubColors": "Red / White",
"venue": "Old Trafford",
"squad": [
{
"id": 3188,
"name": "David De Gea",
"position": "Goalkeeper",
"dateOfBirth": "1990-11-07T00:00:00Z",
"countryOfBirth": "Spain",
"nationality": "Spain",
"shirtNumber": 1,
"role": "PLAYER"
},
{
"id": 3331,
"name": "Marcus Rashford",
"position": "Attacker",
"dateOfBirth": "1997-10-31T00:00:00Z",
"countryOfBirth": "England",
"nationality": "England",
"shirtNumber": 10,
"role": "PLAYER"
},
{
"id": 3372,
"name": "Anthony Martial",
"position": "Attacker",
"dateOfBirth": "1995-12-05T00:00:00Z",
"countryOfBirth": "France",
"nationality": "France",
"shirtNumber": 11,
"role": "PLAYER"
},
{
"id": 3662,
"name": "Romelu Lukaku",
"position": "Attacker",
"dateOfBirth": "1993-05-13T00:00:00Z",
"countryOfBirth": "Belgium",
"nationality": "Belgium",
"shirtNumber": 9,
"role": "PLAYER"
},
If you are using Java 8 or higher, then just iterate over the List first and over the Map in a nested iteration using lambda expressions:
public static void main(String[] args) {
List<Map<String, ?>> jsonList = new ArrayList<>();
Map<String, String> mapOne = new HashMap<String, String>();
mapOne.put("id", String.valueOf(66));
mapOne.put("area", "Some Area");
jsonList.add(mapOne);
jsonList.forEach(map -> {
map.forEach((key, value) -> {
System.out.println(key + ": " + value);
});
});
}
The thing you have to take care of is the String representation of value, since it is a Map<String, ?> in your code and a Map<String, String> in my example, what may lead to problems if you directly use the above example's System.out.println(key + ": " + value);.
First iterate over the list, then iterate over the Map:
for (Map<String, ?> map : allPlayers) {
for (String key : map.keySet()) {
Object player = map.get(key);
// ...
}
}
This is my JSON,
{
"city": {
"id": 2961297,
"name": "Swords",
"coord": {
"lon": -6.21806,
"lat": 53.459721
},
"country": "IE",
"population": 0
},
"cod": "200",
"message": 0.3535,
"cnt": 1,
"list": [
{
"dt": 1481025600,
"temp": {
"day": 284.68,
"min": 284.68,
"max": 285.36,
"night": 285.36,
"eve": 284.8,
"morn": 284.68
},
"pressure": 1028.26,
"humidity": 95,
"weather": [
{
"id": 500,
"main": "Rain",
"description": "light rain",
"icon": "10d"
}
],
"speed": 9.01,
"deg": 186,
"clouds": 92,
"rain": 0.5
}
]
}
I am trying to access the rain value "rain": 0.5 as seen in the returned JSON data above I am unsure how exactly to do this as I don't have much experience working with JSON data.
This is my code,
JSONObject topLevel = new JSONObject(builder.toString());
JSONArray ListArray = topLevel.getJSONArray("list");
weather = String.valueOf(ListArray);
for(int x = 0;x < ListArray.length();x++) {
JSONObject myObj = ListArray.getJSONObject(x);
myObj.getInt("rain");
Log.d("TODAYS Rain"+rain,"");
//System.out.Print("Current Weather" +id+main+icon+dscription+rain);
}
Any help is greatly appreciated.
JSONObject topLevel = new JSONObject(builder.toString());
JSONArray listArray = topLevel.getJSONArray("list");
JSONObject firstObject = (JSONObject)listArray.get(0);
Double rain = firstObject.getDouble("rain");
System.out.println("TODAYs rain :" + rain);
}
The easiest way is to parse a Json is to use POJO classes that map the Json into an object instance.
You define the class structure and it gets filled with the data retrieved.
There is a guide on that same topic on this website: http://www.ssaurel.com/blog/learn-how-to-parse-json-in-android-with-gson/
JSONObject topLevel = new JSONObject(builder.toString());
JSONArray ListArray = topLevel.getJSONArray("list");
weather = String.valueOf(ListArray);
for(int x = 0;x < ListArray.length();x++) {
JSONObject myObj = ListArray.getJSONObject(x);
myObj.getDouble("rain");
Log.d("TODAYS Rain"+rain,"");
//System.out.Print("Current Weather" +id+main+icon+dscription+rain);
}
You just need to use myobj.getDouble("rain") instead of myobj.getInt("rain") as the value of rain is not integer.
in my app i recevie char sequence thats from sql something like this:
"{"1":{"from":"540","to":"1020"},"2":{"from":"540","to":"1020"},"3":{"from":"540","to":"1020"},"4":{"from":"540","to":"1020"},"5":{"from":"540","to":"1020"},"6":{"from":"540","to":"1020"},"7":{"from":"540","to":"1020"}}"
This is full week, day by day and minutes since midnight. I have idea how to use it but i don't know right now how to crop it on sense strings which should be looks like:
String monday_open = 540;
String monday_close = 1020;
and same to the end of the week
Maybe somebody know easy way to crop this sequence?
this
"{"1":{"from":"540","to":"1020"},"2":{"from":"540","to":"1020"},"3":{"from":"540","to":"1020"},"4":{"from":"540","to":"1020"},"5":{"from":"540","to":"1020"},"6":{"from":"540","to":"1020"},"7":{"from":"540","to":"1020"}}"
is a json Text
my json String
{
"coord": {
"lon": 51.42,
"lat": 35.69
},
"weather": [
{
"id": 721,
"main": "Haze",
"description": "haze",
"icon": "50n"
}
],
"base": "cmc stations",
"main": {
"temp": 298.45,
"pressure": 1016,
"humidity": 39,
"temp_min": 298.15,
"temp_max": 299.15
},
"wind": {
"speed": 2.1,
"deg": 240
},
"clouds": {
"all": 40
},
"dt": 1439151053,
"sys": {
"type": 1,
"id": 7032,
"message": 0.0034,
"country": "IR",
"sunrise": 1439084924,
"sunset": 1439134215
},
"id": 112931,
"name": "Tehran",
"cod": 200
}
and i parse it with method blew:
private void jsonRead(String file) throws JSONException {
JSONObject root=new JSONObject(file);
JSONArray jsonArray = root.optJSONArray("weather");
JSONObject jo2=root.optJSONObject("main");
for(int i=0; i < jsonArray.length(); i++) {
JSONObject jsonObject = jsonArray.getJSONObject(i);
dama.setText(jsonObject.getString("description"));
}
rotobat.setText(jo2.getString("humidity"));
}
I have this json string:
I want to extract all the ids that are after the node of number:"0","1","2"...etc.
I have succeeded to get a single id by using jsonpath: $.response.data.0.id and got "15124".
but i'm looking for a jsonpath that will extract all the ids in the Json String.
in other words this is the expexted output: 15124,13498,14296,13364,14060,13672.
This is the Json String i have:
{
"response": {
"code": 200,
"msg": "Success",
"data": {
"0": {
"id": "15124",
"name": " yoav (yoavshaki#yahoo.com) - 301519506662355",
"network_id": 1,
"network_type": "Facebook",
"currency": "USD",
"currency_info": {
"prefix": "$",
"postfix": "",
"name": "US Dollars"
},
"timezone": {
"id": 139,
"code": "IST",
"region": "Asia",
"locality": "Jerusalem",
"offset": 3,
"facebook_code": 70
}
},
"1": {
"id": "13498",
"name": "(Not in used) Daniel - 30138444",
"network_id": 1,
"network_type": "Facebook",
"currency": "USD",
"currency_info": {
"prefix": "$",
"postfix": "",
"name": "US Dollars"
},
"timezone": {
"id": 92,
"code": "PST",
"region": "America",
"locality": "Los_Angeles",
"offset": -7,
"facebook_code": 1
}
},
"2": {
"id": "14296",
"name": "Daniel - ComeOn (bingocafe#walla.com - 1375713835981039)",
"network_id": 1,
"network_type": "Facebook",
"currency": "USD",
"currency_info": {
"prefix": "$",
"postfix": "",
"name": "US Dollars"
},
"timezone": {
"id": 92,
"code": "PST",
"region": "America",
"locality": "Los_Angeles",
"offset": -7,
"facebook_code": 1
}
},
"3": {
"id": "13364",
"name": "Erez - 116060088528093",
"network_id": 1,
"network_type": "Facebook",
"currency": "USD",
"currency_info": {
"prefix": "$",
"postfix": "",
"name": "US Dollars"
},
"timezone": {
"id": 92,
"code": "PST",
"region": "America",
"locality": "Los_Angeles",
"offset": -7,
"facebook_code": 1
}
},
"4": {
"id": "14060",
"name": "Erez - NordicBet (gianniciano82#gmail.com - 105134566315107)",
"network_id": 1,
"network_type": "Facebook",
"currency": "USD",
"currency_info": {
"prefix": "$",
"postfix": "",
"name": "US Dollars"
},
"timezone": {
"id": 139,
"code": "IST",
"region": "Asia",
"locality": "Jerusalem",
"offset": 3,
"facebook_code": 70
}
},
"5": {
"id": "13672",
"name": "Erez - alon.dan - 1378526859026272",
"network_id": 1,
"network_type": "Facebook",
"currency": "USD",
"currency_info": {
"prefix": "$",
"postfix": "",
"name": "US Dollars"
},
"timezone": {
"id": 92,
"code": "PST",
"region": "America",
"locality": "Los_Angeles",
"offset": -7,
"facebook_code": 1
}
}
}
}
}
Thanks for all the helpers!
GSON library is a good option to convert java object to json string and vise versa.
for converting json to java object use: fromJson(String, Class)
for converting java object to json string use: toJson(Object)
Here is the sample code using [Gson#fromJson()] to convert JSON string into java Map.
Find more examples...
Sample code:
BufferedReader reader = new BufferedReader(new FileReader(new File("resources/json.txt")));
Gson gson = new Gson();
Type type = new TypeToken<Map<String, Map<String, Object>>>() {}.getType();
Map<String, Map<String, Object>> map = gson.fromJson(reader, type);
Map<String, Map<String, Object>> innerMap = (Map<String, Map<String, Object>>) map.get("response").get("data");
for (String key : innerMap.keySet()) {
System.out.println("key:" + key + " id:" + innerMap.get(key).get("id"));
}
output:
key:0 id:15124
key:1 id:13498
key:2 id:14296
key:3 id:13364
key:4 id:14060
key:5 id:13672
Thanks Syam S. for your answer.
$.response.data.*.id indeed work!