I'm getting a JSON string that I'd like to clean up a bit and return less data. However, I'm having trouble figuring out how to get the values from the JSON and properly attach it to a data class I've created.
Here is the incoming JSON:
{
"continent": {
"code": "EU",
"names": {
"de": "Europa",
"ru": "Европа",
"pt-BR": "Europa",
"ja": "ヨーロッパ",
"en": "Europe",
"fr": "Europe",
"zh-CN": "欧洲",
"es": "Europa"
},
"geoname_id": 6255148
},
"country": {
"is_in_european_union": true,
"names": {
"de": "Frankreich",
"ru": "Франция",
"pt-BR": "França",
"ja": "フランス共和国",
"en": "France",
"fr": "France",
"zh-CN": "法国",
"es": "Francia"
},
"iso_code": "FR",
"geoname_id": 3017382
},
"city": {
"geoname_id": 2977058,
"names": {
"en": "Saint-Saulve",
"ru": "Сен-Сольв",
"zh-CN": "圣索尔沃"
}
},
"location": {
"accuracy_radius": 10,
"time_zone": "Europe/Paris",
"latitude": 50.3714,
"longitude": 3.5561
},
"postal": {
"code": "59880"
},
"registered_country": {
"is_in_european_union": true,
"names": {
"de": "Frankreich",
"ru": "Франция",
"pt-BR": "França",
"ja": "フランス共和国",
"en": "France",
"fr": "France",
"zh-CN": "法国",
"es": "Francia"
},
"iso_code": "FR",
"geoname_id": 3017382
},
"subdivisions": [
{
"names": {
"fr": "Hauts-de-France",
"en": "Hauts-de-France"
},
"iso_code": "HDF",
"geoname_id": 11071624
},
{
"names": {
"de": "Nord",
"en": "North",
"fr": "Nord",
"es": "Norte"
},
"iso_code": "59",
"geoname_id": 2990129
}
]
}
Data Classes:
data class locationData(val accuracyRadius: String = "", val timeZone: String = "", val latitude: String = "",
val longitude: String = "", val postalCode: String = "", val continent: Continent,
val country: Country, val city: City, val subdivision: Subdivision)
data class Continent(val code: String = "", val name: String = "", val geonameId: String = "")
data class Country(val isEU: Boolean = false, val name: String = "", val isoCode: String = "", val geonameId: String = "")
data class City(val name: String = "", val geonameId: String = "")
data class Subdivision(val name: String = "", val isoCode: String = "", val geonameId: String = "")
My sad attempt at iterating through the json and filtering out the pieces I don't want:
private fun cleanData(data: JsonNode): String {
data.fieldNames().forEachRemaining { field ->
println(field);
}
val result = data.filter { item ->
if (item.has("names")) {
return item.get("names").has("en"); item["name"] = item.get("names").get("en");
}
return item.toString();
}
return "";
/*val continent = {
"code" = data.get("continent").get("code"),
}*/
}
This is what my desired JSON output should be:
{
"accuracy_radius": 10,
"time_zone": "Europe/Paris",
"latitude": 50.3714,
"longitude": 3.5561,
"postalCode": "59880",
"continent": {
"code": "EU",
"name": "Europe",
"geonameId": 6255148
},
"country": {
"isEU": true,
"name": "France",
"isoCode": "FR",
"geonameId": 3017382
},
"city": {
"geonameId": 2977058,
"name": "Saint-Saulve",
},
"subdivisions": [
{
"name": "Hauts-de-France"
"isoCode": "HDF",
"geonameId": 11071624
},
{
"name": "North",
"isoCode": "59",
"geonameId": 2990129
}
]
}
I would suggest using Moshi (https://github.com/square/moshi/) and a custom adapter (see the examples on the github page) to filter/transform your data, when you read them into your data classes. If you have properly filled data objects, you should be able to write your desired JSON without any problems.
Related
I have json data but i need to convert the json to Map in dart/flutter.
The json data is :
{"kabupaten": [
{
"jec_kabupaten_id": "71",
"jec_propinsi_id": "8",
"name": "Aceh Barat"
},
{
"jec_kabupaten_id": "76",
"jec_propinsi_id": "8",
"name": "Aceh Barat Daya"
},
{
"jec_kabupaten_id": "91",
"jec_propinsi_id": "9",
"name": "Medan"
},
{
"jec_kabupaten_id": "92",
"jec_propinsi_id": "9",
"name": "Sinabung"
}
]}
I want to convert to this Map with dart/flutter:
{
"8":{
"71":"Aceh Barat",
"76":"Aceh Barat Daya",
"68":"Aceh Besar"
},
"9":{
"91":"Medan",
"92":"Sinabung"
}
}
It is possible to transform the data using fold for example.
void main() {
const data = {
"kabupaten": [
{
"jec_kabupaten_id": "71",
"jec_propinsi_id": "8",
"name": "Aceh Barat",
},
{
"jec_kabupaten_id": "76",
"jec_propinsi_id": "8",
"name": "Aceh Barat Daya",
},
{
"jec_kabupaten_id": "91",
"jec_propinsi_id": "9",
"name": "Medan",
},
{
"jec_kabupaten_id": "92",
"jec_propinsi_id": "9",
"name": "Sinabung",
},
],
};
final result = data['kabupaten']?.fold<Map<String, Map<String, String>>>(
{},
(prev, elem) => prev
..[elem['jec_propinsi_id']!] ??= {}
..[elem['jec_propinsi_id']!]![elem['jec_kabupaten_id']!] = elem['name']!,
);
print(result);
}
An alternative would be to build up the result in a for loop:
final result = <String, Map<String, String>>{};
for (final elem in data['kabupaten'] ?? []) {
result[elem['jec_propinsi_id']!] ??= {};
result[elem['jec_propinsi_id']!]![elem['jec_kabupaten_id']!] = elem['name']!;
}
This the method I used to fetch the data from an api and then assigning them to a model.
var headers = {
'API-Key': 'TEST_f+y9/tHG+yVxEq3uS3H1ogfezHSCWSq5MsIXUOnIV+Q',
'Content-Type': 'application/json',
};
var data = '"shipment": {
"validate_address": "no_validation",
"ship_to": {
"name": "Amanda Miller",
"phone": "555-555-5555",
"address_line1": "525 S Winchester Blvd",
"city_locality": "San Jose",
"state_province": "CA",
"postal_code": "95128",
"country_code": "US",
"address_residential_indicator": "yes"
},
"ship_from": {
"company_name": "Example Corp.",
"name": "John Doe",
"phone": "111-111-1111",
"address_line1": "4009 Marathon Blvd",
"address_line2": "Suite 300",
"city_locality": "Austin",
"state_province": "TX",
"postal_code": "78756",
"country_code": "US",
"address_residential_indicator": "no"
},
"packages": [
{
"weight": {
"value": 1.0,
"unit": "ounce"
}
}
]
}
}';
final response = await http.post('https://api.shipengine.com/v1/rates', headers: headers, body: data);
if (response.statusCode == 200) {
String responseBody = response.body;
var data = json.decode(responseBody);
print(data);
print(data["rate_response"]["rates"]);
ResRate rates = new ResRate.fromJson(data);
print(rates.rates[0].amount);
} else {
print(response.statusCode);
print(response.body);
}
}
The is model.dart
// Amount amount;
List<Rates> rates;
ResRate({
// this.amount,
this.rates});
factory ResRate.fromJson(Map<String, dynamic> parsedJson){
var list = parsedJson['rates'] as List;
List<Rates> rates = list.map((i) => Rates.fromJson(i)).toList();
return ResRate(
// amount: Amount.fromJson(parsedJson['amount']),
rates: rates
);
}
}
class Amount{
var currency;
String amount;
Amount({this.currency,
this.amount});
factory Amount.fromJson(Map<String, dynamic> parsedJson){
return Amount(
currency: parsedJson['currency'],
amount : parsedJson['amount'],
);
}
}
class Rates{
var rate_id;
var rate_type;
var carrier_id;
Amount amount;
//List<Amount> shipping_amount;
Rates({
this.rate_id, this.amount,
this.rate_type, this.carrier_id,
});
factory Rates.fromJson(Map<String, dynamic> parsedJson){
// var list = parsedJson['images'] as List;
// List<Image> images = list.map((i) => Image.fromJson(i)).toList();
return Rates(
rate_id: parsedJson['rate_id'],
rate_type: parsedJson['rate_type'],
carrier_id: parsedJson['carrier_id'],
amount: Amount.fromJson(parsedJson['shipping_amount']),
);
}
}
But I'm getting error like this in my console.
Unhandled Exception: NoSuchMethodError: The method 'map' was called on
null
which points toward the model code below
var list = parsedJson['rates'] as List;
List<Rates> rates = list.map((i) => Rates.fromJson(i)).toList();
I tried printing the response body and the response body is fetched successfully and prints in the console.The object rates is also fetched in the response. But appears null .As This response is a complex one , rates too has objects.Here's the response fetched from the api.
"rate_response": {
"rate_request_id": 501834,
"shipment_id": "se-2127183",
"status": "completed",
"created_at": "2019-07-26T22:10:50.286Z",
"rates": [
{
"rate_id": "se-11744390",
"rate_type": "shipment",
"carrier_id": "se-123890",
"shipping_amount": {
"currency": "usd",
"amount": 9.37
},
"insurance_amount": {
"currency": "usd",
"amount": 0.00
},
"confirmation_amount": {
"currency": "usd",
"amount": 0.00
},
"other_amount": {
"currency": "usd",
"amount": 0.00
},
"delivery_days": 3,
"guaranteed_service": false,
"estimated_delivery_date": "2019-07-26T05:00:00.000Z",
"carrier_delivery_days": "Friday by 11:00 PM",
"ship_date": "2019-07-26T05:00:00.000Z",
"negotiated_rate": false,
"service_type": "UPS® Ground",
"service_code": "ups_ground",
"trackable": true,
"validation_status": "valid",
"warning_messages": [],
"error_messages": [],
"carrier_code": "ups",
"carrier_nickname": "UPS-28A1R9",
"carrier_friendly_name": "UPS"
}
],
"invalid_rates": []
},
"shipment_id": "se-2127183",
"carrier_id": "",
"external_shipment_id": null,
"ship_date": "2019-07-26T05:00:00.000Z",
"created_at": "2019-07-26T22:10:50.286Z",
"modified_at": "2019-07-26T22:10:50.286Z",
"shipment_status": "pending",
"ship_to": {
"name": "Amanda Miller",
"phone": "555-555-5555",
"address_line1": "525 S Winchester Blvd",
"city_locality": "San Jose",
"state_province": "CA",
"postal_code": "95128",
"country_code": "US",
"address_residential_indicator": "yes"
},
"ship_from": {
"company_name": "Example Corp.",
"name": "John Doe",
"phone": "111-111-1111",
"address_line1": "4009 Marathon Blvd",
"address_line2": "Suite 300",
"city_locality": "Austin",
"state_province": "TX",
"postal_code": "78756",
"country_code": "US",
"address_residential_indicator": "no"
},
"return_to": {
"company_name": "Example Corp.",
"name": "John Doe",
"phone": "111-111-1111",
"address_line1": "4009 Marathon Blvd",
"address_line2": "Suite 300",
"city_locality": "Austin",
"state_province": "TX",
"postal_code": "78756",
"country_code": "US",
"address_residential_indicator": "no"
},
"confirmation": "none",
"advanced_options": {
"bill_to_account": null,
"bill_to_country_code": null,
"bill_to_party": null,
"bill_to_postal_code": null,
"contains_alcohol": false,
"custom_field1": null,
"custom_field2": null,
"custom_field3": null,
"non_machinable": false,
"saturday_delivery": false
},
"insurance_provider": "none",
"tags": [],
"total_weight": {
"value": 1.00,
"unit": "ounce"
},
"packages": [
{
"weight": {
"value": 1.00,
"unit": "ounce"
},
"dimensions": {
"unit": "inch",
"length": 0.0,
"width": 0.0,
"height": 0.0
},
"insured_value": {
"currency": "usd",
"amount": 0.0
}
}
]
}
I found a fix myself turns out I needed to add the sublist and the object header from the array while mapping in the model.
\\replace this
var list = parsedJson['rates'] as List;
\\with this
var list = parsedJson["rate_response"]['rates'] as List;
List<Rates> rates = list.map((i) => Rates.fromJson(i)).toList();
[
{
"name": "ITEM-1",
"desc": "DESCRIPTION",
"listNo" :"0"
},
{
"name": "ITEM-2",
"desc": "DESCRIPTION",
"listNo" :"0"
},
{
"name": "ITEM-3",
"desc": "DESCRIPTION",
"listNo" :"0"
},
{
"name": "ITEM-4",
"desc": "DESCRIPTION",
"listNo" :"1"
},
{
"name": "ITEM-5",
"desc": "DESCRIPTION",
"listNo" :"1"
},
{
"name": "ITEM-6",
"desc": "DESCRIPTION",
"listNo" :"1"
}
]
How to implement this model in futter? I want to show the two lists as shown in and data from JSON above.
The condition for LIST-A is "listNo"="0" and for LIST-B is "listNo"="1".
There are multiple ways to do it but I think the most easiest to understand solution would be to do the following:
import 'dart:convert';
void main() {
const input = '''
[
{
"name": "ITEM-1",
"desc": "DESCRIPTION",
"listNo" :"0"
},
{
"name": "ITEM-2",
"desc": "DESCRIPTION",
"listNo" :"0"
},
{
"name": "ITEM-3",
"desc": "DESCRIPTION",
"listNo" :"0"
},
{
"name": "ITEM-4",
"desc": "DESCRIPTION",
"listNo" :"1"
},
{
"name": "ITEM-5",
"desc": "DESCRIPTION",
"listNo" :"1"
},
{
"name": "ITEM-6",
"desc": "DESCRIPTION",
"listNo" :"1"
}
]
''';
final list1 = <Map<String, dynamic>>[];
final list2 = <Map<String, dynamic>>[];
for (final map in json.decode(input)) {
if (map['listNo'] == '0') {
list1.add(map as Map<String, dynamic>);
} else {
list2.add(map as Map<String, dynamic>);
}
}
print(list1);
// [{name: ITEM-1, desc: DESCRIPTION, listNo: 0}, {name: ITEM-2, desc: DESCRIPTION, listNo: 0}, {name: ITEM-3, desc: DESCRIPTION, listNo: 0}]
print(list2);
// [{name: ITEM-4, desc: DESCRIPTION, listNo: 1}, {name: ITEM-5, desc: DESCRIPTION, listNo: 1}, {name: ITEM-6, desc: DESCRIPTION, listNo: 1}]
}
Alternative you could also do the following if you think that looks more clear:
final parsedJson = json.decode(input) as List<dynamic>;
final list1 = [
...parsedJson
.cast<Map<String, dynamic>>()
.where((map) => map['listNo'] == '0')
];
final list2 = [
...parsedJson
.cast<Map<String, dynamic>>()
.where((map) => map['listNo'] == '1')
];
I am trying to map an array of objects using Object Mapper
I have this code so far, and my mapping is not successful
do {
if let data = data, let sectorData = Mapper<SubSectorsModel>().mapArrayOfArrays(JSONObject: try JSONSerialization.data(withJSONObject: data, options: [])) {
completionHandler(sectorData,(response as! HTTPURLResponse), error)
print("SectionData Received Successfully")
}
} catch {
completionHandler(nil,(response as! HTTPURLResponse), error)
print("Error parsing json get sector data: ", error.localizedDescription)
}
My Json data is as follows:
[
{
"SECTOR_NAME": "MANUFACTURERS",
"ID": "8",
"SECTOR": [
{
"ID": "144",
"NAME": "Biomass Processing"
},
{
"ID": "8",
"NAME": "Servicing engines and motors"
},
{
"ID": "23",
"NAME": "Furniture & fittings"
},
{
"ID": "31",
"NAME": "Fabrics & textiles"
},
{
"ID": "20",
"NAME": "Hand and machine tools"
},
{
"ID": "28",
"NAME": "Safety and security products"
},
{
"ID": "147",
"NAME": "Jewellery"
},
{
"ID": "156",
"NAME": "Beverages"
},
{
"ID": "165",
"NAME": "Stationery"
},
{
"ID": "9",
"NAME": "Industrial equipment"
},
{
"ID": "25",
"NAME": "Cleaning equipment"
},
{
"ID": "33",
"NAME": "Household consumer products"
},
{
"ID": "162",
"NAME": "Paper Products"
},
{
"ID": "170",
"NAME": "Memoribilia"
},
{
"ID": "143",
"NAME": "Food Products"
},
{
"ID": "22",
"NAME": "Automotive aviation marine and rail products"
},
{
"ID": "30",
"NAME": "Household appliances"
},
{
"ID": "151",
"NAME": "Iron Sheet"
},
{
"ID": "167",
"NAME": "Cosmetics"
},
{
"ID": "11",
"NAME": "Fuel Lubricants & Detergents"
},
{
"ID": "19",
"NAME": "Electrical appliances and equipment"
},
{
"ID": "27",
"NAME": "Packaging products"
},
{
"ID": "7",
"NAME": "Engines & parts"
},
{
"ID": "24",
"NAME": "Glass products"
},
{
"ID": "32",
"NAME": "Clothing & footwear"
},
{
"ID": "152",
"NAME": "Building Material"
},
{
"ID": "142",
"NAME": "Food Processing and Packaging"
},
{
"ID": "21",
"NAME": "Plastic products"
},
{
"ID": "29",
"NAME": "Pool & garden products"
},
{
"ID": "157",
"NAME": "Steel Products"
},
{
"ID": "138",
"NAME": "Optical Prescription Lenses"
},
{
"ID": "10",
"NAME": "Servicing & refurbishing"
},
{
"ID": "18",
"NAME": "Chemical"
},
{
"ID": "26",
"NAME": "Board paper and"
}
]
},
.
.
.
]
If you just want to send completionHandler anyway, use code below:
struct MyJsonStruct : Decodable {
struct SectorStruct : Decodable {
var ID : String
var NAME : String
}
var SECTOR_NAME : String
var ID : String
var SECTOR : [SectorStruct]
}
func handle(_ data : Data ) {
do {
let sectorData = try JSONDecoder().decode(MyJsonStruct.self, from: data) as MyJsonStruct
let yourArray = sectorData.SECTOR // if you need an array result
completionHandler(sectorData,(response as! HTTPURLResponse), error)
print("SectionData Received Successfully")
} catch {
completionHandler(nil,(response as! HTTPURLResponse), error)
print("Error parsing json get sector data: ", error.localizedDescription)
}
}
I have the following multiple json objects to post data using Alamofire. In which format I need to pass the parameters in swift. I am new to swift . Help me out.
{
"refno": "",
"ddesc": "",
"free": "0",
"fgift": "",
"sgift": "",
"sandage": {
"bank": "",
"bag": ""
},
"inst": "",
"items": [{
"itemid": "606",
"qty": "1",
"sub": [{
"item": "1586",
"qty": "1",
"type": "addon",
"ext": ""
}, {
"item": "1588",
"qty": "1",
"type": "addon",
"ext": ""
}, {
"item": "1589",
"qty": "1",
"type": "addon",
"ext": ""
}, {
"item": "1590",
"qty": "1",
"type": "addon",
"ext": ""
}]
}, {
"itemid": "639",
"qty": "1",
"sub": [{
"item": "1618",
"qty": "1",
"type": "addon",
"ext": ""
}, {
"item": "1612",
"qty": "1",
"type": "addon",
"ext": ""
}, {
"item": "1611",
"qty": "1",
"type": "addon",
"ext": ""
}, {
"item": "1610",
"qty": "1",
"type": "addon",
"ext": ""
}]
}],
"discount": "0",
"coupon": [],
"delivery": "",
"user": {
"id": "13",
"fname": "Demo",
"lname": "Order",
"phone": "9876543210",
"dno": "",
"add1": "",
"add2": "",
"postcode": "",
"username": "demo#theepos.com",
"status": "1"
},
"otype": "1",
"ptype": "0",
"app_id": "A1A2A3A4",
"app_key": "K1K2K3K4",
"request": "placeorder"
}
I am using Alamofire to post the data..
var url: NSURL = NSURL(string: "http://\(platform).eposapi.co.uk")!
let params = [
"refno": "",
"ddesc": "",
"free": "0",
"fgift": "",
"sgift": "",
.....
]
Alamofire.request(.POST, url, parameters: params, encoding: .JSON)
.responseJSON{ response in
if let result: AnyObject = response.result.value
{
let post: JSON = JSON(result)
}
}
Really thanks guys . I only followed the above commented instructions and got the answer. Help really appreciated
var url: NSURL = NSURL(string: "http://\(platform).eposapi.co.uk")!
let sandage = ["bank": "","bag": ""]
let sub_array = [ "item": "1586","qty": "1","type": "addon","ext": ""]
let items_array = ["itemid": "606","qty": "1","sub": sub_array ]
let user_Detail = ["id": "13","fname": "Demo","lname": "Order",
"phone": "9876543210","dno": "","add1": "",
"add2": "","postcode": "","username": "demo#theepos.com",
"status": "1"]
let params = [
"refno": "",
"ddesc": "",
"free": "0",
"fgift": "",
"sgift": "",
"sandage": sandage,
"inst": "",
"items":items_array,
"discount": "0",
"coupon": [],
"delivery": "",
"user": user_Detail,
"otype": "1",
"ptype": "0",
"app_id": "A1A2A3A4",
"app_key": "K1K2K3K4",
"request": "placeorder"
]
Alamofire.request(.POST, url, parameters: params, encoding: .JSON)
.responseJSON{ response in
if let result: AnyObject = response.result.value
{
let post: JSON = JSON(result)
let status = post["status"].stringValue
let order_id = post["order_id"].stringValue
print(status)
print(order_id)