Home > Software engineering >  How to parse JSON when one of my parameters is incorporated into the JSON itself?
How to parse JSON when one of my parameters is incorporated into the JSON itself?

Time:09-29

I'm new to JSON parsing. I'm trying to retrieve weather data using an API. Users input a city name as a textfield string, which will then be passed into a networking method that should retrieve the temperature for this city. The JSON looks like this:

"remainingCost": 0,
  "queryCost": 1,
  "messages": null,
  "locations": {
    "London": {
      "stationContributions": null,
      "values": [
        {
          "wdir": 322.4,
          "uvindex": 3.0,
          "datetimeStr": "2022-09-28T17:00:00 01:00",
          "preciptype": "",
          "cin": -2.0,
          "cloudcover": 57.4,
          "pop": 19.0,
          "datetime": 1664384400000,
          "precip": 0.0,
          "solarradiation": 280.0,
          "dew": 4.0,
          "humidity": 49.9,
          "temp": 14.3,
          "visibility": 15.0,
          "wspd": 6.0,
          "severerisk": 10.0,
          "solarenergy": 1.0,
          "heatindex": null,
          "snowdepth": 0.0,
          "sealevelpressure": 1000.0,
          "snow": 0.0,
          "wgust": 15.4,
          "conditions": "Partially cloudy",
          "windchill": null,
          "cape": 11.0
        }

Now, I've learned that I can build structs to host the decoded JSON data once I retrieve it, and I've created the following:

struct WeatherModel: Decodable {
    
    let locations: Locations
}

struct Locations: Decodable {
    
    let London: London
}

struct London: Decodable {
    
    let values: [Values]
}

struct Values: Decodable {
    
    let temp: Double
}

Then, using my decoder, I am able to successfully retrieve "temp". So far so good.

The issue is that "temp" is contained inside "values" which is contained inside "London", which is then contained inside "locations". However 'London' should not be called each time, only if the user enters 'London' in the textfield. If they entered 'Paris', for example, then my structs would no longer work, and as far as I know I can't make a 'variable' struct that would accept any city name as its name.

How can I resolve this so that I can get the different city weather depending on the input? Is there a different way of housing the JSON? Is this a shortcoming of the API itself, and maybe I should find a different data source? Thanks in advance for your advice.

CodePudding user response:

For this one, I suggest you create the object model like this:

struct WeatherModel: Decodable {
    let locations: [String: Any?]
}

struct City: Decodable {
    let values: [Values]
}

struct Values: Decodable {
    let temp: Double
}

And when you get the WeatherModel it will include locations as the [String: Any?]. Now, get the dictionary of the city by using the key is city name.

let cityDictionary = weatherModel.locations["cityName"] as? [String: Any?]

The last thing is using JSONSerialization to decode the dictionary into the object, or get the object value key by key.

CodePudding user response:

import Foundation

// MARK: - MyObject
struct MyObject: Codable {
    let remainingCost, queryCost: Int
    let messages: String?
    ///Dictionary that will have the city name 
    ///as the key and the values as an array of objects.
    let locations:[String,[City]]
}

// MARK: - London
struct City: Codable {
    let stationContributions: String?
    let values: [Value]
}

// MARK: - Value
struct Value: Codable {
    let wdir: Double
    let uvindex: Int
    let datetimeStr: Date
    let preciptype: String
    let cin: Int
    let cloudcover: Double
    let pop, datetime, precip, solarradiation: Int
    let dew: Int
    let humidity, temp: Double
    let visibility, wspd, severerisk, solarenergy: Int
    let heatindex: Double? //Check unclear based one sample
    let snowdepth, sealevelpressure, snow: Int
    let wgust: Double
    let conditions: String
    let windchill: Double? //Check unclear based one sample
    let cape: Int
}
  • Related