html - 解码包含 HTML 的 json

标签 html json swift nsjsonserialization decodable

我从示例下面的代码 中提到的 SO 套接字获取了一个真实的响应。我需要将它解码为某种类型的对象。所以我定义了两个可解码结构:SocketResponseQuestion。 然后我尝试使用默认的 JSONDecoder 对其进行解码。

但由于 data 键包含大量无效的 json 格式,它无法正常工作并抛出此错误:

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.})))

我也尝试了 JSONSerialization,但它无法解码并抛出类似的错误。

那么我如何在不丢失 HTML 格式的情况下将这种类型的字符串解码为类型对象?(因为响应可能不同,我们唯一可以依赖的是 数据 值始终是包含一些 HTML 代码的 String。)

- Playground :

这是您可以使用的简单复制代码:

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 &#39;ios&#39;\" rel=\"tag\">ios</a> <a href=\"/questions/tagged/swift\" class=\"post-tag\" title=\"show questions tagged &#39;swift&#39;\" rel=\"tag\">swift</a> <a href=\"/questions/tagged/ipad\" class=\"post-tag\" title=\"show questions tagged &#39;ipad&#39;\" rel=\"tag\">ipad</a> <a href=\"/questions/tagged/ipados\" class=\"post-tag\" title=\"show questions tagged &#39;ipados&#39;\" 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)
}

最佳答案

已编辑

我理解你。在解码数据之前执行响应的简单适配:

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 fileURL = Bundle.main.url(forResource: "SO", withExtension: "txt")
var responseStr = try String(contentsOf: fileURL!, encoding: String.Encoding.utf8)

responseStr = (responseStr as NSString).replacingOccurrences(of: "\r\n", with: "")
responseStr = (responseStr as NSString).replacingOccurrences(of: "\n", with: "")
responseStr = (responseStr as NSString).replacingOccurrences(of: "\"{\"", with: "{\"")
responseStr = (responseStr as NSString).replacingOccurrences(of: "}\"}", with: "}}")


let responseData = responseStr.data(using: .utf8)!

do {
    let json = try JSONDecoder().decode(SocketResponse<Question>.self, from: responseData)
    print("Success", json)
} catch {
    print(error)
}

P.S. 请注意构造 \" 被转换为 "。即使在三重括号中,您也需要使用 \\"

关于html - 解码包含 HTML 的 json,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57461965/

相关文章:

javascript href悬停取消选择

javascript - 小费计算器javascript

python - 使用 python 从 JSON 文件中解析数据并检查它

java - Spring Boot 使用 REST 变量绑定(bind)

ios - 使用 Swift 4 和 UIView 的奇怪动画行为

ios - 即使重复,如何获取特定子字符串的范围

html - 响应式 html 电子邮件 : outlook

javascript - 选择框选项是可见还是隐藏?

Javascript 无法正确解析 JSON 中的大量数字

ios - 如何将collectionview单元设置为从索引 '1'而不是 '0'开始 - Swift