Как сделать запрос и перечислить сложный объект JSON, используя JSON.Net в C#

Как я могу запросить (чтобы увидеть, существует ли свойство) и перечислить (свойство массива), найденные в сложном объекте JSON, используя JSON.NET в C#?

Я получаю сложный объект JSON из API с переменным числом / типом свойств.

Я продолжаю читать документацию JSON.Net, проверять примеры и т. Д., Но далеко не ушел, и теряюсь в JObject, JArray, JToken, используя динамические и т. Д.

Я хочу найти pageResponses.scriptOutput свойство, убедитесь, что оно содержит и .items[] массив, а затем перечислить / перебрать массив.

редактировать

Я добился прогресса и нашел опечатку в примере данных JSON.

Но как я могу запросить / перечислить дочерние объекты, используя имена ключей, например (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
      }
    ]
  }
}

2 ответа

Решение

Я предлагаю создать прокси-класс (я использовал http://json2csharp.com/):

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];
}

Быстро, легко и точно!

Другие вопросы по тегам