简体   繁体   中英

Parsing Nested JSON in Swift 4 with codable

I am trying to parse JSON using decodable in Swift 4

The JSON is as below:

{
  "_id": {
    "$oid": "5afceaa0c1743f37b4ee1cf8"
  },
  "Con_id": "xxx",
  "S_id": "xxx",
  "I_Image": [
    {
      "$binary": {
        "base64": "",
        "subType": "00"
      }
    }
  ],
  "T_Agreements": [
    {
      "Ag_Type": "xxx",
      "Ap_Type": "xxx",
      "Header": {
        "Date": {
          "$numberInt": "0"
        },
        "Company": "xxx",
        "O_Code": "xxx",
        "Lo": "xxx",
        "Completed": true
      },
      "T_Particular": {
        "C_Name": "NA",
        "C_Address": "NA",
        "C_Landline": "NA",
        "ROC": "NA",
        "T_Name": "xxx",
        "Gender": "M",
        "NR": "xxx",
        "Dob": "22/08/1977",
        "C_No": "xxx",
        "T_Address": "xxx",
        "S_No": "xxx",
        "Sign": "NA",
        "Proposed": "xxx",
        "Completed": true
      },
      "D_Agreement": {
        "C_Period": {
          "P_Yr": {
            "$numberInt": "2"
          },
          "P_Mth": {
            "$numberInt": "0"
          },
          "From": {
            "$numberInt": "0"
          },
          "To": {
            "$numberInt": "0"
          }
        },
        "First_Term": {
          "R_A": {
            "$numberInt": "800000"
          },
          "From_Date": {
            "$numberInt": "0"
          },
          "To_Date": {
            "$numberInt": "0"
          }
        },
        "Second_Term": {
          "R_A": "0",
          "From_Date": {
            "$numberInt": "0"
          },
          "To_Date": {
            "$numberInt": "0"
          }
        },
        "S_D": {
          "$numberInt": "800"
        },
        "S_D_M": {
          "$numberInt": "0"
        },
        "C_F": {
          "$numberInt": "0"
        },
        "D_C_F": {
          "$numberInt": "0"
        },
        "Maintenance_Fee": {
          "$numberInt": "0"
        },
        "Others": {
          "Description": "NA",
          "O_F": {
            "$numberInt": "0"
          }
        },
        "D_C": "NA",
        "Completed": true
      },
      "T_S": {
        "$binary": {
          "base64": "",
          "subType": "00"
        }
      },
      "L_Rep": {
        "Name": "xxx",
        "Rep_Sig": {
          "$binary": {
            "base64": "",
            "subType": "00"
          }
        }
      },
      "Remarks": ""
    }
  ],
  "Supp": {
    "B_N": "xxx",
    "B_O_H": "12",
    "C_B_O": "xxx",
    "A_S": "Nil",
    "F_T_Description": "xxx",
    "C_T": "xxx",
    "Completed": true
  },
  "FAdjustment": [
    {
      "Date": {
        "$numberInt": "0"
      },
      "R_Increased": true,
      "Pro_R": {
        "$numberInt": "20066660"
      },
      "A_P_From": {
        "$numberInt": "0"
      },
      "A_P_To": {
        "$numberInt": "0"
      },
      "E_Date": {
        "$numberInt": "0"
      },
      "A_Reason": "xxx",
      "Req": {
        "Name": "xxx",
        "Des": "xxx",
        "Sig": {
          "$binary": {
            "base64": "",
            "subType": "00"
          }
        },
        "Date": {
          "$numberInt": "0"
        }
      },
      "A1": {
        "Name": "xxx",
        "Des": "xxx",
        "Sig": {
          "$binary": {
            "base64": "",
            "subType": "00"
          }
        },
        "Date": {
          "$numberInt": "0"
        }
      },
      "A2": {
        "Name": "xxx",
        "Designation": "xxx",
        "Sig": {
          "$binary": {
            "base64": "",
            "subType": "00"
          }
        },
        "Date": {
          "$numberInt": "0"
        }
      }
    }
  ],
  "Status": "xxx",
  "Re": {
    "Out": "0"
  },
  "Termination": {
    "Terminated": false,
    "Reason": "NA"
  }
}

