У меня есть API, который возвращает JSON с динамическими ключами, т.е. значение ключа изменяется при каждом запросе GET.

Пример: это формат JSON.

У меня есть книжная модель в дротике,

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

Thrillers и Recommended For You не являются постоянными, иногда они могут изменяться на Horror и Romantic или что-то еще. Это динамический

Изменить 2: решение

Благодаря решению @ lrn я придумал новый класс

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();
  }
}
1
Nithin Sai 17 Сен 2021 в 08:30

2 ответа

Лучший ответ

Если вы не знаете ключей, но знаете, что это карта 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)];

(что позволяет избежать создания промежуточных списков книг).

При этом вы просто перебираете значения внешней карты и игнорируете ключи. Карты JSON - это просто Dart Map, и вы можете получить доступ к ключам как .keys (а затем пройти через них, не зная их заранее) и получить доступ к значениям как .values ( и полностью игнорировать ключи).

Каждое значение представляет собой список книг, который вы можете проанализировать с помощью существующих статических функций.

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

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

Это строит карту с теми же ключами (жанрами), но где значениями теперь являются списки Book s.

2
lrn 17 Сен 2021 в 11:33

Ваша модель ответа содержит два разных массива: recommendedForYou и thrillers. Итак, вы можете справиться с этим так:

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

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

1
Akif 17 Сен 2021 в 06:06