Flutter Dart 将具有动态键但结构化值的 json 反序列化为 Map<String, ModelClass>

Flutter Dart deserialize a json with dynamic key but structured values into Map<String, ModelClass>

是否可以将具有动态键但结构化值的 json 反序列化为 flutter dart 中的 Map。

我json喜欢

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

我希望它在 flutter/dart 中反序列化为

下面的模型 class
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;
}

我已经通读了 medium blog 甚至这也没有涵盖地图部分。

你需要做这样的事情:

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

我找到了实现它的方法。我们可以将 Map 从一种类型转换为另一种类型。

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

我有一个类似的 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_item映射的键值(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,它只显示 Pistachio 而不是 Hazelnut,同样它对于 427 只显示 Almonds不是 核桃:

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