难以使用Codeable从JSON中提取数据

问题描述 投票:2回答:2

我试图从下面的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))

我不太清楚为什么关键数据无法找到,因为它没有嵌套在任何东西里面。

有什么我错过的吗?此外,我的布局是否被认为是良好的做法,还是有可以改进的事情。

json swift xcode serialization decoding
2个回答
2
投票

使用本网站: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"
}

0
投票

希望这是你的期望。 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")}
        ]}
© www.soinside.com 2019 - 2024. All rights reserved.