I have a real response fetched from SO's socket mentioned in the sample code below. I need to decode it to some type of object. So I defined two decodable structs: SocketResponse
and Question
.
Then I tried to decode it with a default JSONDecoder
.
But since the data
key contains massive invalid json formatting, it is not going to work and throwing me this error:
dataCorrupted(Swift.DecodingError.Context(codingPath: [], debugDescription: "The given data was not valid JSON.", underlyingError: Optional(Error Domain=NSCocoaErrorDomain Code=3840 "No string key for value in object around character 2." UserInfo={NSDebugDescription=No string key for value in object around character 2.})))
I tried the JSONSerialization
as well but it couldn't decode it and throwing a similar error.
So how can I decode this type of string into the the typed object without loosing the HTML formatting? (Since responses may be different and the only thing we can relay on is the data
value is always a String
containing some HTML code.)
- The Playground:
Here is the simple reproducing code you can play with:
struct SocketResponse<T: Decodable>: Decodable {
let action: String
let data: T
}
struct Question: Decodable {
let id: String
let body: String
let tags: [String]
let siteid: Int
let noAnswers: Bool
let hasBounty: Bool
let fetch: Bool
}
let responseData = """
{
"action": "1-questions-newest-tag-ios",
"data": "{"id":"57238686","body":"<div class=\"question-summary\" id=\"question-summary-57238686\">\r\n <div class=\"statscontainer\">\r\n <div class=\"stats\">\r\n <div class=\"vote\">\r\n <div class=\"votes\">\r\n <span class=\"vote-count-post \"><strong>0</strong></span>\r\n <div class=\"viewcount\">votes</div>\r\n </div>\r\n </div>\r\n <div class=\"status unanswered\">\r\n <strong>0</strong>answers\r\n </div>\r\n </div>\r\n <div class=\"views \" title=\"1 view\">\r\n 1 view\r\n</div>\r\n </div>\r\n <div class=\"summary\">\r\n <h3><a href=\"/questions/57238686/how-to-realize-a-movable-controller-in-ipados-like-mail-app-in-ipad\" class=\"question-hyperlink\">How to realize a movable controller in iPadOS, like mail APP in iPad</a></h3>\r\n <div class=\"excerpt\">\r\n Mail App in iPad, when we create a new mail, the controller will be presented. But in iPadOS system, this controller can be moved, and if move it to the left side or right side, it can become a ...\r\n </div>\r\n <div class=\"tags t-ios t-swift t-ipad t-ipados\">\r\n <a href=\"/questions/tagged/ios\" class=\"post-tag\" title=\"show questions tagged 'ios'\" rel=\"tag\">ios</a> <a href=\"/questions/tagged/swift\" class=\"post-tag\" title=\"show questions tagged 'swift'\" rel=\"tag\">swift</a> <a href=\"/questions/tagged/ipad\" class=\"post-tag\" title=\"show questions tagged 'ipad'\" rel=\"tag\">ipad</a> <a href=\"/questions/tagged/ipados\" class=\"post-tag\" title=\"show questions tagged 'ipados'\" rel=\"tag\">ipados</a> \r\n </div>\r\n <div class=\"started fr\">\r\n <div class=\"user-info \">\r\n <div class=\"user-action-time\">\r\n <a href=\"/questions/57238686/how-to-realize-a-movable-controller-in-ipados-like-mail-app-in-ipad\" class=\"started-link\">asked <span title=\"2019-07-28 07:08:46Z\" class=\"relativetime\">just now</span></a>\r\n </div>\r\n <div class=\"user-gravatar32\">\r\n <a href=\"/users/11847413/peipei\"><div class=\"gravatar-wrapper-32\"><img src=\"https://lh6.googleusercontent.com/-RJzULVcP1iM/AAAAAAAAAAI/AAAAAAAAAAA/ACHi3reW_khZzpeiqEPv6Cww36Wohd_oUg/photo.jpg?sz=32\" alt=\"\" width=\"32\" height=\"32\"></div></a>\r\n </div>\r\n <div class=\"user-details\">\r\n <a href=\"/users/11847413/peipei\">peipei</a>\r\n <div class=\"-flair\">\r\n <span class=\"reputation-score\" title=\"reputation score \" dir=\"ltr\">1</span><span title=\"1 bronze badge\" aria-hidden=\"true\"><span class=\"badge3\"></span><span class=\"badgecount\">1</span></span><span class=\"v-visible-sr\">1 bronze badge</span>\r\n </div>\r\n </div>\r\n</div>\r\n </div>\r\n </div>\r\n</div>","tags":["ios","swift","ipad","ipados"],"siteid":1,"noAnswers":true,"hasBounty":false,"fetch":false}"
}
""".data(using: .utf8)!
do {
let json = try JSONDecoder().decode(SocketResponse<Question>.self, from: responseData)
print(json)
} catch {
print(error)
}