struct User: Codable { var name: String var email: String var id: String var metadata: [String: MetadataType] enum CodingKeys: String, CodingKey { case name, email, id, metadata } } enum MetadataType: Codable { case double(Double) case string(String) init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() do { self = try .double(container.decode(Double.self)) } catch DecodingError.typeMismatch { do { self = try .string(container.decode(String.self)) } catch DecodingError.typeMismatch { throw DecodingError.typeMismatch(MetadataType.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Encoded payload not of an expected type")) } } } func encode(to encoder: Encoder) throws { var container = encoder.singleValueContainer() switch self { case .double(let double): try container.encode(double) case .string(let string): try container.encode(string) } } } import Foundation let decoder = JSONDecoder() let userJson = """ { "id": "4yq6txdpfadhbaqnwp3", "email": "john.doe@example.com", "name":"John Doe", "metadata": { "link_id": "linked-id", "buy_count": 4 } } """.data(using: .utf8)! let user = try! decoder.decode(User.self, from: userJson) print(user) let encoder = PropertyListEncoder() encoder.outputFormat = .xml let plist = try! encoder.encode(user) print(String(data: plist, encoding: .utf8)!)