How can I parse Nested JSON with NESTED dynamic keys in Android kotlin, Moshi and Retrofit?
I get this JSON from alpha-vantage.
Format example:
{
"Meta Data": {
"1. Information": "Intraday (15min) open, high, low, close prices and volume",
"2. Symbol": "AAME",
"3. Last Refreshed": "2019-11-18 16:00:00",
"4. Interval": "15min",
"5. Output Size": "Compact",
"6. Time Zone": "US/Eastern"
},
"Time Series (15min)": {//Dynamic - > Time Series (5min) / Time Series (30min)
"2019-11-18 16:00:00": {//Dynamic
"1. open": "1.6700",
"2. high": "1.6700",
"3. low": "1.5700",
"4. close": "1.5700",
"5. volume": "1521"
},
"2019-11-18 15:45:00": {//Dynamic
"1. open": "1.6600",
"2. high": "1.7400",
"3. low": "1.6600",
"4. close": "1.7400",
"5. volume": "355"
}
}
}
I tried to use custom adapter but I can't find a way to parse a double nested dynamic keys with it. For now I use manual parsing:
fun convertJsonToItemDetails(jso: JSONObject) {
val meta: JSONObject? = jso.optJSONObject("Meta Data")
var metaData: ItemMetaData? = null
meta?.apply {
val information = optString("1. Information")
val symbol = optString("2. Symbol")
val lastRefreshed = optString("3. Last Refreshed")
val interval = optString("4. Interval")
val outputSize = optString("5. Output Size")
val timeZone = optString("6. Time Zone")
metaData =
ItemMetaData(information, symbol, lastRefreshed, interval, outputSize, timeZone)
}
if (metaData == null) {
//TODO return error object
return
}
val timeSeriesJSON = jso.optJSONObject("Time Series (${metaData?.interval})")
val timeSeires = HashMap<String, IntervalOutput>()
if (timeSeriesJSON == null) {
//TODO return error object
return
}
for (key in timeSeriesJSON.keys()) {
val intervalOutPutJSON = timeSeriesJSON.getJSONObject(key)
val open = intervalOutPutJSON.getString("1. open")
val high = intervalOutPutJSON.getString("2. high")
val low = intervalOutPutJSON.getString("3. low")
val close = intervalOutPutJSON.getString("4. close")
val volume = intervalOutPutJSON.getString("5. volume")
timeSeires[key] = IntervalOutput(open, high, low, close, volume)
}
val itemDetails = ItemDetails(metaData, timeSeires)
_itemDetails.value = itemDetails
}
The prefix will change from string to object randomly in both success(...) and failure(...) methods! In above code POJO TrackerRefResponse. java prefix responseMessage is set to string or object of type responseMessage , so we can create the POJO with ref variable with same name (java basics :) )
Moshi is way faster than Gson(Link1, ) and uses less memory, This is due to its usage of Okio which can predict or expect ahead of the time the keys which helps on ignoring the unknown or unwanted fields while parsing a stream (A good article on this).
Moshi is a modern JSON library for Android, Java and Kotlin. It makes it easy to parse JSON into Java and Kotlin classes: Note: The Kotlin examples of this README assume use of either Kotlin code gen or KotlinJsonAdapterFactory for reflection. Plain Java-based reflection is unsupported on Kotlin classes. Java.
Use JSONObject keys() to get the Dynamic Keys
and then Iterate
each particular key to get to the dynamic value.
A very short to print all the JSONObject
of 1st Tier is look like this.
var dynamicJSON: String = {
"Meta Data": {
"1. Information": "Intraday (15min) open, high, low, close prices and volume",
"2. Symbol": "AAME",
"3. Last Refreshed": "2019-11-18 16:00:00",
"4. Interval": "15min",
"5. Output Size": "Compact",
"6. Time Zone": "US/Eastern"
},
"Time Series (15min)": {//Dynamic - > Time Series (5min) / Time Series (30min)
"2019-11-18 16:00:00": {//Dynamic
"1. open": "1.6700",
"2. high": "1.6700",
"3. low": "1.5700",
"4. close": "1.5700",
"5. volume": "1521"
},
"2019-11-18 15:45:00": {//Dynamic
"1. open": "1.6600",
"2. high": "1.7400",
"3. low": "1.6600",
"4. close": "1.7400",
"5. volume": "355"
}
}
}
Then After you have to start parsing it as JSONObject and then further follows the same process for the JSONObject "Meta Data"
& "Time Series (15min)"
val dynamicjson: JSONObject = JSONObject(dynamicJSON)
val keys: Iterator<*> = dynamicjson.keys()
while (keys.hasNext()) { // loop to get the dynamic key
val currentDynamicKey = keys.next() as String
// get the value of the dynamic key
val currentDynamicValue: JSONObject = dynamicjson.getJSONObject(currentDynamicKey)
// do something here with the value... or either make another while loop to Iterate further
Log.e("JSON Value", currentDynamicValue.toString())
}
The OUTPUT looks like this when I executed the code:
2019-12-12 15:21:08.399 19798-19798/com.animusabhi.dynamicjsonparsing E/JSON Value: {"1. Information":"Intraday (15min) open, high, low, close prices and volume","2. Symbol":"AAME","3. Last Refreshed":"2019-11-18 16:00:00","4. Interval":"15min","5. Output Size":"Compact","6. Time Zone":"US/Eastern"}
2019-12-12 15:21:09.158 19798-19798/com.animusabhi.dynamicjsonparsing E/JSON Value{"2019-11-18 16:00:00":{"1. open":"1.6700","2. high":"1.6700","3. low":"1.5700","4. close":"1.5700","5. volume":"1521"},"2019-11-18 15:45:00":{"1. open":"1.6600","2. high":"1.7400","3. low":"1.6600","4. close":"1.7400","5. volume":"355"}}
check and let me know if it not works.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With