2012-12-04 22 views
17

Sto consumando un servizio WCF che restituisce risultati JSON racchiusi all'interno dell'elemento radice 'd'. La risposta JSON assomiglia a questo:Deserializzazione JSON - come ignorare l'elemento radice?

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

Non voglio usare la tipizzazione dinamica, ho il mio Diagnostics.Common.DiskSpaceInfo classe che voglio usare quando la deserializzazione.

Sto utilizzando Json.NET (Netwonsoft JSON).

La domanda è come dirgli di ignorare l'elemento radice (quell'elemento 'd') e analizzare cosa c'è dentro.

La soluzione migliore che ho finora è quello di utilizzare un tipo anonimo:

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

questo funziona realmente, ma non mi piace molto. C'è un altro modo? Quello che vorrei è qualcosa di simile:

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

o qualcosa del genere ...

+0

+1 perché mi piace la soluzione di tipo anonimo. –

+0

Domanda correlata che chiede come eseguire questa operazione senza analizzare un 'JToken' intermedio: [JSON.NET deserializza una proprietà specifica] (https://stackoverflow.com/questions/19438472/json-net-deserialize-a-specific- proprietà). – dbc

risposta

16

Se si sa cosa cercare come in questo caso "d" che è un nodo radice, è possibile eseguire quanto segue.

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

Se si vuole semplicemente ignorare la classe radice che non si conosce, è possibile utilizzare la soluzione di"@Giu Do" solo che è possibile utilizzare test2.ToObject<DiskSpaceInfo[]>(); al posto del 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

Grazie! Belle soluzioni, le ho provate e funzionano. Lascerò l'argomento aperto nel caso qualcuno offra un approccio diverso e poi contrassegnerò il tuo come risposta all'argomento. Tuttavia, nessuna soluzione in particolare mi dà la sensazione di apprezzarlo più degli altri (incluso il mio approccio di tipo anonimo originale). Forse posso fare un po 'di benchmarking per vedere se c'è un vantaggio in termini di prestazioni in uno dei tre modi. –

1

Con Newtonsoft, suppongo si utilizza JSon.net, ecco la mia soluzione, che ho usato LINQ a JSON disponibili in questo quadro:

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

    } 
} 
} 

ho usato la proprietà prima perché è necessario trovare il primo nodo dopo il d, che è il primo nodo del jSON che hai ricevuto.

Devi solo creare una funzione che riproduca il Principale, non dimenticare di controllare se gli oggetti non sono nulli per evitare NullReferenceException.

+0

Grazie Giu Do per la denominazione Json.NET, l'ho modificata nella domanda originale. Per quanto riguarda la soluzione, come posso trasmettere test2 al tipo corretto DiskSpaceInfo? test2 è ancora di tipo Joken. –

1

In seguito alle risposte precedenti, vorrei suggerire di utilizzare la propria classe di utilità statica. Questo è riutilizzabile e ti permetterà di ottenere la sintassi che stai cercando.

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

Si potrebbe richiamare in questo modo:

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

o

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