Reputation: 605
I'm using Newtonsoft JSON in C#.
I have a log file which I am trying to parse so I can populate a database with the data in the log file.
In the log file, each line is a separate JSON object.
Here is what the log file looks like:
{ "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 }]}
Here's what I'm doing so far:
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;
}
The first two cases work fine. However, I can't figure out how to get the array "Raw" out of the "Materials" event.
FYI - there are two other arrays in that line. So, I need to be able to extract the array for "Raw" as well as the others.
So far, I just can't figure this out.
I'm very much a beginner, so please explain this as if you were talking to a toddler. :)
please help with this?
Thanks so much!
Upvotes: 0
Views: 331
Reputation: 605
Thank you all for your answers.
I ended up doing something close to what Coffee suggested.
First, I added a class file to my solution. Then, copied the JSON string and did "Edit>Paste Special>Paste JSON as Classes" which created this:
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; }
}
Then, I deserialized the object into a list:
{
case "Materials":
//do something here that is magical.
Materials m = JsonConvert.DeserializeObject<Materials>(line);
List<Raw> r = m.Raw.ToList();
break;
}
This seemed to do the trick. What do you guys think?
Upvotes: 0
Reputation: 402
All of the answers above are completely valid for the question you're asking, however, for better code readability and debugging you're better converting those json strings to actual c# objects. For example you'd set up some models like this:
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; }
}
You'd have 1 model for each of your different log types. Now in your logic what you want to do is read the event type from the JSON and then turn that into a valid c# type (in my code below I use a dictionary) and then use that type to tell the JsonConvert.DeserializeObject method what to convert your json string into, this is how I implemented it:
//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;
}
}
Upvotes: 4
Reputation: 4260
Instead of going line by line, I suggest to ReadAllText
and loop the 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;
}
}
Upvotes: 0
Reputation: 21
You need to parse an array of JToken. Please try this :
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;
}
}
Hope it will help you.
Upvotes: 0
Reputation: 18155
You could do the following.
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"]}");
}
You are in this case, parsing the "Raw" array from the Json Object and iterating over the JObjects to fetch each element in the array
Upvotes: 1