Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handling JSON where top level structure is an array not a dictionary #106

Closed
tomasebrennan opened this issue Apr 13, 2017 · 5 comments
Closed

Comments

@tomasebrennan
Copy link

Hello,

Very interested in using Marshal however I'm not sure how best to handle JSON where the top level structure is an array rather than a dictionary.

We have some JSON that looks like this:

 [
  {
  "id": "111",
  "firstname":"John",
  "surname": "Doe"
  }, {
  "id": "222",
  "firstname":"Jane",
  "surname": "Doe"
}
]

We would like to be able to map this directly into say an array of Users where User conforms to Unmarshaling i.e.

struct User: Unmarshaling {
    var id: Int
    var firstname: String
    var surname: String

    init(object: MarshaledObject) throws {
        id = try object.value(for: "id")
        firstname = try object.value(for: "firstname")
        surname = try object.value(for: "surname")
    }
}

However the library seems to always need a key in order to create the unmarshaled object. The only way I can see to do this now is to have something like:

var jsonObjects: [JSONObject] = try! JSONParser.JSONArrayWithData(data)
    for obj in jsonObjects {
         let user = User()
         user.id = try obj.value("id")
         user.firstname = try obj.value("firstname")
        user.surname = try obj.value("surname")
    }

This does not seem as elegant as being able to create the array of users directly i.e.

let users: [User] = try json.value("users")

What is the best way of handling this kind of JSON format using Marshal?

Thanks

@stevenkramer
Copy link

@tomasebrennan not sure if this will work, but I had a similar problem. In my case I found it was simply not (very clearly) documented, but well-supported. Construct top-level objects right from their dictionary/array representations using init(object:) or value(from:)

let json = (try? JSONSerialization.jsonObject(with: document, options: JSONSerialization.ReadingOptions()))  as? NSDictionary,
let topLevelObject = try? ObjectResponse(object: json)
....
let topLevelArray = try? [ArrayElement].value(from: json, discardingErrors: false)

@jarsen
Copy link
Member

jarsen commented Apr 17, 2017

This case is a little awkward: Marshal really is designed for dealing with JSON objects, and not JSON Arrays.

One way to deal with this is to put your array inside and object, and then extract it.

let object = { "users": jsonObjects }
let users: [User] = try object.value(for: "users")

You can also use the handy discardingErrors: flag as @stevenkramer mentions, which means you will end up with an array of values without the invalid items, rather than the entire expression throwing an error when one of the array's elements doesn't match the defined schema.

@bwhiteley
Copy link
Contributor

I usually map it with one or two lines. An example can be seen in #85.

@tomasebrennan
Copy link
Author

Thanks I'll stick with @jarsen solution for now.

@jarsen
Copy link
Member

jarsen commented Apr 22, 2017

I'm going to go ahead and close this. Be sure to let us know if you have more questions.

@jarsen jarsen closed this as completed Apr 22, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants