【问题标题】:Map<String, dynamic> to any type of Map without knowing data in advanceMap<String, dynamic> 到任何类型的 Map 无需事先知道数据
【发布时间】:2021-07-30 19:33:36
【问题描述】:

我有一个来自服务器的json响应,格式如下......

{
  key1: {
     subKey1: value1
     subKey2: value2
     [...]   
  },
  key2: {
    [...]
  },
  [...]
}

我遇到的所有答案都建议使用带有 fromJson(...) 的预定义模型类直接映射到 PODO。

但是,这个 JSON 是用于翻译字符串的,而且非常庞大。顶级键是语言代码,但可以是数百个条目,子级键也有数百个,并且它们的名称可能随时更改等。

没有一个简单的方法可以从 Map jsonDecode(response.body) 给我 到 Map>强>?

我试过了

Map<String, Map<String, String> typedMap = jsonResponse.map((key, value) => MapEntry(key, value))

但我被告知格式不匹配。

这是根据建议编辑的输出,

首先是完整的示例代码... Get.find 来自用于状态管理的 GetX 包。它在项目的其他领域工作得很好。

class TranslationsService {
  final logger = getLogger('Translation Service');

  Future<Map<String, Map<String, String>>> getTranslations() async {
    var response = await http.get(
        [url]);

    if (response.statusCode == HttpStatus.ok) {
      var jsonResponse =
          convert.json.decode(response.body) as Map<String, dynamic>;
      Map<String, Map<String, String>> result = jsonResponse
          .map((key, value) => MapEntry(key, value as Map<String, String>));

      logger.i(result);
      return result;
    } else {
      logger.e('Request failed with status code ${response.statusCode}');
      return null;
    }
  }

  static Future load() async {
    final api = TranslationsService();
    Map<String, Map<String, String>> map = await api.getTranslations();
    Get.find<TranslatedStrings>().map = map;
  }
}

还有输出,现在填充的错误更多......

E/flutter (26806): [ERROR:flutter/lib/ui/ui_dart_state.cc(186)] Unhandled Exception: type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'Map<String, String>' in type cast
E/flutter (26806): #0      TranslationsService.getTranslations.<anonymous closure> 
package:dream_x/services/translations_service.dart:19
E/flutter (26806): #1      MapMixin.map  (dart:collection/maps.dart:170:28)
E/flutter (26806): #2      TranslationsService.getTranslations 
package:dream_x/services/translations_service.dart:19
E/flutter (26806): <asynchronous suspension>
[....]
I/example.dream_(26806): Waiting for a blocking GC ProfileSaver

我在这里可能很愚蠢,但是转换一个简单的地图似乎过于复杂..... :D

而且,正如证明我得到的响应不是侥幸一样,这里是带有临时截断文件的 jsonResponse 打印的完整输出,使用 JSON Formatter 格式化和验证:

{
   "en":{
      "title":"Title English",
      "label_search":"Search",
      "label_profile":"Profile",
      "label_dashboard":"Dashboard"
   },
   "fr":{
      "title":"Title French",
      "label_search":"Recherche",
      "label_profile":"Profil",
      "label_dashboard":"Tableau de bord"
   }
}

【问题讨论】:

    标签: flutter dart


    【解决方案1】:

    既然你确定它们总是字符串,你可以使用value.toString()

    Map<String, Map<String, String> typedMap = jsonResponse.map((key, value) => MapEntry(key, value.toString()))
    

    【讨论】:

    • 感谢您的快速回复。但是,我在演员阵容后尝试访问它时遇到此错误...发生异常。 _CastError(类型'_InternalLinkedHashMap'不是类型转换中'Map>'类型的子类型)有什么想法吗?
    • 这意味着我们需要将地图嵌套更深一层。 _InternalLinkedHashMap 转换为 Map
    • 那么 .map 也在 KeyEntry 上吗?老实说,我很困惑。我之前在各种环境中多次处理过 JSON,但这让我陷入了循环......
    • .toString() 会将子图转换为String 而不是Map&lt;String,String&gt;。因此,演员阵容错误。检查我的答案以进行更正stackoverflow.com/a/67457443/13973939
    【解决方案2】:

    问题

    您在大多数情况下使用jsonResponse.map 是正确的,只是您误解了地图回调返回的内容。

    jsonResponse.map((key, value) => MapEntry(key, value)
    
    • key 是您的顶级密钥。它会像“key1”、“key2”一样改变......
    • 这里的value 是您的 Map,它位于键的前面。这就是它的本质:
    //Dart is parsing this as Map<dynamic, dynamic> probably
    {
      subkey1: value1,
      subKey2: value2
    }
    

    解决方案

    您需要做的就是使用as 关键字将Map&lt;dynamic,dynamic&gt; 转换为Map&lt;String,String&gt;

    Map<String,Map<String,String>> result = jsonResponse.map(
        (key, value) => MapEntry(key,value as Map<String,String>)
      );
    

    更新

    可以使用这两种方法中的任何一种来完成铸造

    1. Map&lt;T1,T2&gt;.from,其中 T1 和 T2 是您的目标类型:

      MapEntry(key, Map<String, String>.from(value))
      
    2. Map.castFrom&lt;S1,S2,T1,T2&gt;,其中 S1 和 S2 是您的源类型,T1 和 T2 是您的目标类型:

      MapEntry(key, Map.castFrom<String, dynamic, String, String>(value))
      

    输出

    打印运行时类型:

    print("${jsonResponse.runtimeType}");
    print("${result.runtimeType}");
    

    这是打印出来的

    JsLinkedHashMap<String, dynamic> //<-- jsonResponse
    JsLinkedHashMap<String, Map<String, String>> //<-- result
    

    【讨论】:

    • 我理解你的解释,这对我来说似乎很合乎逻辑。但是,经过尝试,我仍然遇到输入错误,现在使用 Map... 我已经编辑了具有当前进度的原始帖子。有没有机会给你更多的背景/想法?谢谢!
    • 有趣的是我知道你说的有道理。它不应该引起问题,但是,当使用这两种方法来转换 MapEntry 值时,我遇到了同样的错误,即... MapEntry(key, Map.from(value))参数类型 'dynamic' 不能分配给参数类型 'Map' 我开始生气了...只是有点... :D 感谢您的尝试!
    • @aLx450 您可以在 .map 之前打印 jsonResponse 的值并使用输出更新问题。我想看看它有什么。
    【解决方案3】:

    这可能源于我的一个误解,我太习惯于可以直接读取 JSON 并且不需要提前将其显式转换为已知属性的接口的 Javascript。

    因此,我决定以不同的方式进行。我使用QuickType 来获取基于简化数据集的样板代码,然后我将已知属性添加到样板中。添加属性时,它们将直接添加到对象结构中。

    不是最佳的,但我们不想为此付出太多努力。

    【讨论】:

      猜你喜欢
      • 2021-11-15
      • 2021-08-29
      • 2021-10-02
      • 2020-12-15
      • 2021-10-08
      • 1970-01-01
      • 2021-02-11
      • 2021-04-13
      相关资源
      最近更新 更多