0

Input json is (The json is little part of real data, real json is very long and more hierarchy. json line more than 30k)

  {
  "data": {
    "getUsers": [
      {
        "userProfileDetail": {
          "userStatus": {
            "name": "Expired"
          },
          "userStatusDate": "2017-04-04T07:48:25+00:00",
          "lastAttestationDate": "2019-02-01T03:50:42.6049634-05:00"
        },
        "userInformation": {
          "Id": 13610875,
          "lastName": "************",
          "suffix": null,
          "gender": "FEMALE",
          "birthDate": "1970-01-01T00:01:00+00:00",
          "ssn": "000000000",
          "ethnicity": "INVALID_REFERENCE_VALUE",
          "languagesSpoken": null,
          "personalEmail": null,
          "otherNames": null,
          "userType": {
            "name": "APN"
          },
          "primaryuserState": "CO",
          "otheruserState": [
            "CO"
          ],
          "practiceSetting": "INPATIENT_ONLY",
          "primaryEmail": "*****@*****.com"
        }
      },
      {
        "userProfileDetail": {
          "userStatus": {
            "name": "Expired newwwwwwwwwwww"
          },
          "userStatusDate": "2017-04-04T07:48:25+00:00",
          "lastAttestationDate": "2019-02-01T03:50:42.6049634-05:00"
        },
        "userInformation": {
          "Id": 13610875,
          "lastName": "************",
          "suffix": null,
          "gender": "FEMALE",
          "birthDate": "1970-01-01T00:01:00+00:00",
          "ssn": "000000000",
          "ethnicity": "INVALID_REFERENCE_VALUE",
          "languagesSpoken": null,
          "personalEmail": null,
          "otherNames": null,
          "userType": {
            "name": "APN"
          },
          "primaryuserState": "CO",
          "otheruserState": [
            "CO"
          ],
          "practiceSetting": "INPATIENT_ONLY",
          "primaryEmail": "*****@*****.com"
        }
      }
    ]
  }
}

the code is

var obj = JObject.Parse(json);
            // Collect column titles: all property names whose values are of type JValue, distinct, in order of encountering them.
            var jsonValues = obj.DescendantsAndSelf().OfType<JProperty>().Where(p => p.Value is JValue).GroupBy(p => p.Name).ToList();
            var jsonKey = jsonValues.Select(g => g.Key).ToArray();

            // Filter JObjects that have child objects that have values.
            var parentsWithChildren = jsonValues.SelectMany(g => g).SelectMany(v => v.AncestorsAndSelf().OfType<JObject>().Skip(1)).ToHashSet();

            // Collect all data rows: for every object, go through the column titles and get the value of that property in the closest ancestor or self that has a value of that name.
            var rows = obj
                .DescendantsAndSelf()
                .OfType<JObject>()
                .Where(o => o.PropertyValues().OfType<JValue>().Any() && (o == obj || !parentsWithChildren.Contains(o))) // Show a row for the root object + objects that have no children.
                .Select(o => jsonKey.Select(c => o.AncestorsAndSelf().OfType<JObject>().Select(parent => parent[c])
                    .Where(v => v is JValue).Select(v => (string)v).FirstOrDefault()).Reverse() // Trim trailing nulls
                    .SkipWhile(s => s == null).Reverse());

            // Convert to CSV
            var csvRows = new[] { jsonKey }.Concat(rows).Select(r => string.Join(",", r));
            var csv = string.Join("\n", csvRows);
            Console.WriteLine(csv);

Here is the output i get:

getUsers_userProfileDetail_userStatus_name,getUsers_userProfileDetail_userStatusDate,getUsers_userProfileDetail_lastAttestationDate,getUsers_userInformation_Id,getUsers_userInformation_lastName,getUsers_userInformation_suffix,getUsers_userInformation_gender,getUsers_userInformation_birthDate,getUsers_userInformation_ssn,getUsers_userInformation_ethnicity,getUsers_userInformation_languagesSpoken,getUsers_userInformation_personalEmail,getUsers_userInformation_otherNames,getUsers_userInformation_userType_name,getUsers_userInformation_primaryuserState,getUsers_userInformation_otheruserState,getUsers_userInformation_practiceSetting,getUsers_userInformation_primaryEmail Expired,04/04/2017 13:18:25,02/01/2019 14:20:42 APN,,,13610875,************,,FEMALE,01/01/1970 05:31:00,000000000,INVALID_REFERENCE_VALUE,,,,CO,INPATIENT_ONLY,*****@*****.com

