You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在ASP.NET/C#中将嵌套JSON转换为DataTable(无需实体类)

嘿,我懂你为啥不想用实体类——多分支嵌套的JSON写实体类简直是个噩梦!不用急,我给你俩纯C#的方案,不用定义任何实体类就能把嵌套JSON转成DataTable,亲测好用:

方案一:使用Newtonsoft.Json(Json.NET)递归扁平化

这是很多项目里常用的JSON处理库,处理嵌套结构特别灵活。核心思路是把嵌套的JSON节点递归遍历,把每个节点的完整路径(比如PricedItineraries.AirItinerary.OriginDestinationOptions.OriginDestinationOption[0].FlightSegment[0].DepartureAirport.LocationCode)作为DataTable的列名,对应的值作为单元格内容,同时自动处理数组元素,每个数组项生成独立的行。

实现代码

首先确保你已经通过NuGet安装了Newtonsoft.Json包,然后用下面的代码:

using Newtonsoft.Json.Linq;
using System.Collections.Generic;
using System.Data;
using System.Linq;

public class JsonToDataTableConverter
{
    // 递归扁平化JSON,生成每行的键值对列表
    private static List<Dictionary<string, object>> FlattenJsonToList(JToken token, string parentPath = "", Dictionary<string, object> current = null)
    {
        var result = new List<Dictionary<string, object>>();
        current = current ?? new Dictionary<string, object>();

        switch (token.Type)
        {
            case JTokenType.Object:
                foreach (JProperty property in token.Children<JProperty>())
                {
                    var newPath = string.IsNullOrEmpty(parentPath) ? property.Name : $"{parentPath}.{property.Name}";
                    var childResult = FlattenJsonToList(property.Value, newPath, new Dictionary<string, object>(current));
                    result.AddRange(childResult);
                }
                break;
            case JTokenType.Array:
                int index = 0;
                foreach (JToken item in token.Children())
                {
                    var newPath = string.IsNullOrEmpty(parentPath) ? $"[{index}]" : $"{parentPath}[{index}]";
                    var childResult = FlattenJsonToList(item, newPath, new Dictionary<string, object>(current));
                    result.AddRange(childResult);
                    index++;
                }
                break;
            default:
                current.Add(parentPath, token.ToObject<object>());
                result.Add(current);
                break;
        }

        return result;
    }

    // 转换为DataTable
    public static DataTable ConvertNestedJsonToDataTable(string json)
    {
        var jObject = JObject.Parse(json);
        var flattenedList = FlattenJsonToList(jObject);
        
        if (flattenedList.Count == 0)
            return new DataTable();
        
        var dataTable = new DataTable();
        // 添加所有唯一列
        var allColumns = flattenedList.SelectMany(dict => dict.Keys).Distinct();
        foreach (var column in allColumns)
        {
            dataTable.Columns.Add(column);
        }
        
        // 填充行数据
        foreach (var item in flattenedList)
        {
            var row = dataTable.NewRow();
            foreach (var kvp in item)
            {
                row[kvp.Key] = kvp.Value ?? DBNull.Value;
            }
            dataTable.Rows.Add(row);
        }
        
        return dataTable;
    }
}

使用方式

直接调用静态方法就行:

string yourJson = "你的嵌套JSON字符串";
DataTable resultTable = JsonToDataTableConverter.ConvertNestedJsonToDataTable(yourJson);
方案二:使用System.Text.Json(.NET Core/.NET 5+ 自带)

如果你的项目用的是.NET Core或者.NET 5+,可以直接用自带的System.Text.Json,不用额外安装包,思路和上面一致,只是解析方式换成了JsonElement。

实现代码

using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text.Json;

public class JsonToDataTableConverter
{
    // 递归扁平化JsonElement,生成每行的键值对列表
    private static List<Dictionary<string, object>> FlattenJsonElementToList(JsonElement element, string parentPath = "", Dictionary<string, object> current = null)
    {
        var result = new List<Dictionary<string, object>>();
        current = current ?? new Dictionary<string, object>();

        switch (element.ValueKind)
        {
            case JsonValueKind.Object:
                foreach (var property in element.EnumerateObject())
                {
                    var newPath = string.IsNullOrEmpty(parentPath) ? property.Name : $"{parentPath}.{property.Name}";
                    var childResult = FlattenJsonElementToList(property.Value, newPath, new Dictionary<string, object>(current));
                    result.AddRange(childResult);
                }
                break;
            case JsonValueKind.Array:
                int index = 0;
                foreach (var item in element.EnumerateArray())
                {
                    var newPath = string.IsNullOrEmpty(parentPath) ? $"[{index}]" : $"{parentPath}[{index}]";
                    var childResult = FlattenJsonElementToList(item, newPath, new Dictionary<string, object>(current));
                    result.AddRange(childResult);
                    index++;
                }
                break;
            default:
                object value;
                // 处理不同类型的JSON值
                switch (element.ValueKind)
                {
                    case JsonValueKind.String:
                        value = element.GetString();
                        break;
                    case JsonValueKind.Number:
                        if (element.TryGetInt64(out long longValue))
                            value = longValue;
                        else if (element.TryGetDouble(out double doubleValue))
                            value = doubleValue;
                        else
                            value = element.ToString();
                        break;
                    case JsonValueKind.True:
                    case JsonValueKind.False:
                        value = element.GetBoolean();
                        break;
                    case JsonValueKind.Null:
                        value = DBNull.Value;
                        break;
                    default:
                        value = element.ToString();
                        break;
                }
                current.Add(parentPath, value);
                result.Add(current);
                break;
        }

        return result;
    }

    // 转换为DataTable
    public static DataTable ConvertNestedJsonToDataTable(string json)
    {
        var options = new JsonDocumentOptions { AllowTrailingCommas = true };
        using var doc = JsonDocument.Parse(json, options);
        var flattenedList = FlattenJsonElementToList(doc.RootElement);
        
        if (flattenedList.Count == 0)
            return new DataTable();
        
        var dataTable = new DataTable();
        // 添加所有唯一列
        var allColumns = flattenedList.SelectMany(dict => dict.Keys).Distinct();
        foreach (var column in allColumns)
        {
            dataTable.Columns.Add(column);
        }
        
        // 填充行数据
        foreach (var item in flattenedList)
        {
            var row = dataTable.NewRow();
            foreach (var kvp in item)
            {
                row[kvp.Key] = kvp.Value ?? DBNull.Value;
            }
            dataTable.Rows.Add(row);
        }
        
        return dataTable;
    }
}

使用方式

和上面一样,直接调用:

string yourJson = "你的嵌套JSON字符串";
DataTable resultTable = JsonToDataTableConverter.ConvertNestedJsonToDataTable(yourJson);

一些需要注意的点

  • 扁平化后的列名会包含完整的嵌套路径和数组索引(比如OriginDestinationOption[0].FlightSegment[0].DepartureAirport.LocationCode),如果觉得列名太长,可以修改递归方法里的路径生成逻辑,比如去掉数组索引或者简化路径。
  • DataTable的列类型默认会根据第一个出现的值来确定,如果后续行有不同类型的值,可能会抛出异常。如果想避免这种情况,可以在添加列的时候统一指定为typeof(string),或者在代码里增加类型判断逻辑。
  • 如果JSON里有大量重复的结构,生成的DataTable会包含所有唯一的字段,缺失的字段会自动填充DBNull.Value。

内容的提问来源于stack exchange,提问作者NIDIN GOPI

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:32:50