使用c#通常使Json变平

我想一般地压扁一些json,所以我可以转换为数据表并使用c#绑定到数据网格

什么是最好的办法,记住我不知道我要下多少级别?

例如

 {“appointmentmentid”: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”,“电子邮件“:”asdfghj“,”web“:”asdfghjk“,”archived“:false},”安装“:[{”installationid“:6,”installationstatus“:{”installationstatusid“:4,”installationstatus“:” FAIL“},”isactive“:true},{”installationid“:7,”installationstatus“:{”installationstatusid“:1,”installationstatus“:”NEW“},”isactive“:false}],”archived“:假的 

我想扩展这个(我想我可以迭代我转换它的数据表)而不是instal.1.installationid,我会得到installationid1。

因为我要在网格中显示结果数据表,我想保持列名称友好。

您可以使用Json.Net的LINQ-to-JSON API将数据解析为JToken结构。 从那里,您可以使用递归辅助方法来遍历结构并将其展平为Dictionary ,其中键是原始JSON中每个值的“路径”。 我会写这样的东西:

 public class JsonHelper { public static Dictionary DeserializeAndFlatten(string json) { Dictionary dict = new Dictionary(); JToken token = JToken.Parse(json); FillDictionaryFromJToken(dict, token, ""); return dict; } private static void FillDictionaryFromJToken(Dictionary dict, JToken token, string prefix) { switch (token.Type) { case JTokenType.Object: foreach (JProperty prop in token.Children()) { 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一起使用,最终会得到如下的键值对:

 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 

如果你想让键更加人性化,你可以使用一些字符串操作来削减它们。 也许是这样的:

 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); } 

这会给你这个输出:

 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 vs 。 archived )。 你需要弄清楚如何自己处理这个问题。

小提琴: https : //dotnetfiddle.net/gzhWHk

反序列化,然后LINQ选择展平。 我猜,既然你没有说明,你想要所有的约会和安装信息与特定安装在同一记录上吗?

我最初的想法是利用动态,这样你就可以避免为你的JSON输入静态模式。 如果您已经拥有可以充当JSON模式的静态类型,那么您可以避免动态(以及它所需的全部动态)。 这是一个示例类 – 使用JSON.NET – 来说明我在想什么:

 public class DeserializeAndFlatten { public dynamic ParseJson() { var appointment = JObject.Parse(JsonData.JSON_TO_PARSE); // <-- replace the constant w/ the real JSON... // this is where you flatten it all out! // not going to put all the fields in, that would kill the example, LOL var installations = appointment["installations"].Select(installation => new { appointmentId = appointment["appointmentid"], policyId = appointment["policyid"], vehicleId = appointment["vehicle"]["id"], vehicleMake = appointment["vehicle"]["make"], vehicleModel = appointment["vehicle"]["model"], installerId = appointment["installer"]["installerid"], installerName = appointment["installer"]["name"], installationId = installation["installationid"], installationStatus = installation["installationstatus"]["installationstatus"], installationStatusId = installation["installationstatus"]["installationstatusid"], }).ToList(); return installations; } } 

你可以测试代码:

  static void Main(string[] args) { var jsonParser = new DeserializeAndFlatten(); var installations = jsonParser.ParseJson(); // FYI we get back a dynamic listing, // so intellisense wont work... foreach (var installation in installations) { Console.WriteLine($"appointmentId: {installation.appointmentId}"); Console.WriteLine($"installer: {installation.installerName}"); Console.WriteLine($"installation id: {installation.installationId}"); Console.WriteLine($"status: {installation.installationStatus}"); Console.WriteLine(); } Console.ReadLine(); }