I am able to easily parse things such as conID with my Struct:

struct Welcome: Codable {
    let id: ID?
    let conID, sID: String?
    let iImage: [IImage]?
    let tAgreements: [TAgreement]?
    let supp: Supp?
    let fAdjustment: [FAdjustment]?
    let status: String?
    let re: Re?
    let termination: Termination?

    enum CodingKeys: String, CodingKey {
        case id = "_id"
        case conID = "Con_id"
        case sID = "S_id"
        case iImage = "I_Image"
        case tAgreements = "T_Agreements"
        case supp = "Supp"
        case fAdjustment = "FAdjustment"
        case status = "Status"
        case re = "Re"
        case termination = "Termination"
    }
}

struct FAdjustment: Codable {
    let date: APFrom?
    let rIncreased: Bool?
    let proR, aPFrom, aPTo, eDate: APFrom?
    let aReason: String?
    let req, a1, a2: A1?

    enum CodingKeys: String, CodingKey {
        case date = "Date"
        case rIncreased = "R_Increased"
        case proR = "Pro_R"
        case aPFrom = "A_P_From"
        case aPTo = "A_P_To"
        case eDate = "E_Date"
        case aReason = "A_Reason"
        case req = "Req"
        case a1 = "A1"
        case a2 = "A2"
    }
}

struct A1: Codable {
    let name, des: String?
    let sig: IImage?
    let date: APFrom?
    let designation: String?

    enum CodingKeys: String, CodingKey {
        case name = "Name"
        case des = "Des"
        case sig = "Sig"
        case date = "Date"
        case designation = "Designation"
    }
}

struct APFrom: Codable {
    let numberInt: String?

    enum CodingKeys: String, CodingKey {
        case numberInt = "$numberInt"
    }
}

struct IImage: Codable {
    let binary: Binary?

    enum CodingKeys: String, CodingKey {
        case binary = "$binary"
    }
}

struct Binary: Codable {
    let base64, subType: String?
}

struct ID: Codable {
    let oid: String?

    enum CodingKeys: String, CodingKey {
        case oid = "$oid"
    }
}

struct Re: Codable {
    let out: String?

    enum CodingKeys: String, CodingKey {
        case out = "Out"
    }
}

struct Supp: Codable {
    let bN, bOH, cBO, aS: String?
    let fTDescription, cT: String?
    let completed: Bool?

    enum CodingKeys: String, CodingKey {
        case bN = "B_N"
        case bOH = "B_O_H"
        case cBO = "C_B_O"
        case aS = "A_S"
        case fTDescription = "F_T_Description"
        case cT = "C_T"
        case completed = "Completed"
    }
}

struct TAgreement: Codable {
    let agType, apType: String?
    let header: Header?
    let tParticular: TParticular?
    let dAgreement: DAgreement?
    let tS: IImage?
    let lRep: LRep?
    let remarks: String?

    enum CodingKeys: String, CodingKey {
        case agType = "Ag_Type"
        case apType = "Ap_Type"
        case header = "Header"
        case tParticular = "T_Particular"
        case dAgreement = "D_Agreement"
        case tS = "T_S"
        case lRep = "L_Rep"
        case remarks = "Remarks"
    }
}

struct DAgreement: Codable {
    let cPeriod: CPeriod?
    let firstTerm: FirstTerm?
    let secondTerm: SecondTerm?
    let sD, sDM, cF, dCF: APFrom?
    let maintenanceFee: APFrom?
    let others: Others?
    let dC: String?
    let completed: Bool?

