Parsing JSON from Google Distance Matrix API

So I’m trying to pull data from a JSON string (as seen below). When I decode the JSON using the code below, and then attempt to index the duration text, I get a nil return. I have tried everything and nothing seems to work.

Here is the Google Distance Matrix API JSON:

{ "destination\_addresses" : ["San Francisco, CA, USA"], "origin\_addresses" : ["Seattle, WA, USA"], "rows" : [{ "elements" : [ { "distance" : { "text" : "1,299 km", "value" : 1299026 }, "duration" : { "text" : "12 hours 18 mins", "value" : 44303 }, "status" : "OK" }] } ], "status" : "OK" }

And here is my code:

local json = require ("json") local http = require("socket.http") local myNewData1 = {} local SaveData1 = function (event) distanceReturn = "" distance = "" local URL1 = "http://maps.googleapis.com/maps/api/distancematrix/json?origins=Seattle&destinations=San+Francisco&mode=driving&&sensor=false" local response1 = http.request(URL1) local data2 = json.decode(response1) if response1 == nil then native.showAlert( "Data is nill", { "OK"}) print("Error1") distanceReturn = "Error1" elseif data2 == nill then distanceReturn = "Error2" native.showAlert( "Data is nill", { "OK"}) print("Error2") else for i = 1, #data2 do print("Working") print(data2[i].rows) for j = 1, #data2[i].rows, 1 do print("\t" .. data2[i].rows[j]) for k = 1, #data2[i].rows[k].elements, 1 do print("\t" .. data2[i].rows[j].elements[k]) for g = 1, #data2[i].rows[k].elements[k].duration, 1 do print("\t" .. data2[i].rows[k].elements[k].duration[g]) for f = 1, #data2[i].rows[k].elements[k].duration[g].text, 1 do print("\t" .. data2[i].rows[k].elements[k].duration[g].text) distance = data2[i].rows[k].elements[k].duration[g].text distanceReturn = data2[i].rows[k].elements[k].duration[g].text end end end end end end timer.performWithDelay (100, SaveData1, 999999)

JSON and Lua tables are almost identical data structures.  In this case your table data2 has top level entries:

data2.destination_addresses

data2.origin_addresses

data2.rows

data2.status

Now data2.rows is another table that is indexed by numbers (the [] brackets) but here is only one of them, but its still an array entry:

data.rows[1]

