我试图从下面的JSON中提取"data"
:
{
"result": "success",
"code": 200,
"version": "1",
"time": 1,
"id": "NODATA",
"data": {
"user_address_town": {
"label": "town",
"required": true,
"type": "string",
"value": ""
},
"user_address_county": {
"label": "county",
"required": true,
"type": "string"
},
"user_address_line_1": {
"label": "address 1",
"required": true,
"type": "string",
"value": ""
},
"user_address_line_2": {
"label": "address 2",
"required": false,
"type": "string",
"value": ""
},
"user_address_line_3": {
"label": "address 3",
"required": false,
"type": "string",
"value": ""
},
"user_address_postcode": {
"label": "postcode",
"required": false,
"type": "string",
"value": ""
},
"user_address_identifier": {
"label": "identifier",
"required": false,
"type": "string",
"value": ""
},
"stage": "stage1",
"last": true,
"ekyc": true,
"email": {
"label": "email address",
"required": true,
"type": "email",
"value": "[email protected]"
},
"password": {
"label": "password",
"required": true,
"type": "string"
},
"user_title": {
"label": "title",
"required": true,
"type": "string",
"value": "Mrs"
},
"user_first_name": {
"label": "first name",
"required": true,
"type": "string",
"value": "jsns"
},
"user_last_name": {
"label": "last name",
"required": true,
"type": "string",
"value": "nsm"
},
"user_dob": {
"label": "user date of birth",
"type": "date",
"required": true,
"value": "2001-01-22"
},
"user_gender": {
"label": "gender",
"type": "string",
"required": false,
"value": "M"
},
"user_country": {
"label": "country",
"required": true,
"type": "integer",
"value": "1"
},
"user_telephone": {
"label": "telephone",
"required": false,
"type": "string",
"value": "946464646"
},
"user_name_on_card": {
"label": "card name",
"required": false,
"type": "string"
}
}
}
我创建了一个名为IncompleteSignupResponse
的结构体,它在解码时应该包含"data"
对象中的所有数据。 userObject数组用于数据内的较小对象,例如user_address_town
。
以下是我使用的结构:
struct IncompleteSignupResponse {
let stage: String
let last: Bool
let ekyc: Bool
let error: String?
let userObject: [IncompleteUserObjectResponse]
}
struct IncompleteUserObjectResponse: Codable {
let label: String
let required: Bool
let type: String
let value: String
}
extension IncompleteSignupResponse: Codable {
private enum IncompleteSignupResponseAPIResponseCodingKeys: String, CodingKey {
case data = "data"
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: IncompleteSignupResponseAPIResponseCodingKeys.self)
let data = try container.decode(IncompleteSignupResponse.self, forKey: .data)
stage = data.stage
last = data.last
ekyc = data.ekyc
error = data.error
userObject = data.userObject
}
}
尝试解码结构会给出以下响应:
keyNotFound(IncompleteSignupResponseAPIResponseCodingKeys(stringValue:“data”,intValue:nil),Swift.DecodingError.Context(codingPath:[IncompleteSignupResponseAPIResponseCodingKeys(stringValue:“data”,intValue:nil)],debugDescription:“没有与键IncompleteSignupResponseAPIResponseCodingKeys相关的值(stringValue: \“data \”,intValue:nil)(\“data \”)。“,underlyingError:nil))
我不太清楚为什么关键数据无法找到,因为它没有嵌套在任何东西里面。
有什么我错过的吗?此外,我的布局是否被认为是良好的做法,还是有可以改进的事情。
使用本网站:JSONParser。您可以在代码中使用此Struct:
struct Welcome: Codable {
let result: String
let code: Int
let version: String
let time: Int
let id: String
let data: DataClass
}
struct DataClass: Codable {
let userAddressTown, userAddressCounty, userAddressLine1, userAddressLine2: Email
let userAddressLine3, userAddressPostcode, userAddressIdentifier: Email
let stage: String
let last, ekyc: Bool
let email, password, userTitle, userFirstName: Email
let userLastName, userDob, userGender, userCountry: Email
let userTelephone, userNameOnCard: Email
enum CodingKeys: String, CodingKey {
case userAddressTown = "user_address_town"
case userAddressCounty = "user_address_county"
case userAddressLine1 = "user_address_line_1"
case userAddressLine2 = "user_address_line_2"
case userAddressLine3 = "user_address_line_3"
case userAddressPostcode = "user_address_postcode"
case userAddressIdentifier = "user_address_identifier"
case stage, last, ekyc, email, password
case userTitle = "user_title"
case userFirstName = "user_first_name"
case userLastName = "user_last_name"
case userDob = "user_dob"
case userGender = "user_gender"
case userCountry = "user_country"
case userTelephone = "user_telephone"
case userNameOnCard = "user_name_on_card"
}
}
struct Email: Codable {
let label: String
let emailRequired: Bool
let type: TypeEnum
let value: String?
enum CodingKeys: String, CodingKey {
case label
case emailRequired = "required"
case type, value
}
}
enum TypeEnum: String, Codable {
case date = "date"
case email = "email"
case integer = "integer"
case string = "string"
}
希望这是你的期望。 mixedType枚举可以帮助您阅读那些恼人的键。
添加了Response
结构以包裹外层。
struct IncompleteSignupResponse: CustomDebugStringConvertible{
var debugDescription: String{
return "{stage: \(stage) ; last: \(last) ; ekyc : \(ekyc) ; error : \(String(describing: error)) ; userObject: \n \(userObject)}\n"
}
let stage: String
let last: Bool
let ekyc: Bool
let error: String?
let userObject: [IncompleteUserObjectResponse]
}
enum MixtureType : Decodable{
case Complete(IncompleteUserObjectResponse)
case Single(Bool)
case Simple(String)
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
do{ let temp = try container.decode(IncompleteUserObjectResponse.self); self = .Complete(temp) ; return}
catch{do { let temp = try container.decode(Bool.self) ; self = .Single(temp) ; return}
catch{ let temp = try container.decode(String.self) ; self = .Simple(temp) ; return}}
try self.init(from: decoder)
}
func getValue()-> Any{
switch self {
case let .Complete(x): return x
case let .Single(x): return x
case let .Simple(x): return x
}
}
}
extension IncompleteSignupResponse: Decodable {
init(from decoder: Decoder) throws {
do{
let container = try decoder.singleValueContainer()
let data = try container.decode([String: MixtureType].self)
stage = data["stage"]?.getValue() as! String
ekyc = data["ekyc"]?.getValue() as! Bool
last = data["last"]?.getValue() as! Bool
error = data["error"]?.getValue() as? String
userObject = data.filter{ !(["stage" ,"ekyc" , "last" , "error"].contains($0.key))}.values.map{$0.getValue() as! IncompleteUserObjectResponse}
}}
}
struct IncompleteUserObjectResponse: Decodable, CustomDebugStringConvertible {
var debugDescription: String {
return "{label: \(label) ; required: \(required) ; type : \(type) ; value : \(String(describing: value))}\n"
}
let label: String
let required: Bool
let type: String
let value: String?
}
struct Response: Decodable {
let result: String
let code: Int
let version: String
let time: Int
let id: String
let data: IncompleteSignupResponse
}
let json = """
{
"result": "success",
"code": 200,
"version": "1",
"time": 1,
"id": "NODATA",
"data": { "user_address_town": {
"label": "town",
"required": true,
"type": "string",
"value": ""
},
"user_address_county": {
"label": "county",
"required": true,
"type": "string"
},
"user_address_line_1": {
"label": "address 1",
"required": true,
"type": "string",
"value": ""
},
"user_address_line_2": {
"label": "address 2",
"required": false,
"type": "string",
"value": ""
},
"user_address_line_3": {
"label": "address 3",
"required": false,
"type": "string",
"value": ""
},
"user_address_postcode": {
"label": "postcode",
"required": false,
"type": "string",
"value": ""
},
"user_address_identifier": {
"label": "identifier",
"required": false,
"type": "string",
"value": ""
},
"stage": "stage1",
"last": true,
"ekyc": true,
"email": {
"label": "email address",
"required": true,
"type": "email",
"value": "[email protected]"
},
"password": {
"label": "password",
"required": true,
"type": "string"
},
"user_title": {
"label": "title",
"required": true,
"type": "string",
"value": "Mrs"
},
"user_first_name": {
"label": "first name",
"required": true,
"type": "string",
"value": "jsns"
},
"user_last_name": {
"label": "last name",
"required": true,
"type": "string",
"value": "nsm"
},
"user_dob": {
"label": "user date of birth",
"type": "date",
"required": true,
"value": "2001-01-22"
},
"user_gender": {
"label": "gender",
"type": "string",
"required": false,
"value": "M"
},
"user_country": {
"label": "country",
"required": true,
"type": "integer",
"value": "1"
},
"user_telephone": {
"label": "telephone",
"required": false,
"type": "string",
"value": "946464646"
},
"user_name_on_card": {
"label": "card name",
"required": false,
"type": "string"
}
}
}
""".data(using: .utf8)
let obj = try JSONDecoder().decode(Response.self, from: json!)
print(obj.data)
{stage: stage1 ; last: true ; ekyc : true ; error : nil ; userObject:
[{label: title ; required: true ; type : string ; value : Optional("Mrs")}
, {label: address 2 ; required: false ; type : string ; value : Optional("")}
, {label: telephone ; required: false ; type : string ; value : Optional("946464646")}
, {label: password ; required: true ; type : string ; value : nil}
, {label: country ; required: true ; type : integer ; value : Optional("1")}
, {label: user date of birth ; required: true ; type : date ; value : Optional("2001-01-22")}
, {label: first name ; required: true ; type : string ; value : Optional("jsns")}
, {label: card name ; required: false ; type : string ; value : nil}
, {label: postcode ; required: false ; type : string ; value : Optional("")}
, {label: address 1 ; required: true ; type : string ; value : Optional("")}
, {label: county ; required: true ; type : string ; value : nil}
, {label: identifier ; required: false ; type : string ; value : Optional("")}
, {label: address 3 ; required: false ; type : string ; value : Optional("")}
, {label: gender ; required: false ; type : string ; value : Optional("M")}
, {label: town ; required: true ; type : string ; value : Optional("")}
, {label: email address ; required: true ; type : email ; value : Optional("[email protected]")}
, {label: last name ; required: true ; type : string ; value : Optional("nsm")}
]}