0

I hava a json file:

jsonpElixo({  
"response":{  
  "parks":[  
     {  
        "Park":{  
           "id":"2",
           "name":"PARQUE VILLA-LOBOS",
           "type":"Urbano"
        },
        "Address":{  
           "lat":"-23.547245206920508",
           "long":"-46.71627699999999",
           "cep":null,
           "street":"Avenida Professor Fonseca Rodrigues",
           "number":"1025",
           "neighborhood":"Alto Pinheiros",
           "city":"S\u00e3o Paulo",
           "state":"SP",
           "id":"9"
        }
     }
  ]
}
})

But I can't get the elements inside the {}. Because the "jsonpElixo(" is breaking during the decodable.

How can I fix that?


The func to get info about json file.

func getParks() {
var request = URLRequest(url:gitUrl)
request.addValue("application/json", forHTTPHeaderField: "Content-Type")

URLSession.shared.dataTask(with: request) { (data, response, error) in
        guard let data = data else { return }
        do {
            let decoder = JSONDecoder()
            let welcome = try? decoder.decode(Welcome.self, from: data)

        } catch let err {
            print("Err", err)
        }
        }.resume()

}

The structs to Decodable the elements. But I dont know how can I scape this first element ("jsonpElixo(")

struct Welcome: Decodable {
let response: Response
}
struct Response: Decodable {
let parks: [Park]
}
struct Park: Decodable {
let park: ParkClass
let address: Address
enum CodingKeys: String, CodingKey {
    case park = "Park"
    case address = "Address"
}
}

struct Address: Decodable {
let lat, long: String
let cep: String?
let street, number, neighborhood, city: String
let state, id: String
}

struct ParkClass: Decodable {
 let id, name, type: String
}
  • 1
    " Because the "jsonpElixo(" is breaking during the decodable." Why? What's your code? What's the full and exact error thrown ? – Larme Aug 24 '18 at 13:06
  • Hi, Welcome. Please add some code so that we can see what you have done. – Rob Aug 24 '18 at 13:09
  • I updated the post – Henri Silva Aug 24 '18 at 13:19
  • That doesn't look like a valid JSON file. How did you get that JSON? – jlowe Aug 24 '18 at 13:25
  • I get this json from a web server from a client – Henri Silva Aug 24 '18 at 13:33
  • Could we be clear about two things: What's the output of`let jsonData = String(data, encoding: .utf8), print("JSON: \(jsonData)")`? Do you really have `jsonpElixo(` at start ? Also, what's the log of `print("Err", err)`? – Larme Aug 24 '18 at 13:34
  • Yes, this json start with "jsonpElixo(" . Err = Err dataCorrupted(Swift.DecodingError.Context(codingPath: [], debugDescription: "The given data was not valid JSON.", underlyingError: Optional(Error Domain=NSCocoaErrorDomain Code=3840 "JSON text did not start with array or object and option to allow fragments not set." UserInfo={NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set.}))) – Henri Silva Aug 24 '18 at 13:43
  • Here are some sample json files https://support.oneskyapp.com/hc/en-us/articles/208047697-JSON-sample-files . Have you defined a custom type `jsonpElixo`on your web server? – ielyamani Aug 24 '18 at 13:44
  • Usually I get json in the right format. But this client send a json with this start "jsonpElixo", in JsonData that information is the same. – Henri Silva Aug 24 '18 at 13:47
  • This https://stackoverflow.com/questions/2669690/why-does-google-prepend-while1-to-their-json-responses?rq=1 could be related. – jlowe Aug 24 '18 at 13:50
  • 1
    Maybe jsonp is used on the server side https://www.w3schools.com/js/js_json_jsonp.asp – ielyamani Aug 24 '18 at 14:04
  • Is `jsonpElixo` a function on the server? – ielyamani Aug 24 '18 at 14:13
  • 1
    If you have contact with your server, ask them to respond REAL JSON. Else, you can remove the non-JSON part, that's hacky, but you can get inspired there: https://stackoverflow.com/questions/51559807/afnetworking-trim-characters-from-response/51561862#51561862 (don't forget to remove the last ")" too). – Larme Aug 24 '18 at 14:50

1 Answers1

0

You can create a function that will remove the outer jsonpElixo() object and return the json to work with.

Start with an extension on Data so we can create something similar to this:

extension Data {
    func decodeJsonpElixo() -> Data {
        guard let jsonpString = String(data: self, encoding: .utf8) else {return self}

        if jsonpString.hasPrefix("jsonpElixo(") && jsonpString.hasSuffix(")") {
            var decoderString = jsonpString.replacingOccurrences(of: "jsonpElixo(", with: "")
            decoderString.remove(at: String.Index(encodedOffset: decoderString.endIndex.encodedOffset - 1))

            return Data(decoderString.utf8)
        }

        return self
    }
}

Then you can use this in your URLSession closure like this:

guard let data = data else { return }
let decoderData = data.decodeJsonpElixo()
let decoder = JSONDecoder()
do {
    let welcome = try decoder.decode(Welcome.self, from: decoderData)
} catch let err {
    print(err)
}
jlowe
  • 318
  • 4
  • 15
  • 1
    I'd do `if jsonpString.hasPrefix("jsonpElixo(") && if jsonpString.hasSufffix("jsonpElixo(") {}` instead. The JSON could contains at some point the `jsonpElixo(` in the middle. – Larme Aug 24 '18 at 16:32