【问题标题】:How to unflatten flattened json in C#如何在 C# 中展开扁平化的 json
【发布时间】:2017-03-25 07:43:22
【问题描述】:

Answer 我学会了如何在 c# 中展平 JSON 对象。 来自 JSON 字符串:

{"menu": {
  "id": "file",
  "value": "File",
  "popup": {
    "menuitem": [
      {"value": "New", "onclick": "CreateNewDoc()"},
      {"value": "Open", "onclick": "OpenDoc()"},
      {"value": "Close", "onclick": "CloseDoc()"}
    ]
  }
}}

收件人:

以下是字符串行,不是对象

menu.id:file
menu.value:File
menu.popup.menuitem[0].value:New
menu.popup.menuitem[0].onclick:CreateNewDoc()
menu.popup.menuitem[1].value:Open
menu.popup.menuitem[1].onclick:OpenDoc()
menu.popup.menuitem[2].value:Close
menu.popup.menuitem[2].onclick:CloseDoc()

现在,我想反转这个过程。 我可以从 question 找到实现,但它是在 JavaScript 中的。

如何使用 json.net 在 C# 中unflatten(从行中返回结构化 JSON)?

【问题讨论】:

  • 我更新了问题以澄清一些信息

标签: c# json flatten


【解决方案1】:

我设法解决了。

下面是我结合Sarath Rachuri's flattening code的代码。

我没有在太多情况下测试它,所以它可能是错误的。

using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;

namespace JSONHelper
{
    class JSONFlattener
    {
        private enum JSONType{
            OBJECT, ARRAY
        }
        public static Dictionary<string, string> Flatten(JObject jsonObject)
        {
            IEnumerable<JToken> jTokens = jsonObject.Descendants().Where(p => p.Count() == 0);
            Dictionary<string, string> results = jTokens.Aggregate(new Dictionary<string, string>(), (properties, jToken) =>
            {
                properties.Add(jToken.Path, jToken.ToString());
                return properties;
            });
            return results;
        }

        public static JObject Unflatten(IDictionary<string, string> keyValues)
        {
            JContainer result = null;
            JsonMergeSettings setting = new JsonMergeSettings();
            setting.MergeArrayHandling = MergeArrayHandling.Merge;
            foreach (var pathValue in keyValues)
            {
                if (result == null)
                {
                    result = UnflatenSingle(pathValue);
                }
                else
                {
                    result.Merge(UnflatenSingle(pathValue), setting);
                }
            }
            return result as JObject;
        }

        private static JContainer UnflatenSingle(KeyValuePair<string, string> keyValue)
        {
            string path = keyValue.Key;
            string value = keyValue.Value;
            var pathSegments = SplitPath(path);

            JContainer lastItem = null;
            //build from leaf to root
            foreach (var pathSegment in pathSegments.Reverse())
            {
                var type = GetJSONType(pathSegment);
                switch (type)
                {
                    case JSONType.OBJECT:
                        var obj = new JObject();
                        if (null == lastItem)
                        {
                            obj.Add(pathSegment,value);
                        }
                        else
                        {
                            obj.Add(pathSegment,lastItem);
                        }
                        lastItem = obj;
                        break;
                    case JSONType.ARRAY:
                        var array = new JArray();
                        int index = GetArrayIndex(pathSegment);
                        array = FillEmpty(array, index);
                        if (lastItem == null)
                        {
                            array[index] = value;
                        }
                        else
                        {
                            array[index] = lastItem;
                        }
                        lastItem = array;
                        break;
                }
            }
            return lastItem;
        }

        public static IList<string> SplitPath(string path){
            IList<string> result = new List<string>();
            Regex reg = new Regex(@"(?!\.)([^. ^\[\]]+)|(?!\[)(\d+)(?=\])");
            foreach (Match match in reg.Matches(path))
            {
                result.Add(match.Value);
            }
            return result;
        }

        private static JArray FillEmpty(JArray array, int index)
        {
            for (int i = 0; i <= index; i++)
            {
                array.Add(null);
            }
            return array;
        }

        private static JSONType GetJSONType(string pathSegment)
        {
            int x;
            return int.TryParse(pathSegment, out x) ? JSONType.ARRAY : JSONType.OBJECT;
        }

        private static int GetArrayIndex(string pathSegment)
        {
            int result;
            if (int.TryParse(pathSegment, out result))
            {
                return result;
            }
            throw new Exception("Unable to parse array index: " + pathSegment);
        }

    }
}

【讨论】:

    【解决方案2】:

    System.Text.Json 解决方案,用于非扁平化 JSON。需要 .Net 6。

    private static JsonNode Unflatten(Dictionary<string, JsonValue> source)
    {
        var regex = new System.Text.RegularExpressions.Regex(@"(?!\.)([^. ^\[\]]+)|(?!\[)(\d+)(?=\])");
        JsonNode node = JsonNode.Parse("{}");
    
        foreach (var keyValue in source)
        {
            var pathSegments = regex.Matches(keyValue.Key).Select(m => m.Value).ToArray();
    
            for (int i = 0; i < pathSegments.Length; i++)
            {
                var currentSegmentType = GetSegmentKind(pathSegments[i]);
    
                if (currentSegmentType == JsonValueKind.Object)
                {
                    if (node[pathSegments[i]] == null)
                    {
                        if (pathSegments[i] == pathSegments[pathSegments.Length - 1])
                        {
                            node[pathSegments[i]] = keyValue.Value;
                            node = node.Root;
                        }
                        else
                        {
                            var nextSegmentType = GetSegmentKind(pathSegments[i + 1]);
    
                            if (nextSegmentType == JsonValueKind.Object)
                            {
                                node[pathSegments[i]] = JsonNode.Parse("{}");
                            }
                            else
                            {
                                node[pathSegments[i]] = JsonNode.Parse("[]");
                            }
                                node = node[pathSegments[i]];
                            }
                        }
                        else
                        {
                            node = node[pathSegments[i]];
                        }
                    }
                    else
                    {
                        if (!int.TryParse(pathSegments[i], out int index))
                        {
                            throw new Exception("Cannot parse index");
                        }
    
                        while (node.AsArray().Count - 1 < index)
                        {
                            node.AsArray().Add(null);
                        }
    
                        if (i == pathSegments.Length - 1)
                        {
                            node[index] = keyValue.Value;
                            node = node.Root;
                        }
                        else
                        {
                            if (node[index] == null)
                            {
                                var nextSegmentType = GetSegmentKind(pathSegments[i + 1]);
    
                                if (nextSegmentType == JsonValueKind.Object)
                                {
                                    node[index] = JsonNode.Parse("{}");
                                }
                                else
                                {
                                    node[index] = JsonNode.Parse("[]");
                                }
                            }
    
                            node = node[index];
                        }
                    }
                }
            }
    
        return node;
    }
    
    private static JsonValueKind GetSegmentKind(string pathSegment) =>
        int.TryParse(pathSegment, out _) ? JsonValueKind.Array : JsonValueKind.Object;
    

    【讨论】:

      【解决方案3】:

      要展平 JSON 对象:

      arrayJSON.stringify()
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-11-15
        • 1970-01-01
        • 2021-11-19
        • 2021-05-24
        • 1970-01-01
        • 2023-03-04
        • 2019-12-13
        相关资源
        最近更新 更多