【How to Flatten JSON in Flutter】 JSONをフラットにする方法

はじめに

とある事情でFlutterのJSONをフラットにする必要があったが、探してもこれと言うものが見つからず….

自作してみたので、そのコードを公開します!

実装コード

注: リストは key.0: value0, key.1: value1 のように表示されます。

Note: Lists are displayed as `key.0: value0, key.1: value1`, and so on.

/// Convert nested json to flat json
Map<String, dynamic> convert({required Map<String, dynamic> map, String? parentKey}) {
    final Map<String, dynamic> newMap = {};
    for(var MapEntry(key: key, value: value) in map.entries){
        final newkey = parentKey != null ?  "$parentKey.$key" : key;
        
        if(value is List){
            value = value.asMap().map((key, value) => MapEntry("$key", value));
        }
        if(value is Map){
            final convertMap = convert(map: value as Map<String, dynamic>, parentKey: newkey);
            newMap.addAll(convertMap);
        }else{
            newMap[newkey] = value;
        }
    }
    return newMap;
}

テスト

テスト用JSONは、https://json.org/example.htmlから取得

ネストしたJSON

IN

{
    "glossary": {
        "title": "example glossary",
		"GlossDiv": {
            "title": "S",
			"GlossList": {
                "GlossEntry": {
                    "ID": "SGML",
					"SortAs": "SGML",
					"GlossTerm": "Standard Generalized Markup Language",
					"Acronym": "SGML",
					"Abbrev": "ISO 8879:1986",
					"GlossDef": {
                        "para": "A meta-markup language, used to create markup languages such as DocBook.",
						"GlossSeeAlso": ["GML", "XML"]
                    },
					"GlossSee": "markup"
                }
            }
        }
    }
}

OUT

{
  "glossary.title": "example glossary",
  "glossary.GlossDiv.title": "S",
  "glossary.GlossDiv.GlossList.GlossEntry.ID": "SGML",
  "glossary.GlossDiv.GlossList.GlossEntry.SortAs": "SGML",
  "glossary.GlossDiv.GlossList.GlossEntry.GlossTerm": "Standard Generalized Markup Language",
  "glossary.GlossDiv.GlossList.GlossEntry.Acronym": "SGML",
  "glossary.GlossDiv.GlossList.GlossEntry.Abbrev": "ISO 8879:1986",
  "glossary.GlossDiv.GlossList.GlossEntry.GlossDef.para": "A meta-markup language, used to create markup languages such as DocBook.",
  "glossary.GlossDiv.GlossList.GlossEntry.GlossDef.GlossSeeAlso.0": "GML",
  "glossary.GlossDiv.GlossList.GlossEntry.GlossDef.GlossSeeAlso.1": "XML",
  "glossary.GlossDiv.GlossList.GlossEntry.GlossSee": "markup"
}

nullありJSON

IN

{"menu": {
    "header": "SVG Viewer",
    "items": [
        {"id": "Open"},
        {"id": "OpenNew", "label": "Open New"},
        null,
        {"id": "ZoomIn", "label": "Zoom In"},
        {"id": "ZoomOut", "label": "Zoom Out"},
        {"id": "OriginalView", "label": "Original View"},
        null,
        {"id": "Quality"},
        {"id": "Pause"},
        {"id": "Mute"},
        null,
        {"id": "Find", "label": "Find..."},
        {"id": "FindAgain", "label": "Find Again"},
        {"id": "Copy"},
        {"id": "CopyAgain", "label": "Copy Again"},
        {"id": "CopySVG", "label": "Copy SVG"},
        {"id": "ViewSVG", "label": "View SVG"},
        {"id": "ViewSource", "label": "View Source"},
        {"id": "SaveAs", "label": "Save As"},
        null,
        {"id": "Help"},
        {"id": "About", "label": "About Adobe CVG Viewer..."}
    ]
}}

OUT

{
  "menu.header": "SVG Viewer",
  "menu.items.0.id": "Open",
  "menu.items.1.id": "OpenNew",
  "menu.items.1.label": "Open New",
  "menu.items.2": null,
  "menu.items.3.id": "ZoomIn",
  "menu.items.3.label": "Zoom In",
  "menu.items.4.id": "ZoomOut",
  "menu.items.4.label": "Zoom Out",
  "menu.items.5.id": "OriginalView",
  "menu.items.5.label": "Original View",
  "menu.items.6": null,
  "menu.items.7.id": "Quality",
  "menu.items.8.id": "Pause",
  "menu.items.9.id": "Mute",
  "menu.items.10": null,
  "menu.items.11.id": "Find",
  "menu.items.11.label": "Find...",
  "menu.items.12.id": "FindAgain",
  "menu.items.12.label": "Find Again",
  "menu.items.13.id": "Copy",
  "menu.items.14.id": "CopyAgain",
  "menu.items.14.label": "Copy Again",
  "menu.items.15.id": "CopySVG",
  "menu.items.15.label": "Copy SVG",
  "menu.items.16.id": "ViewSVG",
  "menu.items.16.label": "View SVG",
  "menu.items.17.id": "ViewSource",
  "menu.items.17.label": "View Source",
  "menu.items.18.id": "SaveAs",
  "menu.items.18.label": "Save As",
  "menu.items.19": null,
  "menu.items.20.id": "Help",
  "menu.items.21.id": "About",
  "menu.items.21.label": "About Adobe CVG Viewer..."
}

悪くなさそう!

補足)コンソールでdart run で動かすサンプル

assets/test.jsonにjsonを用意し、以下のコードを、dart run test.dart

import 'dart:convert';
import 'dart:io';


/// Convert nested json to flat json
Map<String, dynamic> convert({required Map<String, dynamic> map, String? parentKey}) {
    final Map<String, dynamic> newMap = {};
    for(var MapEntry(key: key, value: value) in map.entries){
        final newkey = parentKey != null ?  "$parentKey.$key" : key;
        
        if(value is List){
            value = value.asMap().map((key, value) => MapEntry("$key", value));
        }
        if(value is Map){
            final convertMap = convert(map: value as Map<String, dynamic>, parentKey: newkey);
            newMap.addAll(convertMap);
        }else{
            newMap[newkey] = value;
        }
    }
    return newMap;
}


/// Read json file and return as Map
Future<Map<String, dynamic>> readJsonFile(String filePath) async {
  final input = await File(filePath).readAsString();
  final map = jsonDecode(input);
  return map;
}


/// Print json in a pretty format
void prityPrintJson(Map<String, dynamic> map){
  JsonEncoder encoder = new JsonEncoder.withIndent('  ');
  String prettyJson = encoder.convert(map);
  print(prettyJson);
}

main() async{
  final json = await readJsonFile('assets/test.json');

  prityPrintJson(json);

  final convertedJson = convert(map: json);

  prityPrintJson(convertedJson);
}

コメント

タイトルとURLをコピーしました