2012-12-04 5 views
17

Używam usługi WCF, która zwraca wyniki JSON zapakowane wewnątrz elementu głównego "d". Odpowiedź JSON wygląda następująco:Deseryzacja JSON - jak zignorować element główny?

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

nie chcę użyć dynamicznej wpisywanie, mam klasy Diagnostics.Common.DiskSpaceInfo że chcę użyć podczas deserializacji.

Używam Json.NET (Netwonsoft JSON).

Pytanie, w jaki sposób powiedzieć, aby zignorować element główny (ten element "d") i przeanalizować, co jest w środku.

Najlepszym rozwiązaniem mam tak daleko jest użycie typu anonimowego:

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

to faktycznie działa, ale nie podoba mi się to bardzo. Czy istnieje inny sposób? Chciałbym coś takiego jak:

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

czy coś takiego ...

+0

+1 bo lubię swój anonimowych rozwiązanie typu. –

+0

Powiązane pytanie, które pyta, jak to zrobić bez parsowania do pośredniego 'JToken': [JSON.NET deserialize określonej właściwości] (https://stackoverflow.com/questions/19438472/json-net-deserialize-a-specific- własność). – dbc

Odpowiedz

16

Jeśli wiesz, czego szukać jak w tym przypadku "d", który jest węzłem głównym, możesz wykonać następujące czynności.

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

Jeśli chcesz po prostu zignorować klasę głównego, którego nie znasz, to możesz użyć „@Giu zrobienia” rozwiązanie tylko, że można użyć test2.ToObject<DiskSpaceInfo[]>(); zamiast 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

Dzięki! Ładne rozwiązania, wypróbowałem je i działają. Zostawię temat otwarty na wypadek, gdyby ktoś zaproponował inne podejście, a następnie zaznaczę twoją jako odpowiedź na dany temat. Jednak żadne rozwiązanie nie daje mi wyraźnego poczucia, że ​​bardziej lubię to bardziej niż inne (w tym moje oryginalne podejście typu anonimowego). Być może uda mi się przeprowadzić analizę porównawczą, aby sprawdzić, czy występuje efekt wydajności na jeden z trzech sposobów. –

1

Przez Newtonsoft, przypuszczam użyć JSon.net, tu jest moje rozwiązanie, użyłem Linq do JSON dostępnych w tym kontekście:

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

    } 
} 
} 

Użyłem z obiektem First ponieważ trzeba znaleźć pierwszy węzeł po D, który pierwszy węzeł z JSON, który otrzymałeś.

Trzeba tylko utworzyć funkcję, która odtwarza Main, nie zapomnij sprawdzić, czy obiekty nie są zerowe, aby uniknąć NullReferenceException.

+0

Dzięki Giu Do za nazewnictwo Json.NET, zredagowałem to w pierwotnym pytaniu. Jeśli chodzi o Twoje rozwiązanie, w jaki sposób przesłać test2 do poprawnego typu DiskSpaceInfo? test2 nadal jest typu JToken. –

1

W następstwie poprzednich odpowiedzi tutaj, chciałbym zasugerować użycie własnej statycznej klasy narzędzia. To jest wielokrotnego użytku i pozwoli ci uzyskać składnię, której szukasz.

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

Można by powołać go tak:

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

lub

var resultB = JsonUtil.Deserialize<DiskSpaceInfoRoot>(json, ignoreRoot: false);