How to parse data which starts with an array [? - json

So in my swift 3 xcode project, I want to parse some data using JSOmN by consuming a web service called "http://tour-pedia.org/api/"
And the data within it for example is set like this:
[
{
"address": "Science Park 904",
"category": "attraction",
"id": 30884,
"lat": 52.355320008998,
"lng": 4.9574317242814,
"location": "Amsterdam",
"name": "Dakterras Science Park",
"originalId": "4d8b3370bc848cfa1043ea2b",
"polarity": 0,
"subCategory": "Scenic Lookout",
},
{
"address": "Science Park 201",
"category": "attraction",
"id": 30661,
"lat": 52.356701093273,
"lng": 4.9529844809109,
"location": "Amsterdam",
"name": "In 'de Natuur' rondom Science Park",
"originalId": "4da2ede7c6e96ea85e1ede5d",
"polarity": 0,
"subCategory": "Field",
}
]
I want to use the address, location and name field.
so far i have done this:
func fetchInfos(){
let urlRequest = URLRequest(url: URL(string: "http://tour-pedia.org/api/")!)
let task = URLSession.shared.dataTask(with: urlRequest){ (data,response,error) in
if error != nil {
print(error)
return
}
do{
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! [String : AnyObject]
} catch let error {
print(error)
}
}
}
but i don't know how to continue on from here.
Any help will be appreciated, thank you!

Let us assume your string s is the json with sqaure brackets
String s = "[{\"a\":\"b\"}]";
s = s.substring(1, s.length() - 1);
//do all your processing on s now, as the sqaure brackets will be removed !!

Related

How to serialize a Json partially?

I have a huge json (20 mb, 6000+ records) that If I use decode it takes ages, then I started using serialize to try to parse it in pieces. But I'm having trouble to parse it (getting null when I serialize it, funny enough I don't specify as? [String:Any] I actually get the json)
is there a better way to parse a Json partially?
Json structure
[
{
"page": 1,
"total": 100,
"data": [
{
"address": "677 Quincy Street #1B",
"neighborhood": "Stuyvesant Heights",
"zipcode": "11221",
"latitude": 40.68935935,
"longitude": -73.93179845,
"bedroom": "2 beds",
"bath": "1.5 baths",
"area": null,
"status": "current",
"photos": [
"https://photos.zillowstatic.com/fp/b444ec7e07f1bb83f27c6dfa2167e92a-se_extra_large_1500_800.jpg"
],
"video": null,
"description": "NO FEE!!Luxury 2 BR / 1.5 Bath DUPLEX Apartment",
"new_listing": 1,
"date_available": "Available Now",
"open_house": null,
"price": 2999,
"dishwasher": false,
"washer_and_dryer": false,
"pets_allowed": true,
"live_in_super": false,
"elevator": false,
"url": "https://streeteasy.com/building/677-quincy-street-brooklyn/1b"
},
]
}
]
I made it work, but sadly serialization doesn't help with the load speed, I was thinking to do "pagination with the first 100 items" but swift needs to parse the entire json first.
//serialization baby!
let json = try JSONSerialization.jsonObject(with: data!, options: []) as? [[String:Any]]
//make it an array
let first100Listings = json!.first!["data"] as? NSArray
let jsonData = try JSONSerialization.data(withJSONObject: first100Listings!, options: [])
let responseModel = try JSONDecoder().decode([Listings].self, from: jsonData)
self.listingsZ = responseModel

Getting invalid json when calling JSONSerialization in Swift

