Parsing JSON into a usable format

284 Views Asked by At

I'm currently downloading data from a server and I'm not sure how to get the response that I'm getting back into the format that's expected by the method that I'm working with. Could someone guide me on what I would need to do to get all of the items in the JSON response added into a [[String : AnyObject]] format?

Thank you in advance!!

JSON that I'm getting back

{
    "Green Shirt": [
        {
            "id": "740",
            "name": “Nice Green Shirt",
            "quantity": "0",
            "make": "",
            "model": "",
            "price": “15.00",
            "size": "XXS",
            "sku": null,
            "image": "https:\/\/google.com\/green_shirt.jpg",
            "new_record": false,
            "category_name": "",
            "bar_code": "",
        },
        {
            "id": "743",
            "name": "Green Shirt",
            "quantity": “68",
            "make": "",
            "model": "",
            "price": “20.00",
            "size": "XS",
            "sku": null,
            "image": "https:\/\/google.com\/green_shirt.jpg",
            "new_record": false,
            "category_name": "",
            "bar_code": "",
        }
    ],
    "Dark Blue Jeans": [
        {
            "id": "1588",
            "name": "Dark Blue Jeans",
            "quantity": "0",
            "make": "",
            "model": "",
            "price": "0.00",
            "size": “S",
            "sku": null,
            "image": "https:\/\/google.com\/dark_blue_jeans.jpg",
            "new_record": false,
            "category_name": "",
            "bar_code": "",
            "category": null
        },
        {
            "id": "1559",
            "name": "Dark Blue Jeans",
            "quantity": "4",
            "make": "",
            "model": "",
            "price": "0.00",
            "size": “XL",
            "sku": null,
            "image": "https:\/\/google.com\/dark_blue_jeans.jpg",
            "new_record": false,
            "category_name": "",
            "bar_code": "",
            "category": null
        }
    ],
    "White Belt": [
        {
            "id": "1536",
            "name": "White Belt",
            "quantity": "37",
            "make": "",
            "model": "",
            "price": "0.00",
            "size": "One Size",
            "sku": null,
            "image": "https:\/\/google.com\/white_belt.jpg",
            "new_record": false,
            "category_name": "",
            "bar_code": "",
            "category": null
        }
    ]
}

What i'm trying to do is take all the items in "Green Shirt", "Dark Blue Jeans" and "White Belt" and put them in this format [[String : AnyObject]]

// 1 - Make the HTTP Request
var endpoint = NSURL(string: "https://www.mycustomsite.com/get-inventory")
var data = NSData(contentsOfURL: endpoint!)


// 2 - Validate and Deserialize the response

if let json: NSDictionary = NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers, error: nil) as? NSDictionary {


}
2

There are 2 best solutions below

1
On BEST ANSWER

The trick is to declare the right type for the cast.

For your data we are using [String: [[String: AnyObject]]]: a dictionary with a String as key and an array of dictionaries as value, these dictionaries have their value as AnyObject because there's several possible types.

After a successful decoding, we print the resulting dictionary (Result 1).

Then, as an example, we loop over the dictionaries contained in the array behind the key "Green Shirt", and display their ID and size.

And as a last example: get an array with all the clothes objects.

if let json = NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.allZeros, error: nil) as? [String: [[String: AnyObject]]] {

    // Result 1
    println(json)

    // Example of how to parse the data
    if let allGreenShirts = json["Green Shirt"] {
        for greenShirt in allGreenShirts {
            if let id = greenShirt["id"] as? String, let size = greenShirt["size"] as? String {
                println("ID \(id) is of size \(size)")
            }
        }
    }

    // If you want an array of all the clothes, populate an array of dictionaries:
    var allClothes = [[String:AnyObject]]()
    for (_, clothes) in json {
        allClothes += clothes
    }

    println(allClothes)

}

Result 1:

