Swift 4 codable: the keys are Int array in JSON data - json

{
"0": {
"name": "legaldoc.pdf",
"cmisid": "yib5C-w92PPtxTBlXl4UJ8oDBthDtAU9mKN5kh2_KrQ"
},
"1": {
"name": "persdoc.pdf",
"cmisid": "dqAnrdNMXGTz1RbOMI37OY6tH9xMdxiTnz6wEl2m-VE"
},
"2": {
"name": "certdoc.pdf",
"cmisid": "6d7DuhldQlnb0JSjXlZb9mMOjxV3E_ID-ynJ0QRPMOA"
}
}
How do I use Swift 4 Codable to parse JSON data like that? the problem is that the keys are Int array.
How do I set CodingKeys for this?

As mentioned in the comments there is no array. All collection types are dictionaries.
You can decode it as Swift dictionary. To get an array map the result to the values of the sorted keys
let jsonString = """
{
"0": {
"name": "legaldoc.pdf",
"cmisid": "yib5C-w92PPtxTBlXl4UJ8oDBthDtAU9mKN5kh2_KrQ"
},
"1": {
"name": "persdoc.pdf",
"cmisid": "dqAnrdNMXGTz1RbOMI37OY6tH9xMdxiTnz6wEl2m-VE"
},
"2": {
"name": "certdoc.pdf",
"cmisid": "6d7DuhldQlnb0JSjXlZb9mMOjxV3E_ID-ynJ0QRPMOA"
}
}
"""
struct Item : Codable {
let name, cmisid : String
}
do {
let data = Data(jsonString.utf8)
let result = try JSONDecoder().decode([String: Item].self, from: data)
let keys = result.keys.sorted()
let array = keys.map{ result[$0]! }
print(array)
} catch {
print(error)
}

Related

Load JSON in SwiftUI with arbitrary keys

I have a pretty simple JSON file I would like to load into a SwiftUI project. The JSON file looks like this:
{
"all": ["foo", "bar", "baz", ...],
"4": ["asd", "qwe", ...],
"25": ["something", "another", ...],
...
"2": ["xxx", "yyy", ...]
}
Pretty simple, a dictionary where each value is a list of strings. The keys are "all" and then an arbitrary number of integers such as "1", "123" and so on. They must not be in order, they can be any number, and there may be any number of them. So I don't know before hand how many keys there are.
I have managed to get this JSON into a variable of type String. But now I am stuck with how to parse this so I can for example fetch the list at key "all", or check if the key "123" exists and if so get that list.
How do I do that in SwiftUI?
Oh, and by the way, the string are Unicode and contain special characters like åäö.
try this approach:
struct ContentView: View {
#State var dataList: [String:[String]] = [:]
var body: some View {
List(Array(dataList.keys), id: \.self) { key in
Section(header: Text(key).foregroundColor(.red).font(.headline)) {
if let values = dataList[key] {
ForEach(values, id: \.self) { item in
Text("\(item)")
}
}
}
}
.onAppear {
let json = """
{
"all": ["foo", "bar", "baz"],
"4": ["asd", "qwe"],
"25": ["something", "another"],
"2": ["xxx", "yyy", "åäö"],
"åäö": ["qwerty", "uiop", "dfghjkh"]
}
"""
if let data = json.data(using: .utf8) {
do {
self.dataList = try JSONDecoder().decode([String: [String]].self, from: data)
} catch {
print("decode error: \(error)")
}
}
}
}
}

How to serialize JSON string to multidimensional NSDictionary

