I've written some code to parse the Google Distance Matrix JSON response received by my Android program. The only piece of data I'm interested in is in the "distance" "value" node.
My code works, but it seems like there must be an easier way to do this. The distance value node is nested pretty deep inside the JSON, but is it really necessary to go through every layer of the JSON to get to the field you want?
Here's my JSON response:
{
"destination_addresses" : [
"5660 Baltimore National Pike, Ingleside Shopping Center, Catonsville, MD 21228, USA"
],
"origin_addresses" : [ "Hilltop Cir, Baltimore, MD 21250, USA" ],
"rows" : [
{
"elements" : [
{
"distance" : {
"text" : "3.1 mi",
"value" : 4922 <--THE FIELD I WANT TO EXTRACT
},
"duration" : {
"text" : "11 mins",
"value" : 666
},
"status" : "OK"
}
]
}
],
"status" : "OK"
}
And here is the code I used to pull out the distance value:
private double extractDistance(JSONObject json) {
JSONArray rowsArray = null;
double distanceInMiles = -1;
try {
// Getting Array of Distance Matrix Results
rowsArray = json.getJSONArray("rows");
JSONObject rowsObject = rowsArray.getJSONObject(0);//only one element in this array
JSONArray elementsArray = rowsObject.getJSONArray("elements");
JSONObject elementsObject = elementsArray.getJSONObject(0);//only one element in this array
JSONObject distanceObject = elementsObject.getJSONObject("distance");
distanceInMiles = (distanceObject.getDouble("value"))/1609.344; //distance in meters converted to miles
}
catch (JSONException e) {
e.printStackTrace();
}
return distanceInMiles;
}
Thanks!
I recommend you GSON (http://code.google.com/p/google-gson/) which parse the JSON text into a java class instance, and can convert the class instance to JSON text
Jackson is another good third party parser http://jackson.codehaus.org/. Looks like there's a comparison here, http://www.cowtowncoder.com/blog/archives/2009/09/entry_326.html.
Here's an example traversing using a tree, not sure if it qualifies as easier then what you are already doing, http://wiki.fasterxml.com/JacksonTreeModel
Unless you want to go into writing a custom regular expression to search the json string, yes that's going to be the best way of accessing it (and the easiest). Is there a reason you feel you need to access it 'more efficiently'?
If you are willing to include a third party library you might check out http://code.google.com/p/json-path/ .
I know what you feel right now, I had / have same issues with JSON parsing on android where we dont have #getValueforKey kind of features which is embedded on iOS, Even its so obivious google should realize it now, But there is good work done on Gson lib., look for Google Gson Here for easy way to parse json
Here is nice tute : Gson tute
Related
I have a json in which 1 key is coming as jsonArray if it has data otherwise it is coming as empty string. It is giving error while parsing in gson with retrofit.
"section": "Technology",
"subsection": "",
"title": "Depiction of Amazon Stirs a Debate About Work Culture",
"abstract": "Details of working conditions at Amazon led to a response from employees, relatives and friends.",
"url": "http://www.nytimes.com/2015/08/19/technology/amazon-workplace-reactions-comments.html",
"byline": "By THE NEW YORK TIMES",
"item_type": "Article",
"updated_date": "2015-08-18T07:35:33-5:00",
"created_date": "2015-08-18T07:35:35-5:00",
"published_date": "2015-08-19T04:00:00-5:00",
"material_type_facet": "News",
"kicker": "",
"des_facet": [
"Workplace Environment"
],
"org_facet": [
"Amazon.com Inc"
],
"per_facet": "",
"geo_facet": "",
des_facet , org_facet, per_facet, geo_facet are jsonArray but you can see that 2 are not having data so coming as empty string.
How to handle this scenario with retrofit +gson.
Json format can't be changed here at server.
is there any way I can achieve it in android?
Ok so there are two option you can solve this
Option 1:
JSON which I used as a example
"des_facet": [
"Workplace Environment"
],
"org_facet": [
"Amazon.com Inc"
],
"per_facet": ["Akshay"],
"geo_facet": ""
In your model class convert those variable to Object type
#Expose
#SerializedName("geo_facet")
private Object geo_facet;
#Expose
#SerializedName("per_facet")
private Object per_facet;
then where you want to set data do the following
if (model != null)
{
if (model.getGeo_facet() != null || model.getGeo_facet() != "")
{
Object arr = model.getGeo_facet();
}
if (model.getPer_facet() !=null || model.getPer_facet()!= "")
{
Object arr = model.getPer_facet();
if (arr!=null && arr.toString().length()>0)
{
arr = arr.toString();
Log.d("akshay","arr= "+arr);
//Do your Stuff or Set data
}
}
}
This is the output= 08-11 16:51:29.830 17951-17951/com.android.example
D/akshay: arr= [Akshay]
Option 2:
Follow this which is a little bit complex
Option 3:
Write own custom Parsing like this and Handle your response accordingly
a json can have a single structure. From the code it is clear that the key is given with 2 types of data
Ideally, it should not give "" when no items. It should give null
Please change the data
If no items,
"des_facet"=null // this is the change on server side. No need to change it on app side
If it has items
"des_facet"=[
"Workplace Environment"
]
instead of
If no items,
"des_facet"=""
If it has items
"des_facet"=[
"Workplace Environment"
]
You can use AutoValue with gson plugin and mark the field as nullable which will notify the Autovalue to make this field optional.
AZs an example this is how you do it:
#AutoValue
public abstract class NewsResponse{
public static TypeAdapter<NewsResponse> typeAdapter(Gson gson){
return new AutoValue_NewsResponse.GsonTypeAdapter(gson);
}
#SerializedName("api_status")
public abstract String apiStatus();
#SerializedName("api_text")
public abstract String success();
#Nullable
#SerializedName("errors")
public abstract ErrorDetails errorDetails();
#SerializedName("news")
public abstract List<NewsDetails> newsDetails();
}
you must import both of them see more info about importing at: AutoValue and AutoValue Gson Plugin
I'm developing app using QuickBlox services. I have String field with JSON in content. This is my JSON:
{"answers":[[{"name":"first"}],[{"name":"second"}],[{"name":"third"}],[{"name":"fourth"}],[{"name":"fifth"}],[{"name":"sixth"}]]}
Here is problem. When I want to get my field with JSON from QBCustomObject, it is serialized to this (without quotes and square braces):
[{
answers :
{
name : first
},
{
name : second
},
{
name : third
},
{
name : fourth
},
{
name : fifth
},
{
name : sixth
}
}]
What can I do in this situation?
I found in QBCustomObjectDeserializer class that code:
if(value.contains("[")) {
String[] values2 = value.replace("[", "").replace("]", "").replace("\"", "").split(",");
Can I change rules of deserialization in QuickBlox SDK? Can I use my own deserializer?
Anyone can help resolve my problem please?
Fixed in development branch
https://github.com/QuickBlox/quickblox-android-sdk/tree/development
will be rolled out in our next upcoming release
I want to get a list of friends' names from the Facebook API in Android. In that process, I want to learn how to read JSON objects/Arrays.
I have JSONObject and/or JSONArrays that have been passed to me. I don't know what's in them*. I know how to read the data once I know what fields exist, but I can't read anything as far as I can tell, without a key. Even with the key, How can I tell what's in it?
Basically, I'd like a piece of code that looks like:
JSONArray mArray = response.getJSONArray();
String theEntireDatabase = mArray.getStringOFEntireDatabase();
and have it respond with a String that looks like this:
{
"phoneNumber": [
{
"type": "work",
"num": "11111"
},
{
"type": "home",
"num": "2222"
}
],
"address": {
"state": "World",
"address": "infinite space, 000",
"city": "Android city"
},
"surname": "Swa",
"name": "Android"
}
Having known nothing of what is in the database beforehand?
*it could be "color:" it could be "nuclear threat level:" for all I know.
I tried this, but it only gives keys: Javascript get JSON key Name
JSONArray mArray = response.getJSONArray();
String theEntireDatabase = mArray.toString();
This should work well.
If you want the JSONArray pretty printed you can add this after the code I've just provided you.
Gson gson = new GsonBuilder().setPrettyPrinting().create();
JsonParser jp = new JsonParser();
JsonElement je = jp.parse(theEntireDatabase);
String prettyJsonString = gson.toJson(je);
JSONObject#keys will tell you what keys are defined for the object. JSONArray#length will tell you how many entries are in the array (and therefore the range of values you can use for index with the other methods: 0 through length() - 1). JSONObject#toString/JSONArray#toString will give you the string you've asked for.
Take a look at Jacksons built-in tree model feature.
http://wiki.fasterxml.com/JacksonTreeModel
And your code will be:
public void parse(String json) {
JsonFactory factory = new JsonFactory();
ObjectMapper mapper = new ObjectMapper(factory);
JsonNode rootNode = mapper.readTree(json);
Iterator<Map.Entry<String,JsonNode>> fieldsIterator = rootNode.fields();
while (fieldsIterator.hasNext()) {
Map.Entry<String,JsonNode> field = fieldsIterator.next();
System.out.println("Key: " + field.getKey() + "\tValue:" + field.getValue());
}
}
besides the technical answers (JSONObject#toString(n) seems the easiest - see http://developer.android.com/reference/org/json/JSONObject.html),
I would often use two more pragmatic solutions:
look for an API documentation... I know, it sounds crazy, but some companies do offer such a thing
hack together a short javascript script to try the API and inspect the result in the developer console/firebug/whatever is handy
I found a lot of tutorials here, how to parse JSON Data of an JSON Array.
But my JSON File is a little bit complicate (for me). It has the following structure:
JSON File (excerpt)
{
"data": {
"schedule_id": {
"12": {
"name": "CP",
"d_id": [
"7"
]
},
"17": {
"name": "WT",
"d_id": [
"88",
"14"
]
}
}
}
}
Java Code (excerpt)
Info: I've parsed the json into "json" using HTTP GET in another Activity.
JSONObject dataJsonData = json.getJSONObject("data").getJSONObject("schedule_id");
Now I would parse through the ids using a "for"-loop:
ArrayList<String> parsedNameList = new ArrayList<String>();
for (int i = 0; i < idontknow; i++) {
String s = new Integer(i).toString();
parsedNameList.add(dateJsonData.getJSONObject(i).getString("name"));
}
This would add each value of "name" to the ArrayList.
But there are 2 problems:
1. The "schedule_id"s are messed up and incomplete. For example, there is no id "0" and, like in given json, the ids "13, 14, 15, 16" are missing.
2. The "schedule_id"s will be changed every day and will be mixed.
So I don't think, that I can use the predefined integer "i" because some integers aren't a "schedule_id". I could use this loop and would ignore empty entries in the ArrayList, but the JSON contains more than 200 ids - I think it would be more efficient, if there is another way to parse through this json.
I found some informations of the getJSONArray method, but the "d_id"s are Arrays - not the "schedule_ids".
Does anyone has an idea? Is there maybe a placeholder for the parameter of the getString method?
PS: Excuse my english, I'm from germany :)
I think this should work
Iterator keys = dataJsonData.keys();
while(keys.hasNext()) {
// loop to get the dynamic key
String currentDynamicKey = (String)keys.next();
// get the value of the dynamic key
String currentDynamicValue = dataJsonData .getString(currentDynamicKey);
parsedJsonList.add(currentDynamicValue );
}
Source: How to parse a dynamic JSON key in a Nested JSON result?
According to your context, it is better to change the json structure,if you have access to web service.
Request for json structure to be like this,
{
"data":{
"schedule":[
{
"id":12,
"name":"CP",
"d_id":[
"7"
]
},
{
"id":12,
"name":"CP",
"d_id":[
"7",
"88"
]
},
{
"id":200,
"name":"AT",
"d_id":[
"7",
"88"
]
}
]
}
}
Otherwise too much iteration can slow down you CPU.
I have a JSON as below
{
"shippingGroupListJson":[
{
"lineId":123,
"shippedTo":{
"country":"US"
},
"cartons":1,
"group":"4",
"shipInscription":{
"municipalInscription":"",
"inscriptionType":"",
"stateInscription":"",
"suframaInscriptionNumber":"",
"inscriptionBranch":"",
"contributorClass":"",
"inscriptionDigit":"",
"inscriptionNumber":""
},
"shipCartonDetails":[
],
"shippedContact":{
"firstName":"Mjjkk",
"email":"nob#gmail.com",
"fax":"--",
"phone":"80-121",
"lastName":"Henry"
},
"mobilityShipStatus":"Not Yet Shipped",
"shipDate":"13 Dec 2014"
},
{
"lineId":0,
"shippedTo":[
],
"cartons":0,
"group":"5",
"shipInscription":[
],
"shipCartonDetails":[
],
"shippedContact":[
],
"mobilityShipStatus":"",
"shipDate":"",
"shipStatus":""
}
]
}
If you see in this above JSON in key "shippedTo", when there is value , I get a JSON Object and when no value is present then i get a Blank JSONArray.
I need to fix this issue. I cannot communicate with the service team to change this as they won't make changes to it. Can any one tell me how can i do the required changes.
I know this is not the rite way, but i need to do something..
I tried using String.replaceAll(oldChar,newChar);
You say you are using GSON, in which case JsonArray and JsonObject are both subclasses of JsonElement.
But you do not say if you are using the DOM or Streaming technique with GSON.
You should show your parsing code, or the class that's being automatically used for the parsing.
In the meantime, based on what you have said, I would define my shippedTo field in my class as an Object. That should parse correctly (if using DOM), and after that you can analyse exactly what you have in that field.
Instead of:
private MyCountryType shippedTo;
Have:
private Object shippedTo;
You could simply check its type at runtime i.e
JSONObject jsPar=new JSONObject(json_data);
JSONArray jsarrPar=js.getJSONArray("shippingGroupListJson");
for(int i=0;i<jsarrPar.size();i++){
JSONObject js= jsarrPar.getJSONObject(i);
if(js.get("shippedTo") instanceof JSONArray){
//Treat it as an array
}
else{
//Treat it as a single json object
}
}
Furthermore if you need it as an JSONObject immaterial of it being a single element then do this to get your customized string
JSONObject jsPar=new JSONObject(json_data);
JSONArray jsarrPar=js.getJSONArray("shippingGroupListJson");
for(int i=0;i<jsarrPar.size();i++){
JSONObject js= jsarrPar.getJSONObject(i);
JSONObject js=new JSONObject(json_data);
if(js.get("shippedTo") instanceof JSONArray){
js.put("shippedTo",new JSONObject()); //purge the original array with this new blank element
}
else{
//Do your normal stuff
}
}
String curmodstring=jsPar.toString();
Hope you get the general idea.