【问题标题】:Pulling an Array from a JSON object in C# (New从 C# 中的 JSON 对象中提取数组(新
【发布时间】:2020-05-23 18:28:37
【问题描述】:

我在 C# 中使用 Newtonsoft JSON。

我有一个正在尝试解析的日志文件,以便我可以使用日志文件中的数据填充数据库。

在日志文件中,每一行都是一个单独的 JSON 对象。

日志文件如下所示:

{ "timestamp":"2020-02-02T04:49:53Z", "event":"Friends", "Status":"Online", "Name":"User1" }
{ "timestamp":"2020-02-02T04:48:06Z", "event":"Commander", "FID":"F2", "Name":"User2" }
{ "timestamp":"2020-02-02T04:48:06Z", "event":"Materials", "Raw":[ { "Name":"cadmium", "Count":9},
      { "Name":"zinc", "Count":45 }, { "Name":"iron", "Count":71 }]}

这是我目前正在做的事情:

var fullPath = @"X:\Data\Log Files\test log.log";
string[] lines = File.ReadAllLines(fullPath);

            foreach (var line in lines)
        {
            var json = JObject.Parse(line);
            var eventType = json["event"].Value<string>();

            JArray raw = (JArray)line["Raw"];

            switch (eventType)
               {
                case "Friends":

                    var status = json["Status"].Value<string>();
                    var frName = json["Name"].Value<string>();

                    Console.WriteLine("The friend " + frName + " is currently " + status + ".");

                    Console.WriteLine(json);

                    break;

                case "Commander":

                    var fid = json["FID"].Value<string>();
                    var CMDR = json["Name"].Value<string>();

                    Console.WriteLine("User " + CMDR + " with ID " + ".");

                    Console.WriteLine(json);

                    break;

                case "Materials":


                    //do something here that is magical.

                    break;

                default:
                    Console.WriteLine("N/A");
                    break;
            }

前两种情况正常。但是,我不知道如何从“材料”事件中获取数组“原始”。

仅供参考 - 该行中还有另外两个数组。所以,我需要能够 提取“Raw”以及其他数组。

到目前为止,我只是想不通。

我是一个初学者,所以请像在和蹒跚学步的孩子说话一样解释这一点。 :)

请帮忙?

非常感谢!

【问题讨论】:

标签: c# arrays json.net


【解决方案1】:

以上所有答案对于您提出的问题都是完全有效的,但是,为了更好的代码可读性和调试,您最好将这些 json 字符串转换为实际的 c# 对象。例如,您会设置一些这样的模型:

public class Friends
{
    public string Timestamp { get; set; }
    public string Event { get; set; }
    public string Status { get; set; }
    public string Name { get; set; }
}

public class Commander
{
    public string Timestamp { get; set; }
    public string Event { get; set; }
    public string FID { get; set; }
    public string Name { get; set; }
}

public class Materials
{
    public string Timestamp { get; set; }
    public string Event { get; set; }
    public List<Material> Raw { get; set; }
}

public class Material
{
    public string Name { get; set; }
    public string Count { get; set; }
}

每个不同的日志类型都有 1 个模型。现在,在您的逻辑中,您要做的是从 JSON 中读取事件类型,然后将其转换为有效的 c# 类型(在下面的代码中,我使用字典),然后使用该类型告诉 JsonConvert.DeserializeObject 方法要做什么将您的 json 字符串转换为,这就是我实现它的方式:

//Same as your code
        var fullPath = @"C:\testLog.log";
        string[] lines = File.ReadAllLines(fullPath);

        //This dictionary stores each of your different log types in a way where you can use the "event" string in each json to get the c# object type
        Dictionary<string, Type> types = new Dictionary<string, Type>()
        {
            { "Friends", typeof(Friends)},
            {"Commander", typeof(Commander) },
            {"Materials", typeof(Materials) }
        };

        foreach (var line in lines)
        {
            //Same as your code
            var json = JObject.Parse(line);
            Type eventType = types[json["event"].Value<string>()];

            //This line will use the event type provided by the json to deserialise your object
            var x = JsonConvert.DeserializeObject(line, eventType);

            switch (x)
            {
                case Friends friendObject:
                    //Do stuff with the friend object here
                    Console.WriteLine("Friend log found");
                    Console.WriteLine(friendObject.Timestamp);
                    Console.WriteLine(friendObject.Name);
                    Console.WriteLine(friendObject.Status);
                    Console.WriteLine();
                    break;
                case Commander commanderObject:
                    //Do stuff with the commander object here
                    Console.WriteLine("Commander log found");
                    Console.WriteLine(commanderObject.Timestamp);
                    Console.WriteLine(commanderObject.FID);
                    Console.WriteLine(commanderObject.Name);
                    Console.WriteLine();
                    break;
                case Materials materialsObject:
                    //do stuff with the material object here
                    Console.WriteLine("Materials log found");
                    Console.WriteLine(materialsObject.Timestamp);
                    materialsObject.Raw.ForEach(material=>Console.WriteLine(material.Name + ". Count: " + material.Count));
                    break;
            }
        }