here userType > name not column is not in correct place and otheruserState array not come in output.

Anyone can help me?

3
  • 1
    Maybe there is some LINQ kung-fu that could dig into those nested items to get your results but wouldn't it be easier to deserialize the json to a strong Type and code a converter to csv ? Commented Dec 29, 2019 at 12:29
  • 1
    create a class-based on this JSON and convert the JSON to class and use its properties Commented Dec 29, 2019 at 12:50
  • Do you need a comma after the curly brace, but before the closing square bracket for getUsers ? Not sure... Commented Dec 29, 2019 at 13:00

2 Answers 2

1

Following process is what I would recommend since it does not skip the null values and doesnt throw errors if there are nulls. Process below creates a csv formatted string for each of the user in the json and writes down a string.empty for any null value.

List of strings are converted to | delimited since its going in a comma delimited format. You should update all the classes and use Capital first letter in attribute names. I am simply pasting what I got from json2csharp site.

Get Classes for Json

I used json2csharp site to convert your json to classes. Once i got the classes, i used an override method on GetUser to convert the user data to string.... then used that information to print it.

Classes for the Json


    public class UserStatus
    {
        public string name { get; set; }
    }

    public class UserProfileDetail
    {
        public UserStatus userStatus { get; set; }
        public DateTime userStatusDate { get; set; }
        public DateTime lastAttestationDate { get; set; }
    }

    public class UserType
    {
        public string name { get; set; }
    }

    public class UserInformation
    {
        public int Id { get; set; }
        public string lastName { get; set; }
        public string suffix { get; set; }
        public string gender { get; set; }
        public DateTime birthDate { get; set; }
        public string ssn { get; set; }
        public string ethnicity { get; set; }
        public List<string> languagesSpoken { get; set; }
        public string personalEmail { get; set; }
        public List<string> otherNames { get; set; }
        public UserType userType { get; set; }
        public string primaryuserState { get; set; }
        public List<string> otheruserState { get; set; }
        public string practiceSetting { get; set; }
        public string primaryEmail { get; set; }
    }

    public class GetUser
    {
        public override string ToString()
        {
            List<string> userData = new List<string>
            {
                userProfileDetail.userStatus.name,
                userProfileDetail.userStatusDate.ToString(),
                userProfileDetail.lastAttestationDate.ToString(),
                userInformation.Id.ToString(),
                userInformation.lastName,
                userInformation.suffix?? string.Empty ,
                userInformation.gender?? string.Empty ,
                userInformation.birthDate.ToString(),
                userInformation.ssn?? string.Empty ,
                userInformation.ethnicity?? string.Empty ,
                string.Join("|", userInformation.languagesSpoken?? new List<string>()),
                userInformation.personalEmail?? string.Empty ,
                string.Join("|", userInformation.otherNames?? new List<string>() ),
                userInformation.userType.name?? string.Empty ,
                userInformation.primaryuserState?? string.Empty ,
                string.Join("|", userInformation.otheruserState),
                userInformation.practiceSetting?? string.Empty ,
                userInformation.primaryEmail
            };

            return string.Join(",", userData);
        }
        public UserProfileDetail userProfileDetail { get; set; }
        public UserInformation userInformation { get; set; }
    }

    public class Data
    {
        public List<GetUser> getUsers { get; set; }
    }

    public class RootObject
    {
            public string GetHeader()
            {
                return "getUsers_userProfileDetail_userStatus_name,getUsers_userProfileDetail_userStatusDate,getUsers_userProfileDetail_lastAttestationDate,getUsers_userInformation_Id,getUsers_userInformation_lastName,getUsers_userInformation_suffix,getUsers_userInformation_gender,getUsers_userInformation_birthDate,getUsers_userInformation_ssn,getUsers_userInformation_ethnicity,getUsers_userInformation_languagesSpoken,getUsers_userInformation_personalEmail,getUsers_userInformation_otherNames,getUsers_userInformation_userType_name,getUsers_userInformation_primaryuserState,getUsers_userInformation_otheruserState,getUsers_userInformation_practiceSetting,getUsers_userInformation_primaryEmail";
            }
        public Data data { get; set; }
    }

