本文转载自 http://xiaosheng.me/2016/10/01/article25/javascript
最近在 C# 项目中须要使用到 Json 格式的数据,我简单上网搜索了一下,基本上有两种操做 Json 数据的方法:php
本着“第三方包必定有比系统自带类优秀地方,不然就不会存在”的原则,再加上 JavaScriptSerializer、DataContractJsonSerializer 等这些自带类库使用起来很麻烦,我坚决果断地就选择了在 Json 操做方面小有名气的 Json.NET。Json.NET 本身也作了与自带类库的比较,详情能够见 Json.NET vs .NET Serializers 和 Json.NET vs Windows.Data.Json。html
Json.NET 是一个 Newtonsoft 编写的开源类库包,你能够直接到 Github 上查看项目的源码和说明。Json.NET 提供了大量对于 Json 数据的操做方法,他们使用起来很是简单,并且执行效率很高。java
JsonConvert 是 Json.NET 中的一个数据转换类,提供了用于 .NET 对象序列化和反序列化的方法 SerializeObject() 和 DeserializeObject()。在一般状况下,咱们也只须要使用这两个方法就足以完成任务了。git
好比说,咱们如今定义了一个学生类 Student:github
class Student //学生类 { public int Id { get; set;} //学号 public string Name { get; set;} //姓名 public double[] Scores { get; set;} //成绩 }
如今咱们建立一个学生类对象,并使用 JsonConvert 类提供的 SerializeObject() 方法将它转换到 Json 字符串(须要引入命名空间 using Newtonsoft.Json):web
Student student = new Student { Id = 12883, Name = "Jim David", Scores = new double[] { 87.5, 92, 76.2 } }; string jsonStudent = JsonConvert.SerializeObject(student); //{"Id":12883,"Name":"Jim David","Scores":[87.5,92.0,76.2]}
能够看到在序列化的过程当中,JsonConvert 会将 .NET 对象中的变量名转换为 Json 中的“属性”,同时将变量的值复制为 Json 的“属性值”。接下来,咱们尝试将 Json 字符串转换为 Student 对象,使用 JsonConvert 提供的 DeserializeObject() 方法:json
Student deserializedStudent = JsonConvert.DeserializeObject<Student>(jsonStudent); Console.WriteLine("student.Id = " + deserializedStudent.Id); //student.Id = 12883 Console.WriteLine("student.Name = " + deserializedStudent.Name); //student.Name = Jim David
能够看到,建立的学生对象 student 的 Json 字符串被顺利地解析成了 Student 对象。在调用 DeserializeObject() 方法进行反序列化时,最好使用带泛型参数的重载方法。api
若是在调用 DeserializeObject() 时不指定对象类型,JsonConvert 会默认转换为 Object 对象。
上面咱们已经简单测试了 JsonConvert 提供的 SerializeObject() 和 DeserializeObject() 方法,完成了 .NET 对象的序列化和反序列化。数组
C# 项目中,除了自定义的类型外,集合(Collections)也是常常会使用的数据类型,包括列表、数组、字典或者咱们自定义的集合类型。咱们一样能够使用以前使用的 SerializeObject() 和 DeserializeObject() 方法来完成集合的序列化和反序列化。
为了使转换后的结果更加易读,我指定转换后的 Json 字符串带缩进。经过向 SerializeObject() 方法传递进第二个参数 Formatting 实现。
Student student1 = new Student { Id = 12883, Name = "Jim David", Scores = new double[] { 87.5, 92, 76.2 } }; Student student2 = new Student { Id = 35228, Name = "Milly Smith", Scores = new double[] { 92.5, 88, 85.7 } }; List<Student> students = new List<Student>(); students.Add(student1); students.Add(student2); string jsonStudents = JsonConvert.SerializeObject(students, Formatting.Indented); //[ // { // "Id": 12883, // "Name": "Jim David", // "Scores": [ // 87.5, // 92.0, // 76.2 // ] // }, // { // "Id": 35228, // "Name": "Milly Smith", // "Scores": [ // 92.5, // 88.0, // 85.7 // ] // } //]
接下来咱们对上面生成的 Json 字符串进行反序列化,解析出原有的 Student 类型列表。一样,咱们须要使用带泛型参数的 DeserializeObject() 方法,指定 JsonConvert 解析的目标类型。
string jsonStudentList = @"[ { 'Id': 12883, 'Name': 'Jim David', 'Scores': [ 87.5, 92.0, 76.2 ] }, { 'Id': 35228, 'Name': 'Milly Smith', 'Scores': [ 92.5, 88.0, 85.7 ] } ]"; List<Student> studentsList = JsonConvert.DeserializeObject<List<Student>>(jsonStudentList); Console.WriteLine(studentsList.Count); //2 Student s = studentsList[0]; Console.WriteLine(s.Name); //Jim David
若是 Json 对象拥有统一类型的属性和属性值,咱们还能够把 Json 字符串反序列化为 .NET 中的字典,Json 对象的“属性”和“属性值”会依次赋值给字典中的 Key 和 Value。下面我举一个简单的例子:
string json = @"{""English"":88.2,""Math"":96.9}"; Dictionary<string, double> values = JsonConvert.DeserializeObject<Dictionary<string, double>>(json); Console.WriteLine(values.Count); //2 Console.WriteLine(values["Math"]); //96.9
现在大量的 Web API 为咱们编写复杂程序提供了极大的方便,例如百度地图 API、图灵机器人 API等等,利用这些 Web 应用程序咱们能够充分发挥云服务的优点,开发出大量有趣的应用。
Web API 一般返回 Json 或 XML 格式的检索数据,因为 Json 数据量更小,因此目前大多数状况下咱们都选择返回 Json 格式的数据。
若是返回的 Json 文档很大,而咱们仅仅须要其中的一小部分数据。按照以前的方法,咱们必须首先定义一个与 Json 对象对应的 .NET 对象,而后反序列化,最后才能从对象中取出咱们须要的数据。而有了 Json.NET,这个任务就很容易实现了,咱们能够局部地解析一个 Json 对象。
下面以获取 Google 搜索结果为例,简单演示一下对复杂结构 Json 文档的解析。
string googleSearchText = @"{ 'responseData': { 'results': [ { 'GsearchResultClass': 'GwebSearch', 'unescapedUrl': 'http://en.wikipedia.org/wiki/Paris_Hilton', 'url': 'http://en.wikipedia.org/wiki/Paris_Hilton', 'visibleUrl': 'en.wikipedia.org', 'cacheUrl': 'http://www.google.com/search?q=cache:TwrPfhd22hYJ:en.wikipedia.org', 'title': '<b>Paris Hilton</b> - Wikipedia, the free encyclopedia', 'titleNoFormatting': 'Paris Hilton - Wikipedia, the free encyclopedia', 'content': '[1] In 2006, she released her debut album...' }, { 'GsearchResultClass': 'GwebSearch', 'unescapedUrl': 'http://www.imdb.com/name/nm0385296/', 'url': 'http://www.imdb.com/name/nm0385296/', 'visibleUrl': 'www.imdb.com', 'cacheUrl': 'http://www.google.com/search?q=cache:1i34KkqnsooJ:www.imdb.com', 'title': '<b>Paris Hilton</b>', 'titleNoFormatting': 'Paris Hilton', 'content': 'Self: Zoolander. Socialite <b>Paris Hilton</b>...' } ], 'cursor': { 'pages': [ { 'start': '0', 'label': 1 }, { 'start': '4', 'label': 2 }, { 'start': '8', 'label': 3 }, { 'start': '12', 'label': 4 } ], 'estimatedResultCount': '59600000', 'currentPageIndex': 0, 'moreResultsUrl': 'http://www.google.com/search?oe=utf8&ie=utf8...' } }, 'responseDetails': null, 'responseStatus': 200 }";
上面就是从 Google 搜索返回的 Json 数据,咱们如今须要的是 responseData 属性下的 results 列表中结果,并且仅仅须要结果中的 title
、content
和 url
属性值。
public class SearchResult { public string Title { get; set; } public string Content { get; set; } public string Url { get; set; } }
//将 Json 文档解析为 JObject JObject googleSearch = JObject.Parse(googleSearchText); //将得到的 Json 结果转换为列表 IList<JToken> results = googleSearch["responseData"]["results"].Children().ToList(); //将 Json 结果反序列化为 .NET 对象 IList<SearchResult> searchResults = new List<SearchResult>(); foreach(JToken result in results) { SearchResult searchResult = JsonConvert.DeserializeObject<SearchResult>(result.ToString()); searchResults.Add(searchResult); } // Title = <b>Paris Hilton</b> - Wikipedia, the free encyclopedia // Content = [1] In 2006, she released her debut album... // Url = http://en.wikipedia.org/wiki/Paris_Hilton // Title = <b>Paris Hilton</b> // Content = Self: Zoolander. Socialite <b>Paris Hilton</b>... // Url = http://www.imdb.com/name/nm0385296/
能够看到,对 Json 文档的解析基本分为如下几步:
JObject[属性]
获取 JObject 对象中某个属性的值(JToken 格式)JToken[属性]
获取属性内部的属性值(依然为 JToken 格式)若是属性值为咱们须要的数据对象,那么直接反序列化该对象就能够了;若是属性值为列表(好比上面 results 属性的值),那么就能够调用 JToken 类的 Children() 函数,得到一个可迭代的 JEnumerable<JToken> 对象(用于迭代访问列表中的每个对象),最后再依次反序列化列表中的对象。