Home > OS >  How to transform or convert dot (.) appended flat json structure to tree view (regular) json
How to transform or convert dot (.) appended flat json structure to tree view (regular) json

Time:05-17

I have below Json, I need to transform this dotted flat hierarchy into tree view hierarchy

    {  
      "info.clinical.user.gender.1": "female",
      "info.clinical.user.gender.2": "male",
      "info.clinical.user.age.max": "60",
      "info.clinical.user.age.min": "18",
    }

How to convert above Json to below JSON in a best and optimized way using C#

{
  "info": {
    "clinical": {
      "user": {
        "age": {
          "min": 18,
          "max": 60
        },
        "gender": [
          "female",
          "male"
        ]
      }
    }
  }
}

CodePudding user response:

try this

   var origJsonObj = JObject.Parse(json);

    var arrFirst = origJsonObj.Properties().First().Name.Split('.');
    var jsonObj = new JObject();
    var prevObj = jsonObj;
    for (int i = 0; i < arrFirst.Length - 2; i  )
    {
        var currObj = new JObject();
        var newProperty = new JProperty(arrFirst[i], currObj);
        prevObj.Add(newProperty);
        prevObj = currObj;
    }

    foreach (var prop in origJsonObj.Properties())
    {
        var arr = prop.Name.Split('.');
        var name = arr[arr.Length - 2];
        if (int.TryParse(arr[arr.Length - 1], out var index))
        {
            JArray jArr;
            if (prevObj[name] == null)
            {
                jArr = new JArray();
                var newProperty = new JProperty(arr[arr.Length - 2], jArr);
                prevObj.Add(newProperty);
            }
            else jArr = (JArray)prevObj[name];

            jArr.Add(prop.Value);
            continue;
        }

        JObject jObj = null;
        if (prevObj[name] == null)
        {
            jObj = new JObject();
            prevObj.Add(new JProperty(name, jObj));
        }
        else jObj = (JObject)prevObj[name];

        jObj[arr[arr.Length - 1]] = prop.Value;
    }

CodePudding user response:

Maybe you should implement it yourself, like:

using System.Text.Json.Nodes;

namespace FlatJson
{
    public static class FlatJson
    {
        public static JsonObject ToTree(this JsonObject flat, char sep = '.')
        {
            var result = new JsonObject();
            foreach (var flatItem in flat)
            {
                var layerNames = flatItem.Key.Split(sep);
                var lastIndex = layerNames.Length - 1;

                var currentLayer = result;
                for (int layerIndex = 0; layerIndex < lastIndex; layerIndex  )
                {
                    var layerName = layerNames[layerIndex];
                    var nextLayer = currentLayer[layerName]?.AsObject();
                    if (nextLayer is not null)
                        currentLayer = nextLayer;
                    else
                    {
                        nextLayer = new JsonObject();
                        currentLayer[layerName] = nextLayer;
                        currentLayer = nextLayer;
                    }
                }

                var propertyName = layerNames[lastIndex];
                var value = flatItem.Value?.GetValue<object?>();
                currentLayer[propertyName] = JsonValue.Create(value);
            }
            return result;
        }
    }
}

And how to use it:

using System.Diagnostics;
using System.Text.Json.Nodes;

using FlatJson;

var t = File.ReadAllText("test.json");

JsonObject? obj = JsonNode.Parse(t)?.AsObject();
Debug.Assert(obj is not null);

JsonObject result = obj.ToTree();

Console.WriteLine(obj);
Console.WriteLine();
Console.WriteLine(result);

But as I asked in the comments, we don't really know whether the "60" here is a number or not, and whether the info.clinical.user.gender is a list or an object. So the output of my code is (which makes sense to me):

(The original json has been changed to show you how it works in some other situations.)

{
  "info.clinical.user.gender.1": "60",
  "info.clinical.user.gender.2": "male",
  "info.clinical.user.age.max": 60,
  "info.clinical.user.age.min": null
}

{
  "info": {
    "clinical": {
      "user": {
        "gender": {
          "1": "60",
          "2": "male"
        },
        "age": {
          "max": 60,
          "min": null
        }
      }
    }
  }
}
  • Related