
本文详解如何根据 group 字符串路径(如 "1.2.2.1")将扁平属性映射为深度嵌套的树形 JSON 结构,提供简洁可靠的递归路径解析方案,并附可直接运行的代码示例与关键注意事项。
本文详解如何根据 `group` 字符串路径(如 `"1.2.2.1"`)将扁平属性映射为深度嵌套的树形 json 结构,提供简洁可靠的递归路径解析方案,并附可直接运行的代码示例与关键注意事项。
在处理配置驱动型数据建模或动态表单渲染等场景时,常需将带层级标识(如 group: "1.2.2.1")的扁平属性集转换为符合树状结构的嵌套对象。核心挑战在于:将点分组路径(dot-notation)精准拆解为多层嵌套的 attributes 对象,并确保中间节点自动创建、同级节点共存、原始属性正确挂载到底层叶子节点。
以下是一个高效、无副作用、易于理解的实现方案:
const data = {
"id": "jsonid",
"attributes": {
"personName": { "id": "name1", "group": "1.1" },
"age": { "id": "age1", "group": "1.2.1" },
"height": { "id": "height1", "group": "1.2.2.1" }
}
};
// 初始化结果对象,保留顶层 id,重置 attributes 为嵌套结构
let result = { ...data, attributes: {} };
// 遍历每个原始属性
for (const key in data.attributes) {
const { id: attrId, group } = data.attributes[key];
const fullGroupId = 'group' + group; // 统一前缀,如 "1.1" → "group1.1"
let attr = result.attributes;
// 工具函数:安全获取/创建指定 groupId 的节点,并返回其 attributes 子对象
const getAttributes = (groupId) => {
if (!attr[groupId]) {
attr[groupId] = { id: groupId, attributes: {} };
}
return attr[groupId].attributes;
};
// 逐级解析路径:对 "group1.2.2.1",依次创建 group1 → group1.2 → group1.2.2 → group1.2.2.1
let i = fullGroupId.indexOf('.');
while (i > 0) {
attr = getAttributes(fullGroupId.slice(0, i));
i = fullGroupId.indexOf('.', i + 1);
}
// 最终在最深层节点的 attributes 中挂载原始属性(如 personName)
getAttributes(fullGroupId)[key] = { id: attrId };
}
console.log(JSON.stringify(result, null, 2));
✅ 关键设计亮点:
- 路径驱动创建:利用 indexOf('.', i + 1) 迭代提取所有前缀(group1, group1.2, group1.2.2, group1.2.2.1),避免手动分割数组与嵌套循环;
- 惰性初始化:通过空合并赋值 ??=(或兼容写法 if (!attr[groupId]) {...})确保中间节点按需生成,不冗余;
- 语义清晰:getAttributes(groupId) 封装了“获取或新建节点 + 返回其 attributes”的原子操作,大幅提升可读性与复用性;
- 零依赖:纯 JavaScript 实现,兼容 Node.js 与主流浏览器(ES2015+)。
⚠️ 注意事项:
- group 值必须为合法点分字符串(如 "1", "1.2", "1.2.3"),不支持空段、重复点或非数字片段;
- 若多个属性共享同一 group(如 personName 和 email 同属 "1.1"),它们将自然并列于同一 attributes 下,符合预期;
- 原始 attributes 中的 group 字段仅用于构建结构,不会透传至输出,最终结构中仅保留 id 和嵌套 attributes;
- 如需支持更复杂路径(如含字母前缀 "a.b.c"),只需移除 'group' + 前缀逻辑,直接使用原始 group 值即可。
该方案以极简代码达成高鲁棒性嵌套构建,是处理动态层级配置的理想实践。











