I m using Alamofire and SwiftyJSOn to parse JSON output. It works very well however some sites give json with escaped output. I use Alamofire like below
Alamofire.request(.POST, url, parameters: param, encoding: .JSON)
.responseJSON { (req, res, json, error) in
var json = JSON(json!)
Site gives me JSON result with escaped string so SwiftyJSON can't decode it. How can I convert below
{
"d": "{\"UniqeView\":{\"ArrivalDate\":null,\"ArrivalUnitId\":null,\"DeliveryCityName\":null,\"DeliveryTownName\":null},\"ErrorMessage\":null,\"Message\":null,\"IsFound\":false,\"IsSuccess\":true}"
}
to something like
{
"d": {
"UniqeView": {
"ArrivalDate": null,
"ArrivalUnitId": null,
"DeliveryCityName": null,
"DeliveryTownName": null
},
"ErrorMessage": null,
"Message": null,
"IsFound": false,
"IsSuccess": true
}
}
The backslash ( \ ) is a special character in both PHP and JSON. Both languages use it to escape special characters in strings and in order to represent a backslash correctly in strings you have to prepend another backslash to it, both in PHP and JSON.
Those backslashes are escape characters. They are escaping the special characters inside of the string associated with JSON response. You have to use JSON. parse to parse that JSON string into a JSON object. For example, below url will have backward slashes if it's a raw JSON string.
The stripslashes() function removes backslashes added by the addslashes() function. Tip: This function can be used to clean up data retrieved from a database or from an HTML form.
Here is another approach for Swift 4 - Using Codable
This was the json that I received:
{
"error_code": 0,
"result": {
"responseData": "{\"emeter\":{\"get_realtime\":{\"voltage_mv\":237846,\"current_ma\":81,\"power_mw\":7428,\"total_wh\":1920,\"err_code\":0}}}"
}
}
The JSON part with backslashes is equal to this:
{
"emeter": {
"get_realtime": {
"voltage_mv": 237846,
"current_ma": 81,
"power_mw": 7428,
"total_wh":19201,
"err_code":0
}
}
}
And this was the code that I used:
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
}
}
And this is the trick:
emeter = try JSONDecoder().decode(Emeter.self, from: Data(dataString.utf8))
// 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
}
}
}
}
I guess you have to decode twice: the wrapping object, and its content.
@ericd comments helped me to solve the issue. I accepted his answer for this question. Since I am using Alamofire for asynchronous operation, and SwiftyJSON, I couldn't use his code. Here is the code with Alamofire and 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!)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With