C#使用Json.NET解析Json

本文轉載自 http://xiaosheng.me/2016/10/01/article25/javascript

最近在 C# 項目中須要使用到 Json 格式的數據,我簡單上網搜索了一下,基本上有兩種操做 Json 數據的方法:php

  • 使用 Windows 系統自帶的類
  • 使用第三方的包

本着「第三方包必定有比系統自帶類優秀地方,不然就不會存在」的原則,再加上 JavaScriptSerializerDataContractJsonSerializer 等這些自帶類庫使用起來很麻煩,我堅決果斷地就選擇了在 Json 操做方面小有名氣的 Json.NET。Json.NET 本身也作了與自帶類庫的比較,詳情能夠見 Json.NET vs .NET Serializers 和 Json.NET vs Windows.Data.Jsonhtml

Json.NET 是一個 Newtonsoft 編寫的開源類庫包,你能夠直接到 Github 上查看項目的源碼和說明。Json.NET 提供了大量對於 Json 數據的操做方法,他們使用起來很是簡單,並且執行效率很高。java

.NET 對象的序列化和反序列化

1. 普通對象的序列化和反序列化

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

解析複雜的 Json 字符串

現在大量的 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 列表中結果,並且僅僅須要結果中的 titlecontent 和 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 文檔的解析基本分爲如下幾步:

  1. 將 Json 文檔轉換爲 JObject 對象
  2. 使用JObject[屬性]獲取 JObject 對象中某個屬性的值(JToken 格式)
    能夠繼續經過 JToken[屬性] 獲取屬性內部的屬性值(依然爲 JToken 格式)
  3. 將 JToken 格式的屬性值反序列化爲 .NET 對象

若是屬性值爲咱們須要的數據對象,那麼直接反序列化該對象就能夠了;若是屬性值爲列表(好比上面 results 屬性的值),那麼就能夠調用 JToken 類的 Children() 函數,得到一個可迭代的 JEnumerable<JToken> 對象(用於迭代訪問列表中的每個對象),最後再依次反序列化列表中的對象。

相關文章
相關標籤/搜索