如何快速解析此JSON格式 [英] How to parse this JSON format in swift
问题描述
我有这种JSON格式:
I have this JSON format:
{
"version":"7.0.19",
"fields": ["ID","pm","age","pm_0","pm_1","pm_2","pm_3","pm_4","pm_5","pm_6","conf","pm1","pm_10","p1","p2","p3","p4","p5","p6","Humidity","Temperature","Pressure","Elevation","Type","Label","Lat","Lon","Icon","isOwner","Flags","Voc","Ozone1","Adc","CH"],
"data":[[20,0.0,1,0.0,0.0,0.0,0.0,0.0,0.0,0.0,97,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,null,null,null,1413,0,"Oakdale",40.603077,-111.83612,0,0,0,null,null,0.01,1]],
"count":11880
}
但是我无法弄清楚如何使用Codable协议来解析json响应.
but I cannot work out how to use a Codable protocol to parse the json response.
这将是我想要的模型.
struct Point: Codable {
let pm2: String?
let latitude, longitude: Double?
let temp: String?
let iD: String?
enum CodingKeys: String, CodingKey {
case pm2 = "pm", temp = "Temperature", iD = "ID", latitude = "Lat", longitude = "Lon"
}
}
这是json的URL
Here is a URL to the json
https://webbfoot.com/dataa.json
推荐答案
这很棘手,需要手动解码.原理是定义要解码的字段与对象属性之间的映射,然后根据属性的类型( String
, Double
等...),尝试对数据进行解码.
This one is tricky and requires manual decoding. The principle would be to define a mapping between the fields you expect to decode and the properties of your object, then depending on the type of the property (String
, Double
, etc...), attempt to decode the data.
第二,由于具有点数组,因此需要某种容器对象来保存该数组,例如:
Second, since you have an array of points, you need some kind of container object to hold the array, for example:
struct Points {
var data: [Point] = []
}
首先,您的某些模型属性与数据中的类型不匹配,例如 iD
是 String
,但是数据具有 Int
.为简单起见,我将重新定义您的模型以匹配数据
First, some of your model properties don't match the type in the data, e.g. iD
is a String
, but the data has an Int
. For simplicity, I'll redefine your model to match the data
struct Point {
var pm2: Int? = nil
var latitude: Double? = nil
var longitude: Double? = nil
var temp: Int? = nil
var iD: Int? = nil
}
现在,为父容器 Points
编写手动解码器:
Now, write the manual decoder for the parent container Points
:
extension Points: Decodable {
static let mapping: [String: PartialKeyPath<Point>] = [
"pm": \Point.pm2,
"Lat": \Point.latitude,
"Lon": \Point.longitude,
"Temperature": \Point.temp,
"ID": \Point.iD
]
enum CodingKeys: CodingKey { case fields, data }
private struct Dummy: Decodable {} // see below why
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let fields = try container.decode([String].self, forKey: .fields)
var data = try container.nestedUnkeyedContainer(forKey: .data)
while !data.isAtEnd {
var row = try data.nestedUnkeyedContainer()
var point = Point()
for field in fields {
let keyPath = Points.mapping[field]
switch keyPath {
case let kp as WritableKeyPath<Point, String?>:
point[keyPath: kp] = try row.decodeIfPresent(String.self)
case let kp as WritableKeyPath<Point, Int?>:
point[keyPath: kp] = try row.decodeIfPresent(Int.self)
case let kp as WritableKeyPath<Point, Double?>:
point[keyPath: kp] = try row.decodeIfPresent(Double.self)
default:
// this is a hack to skip this value
let _ = try? row.decode(Dummy.self)
}
}
self.data.append(point)
}
}
}
有了它,就可以像这样对JSON进行解码:
Once you have that, you can decode the JSON like so:
let points = try JSONDecoder().decode(Points.self, from: jsonData)
let firstPoint = points.data[0]
这篇关于如何快速解析此JSON格式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!