如何快速解析这种 JSON 格式
Posted
技术标签:
【中文标题】如何快速解析这种 JSON 格式【英文标题】:How to parse this JSON format in swift 【发布时间】:2020-09-29 16:00:11 【问题描述】:我有这种 JSON 格式:
"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 响应。
这将是我想要的模型。
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
https://webbfoot.com/dataa.json
【问题讨论】:
所以,这个想法是"data"
中的值顺序是由"fields"
中的字段顺序定义的?
是的。例如..第一行 I.D. = 20,下午 = 0.0 等等...
你应该在你的问题中添加你想要得到的结果模型,即使你不知道怎么做
我过去回答过一个类似的问题,所以它可能会有所帮助:***.com/a/61854827/968155
责备服务的所有者发送这种伪 CSV 格式。这是非常不切实际的解析。
【参考方案1】:
你可以使用Codable
来解析这个:
struct Response: Decodable
let version: String
let fields: [String]
let data: [[QuantumValue?]]
let count: Int
enter code here
enum QuantumValue: Decodable
case float(Float), string(String)
init(from decoder: Decoder) throws
if let int = try? decoder.singleValueContainer().decode(Float.self)
self = .float(float)
return
if let string = try? decoder.singleValueContainer().decode(String.self)
self = .string(string)
return
throw QuantumError.missingValue
enum QuantumError:Error
case missingValue
QuantumValue
将处理 Float
和 String
和 ?
将处理 null
部分。
【讨论】:
这不起作用,因为"data"
包含Int
和String
和null
这行得通,但您应该首先向 OP 澄清生成的模型应该是什么。编辑:查看他的最新编辑【参考方案2】:
这个比较棘手,需要手动解码。原则是定义您希望解码的字段和对象的属性之间的映射,然后根据属性的类型(String
、Double
等...),尝试解码数据.
第二,既然你有一个点数组,你需要某种容器对象来保存这个数组,例如:
struct Points
var data: [Point] = []
首先,您的某些模型属性与数据中的类型不匹配,例如iD
是 String
,但数据有 Int
。为简单起见,我将重新定义您的模型以匹配数据
struct Point
var pm2: Int? = nil
var latitude: Double? = nil
var longitude: Double? = nil
var temp: Int? = nil
var iD: Int? = nil
现在,为父容器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:
let points = try JSONDecoder().decode(Points.self, from: jsonData)
let firstPoint = points.data[0]
【讨论】:
我已将 URL 添加到问题中。你能告诉我这在你上面的代码中是如何工作的吗?谢谢 因此,您在 URL 中所拥有的内容与您在问题中所拥有的内容并不完全一样。在 URL 中,JSON 包含data
的多行(内部数组),而您问题中的 JSON 有一个内部行。大概,您想要解码Point
s 的数组?
是的.. 我在最初的问题中只显示了一行,但我真正想做的是根据其与用户 lat long 的 lat long 接近度找到特定行的 ID
我更新了答案以解码点数组。解码响应后,您可以进行任何您需要的搜索。以上是关于如何快速解析这种 JSON 格式的主要内容,如果未能解决你的问题,请参考以下文章