.NET Core中如何将带路径键的扁平JSON转换为层级JSON对象
问题描述
在.NET Core环境中,数据库存储的JSON Schema字符串为扁平结构,所有键以点分隔的路径形式存在。使用JObject.Parse解析后无法得到期望的嵌套层级JSON结构,需要将这类扁平JSON转换为嵌套结构返回给前端。
示例代码
string json = $@"{{ ""xcollapse.id"":""xcollapse"", ""xcollapse.el"":202, ""xcollapse.cols.props.cn"":""title"", ""xcollapse.cols.props.desc"":"""", ""xcollapse.cols.props.visible"":-1, ""xcollapse.cols.children.id"":""f272681"", ""xcollapse.cols.children.el"":200, ""xcollapse.cols.children.props"":""{{}}"" }}"; var jObj = JObject.Parse(json); var result = jObj.ToString();
期望转换结果
{ "xcollapse": { "id": "xcollapse", "el": 202, "cols": [ { "props": { "cn": "title", "desc": "", "visible": -1 }, "children": { "id": "f272681", "el": 200, "props": {} } } ] } }
数据库完整扁平JSON结构
{ "xcollapse.id":"xcollapse", "xcollapse.el":202, "xcollapse.props":{}, "xcollapse.styles.visible":-1, "xcollapse.cols.deletable":false, "xcollapse.cols.props.cn":"title", "xcollapse.cols.props.desc":"", "xcollapse.cols.props.visible":-1, "xcollapse.cols.styles":null, "xcollapse.cols.children.id":"f272681", "xcollapse.cols.children.el":200, "xcollapse.cols.children.props":{}, "xcollapse.cols.children.styles.visible":-1, "xcollapse.cols.children.cols.deletable":false, "xcollapse.cols.children.cols.props.visible":-1, "xcollapse.cols.children.cols.styles.span":8, "xcollapse.cols.children.cols.children.id":"fname", "xcollapse.cols.children.cols.children.el":100, "xcollapse.cols.children.cols.children.props.ek":"fbillhead", "xcollapse.cols.children.cols.children.props.cn":"title", "xcollapse.cols.children.cols.children.props.group":"", "xcollapse.cols.children.cols.children.props.fn":"fname", "xcollapse.cols.children.cols.children.props.pn":"fname", "xcollapse.cols.children.cols.children.props.desc":"", "xcollapse.cols.children.cols.children.props.must":"0", "xcollapse.cols.children.cols.children.props.visible":-1, "xcollapse.cols.children.cols.children.props.len":"100", "xcollapse.cols.children.cols.children.props.lock":"0", "xcollapse.cols.children.cols.children.props.copy":"1", "xcollapse.cols.children.cols.children.props.defval":"", "xcollapse.cols.children.cols.children.props.canchange":"0", "xcollapse.cols.children.cols.children.props.xlsin":"1", "xcollapse.cols.children.cols.children.props.acl":"1", "xcollapse.cols.children.cols.children.props.sbm":"0", "xcollapse.cols.children.cols.children.props.notrace":"1", "xcollapse.cols.children.cols.children.props.apipn":"sourceType", "xcollapse.cols.children.cols.children.props.ctlfk":"", "xcollapse.cols.children.cols.children.props.editmode":"0", "xcollapse.cols.children.cols.children.props.xsslv":"0", "xcollapse.cols.children.cols.children.styles.align":"left", "xcollapse.cols.children.cols.children.styles.width":"", "xcollapse.cols.children.cols.children.styles.row":2, "xcollapse.cols.children.cols.children.cols":{}, "xcollapse.cols.children.cols.children.deletable":true, "xcollapse.cols.children.cols.children.pid":"", "xcollapse.cols.children.cols.children.seq":1, "xcollapse.cols.children.cols.seq":1, "xcollapse.cols.children.deletable":true, "xcollapse.cols.children.pid":"", "xcollapse.cols.children.seq":1, "xcollapse.cols.seq":1, "xcollapse.deletable":true, "xcollapse.pid":"", "xcollapse.seq":1 }
解决方案
实现工具方法遍历扁平JObject的键值对,拆分点分隔路径并递归构建嵌套结构,同时识别cols这类需要转为数组的节点(可根据需求扩展识别规则)。
using Newtonsoft.Json.Linq; public static class JsonFlattenHelper { public static JObject Unflatten(JObject flatJson) { var result = new JObject(); foreach (var kvp in flatJson) { var pathSegments = kvp.Key.Split('.'); JToken current = result; for (int i = 0; i < pathSegments.Length; i++) { var segment = pathSegments[i]; bool isLastSegment = i == pathSegments.Length - 1; // 处理需要转为数组的节点(此处约定cols为数组节点) if (segment == "cols" && !isLastSegment) { if (current[segment] == null) { current[segment] = new JArray(); } var array = (JArray)current[segment]; // 扁平结构中cols子属性对应数组首个元素 if (array.Count == 0) { array.Add(new JObject()); } current = array[0]; } else { // 处理普通对象节点 if (current[segment] == null) { current[segment] = isLastSegment ? kvp.Value : new JObject(); } else if (!isLastSegment && current[segment].Type != JTokenType.Object) { // 冲突时替换为对象节点 current[segment] = new JObject(); } current = current[segment]; } } } return result; } }
使用示例
string json = $@"{{ ""xcollapse.id"":""xcollapse"", ""xcollapse.el"":202, ""xcollapse.cols.props.cn"":""title"", ""xcollapse.cols.props.desc"":"""", ""xcollapse.cols.props.visible"":-1, ""xcollapse.cols.children.id"":""f272681"", ""xcollapse.cols.children.el"":200, ""xcollapse.cols.children.props"":""{{}}"" }}"; var flatJObj = JObject.Parse(json); var nestedJObj = JsonFlattenHelper.Unflatten(flatJObj); Console.WriteLine(nestedJObj.ToString(Newtonsoft.Json.Formatting.Indented));
运行后输出与期望结构一致,也能正确处理数据库中的完整扁平JSON,构建多层嵌套的层级结构。
内容的提问来源于stack exchange,提问作者beiduoan
相关产品推荐
相关产品推荐

