iOS : Parsing JSON with Swift 2 – A Realistic Example
Okay so I wrote this blog post to help others who might be frustrated by the lack of real-world examples of parsing JSON with Swift 2. There are quite a few examples on the net you can find but (so far in my search at least) they are all way too simple to be useful when faced with some JSON with multiple levels of nested data.
Here is some JSON I downloaded from the Glasgow Smart City Car Park occupancy feed here.
{ "version":"1.0", "encoding":"UTF-8", "d2lm$d2LogicalModel":{ "@xmlns$d2lm":"http://datex2.eu/schema/1_0/1_0", "@xmlns$xsi":"http://www.w3.org/2001/XMLSchema-instance", "@xmlns$xalan":"http://xml.apache.org/xslt", "@xmlns$java":"http://xml.apache.org/xalan/java", "@modelBaseVersion":"1.0", "@xsi$schemaLocation":"http://datex2.eu/schema/1_0/1_0 http://datex2.eu/schema/1_0/1_0/DATEXIISchema_1_0_1_0.xsd", "d2lm$exchange":{ "d2lm$supplierIdentification":{ "d2lm$country":"gb", "d2lm$nationalIdentifier":"TIH Toolkit" } }, "d2lm$payloadPublication":{ "@lang":"en", "@xsi$type":"d2lm:SituationPublication", "d2lm$publicationTime":"2015-12-16T19:08:52", "d2lm$publicationCreator":{ "d2lm$country":"gb", "d2lm$nationalIdentifier":"TIH Toolkit" }, "d2lm$situation":[ { "@id":"CPG25C", "d2lm$headerInformation":{ "d2lm$confidentiality":"noRestriction", "d2lm$informationStatus":"real" }, "d2lm$situationRecord":{ "@id":"CPG25C_1", "@xsi$type":"d2lm:CarParks", "d2lm$situationRecordCreationTime":"2015-08-24T12:29:44", "d2lm$situationRecordVersion":"1", "d2lm$situationRecordVersionTime":"2015-08-24T12:29:44", "d2lm$situationRecordFirstSupplierVersionTime":"2015-08-24T12:29:44", "d2lm$probabilityOfOccurrence":"certain", "d2lm$validity":{ "d2lm$validityStatus":"active", "d2lm$validityTimeSpecification":{ "d2lm$overallStartTime":"2015-08-24T12:29:44" } }, "d2lm$groupOfLocations":{ "d2lm$locationContainedInGroup":{ "@xsi$type":"d2lm:Point", "d2lm$pointByCoordinates":{ "d2lm$pointCoordinates":{ "d2lm$latitude":"55.85988984843241", "d2lm$longitude":"-4.282341367108816" } } } }, "d2lm$carParkIdentity":"SECC:CPG25C", "d2lm$carParkOccupancy":"17.0", "d2lm$carParkStatus":"enoughSpacesAvailable", "d2lm$occupiedSpaces":"282", "d2lm$totalCapacity":"1600" } }, { "@id":"CPG24C", "d2lm$headerInformation":{ "d2lm$confidentiality":"noRestriction", "d2lm$informationStatus":"real" }, "d2lm$situationRecord":{ "@id":"CPG24C_1", "@xsi$type":"d2lm:CarParks", "d2lm$situationRecordCreationTime":"2015-08-24T12:29:44", "d2lm$situationRecordVersion":"1", "d2lm$situationRecordVersionTime":"2015-08-24T12:29:44", "d2lm$situationRecordFirstSupplierVersionTime":"2015-08-24T12:29:44", "d2lm$probabilityOfOccurrence":"certain", "d2lm$validity":{ "d2lm$validityStatus":"active", "d2lm$validityTimeSpecification":{ "d2lm$overallStartTime":"2015-08-24T12:29:44" } }, "d2lm$groupOfLocations":{ "d2lm$locationContainedInGroup":{ "@xsi$type":"d2lm:Point", "d2lm$pointByCoordinates":{ "d2lm$pointCoordinates":{ "d2lm$latitude":"55.85966175538049", "d2lm$longitude":"-4.236528758151018" } } } }, "d2lm$carParkIdentity":"Duke Street:CPG24C", "d2lm$carParkOccupancy":"54.0", "d2lm$carParkStatus":"enoughSpacesAvailable", "d2lm$occupiedSpaces":"643", "d2lm$totalCapacity":"1170" } } ] } } }
What we want to extract are the contents of the top level elements of the “d2lm$situationRecord” tags (I have edited the original JSON to only include two records for brevity). To do this we are going to have to parse down a few levels. I had to figure out how to do this as all the examples I have seen on the net are for very simple JSON. Here is a short example swift command line program to demonstrated how it’s done.
import Foundation var CAR_PARK_JSON : String = "{\"version\":\"1.0\",\"encoding\":\"UTF-8\",\"d2lm$d2LogicalModel\":{\"@xmlns$d2lm\":\"http://datex2.eu/schema/1_0/1_0\",\"@xmlns$xsi\":\"http://www.w3.org/2001/XMLSchema-instance\",\"@xmlns$xalan\":\"http://xml.apache.org/xslt\",\"@xmlns$java\":\"http://xml.apache.org/xalan/java\",\"@modelBaseVersion\":\"1.0\",\"@xsi$schemaLocation\":\"http://datex2.eu/schema/1_0/1_0 http://datex2.eu/schema/1_0/1_0/DATEXIISchema_1_0_1_0.xsd\",\"d2lm$exchange\":{\"d2lm$supplierIdentification\":{\"d2lm$country\":\"gb\",\"d2lm$nationalIdentifier\":\"TIH Toolkit\"}},\"d2lm$payloadPublication\":{\"@lang\":\"en\",\"@xsi$type\":\"d2lm:SituationPublication\",\"d2lm$publicationTime\":\"2015-12-16T19:08:52\",\"d2lm$publicationCreator\":{\"d2lm$country\":\"gb\",\"d2lm$nationalIdentifier\":\"TIH Toolkit\"},\"d2lm$situation\":[{\"@id\":\"CPG25C\",\"d2lm$headerInformation\":{\"d2lm$confidentiality\":\"noRestriction\",\"d2lm$informationStatus\":\"real\"},\"d2lm$situationRecord\":{\"@id\":\"CPG25C_1\",\"@xsi$type\":\"d2lm:CarParks\",\"d2lm$situationRecordCreationTime\":\"2015-08-24T12:29:44\",\"d2lm$situationRecordVersion\":\"1\",\"d2lm$situationRecordVersionTime\":\"2015-08-24T12:29:44\",\"d2lm$situationRecordFirstSupplierVersionTime\":\"2015-08-24T12:29:44\",\"d2lm$probabilityOfOccurrence\":\"certain\",\"d2lm$validity\":{\"d2lm$validityStatus\":\"active\",\"d2lm$validityTimeSpecification\":{\"d2lm$overallStartTime\":\"2015-08-24T12:29:44\"}},\"d2lm$groupOfLocations\":{\"d2lm$locationContainedInGroup\":{\"@xsi$type\":\"d2lm:Point\",\"d2lm$pointByCoordinates\":{\"d2lm$pointCoordinates\":{\"d2lm$latitude\":\"55.85988984843241\",\"d2lm$longitude\":\"-4.282341367108816\"}}}},\"d2lm$carParkIdentity\":\"SECC:CPG25C\",\"d2lm$carParkOccupancy\":\"17.0\",\"d2lm$carParkStatus\":\"enoughSpacesAvailable\",\"d2lm$occupiedSpaces\":\"282\",\"d2lm$totalCapacity\":\"1600\"}},{\"@id\":\"CPG24C\",\"d2lm$headerInformation\":{\"d2lm$confidentiality\":\"noRestriction\",\"d2lm$informationStatus\":\"real\"},\"d2lm$situationRecord\":{\"@id\":\"CPG24C_1\",\"@xsi$type\":\"d2lm:CarParks\",\"d2lm$situationRecordCreationTime\":\"2015-08-24T12:29:44\",\"d2lm$situationRecordVersion\":\"1\",\"d2lm$situationRecordVersionTime\":\"2015-08-24T12:29:44\",\"d2lm$situationRecordFirstSupplierVersionTime\":\"2015-08-24T12:29:44\",\"d2lm$probabilityOfOccurrence\":\"certain\",\"d2lm$validity\":{\"d2lm$validityStatus\":\"active\",\"d2lm$validityTimeSpecification\":{\"d2lm$overallStartTime\":\"2015-08-24T12:29:44\"}},\"d2lm$groupOfLocations\":{\"d2lm$locationContainedInGroup\":{\"@xsi$type\":\"d2lm:Point\",\"d2lm$pointByCoordinates\":{\"d2lm$pointCoordinates\":{\"d2lm$latitude\":\"55.85966175538049\",\"d2lm$longitude\":\"-4.236528758151018\"}}}},\"d2lm$carParkIdentity\":\"Duke Street:CPG24C\",\"d2lm$carParkOccupancy\":\"54.0\",\"d2lm$carParkStatus\":\"enoughSpacesAvailable\",\"d2lm$occupiedSpaces\":\"643\",\"d2lm$totalCapacity\":\"1170\"}}]}}}" var datastring : NSString = CAR_PARK_JSON var nsdata : NSData! = datastring.dataUsingEncoding(NSUTF8StringEncoding) do { let json = try NSJSONSerialization.JSONObjectWithData(nsdata, options: .AllowFragments) let d2LogicalModel = json["d2lm$d2LogicalModel"] as! [String : AnyObject] let payloadPublication = d2LogicalModel["d2lm$payloadPublication"] as! [String : AnyObject] let situations = payloadPublication["d2lm$situation"] as! [[String : AnyObject]] for situation in situations { let record = situation["d2lm$situationRecord"] as! [String : AnyObject] let carParkIdentity = record["d2lm$carParkIdentity"] as! String let carParkOccupancy = record["d2lm$carParkOccupancy"] as! String let carParkStatus = record["d2lm$carParkStatus"] as! String let occupiedSpaces = record["d2lm$occupiedSpaces"] as! String let totalCapacity = record["d2lm$totalCapacity"]as! String print("id :\(carParkIdentity), occupancy:\(carParkOccupancy), status:\(carParkStatus), capacity:\(totalCapacity), occupied:\(occupiedSpaces)\n") } } catch { print("error serializing JSON: \(error)") }
If you run this you should get the output
id :SECC:CPG25C, occupancy:17.0, status:enoughSpacesAvailable, capacity:1600, occupied:282 id :Duke Street:CPG24C, occupancy:54.0, status:enoughSpacesAvailable, capacity:1170, occupied:643
A few things to note:
- In the sample application I have defined the test JSON as one long String. I had to escape the double quotes. Single quotes will not work.
- There may be a way to shortcut moving down through the nested levels. I don’t know how though.
I hope this helps someone else.