关于Json数据动态解析的处理方法
有时会遇到json数据是动态的,没有固定的格式和字段,没办法反序列化固定model进行解析,只能用dynamic来接收。如何解析呢?想到的办法是转化成键值对,用Dictionary
首先用到Newtonsoft.Json来解析,简单介绍下目前用到的这里面的几个类的作用:
- JToken:抽象类,所有json元素描述的父类
- JObject:json对象描述,对应{}
- JProperty:json中key:value的描述,对应{}中的键值
- JArray :描述json数组,对应[]
- JValue:描述json中的value
写了个解析json为字典的扩展方法,支持设置解析的深度,一开始没有发现JToken有Path这个属性,自己写了全路径的拼接(代码第一个方法),正好可以加深对json和Newtonsoft.Json的理解和应用,代码如下:

1 using Newtonsoft.Json.Linq; 2 using System; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Text; 6 7 namespace Extensions 8 { 9 public static class JsonHelperExtension 10 { 11 ///12 /// json数据解析字典数据 13 /// 14 /// 键头 15 /// 键 16 /// json源数据 17 /// 数组索引 18 /// 字典 19 /// 深度 20 /// 21 public static Dictionary<string, object> GetDictionary(Dictionary<string, object> dic,string keyHeadName, JToken targetJToken , string key=null, 22 int arrayStartIndex=0, int depth = -2) 23 { 24 if (depth + 1 == 0) return dic; 25 foreach (var token in targetJToken) 26 { 27 if (targetJToken.Type.Equals(JTokenType.Array))//json数组 28 { 29 var jArray = targetJToken.ToObject (); 30 var pathKey = key + arrayStartIndex++; 31 if (token.Type.Equals(JTokenType.String) || token.Type.Equals(JTokenType.Integer) || 32 token.Type.Equals(JTokenType.Float))//JValue 33 { 34 var jValue = token.ToObject (); 35 var val = jValue?.Value; 36 dic.Add(keyHeadName + ":" + pathKey, val); 37 continue; 38 } 39 else//非JValue 40 { 41 GetDictionary(dic, keyHeadName, token, pathKey, 0, depth - 1); 42 } 43 } 44 else//非json数组 45 { 46 var jProperty = token.ToObject (); 47 var pathKey = key == null ? jProperty?.Name : key + "." + jProperty?.Name; 48 if (jProperty.Value.Type.Equals(JTokenType.String) || jProperty.Value.Type.Equals(JTokenType.Integer) || 49 jProperty.Value.Type.Equals(JTokenType.Float))//JValue 50 { 51 var jValue = jProperty.Value.ToObject (); 52 var val = jValue?.Value; 53 dic.Add(keyHeadName + ":" + pathKey, val); 54 continue; 55 } 56 else//非JValue 57 { 58 GetDictionary(dic, keyHeadName, jProperty.Value, pathKey, 0, depth - 1); 59 } 60 } 61 } 62 63 return dic; 64 } 65 66 /// 67 /// json数据解析字典数据 68 /// 69 /// 键头 70 /// 目标json对象 71 /// 字典 72 /// 小于-1全遍历 73 /// 74 public static Dictionary<string, object> GetDictionary(string keyHeadName, JToken currentJToken, 75 Dictionary<string, object> dic, int depth = -2) 76 { 77 var key = keyHeadName; 78 if (depth + 1 == 0) return dic; 79 foreach (var jsonValue in currentJToken) 80 { 81 if (jsonValue.Type.Equals(JTokenType.String) || jsonValue.Type.Equals(JTokenType.Integer) || 82 jsonValue.Type.Equals(JTokenType.Float)) 83 { 84 var jValue = jsonValue.ToObject (); 85 key = keyHeadName + ":" + jsonValue.Path.Replace("[", "") 86 .Replace("]", ""); 87 dic.Add(key, jValue?.Value); 88 continue; 89 } 90 else 91 { 92 dic = GetDictionary(key, jsonValue, dic, depth - 1); 93 } 94 } 95 96 return dic; 97 } 98 } 99 }
测试一下:

1 static void Main(string[] args) 2 { 3 var json = 4 "{\"key\":\"value1\",\"keyX\":{\"key\":\"value2\",\"keyX\":[{\"key\":\"value3\"},{\"key\":\"value4\"}],\"keyXX\":[\"value5\",\"value6\"]},\"keyXX\":[[{\"key\":\"value7\"},{\"key\":\"value8\"}],[\"value9\",\"value10\"]]}"; 5 var jToken = JToken.Parse(json); 6 7 var dic1 = new Dictionary<string, object>(); 8 var dic2 = new Dictionary<string, object>(); 9 dic1 = JsonHelperExtension.GetDictionary(dic1, "S", jToken, null, 0); 10 dic2 = JsonHelperExtension.GetDictionary("S", jToken, dic2, -2); 11 12 Console.WriteLine(JsonConvert.SerializeObject(dic1)); 13 Console.WriteLine(JsonConvert.SerializeObject(dic2)); 14 15 Console.ReadKey(); 16 }
解析结果正确,两个方法结果一致: