Flutter Dart десериализует json с динамическим ключом, но структурированными значениями в Map <String, ModelClass>

Можно ли десериализовать json с динамическим ключом, но структурированными значениями в карту в flutter dart.

У меня есть json как

{
   "data" : {
            "apple":{"qty":5, "price":100},
            "orange":{"qty":2, "price":40},
           }
}

И я хочу, чтобы это десериализовалось во флаттере / дротике до класса модели ниже

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;
}

Я прочитал средний блог, и даже он не касается части карты.

3 ответа

Решение

Я нашел способ добиться этого. Мы можем преобразовать карту из одного типа в другой.

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']);
   }
}

Вам нужно сделать что-то вроде этого:

//...
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();
  //..
}

Если вам нужно, чтобы название фрукта было частью объекта:

//...
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
  //..
}

У меня есть аналогичный JSON с небольшими изменениями:

{
  "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|"]
  }
}

Ключи sub_itemmap (491, 427, 396, 275 и...) являются динамическими (как метка, а не как тип) и будут меняться в зависимости от порядка. Например, это будет 376, 325, 493... в другом порядке.

Я хочу отображать ключи и значения в моем приложении Flutter и не знаю, как получить эти данные и показать их по отдельности. Что-то вроде этого:

491:
£1.30  Pistachio
£2.50  Hazelnut

427:
£7.05  Almonds
£5.12  Walnuts

396:
£15.00 Saffron

275:
£45.00 Caviar

Я использовал этот код, и он у меня как-то сработал, но показывает только первый элемент списков. например, он показывает только фисташку для 491, а не фундук, и то же самое показывает только миндаль для 427, а не грецкие орехи:

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]);
  }
}

Результат консоли:

flutter: 491
flutter: Pistachio
flutter: 427
flutter: Almonds
flutter: 396
flutter: Saffron
flutter: 275
flutter: Caviar
Другие вопросы по тегам