Zack Cheang Weng Seong
Zack Cheang Weng Seong

Reputation: 338

Swift Json Decodable data structure, varying values in single array

what im working with

"meta_data": [
        {
            "id": 4116,
            "key": "_wcf_frm_created",
            "value": ""
        },
        {
            "id": 4117,
            "key": "_wcf_custom_degin_checkbox",
            "value": ""
        },
        {
            "id": 4118,
            "key": "_wcf_frm_data",
            "value": {
                "1": {
                    "1": "",
                    "2": "",
                    "3": "chk_box"
                }
            }
        },
        {
            "id": 4142,
            "key": "_vendor_select",
            "value": "6484"
        },
        {
            "id": 4143,
            "key": "_vendor_percentage",
            "value": "100"
        },
        {
            "id": 4144,
            "key": "_vendor_pro_cat",
            "value": "Sushi"
        },
        {
            "id": 4156,
            "key": "slide_template",
            "value": "default"
        }
    ],
    "_links": {
        "self": [
            {
                "href": "https://xxxxxx.net/wp-json/wc/v3/products/6489"
            }
        ],
        "collection": [
            {
                "href": "https://xxxxxx.net/wp-json/wc/v3/products"
            }
        ]
    }

what I currently have

struct woocomerceProduct : Decodable, Encodable
{
    var meta_data : [Meta_data?]
    var _links : [_Links?]


}

    struct Meta_data : Decodable, Encodable
{
    var id : Int?
    var key : String?
    var value : String?
}
   struct One : Decodable, Encodable
{
        var one : String?
        var two : String?
        var three : String?
}

struct _Links : Decodable, Encodable
{
    var SELF : [String?]
    var collectio : [String?]
}

ok so here are the questions. 1. id 4118. value goes from String to obj, how do I code this part? 2. it also uses a variable string "1","2"... I can't use integer as variable, so I spelled it out? should be ok. 3. The value here is self, I can't use a variable self cause it will think it's a self property. so I just capitalized this.

I looked at this, which i believe is something similar to what i need to do, but since this is between an object and an string, im not sure what i need to code here. Swift structures: handling multiple types for a single property

Upvotes: 0

Views: 369

Answers (2)

Vasucd
Vasucd

Reputation: 357

Try this link for conversion of your json into Codable model link

    import Foundation

// MARK: - Welcome
struct Welcome: Codable {
    let metaData: [MetaDatum]
    let links: Links

    enum CodingKeys: String, CodingKey {
        case metaData = "meta_data"
        case links = "_links"
    }
}

// MARK: - Links
struct Links: Codable {
    let linksSelf, collection: [Collection]

    enum CodingKeys: String, CodingKey {
        case linksSelf = "self"
        case collection
    }
}

// MARK: - Collection
struct Collection: Codable {
    let href: String
}

// MARK: - MetaDatum
struct MetaDatum: Codable {
    let id: Int
    let key: String
    let value: ValueUnion
}

enum ValueUnion: Codable {
    case string(String)
    case valueClass(ValueClass)

    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        if let x = try? container.decode(String.self) {
            self = .string(x)
            return
        }
        if let x = try? container.decode(ValueClass.self) {
            self = .valueClass(x)
            return
        }
        throw DecodingError.typeMismatch(ValueUnion.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for ValueUnion"))
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        switch self {
        case .string(let x):
            try container.encode(x)
        case .valueClass(let x):
            try container.encode(x)
        }
    }
}

// MARK: - ValueClass
struct ValueClass: Codable {
    let the1: [String: String]

    enum CodingKeys: String, CodingKey {
        case the1 = "1"
    }
}

Upvotes: 4

vadian
vadian

Reputation: 285260

Too many unnecessary optionals, too many unnecessary underscore characters.

  1. To decode two different types an enum with associated types is reasonable.
  2. The code decodes a dictionary [String:[String:String]].
  3. To map inappropriate keys provide CodingKeys.

struct WoocomerceProduct : Decodable {
    let metaData : [Meta]
    let links : Links

    private enum CodingKeys : String, CodingKey { case metaData  = "meta_data", links = "_links" }
}

struct Meta : Decodable {
    let id : Int
    let key : String
    let value : StringOrDictionary
}

struct Links : Decodable {
    let myself : [URLType]
    let collection : [URLType]

    private enum CodingKeys : String, CodingKey { case myself  = "self", collection }
}

struct URLType : Decodable {
    let href : URL
}


enum StringOrDictionary : Decodable {
    case string(String), dictionary([String:[String:String]])

    init(from decoder : Decoder) throws
    {
        let container = try decoder.singleValueContainer()
        do {
            let stringData = try container.decode(String.self)
            self = .string(stringData)
        } catch DecodingError.typeMismatch {
            let dictionaryData = try container.decode([String:[String:String]].self)
            self = .dictionary(dictionaryData)
        }
    }
}

Upvotes: 0

Related Questions