[White Belt: [[size: One Size, price: 0.00, category: , make: , model: , image: https://google.com/white_belt.jpg, category_name: , new_record: 0, name: White Belt, sku: , id: 1536, quantity: 37, bar_code: ]], Green Shirt: [[size: XXS, price: 15.00, sku: , name: Nice Green Shirt, id: 740, make: , model: , image: https://google.com/green_shirt.jpg, category_name: , quantity: 0, bar_code: , new_record: 0], [size: XS, price: 20.00, sku: , name: Green Shirt, id: 743, make: , model: , image: https://google.com/green_shirt.jpg, category_name: , quantity: 68, bar_code: , new_record: 0]], Dark Blue Jeans: [[size: S, price: 0.00, category: , make: , model: , image: https://google.com/dark_blue_jeans.jpg, category_name: , new_record: 0, name: Dark Blue Jeans, sku: , id: 1588, quantity: 0, bar_code: ], [size: XL, price: 0.00, category: , make: , model: , image: https://google.com/dark_blue_jeans.jpg, category_name: , new_record: 0, name: Dark Blue Jeans, sku: , id: 1559, quantity: 4, bar_code: ]]]

Example:

ID 740 is of size XXS
ID 743 is of size XS

Array of all clothes:

[[size: One Size, price: 0.00, category: , make: , model: , image: https://google.com/white_belt.jpg, category_name: , new_record: 0, name: White Belt, sku: , id: 1536, quantity: 37, bar_code: ], [size: XXS, price: 15.00, sku: , name: Nice Green Shirt, id: 740, make: , model: , image: https://google.com/green_shirt.jpg, category_name: , quantity: 0, bar_code: , new_record: 0], [size: XS, price: 20.00, sku: , name: Green Shirt, id: 743, make: , model: , image: https://google.com/green_shirt.jpg, category_name: , quantity: 68, bar_code: , new_record: 0], [size: S, price: 0.00, category: , make: , model: , image: https://google.com/dark_blue_jeans.jpg, category_name: , new_record: 0, name: Dark Blue Jeans, sku: , id: 1588, quantity: 0, bar_code: ], [size: XL, price: 0.00, category: , make: , model: , image: https://google.com/dark_blue_jeans.jpg, category_name: , new_record: 0, name: Dark Blue Jeans, sku: , id: 1559, quantity: 4, bar_code: ]]

Note that with our mapping, we can also easily create allClothes with flatMap instead of making a loop:

let allClothes = flatMap(json, { $1 })

So, to conclude, here's our functions included in a class as an example of how you could use it.

class DataManager {

    typealias myJSONDic = [String: [[String: AnyObject]]]

    func getClothesDictionaryFromJSON(data: NSData) -> myJSONDic? {
        if let json = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.allZeros, error: nil) as? myJSONDic {
            return json
        }
        return nil
    }

    func shirtsSizes(json: myJSONDic, category: String) -> [String] {
        var shirts = [String]()
        if let allShirtsInCategory = json[category] {
            for shirt in allShirtsInCategory {
                if let id = shirt["id"] as? String, let size = shirt["size"] as? String {
                    shirts.append("ID \(id) is of size \(size)")
                }
            }
        }
        return shirts
    }

    func getAllClothes(json: myJSONDic) -> [[String: AnyObject]] {
        return flatMap(json, { $1 })
    }

}

let manager = DataManager()
let clothesDictionary = manager.getClothesDictionaryFromJSON(data!)
let greenShirtsSizes = manager.shirtsSizes(clothesDictionary!, category: "Green Shirt")
let allClothes = manager.getAllClothes(clothesDictionary!)

Note that in this class example we've created a typealias for the type of our dictionary, it's more convenient to write and read.

Swift 2 update

class DataManager {

    typealias myJSONDic = [String: [[String: AnyObject]]]

    func getClothesDictionaryFromJSON(data: NSData) -> myJSONDic? {
        do {
            if let json = try NSJSONSerialization.JSONObjectWithData(data, options: []) as? myJSONDic {
                return json
            }
        } catch let error as NSError {
            print(error)
        }
        return nil
    }

    func shirtsSizes(json: myJSONDic, category: String) -> [String] {
        var shirts = [String]()
        if let allShirtsInCategory = json[category] {
            for shirt in allShirtsInCategory {
                if let id = shirt["id"] as? String, let size = shirt["size"] as? String {
                    shirts.append("ID \(id) is of size \(size)")
                }
            }
        }
        return shirts
    }

    func getAllClothes(json: myJSONDic) -> [[String: AnyObject]] {
        return json.flatMap { $1 }
    }

}

let manager = DataManager()
if let data = data, let clothesDictionary = manager.getClothesDictionaryFromJSON(data) {
    let greenShirtsSizes = manager.shirtsSizes(clothesDictionary, category: "Green Shirt")
    let allClothes = manager.getAllClothes(clothesDictionary)
    print(greenShirtsSizes)
    print(allClothes)
}
0
On

Something along these lines would parse the individual items into an array of dictionaries for you:

var items: [[String: AnyObject]] = [] //Create new array
for key in json.keys {
    let group = json[key] as! [[String: AnyObject]] //Get array such as "Green Shirt"

    for item in group {
        items.append(item) //Loop through items and add to new array
    }
}