web-dev-qa-db-ja.com

JSONの逆シリアル化-ルート要素を無視する方法は?

'd'ルート要素内にラップされたJSON結果を返すWCFサービスを使用しています。 JSON応答は次のようになります。

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

動的型付けを使用したくありません。逆シリアル化するときに使用したいクラスDiagnostics.Common.DiskSpaceInfoがあります。

Json.NET(Netwonsoft JSON)を使用しています。

問題は、ルート要素(その「d」要素)を無視し、内部にあるものを解析するように指示する方法です。

私がこれまでに持っている最善の解決策は、匿名型を使用することです。

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

これは実際には機能しますが、私はあまり好きではありません。別の方法はありますか?私が欲しいのは次のようなものです:

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

またはそのようなもの...

22

この場合、ルートノードである「d」のように検索する方法がわかっている場合は、次の操作を実行できます。

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

わからないルートクラスを単に無視したい場合は、test2.ToObject<DiskSpaceInfo[]>();の代わりにConsole.Write(test2);を使用できるというだけで、"@ Giu Do"ソリューションを使用できます。

        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[]>();
                }
            }
        }
20
keyr

ここでの以前の回答に続いて、独自の静的ユーティリティクラスを使用することをお勧めします。これは再利用可能であり、探している構文を取得できます。

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

次のように呼び出します。

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

または

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

Newtonsoftによると、JSon.netを使用していると思います。これが私のソリューションです。このフレームワークで利用可能なLinq to JSonを使用しました:

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

    }
}
}

私はプロパティFirstを使用しました。これは、受け取ったjsonの最初のノードであるdの後の最初のノードを見つける必要があるためです。

Mainを再現する関数を作成する必要があります。回避するために、オブジェクトがnullでないかどうかを確認することを忘れないでくださいNullReferenceException

1
Giu