我想知道在Swift 4中解析以下类型的json响应的最佳方法。响应是双重编码的-
\“ [{{\\” value \\“:\\”国际大学\\\\“ MITSO \\\\” \\“,\\” id \\“:\\” a1v24000000uOrPAAU \\“ ,\\“ addlFields \\”:[\\“ Mi?narodny Universitet \\\\” MITSO \\\\“ \\”]}] \“
以下是NSData格式的数据-
(字符串)$ R0 =“数据:可选(146个字节)作为NSData的:<225b7b5c 2276616c 75655c22 3a5c2249 6e746572 6e617469 6f6e616c 20556e69 76657273 69747920 5c5c5c22 4d495453 4f5c5c5c 225c222c 5c226964 5c223a5c 22613176 32343030 30303030 754f7250 4141555c 222c5c22 6164646c 4669656c 64735c22 3a5b5c22 4d693f6e 61726f64 6e792055 6e697665 72736974 6574205c 5c5c224d 4954534f 5c5c5c22 5c225d7d 5d22>“
如您所见,键“值”的值具有一个内部双引号(“)。 JSONSerialization 将此视为无效的Json。 任何帮助将不胜感激。
答案 0 :(得分:2)
以String表示的数据内容如下:
"[{\"value\":\"International University \\\"MITSO\\\"\",\"id\":\"a1v24000000uOrPAAU\",\"addlFields\":[\"Mi?narodny Universitet \\\"MITSO\\\"\"]}]"
看到实际内容而没有多余的双引号和反斜杠,以将String显示为String-literal,就好像在String中嵌入了一些有效的JSON。
当服务器端代码对数据进行双重编码时,可能会发生这种情况。您最好告诉服务器端工程师解决此问题,但是如果遇到困难或需要很长时间,则可以对其进行两次解码。
测试代码:
import Foundation
let dataStr = "<225b7b5c 2276616c 75655c22 3a5c2249 6e746572 6e617469 6f6e616c 20556e69 76657273 69747920 5c5c5c22 4d495453 4f5c5c5c 225c222c 5c226964 5c223a5c 22613176 32343030 30303030 754f7250 4141555c 222c5c22 6164646c 4669656c 64735c22 3a5b5c22 4d693f6e 61726f64 6e792055 6e697665 72736974 6574205c 5c5c224d 4954534f 5c5c5c22 5c225d7d 5d22>".dropFirst().dropLast().replacingOccurrences(of: " ", with: "")
let byteArr = stride(from: 0, to: dataStr.count, by: 2).map{(index: Int)->UInt8 in
let start = dataStr.index(dataStr.startIndex, offsetBy: index)
let end = dataStr.index(start, offsetBy: 2)
return UInt8(dataStr[start..<end], radix: 16)!
}
let responseData = Data(bytes: byteArr)
print(responseData as NSData)
在此处检查print
语句的输出是否与示例响应完全相同。 (如果要使用实际数据而不是示例响应来测试以下代码,请仅使用let responseData = result as! Data
而不是上面的行。)
因此,您只需使用两次JSONSerialization
:
block: do {
let firstDecoded = try JSONSerialization.jsonObject(with: responseData, options: .allowFragments) as! String
let firstDecodedData = firstDecoded.data(using: .utf8)!
let secondDecoded = try JSONSerialization.jsonObject(with: firstDecodedData)
//Code below is an example of using decoded result.
guard let resultArray = secondDecoded as? [[String: Any]] else {
print("result is not an Array of Dictionary")
break block
}
print(resultArray)
if
let addlFields = resultArray[0]["addlFields"] as? [String],
let firstAddl = addlFields.first
{
print(firstAddl)
}
} catch {
print(error)
}
输出:(为print(responseData as NSData)
省略了一些输出。)
[["id": a1v24000000uOrPAAU, "value": International University "MITSO", "addlFields": <__NSSingleObjectArrayI 0x100e40c80>( Mi?narodny Universitet "MITSO" ) ]] Mi?narodny Universitet "MITSO"
(您可能会发现<__NSSingleObjectArrayI 0x100e40c80>
之类的某些部分很奇怪,但这只是生成默认描述的问题,您可以将元素作为数组访问。)
无论如何,请尝试看看上面的代码为您带来的好处。
答案 1 :(得分:0)
@OOPer感谢您的解决方案。感谢您抽出宝贵的时间。 解决方案按预期工作。在此处粘贴代码可能会对其他人有所帮助。
这就是我的状况-
func getData(text:String, callback:@escaping (_ result: Array<somedata>?,_ error:Error?) -> Void) {
let params = ["search":text]
getDataSomeAPI(url: "http:\\xyz.com\fdf", params: params) { (result, error) in
if error == nil {
do {
//Response is double encoded
if let firstDecoded = try JSONSerialization.jsonObject(with: result as! Data, options: .allowFragments) as? String
{
let firstDecodedData = firstDecoded.data(using: .utf8)!
if let secondDecoded = try JSONSerialization.jsonObject(with: firstDecodedData) as? NSArray {
var array = [somedata]()
for obj in secondDecoded {
Mapper<somedata>().map(JSONObject: obj).then { mappedObj in
array.append(mappedObj)
}
}
callback(array,nil)
}
}
}
catch {
//Handle unexpected data format
let error = NSError(domain: "",
code: 0,
userInfo: nil)
let sErr = Error(err: error)
callback(nil, sErr)
}
} else {
callback(nil, error)
}
}
}