    enum CodingKeys: String, CodingKey {
        case cPeriod = "C_Period"
        case firstTerm = "First_Term"
        case secondTerm = "Second_Term"
        case sD = "S_D"
        case sDM = "S_D_M"
        case cF = "C_F"
        case dCF = "D_C_F"
        case maintenanceFee = "Maintenance_Fee"
        case others = "Others"
        case dC = "D_C"
        case completed = "Completed"
    }
}

struct CPeriod: Codable {
    let pYr, pMth, from, to: APFrom?

    enum CodingKeys: String, CodingKey {
        case pYr = "P_Yr"
        case pMth = "P_Mth"
        case from = "From"
        case to = "To"
    }
}

struct FirstTerm: Codable {
    let rA, fromDate, toDate: APFrom?

    enum CodingKeys: String, CodingKey {
        case rA = "R_A"
        case fromDate = "From_Date"
        case toDate = "To_Date"
    }
}

struct Others: Codable {
    let description: String?
    let oF: APFrom?

    enum CodingKeys: String, CodingKey {
        case description = "Description"
        case oF = "O_F"
    }
}

struct SecondTerm: Codable {
    let rA: String?
    let fromDate, toDate: APFrom?

    enum CodingKeys: String, CodingKey {
        case rA = "R_A"
        case fromDate = "From_Date"
        case toDate = "To_Date"
    }
}

struct Header: Codable {
    let date: APFrom?
    let company, oCode, lo: String?
    let completed: Bool?

    enum CodingKeys: String, CodingKey {
        case date = "Date"
        case company = "Company"
        case oCode = "O_Code"
        case lo = "Lo"
        case completed = "Completed"
    }
}

struct LRep: Codable {
    let name: String?
    let repSig: IImage?

    enum CodingKeys: String, CodingKey {
        case name = "Name"
        case repSig = "Rep_Sig"
    }
}

struct TParticular: Codable {
    let cName, cAddress, cLandline, roc: String?
    let tName, gender, nr, dob: String?
    let cNo, tAddress, sNo, sign: String?
    let proposed: String?
    let completed: Bool?

    enum CodingKeys: String, CodingKey {
        case cName = "C_Name"
        case cAddress = "C_Address"
        case cLandline = "C_Landline"
        case roc = "ROC"
        case tName = "T_Name"
        case gender = "Gender"
        case nr = "NR"
        case dob = "Dob"
        case cNo = "C_No"
        case tAddress = "T_Address"
        case sNo = "S_No"
        case sign = "Sign"
        case proposed = "Proposed"
        case completed = "Completed"
    }
}

struct Termination: Codable {
    let terminated: Bool?
    let reason: String?

    enum CodingKeys: String, CodingKey {
        case terminated = "Terminated"
        case reason = "Reason"
    }
}

I'm struggling with getting the nested stuff out.

How do I get things from T_Agreements like Ag_Type out individually and everything from T_Particular out individually?

I have tried

  let jsonUrlString = "URL REMOVED REFER TO JSON ABOVE"
        guard let url = URL(string: jsonUrlString) else { return }
        URLSession.shared.dataTask(with: url) { (data, response, err) in
            guard let data = data else { return }
            do {
                let decoder = JSONDecoder()
                let welcome = try! decoder.decode(Welcome.self, from: data)
                let tagree = try! decoder.decode(TAgreement.self, from: data)

                print(tagree) // This returns all the header inside T_Agreements but the values are all nil
                print(tagree.tParticular.cAddress) // This returns nil too

            }

            }.resume()

Much thanks and appreciation

The line let welcome = try! decoder.decode(Welcome.self, from: data) let welcome = try! decoder.decode(Welcome.self, from: data) loads the json data into a Welcome data model, which matches the structure of the json. Trying to reload the same json data into other data models (as you do in the next line) won't work. You need to extract the data directly from the populated data models you've created.

To get TAgreements, you just grab that data from the welcome model:

let tagreements = welcome.tAgreements

To get Ag_Type out, you get the populated data from the first element of tagreements:

let agType = tagreements[0].agType

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM