5

I'm using SwiftSoup in combination with Codable to get the correct element(s) and parse the data. However, I receive this error:

JSON decode failed: Swift.DecodingError.dataCorrupted(Swift.DecodingError.Context(codingPath: [], debugDescription: "The given data was not valid JSON.", underlyingError: Optional(Error Domain=NSCocoaErrorDomain Code=3840 "No value." UserInfo={NSDebugDescription=No value.}))) 

I've looked online, ensure my data matches correctly, even change the expected types from Int to String but got an error stating an Int was expected.

This is the data I am receiving and can print in the console:

data - {"test":0,"ppace":85,"pshooting":92,"ppassing":91,"pdribbling":95,"pdefending":38,"pphysical":65,"acceleration":91,"sprintspeed":80,"agility":91,"balance":95,"reactions":94,"ballcontrol":96,"dribbling":96,"positioning":93,"finishing":95,"shotpower":86,"longshotsaccuracy":94,"volleys":88,"penalties":75,"interceptions":40,"headingaccuracy":70,"marking":32,"standingtackle":35,"slidingtackle":24,"vision":95,"crossing":85,"freekickaccuracy":94,"shortpassing":91,"longpassing":91,"curve":93,"jumping":68,"stamina":72,"strength":69,"aggression":44,"composure":96} 

This is my function:

 func parseData() { do { let html = try String(contentsOf: url!, encoding: String.Encoding.ascii) let doc: Document = try! SwiftSoup.parse(html) let elements = try doc.getAllElements() for element in elements { switch element.id() { case "player_stats_json": let content = try! element.getElementsContainingText("ppace").text() print(content.utf8) let jsonData = content.data(using: .utf8) do { self.player = try JSONDecoder().decode(PlayerModel.self, from: Data(jsonData!)) } catch let jsonError as NSError { print("JSON decode failed: \(jsonError)") print("data - \(content)") } default: break } } } catch Exception.Error(type: let type, Message: let message) { print(type) print(message) } catch { print("") } } 

And this is my model file:

struct PlayerModel: Codable { var test: Int var ppace: Int var pshooting: Int var ppassing: Int var pdribbling: Int var pdefending: Int var pphysical: Int var acceleration: Int var sprintspeed: Int var agility: Int var balance: Int var reactions: Int var ballcontrol: Int var dribbling: Int var positioning: Int var finishing: Int var shotpower: Int var longshotsaccuracy: Int var volleys: Int var penalties: Int var interceptions: Int var headingaccuracy: Int var marking: Int var standingtackle: Int var slidingtackle: Int var vision: Int var crossing: Int var freekickaccuracy: Int var shortpassing: Int var longpassing: Int var curve: Int var jumping: Int var stamina: Int var strength: Int var aggression: Int var composure: Int } 

I've double and tripled checked the variable names match up with each key. I've pasted the outputted data in the console in an Online JSON validator, and no errors appear. I'm genuinley left scratching my head right now, because I can't understand where I've gone wrong.

1
  • Comments are not for extended discussion; this conversation has been moved to chat. Commented Oct 10, 2020 at 7:03

1 Answer 1

3

I still have no idea whats wrong with your parsing. I've managed to parse your html but I have no idea why when trying to use Int instead of Uint8 it kept failing to return the right values. This is what worked for me:

import UIKit import PlaygroundSupport PlaygroundPage.current.needsIndefiniteExecution = true struct PlayerModel: Codable { let test: UInt8 let ppace: UInt8 let pshooting: UInt8 let ppassing: UInt8 let pdribbling: UInt8 let pdefending: UInt8 let pphysical: UInt8 let acceleration: UInt8 let sprintspeed: UInt8 let agility: UInt8 let balance: UInt8 let reactions: UInt8 let ballcontrol: UInt8 let dribbling: UInt8 let positioning: UInt8 let finishing: UInt8 let shotpower: UInt8 let longshotsaccuracy: UInt8 let volleys: UInt8 let penalties: UInt8 let interceptions: UInt8 let headingaccuracy: UInt8 let marking: UInt8 let standingtackle: UInt8 let slidingtackle: UInt8 let vision: UInt8 let crossing: UInt8 let freekickaccuracy: UInt8 let shortpassing: UInt8 let longpassing: UInt8 let curve: UInt8 let jumping: UInt8 let stamina: UInt8 let strength: UInt8 let aggression: UInt8 let composure: UInt8 } 

let url = URL(string:"https://www.futbin.com/21/player/541/lionel-messi")! URLSession.shared.dataTask(with: url) { data, response, error in guard let data = data, let html = String(data: data, encoding: .utf8) else { return } if let start = html.range(of: #"<div style="display: none;" id="player_stats_json">"#)?.upperBound, let end = html[start...].range(of: #"</div>"#)?.lowerBound { let json = html[start..<end] do { let player = try JSONDecoder().decode(PlayerModel.self, from: Data(json.utf8)) print(player) } catch { print(error) } } }.resume() 

This will print

PlayerModel(test: 0, ppace: 85, pshooting: 92, ppassing: 91, pdribbling: 95, pdefending: 38, pphysical: 65, acceleration: 91, sprintspeed: 80, agility: 91, balance: 95, reactions: 94, ballcontrol: 96, dribbling: 96, positioning: 93, finishing: 95, shotpower: 86, longshotsaccuracy: 94, volleys: 88, penalties: 75, interceptions: 40, headingaccuracy: 70, marking: 32, standingtackle: 35, slidingtackle: 24, vision: 95, crossing: 85, freekickaccuracy: 94, shortpassing: 91, longpassing: 91, curve: 93, jumping: 68, stamina: 72, strength: 69, aggression: 44, composure: 96)

Sign up to request clarification or add additional context in comments.

7 Comments

I've just copied in your function and now I've seemed to have success with it. Even appended to an array on PlayerModels whilst keeping all values as Ints within my Model class.
@SwiftUser Glad to help. I think you should find an API to return a JSON instead of parsing it from an html if possible.
Thank you so much for your time and effort! I honestly appreciate it. There is an API that's available to pay for, which I don't mind. I tried contacting them in the hopes of a deal. However, their email wasn't send. One question, I see you used html.range start and end to point in the right direction of the data which should be parsed, is it possible to create multiple ranges? And parse the data all at once?
stackoverflow.com/questions/32305891/… this will return ranges but you have different strings to find.
You would need to use NSRegularExpression and get the group ranges. This might help if you know how to create regex patterns stackoverflow.com/a/64235708/2303865
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.