I am using JSON.Net to convert the data from my c# program to JSON format using JSON.NET. I was wondering if there was any way in which I could use methods that I use in my c# program when serialising to json?
Bit of background context:
There exists a class Students which has attributesString StudentName, Guid StudentId and Dictionary<String, Int> Grades Record where subject names are the keys and grades are the values.
There exists another class ClassOfStudents which has an attribute List<Student> Students.
I am trying to print out the list of all the students names. I have managed to do this on c# with the method below:
public static void ViewStudentsPool()
{
Console.Write(Line);
Console.WriteLine("\nPlease find updated students pool below");
Console.Write(Line + "\n");
foreach (var studentname in ClassOfStudents.Students)
{
Console.WriteLine("Student Id: " + studentname.StudentId + "| Student Name: " + studentname.StudentName);
}
Console.Write(Line + "\n\n");
}
I was wondering if I could then use this method when serialising to JSON.
I currently have the below, which prints out all attributes of the students which I do not want, I only want to print their names out.
JsonSerializer serializer = new JsonSerializer();
serializer.NullValueHandling = NullValueHandling.Ignore;
using (StreamWriter sw = new StreamWriter(#"c:\Students.txt"))
using (JsonWriter writer = new JsonTextWriter(sw))
{
writer.Formatting = Formatting.Indented;
serializer.Serialize(writer, ClassOfStudents.Students );
}
I have tried replacing ClassOfStudents.Studentson the last line with ViewStudentsPool() but it shows an error.
Any help on how I can print out only the student names?
Thanks
A simple approach would be to just map your ClassOfStudents.Students list to the structure that you're looking for, using LINQ, for example:
var studentsWithNamesOnly = ClassOfStudents.Students
.Select(x => new { x.StudentName });
You can take this output and serialise that instead of your original ClassOfStudents.Students variable, like this:
serializer.Serialize(writer, studentsWithNamesOnly);
This would produce something like this:
[
{ "StudentName": "Name1" },
{ "StudentName": "Name2" },
...
]
You don't have to create a new anonymous object in the Select like I've done here: You could format a string like your original example, if that's what's needed.
Related
I have a question regarding logic in C# of the following. I need to generate a file where the order of the fields are specified by the input JSON. For example, I have three fields in my output:
{ID, Name, Value}
The order of these fields are specified in the JSON file i.e.
ID = 1
Name = 2
Value = 3
So, if I need to change an order of the field I just do it in my JSON file which is added to the project.
try this
using Newtonsoft.Json;
var json = "{\"FileConf\": [ { \"ID\" : 1, \"Name\" : 2, \"Value\" : 3 } ]}";
var jArray = (JArray)JObject.Parse(json)["FileConf"];
var arr = jArray.Select(a => new string[] { a["ID"].ToString(),
a["Name"].ToString(), a["Value"].ToString() });
var sb= new StringBuilder();
foreach (var item in arr)
{
sb.Append(string.Join(",",item));
sb.Append(Environment.NewLine);
}
File.WriteAllText("somefile.csv",sb.ToString());
Does anyone know how to convert the below nested JSON to CSV via CHOETL (An ETL framework for .NET)? Thank you!
I'm using this code but it will only return the first equipment record.
CODE:
{
using (var json = new ChoJSONReader("./test.json"))
{
csv.Write(json.Cast<dynamic>().Select(i => new
{
EquipmentId = i.GpsLocation.Equipment[0].EquipmentId,
InquiryValue = i.GpsLocation.Equipment[0].InquiryValue,
Timestamp = i.GpsLocation.Equipment[0].Timestamp
}));
}
}
JSON:
"GpsLocation": {
"Equipment": [
{
"EquipmentId": "EQ00001",
"InquiryValue": [
"IV00001"
],
"Timestamp": "2020-01-01 01:01:01.01",
},
{
"EquipmentId": "EQ00002",
"InquiryValue": [
"IV00002"
],
"Timestamp": "2020-01-01 01:01:01.01"
}
]
}
}````
As others suggest, the issue is you are only looking at the first element of the array.
It appears that the easiest way to control what you serialise into CSV is by correctly defining your source objects from JSON. JSON Path expressions come in pretty handy.
What I ended up doing here is query all JSON to return an array of Equipment objects regardless of where they are in the hierarchy (which means you may need to filter it a bit better depending on your full JSON).
Then it's pretty easy to define each field based on JSON path and just pass the result to CSVWriter.
Also check out some gotchas that I outlined in the respective comment lines.
void Main()
{
var jsonString = "{\"GpsLocation\":{\"Equipment\":[{\"EquipmentId\":\"EQ00001\",\"InquiryValue\":[\"IV00001\"],\"Timestamp\":\"2020-01-01 01:01:01.01\"},{\"EquipmentId\":\"EQ00002\",\"InquiryValue\":[\"IV00002\"],\"Timestamp\":\"2020-01-01 01:01:01.01\"}]}}";
var jsonReader = new StringReader(jsonString);
var csvWriter = new StringWriter(); // outputs to string, comment out if you want file output
//var csvWriter = new StreamWriter(".\\your_output.csv"); // writes to a file of your choice
using (var csv = new ChoCSVWriter(csvWriter))
using (var json = new ChoJSONReader(jsonReader)
.WithJSONPath("$..Equipment[*]", true) // firstly you scope the reader to all Equipment objects. take note of the second parameter. Apparently you need to pass true here as otherwise it just won't return anythig
.WithField("EquipmentId", jsonPath: "$.EquipmentId", isArray: false) // then you scope each field in the array to what you want it to be. Since you want scalar values, pass `isArray: false` for better predictability
.WithField("InquiryValue", jsonPath: "$.InquiryValue[0]", isArray: false) // since your InquiryValue is actually an array, you want to obtain first element here. if you don't do this, fields names and values would go askew
.WithField("Timestamp", jsonPath: "$.Timestamp", fieldType: typeof(DateTime), isArray: false)) // you can also supply field type, otherwise it seems to default to `string`
{
csv.WithFirstLineHeader().Write(json);
}
Console.WriteLine(csvWriter.GetStringBuilder().ToString()); // comment this out if writing to file - you won't need it
}
Update summary:
Pivoted to update the code to rely on JSON Path scoping - this seems to allow for field name manipulation with pretty low effort
Looking at your comment, you could probably simplify your file writer a little bit - use StreamWriter instead of StringWriter - see updated code for example
Here is the working sample of producing CSV from your JSON
string json = #"{
""GpsLocation"": {
""Equipment"": [
{
""EquipmentId"": ""EQ00001"",
""InquiryValue"": [
""IV00001""
],
""Timestamp"": ""2020-02-01 01:01:01.01"",
},
{
""EquipmentId"": ""EQ00002"",
""InquiryValue"": [
""IV00002""
],
""Timestamp"": ""2020-01-01 01:01:01.01""
}
]
}
}";
StringBuilder csv = new StringBuilder();
using (var r = ChoJSONReader.LoadText(json)
.WithJSONPath("$.GpsLocation.Equipment")
.WithField("EquipmentId")
.WithField("InquiryValue", jsonPath: "InquiryValue[0]", fieldType: typeof(string))
.WithField("Timestamp", fieldType: typeof(DateTime))
)
{
using (var w = new ChoCSVWriter(csv)
.WithFirstLineHeader())
w.Write(r);
}
Console.WriteLine(csv.ToString());
Output:
EquipmentId,InquiryValue,Timestamp
EQ00001,IV00001,2/1/2020 1:01:01 AM
EQ00002,IV00002,1/1/2020 1:01:01 AM
Sample fiddle: https://dotnetfiddle.net/hJWtqH
Your code is sound, but the issue is that you're only writing the first variable in the array by using i.GpsLocation.Equipment[0]. Instead, try looping over everything by putting it into a for loop, and changing the [0] to your iterating variable inside of said loop.
I read json values from a text and store it in array using this code.
string[] allLines = System.IO.File.ReadAllLines("D:\\tweets.txt");
I need to extract certain fields from this array containing Json.
My Json is of this type:
{"Name":"John","Id":"45","Time":"11 pm"}
{"Name":"Pear","Id":"34","Time":"3 pm"}
I want to extract each "Name" in one array and each "Id" in one array, something like this.
string[] Name= null;
string[] Id= null;
for (var i = 0; i < allLines[i].length; i++)
{
Name = allLines[i].Name;
Id = allLines[i].Id;
}
I tried another way using json parsing as well. I can obtain one row at one time json deserialized this way. But then confused how to obtain the selected fields.
StreamReader streamReader = System.IO.File.OpenText("D:\\tweets.txt");
string lineContent = streamReader.ReadLine();
do
{
if (lineContent != null)
{
var a = JsonConvert.DeserializeObject(lineContent);
}
lineContent = streamReader.ReadLine();
}
while (streamReader.Peek() != -1);
streamReader.Close();
Please help.
I recommend using Json.NET to parse JSON, you can download it as a NuGet package.
It has some great documentation about querying JSON here
Querying your JSON with LINQ would look something like:
JObject json = JObject.Parse(json);
var name = from p in json
select (string)p["Name"];
This example uses the NewtonSoft Json library to deserialize your Json into an object. Then, linq is used to pull out the lists that you are interested in.
I have written this example as a Console Application in Visual Studio. You will need to create a new Console Application, then copy this code into it.
Also, to use the NewtonSoft library in your new Console Application, you will need to load it from NuGet. To do this in VisualStudio, you will need to
Right-click on the project name
Click on Manage NuGet Packages...
In the search box on the top right, enter "newtonsoft" (without the quotes)
Newtonsoft.Json should show up in the list. Click it and press the Install button. This will load the binary and set up the references in your project. After that, you can use the sample code shown in this example.
static void Main(string[] args)
{
TestParseJson();
Console.WriteLine();
Console.WriteLine("Press Any Key to End");
Console.ReadLine(); // Wait for input so we can see our output text
}
// 1 - Construct an object used for deserialization. You will need to make this class match the format of the records in your json text file.
public class User
{
public string Name { get; set; }
public int Id { get; set; }
public DateTime Time { get; set; }
}
// 2 - Simulate Json creation and then use the NewtonSoft library to deserialize. You will need to just extract from the DeserializeObject line down
public static void TestParseJson()
{
// Read list of json objects from file, one line at a time. The json in the test file users.json is in this format:
// {"Name":"John","Id":45,"Time":"2015-11-05T19:18:02.0324468Z"}
// {"Name":"Pear","Id":34,"Time":"2015-11-06T19:18:02.0329474Z"}
var jsonLines = File.ReadLines(#"c:\temp\users.json");
var deserializedUsers = jsonLines.Select(JsonConvert.DeserializeObject<User>).ToList();
// Use Linq to project the list of deserializedUsers into the lists that you want
var names = deserializedUsers.Select(user => user.Name);
var ids = deserializedUsers.Select(user => user.Id);
// Output list of names and ids for debugging purposes
Console.WriteLine("");
Console.WriteLine(" Names:");
foreach (var name in names)
{
Console.WriteLine(" " + name);
}
Console.WriteLine(" Ids:");
foreach (var id in ids)
{
Console.WriteLine(" " + id);
}
}
Your JSON does not actually represent an array, but rather a series of individual objects back-to-back. To be considered a valid JSON array, the objects would need to be enclosed in square brackets and separated by commas (see JSON.org). Regardless, it is still possible to read and parse this non-standard JSON using Json.Net. The JsonTextReader class has a special SupportMultipleContent setting that is designed to cope with this situation. You can process your file using the following code:
List<string> names = new List<string>();
List<string> ids = new List<string>();
JsonSerializer serializer = new JsonSerializer();
using (StreamReader sr = new StreamReader("D:\\tweets.txt"))
using (JsonTextReader reader = new JsonTextReader(sr))
{
reader.SupportMultipleContent = true;
while (reader.Read())
{
if (reader.TokenType == JsonToken.StartObject)
{
JObject jo = JObject.Load(reader);
names.Add((string)jo["Name"]);
ids.Add((string)jo["Id"]);
}
}
}
Console.WriteLine("Names: " + string.Join(", ", names));
Console.WriteLine("Ids: " + string.Join(", ", ids));
Fiddle: https://dotnetfiddle.net/tYVLLr
I want to read files, each of which contains a person's details, as below, and convert it to a Person object.
Covert below
id=1
firstName=John
lastName=Smith
To:
public class Person
{
public int Id {get;set;}
public string FirstName{get;set;}
public string LastName{get;set;}
}
Are there .NET built-in methods to do that, or third party library. I cannot find it via google.
Update:
The file format CANNOT be changed.
.NET is really into XML, so you won't find build-in functionality for INI-like formats. But there are a bunch of libs that make it easy to read and write such files, e.g. ini-parser or nini, but you still have to do the mapping to and from objects manually.
You could parse the text with String.Split and LINQ:
Dictionary<string, string> dict = text
.Split(new[] { Environment.NewLine }, StringSplitOptions.None)
.Select(e => e.Split('='))
.ToDictionary(strings => strings[0], strings => strings[1]);
Then use something like Dictionary Adapter.
For example using File.ReadAllLines, a little bit of Linq and String.Substring?
var lines = File.ReadAllLines(path).Select(l => l.Trim());
var idLine = lines.FirstOrDefault(l => l.StartsWith("id=", StringComparison.OrdinalIgnoreCase));
var lNameLine = lines.FirstOrDefault(l => l.StartsWith("lastname=", StringComparison.OrdinalIgnoreCase));
var fNameLine = lines.FirstOrDefault(l => l.StartsWith("firstname=", StringComparison.OrdinalIgnoreCase));
if (idLine != null && lNameLine != null && fNameLine != null)
{
Person person = new Person()
{
Id = int.Parse(idLine.Substring(idLine.IndexOf("=") + 1)),
FirstName = fNameLine.Substring(fNameLine.IndexOf("=") + 1),
LastName = lNameLine.Substring(lNameLine.IndexOf("=") + 1)
};
}
(assuming that there's just one person per file)
But i would use a different format like XML (or a database of course).
I really think you should consider changing your input data format into something more standard (like XML or JSON).
But that does not mean you can't read your file at all. You should just read your text file by your own:
var people = new List<Person>();
using (var stream = File.OpenRead("Input.txt"))
{
using (var reader = new StreamReader(stream))
{
while (!reader.EndOfStream)
{
int id = int.Parse(reader.ReadLine().Substring(3));
string firstName = reader.ReadLine().Substring(10);
string lastName = reader.ReadLine().Substring(9);
var newPerson = new Person()
{
Id = id,
FirstName = firstName,
LastName = lastName
};
people.Add(newPerson);
}
}
}
If you have the data in a format like this:
<Person>
<Id>1</Id>
<FirstName>John</FirstName>
<LastName>Smith</LastName>
</Person>
Then this C# code will desrialise into an instance of Person
//assuming you have a string called "data" that contains the above XML.
XDocument xd=XDocument.Parse(data); //needs System.Xml.Linq for XDocument type.
using(var reader = xd.CreateReader())
{
using(XmlSerializer ser = new XmlSerializer(typeof(Person))
{
Person p = ser.Deserialize(reader) as Person;
//p will be null if it didn't work, so make sure to check it!
}
}
Note that the deserializer is case sensitive so you need to make sure the element cases match the casing of the properties in your class (You can get arond this by decorating your properties with Serializer attributes that tell the serialzer how to map them here)
The plain native serialzer is great for simple objects like this but can trip you up on some data types like char, bool, etc, so do checkout that link on the attributes.
If you wanted to do it from the format you gave in the question, you'd need to write a custom serialiser, in your case my advice would be to read from your file and generate XML from the data using XDocument Hope that helps.
I have a Table for categories , which stores Hierarchical Data in the following format
NodeID--->ParentID--->NodeName
I want to select categories in the following manner for which i need to return a JSON Object in a predefined format.
JSON FORMAT
"Option 1": {"Suboption":200},
"Option 2": {"Suboption 2": {"Subsub 1":201, "Subsub 2":202},
"Suboption 3": {"Subsub 3":203, "Subsub 4":204, "Subsub 5":205}
}
How do i return JSON in this format from a hierarchical database?? I mean how do i approach?? Kindly show me a direction.
NOTE:
Click Here to Checkout the (jQuery) Plugin I am using
Provided you are in ASP.Net you can just iterate though it using the build in functions:
System.Web.Script.Serialization.JavaScriptSerializer oSerializer =
new System.Web.Script.Serialization.JavaScriptSerializer();
string sJSON = oSerializer.Serialize(oList);
You can perform iterations using loops as well:
var productsJObject = JObject.Parse(result.Content.ReadAsStringAsync().Result);
foreach (var category in categories)
{
foreach (var category2 in category.Value)
{
foreach (var category3 in category2.Value)
{
var olist = new MyList { Id = version.SelectToken("id").ToString()
};
}
}
}
This can be ugly but usable if you have a defined set of levels, if you are performing an Nth dimensional transition it gets very complex very fast.
You can look here for an idea:
Java - Create JSON Object from Multiple Multidimensional Arrays