Then inside of it is another numerically indexed table called elements. 
So far to get to the element they are (again there is only one of them

data2.rows[1].elements[1]

then it’s just accessing the remaining elements:

data2.rows[1].elements[1].distance.text

data2.rows[1].elements[1].distance.value

data2.rows[1].elements[1].duration.text

data2.rows[1].elements[1].duration.value

There is a great table printing function called print_r which can be found in the community code which is great for dumping tables like this to see their structure.

That works perfectly! Thank you for your quick response  :slight_smile:

One more question….when I make the same request with ssl, I get an error: “Attempt to index nil value”.

My request URL is as follows:

local URL = ("https://maps.googleapis.com/maps/api/distancematrix/json?origins="..veh1lat..","..veh1long.."&destinations="..currentLatitude..","..currentLongitude.."&mode=driving&sensor=false&key=\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*") print(URL) local response = http.request(URL) local data2 = json.decode(response)

When I plug the URL into a browser, it return the same result as the non ssl URL. 

Any thoughts? 

I would suggest printing out the response value and make sure it’s formatted the way you expect it to be.  Then if you grabbed that print_r function, run it after you json.decode() the response and see if things are where you expect them to be.

Rob

I did what you suggested. Here’s what I got by printing my return:  

{ "destination\_addresses" : [], "error\_message" : "Requests to this API must be over SSL.", "origin\_addresses" : [], "rows" : [], "status" : "REQUEST\_DENIED" }

However, when I paste the URL into a browser, it works.

{ "destination\_addresses" : ["1464-1468 Upper Park Road, Santa Cruz, CA 95065, USA"], "origin\_addresses" : ["2132-2138 Cabrillo Highway North, Half Moon Bay, CA 94019, USA"], "rows" : [{ "elements" : [ { "distance" : { "text" : "84.5 km", "value" : 84517 }, "duration" : { "text" : "1 hour 8 mins", "value" : 4068 }, "status" : "OK" }] } ], "status" : "OK" }

If I use the URL: https://maps.googleapis.com/maps/api/distancematrix/json?origins=37.48332995,-122.44635864&destinations=37,-122&mode=driving&sensor=false with no key, I get a good return.

Possibly I could use an openSSL plugin?

What is the URL you are using and the network code to fetch it?

The URL:  https ://maps.googleapis.com/maps/api/distancematrix/output?parameters

Full URL with paramaters: 

local URL = ("http://maps.googleapis.com/maps/api/distancematrix/json?origins="..veh1lat..","..veh1long.."&destinations="..currentLatitude..","..currentLongitude.."&mode=driving&sensor=false")

There is no network code, I simply use the url in the folowing set up:

json = require ("json") http = require("socket.http") local URL = ("https://maps.googleapis.com/maps/api/distancematrix/json?origins="..veh1lat..","..veh1long.."&destinations="..currentLatitude..","..currentLongitude.."&mode=driving&sensor=false") print(URL) local response = http.request(URL) print(response) local data2 = json.decode(response) print(data2) distanceReturn = data2.rows[1].elements[1].duration.text 

 It works without the Key, but when I add &key=****************************, it returns an error. However, if i plug the url with key into a browser, it works. Here is the documentation for the matrix API:

https://developers.google.com/maps/documentation/distancematrix/

Okay, you have two issues.  Google wants you to use HTTPS protocol, i.e. http_s_://.  When you do use http:// Google is most likely doing a redirect from http: to https: for you.  The second issue is that Lua sockets does NOT support https. 

You really need to use network.request() instead of how you’re doing it and access the URL using https://

Rob

JSON and Lua tables are almost identical data structures.  In this case your table data2 has top level entries:

data2.destination_addresses

data2.origin_addresses

data2.rows

data2.status

Now data2.rows is another table that is indexed by numbers (the [] brackets) but here is only one of them, but its still an array entry:

data.rows[1]

Then inside of it is another numerically indexed table called elements. 
So far to get to the element they are (again there is only one of them

data2.rows[1].elements[1]

then it’s just accessing the remaining elements:

data2.rows[1].elements[1].distance.text

data2.rows[1].elements[1].distance.value

data2.rows[1].elements[1].duration.text

data2.rows[1].elements[1].duration.value

There is a great table printing function called print_r which can be found in the community code which is great for dumping tables like this to see their structure.

That works perfectly! Thank you for your quick response  :slight_smile:

One more question….when I make the same request with ssl, I get an error: “Attempt to index nil value”.

My request URL is as follows:

local URL = ("https://maps.googleapis.com/maps/api/distancematrix/json?origins="..veh1lat..","..veh1long.."&destinations="..currentLatitude..","..currentLongitude.."&mode=driving&sensor=false&key=\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*") print(URL) local response = http.request(URL) local data2 = json.decode(response)

When I plug the URL into a browser, it return the same result as the non ssl URL. 

Any thoughts? 

I would suggest printing out the response value and make sure it’s formatted the way you expect it to be.  Then if you grabbed that print_r function, run it after you json.decode() the response and see if things are where you expect them to be.

Rob

I did what you suggested. Here’s what I got by printing my return:  

{ "destination\_addresses" : [], "error\_message" : "Requests to this API must be over SSL.", "origin\_addresses" : [], "rows" : [], "status" : "REQUEST\_DENIED" }

However, when I paste the URL into a browser, it works.

{ "destination\_addresses" : ["1464-1468 Upper Park Road, Santa Cruz, CA 95065, USA"], "origin\_addresses" : ["2132-2138 Cabrillo Highway North, Half Moon Bay, CA 94019, USA"], "rows" : [{ "elements" : [ { "distance" : { "text" : "84.5 km", "value" : 84517 }, "duration" : { "text" : "1 hour 8 mins", "value" : 4068 }, "status" : "OK" }] } ], "status" : "OK" }

If I use the URL: https://maps.googleapis.com/maps/api/distancematrix/json?origins=37.48332995,-122.44635864&destinations=37,-122&mode=driving&sensor=false with no key, I get a good return.

Possibly I could use an openSSL plugin?

What is the URL you are using and the network code to fetch it?

The URL:  https ://maps.googleapis.com/maps/api/distancematrix/output?parameters

Full URL with paramaters: 

local URL = ("http://maps.googleapis.com/maps/api/distancematrix/json?origins="..veh1lat..","..veh1long.."&destinations="..currentLatitude..","..currentLongitude.."&mode=driving&sensor=false")

There is no network code, I simply use the url in the folowing set up:

json = require ("json") http = require("socket.http") local URL = ("https://maps.googleapis.com/maps/api/distancematrix/json?origins="..veh1lat..","..veh1long.."&destinations="..currentLatitude..","..currentLongitude.."&mode=driving&sensor=false") print(URL) local response = http.request(URL) print(response) local data2 = json.decode(response) print(data2) distanceReturn = data2.rows[1].elements[1].duration.text 

 It works without the Key, but when I add &key=****************************, it returns an error. However, if i plug the url with key into a browser, it works. Here is the documentation for the matrix API:

https://developers.google.com/maps/documentation/distancematrix/

Okay, you have two issues.  Google wants you to use HTTPS protocol, i.e. http_s_://.  When you do use http:// Google is most likely doing a redirect from http: to https: for you.  The second issue is that Lua sockets does NOT support https. 

You really need to use network.request() instead of how you’re doing it and access the URL using https://

Rob