2012-12-04 33 views
17

Tôi đang sử dụng dịch vụ WCF trả về kết quả JSON được bao trong phần tử gốc 'd'. Câu trả lời JSON trông như thế này:Deserializing JSON - cách bỏ qua phần tử gốc?

{"d":[ 
    { 
    "__type":"DiskSpaceInfo:#Diagnostics.Common", 
    "AvailableSpace":38076567552, 
    "Drive":"C:\\", 
    "TotalSpace":134789197824 
    }, 
    { 
    "__type":"DiskSpaceInfo:#Diagnostics.Common", 
    "AvailableSpace":166942183424, 
    "Drive":"D:\\", 
    "TotalSpace":185149157376 
    } 
]} 

Tôi không muốn sử dụng gõ năng động, tôi có Diagnostics.Common.DiskSpaceInfo lớp học của tôi mà tôi muốn sử dụng khi deserializing.

Tôi đang sử dụng Json.NET (JSON của Netwonsoft).

Câu hỏi đặt ra là cách yêu cầu nó bỏ qua phần tử gốc (phần tử 'd' đó) và phân tích nội dung bên trong.

Giải pháp tốt nhất mà tôi có cho đến nay là sử dụng một loại vô danh:

DiskSpaceInfo[] result = JsonConvert.DeserializeAnonymousType(json, new 
    { 
     d = new DiskSpaceInfo[0] 
    }).d; 

này thực sự hoạt động nhưng tôi không thích nó rất nhiều. Có cách nào khác không? Những gì tôi muốn là một cái gì đó như:

DiskSpaceInfo[] result = JsonConvert.Deserialize(json, skipRoot: true); 

hoặc một cái gì đó như thế ...

+0

+1 vì tôi thích giải pháp loại vô danh của bạn. –

+0

Câu hỏi liên quan yêu cầu cách thực hiện điều này mà không cần phân tích cú pháp thành một trung gian 'JToken': [JSON.NET deserialize một thuộc tính cụ thể] (https://stackoverflow.com/questions/19438472/json-net-deserialize-a-specific- bất động sản). – dbc

Trả lời

16

Nếu bạn biết tìm kiếm như thế nào trong trường hợp này "d" là nút gốc thì bạn có thể thực hiện các thao tác sau.

JObject jo = JObject.Parse(json); 
DiskSpaceInfo[] diskSpaceArray = jo.SelectToken("d", false).ToObject<DiskSpaceInfo[]>(); 

Nếu bạn chỉ đơn giản là muốn bỏ qua lớp gốc mà bạn không biết thì bạn có thể sử dụng "@Giu Đỗ" giải pháp chỉ mà bạn có thể sử dụng test2.ToObject<DiskSpaceInfo[]>(); thay vì Console.Write(test2);

 JObject o = JObject.Parse(json); 
     if (o != null) 
     { 
      var test = o.First; 
      if (test != null) 
      { 
       var test2 = test.First; 
       if (test2 != null) 
       { 
        DiskSpaceInfo[] diskSpaceArray = test2.ToObject<DiskSpaceInfo[]>(); 
       } 
      } 
     } 
+0

Cảm ơn! Các giải pháp tốt đẹp, tôi đã thử chúng và chúng hoạt động. Tôi sẽ để chủ đề mở trong trường hợp ai đó đưa ra một cách tiếp cận khác và sau đó tôi sẽ đánh dấu chủ đề của bạn là câu trả lời cho chủ đề. Tuy nhiên, không có giải pháp nào đặc biệt mang lại cho tôi cảm giác mạnh mẽ để thích nó hơn những người khác (bao gồm cả cách tiếp cận kiểu ẩn danh ban đầu của tôi). Có lẽ tôi có thể làm một số điểm chuẩn để xem nếu có một lợi ích hiệu suất theo một trong ba cách. –

1

By Newtonsoft, tôi giả sử bạn sử dụng JSon.net, đây là giải pháp của tôi, tôi đã sử dụng LINQ to JSON sẵn trong khuôn khổ này:

using System; 
using Newtonsoft.Json.Linq; 

namespace JSonTest 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      string json = @"{""d"":[ 
    { 
    ""__type"":""DiskSpaceInfo:#Diagnostics.Common"", 
    ""AvailableSpace"":38076567552, 
    ""Drive"":""C:\\"", 
    ""TotalSpace"":134789197824 
    }, 
    { 
    ""__type"":""DiskSpaceInfo:#Diagnostics.Common"", 
    ""AvailableSpace"":166942183424, 
    ""Drive"":""D:\\"", 
    ""TotalSpace"":185149157376 
    } 
]}"; 
     JObject o = JObject.Parse(json); 

     if (o != null) 
     { 
      var test = o.First; 

      if (test != null) 
      { 
       var test2 = test.First; 
       if (test2 != null) 
       { 
        Console.Write(test2); 
       } 
      } 
     } 

     Console.Read(); 

    } 
} 
} 

tôi đã sử dụng tài sản đầu tiên bởi vì bạn cần phải tìm nút đầu tiên sau khi d, mà là nút đầu tiên của json bạn nhận được.

Bạn chỉ cần tạo một chức năng reproduice chính, đừng quên kiểm tra xem các đối tượng không phải là null để tránh NullReferenceException.

+0

Cảm ơn Giu Do đã đặt tên cho Json.NET, tôi đã chỉnh sửa nó trong câu hỏi gốc. Về giải pháp của bạn, làm cách nào để truyền test2 vào đúng loại DiskSpaceInfo? test2 vẫn thuộc loại JToken. –

1

Tiếp theo các câu trả lời trước đây ở đây, tôi muốn đề xuất sử dụng lớp tiện ích tĩnh của riêng bạn. Điều này có thể tái sử dụng và sẽ cho phép bạn nhận cú pháp bạn đang tìm kiếm.

public static class JsonUtil 
{ 
    public static T Deserialize<T>(string json, bool ignoreRoot) where T : class 
    { 
     return ignoreRoot 
      ? JObject.Parse(json)?.Properties()?.First()?.Value?.ToObject<T>() 
      : JObject.Parse(json)?.ToObject<T>(); 
    } 
} 

Bạn sẽ gọi nó như thế này:

var resultA = JsonUtil.Deserialize<DiskSpaceInfo[]>(json, ignoreRoot: true); 

hoặc

var resultB = JsonUtil.Deserialize<DiskSpaceInfoRoot>(json, ignoreRoot: false); 
Các vấn đề liên quan