Question Structure json à aplatissement C #


J'ai un objet json en C # (représenté sous la forme d'un objet Newtonsoft.Json.Linq.JObject) et j'ai besoin de l'aplatir dans un dictionnaire. Laissez-moi vous montrer un exemple de ce que je veux dire:

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

Cela devrait donner un dictionnaire avec les paires clé-valeur suivantes:

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

Comment puis-je faire ceci?


15
2017-09-12 21:59


origine


Réponses:


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;
                    });

J'ai eu la même exigence d'aplatir une structure json imbriquée dans un objet dictionnaire. Trouvé la solution ici.


13
2018-03-07 08:12



Vous pouvez utiliser https://github.com/jsonfx/jsonfx désérialiser json dans un objet dynamique. Ensuite, utilisez ExpandoObject pour obtenir ce que vous voulez.

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);
                    }
                }
            }
        }

4
2017-09-12 23:15



En fait, j’ai eu le même problème plus tôt aujourd’hui et je n’ai pas trouvé cette question sur SO au début, et j’ai fini par écrire ma propre méthode d’extension pour retourner la question. JValue objets contenant les valeurs de noeud feuille du blob JSON. C'est similaire à la réponse acceptée, sauf pour quelques améliorations:

  1. Il gère tout JSON que vous lui donnez (tableaux, propriétés, etc.) au lieu d'un objet JSON.
  2. Moins de mémoire utilisée
  3. Pas d'appels à .Count() sur les descendants, vous n'avez finalement pas besoin

Selon votre cas d'utilisation, ceux-ci peuvent ou non être pertinents, mais ils le sont pour mon cas. J'ai écrit sur l'apprentissage de l'aplatissement des objets JSON.NET sur mon blog. Voici la méthode d'extension que j'ai écrite:

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
}

Ensuite, dans mon code d'appel, je viens d'extraire le Path et Value propriétés de la JValue objets retournés:

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

0
2018-04-04 01:17