将数据行转换为JSON对象

本文关键字:JSON 对象 转换 数据 | 更新日期: 2023-09-27 18:19:44

我有一个DataTable,它只有一行,看起来像

   America              |  Africa               |     Japan     |   
   -------------------------------------------------------------
  {"Id":1,"Title":"Ka"} | {"Id":2,"Title":"Sf"} | {"Id":3,"Title":"Ja","Values":{"ValID":4,"Type":"Okinawa"}} 

DataTable列为美国、非洲、日本。

现在我想将DataTable转换为JSON,使JSON看起来像

{
"America": {
    "Id": 1,
    "Title": "Ka"
},
"Africa": {
    "Id": 2,
    "Title": "Sf"
},
"Japan": {
    "Id": 3,
    "Title": "Ja",
    "Values": {
        "ValID": 4,
        "Type": "Okinawa"
    }
  }
}  

我的尝试是:

string js = JSonConvverter.Serializeobject(datatable);
var objType =  JObject.Parse(js);

但它没有起作用。如有任何帮助,我们将不胜感激。

将数据行转换为JSON对象

假设您使用的是json.net,那么有一个特殊的内置转换器DataTableConverter,它以行数组的缩写格式输出数据表,其中每一行都序列化为列名/值对,如您的问题所示。虽然DataSet也有一个转换器,但DataRow没有特定的内置转换器。因此,当直接序列化DataRow时,Json.NET将序列化DataRow的所有字段和属性,从而产生更详细的输出——这是您不希望的。

DataTable使用的更紧凑的形式序列化DataRow最简单的方法是使用JArray.FromObject()将整个表序列化为JArray,然后选择与要序列化的DataRow具有相同索引的数组项:

var rowIndex = 0;
var jArray = JArray.FromObject(datatable, JsonSerializer.CreateDefault(new JsonSerializerSettings { /* Add settings as required e.g. */ NullValueHandling = NullValueHandling.Ignore }));
var rowJToken = jArray[rowIndex];
var rowJson = rowJToken.ToString(Formatting.Indented);  // Or Formatting.None if you prefer

由于您的表只有一行,所以rowIndex应该是0。更一般地说,如果您不知道给定DataRow的索引,请参阅如何从数据表中获取行号

这应该适用于只有一行的表,但通常不会具有性能。

在这里演示小提琴#1。

或者,如果表有很多行但只有很少的列,则可以使用LINQ将该行转换为Dictionary<string, object>,并对其进行序列化:

var rowJson = JsonConvert.SerializeObject(
    row.Table.Columns.Cast<DataColumn>()
        .ToDictionary(c => c.ColumnName, c => row.IsNull(c) ? null : row[c]), 
    Formatting.Indented);

只要列的数量少,性能就不会太差。

Fiddle#2在这里。

序列化行的最高效的方式是为DataRow引入一个自定义JsonConverter,将行作为对象写入JSON:

public class DataRowConverter : JsonConverter<DataRow>
{
    public override DataRow ReadJson(JsonReader reader, Type objectType, DataRow existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException(string.Format("{0} is only implemented for writing.", this));
    }
    public override void WriteJson(JsonWriter writer, DataRow row, JsonSerializer serializer)
    {
        var table = row.Table;
        if (table == null)
            throw new JsonSerializationException("no table");
        var contractResolver = serializer.ContractResolver as DefaultContractResolver;
        writer.WriteStartObject();
        foreach (DataColumn col in row.Table.Columns)
        {
            var value = row[col];
            if (serializer.NullValueHandling == NullValueHandling.Ignore && (value == null || value == DBNull.Value))
                continue;
            
            writer.WritePropertyName(contractResolver != null ? contractResolver.GetResolvedPropertyName(col.ColumnName) : col.ColumnName);
            serializer.Serialize(writer, value);
        }
        writer.WriteEndObject();
    }
}

然后像这样使用:

var settings = new JsonSerializerSettings
{
    Converters = { new DataRowConverter() },
    // Add other settings as required.
};
var rowJson = JsonConvert.SerializeObject(row, Formatting.Indented, settings);

注:

  • 虽然序列化单个DataRow是有意义的,但反序列化是没有意义的,因为DataRow不是一个独立的对象;它只存在于某些父CCD_ 22内部。因此CCD_ 23没有被实现。

  • JsonConverter<T>是在Json.NET 11.0.1中引入的。在早期版本中,继承自JsonConverter

演示小提琴#3在这里。

作为这里找到的答案的替代方案,您可以使用ExpandoObject快速而轻松地将单行呈现为JSON,例如:

var expando = new System.Dynamic.ExpandoObject() as IDictionary<string, object>;
foreach (DataColumn col in myRow.Table.Columns)
{
    expando[col.ColumnName] = myRow[col];
}
var json = JsonConvert.SerializeObject(expando);

拼写?您对"SerializeObject"方法的调用不应该是:吗

string js = JsonConvert.SerializeObject(datatable);

另请参阅关于将数据表转换为JSON字符串的类似问题。

就像Gazzi说的应该包含NewtonSoft.Json库一样,它包含在Visual Studio中。

要获得一个与您所描述的类似的对象,您应该创建一个类似Country.cs的数据模型,它看起来像这样。

[Serializable]
public class CountryModel {
   public int ID { get; set; }
   public string Title { get; set; }
   public List<ValueModel> Values { get; set; }
}
[Serializable]
public class ValueModel {
   public int ValueID { get; set; }
   public string Type { get; set; }
}

创建一个辅助函数,将表数据转换为这些模型。然后,您可以根据需要使用Newtonsoft库序列化/反序列化数据。