通常使用C#展平Json [英] Generically Flatten Json using c#
问题描述
我想一般地展平一些json,以便我可以转换为数据表并使用c#绑定到数据网格
I want to generically flatten some json so I can convert to a datatable and bind to a datagrid using c#
记住我不知道要下降多少级别,最好的控制方式是什么?
What is the best way of doign it, bearing in mind I dont know how many levels I am going down?
例如
{
"appointmentid": 4,
"policyid": 1,
"guid": "00000000-0000-0000-0000-000000000000",
"number": "1234567890",
"ampm": "false",
"date": "2015-09-08T00:00:00",
"vehicle": {
"id": 1,
"guid": "00000000-0000-0000-0000-000000000000",
"make": null,
"model": null
},
"installer": {
"installerid": "1",
"name": "Installer 1",
"contact": "qwerty",
"qascore": "0",
"address1": "qwerty",
"address2": "qwerty",
"address3": null,
"address4": null,
"city": "qwertyu",
"county": "qwertyu",
"postcode": "asdfghj",
"country": "GB",
"email": "asdfghj",
"web": "asdfghjk",
"archived": false
},
"installations": [
{
"installationid": 6,
"installationstatus": {
"installationstatusid": 4,
"installationstatus": "FAIL"
},
"isactive": true
},
{
"installationid": 7,
"installationstatus": {
"installationstatusid": 1,
"installationstatus": "NEW"
},
"isactive": false
}
],
"archived": false
}
我想扩展它(我想可以对转换后的数据表进行迭代),而不是installations.1.installationid,我可以得到installationid1.
i would like to extend this (I suppose I could iterate over the datatable on I had converted it) rather than installations.1.installationid, i would get installationid1.
因为我要在网格中显示结果数据表,所以我希望保持列名友好.
as I'm going to be displaying the resulting datatable in a grid I would like to keep the column names friendly.
推荐答案
您可以使用Json.Net的 LINQ -to-JSON API 将数据解析为 JToken
结构.从那里,您可以使用递归辅助方法来遍历结构并将其展平到Dictionary<string, object>
,其中键是原始JSON中每个值的路径".我会这样写:
You can use Json.Net's LINQ-to-JSON API to parse the data into a JToken
structure. From there, you can use a recursive helper method to walk the structure and flatten it to a Dictionary<string, object>
where the keys are the "path" to each value from the original JSON. I would write it something like this:
public class JsonHelper
{
public static Dictionary<string, object> DeserializeAndFlatten(string json)
{
Dictionary<string, object> dict = new Dictionary<string, object>();
JToken token = JToken.Parse(json);
FillDictionaryFromJToken(dict, token, "");
return dict;
}
private static void FillDictionaryFromJToken(Dictionary<string, object> dict, JToken token, string prefix)
{
switch (token.Type)
{
case JTokenType.Object:
foreach (JProperty prop in token.Children<JProperty>())
{
FillDictionaryFromJToken(dict, prop.Value, Join(prefix, prop.Name));
}
break;
case JTokenType.Array:
int index = 0;
foreach (JToken value in token.Children())
{
FillDictionaryFromJToken(dict, value, Join(prefix, index.ToString()));
index++;
}
break;
default:
dict.Add(prefix, ((JValue)token).Value);
break;
}
}
private static string Join(string prefix, string name)
{
return (string.IsNullOrEmpty(prefix) ? name : prefix + "." + name);
}
}
将此DeserializeAndFlatten
方法与您的JSON结合使用,您将最终得到像这样的键值对:
Using this DeserializeAndFlatten
method with your JSON you would end up with key-value pairs like this:
appointmentid: 4
policyid: 1
guid: 00000000-0000-0000-0000-000000000000
number: 1234567890
ampm: false
date: 9/8/2015 12:00:00 AM
vehicle.id: 1
vehicle.guid: 00000000-0000-0000-0000-000000000000
vehicle.make:
vehicle.model:
installer.installerid: 1
installer.name: Installer 1
installer.contact: qwerty
installer.qascore: 0
installer.address1: qwerty
installer.address2: qwerty
installer.address3:
installer.address4:
installer.city: qwertyu
installer.county: qwertyu
installer.postcode: asdfghj
installer.country: GB
installer.email: asdfghj
installer.web: asdfghjk
installer.archived: False
installations.0.installationid: 6
installations.0.installationstatus.installationstatusid: 4
installations.0.installationstatus.installationstatus: FAIL
installations.0.isactive: True
installations.1.installationid: 7
installations.1.installationstatus.installationstatusid: 1
installations.1.installationstatus.installationstatus: NEW
installations.1.isactive: False
archived: False
如果您希望使按键更人性化,则可以使用一些字符串操作将其缩减.也许是这样的:
If you're looking to make the keys more human friendly, you could use a little string manipulation to cut them down. Maybe something like this:
var dict = JsonHelper.DeserializeAndFlatten(json);
foreach (var kvp in dict)
{
int i = kvp.Key.LastIndexOf(".");
string key = (i > -1 ? kvp.Key.Substring(i + 1) : kvp.Key);
Match m = Regex.Match(kvp.Key, @"\.([0-9]+)\.");
if (m.Success) key += m.Groups[1].Value;
Console.WriteLine(key + ": " + kvp.Value);
}
这将为您提供以下输出:
That would give you this output instead:
appointmentid: 4
policyid: 1
guid: 00000000-0000-0000-0000-000000000000
number: 1234567890
ampm: false
date: 9/8/2015 12:00:00 AM
id: 1
guid: 00000000-0000-0000-0000-000000000000
make:
model:
installerid: 1
name: Installer 1
contact: qwerty
qascore: 0
address1: qwerty
address2: qwerty
address3:
address4:
city: qwertyu
county: qwertyu
postcode: asdfghj
country: GB
email: asdfghj
web: asdfghjk
archived: False
installationid0: 6
installationstatusid0: 4
installationstatus0: FAIL
isactive0: True
installationid1: 7
installationstatusid1: 1
installationstatus1: NEW
isactive1: False
archived: False
但是请注意,通过这种安排,您失去了一些上下文:例如,您可以看到现在有两个相同的archived
键,而在原始JSON中,它们是不同的,因为它们出现在层次结构的不同部分中(installer.archived
与archived
).您将需要弄清楚如何自行解决该问题.
But note, with this arrangement, you have lost some context: for example, you can see that there are now two identical archived
keys, whereas in the original JSON they were distinct because they appeared in different parts of the hierarchy (installer.archived
vs. archived
). You will need to figure out how to deal with that problem on your own.
提琴: https://dotnetfiddle.net/gzhWHk
这篇关于通常使用C#展平Json的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!