I am trying to access a URL and parse the JSON output. Printing JSON in utf8 encoding
Code:
let urlString:String = "https://developer.nrel.gov/api/.../"
let pvURL = URL(string: urlString)
let dataTask = URLSession.shared.dataTask(with:pvURL!) { (data, response, error) in
do {
let json = try JSONSerialization.jsonObject(with: data!)
print(String(data: data!, encoding: .utf8)!)
}catch let err {
print("error: \(err.localizedDescription)")
}
}
dataTask.resume()
Prints the following output. I try this JSON in an online JSON parser it fails. Gives error in the first line itself.
{"inputs":{"lat":"29.93","lon":"-95.61","system_capacity":"30.30","azimuth":"180","tilt":"40","array_type":"1","module_type":"1","losses":"10"},"errors":[],"warnings":[],"version":"1.0.1","ssc_info":{"version":45,"build":"Linux 64 bit GNU/C++ Jul 7 2015 14:24:09"},"station_info":{"lat":29.93000030517578,"lon":-95.62000274658203,"elev":41.0,"tz":-6.0,"location":"None","city":"","state":"Texas","solar_resource_file":"W9562N2993.csv","distance":964},"outputs":{"ac_monthly":[3480.57373046875,3440.078369140625,3992.6513671875,3977.071533203125,4074.91357421875,3701.75,3897.655517578125,4248.00390625,4023.283447265625,4157.29931640625,3605.156005859375,3342.12890625],"poa_monthly":[139.791015625,140.18896484375,164.8218536376953,164.47149658203125,173.2971649169922,159.90576171875,169.84793090820312,186.20114135742188,173.14492797851562,176.2291717529297,148.28318786621094,136.62326049804688],"solrad_monthly":[4.509387493133545,5.006748676300049,5.316833972930908,5.4823832511901855,5.590230941772461,5.3301920890808105,5.4789652824401855,6.00648832321167,5.77149772644043,5.684812068939209,4.94277286529541,4.407201766967773],"dc_monthly":[3644.867919921875,3606.52001953125,4179.85107421875,4158.3193359375,4252.9140625,3865.03369140625,4069.092041015625,4432.62744140625,4198.369140625,4336.99609375,3767.055419921875,3490.091064453125],"ac_annual":45940.55859375,"solrad_annual":5.293959140777588,"capacity_factor":17.308107376098633}}`
whereas if I access the urlString in a browser gives valid json:
{
"inputs": {
"lat": "29.93",
"lon": "-95.61",
"system_capacity": "30.30",
"azimuth": "180",
"tilt": "40",
"array_type": "1",
"module_type": "1",
"losses": "10"
},
"errors": [],
"warnings": [],
"version": "1.0.1",
"ssc_info": {
"version": 45,
"build": "Linux 64 bit GNU/C++ Jul 7 2015 14:24:09"
},
"station_info": {
"lat": 29.93000030517578,
"lon": -95.62000274658203,
"elev": 41,
"tz": -6,
"location": "None",
"city": "",
"state": "Texas",
"solar_resource_file": "W9562N2993.csv",
"distance": 964
},
"outputs": {
"ac_monthly": [
3480.57373046875,
3440.078369140625,
3992.6513671875,
3977.071533203125,
4074.91357421875,
3701.75,
3897.655517578125,
4248.00390625,
4023.283447265625,
4157.29931640625,
3605.156005859375,
3342.12890625
],
...
}
In your code you are converting the JSON data into an JSON object(Array, Dictionary).
But In browser the JSON data is printing as String and not as JSON object(Array, Dictionary).
So if you want to print the JSON string in your code as well, you can print as like below.
let string = String(data: self, encoding: .utf8)
print("JSON String:\(String(describing: string))")
Hope it helps.

swift json parsing based on parameter

I am having the following web service response in which I need parse the parameters based on "MainServiceCategories_ID"
Here is the response
{
"Entity": {
"ID": 20021,
"UserTypeID": 1,
"UserType": null,
"UserID": 30046,
"Code": "lPx1lTEq",
"Name": "بدراء",
"EnglishName": "Badra",
"IconProfileImageID": "",
"MainImageProfileImageID": "EED372C3-5C4F-E711-8100-0CC47A343427",
"LocationLng": 78.37021,
"LocationLat": 17.432563,
"Services": [
{
"ID": 11788,
"MainServiceCategories_ID": 3,
"ServiceCategories_ID": 6,
"Children": [
{
"Parent_ID": 6,
"Name": “John”,
"EnglishName": “Johnny”,
},
{
"Parent_ID": 6,
"Name": “Ronny”,
"EnglishName": “Ronny”,
}]
},
{
"ID": 11788,
"MainServiceCategories_ID": 2,
"ServiceCategories_ID": 6,
"Children": [
{
"Parent_ID": 6,
"Name": “Samuel”,
"EnglishName": “Samuel”,
},
{
"Parent_ID": 6,
"Name": “Badri”,
"EnglishName": “Badri”,
}]
},
{
"ID": 11788,
"MainServiceCategories_ID": 3,
"ServiceCategories_ID": 6,
"Children": [
{
"Parent_ID": 6,
"Name": “emma”,
"EnglishName": “Emma”,
},
{
"Parent_ID": 6,
"Name": “Sean”,
"EnglishName": “Sean”,
}]
}]
this is the code I am writing to do it
do{
let entityDic = responseDictionary["Entity"] as? [String: Any]
let servicesDic = entityDic?["Services"] as? [Any]
for i in 0 ..< servicesDic!.count {
let services = servicesDic?[i] as? [String: Any]
let availableServices = services!["EnglishName"]
servicesNamesArr.append(availableServices! as! String)
let children = services!["Children"]
childrenServices.append(children!)
let MainServiceCategories_ID = services!["MainServiceCategories_ID"]
MainServiceCategoriesID.append(MainServiceCategories_ID!)
}
print("childrenServices \(childrenServices)")
}
catch let error{
print(error)
}
I am able to get upto children dictionaries. Now the thing is I am trying to parse "English name" under children section and separate them based on "MainServiceCategories_ID" where I am getting fatal error in unwrapping the value.
for example if MainServiceCategories_ID =1 then that "English Name" need to be store in an array and if MainServiceCategories_ID =2 then into another array
The problem is, you are trying to parse "EnglishName" as a key of an element of the "Services" array and not as a key of a "Children" element. "Services" does not have a key "EnglishName", so you can't store that in servicesNamesArr. servicesDic should also be an Array of Dictionaries and not an array of Any objects.
See below code using guard statements using safe optional unwrapping:
do{
guard let entityDic = responseDictionary["Entity"] as? [String: Any] else {return}
guard let servicesDic = entityDic?["Services"] as? [[String:Any]] else {return}
for service in services {
guard let MainServiceCategoryID = service["MainServiceCategories_ID"] as? Int else {return}
MainServiceCategoriesID.append(MainServiceCategoryID)
guard let children = service["Children"] as? [[String:Any]] else {return}
childrenServices.append(children)
if MainServiceCategoryID == 3 {
for child in children {
if let availableService = child["EnglishName"] as? String {
servicesNamesArr.append(availableService)
}
}
}
}
print("childrenServices \(childrenServices)")
} catch let error{
print(error)
}

Swift3 Json Parsing - how to access relevant fields

Having real difficulties accessing the info required in Swift 3 from a JSON, here's what I have:
override func viewDidLoad()
{
super.viewDidLoad()
let url = URL(string: "http://api.brewerydb.com/v2/beers?key=e3bdce7d0a80584c784cdc4b02459add&name=budweiser")
URLSession.shared.dataTask(with:url!) { (data, response, error) in
if error != nil {
print(error!)
}
else {
do {
let parsedData = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as AnyObject
// print(parsedData)
let dataLevel = parsedData["data"] as? NSDictionary
print(dataLevel)
let abv = dataLevel?["abv"] as? AnyObject
print(abv!)
} catch let error as NSError {
print(error)
}
}
}.resume()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
the link to the JSON file is in the code - why is my code not returning the 'data' section, and how could I retrieve the beer 'name', 'abv' and 'description'?
When you deal with JSON I think it is helpful to use tools like:
jsonformatter.curiousconcept.com
or
jsonlint.com
which help me a lot understanding the structure and what kind of data I am dealing with.
If you look at your json in you can notice that, as Eric Aya said, data is an array not a dictionary:
{
"currentPage": 1,
"numberOfPages": 1,
"totalResults": 1,
"data": [{
"id": "1P45iR",
"name": "Budweiser",
"nameDisplay": "Budweiser",
"description": "Known as \u201cThe King of Beers\u201d, Budweiser was first introduced by Adolphus Busch in 1876 and is brewed with the same high quality standards today. Budweiser is a medium-bodied, flavorful, crisp American-style lager, craft brewed with a blend of premium hop varieties, and associated with the core American values of celebration and optimism.",
"abv": "5",
"glasswareId": 5,
"srmId": 5,
"availableId": 1,
"styleId": 93,
"isOrganic": "N",
"labels": {
"icon": "https:\/\/s3.amazonaws.com\/brewerydbapi\/beer\/1P45iR\/upload_Y13vwL-icon.png",
"medium": "https:\/\/s3.amazonaws.com\/brewerydbapi\/beer\/1P45iR\/upload_Y13vwL-medium.png",
"large": "https:\/\/s3.amazonaws.com\/brewerydbapi\/beer\/1P45iR\/upload_Y13vwL-large.png"
},
"status": "verified",
"statusDisplay": "Verified",
"servingTemperature": "cold",
"servingTemperatureDisplay": "Cold - (4-7C\/39-45F)",
"createDate": "2012-01-03 02:42:55",
"updateDate": "2016-03-21 19:54:11",
"glass": {
"id": 5,
"name": "Pint",
"createDate": "2012-01-03 02:41:33"
},
"srm": {
"id": 5,
"name": "5",
"hex": "FBB123"
},
"available": {
"id": 1,
"name": "Year Round",
"description": "Available year round as a staple beer."
},
"style": {
"id": 93,
"categoryId": 8,
"category": {
"id": 8,
"name": "North American Lager",
"createDate": "2012-03-21 20:06:46"
},
"name": "American-Style Lager",
"shortName": "American Lager",
"description": "Light in body and very light to straw in color, American lagers are very clean and crisp and aggressively carbonated. Flavor components should b e subtle and complex, with no one ingredient dominating the others. Malt sweetness is light to mild. Corn, rice, or other grain or sugar adjuncts are often used. Hop bitterness, flavor and aroma are negligible to very light. Light fruity esters are acceptable. Chill haze and diacetyl should be absent.",
"ibuMin": "5",
"ibuMax": "13",
"abvMin": "3.8",
"abvMax": "5",
"srmMin": "2",
"srmMax": "4",
"ogMin": "1.04",
"fgMin": "1.006",
"fgMax": "1.01",
"createDate": "2012-03-21 20:06:46",
"updateDate": "2015-04-07 15:39:26"
}
}],
"status": "success"
}
The following code works but I am sure there is a better way to get abv with less code:
override func viewDidLoad()
{
super.viewDidLoad()
let url = URL(string: "http://api.brewerydb.com/v2/beers?key=e3bdce7d0a80584c784cdc4b02459add&name=budweiser")
URLSession.shared.dataTask(with:url!) { (data, response, error) in
if error != nil {
print(error!)
}
else {
do {
let parsedData = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as? [String: Any]
let jsonArrayData = parsedData?["data"] as! NSArray
let data = jsonArrayData[0] as! NSDictionary
let abv = data["abv"]
print(abv)//Optional(5) in your case
} catch let error as NSError {
print(error)
}
}
}.resume()
}

Accessing JSON data in swift

I am trying to access JSON data in my swift code and I'm having trouble getting it to return correctly. Here is my JSON code:
[
{
"id": "1",
"isImage": "0",
"name": "test name",
"post": "test post",
"time": "10:27",
"ip": "192.168.1.1",
"city ": "Columbus",
"latlong": "39.896418,-82.9751105",
"clientID": "clientID",
"popularity": "300"
},
{
"id": "2",
"isImage": "0",
"name": "test name two",
"post": "test post two",
"time": "13:37",
"ip": "192.168.1.1",
"city ": "Columbus",
"latlong": "39.896418,-82.9751105",
"clientID": "clientID",
"popularity": "69"
}
]
I'd just like to know how to access the data by their keys json[0].['id'] or?
I am currently using this json.swift module and trying to access the data with
func jsonHandle(data: NSString) {
var parsedJSON = JSON(data)
var id = parsedJSON[0].["id"]
NSLog("\(id)")
}
but it returns nothing. Any Ideas?
You can call the JSON(string:...) rendition and eliminate the period between the [0] and the ["id"]:
func jsonHandle(data: NSString) {
let parsedJSON = JSON(string: data)
var id = parsedJSON[0]["id"]
NSLog("\(id)")
}
Or, if you had a NSData you could use the JSON(data: ...) rendition:
func jsonHandle(data: NSData) {
let parsedJSON = JSON(data: data)
let id = parsedJSON[0]["id"]
NSLog("\(id)")
}
Or, if you wanted to use the native NSJSONSerialization, rather than that third-party library, you could:
func jsonHandle(data: NSData) {
var error: NSError?
let parsedJSON = NSJSONSerialization.JSONObjectWithData(data, options: nil, error: &error) as NSArray
let id = parsedJSON[0]["id"]
NSLog("\(id)")
}
Personally, I'd lean towards the standard NSJSONSerialization approach as it's a tried and true approach, but that's your call.