Parse Json with a definition at the beginning - json

I want to parse a Json file with this structure:
{"x":"exchange","b":"usd","ds":["exchange","avgp","mcap","ppc7D","ppc12h","ppc4h","ppc24h"],"data":[["Dow Jones","16360.447","273.89B","6.62","2.14","-0.59","-1.99"],["Dax","877.422","6.80B","38.15","-7.4","-4.44","-4.12"],["nikkei","30.077","2.96B","24.22","-2.3","-4.02","-4.95"],["ATX","281.509","15.29B","214.97","-5.48","-4.58","-10.77"]]}
I do not know how to parse a Json file where there is no definition like:
exchange = "Dow Jones", avgp = 16360.477" etc.
And i could not found anything online.
My code looks like this:
let json = """
{"x":"exchange","b":"usd","ds":["exchange","avgp","mcap","ppc7D","ppc12h","ppc4h","ppc24h"],"data":[["Dow Jones","16360.447","273.89B","6.62","2.14","-0.59","-1.99"],["Dax","877.422","6.80B","38.15","-7.4","-4.44","-4.12"],["nikkei","30.077","2.96B","24.22","-2.3","-4.02","-4.95"],["ATX","281.509","15.29B","214.97","-5.48","-4.58","-10.77"]]}
""".data(using: .utf8)!
struct JsonWebsocket: Decodable {
let exchange: String
let avgp: String
let mcap: String
let ppc7D: String
let ppc12h: String
let ppc4h: String
let ppc24h: String
init(exchange: String, avgp: String, mcap: String, ppc7D: String, ppc12h: String, ppc4h: String, ppc24h: String) {
self.exchange = exchange
self.avgp = avgp
self.mcap = mcap
self.ppc7D = ppc7D
self.ppc12h = ppc24h
self.ppc4h = ppc4h
self.ppc24h = ppc24h
}
}
func fetchJson() -> [String:JsonWebsocket] {
let jsonCoinsDecode = json
let coinDecode = JSONDecoder()
let output = try! coinDecode.decode([String:JsonWebsocket].self, from: jsonCoinsDecode)
return output
}
let array = fetchDataTradingPairs()
But of course it returns an error as the structure does not match the json file.
Does anyone know how to parse this json?
Thanks!

create a struct like that.
struct JsonWebsocket: Decodable {
let x: String
let b: String
let ds: [String]
let data: [[String]]
}
and decode
do {
let coinDecode = JSONDecoder()
let output = try coinDecode.decode(JsonWebsocket.self, from: json)
print(output.data)
}
catch let error{
print(error.localizedDescription)
}
alter native
otherwise, create a custom
struct JsonWebsocket: Decodable {
let exchange: String
let avgp: String
let mcap: String
let ppc7D: String
let ppc12h: String
let ppc4h: String
let ppc24h: String
init(json: [String]) {
self.exchange = json[0]
self.avgp = json[1]
self.mcap = json[2]
self.ppc7D = json[3]
self.ppc12h = json[4]
self.ppc4h = json[5]
self.ppc24h = json[6]
}
}
do {
let jsonData = try JSONSerialization.jsonObject(with: json, options: []) as? [String: Any]
var jsonWebsocket: [JsonWebsocket] = []
if let data = jsonData!["data"] as? [[String]] {
for d in data {
jsonWebsocket.append(JsonWebsocket(json: d))
}
}
print(jsonWebsocket.count)
}
catch let error{
print(error.localizedDescription)
}

Related

please help get data from json in swift

