-1

can you tell me how to parse this kind of json using Сodable?

{
"-MV_nbUZXH0YxpkMtdDK": {
    "log": "Installing dependencies",
    "ts": "2021-03-12T09:39:51.373513016Z"
},
"-MV_nbUeK8yJbrTkyhku": {
    "log": "Python version set to 2.7",
    "ts": "2021-03-12T09:39:51.376706383Z"
},
"-MV_nbnKj7ooihytbFb_": {
    "log": "Downloading and installing node v10.24.0...",
    "ts": "2021-03-12T09:39:52.640846883Z"
},
"-MV_nbr6_lCOgmASvjIx": {
    "log": "Downloading https://nodejs.org/dist/v10.24.0/node-v10.24.0-linux-x64.tar.xz...",
    "ts": "2021-03-12T09:39:52.882689552Z"
},
"-MV_nbx-xDFgKY5gt7LW": {
    "log": "Computing checksum with sha256sum",
    "ts": "2021-03-12T09:39:53.257948857Z"
},
"-MV_nbyq7zFzPKlZoUUW": {
    "log": "Checksums matched!",
    "ts": "2021-03-12T09:39:53.370929002Z"
},
"-MV_ncWPSrcJTxwRO-9Y": {
    "log": "Now using node v10.24.0 (npm v6.14.11)",
    "ts": "2021-03-12T09:39:55.588474395Z"
},
"-MV_ncXt4WBTobLQWtsP": {
    "log": "Started restoring cached build plugins",
    "ts": "2021-03-12T09:39:55.684040489Z"
}

I cannot understand the pattern of these names) This is the build log received from Google, I would like to display them in the application.

2 Answers2

3
import Foundation
    
struct LogValue: Codable {
        let log, ts: String
}
    
typealias Logs = [String: LogValue]

let logs = try? JSONDecoder().decode(Logs, from: jsonData)
George
  • 328
  • 2
  • 8
0

I assume the keys (the random strings) are of no interest so this solution only returns the actual log records.

I have chosen to convert the timestamp into a Date using a custom DateFormatter but note that there is a drawback to this since the formatter only handle milliseconds so some precision is lost, see this question

struct LogRecord: Decodable {
    let log: String
    let timestamp: Date

    enum CodingKeys: String, CodingKey {
        case log
        case timestamp = "ts"
    }
}

Here is how the decoder is configured to handle the date conversion

let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"

let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .formatted(dateFormatter)

And here is the decoding where I only keep the values from the decoded dictionary

do {
    let logs = try decoder.decode([String: LogRecord].self, from: data).values
    for log in logs.sorted(by: { $0.timestamp < $1.timestamp }) {
        print("\(dateFormatter.string(from: log.timestamp)): \(log.log)")
    }
} catch {
    print(error)
}

Output

2021-03-12T10:39:51.373+0100: Installing dependencies
2021-03-12T10:39:51.376+0100: Python version set to 2.7
2021-03-12T10:39:52.640+0100: Downloading and installing node v10.24.0...
2021-03-12T10:39:52.882+0100: Downloading nodejs.org/dist/v10.24.0/node-v10.24.0-linux-x64.tar.xz...
2021-03-12T10:39:53.257+0100: Computing checksum with sha256sum
2021-03-12T10:39:53.370+0100: Checksums matched!
2021-03-12T10:39:55.588+0100: Now using node v10.24.0 (npm v6.14.11)
2021-03-12T10:39:55.684+0100: Started restoring cached build plugins

Joakim Danielson
  • 43,251
  • 5
  • 22
  • 52