C#实现含多层嵌套数组的任意格式Json通用转Datatable方法
C# 任意结构JSON转DataTable通用方案
核心算法思路
- 路径命名规则:所有嵌套属性以
.拼接层级作为DataTable列名,无需提前定义实体结构,动态适配任意JSON结构 - 公共值继承:遍历过程中所有非数组类型的父节点属性值,会自动继承给所有下层子数组的每一行,不会丢失上层公共字段
- 递归展开逻辑:遍历JSON节点时只要遇到数组类型,就逐个遍历数组元素,每个元素单独复制一份当前已收集的公共属性集合再继续解析,避免不同数组元素之间的属性互相干扰
- 动态列扩展:解析过程中如果发现新的属性路径,自动向DataTable中添加对应数据类型的列
- 边界场景兼容:支持根节点为对象、根节点为数组、无嵌套数组、多层嵌套数组等所有常见JSON结构
实现代码
依赖说明:需要先安装Newtonsoft.Json NuGet包
using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System.Data; public static class JsonToDataTableConverter { public static DataTable ConvertToDataTable(string json) { DataTable dt = new DataTable(); JToken root = JToken.Parse(json); Dictionary<string, object> currentRowValues = new Dictionary<string, object>(); ParseJToken(root, "", currentRowValues, dt); // 兼容无数组的纯对象JSON,直接生成单行数据 if (dt.Rows.Count == 0 && currentRowValues.Count > 0) { AddRow(currentRowValues, dt); } return dt; } private static void ParseJToken(JToken token, string parentPath, Dictionary<string, object> currentRowValues, DataTable dt) { switch (token.Type) { case JTokenType.Object: foreach (var prop in ((JObject)token).Properties()) { string currentPath = string.IsNullOrEmpty(parentPath) ? prop.Name : $"{parentPath}.{prop.Name}"; ParseJToken(prop.Value, currentPath, currentRowValues, dt); } break; case JTokenType.Array: foreach (var item in ((JArray)token)) { // 每个数组元素复制上层属性集合,互不干扰 Dictionary<string, object> newRowValues = new Dictionary<string, object>(currentRowValues); ParseJToken(item, parentPath, newRowValues, dt); // 当前元素为基础类型时直接生成行 if (item.Type != JTokenType.Array && item.Type != JTokenType.Object) { AddRow(newRowValues, dt); } } break; default: // 基础值类型存入当前行属性集合,同步维护列结构 currentRowValues[parentPath] = ((JValue)token).Value; if (!dt.Columns.Contains(parentPath)) { Type colType = token.Type == JTokenType.Null ? typeof(object) : ((JValue)token).Value?.GetType() ?? typeof(object); dt.Columns.Add(parentPath, colType); } break; } } private static void AddRow(Dictionary<string, object> rowValues, DataTable dt) { DataRow row = dt.NewRow(); foreach (var kvp in rowValues) { if (dt.Columns.Contains(kvp.Key)) { row[kvp.Key] = kvp.Value ?? DBNull.Value; } } dt.Rows.Add(row); } }
调用示例
// 你提供的三层嵌套数组测试JSON public const string ResponseThreeArrays = @"{ ""key1"": ""val1"", ""key2"": { ""key2-1"": [ { ""key2-arr1-1"": ""val2-arr1-1(1)"", ""key2-arr1-2"": [ { ""key2-arr1-arr2-1"" : ""val2-arr1-arr2-1(1)(1)"", ""key2-arr1-arr2-2"" : [ { ""key2-arr1-arr2-arr3-1"" : ""val2-arr1-arr2-arr3-1(1)(1)(1)"", ""key2-arr1-arr2-arr3-2"" : ""val2-arr1-arr2-arr3-2(1)(1)(1)"", ""key2-arr1-arr2-arr3-3"" : ""val2-arr1-arr2-arr3-3(1)(1)(1)"" }, { ""key2-arr1-arr2-arr3-1"" : ""val2-arr1-arr2-arr3-1(1)(1)(2)"", ""key2-arr1-arr2-arr3-2"" : ""val2-arr1-arr2-arr3-2(1)(1)(2)"", ""key2-arr1-arr2-arr3-3"" : ""val2-arr1-arr2-arr3-3(1)(1)(2)"" }, { ""key2-arr1-arr2-arr3-1"" : ""val2-arr1-arr2-arr3-1(1)(1)(3)"", ""key2-arr1-arr2-arr3-2"" : ""val2-arr1-arr2-arr3-2(1)(1)(3)"", ""key2-arr1-arr2-arr3-3"" : ""val2-arr1-arr2-arr3-3(1)(1)(3)"" } ], ""key2-arr1-arr2-3"" : ""val2-arr1-arr2-3(1)(1)"" }, { ""key2-arr1-arr2-1"" : ""val2-arr1-arr2-1(1)(2)"", ""key2-arr1-arr2-2"" : [ { ""key2-arr1-arr2-arr3-1"" : ""val2-arr1-arr2-arr3-1(1)(2)(1)"", ""key2-arr1-arr2-arr3-2"" : ""val2-arr1-arr2-arr3-2(1)(2)(1)"", ""key2-arr1-arr2-arr3-3"" : ""val2-arr1-arr2-arr3-3(1)(2)(1)"" }, { ""key2-arr1-arr2-arr3-1"" : ""val2-arr1-arr2-arr3-1(1)(2)(2)"", ""key2-arr1-arr2-arr3-2"" : ""val2-arr1-arr2-arr3-2(1)(2)(2)"", ""key2-arr1-arr2-arr3-3"" : ""val2-arr1-arr2-arr3-3(1)(2)(2)"" }, { ""key2-arr1-arr2-arr3-1"" : ""val2-arr1-arr2-arr3-1(1)(2)(3)"", ""key2-arr1-arr2-arr3-2"" : ""val2-arr1-arr2-arr3-2(1)(2)(3)"", ""key2-arr1-arr2-arr3-3"" : ""val2-arr1-arr2-arr3-3(1)(2)(3)"" } ], ""key2-arr1-arr2-3"" : ""val2-arr1-arr2-3(1)(2)"" } ] }, { ""key2-arr1-1"": ""val2-arr1-1(2)"", ""key2-arr1-2"": [ { ""key2-arr1-arr2-1"" : ""val2-arr1-arr2-1(2)(1)"", ""key2-arr1-arr2-2"" : [ { ""key2-arr1-arr2-arr3-1"" : ""val2-arr1-arr2-arr3-1(2)(1)(1)"", ""key2-arr1-arr2-arr3-2"" : ""val2-arr1-arr2-arr3-2(2)(1)(1)"", ""key2-arr1-arr2-arr3-3"" : ""val2-arr1-arr2-arr3-3(2)(1)(1)"" }, { ""key2-arr1-arr2-arr3-1"" : ""val2-arr1-arr2-arr3-1(2)(1)(2)"", ""key2-arr1-arr2-arr3-2"" : ""val2-arr1-arr2-arr3-2(2)(1)(2)"", ""key2-arr1-arr2-arr3-3"" : ""val2-arr1-arr2-arr3-3(2)(1)(2)"" }, { ""key2-arr1-arr2-arr3-1"" : ""val2-arr1-arr2-arr3-1(2)(1)(3)"", ""key2-arr1-arr2-arr3-2"" : ""val2-arr1-arr2-arr3-2(2)(1)(3)"", ""key2-arr1-arr2-arr3-3"" : ""val2-arr1-arr2-arr3-3(2)(1)(3)"" } ], ""key2-arr1-arr2-3"" : ""val2-arr1-arr2-3(2)(1)"" }, { ""key2-arr1-arr2-1"" : ""val2-arr1-arr2-1(2)(2)"", ""key2-arr1-arr2-2"" : [ { ""key2-arr1-arr2-arr3-1"" : ""val2-arr1-arr2-arr3-1(2)(2)(1)"", ""key2-arr1-arr2-arr3-2"" : ""val2-arr1-arr2-arr3-2(2)(2)(1)"", ""key2-arr1-arr2-arr3-3"" : ""val2-arr1-arr2-arr3-3(2)(2)(1)"" }, { ""key2-arr1-arr2-arr3-1"" : ""val2-arr1-arr2-arr3-1(2)(2)(2)"", ""key2-arr1-arr2-arr3-2"" : ""val2-arr1-arr2-arr3-2(2)(2)(2)"", ""key2-arr1-arr2-arr3-3"" : ""val2-arr1-arr2-arr3-3(2)(2)(2)"" }, { ""key2-arr1-arr2-arr3-1"" : ""val2-arr1-arr2-arr3-1(2)(2)(3)"", ""key2-arr1-arr2-arr3-2"" : ""val2-arr1-arr2-arr3-2(2)(2)(3)"", ""key2-arr1-arr2-arr3-3"" : ""val2-arr1-arr2-arr3-3(2)(2)(3)"" } ], ""key2-arr1-arr2-3"" : ""val2-arr1-arr2-3(2)(2)"" } ] } ], ""key2-2"" : ""val2-2"" }, ""key3"": ""val3"" }"; // 直接调用转换方法即可得到目标DataTable DataTable result = JsonToDataTableConverter.ConvertToDataTable(ResponseThreeArrays);
转换后的DataTable会自动把所有层级属性平铺为列,最深层数组的每个元素对应一行,上层公共属性如key1、key3、key2.key2-2等值会自动填充到每一行中。
内容的提问来源于stack exchange,提问作者bruno valverde
相关产品推荐
相关产品推荐