I parsed data from a json file, but I don't know how to get these variables.
Need charcode, name and value.
I need to display them in a table using swiftui. I got a mess in the console and I don't know how to get to this data
this is struct
import Foundation
struct CurrencyModel: Codable {
let valute: [String : Valute]
enum CodingKeys: String, CodingKey {
case valute = "Valute"
}
}
struct Valute: Codable {
let charCode, name: String
let value: Double
enum CodingKeys: String, CodingKey {
case charCode = "CharCode"
case name = "Name"
case value = "Value"
}
}
and this is parser
class FetchDataVM: ObservableObject {
var valueData = [String : Any]()
init() {
fetchCurrency()
}
func fetchCurrency() {
let urlString = "https://www.cbr-xml-daily.ru/daily_json.js"
let url = URL(string: urlString)
URLSession.shared.dataTask(with: url!) {data, _, error in
DispatchQueue.main.async {
if let data = data {
do {
let decoder = JSONDecoder()
let decodedData = try decoder.decode(CurrencyModel.self, from: data)
print(decodedData)
} catch {
print("Error! Something went wrong.")
}
}
}
}.resume()
}
}
As all needed information is in the Valute struct you need only the values of the valute dictionary. Replace
var valueData = [String : Any]()
with
#Published var valueData = [Valute]()
and after the line print(decodedData) insert
self.valueData = decodedData.valute.values.sorted{$0.name < $1.name}
or
self.valueData = decodedData.valute.values.sorted{$0.charCode < $1.charCode}
In the view you can iterate the array simply with a ForEach expression

How to read local JSON file and output JSON in swift?

