如何在 C# 中使用 JSON.Net 查询和枚举复杂的 JSON 对象

How to Query and Enumerate complex JSON object using JSON.Net in C#

如何使用 JSON.NET 在 C# 中 ?

我从 API 接收到一个复杂的 JSON 对象,该对象的属性变量为 number/type。

我一直在阅读 the JSON.Net Documentation、审查示例等,但没有深入了解 JObject、JArray、JToken、使用动态等...

我想找到 pageResponses.scriptOutput 属性,验证它包含 .items[] 数组,然后 enumerate/iterate 数组。

编辑

我取得了进步,但在 JSON 数据示例中发现了拼写错误。

但是我如何 query/enumerate 使用键名的子对象,例如 (item.location, item.timestamp) ?

string json = File.ReadAllText(@"Output.json");
JObject jObj = JObject.Parse(json);

IList<JToken> items = jObj["pageResponses"][0]["scriptOutput"]["items"].ToList();
foreach (JToken item in items){
    Console.WriteLine(item["location"]);
}
/*** Console Output ***/
// Austin, TX
// Anaheim, CA
// Adams, MN
// Barstow, CA

var varItems = from o in jObj["pageResponses"][0]["scriptOutput"]["items"].ToList() select o;

foreach (var item in varItems){
    Console.WriteLine(item["timestamp"]);
}
/*** Console Output ***/
// 2016 - 05 - 03 19:53
// 2016 - 05 - 04 04:10
// 2016 - 05 - 04 08:18
// 2016 - 05 - 01 12:26

(JSON 为简洁起见,下面的示例被删减了)

{
  "meta": {
    "outputAsJson": true,
    "backend": {
      "os": "linux",
      "id": "10.240.0.3_2",
      "requestsProcessed": 8
    }
  },
  "pageResponses": [
    {
      "pageRequest": {
        "renderType": "script",
        "outputAsJson": true
      },
      "frameData": {
        "name": "",
        "childCount": 1
      },
      "events": [
                  {
                    "key": "navigationRequested",
                    "time": "2016-05-06T13:43:30.344Z"
                  },
                  {
                    "key": "navigationRequested",
                    "time": "2016-05-06T13:43:31.131Z"
                  }
      ],
      "scriptOutput": {
        "items": [
          {
            "location": "Austin, TX",
            "timestamp": "2016-05-03 19:53",
            "title": "User Login"
          },
          {
            "location": "Anaheim, CA",
            "timestamp": "2016-05-04 04:10",
            "title": "User Logout"
          },
          {
            "location": "Adams, MN",
            "timestamp": "2016-05-04 08:18",
            "title": "User Login"
          },
          {
            "location": "Barstow, CA",
            "timestamp": "2016-05-01 12:26",
            "title": "User Logout"
          }
        ]
      },
      "statusCode": 200
    }
  ],
  "statusCode": 200,
  "content": {
    "name": "content.json",
    "encoding": "utf8"
  },
  "originalRequest": {
    "pages": [
      {
        "renderType": "script",
        "outputAsJson": true
      }
    ]
  }
}

我建议创建一个代理 class(我使用 json2csharp):

public class Backend
{
    public string os { get; set; }
    public string id { get; set; }
    public int requestsProcessed { get; set; }
}

public class Meta
{
    public bool outputAsJson { get; set; }
    public Backend backend { get; set; }
}

public class PageRequest
{
    public string renderType { get; set; }
    public bool outputAsJson { get; set; }
}

public class FrameData
{
    public string name { get; set; }
    public int childCount { get; set; }
}

public class Event
{
    public string key { get; set; }
    public string time { get; set; }
}

public class ScriptOutput
{
    public List<object> items { get; set; }
}

public class PageRespons
{
    public PageRequest pageRequest { get; set; }
    public FrameData frameData { get; set; }
    public List<Event> events { get; set; }
    public ScriptOutput scriptOutput { get; set; }
    public int statusCode { get; set; }
}

public class Content
{
    public string name { get; set; }
    public string encoding { get; set; }
}

public class Page
{
    public string renderType { get; set; }
    public bool outputAsJson { get; set; }
}

public class OriginalRequest
{
    public List<Page> pages { get; set; }
}

public class RootObject
{
    public Meta meta { get; set; }
    public List<PageRespons> pageResponses { get; set; }
    public int statusCode { get; set; }
    public Content content { get; set; }
    public OriginalRequest originalRequest { get; set; }
}

然后反序列化:

var obj = JsonConvert.DeserializeObject<RootObject>(json);
if (obj != null && obj.pageResponses != null)
{
    foreach (var pageResponse in obj.pageResponses)
    {
        if (pageResponse.scriptOutput == null)
            continue;

        foreach (var item in pageResponse.scriptOutput.items)
        {
            Console.WriteLine(item);
        }
    }
}

我用几个扩展方法来做到这一点,我使用 JsonConvert.DeserializeObject。

下面的代码片段。

用法

ExpandoObject data = JsonConvert.DeserializeObject<ExpandoObject>(jsonString);
if(data.HasProperty("propertyToCheck"))
{
   object[] objects = data.Get<object[]>("propertyToCheck");
}

在上面的代码片段中,我检查了一个 属性 是否存在,然后我将它分配给一个 .Net 类型,在本例中是一个对象数组。虽然它可以是任何类型,只要它是理智的。

扩展方法

public static bool HasProperty(this ExpandoObject value, string property)
{
    bool hasProp = false;
    if (((IDictionary<String, object>)value).ContainsKey(property))
    {
        hasProp = true;
    }
    return hasProp;
}

public static T Get<T>(this ExpandoObject value, string property)
{
    return (T)((IDictionary<String, dynamic>)value)[property];
}

快速、简单、切中要点!