user8149311
user8149311

Reputation:

Parsing json file in c# to get into all sections and properties

==========Update

So in trying to phrase the issue properly, I have misled the responders in not giving me the answer I need. Apologies, let me try to clarify.

I need to be able to cycle through a json file that is not as structured as I indicated in the OP, it is much more random. The OP file did not convey that very well.

Let me try to describe what is closer to the file I'll be getting. The first two levels will be fixed, I'll call them LevelA and LevelB. But the properties in LevelB can be any pair of random data. This is a better json file example:

{
  "LevelA": {
    "LevelB": [
      {
        "EmpName": "John",
        "EmpGender": "Male",
        "Age": "25"
      },
      {
        "FavoriteFood": "Beer",
        "BaseballTeam": "Kansas City Royals"
      },
      {
        "Red": "10",
        "Blue": "40",
        "White: "True"
      }
    ]
  }
}

Say I need to write out the following to console:

A LevelB entry has these properties:
Property: EmpName, Value: John
Property: EmpGender, Value: Male
Property: Age, Value: 25

A LevelB entry has these properties:
Property: FavoriteFood, Value: Beer
Property: BaseballTeam, Value: Kansas City Royals

A LevelB entry has these properties:
Property: Red, Value: 10
Property: Blue, Value: 40
Property: White, Value: True

It may not make sense but, I need to find a way to do that, I need that knowledge. I appreciate the answers about using a model, but I don't see a way to use a model without complicating what I think should be a simple task. Although not simple enough for me to figure out apparently. :)

==========

C#, VS 2019, a .NET framework console test app. I'm looking to do something simple but I can't find the right syntax. I have a json file with the following structure. I want to loop through each Employee below and get at its properties (name, gender, etc...):

{
  "Company": {
    "Employees": [
      {
        "EmpName": "John",
        "EmpGender": "Male",
        "Age": "25"
      },
      {
        "EmpName": "Mary",
        "EmpGender": "Female"
      },
      {
        "EmpName": "Bill",
        "Age": "30"
      }
    ]
  }
}

First question is which package will do the job? I've installed Microsoft.Extensions.Configuration.Json and System.Configuration.ConfigurationManager but am having difficulties getting the syntax correct. Are these the right packages to use? I decided to use those because I thought I could load the file via ConfigurationBuilder and that the GetSection and/or GetChildren methods would help me. I can load the file but I can't figure out how to use those methods to give me what I want.

Second I don't want to build a model for this, I just want at the data. If I can get each employee into a dictionary, I can analyze that, and that would get me going. Thanks for any advice.

Upvotes: 1

Views: 15428

Answers (3)

Attila Molnar
Attila Molnar

Reputation: 76

Why is it a requirement not to build models? In my opinoin that is the easiest way and if you need to expand due to JSON changes, you can easily adapt it in the code. I paste a sample code here what is using System.Text.Json namespace (no other packages are also required due to it is built-in).

using System;
using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace jsontest
{
    class Program
    {
        static void Main(string[] args)
        {
            string input = "{ \"Company\": { \"Employees\": [{ \"EmpName\": \"John\", \"EmpGender\": \"Male\", \"Age\": \"25\" }, { \"EmpName\": \"Mary\", \"EmpGender\": \"Female\" }, { \"EmpName\": \"Bill\", \"Age\": \"30\" }]}}";

            var processedInput = JsonSerializer.Deserialize<Company>(input);
            
            foreach (var item in processedInput.Peoples.PeopleList)
            {
                Console.WriteLine($"{item.Name} - {item.Gender} - {item.Age}");
            }
        }
    }

    public class Employee
    {
        [JsonPropertyName("EmpName")]
        public string Name { get; set; }

        [JsonPropertyName("EmpGender")]
        public string Gender { get; set; }

        [JsonPropertyName("Age")]
        public string Age { get; set; }
    }

    public class Employees
    {
        [JsonPropertyName("Employees")]
        public List<Employee> PeopleList { get; set; }
    }

    public class Company
    {
        [JsonPropertyName("Company")]
        public Employees Peoples { get; set; }
    }
}

Update after your update: Strange why you store data in JSON on this way. I wrote a quick code, it is using regex and some built-in function to parse the text. At the end result is similar what you would prefer. Code is a bit long, but only because I put some comment to make understanding easier.

