C# flattening json structure

后端 未结 5 597
囚心锁ツ
囚心锁ツ 2020-12-08 07:41

I have a json-object in C# (represented as a Newtonsoft.Json.Linq.JObject object) and I need to flatten it to a dictionary. Let me show you an example of what I mean:

<
5条回答
  •  甜味超标
    2020-12-08 07:51

    As of .NET Core 3.0 JsonDocument is a way (Json.NET is not needed). I'm sure this will get easier.

    using System.Linq;
    using System.Text.Json;
    (...)
    
    
    public static Dictionary GetFlat(string json)
    {
        IEnumerable<(string Path, JsonProperty P)> GetLeaves(string path, JsonProperty p)
            => p.Value.ValueKind != JsonValueKind.Object
                ? new[] { (Path: path == null ? p.Name : path + "." + p.Name, p) }
                : p.Value.EnumerateObject() .SelectMany(child => GetLeaves(path == null ? p.Name : path + "." + p.Name, child));
    
        using (JsonDocument document = JsonDocument.Parse(json)) // Optional JsonDocumentOptions options
            return document.RootElement.EnumerateObject()
                .SelectMany(p => GetLeaves(null, p))
                .ToDictionary(k => k.Path, v => v.P.Value.Clone()); //Clone so that we can use the values outside of using
    }
    

    A more expressive version is shown below.

    Test

    using System.Linq;
    using System.Text.Json;
    (...)
    
    var json = @"{
        ""name"": ""test"",
        ""father"": {
                ""name"": ""test2"", 
             ""age"": 13,
             ""dog"": {
                    ""color"": ""brown""
             }
            }
        }";
    
    var d = GetFlat(json);
    var options2 = new JsonSerializerOptions { WriteIndented = true };
    Console.WriteLine(JsonSerializer.Serialize(d, options2));
    

    Output

    {
      "name": "test",
      "father.name": "test2",
      "father.age": 13,
      "father.dog.color": "brown"
    }
    

    More expressive version

    using System.Linq;
    using System.Text.Json;
    (...)
    
    static Dictionary GetFlat(string json)
        {
            using (JsonDocument document = JsonDocument.Parse(json))
            {
                return document.RootElement.EnumerateObject()
                    .SelectMany(p => GetLeaves(null, p))
                    .ToDictionary(k => k.Path, v => v.P.Value.Clone()); //Clone so that we can use the values outside of using
            }
        }
    
    
        static IEnumerable<(string Path, JsonProperty P)> GetLeaves(string path, JsonProperty p)
        {
            path = (path == null) ? p.Name : path + "." + p.Name;
            if (p.Value.ValueKind != JsonValueKind.Object)
                yield return (Path: path, P: p);
            else
                foreach (JsonProperty child in p.Value.EnumerateObject())
                    foreach (var leaf in GetLeaves(path, child))
                        yield return leaf;
        }
    
    
    

提交回复
热议问题