"[{\"person\":\"person1\",\"data\":{\"age\":\"10\",\"name\":\"John\"}},
{\"person\":\"person2\",\"data\":{\"age\":\"20\",\"name\":\"Jonathan\"}},
{\"person\":\"person3\",\"data\":{\"age\":\"30\",\"name\":\"Joe\"}}]"
Note that the value "data" is also a dictionary.
I have a JSON string like above and am trying to serialize like:
if let dataFromString = conf.data(using: .utf8, allowLossyConversion: false) {
let json = try JSON(data: dataFromString)
configuration = json.dictionary ?? [:]
}
However configuration is always an empty dictionary.
You need to parse the JSON you've as an array of dictionaries of type [[String: Any]]. The better modern approach is to use Decodable model to decode the JSON.
let string = """
[
{
"person": "person1",
"data": {
"age": "10",
"name": "John"
}
},
{
"person": "person2",
"data": {
"age": "20",
"name": "Jonathan"
}
},
{
"person": "person3",
"data": {
"age": "30",
"name": "Joe"
}
}
]
"""
let data = Data(string.utf8)
struct Person: Decodable {
let person: String
let data: PersonData
}
struct PersonData: Decodable {
let age, name: String
}
do {
let people = try JSONDecoder().decode([Person].self, from: data)
print(people)
} catch { print(error) }
For the JSON String,
let conf = "[{\"person\":\"person1\",\"data\":{\"age\":\"10\",\"name\":\"John\"}},{\"person\":\"person2\",\"data\":{\"age\":\"20\",\"name\":\"Jonathan\"}},{\"person\":\"person3\",\"data\":{\"age\":\"30\",\"name\":\"Joe\"}}]"
use JSONSerialization's jsonObject(with:options:) method to get the expected response.
if let conf = str.data(using: .utf8 ) {
do {
let dict = try JSONSerialization.jsonObject(with: data, options: []) as? [[String:Any]]
print(dict)
} catch {
print(error)
}
}

Order of JSON node changes while making POST request Swift

I was trying to post the following jSON body
request JSON :
let parameters = [
"createTransactionRequest": [
"merchantAuthentication": [
"name": "xxxxxxxx",
"transactionKey": "xxxxxxxxx"
],
"refId": "123456",
"transactionRequest": [
"transactionType": "authCaptureTransaction",
"amount": "5",
"payment": [
"opaqueData": [
"dataDescriptor": desc!,
"dataValue": tocken!
]
]
]
]
]
When I am trying to print(parameters) the order of node changes it looks like
["createTransactionRequest":
["refId": "123456",
"transactionRequest":
["payment": ["opaqueData": ["dataDescriptor": "COMMON.ACCEPT.INAPP.PAYMENT", "dataValue": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx="]],
"transactionType": "authCaptureTransaction",
"amount": "5"],
"merchantAuthentication": ["name": "xxxxxxx", "transactionKey":
"6gvE46G5seZt563w"]
]
]
I am getting response like
{ messages = {
message = (
{
code = E00003;
text = "The element 'createTransactionRequest' in namespace
'AnetApi/xml/v1/schema/AnetApiSchema.xsd' has invalid child element
'refId' in namespace 'AnetApi/xml/v1/schema/AnetApiSchema.xsd'. List of
possible elements expected: 'merchantAuthentication' in namespace
'AnetApi/xml/v1/schema/AnetApiSchema.xsd'.";
}
);
resultCode = Error;
};
}
This is really annoying. anyones help will be highly grateful.
You need to change your data structure as follow:
struct Transaction: Codable {
let createTransactionRequest: CreateTransactionRequest
}
struct CreateTransactionRequest: Codable {
let merchantAuthentication: MerchantAuthentication
let refId: String
let transactionRequest: TransactionRequest
}
struct MerchantAuthentication: Codable {
let name: String
let transactionKey: String
}
struct TransactionRequest: Codable {
let transactionType: String
let amount: String
let payment: Payment
}
struct Payment: Codable {
let opaqueData: OpaqueData
}
struct OpaqueData: Codable {
let dataDescriptor: String
let dataValue: String
}
Testing
let json = """
{ "createTransactionRequest":
{ "merchantAuthentication":
{ "name": "YOUR_API_LOGIN_ID",
"transactionKey": "YOUR_TRANSACTION_KEY"
},
"refId": "123456",
"transactionRequest":
{ "transactionType": "authCaptureTransaction",
"amount": "5",
"payment":
{ "opaqueData":
{ "dataDescriptor": "COMMON.ACCEPT.INAPP.PAYMENT",
"dataValue": "PAYMENT_NONCE_GOES_HERE"
}
}
}
}
}
"""
let jsonData = Data(json.utf8)
do {
let transaction = try JSONDecoder().decode(Transaction.self, from: jsonData)
print(transaction)
// encoding
let encodedData = try JSONEncoder().encode(transaction)
print(String(data: encodedData, encoding: .utf8)!)
} catch {
print(error)
}
{"createTransactionRequest":{"merchantAuthentication":{"name":"YOUR_API_LOGIN_ID","transactionKey":"YOUR_TRANSACTION_KEY"},"refId":"123456","transactionRequest":{"transactionType":"authCaptureTransaction","amount":"5","payment":{"opaqueData":{"dataValue":"PAYMENT_NONCE_GOES_HERE","dataDescriptor":"COMMON.ACCEPT.INAPP.PAYMENT"}}}}}

How to parse JSON in Swift?

I have some JSON data that looks like this which I am trying to parse in Swift.
[
[
{
a: "1",
b: "2"
},
[
{
c: "3",
},
{
d: "4",
}
]
]
]
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: .AllowFragments)
if let myArray = json[0] as? [[AnyObject]] {
for myObject in myArray {
print("This works!\(myObject)")
}
}
However nothing I try seems to work - any help would be appreciated.
you can use SwiftyJSON - https://github.com/SwiftyJSON/SwiftyJSON
or create a class based on your JSON scheme try to parse with it.
like:
class object
{
let data = Array<subObject>()
}
class subObject
{
let subData = Array<Dictionary<AnyObject,AnyObject>>()
}
This snippet is not JSON. If it was JSON, the keys would be strings, like this:
[
[
{
"a": "1",
"b": "2"
},
[
{
"c": "3",
},
{
"d": "4",
}
]
]
]
And anyway in your screenshot we see that your JSON has already been parsed!
What you show in the image is not JSON either, but an array containing arrays and dictionaries...
But let's say your JSON is actually valid and the missing quotes are just a copy/paste problem.
Then to achieve your goal you have to cast the result of NSJSONSerialization to the correct JSON format, then you can access the inner objects.
Like this, for example:
do {
if let json = try NSJSONSerialization.JSONObjectWithData(data!, options: []) as? [[AnyObject]] {
if let myArray = json.first {
for myObject in myArray {
print("This works!\(myObject)")
}
}
}
} catch let error as NSError {
print(error.localizedDescription)
}

Can't access JSON using SwiftyJSON

I am trying to access the JSON that I get via Alamofire:
func getDataFromServer() {
Alamofire.request(.POST, websiteURL, parameters: myParameters) .responseString {
(response) -> Void in
if let value = response.result.value {
let json = JSON(value)
self.parseJSON(json)
}
}
}
,and the JSON that is being returned to me looks something like this:
{
"status":"success",
"object":[
{
"name":"Bob",
"age":"20 ",
},
{
"name": "Jane",
"age":"25"
},
]
}
and I am using SwiftyJSON to access the names:
func parseJSON(json: JSON) {
for result in json["object"].arrayValue {
print(result["name"].stringValue)
}
}
but it is not printing anything. Am I doing something wrong?
responseJSON should be used instead of responseString
Your JSON is invalid
{
"status": "success",
"object": [
{
"name": "Bob",
"age": "20 ",
},
{
"name": "Jane",
"age": "25"
}, <--Delete this comma
]
}
Managed to figure out what was wrong with my code. When I did a POST request using Alamofire, I was returning the data back as a string: .responseString instead of JSON: .responseJSON
working code:
func getDataFromServer() {
Alamofire.request(.POST, websiteURL, parameters: myParameters) .responseJSON {
(response) -> Void in
if let value = response.result.value {
let json = JSON(value)
self.parseJSON(json)
}
}
}
Replace responseString with responseJSON