JSON 使用反斜杠编码
JSON encoding with backslashes
我正在使用 Alamofire 和 SwiftyJSOn 来解析 JSON 输出。它工作得很好,但是有些网站给 json 转义输出。我像下面这样使用 Alamofire
Alamofire.request(.POST, url, parameters: param, encoding: .JSON)
.responseJSON { (req, res, json, error) in
var json = JSON(json!)
网站给我 JSON 结果和转义字符串,所以 SwiftyJSON 无法解码它。下面如何转换
{
"d": "{\"UniqeView\":{\"ArrivalDate\":null,\"ArrivalUnitId\":null,\"DeliveryCityName\":null,\"DeliveryTownName\":null},\"ErrorMessage\":null,\"Message\":null,\"IsFound\":false,\"IsSuccess\":true}"
}
类似于
{
"d": {
"UniqeView": {
"ArrivalDate": null,
"ArrivalUnitId": null,
"DeliveryCityName": null,
"DeliveryTownName": null
},
"ErrorMessage": null,
"Message": null,
"IsFound": false,
"IsSuccess": true
}
}
我使用一些自定义函数来完成这项工作:
import Foundation
func unescapeString(string: String) -> String {
return string.stringByReplacingOccurrencesOfString("\"", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil)
}
希望对您有所帮助 ;)
很多人在区分他们得到的东西和他们的系统打印的东西时遇到了问题。因此,第一步是您需要查明您收到的到底是什么,以及这些转义字符是否只是您打印的产物。
如果这是您实际收到的内容,那么服务器已向您发送了一个包含单个键 "d" 和一个字符串的字典,并且该字符串包含序列化数据。在这种情况下,将字符串转换为 NSData 并将其推入 NSJSONSerialization,这会将其转换为您想要的字典。这是传输 JSON 数据的一种相当愚蠢的方式,但它确实发生了。
// This Dropbox url is a link to your JSON
// I'm using NSData because testing in Playground
if let data = NSData(contentsOfURL: NSURL(string: "https://www.dropbox.com/s/9ycsy0pq2iwgy0e/test.json?dl=1")!) {
var error: NSError?
var response: AnyObject? = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.allZeros, error: &error)
if let dict = response as? NSDictionary {
if let key = dict["d"] as? String {
let strData = key.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
var error: NSError?
var response: AnyObject? = NSJSONSerialization.JSONObjectWithData(strData!, options: NSJSONReadingOptions.allZeros, error: &error)
if let decoded = response as? NSDictionary {
println(decoded["IsSuccess"]!) // => 1
}
}
}
}
我猜你必须解码两次:包装对象及其内容。
@ericd 评论帮助我解决了这个问题。我接受了他对这个问题的回答。由于我正在使用 Alamofire 进行异步操作和 SwiftyJSON,所以我无法使用他的代码。这是使用 Alamofire 和 SwiftyJSON 的代码。
Alamofire.request(.POST, url, parameters: param, encoding: .JSON)
.responseJSON { (req, res, json, error) in
if(error != nil) {
NSLog("Error: \(error)")
failure(res, json, error)
}
else {
var jsond = JSON(json!)
var data = jsond["d"].stringValue.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
jsond = JSON(data: data!)
我花了太长时间试图找出同样的问题。这就是我解决它的方法。
我有一个网络管理员,当被调用时,returns 响应 [Any]?
我遍历每条记录,将其转换为 JSON,但在这种情况下无法识别固有的字典结构。
所以我提取了 rawString 然后使用解析。这确实识别字典。
从那里你应该可以像你想的那样使用它。在我的示例中,我将数据传递给数据模型 (MyApi),
networkManager .requestResource(withUrl: urlPath, andParams: params,
successHandler: { (response: [Any]?) in
if let rawResponse = response {
let mutableArray = NSMutableArray()
for item in rawResponse {
let jsonData = JSON(item)
guard let rawString = jsonData.rawString() else {
return
}
let parsedData = JSON.parse(rawString)
let typedResponse = MyApi(json: parsedData)
mutableArray.add(typedResponse)
}
let array = mutableArray.copy() as! [MyApi]
//do something with array
} else {
let error = NSError .init(domain: "MyApi", code: 100, userInfo: nil)
//log error
}
}, failureHandler: { (response: [Any]?) in
let error = NSError .init(domain: "MyApi", code: 101, userInfo: nil)
//log error
})
这是 Swift 4 的另一种方法 - 使用 Codable
这是我收到的json:
{
"error_code": 0,
"result": {
"responseData": "{\"emeter\":{\"get_realtime\":{\"voltage_mv\":237846,\"current_ma\":81,\"power_mw\":7428,\"total_wh\":1920,\"err_code\":0}}}"
}
}
带反斜杠的 JSON 部分等于:
{
"emeter": {
"get_realtime": {
"voltage_mv": 237846,
"current_ma": 81,
"power_mw": 7428,
"total_wh":19201,
"err_code":0
}
}
}
这是我使用的代码:
import Foundation
class RealtimeEnergy: Codable {
let errorCode: Int
let result: ResultRealtimeEnergy?
let msg: String?
enum CodingKeys: String, CodingKey {
case errorCode = "error_code"
case result, msg
}
init(errorCode: Int, result: ResultRealtimeEnergy?, msg: String?) {
self.errorCode = errorCode
self.result = result
self.msg = msg
}
}
class ResultRealtimeEnergy: Codable {
let responseData: String
var emeter: Emeter
enum CodingKeys: String, CodingKey {
case responseData
}
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
responseData = try container.decode(String.self, forKey: .responseData)
let dataString = try container.decode(String.self, forKey: .responseData)
emeter = try JSONDecoder().decode(Emeter.self, from: Data(dataString.utf8))
}
}
class Emeter: Codable {
let emeter: EmeterClass
init(emeter: EmeterClass) {
self.emeter = emeter
}
}
class EmeterClass: Codable {
let getRealtime: GetRealtime
enum CodingKeys: String, CodingKey {
case getRealtime = "get_realtime"
}
init(getRealtime: GetRealtime) {
self.getRealtime = getRealtime
}
}
class GetRealtime: Codable {
let voltageMv, currentMa, powerMw, totalWh: Int
let errCode: Int
enum CodingKeys: String, CodingKey {
case voltageMv = "voltage_mv"
case currentMa = "current_ma"
case powerMw = "power_mw"
case totalWh = "total_wh"
case errCode = "err_code"
}
init(voltageMv: Int, currentMa: Int, powerMw: Int, totalWh: Int, errCode: Int) {
self.voltageMv = voltageMv
self.currentMa = currentMa
self.powerMw = powerMw
self.totalWh = totalWh
self.errCode = errCode
}
}
这就是诀窍:
emeter = try JSONDecoder().decode(Emeter.self, from: Data(dataString.utf8))
我正在使用 Alamofire 和 SwiftyJSOn 来解析 JSON 输出。它工作得很好,但是有些网站给 json 转义输出。我像下面这样使用 Alamofire
Alamofire.request(.POST, url, parameters: param, encoding: .JSON)
.responseJSON { (req, res, json, error) in
var json = JSON(json!)
网站给我 JSON 结果和转义字符串,所以 SwiftyJSON 无法解码它。下面如何转换
{
"d": "{\"UniqeView\":{\"ArrivalDate\":null,\"ArrivalUnitId\":null,\"DeliveryCityName\":null,\"DeliveryTownName\":null},\"ErrorMessage\":null,\"Message\":null,\"IsFound\":false,\"IsSuccess\":true}"
}
类似于
{
"d": {
"UniqeView": {
"ArrivalDate": null,
"ArrivalUnitId": null,
"DeliveryCityName": null,
"DeliveryTownName": null
},
"ErrorMessage": null,
"Message": null,
"IsFound": false,
"IsSuccess": true
}
}
我使用一些自定义函数来完成这项工作:
import Foundation
func unescapeString(string: String) -> String {
return string.stringByReplacingOccurrencesOfString("\"", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil)
}
希望对您有所帮助 ;)
很多人在区分他们得到的东西和他们的系统打印的东西时遇到了问题。因此,第一步是您需要查明您收到的到底是什么,以及这些转义字符是否只是您打印的产物。
如果这是您实际收到的内容,那么服务器已向您发送了一个包含单个键 "d" 和一个字符串的字典,并且该字符串包含序列化数据。在这种情况下,将字符串转换为 NSData 并将其推入 NSJSONSerialization,这会将其转换为您想要的字典。这是传输 JSON 数据的一种相当愚蠢的方式,但它确实发生了。
// This Dropbox url is a link to your JSON
// I'm using NSData because testing in Playground
if let data = NSData(contentsOfURL: NSURL(string: "https://www.dropbox.com/s/9ycsy0pq2iwgy0e/test.json?dl=1")!) {
var error: NSError?
var response: AnyObject? = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.allZeros, error: &error)
if let dict = response as? NSDictionary {
if let key = dict["d"] as? String {
let strData = key.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
var error: NSError?
var response: AnyObject? = NSJSONSerialization.JSONObjectWithData(strData!, options: NSJSONReadingOptions.allZeros, error: &error)
if let decoded = response as? NSDictionary {
println(decoded["IsSuccess"]!) // => 1
}
}
}
}
我猜你必须解码两次:包装对象及其内容。
@ericd 评论帮助我解决了这个问题。我接受了他对这个问题的回答。由于我正在使用 Alamofire 进行异步操作和 SwiftyJSON,所以我无法使用他的代码。这是使用 Alamofire 和 SwiftyJSON 的代码。
Alamofire.request(.POST, url, parameters: param, encoding: .JSON)
.responseJSON { (req, res, json, error) in
if(error != nil) {
NSLog("Error: \(error)")
failure(res, json, error)
}
else {
var jsond = JSON(json!)
var data = jsond["d"].stringValue.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
jsond = JSON(data: data!)
我花了太长时间试图找出同样的问题。这就是我解决它的方法。
我有一个网络管理员,当被调用时,returns 响应 [Any]?
我遍历每条记录,将其转换为 JSON,但在这种情况下无法识别固有的字典结构。
所以我提取了 rawString 然后使用解析。这确实识别字典。
从那里你应该可以像你想的那样使用它。在我的示例中,我将数据传递给数据模型 (MyApi),
networkManager .requestResource(withUrl: urlPath, andParams: params,
successHandler: { (response: [Any]?) in
if let rawResponse = response {
let mutableArray = NSMutableArray()
for item in rawResponse {
let jsonData = JSON(item)
guard let rawString = jsonData.rawString() else {
return
}
let parsedData = JSON.parse(rawString)
let typedResponse = MyApi(json: parsedData)
mutableArray.add(typedResponse)
}
let array = mutableArray.copy() as! [MyApi]
//do something with array
} else {
let error = NSError .init(domain: "MyApi", code: 100, userInfo: nil)
//log error
}
}, failureHandler: { (response: [Any]?) in
let error = NSError .init(domain: "MyApi", code: 101, userInfo: nil)
//log error
})
这是 Swift 4 的另一种方法 - 使用 Codable
这是我收到的json:
{
"error_code": 0,
"result": {
"responseData": "{\"emeter\":{\"get_realtime\":{\"voltage_mv\":237846,\"current_ma\":81,\"power_mw\":7428,\"total_wh\":1920,\"err_code\":0}}}"
}
}
带反斜杠的 JSON 部分等于:
{
"emeter": {
"get_realtime": {
"voltage_mv": 237846,
"current_ma": 81,
"power_mw": 7428,
"total_wh":19201,
"err_code":0
}
}
}
这是我使用的代码:
import Foundation
class RealtimeEnergy: Codable {
let errorCode: Int
let result: ResultRealtimeEnergy?
let msg: String?
enum CodingKeys: String, CodingKey {
case errorCode = "error_code"
case result, msg
}
init(errorCode: Int, result: ResultRealtimeEnergy?, msg: String?) {
self.errorCode = errorCode
self.result = result
self.msg = msg
}
}
class ResultRealtimeEnergy: Codable {
let responseData: String
var emeter: Emeter
enum CodingKeys: String, CodingKey {
case responseData
}
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
responseData = try container.decode(String.self, forKey: .responseData)
let dataString = try container.decode(String.self, forKey: .responseData)
emeter = try JSONDecoder().decode(Emeter.self, from: Data(dataString.utf8))
}
}
class Emeter: Codable {
let emeter: EmeterClass
init(emeter: EmeterClass) {
self.emeter = emeter
}
}
class EmeterClass: Codable {
let getRealtime: GetRealtime
enum CodingKeys: String, CodingKey {
case getRealtime = "get_realtime"
}
init(getRealtime: GetRealtime) {
self.getRealtime = getRealtime
}
}
class GetRealtime: Codable {
let voltageMv, currentMa, powerMw, totalWh: Int
let errCode: Int
enum CodingKeys: String, CodingKey {
case voltageMv = "voltage_mv"
case currentMa = "current_ma"
case powerMw = "power_mw"
case totalWh = "total_wh"
case errCode = "err_code"
}
init(voltageMv: Int, currentMa: Int, powerMw: Int, totalWh: Int, errCode: Int) {
self.voltageMv = voltageMv
self.currentMa = currentMa
self.powerMw = powerMw
self.totalWh = totalWh
self.errCode = errCode
}
}
这就是诀窍:
emeter = try JSONDecoder().decode(Emeter.self, from: Data(dataString.utf8))