问题
I want to convert a dataset which has multiple data-tables within it.
Following is the example,
The dataset X has two data tables A and B

I want the result as follows,
{
"type":"A",
"value":"100",
"details":[
{"name":"John", "age":"45", "gender":"M"},
{"name":"Sebastin", "age":"34", "gender":"M"},
{"name":"Marc", "age":"23", "gender":"M"},
{"name":"Natalia", "age":"34", "gender":"F"}
]
}
Currently I am using Newtonsoft.Json. Is it possible with Newtonsoft.Json? If not, is it possible with any other .net Json tools?
回答1:
You can get the JSON you want by implementing a custom JsonConverter
for the DataSet like this:
class CustomDataSetConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(DataSet));
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
DataSet x = (DataSet)value;
JObject jObject = new JObject();
DataTable a = x.Tables["A"];
foreach (DataColumn col in a.Columns)
{
jObject.Add(col.Caption.ToLower(), a.Rows[0][col].ToString());
}
JArray jArray = new JArray();
DataTable b = x.Tables["B"];
foreach (DataRow row in b.Rows)
{
JObject jo = new JObject();
foreach (DataColumn col in b.Columns)
{
jo.Add(col.Caption.ToLower(), row[col].ToString());
}
jArray.Add(jo);
}
jObject.Add("details", jArray);
jObject.WriteTo(writer);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
Here is a demo:
class Program
{
static void Main(string[] args)
{
DataSet x = new DataSet();
DataTable a = x.Tables.Add("A");
a.Columns.Add("Type");
a.Columns.Add("Value");
a.Rows.Add("A", "100");
DataTable b = x.Tables.Add("B");
b.Columns.Add("Name");
b.Columns.Add("Age");
b.Columns.Add("Gender");
b.Rows.Add("John", "45", "M");
b.Rows.Add("Sebastian", "34", "M");
b.Rows.Add("Marc", "23", "M");
b.Rows.Add("Natalia", "34", "F");
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.Converters.Add(new CustomDataSetConverter());
settings.Formatting = Formatting.Indented;
string json = JsonConvert.SerializeObject(x, settings);
Console.WriteLine(json);
}
}
Output:
{
"type": "A",
"value": "100",
"details": [
{
"name": "John",
"age": "45",
"gender": "M"
},
{
"name": "Sebastian",
"age": "34",
"gender": "M"
},
{
"name": "Marc",
"age": "23",
"gender": "M"
},
{
"name": "Natalia",
"age": "34",
"gender": "F"
}
]
}
回答2:
I don't think Json.Net will do this automatically, but you should be able to do this using Typed Datasets.
A typed dataset is the same as the regular DataSet/DataTable classes, but they extend them with properties for each column in the tables and with relations.
Edit:
Alternatively you could build a method that converts the DataTable structures into a class model and then use Json.Net to serialize that. The data model would be simple, with only two classes, and the conversion should also be quite simple to implement.
Edit 2:
An example of how to convert the data table into a class structure:
public class ClassA
{
public string Type { get; set; }
public int Value { get; set; }
public List<ClassB> Details { get; set; }
public static ClassA FromDataRow(DataRow row, IEnumerable<DataRow> relatedRows)
{
var classA = new ClassA
{
Type = (string) row["Type"],
Value = (int) row["Value"],
Details = relatedRows.Select(r => new ClassB
{
Name = (string)r["Name"],
Age = (int)r["Age"],
Gender = (string)r["Gender"]
}).ToList()
};
return classA;
}
}
public class ClassB
{
public string Name { get; set; }
public int Age { get; set; }
public string Gender { get; set; }
}
Here you can run ClassA.FromDataRow() and pass it one row from TableA and a list of rows from TableB and end up with an object structure. This can easily be serialized to the format you want.
Please note that the code must be modified for your use and will probably not compile as it is. But the concept should be clear.
回答3:
Final Solution for reference
using System.Web.Script.Serialization;
public class ClassA
{
public string Type { get; set; }
public string Value { get; set; }
public List<ClassB> Details { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
DataSet x = new DataSet();
DataTable a = x.Tables.Add("A");
a.Columns.Add("Type");
a.Columns.Add("Value");
a.Rows.Add("A", "100");
DataTable b = x.Tables.Add("B");
b.Columns.Add("Name");
b.Columns.Add("Age");
b.Columns.Add("Gender");
b.Rows.Add("John", "45", "M");
b.Rows.Add("Sebastian", "34", "M");
b.Rows.Add("Marc", "23", "M");
b.Rows.Add("Natalia", "34", "F");
var s = FromDataRow(a.Rows[0], b.AsEnumerable());
JavaScriptSerializer jss = new JavaScriptSerializer();
string output = jss.Serialize(s);
}
public static ClassA FromDataRow(DataRow row, IEnumerable<DataRow> relatedRows)
{
var classA = new ClassA
{
Type = (string)row["Type"],
Value = (string)row["Value"],
Details = relatedRows.Select(r => new ClassB
{
Name = (string)r["Name"],
Age = (string)r["Age"],
Gender = (string)r["Gender"]
}).ToList()
};
return classA;
}
}
public class ClassB
{
public string Name { get; set; }
public string Age { get; set; }
public string Gender { get; set; }
}
来源:https://stackoverflow.com/questions/21727144/convert-dataset-with-multiple-datatables-to-json