问题
Is it possible to deserialize a json with dynamic key but structured values into Map in flutter dart.
I am having a json like
{
"data" : {
"apple":{"qty":5, "price":100},
"orange":{"qty":2, "price":40},
}
}
And I want this to deserialize in flutter/dart to a model class below
class Data {
Map<String, Item> itemMap;
factory Data.fromJson(Map<String,dynamic> json) {
itemMap : json["data"]; //How to parse.
}
}
class Item {
int qty;
int price;
}
I have read through a medium blog and even this also not covering the Map part.
回答1:
I have a similar JSON with a few changes:
{
"sub_item": {
"491": ["92837|1.3|Pistachio|right", "92838|2.5|Hazelnut|left"],
"427": ["92839|7.05|Almonds|", "92840|5.12|Walnuts|"],
"396": ["92841|15|Saffron|"],
"275": ["92842|45|Caviar|"]
}
}
The keys of sub_item
map (491, 427, 396, 275, and...) are dynamic(as a label not as a type) and will change per order. For example, it will be 376, 325, 493... in another order.
I want to shows both keys and values on my Flutter app and do not know how to fetch these data and show them separately. Something like this:
491:
£1.30 Pistachio
£2.50 Hazelnut
427:
£7.05 Almonds
£5.12 Walnuts
396:
£15.00 Saffron
275:
£45.00 Caviar
I used this code and it worked for me somehow but it shows only the first item of the lists. for example, it shows only Pistachio for 491 not Hazelnut and the same it shows only Almonds for 427 not Walnuts:
Future<List<ItemModel>> fetchFood() async {
List<ItemModel> foodItemsList = [];
final response = {
"sub_item": {
"491": ["92837|1.3|Pistachio|right", "92838|2.5|Hazelnut|left"],
"427": ["92839|7.05|Almonds|", "92840|5.12|Walnuts|"],
"396": ["92841|15|Saffron|"],
"275": ["92842|45|Caviar|"]
}
};
final parsedJson = response['sub_item'];
parsedJson.forEach((fruitName, fruitDetails) =>
foodItemsList.add(ItemModel.fromJson(fruitName, fruitDetails)));
return foodItemsList;
}
// Item model
class ItemModel {
String id;
String details;
ItemModel.fromJson(String subItemID, List<dynamic> subItemDetails)
: id = subItemID,
details = subItemDetails[0];
}
// Then call it
mainTest() async {
List<ItemModel> foodItemsList = await fetchFood();
for (var i = 0, j = 0;
i < foodItemsList.length;
j < foodItemsList[i].details.length, i++, j++) {
print(foodItemsList[i].id);
print(foodItemsList[j].details.split('|')[2]);
}
}
The console result:
flutter: 491
flutter: Pistachio
flutter: 427
flutter: Almonds
flutter: 396
flutter: Saffron
flutter: 275
flutter: Caviar
回答2:
You need to do something like this:
//...
Future<List<ItemModel>> fetchFood() async {
List<ItemModel> foodItemsList = [];
// Get json response and parse it as a Map<String, dynamic>
final response = {
"data" : {
"apple":{"qty":5, "price":100},
"orange":{"qty":2, "price":40},
}
};
// with your real get request use this:
// final parsedJson = json.decode(response.body)['data'];
// Parsed Json have what's inside data, in case of real request look for the line above this.
final parsedJson = response['data'];
// Iterate over all fruits and create Item object from each,
// then push to a list of Item's objects to return it.
parsedJson.forEach((k,v) => foodItemsList.add(ItemModel.fromJson(v)));
return foodItemsList;
}
// Item model
class ItemModel {
int qty;
int price;
ItemModel.fromJson(Map<String,dynamic> parsedJson)
: qty = parsedJson['qty'],
price = parsedJson['price'];
}
// Then call it
main() async {
List<ItemModel> foodItemsList = await fetchFood();
//..
}
If you need the fruit name as part of the object:
//...
Future<List<ItemModel>> fetchFood() async {
List<ItemModel> foodItemsList = [];
// Get json response and parse it as a Map<String, dynamic>
final response = {
"data" : {
"apple":{"qty":5, "price":100},
"orange":{"qty":2, "price":40},
}
};
// with your real get request use this:
// final parsedJson = json.decode(response.body)['data'];
// Parsed Json have what's inside data, in case of real request look for the line above this.
final parsedJson = response['data'];
// Iterate over all fruits and create Item object from each,
// then push to a list of Item's objects to return it.
parsedJson.forEach((fruitName, fruitDetails)
=> foodItemsList.add(
ItemModel.fromJson(fruitName, fruitDetails)
)
);
return foodItemsList;
}
// Item model
class ItemModel {
String name;
int qty;
int price;
ItemModel.fromJson(String fruitName, Map<String,dynamic> parsedJson)
: name = fruitName,
qty = parsedJson['qty'],
price = parsedJson['price'];
}
// Then call it
main() async {
List<ItemModel> foodItemsList = await fetchFood();
print(foodItemsList[1].name); //orange
//..
}
回答3:
I found a way to achieve it. We can convert the Map from one type to another.
class Data {
Map<String, Item> itemMap;
factory Data.fromJson(Map<String,dynamic> json) {
itemMap : getMapDataFrom(json["data"]); //How to parse.
}
static Map<String, Item> getFruitItemMap(Map<String, dynamic> map) {
final Map<String, Item> fruitItemMap = HashMap();
map.forEach((name, value) {
bitItemLites[name] = Item.fromJson(value, name);
});
return bitItemLites;
}
}
class Item {
int qty;
int price;
factory Item.fromJson(Map<String,dynamic> json) {
return Item(json['qty'], json['price']);
}
}
来源:https://stackoverflow.com/questions/57976532/flutter-dart-deserialize-a-json-with-dynamic-key-but-structured-values-into-map