Подтвердить что ты не робот

Сжатие json-структуры С#

У меня есть json-объект в С# (представленный как объект Newtonsoft.Json.Linq.JObject), и мне нужно сгладить его в словаре. Позвольте мне показать вам пример того, что я имею в виду:

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

Это даст словарь со следующими парами ключ-значение:

["name"] == "test",
["father.name"] == "test2",
["father.age"] == 13,
["father.dog.color"] == "brown"

Как я могу это сделать?

4b9b3361

Ответ 1

JObject jsonObject=JObject.Parse(theJsonString);
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;
                    });

У меня было такое же требование сглаживания вложенной структуры json в объект словаря. Найденное решение здесь.

Ответ 2

Вы можете использовать https://github.com/jsonfx/jsonfx для десериализации json в динамический объект. Затем используйте ExpandoObject, чтобы получить то, что вы хотите.

public Class1()
        {
            string json = @"{
                                ""name"": ""test"",
                                ""father"": {
                                     ""name"": ""test2"",
                                     ""age"": 13,
                                     ""dog"": {
                                         ""color"": ""brown""
                                     }
                                }
                            }";

            var reader = new JsonFx.Json.JsonReader();
            dynamic output = reader.Read(json);
            Dictionary<string, object> dict = new Dictionary<string, object>();

            GenerateDictionary((System.Dynamic.ExpandoObject) output, dict, "");
        }

        private void GenerateDictionary(System.Dynamic.ExpandoObject output, Dictionary<string, object> dict, string parent)
        {
            foreach (var v in output)
            {
                string key = parent + v.Key;
                object o = v.Value;

                if (o.GetType() == typeof(System.Dynamic.ExpandoObject))
                {
                    GenerateDictionary((System.Dynamic.ExpandoObject)o, dict, key + ".");
                }
                else
                {
                    if (!dict.ContainsKey(key))
                    {
                        dict.Add(key, o);
                    }
                }
            }
        }

Ответ 3

У меня фактически была та же самая проблема ранее сегодня, я не мог сначала найти этот вопрос на SO, и в итоге я написал свой собственный метод расширения, чтобы возвращать объекты JValue содержащие значения листовых узлов BLOB-объекта JSON. Это похоже на принятый ответ, за исключением некоторых улучшений:

  1. Он обрабатывает любой JSON, который вы ему даете (массивы, свойства и т.д.), А не просто объект JSON.
  2. Меньше использования памяти
  3. Нет вызовов .Count() для потомков, которые вам в конечном итоге не нужны

В зависимости от вашего варианта использования, они могут или не могут иметь отношение, но они для моего случая. Я написал об обучении выравнивать объекты JSON.NET в своем блоге. Вот метод расширения, который я написал:

public static class JExtensions
{
    public static IEnumerable<JValue> GetLeafValues(this JToken jToken)
    {
        if (jToken is JValue jValue)
        {
            yield return jValue;
        }
        else if (jToken is JArray jArray)
        {
            foreach (var result in GetLeafValuesFromJArray(jArray))
            {
                yield return result;
            }
        }
        else if (jToken is JProperty jProperty)
        {
            foreach (var result in GetLeafValuesFromJProperty(jProperty))
            {
                yield return result;
            }
        }
        else if (jToken is JObject jObject)
        {
            foreach (var result in GetLeafValuesFromJObject(jObject))
            {
                yield return result;
            }
        }
    }

    #region Private helpers

    static IEnumerable<JValue> GetLeafValuesFromJArray(JArray jArray)
    {
        for (var i = 0; i < jArray.Count; i++)
        {
            foreach (var result in GetLeafValues(jArray[i]))
            {
                yield return result;
            }
        }
    }

    static IEnumerable<JValue> GetLeafValuesFromJProperty(JProperty jProperty)
    {
        foreach (var result in GetLeafValues(jProperty.Value))
        {
            yield return result;
        }
    }

    static IEnumerable<JValue> GetLeafValuesFromJObject(JObject jObject)
    {
        foreach (var jToken in jObject.Children())
        {
            foreach (var result in GetLeafValues(jToken))
            {
                yield return result;
            }
        }
    }

    #endregion
}

Затем в своем коде вызова я просто извлекаю свойства Path и Value из JValue объектов JValue:

var jToken = JToken.Parse("blah blah json here"); 
foreach (var jValue in jToken.GetLeafValues()) 
{
    Console.WriteLine("{0} = {1}", jValue.Path, jValue.Value);
}