using System;
using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace jsontest
{
    class Program
    {
        static void Main(string[] args)
        {
            List<List<ListItem>> result = new List<List<ListItem>>();

            string input = "{ \"Company\": { \"Employees\": [{ \"EmpName\": \"John\", \"EmpGender\": \"Male\", \"Age\": \"25\" }, { \"EmpName\": \"Mary\", \"EmpGender\": \"Female\" }, { \"EmpName\": \"Bill\", \"Age\": \"30\" }]}}";

            // Remove new lines, so input will become one single line
            input = input.Replace(Environment.NewLine, " ");

            // 1. group is the group name (in this case Employees)
            // 2. group is the content after group name
            string pattern1 = @"[{].+[{](.+)[\[](.+)[\]]";

            foreach (System.Text.RegularExpressions.Match m in System.Text.RegularExpressions.Regex.Matches(input, pattern1))
            {
                // groupName -> "Employees":
                string groupName = m.Groups[1].Value;

                // groupName -> Employees
                groupName = groupName.Substring(0, groupName.LastIndexOf("\""));
                groupName = groupName.Substring(groupName.IndexOf("\"") + 1);

                // contentList -> { "EmpName": "John", "EmpGender": "Male", "Age": "25" }, { "EmpName": "Mary", "EmpGender": "Female" }, { "EmpName": "Bill", "Age": "30" }
                string contentList = m.Groups[2].Value;

                // Split the line onto more lines where "}," characters
                // { "EmpName": "John", "EmpGender": "Male", "Age": "25"
                // { "EmpName": "Mary", "EmpGender": "Female"
                // { "EmpName": "Bill", "Age": "30" }
                string[] contentItems = contentList.Split("},");

                foreach (var item in contentItems)
                {
                    // Check every group and store them in separate list
                    result.Add(new List<ListItem>());

                    string[] keys = item.Split(",");

                    foreach (var key in keys)
                    {
                        // Check every Key-Value pair and store their value in the current list
                        string pattern2 = "[\"](.+)[:].[\"](.+)[\"]";
                        foreach (System.Text.RegularExpressions.Match m2 in System.Text.RegularExpressions.Regex.Matches(key, pattern2))
                        {
                            result[result.Count - 1].Add(new ListItem() { Property = groupName, Key = m2.Groups[1].Value.Substring(0, m2.Groups[1].Value.Length - 1), Value = m2.Groups[2].Value });
                        }
                    }
                }
            }

            for (int i = 0; i < result.Count; i++)
            {
                for (int j = 0; j < result[i].Count; j++)
                {
                    if (j == 0)
                        Console.WriteLine($"A {result[i][j].Property} entry has these properties:");

                    Console.WriteLine($"Proprty: {result[i][j].Key}, Value: {result[i][j].Value}");
                }
            }
        }
    }

    class ListItem
    {
        public string Property { get; set; }
        public string Key { get; set; }
        public string Value { get; set; }
    }


}

Output of this code is:

A Employees entry has these properties:
Proprty: EmpName, Value: John
Proprty: EmpGender, Value: Male
Proprty: Age, Value: 25
A Employees entry has these properties:
Proprty: EmpName, Value: Mary
Proprty: EmpGender, Value: Female
A Employees entry has these properties:
Proprty: EmpName, Value: Bill
Proprty: Age, Value: 30

Upvotes: 0

Yiyi You
Yiyi You

Reputation: 18179

If you don't want to create a model,and get a List<Dictionary<string,string>>,you can use custom model binding,here is a demo: CustomBinder:

public class CustomBinder:IModelBinder
    {
        public Task BindModelAsync(ModelBindingContext bindingContext)
        {
            if (bindingContext == null)
            {
                throw new ArgumentNullException(nameof(bindingContext));
            }
            var model = new List<Dictionary<string, string>>();
            using (var reader = new StreamReader(bindingContext.HttpContext.Request.Body))
            {
                var body = reader.ReadToEndAsync();

                var mydata = JsonConvert.DeserializeObject<JObject>(body.Result);
                var s = mydata["Company"]["Employees"].ToString();
                var list=JsonConvert.DeserializeObject<List<JObject>>(s);
                foreach (var jobj in list) {
                    Dictionary<string, string> d = new Dictionary<string, string>();
                    foreach (var x in jobj)
                    {
                        string name = x.Key;
                        string value = x.Value.ToString();
                        d.Add(x.Key, x.Value.ToString());
                    }
                    model.Add(d);
                }

            }

            bindingContext.Result = ModelBindingResult.Success(model);
            return Task.CompletedTask;
        }
    }

Action:

public void TestJson1([ModelBinder(BinderType = typeof(CustomBinder))] List<Dictionary<string, string>> jsondata)
        {

        }

result: enter image description here

Upvotes: 1

Ibram Reda
Ibram Reda

Reputation: 2820

You can use the built-in JSON library in the .net core

using System.Text.Json;

add the following model definition

 public class Rootobject
    {
        public Company Company { get; set; }
    }

    public class Company
    {
        public Employee[] Employees { get; set; }
    }

    public class Employee
    {
        public string EmpName { get; set; }
        public string EmpGender { get; set; }
        public string Age { get; set; }
    }

deserialize your object like the following

string jsonData = File.ReadAllText("data.json");
Rootobject ob = JsonSerializer.Deserialize<Rootobject>(jsonData);

now you have ob in you c# represent your JSON as C# object

I don't want to build a model for this

if you use Visual Studio you can auto generate your model classes required for your JSON as described here the above models are auto generated by Visual Studio

Upvotes: 4

Related Questions