import Foundation
class ReadLocalJSON {
static func readJSONFromFile(fileName: String) -> JSON
{
var json: JSON
if let path = Bundle.main.path(forResource: fileName, ofType: "json") {
do {
let fileUrl = URL(fileURLWithPath: path)
let data = try Data(contentsOf: fileUrl, options: .mappedIfSafe)
json = try? JSONSerialization.jsonObject(with: data)
} catch {
print("Something goes wrong when reading local json file.")
}
}
return json
}
}
I try to read the local json file and output json. But the line json = try? JSONSerialization.jsonObject(with: data) gives an error saying Cannot assign value of type 'Any?' to type 'JSON'.
My json data looks like
{
"leagues":
[
{ "name": "Hockey",
"image": "hockey",
"games":
[
{
"game_state": "Final",
"game_time": 1456662600,
"home_team_city": "Alberta",
"home_team_name": "Pigs",
"home_team_score": 1,
"home_team_logo": "pig",
"visit_team_city": "Montreal",
"visit_team_name": "Fishes",
"visit_team_score": 4,
"visit_team_logo": "fish"
}
]
}
]
}
When I change the output type to be Any? I print the output and it seems missing some elements.
{
leagues = (
{
games = (
{
"game_state" = Final;
"game_time" = 1456662600;
...
How can I fix it?
Check the solution below, I used Codable for the JSON decoding.
import Foundation
struct Sports: Codable {
let leagues: [League]
}
struct League: Codable {
let name, image: String
let games: [Game]
}
struct Game: Codable {
let gameState: String
let gameTime: Int
let homeTeamCity, homeTeamName: String
let homeTeamScore: Int
let homeTeamLogo, visitTeamCity, visitTeamName: String
let visitTeamScore: Int
let visitTeamLogo: String
enum CodingKeys: String, CodingKey {
case gameState = "game_state"
case gameTime = "game_time"
case homeTeamCity = "home_team_city"
case homeTeamName = "home_team_name"
case homeTeamScore = "home_team_score"
case homeTeamLogo = "home_team_logo"
case visitTeamCity = "visit_team_city"
case visitTeamName = "visit_team_name"
case visitTeamScore = "visit_team_score"
case visitTeamLogo = "visit_team_logo"
}
}
class ReadLocalJSON {
static func readJSONFromFile(fileName: String) -> Sports?
{
let path = Bundle.main.path(forResource: fileName, ofType: "json")
let url = URL(fileURLWithPath: path!)
let sportsData = try? Data(contentsOf: url)
guard
let data = sportsData
else { return nil }
do {
let result = try JSONDecoder().decode(Sports.self, from: data)
print(result)
return result
} catch let error {
print("Failed to Decode Object", error)
return nil
}
}
}
ReadLocalJSON.readJSONFromFile(fileName: "test")
Step 1:- first make a modal class in your project
struct Welcome: Codable {
let leagues: [League]?
}
// MARK: - League
struct League: Codable {
let name, image: String?
let games: [Game]?
}
// MARK: - Game
struct Game: Codable {
let gameState: String?
let gameTime: Int?
let homeTeamCity, homeTeamName: String?
let homeTeamScore: Int?
let homeTeamLogo, visitTeamCity, visitTeamName: String?
let visitTeamScore: Int?
let visitTeamLogo: String?
enum CodingKeys: String, CodingKey {
case gameState = "game_state"
case gameTime = "game_time"
case homeTeamCity = "home_team_city"
case homeTeamName = "home_team_name"
case homeTeamScore = "home_team_score"
case homeTeamLogo = "home_team_logo"
case visitTeamCity = "visit_team_city"
case visitTeamName = "visit_team_name"
case visitTeamScore = "visit_team_score"
case visitTeamLogo = "visit_team_logo"
}
}
Step 2 : - After getting response write this line,
let decoder = JSONDecoder()
let obj = try! decoder.decode(Welcome.self, from: jsonData!)
IF you have still problem let me know

Getting error when parsing JSON in Swift 3

1. This is the response String
{"error_msg": null,"applicationStateJson": {"notifications_size": "0","dfilterlogin": 1,"loginstype": null,"email_status": "0","address_status": "0","defaultfiltername": "hyderabad","login_status": "1","defaultfilterid": 145,"profile_id": null,"freelancer": "Y","otp_status": "1","notifications": []},"status": null}
2. Below one is the perfect JSONObject, I get it to using JSONLint
{
"error_msg": null,
"applicationStateJson": {
"notifications_size": "0",
"dfilterlogin": 1,
"loginstype": null,
"email_status": "0",
"address_status": "0",
"defaultfiltername": "hyderabad",
"login_status": "1",
"defaultfilterid": 145,
"profile_id": null,
"freelancer": "Y",
"otp_status": "1",
"notifications": []
},
"status": null
}
3. When I try the below code in Swift 3
let json1 = try? JSONSerialization.jsonObject(with: data, options: [])
if let object = json1 as? [String: Any]{
if let applicationState = object["applicationStateJson"] as? [String: Any]{
print("applicationState \(applicationState)")
}
}
4. I got JSONObject but it's not a proper JSONObject
(because the commas are changed into semicolon, null values are changed into "< null >" and then empty array [] changed into ())
Optional({
applicationStateJson = {
"address_status" = 0;
defaultfilterid = 145;
defaultfiltername = hyderabad;
dfilterlogin = 1;
"email_status" = 0;
freelancer = Y;
"login_status" = 1;
loginstype = "<null>";
notifications = (
);
"notifications_size" = 0;
"otp_status" = 1;
"profile_id" = "<null>";
};
"error_msg" = "<null>";
status = "<null>";
})
I want the JSONObject like the step 2, any help?
To read and use a JSON response in Swift does not require you to convert the JSON object back to JSON just to get a particular part. Once you have the data loaded into a Swift type you can work directly with it to get the parts you need.
So the long way which explains my point better...
let jsonData = jsonString.data(using: .utf8)!
let json1 = try? JSONSerialization.jsonObject(with: jsonData, options: [])
if let object = json1 as? [String: Any]{
if let applicationState = object["applicationStateJson"] as? [String: Any]{
print("applicationState \(applicationState)")
if let addressStatus = applicationState["address_status"] as? String {
print(addressStatus)
}
}
}
The Swift 4 way of doing this with the Codable Protocol
let jsonString = "{\"error_msg\": null,\"applicationStateJson\": {\"notifications_size\": \"0\",\"dfilterlogin\": 1,\"loginstype\": null,\"email_status\": \"0\",\"address_status\": \"0\",\"defaultfiltername\": \"hyderabad\",\"login_status\": \"1\",\"defaultfilterid\": 145,\"profile_id\": null,\"freelancer\": \"Y\",\"otp_status\": \"1\",\"notifications\": []},\"status\": null}"
struct ApplicationState: Codable {
let notificationsSize: String
let dFilterLogin: Int
let loginsType: String?
let emailStatus: String
let addressStatus: String
enum CodingKeys : String, CodingKey {
case notificationsSize = "notifications_size"
case dFilterLogin = "dfilterlogin"
case addressStatus = "address_status"
case loginsType = "loginstype"
case emailStatus = "email_status"
}
}
struct ApplicationStateResponse: Codable {
let errorMsg: String?
let applicationState: ApplicationState
enum CodingKeys : String, CodingKey {
case errorMsg = "error_msg"
case applicationState = "applicationStateJson"
}
}
let jsonData = jsonString.data(using: .utf8)!
let decoder = JSONDecoder()
let response = try! decoder.decode(ApplicationStateResponse.self, from: jsonData)
let appState = response.applicationState
print(appState.addressStatus)
Both of these print 0 for the address status as expected. one is much easier to work with than the other though.
This article which explains the codable protocol a bit more would be a good read.
Convert Swift Dictionary object to JSON string,
if let theJSONData = try? JSONSerialization.data(withJSONObject: applicationState, options: .prettyPrinted),
let theJSONText = String(data: theJSONData, encoding: String.Encoding.ascii) {
print("JSON string = \n\(theJSONText)")
}

getting JSON Data with Swift 4 and Xcode 9

I've been trying to work with the below code to get my JSON data. It returns "Error after loading". I am using this JSON data in another application and it works. I'm trying to implement the new simplified method using Swift 4. The code does work to the point of the print statement "downloaded".
class MortgageRatesVC: UIViewController {
final let url = URL (string:"http://mortgous.com/JSON/currentRatesJSON.php")
override func viewDidLoad() {
super.viewDidLoad()
downloadJason()
}
func downloadJason () {
guard let downloadURL = url else { return }
URLSession.shared.dataTask(with: downloadURL) { data, urlResponse, error in
guard let data = data, error == nil, urlResponse != nil else {
print("Oops Call for Help")
return
}
print("downloaded")
do
{
let decoder = JSONDecoder()
let rates = try decoder.decode([LenederRates].self, from: data)
print(rates)
} catch {
print("Error after loading")
}
}.resume()
}
}
Class
class LenederRates: Codable {
let key : String
let financial_institution : String
let variable_rate : String
let six_months : String
let one_year : String
let two_year : String
let three_year : String
let four_year : String
let five_year : String
// let date : Date
init(key: String, financial_institution: String, variable_rate: String, six_months: String, one_year: String, two_year: String, three_year: String, four_year: String, five_year: String) {
self.key = key
self.financial_institution = financial_institution
self.variable_rate = variable_rate
self.six_months = six_months
self.one_year = one_year
self.two_year = two_year
self.three_year = three_year
self.four_year = four_year
self.five_year = five_year
}
}
The problem is the missing property date in your Codable class. You need to set the decoder dateDecodingStrategy to .formatted and pass a fixed format dateFormatter. Btw I suggest changing your class for a struct, change your property names using the Swift naming convention camelCase and provide the custom CodingKeys:
struct LenederRates: Codable {
let key: String
let financialInstitution : String
let variableRate: String
let sixMonths: String
let oneYear: String
let twoYear: String
let threeYear: String
let fourYear: String
let fiveYear: String
let date: Date
private enum CodingKeys: String, CodingKey {
case key, financialInstitution = "financial_institution", variableRate = "variable_rate", sixMonths = "six_months", oneYear = "one_year", twoYear = "two_year", threeYear = "three_year", fourYear = "four_year", fiveYear = "five_year", date
}
}
let mortgousURL = URL(string:"http://mortgous.com/JSON/currentRatesJSON.php")!
URLSession.shared.dataTask(with: mortgousURL) { data, urlResponse, error in
guard let data = data else { return }
do {
let dateFormat = DateFormatter()
dateFormat.locale = Locale(identifier: "en_US_POSIX")
dateFormat.dateFormat = "yyyy-MM-dd"
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .formatted(dateFormat)
let rates = try decoder.decode([LenederRates].self, from: data)
print(rates)
} catch {
print(error)
}
}.resume()

Parse JSON data in swift

I am trying to parse my json data in swift 3.0. I am using Alamofire 4.0+
Here is my json
{
"token":
"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1MDQ0MjgzNzgxMTF9.CNonyvtQbRgaqqkdPO5KwqpVaUmlGrpaTqlBxmvaX80",
"expires": 1504428378111,
"user":
[{"user_id":13,"user_first_name":"Himanshu","user_last_name":"Srivastava","full_name":"Himanshu Srivastava"}]
}
Here is my model class to hold these values
import Foundation
import ObjectMapper
class LoginResult:Mappable{
var token:String?
var expires:Double?
var users:[[String:Any]]?
required init?(map:Map){
}
func mapping(map:Map)->Void{
self.token <- map["token"]
self.expires <- map["expires"]
self.users <- map["user"]
}
}
None of the solution available on internet worked for me. How can I parse this json and map to the model class?
Any help here?
I was mistaken, the value for key user is indeed a regular array.
This is a solution without a third party mapper and with an extra User struct (by the way the value for key expires is an Int rather than Double).
Assuming the user data comes from a database which always sends all fields the user keys are forced unwrapped. If this is not the case use optional binding also for the user data:
struct User {
let firstName : String
let lastName : String
let fullName : String
let userID : Int
}
class LoginResult {
let token : String
let expires : Int
var users = [User]()
init(json : [String:Any]) {
self.token = json["token"] as? String ?? ""
self.expires = json["expires"] as? Int ?? 0
if let users = json["user"] as? [[String:Any]] {
self.users = users.map { User(firstName: $0["user_first_name"] as! String,
lastName: $0["user_last_name"] as! String,
fullName: $0["full_name"] as! String,
userID: $0["user_id"] as! Int)
}
}
}
}
let json = "{\"token\":\"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1MDQ0MjgzNzgxMTF9.CNonyvtQbRgaqqkdPO5KwqpVaUmlGrpaTqlBxmvaX80\",\"expires\":504428378111,\"user\":[{\"user_id\":13,\"user_first_name\":\"Himanshu\",\"user_last_name\":\"Srivastava\",\"full_name\":\"Himanshu Srivastava\"}]}"
let jsonData = json.data(using: .utf8)!
do {
if let userData = try JSONSerialization.jsonObject(with: jsonData) as? [String:Any] {
let loginResult = LoginResult(json: userData)
print(loginResult.users[0])
// do something with loginResult
}
} catch {
print(error)
}
Here is the answer with map replaced by dictionary. Don't forget to handle error or unwrap carefully :)
let str = "{\"token\": \"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1MDQ0MjgzNzgxMTF9.CNonyvtQbRgaqqkdPO5KwqpVaUmlGrpaTqlBxmvaX80\",\"expires\": 1504428378111,\"user\": [{\"user_id\":13,\"user_first_name\":\"Himanshu\",\"user_last_name\":\"Srivastava\",\"full_name\":\"Himanshu Srivastava\"}]}"
let data = str.data(using: .utf8)
do{
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? [String: Any]
//Pass this json into the following function
}catch let error{
}
func mapping(json:[String: Any]?)->Void{
self.token <- json?["token"] as? String
self.expires <- json?["expires"] as? Double
self.users <- json?["user"] as? [[String: Any]]
}