How to use the classes above

    string json = File.ReadAllLines("locationOfJson");
    var rootObject = JsonConvert.DeserializeObject<RootObject>(json);
    Console.WriteLine(rootObject.GetHeader()); // Prints Header
    foreach (var user in rootObject.data.getUsers)
    {
        Console.WriteLine(user.ToString()); // Print Each User.
    }

Output

getUsers_userProfileDetail_userStatus_name,getUsers_userProfileDetail_userStatusDate,getUsers_userProfileDetail_lastAttestationDate,getUsers_userInformation_Id,getUsers_userInformation_lastName,getUsers_userInformation_suffix,getUsers_userInformation_gender,getUsers_userInformation_birthDate,getUsers_userInformation_ssn,getUsers_userInformation_ethnicity,getUsers_userInformation_languagesSpoken,getUsers_userInformation_personalEmail,getUsers_userInformation_otherNames,getUsers_userInformation_userType_name,getUsers_userInformation_primaryuserState,getUsers_userInformation_otheruserState,getUsers_userInformation_practiceSetting,getUsers_userInformation_primaryEmail
Expired,4/4/2017 3:48:25 AM,2/1/2019 3:50:42 AM,13610875,************,,FEMALE,12/31/1969 7:01:00 PM,000000000,INVALID_REFERENCE_VALUE,,,,APN,CO,CO,INPATIENT_ONLY,*****@*****.com

I suggest copy pasting the data in excel to see how it fits. I tested it and seems like all the data goes correctly under their heading.

Sign up to request clarification or add additional context in comments.

1 Comment

The above json is little part of real data, real json is very long and more hierarchy. json line more than 30k.
0

The solution for the case you provided is below. It is using JsonTextReader instead of LINQ to JSON to give you full control over output formatting. For example you did not specify how it should behave for arrays of string (otheruserState) so in my solution I separated string values with the dash. I'm using empty strings for null values.

string propertyName = "";
var isArray = false;
var arrayHeaderprinted = false;

var headers = new List<string>();
var data = new List<string>();
var arrayData = new List<string>();

using (var reader = new JsonTextReader(new StringReader(json)))
{
    while (reader.Read())
    {
        switch (reader.TokenType)
        {
            case JsonToken.PropertyName:
                propertyName = (string)reader.Value;
                break;
            case JsonToken.StartArray:
                isArray = true;
                break;
            case JsonToken.EndArray:
            case JsonToken.StartObject:
                isArray = false;
                if (arrayHeaderprinted)
                {
                    arrayHeaderprinted = false;
                    data.Add(string.Join("-", arrayData));
                }
                break;
            case JsonToken.Null:
            case JsonToken.String:
            case JsonToken.Boolean:
            case JsonToken.Date:
            case JsonToken.Float:
            case JsonToken.Integer:
                if (isArray)
                {
                    if (!arrayHeaderprinted)
                    {
                        arrayHeaderprinted = true;
                        headers.Add(propertyName);
                    }
                    arrayData.Add(reader.Value.ToString());
                }
                else
                {
                    headers.Add(propertyName);
                    data.Add(reader.Value?.ToString() ?? "");
                }
                break;
        }
    }
}

Console.WriteLine(string.Join(",", headers));
Console.WriteLine(string.Join(",", data));

The output it produces:

name,userStatusDate,lastAttestationDate,Id,lastName,suffix,gender,birthDate,ssn,ethnicity,languagesSpoken,personalEmail,otherNames,name,primaryuserState,otheruserState,practiceSetting,primaryEmail
Expired,04.04.2017 09:48:25,01.02.2019 09:50:42,13610875,************,,FEMALE,01.01.1970 01:01:00,000000000,INVALID_REFERENCE_VALUE,,,,APN,CO,CO-PP,INPATIENT_ONLY,*****@*****.com

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.