【问题标题】:Parse complex JSON: multiple loops vs. classes解析复杂的 JSON:多个循环与类
【发布时间】:2016-07-12 06:36:16
【问题描述】:

我有一个 Json 类型:

{
"JobProcessors": [
{
  "JobName": "ArchivalJob",
  "IsEnabled": true,
  "Batching": {
    "BatchSize": 0,
    "DegreeOfParallelism": -1
  },
  "Settings": {
    "ArchivalJobCollectionPageSize": 50
  }
},
{
  "JobName": "AuditLogJob",
  "IsEnabled": false,
  "Batching": {
    "BatchSize": 10,
    "DegreeOfParallelism": -1
  },
  "Settings": {}
} 
],  
"ScheduledJobs": [
{
  "JobName": "RemoteStartClientCommandJob",
  "PrimaryAction": {
    "ConnectionString": "#JobProcessorsIntegrationSBConnectionStringValue#",
     "Settings": {
      "LeadTimeInSeconds": "600",
      "MaxSrsJobCount": 25
    }
  },
  "ErrorAction": {
    "ConnectionString": "#PairedJobProcessorIntegrationSBConnectionStringValue#",
    "EntityPath": "remotestartqueue",
    "Settings": {
      "LeadTimeInSeconds": "600",
      "MaxSrsJobCount": 25
    }
  }
}
]  
}

我想检查“JobProcessors”类别下所有“JobName”的“IsEnabled”属性。 在 C# 中我到目前为止使用的是:

dynamic parsedJson = JsonConvert.DeserializeObject(reader.GetString(1));
foreach (var item in parsedJson)
{
    foreach (var smallitem in item)
    {
        foreach (var tag in smallitem)
        {
            if(tag.IsEnabled.toString()=="true"){
                Console.WriteLine("true");
            }                                 
        }
    }

}

这给了我正确的结果,除了它也为 "ScheduledJobs" 进行迭代。但主要问题是:


这是正确或最有效的方法吗?如果可能的话建议一些更好的方法。

我知道的一个是使用类,但我可能事先不知道 json 结构。而且 json 非常庞大,所以制作类可能很麻烦!!

【问题讨论】:

  • 你为什么要解析成dynamic?更好地创建一个强类型对象来表示您的结构
  • 用 for 循环切换 foreach。 for 循环总是比 for each 循环快
  • @haim770 我可能事先不知道类的结构。
  • @Florian Neiss 实际上我不知道数组中元素的数量。
  • 另一种解决方法是在 foreach (var smallitem in item) 下编写一个 if 来检查 smallitem 是否为“JobProcessors”

标签: c# json parsing json.net


【解决方案1】:

鉴于您已经在使用 JObject.Parse(jsonstring); 来解析 JSON 字符串,您可以使用 SelectTokens() 和 JSONPath query 来查找“JobProcessors”下的所有“JobName”对象:

// I want to check the "IsEnabled" property for all "JobName" for which come under "JobProcessors" 
foreach (var job in root.SelectTokens("..JobProcessors[?(@.JobName)]"))
{
    var isEnabled = (bool?)job["IsEnabled"];
    Debug.WriteLine(string.Format("Job {0}: IsEnabled={1}", job["JobName"], isEnabled));
}

注意事项:

  • .. 是 递归下降 运算符:它递归下降返回每个项目的 JToken 层次结构,随后与查询字符串的其余部分进行匹配。

  • JobProcessors 返回该名称的属性值。

  • [?(@.JobName)] 返回数组项(在本例中为JobProcessors),它们是具有JobName 属性的对象。

  • (bool?) 将“IsEnabled”的值转换为布尔值,如果缺失则为 null。

这个的输出是:

Job ArchivalJob: IsEnabled=True
Job AuditLogJob: IsEnabled=False

【讨论】:

  • 特别感谢[?(@.JobName)]。
【解决方案2】:

在您的代码 sn-p 中,我们使用了两个 foreach,大型对象可能需要一些时间。所以我们可以在单个 foreach 中做同样的事情,或者如果你有一些特定的节点要获取或搜索,我们可以使用 linq,为此首先我们需要将我们的 json 对象转换为 c# 对象。要将 Json 对象转换为 C#,您可以使用此站点“http://json2csharp.com/”然后我们可以将 Json 对象反序列化为 C#。

会是这样的

string jsonString = "your Json Object as string";
        var jsonObject = JsonConvert.DeserializeObject<RootObject>(jsonString);
        foreach (JobProcessor obj in jsonObject.JobProcessors)
        {
            string JobName = obj.JobName;
            bool value=obj.IsEnabled;
        }

我还把给定的 Json 转换成 c# 对象,如果 Json 对象相同,你可以直接使用这些类。

    public class Batching
    {
        public int BatchSize { get; set; }
        public int DegreeOfParallelism { get; set; }
    }

    public class Settings
    {
        public int ArchivalJobCollectionPageSize { get; set; }
    }

    public class JobProcessor
    {
        public string JobName { get; set; }
        public bool IsEnabled { get; set; }
        public Batching Batching { get; set; }
        public Settings Settings { get; set; }
    }

    public class Settings2
    {
        public string LeadTimeInSeconds { get; set; }
        public int MaxSrsJobCount { get; set; }
    }

    public class PrimaryAction
    {
        public string ConnectionString { get; set; }
        public Settings2 Settings { get; set; }
    }

    public class Settings3
    {
        public string LeadTimeInSeconds { get; set; }
        public int MaxSrsJobCount { get; set; }
    }

    public class ErrorAction
    {
        public string ConnectionString { get; set; }
        public string EntityPath { get; set; }
        public Settings3 Settings { get; set; }
    }

    public class ScheduledJob
    {
        public string JobName { get; set; }
        public PrimaryAction PrimaryAction { get; set; }
        public ErrorAction ErrorAction { get; set; }
    }

    public class RootObject
    {
        public List<JobProcessor> JobProcessors { get; set; }
        public List<ScheduledJob> ScheduledJobs { get; set; }
    }

希望这会有所帮助。 谢谢

【讨论】:

  • 非常感谢这种方法,但我不想使用类!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-29
  • 2021-06-20
  • 2018-01-05
  • 1970-01-01
相关资源
最近更新 更多