如何在Flutter中解析嵌套JSON树并转换为对象列表
问题:解析嵌套JSON树为全层级对象列表(Flutter)
问题背景
现有嵌套结构的JSON树,当前代码仅能解析第一层节点,需要实现全层级解析,提取每个节点的level值并转换为对象列表,用于Flutter组件。
嵌套JSON结构
{ "children": [ { "children": [], "id": 9, "level": 1, "name": "Zone d'audit Interne" }, { "children": [], "id": 10, "level": 1, "name": "Magasin PF" }, { "children": [], "id": 11, "level": 1, "name": "Magasin MP" }, { "children": [ { "children": [], "id": 14, "level": 2, "name": "Packaging" }, { "children": [], "id": 15, "level": 2, "name": "Labelling" }, { "children": [], "id": 16, "level": 2, "name": "Assemblage Acc" } ], "id": 12, "level": 1, "name": " U4: Assembalge Finale" }, { "children": [ { "children": [], "id": 18, "level": 2, "name": "Contrôle traitement" }, { "children": [], "id": 19, "level": 2, "name": "Tunnel de Séchage" }, { "children": [], "id": 20, "level": 2, "name": "Traitement Mécanique" } ], "id": 17, "level": 1, "name": "U3: Traitement" }, { "children": [ { "children": [], "id": 23, "level": 2, "name": "Ass_Ligne 2" }, { "children": [], "id": 24, "level": 2, "name": "Ass_ligne 1" }, { "children": [], "id": 39, "level": 2, "name": "BU" } ], "id": 21, "level": 1, "name": "U2: Assemblage SF" }, { "children": [ { "children": [], "id": 26, "level": 2, "name": "Mgasin Tampon" }, { "children": [], "id": 27, "level": 2, "name": "Contrôle Kitting" } ], "id": 25, "level": 1, "name": "U1: Kitting" }, { "children": [], "id": 35, "level": 1, "name": "to-delete" } ], "id": 8, "level": 0, "name": "DEMO" }
当前解析代码
Future<Map<String, dynamic>?> fetchPerimeterTree( {required int id, required String baseUrl}) async { try { final request = http.Request( 'GET', Uri.parse("$baseUrl${Endpoints.fetchPerim}$id/json")); http.StreamedResponse response = await request.send(); if (response.statusCode == 200) { debugPrint("Perimeters tree fetched with success"); var jsonData = jsonDecode(await response.stream.bytesToString()); List<dynamic> fetchData2 = jsonData["children"]; fetchData2.forEach((element) { print(element["name"]); print(element["children"]); print(element["level"]); }); print(fetchData2); return jsonData; } else { throw Exception('Failed to load perimeter tree ${response.statusCode}'); } } catch (ex) { debugPrint(ex.toString()); } }
解决方案
1. 定义数据模型类
创建对应节点的Dart类,包含递归解析JSON的工厂方法:
class PerimeterNode { final int id; final int level; final String name; final List<PerimeterNode> children; PerimeterNode({ required this.id, required this.level, required this.name, required this.children, }); // 递归解析JSON为节点对象 factory PerimeterNode.fromJson(Map<String, dynamic> json) { List<PerimeterNode> childNodes = (json['children'] as List) .map((childJson) => PerimeterNode.fromJson(childJson)) .toList(); return PerimeterNode( id: json['id'], level: json['level'], name: json['name'], children: childNodes, ); } }
2. 递归遍历并扁平化节点列表
如果需要将所有层级的节点整理为扁平列表(方便ListView等组件使用),添加递归遍历函数:
// 遍历整个节点树,收集所有节点到扁平列表 List<PerimeterNode> flattenPerimeterTree(PerimeterNode root) { List<PerimeterNode> allNodes = [root]; for (var child in root.children) { allNodes.addAll(flattenPerimeterTree(child)); } return allNodes; }
3. 修改请求函数完成全层级解析
更新原请求函数,将JSON解析为节点对象,并按需返回扁平列表或树结构:
Future<List<PerimeterNode>?> fetchAllPerimeterNodes({required int id, required String baseUrl}) async { try { final request = http.Request( 'GET', Uri.parse("$baseUrl${Endpoints.fetchPerim}$id/json")); http.StreamedResponse response = await request.send(); if (response.statusCode == 200) { debugPrint("Perimeters tree fetched with success"); var jsonData = jsonDecode(await response.stream.bytesToString()); // 解析根节点(包含全层级子节点) PerimeterNode rootNode = PerimeterNode.fromJson(jsonData); // 转换为扁平节点列表 List<PerimeterNode> allNodes = flattenPerimeterTree(rootNode); // 验证输出 allNodes.forEach((node) { print("Level ${node.level}: ${node.name} (ID: ${node.id})"); }); return allNodes; } else { throw Exception('Failed to load perimeter tree ${response.statusCode}'); } } catch (ex) { debugPrint(ex.toString()); return null; } }
说明
- 模型类的
fromJson方法通过递归处理子节点,实现全层级解析。 - 若需保留树结构(用于树形展开组件),直接返回
rootNode即可,无需调用flattenPerimeterTree。 - 扁平列表可直接用于Flutter的列表组件,每个节点包含完整的
level、id、name信息。
内容的提问来源于stack exchange,提问作者Islam TALBI
相关产品推荐
相关产品推荐