【讨论】:

    【解决方案2】:

    您可以执行以下操作。

      var eventType = json["event"].Value<string>();
      Console.WriteLine($"Event Type {eventType}");
      foreach(var obj in json["Raw"])
      {
        Console.WriteLine($"Name={obj["Name"]},Count = {obj["Count"]}");
      }
    

    在这种情况下,您从 Json 对象中解析“原始”数组并遍历 JObject 以获取数组中的每个元素

    【讨论】:

      【解决方案3】:

      你需要解析一个 JToken 数组。 请试试这个:

      foreach (var line in lines)
              {
                  var json = JObject.Parse(line);
                  var eventType = json["event"].Value<string>();
      
      
                  switch (eventType)
                  {
                      case "Friends":
      
                          var status = json["Status"].Value<string>();
                          var frName = json["Name"].Value<string>();
      
                          Console.WriteLine("The friend " + frName + " is currently " + status + ".");
      
                          Console.WriteLine(json);
      
                          break;
      
                      case "Commander":
      
                          var fid = json["FID"].Value<string>();
                          var CMDR = json["Name"].Value<string>();
      
                          Console.WriteLine("User " + CMDR + " with ID " + ".");
      
                          Console.WriteLine(json);
      
                          break;
      
                      case "Materials":
                          var raw = JArray.Parse(json["Raw"].ToString());
      
                          foreach(JToken token in raw)
                          {
                              Console.WriteLine("Name " + token["Name"] + " Counter " + token["Count"]);
                          }
      
      
                          break;
      
                      default:
                          Console.WriteLine("N/A");
                          break;
                  }
              }
      

      希望对你有所帮助。

      【讨论】:

        【解决方案4】:

        我建议不要逐行,而是 ReadAllText 并循环 JsonArray

        var json = JArray.Parse(File.ReadAllText(fullPath));
        foreach (var jsonItem in json)
        {
            var eventType = jsonItem["event"].ToString();
            switch (eventType)
            {
                case "Friends":
                    var status = jsonItem["Status"].Value<string>();
                    var frName = jsonItem["Name"].Value<string>();
                    Console.WriteLine("The friend " + frName + " is currently " + status + ".");
                    break;
                case "Commander":
                    var fid = jsonItem["FID"].Value<string>();
                    var CMDR = jsonItem["Name"].Value<string>();
                    Console.WriteLine("User " + CMDR + " with ID " + ".");
                    break;
                case "Materials":
                    //Your magic code here
                    var raw = JArray.Parse(jsonItem["Raw"].ToString());
                    foreach (var rawItem in raw)
                    {
                        Console.WriteLine("Name " + rawItem["Name"] + " with Count " + rawItem["Count"] + ".");
                    }
                    break;
                default:
                    Console.WriteLine("N/A");
                    break;
            }
        }
        

        【讨论】:

          【解决方案5】:

          谢谢大家的回答。

          我最终做了一些接近咖啡建议的事情。

          首先,我在我的解决方案中添加了一个类文件。然后,复制 JSON 字符串并执行“Edit>Paste Special>Paste JSON as Classes”创建了这个:

          public class Materials
          {
          public DateTime timestamp { get; set; }
          public string _event { get; set; }
          public Raw[] Raw { get; set; }
          }
          
          public class Raw
          {
          public string Name { get; set; }
          public int Count { get; set; }
          }
          

          然后,我将对象反序列化为一个列表:

          {
          case "Materials":
          
          //do something here that is magical.
          
          Materials m = JsonConvert.DeserializeObject<Materials>(line);
          List<Raw> r = m.Raw.ToList();
          
          break;
          }
          

          这似乎起到了作用。大家觉得呢?

          【讨论】:

          • 看起来不错,我绝对建议您对所有日志执行此操作,以便将来假设您想向其中一个日志添加额外的属性,您可以将其添加到类中并就是这样,无需手动编写代码来获取数据
          猜你喜欢
          • 1970-01-01
          • 2019-03-22
          • 2019-09-20
          • 1970-01-01
          • 1970-01-01
          • 2023-04-02
          • 1970-01-01
          • 1970-01-01
          • 2015-03-27
          相关资源
          最近更新 更多