如何从CSV生成带层级信息的多级嵌套JSON以制作树形图
解决多层CSV转嵌套层级JSON的递归方案
我太懂你这个困扰了——用d3.nest处理多层级数据时,它确实会把所有聚合信息都压在叶子节点,中间层级完全是“空架子”,别说8层这种复杂结构,稍微层级多一点就没法满足树形图的需求。下面给你一套通用的递归处理方案,不管你有多少层级、有没有缺失子节点,都能完美生成带完整层级信息的嵌套JSON。
核心思路
核心逻辑是按层级顺序递归遍历每一行数据:从最顶层开始,把每一行数据按层级字段逐步“插入”到对应的嵌套节点中,每个中间层级的节点都会保留自己的分组标识(比如名称),而不是只在叶子节点存数据。哪怕某行数据到第3层就没有子节点了,递归也会自动终止在该节点,不会强行生成空的子层级。
代码实现(JavaScript)
假设你的CSV结构是按层级排序的列,比如:level1,level2,level3,...,level8,value(其中部分层级可能为空值,表示没有子节点)。我们用d3解析CSV后,通过递归函数构建结构:
// 1. 解析CSV数据(示例) const csvData = d3.csvParse(`level1,level2,level3,level4,level5,level6,level7,level8,value A,A1,A11,,,,,50 A,A1,A12,,,,,30 A,A2,,,,,,,40 B,B1,B11,B111,,,,20 B,B2,,,,,,,60`); // 2. 定义层级顺序(按CSV列的层级顺序排列) const hierarchyLevels = ['level1', 'level2', 'level3', 'level4', 'level5', 'level6', 'level7', 'level8']; // 3. 递归构建嵌套结构的核心函数 function buildHierarchy(data, currentLevelIndex) { // 终止条件:已经处理完所有层级,或者当前层级无有效分组值 if (currentLevelIndex >= hierarchyLevels.length) { // 叶子节点返回数据(比如value),可根据需求扩展 return data.map(item => ({ value: +item.value, // 可添加其他叶子节点属性 })); } const currentLevelKey = hierarchyLevels[currentLevelIndex]; // 按当前层级分组 const groups = d3.group(data, d => d[currentLevelKey]); const result = []; for (const [groupName, groupData] of groups) { // 跳过空值的分组(比如某行该层级为空,表示没有子节点) if (!groupName) continue; const node = { name: groupName, // 可添加当前层级节点的额外属性,比如统计当前分组的总value totalValue: d3.sum(groupData, d => +d.value) }; // 递归处理下一层级 const children = buildHierarchy(groupData, currentLevelIndex + 1); // 如果有子节点才添加children属性,避免空数组 if (children.length > 0) { node.children = children; } result.push(node); } return result; } // 4. 生成最终的嵌套JSON const nestedJson = buildHierarchy(csvData, 0); console.log(JSON.stringify(nestedJson, null, 2));
关键细节说明
- 适配任意层级:只要修改
hierarchyLevels数组的长度和字段名,不管是3层还是10层都能处理,完全不需要修改递归逻辑。 - 保留中间层级信息:每个中间节点都会存储
name和自定义的属性(比如totalValue),不是空壳节点,完美满足树形图的层级展示需求。 - 处理缺失子节点:如果某行数据在某个层级之后没有值,递归会自动终止,不会生成空的
children数组,避免无效节点。 - 灵活扩展:你可以在节点中添加任意需要的属性,比如当前分组的数量、自定义标识等,只需要修改
node对象的定义即可。
输出示例(简化版)
上面的示例CSV会生成类似这样的嵌套结构:
[ { "name": "A", "totalValue": 120, "children": [ { "name": "A1", "totalValue": 80, "children": [ { "name": "A11", "totalValue": 50, "children": [ { "value": 50 } ] }, { "name": "A12", "totalValue": 30, "children": [ { "value": 30 } ] } ] }, { "name": "A2", "totalValue": 40, "children": [ { "value": 40 } ] } ] }, { "name": "B", "totalValue": 80, "children": [ { "name": "B1", "totalValue": 20, "children": [ { "name": "B11", "totalValue": 20, "children": [ { "name": "B111", "totalValue": 20, "children": [ { "value": 20 } ] } ] } ] }, { "name": "B2", "totalValue": 60, "children": [ { "value": 60 } ] } ] } ]
这个结构完全符合树形图模板的需求,每个层级都有自己的信息,叶子节点也保留了原始数据。
内容的提问来源于stack exchange,提问作者HenryLau
相关产品推荐
相关产品推荐

