如何解析飞镖中的动态 JSON 键

How to parse dynamic JSON keys in dart

我有一个 API returns JSON 带有动态键,即每个 GET 请求都会更改键值。

例如:这是 JSON.

的格式

我在 dart 中有一个书本模型,

class Book {
  String id = "";
  String title = "";
  
  Book();
  
  Book.fromJson(Map<String, dynamic> json) {
    id = json['id'];
    title = json['title'];
  }
  
  static List<Book> listFromJson(List<dynamic> json) {
    return json.map((val) => Book.fromJson(val)).toList();
  }
}

和JSON响应,

{
    "Recommended For You" : [
        {
            "id" : "001",
            "title" : "title001"
        },
        ...
    ],
    "Thrillers" : [
        {
            "id" : "005",
            "title" : "title005"
        },
        ...
    ]
}

考虑到类型(如 Thrillers)可以改变(即它是动态的并且可能因每个用户而改变),如何根据类型将其解析为书籍列表?

编辑 1

ThrillersRecommended For You 不是恒定的,有时它可能会更改为 HorrorRomantic 或其他。这是动态

编辑 2:解决方案

感谢@lrn 的解决方案,我想出了一个新的 Class

class Recommendations {
  String recommendationType;
  List<Book> recommendations;

  @override
  String toString() {
    return 'Recomendations[title: $recommendationType]';
  }

  Recommendations.fromJson(MapEntry<String, dynamic> json) {
    if (json == null) return;
    this.recommendationType = json.key;
    this.recommendations = Book.listFromJson(json.value);
  }

  static List<Recommendations> listFromJson(Map<String, dynamic> json) {
    return json == null
        ? List<Recommendations>.empty()
        : json.entries
            .map((value) => new Recommendations.fromJson(value))
            .toList();
  }
}

您的响应模型包含两个不同的数组,recommendedForYouthrillers。所以,你可以这样处理:

// To parse this JSON data, do
//
//     final responseModel = responseModelFromJson(jsonString);

import 'dart:convert';

ResponseModel responseModelFromJson(String str) => ResponseModel.fromJson(json.decode(str));

String responseModelToJson(ResponseModel data) => json.encode(data.toJson());

class ResponseModel {
    ResponseModel({
        this.recommendedForYou,
        this.thrillers,
    });

    List<Book> recommendedForYou;
    List<Book> thrillers;

    factory ResponseModel.fromJson(Map<String, dynamic> json) => ResponseModel(
        recommendedForYou: json["Recommended For You"] == null ? null : List<Book>.from(json["Recommended For You"].map((x) => Book.fromJson(x))),
        thrillers: json["Thrillers"] == null ? null : List<Book>.from(json["Thrillers"].map((x) => Book.fromJson(x))),
    );

    Map<String, dynamic> toJson() => {
        "Recommended For You": recommendedForYou == null ? null : List<dynamic>.from(recommendedForYou.map((x) => x.toJson())),
        "Thrillers": thrillers == null ? null : List<dynamic>.from(thrillers.map((x) => x.toJson())),
    };
}

class Book {
    Book({
        this.id,
        this.title,
    });

    String id;
    String title;

    factory Book.fromJson(Map<String, dynamic> json) => Book(
        id: json["id"] == null ? null : json["id"],
        title: json["title"] == null ? null : json["title"],
    );

    Map<String, dynamic> toJson() => {
        "id": id == null ? null : id,
        "title": title == null ? null : title,
    };
}

您可以使用此 site 将您的 json 转换为任何飞镖模型。

如果您不知道键,但知道它是一个 JSON 地图,其中的值是您要查找的图书列表,我会写:

List<Book> parseCategorizedBooksJson(Map<String, dynamic> json) =>
  [for (var books in json.values) ...Book.listFromJson(books)];

List<Book> parseCategorizedBooksJson(Map<String, dynamic> json) =>
  [for (var books in json.values) 
     for (var book in books) Book.fromJson(book)];

(避免建立中间书籍列表)。

有了这个,您只需迭代外部地图的 values,并忽略键。 JSON 映射只是普通的 Dart Maps,您可以访问键作为 .keys(然后遍历它们而无需提前知道它们)并访问值作为 .values(并完全忽略键)。

每个值都是一个图书列表,您可以使用现有的静态函数对其进行解析。

要包含该类型,您必须说明您希望如何记住该类型。最简单的就是将数据保留为地图:

var categoriedBooks = {for (var genre in json) 
    genre: Book.listFromJson(json[genre])
};

这将构建一个具有相同键(流派)的地图,但其中的值现在是 Books 的列表。