Search code examples
c#json.netjson.net

How can I convert a string with dot notation and arrays to json?


I'm trying to convert a string that is in dot notation to JSON.

For example, in a Dictionary<string, object> I have the key-value pairs of:

key: "resource.person[0].name"  
value: "bob"

key: "resource.person[1].name"  
value: "dylan"

I have the below code that can convert the dot notation of the key to JSON but it ignores the arrays:

var formattedDictionary = new Dictionary<string, object>();
   foreach(var pair in returnFields)
   {
      var key = pair.Key;
      var parts = key.Split('.');
      var currentObj = formattedDictionary;
      for (int i = 0; i < parts.Length-1; i++)
      {
         var property = parts[i];
         if (!currentObj.ContainsKey(property))
            currentObj[property] = new Dictionary<string, object>();
         currentObj = (Dictionary<string, object>)currentObj[property];
      }

      currentObj[parts[^1]] = pair.Value;
    }
 return formattedDictionary;

Currently Returns:

{
   "resource": {
      "person[0]": {
         "name" : "bob"
      },
      "person[1]": {
         "name" : "dylan"
      }
   }
}

I would like some help modifying the above code to also handle the arrays to give me an output that looks like this

Ideal Return:

{
   "resource": {
      "person": [
        {
         "name" : "bob"
        },
        {
         "name" : "dylan"
        }
      ]
   }
}

Thanks!


Solution

  • This works for me (using Recursion)

    private static Dictionary<string, object> CheckAndCreateKey(string key, object value, Dictionary<string, object> dict) 
        {
            if (!key.Contains(".")) 
            {
                dict[key] = value;
                return dict;
            }
    
            var firstLevel = key.Split('.')[0];
            var remainingParts = key.Replace(firstLevel + ".", ""); 
            var index = -1;
            if (firstLevel.Contains("[")) 
            {
                var bits = firstLevel.Split('[', ']');
                firstLevel = bits[0]; 
                index = int.Parse(bits[1]);
            }
    
            if (!dict.ContainsKey(firstLevel)) 
            {
                // new property
                var nestedDict = CheckAndCreateKey(remainingParts, value, new Dictionary<string, object>());
                if (index > -1) 
                {
                    // this is an Array
                    var list = new List<Dictionary<string, object>>();
    
                    while (list.Count <= index) // add require length, in case when index are in the wrong order (e.g. cars[1].make appears first before cars[0].make)
                        list.Add(new Dictionary<string, object>());
    
                    list[index] = nestedDict;
                    dict[firstLevel] = list;
                    return dict;
                }
    
                dict[firstLevel] = nestedDict;
                return dict;
            }
    
            if (index > -1) 
            {
                var list = (List<Dictionary<string, object>>) dict[firstLevel];
                while (list.Count <= index) // add missing items
                    list.Add(new Dictionary<string, object>());
    
                var nestedDict = CheckAndCreateKey(remainingParts, value, (Dictionary<string, object>) list[index]);
                dict[firstLevel] = list;
                return dict;
            }
            
            var current = (Dictionary<string, object>) dict[firstLevel];
            dict[firstLevel] = CheckAndCreateKey(remainingParts, value, current);
            return dict;
        }
    
        public static Dictionary<string, object> ParseDotNotation(this Dictionary<string, object> input) 
        {
            var formattedDictionary = new Dictionary<string, object>();
            foreach (var pair in input)
            {
                CheckAndCreateKey(pair.Key, pair.Value, formattedDictionary);
            }
            return formattedDictionary;
        }