web-dev-qa-db-fra.com

Rechercher un JToken spécifique par son nom dans une hiérarchie de JObject

J'ai une réponse du serveur Json, par exemple:

{"routes" : [
  {
     "bounds" : {
        "northeast" : {
           "lat" : 50.4639653,
           "lng" : 30.6325177
        },
        "southwest" : {
           "lat" : 50.4599625,
           "lng" : 30.6272425
        }
     },
     "copyrights" : "Map data ©2013 Google",
     "legs" : [
        {
           "distance" : {
              "text" : "1.7 km",
              "value" : 1729
           },
           "duration" : {
              "text" : "4 mins",
              "value" : 223
           },

Et je veux obtenir la valeur du jeton 'texte' de 

      "legs" : [
        {
           "distance" : {
              "text" : "1.7 km",
              "value" : 1729
           },

qui est une chaîne avec la valeur "1,7 km".

Question: existe-t-il une fonction intégrée dans NewtonsoftJson lib qui peut ressembler à:

public string(or JToken) GetJtokenByName(JObject document, string jtokenName)

ou dois-je implémenter une méthode récursive qui va rechercher JToken par nom dans tous JTokens et JArrays dans JObject?

25
Dima Serdechnyi

Si vous recherchez un jeton très spécifique et connaissez son chemin, vous pouvez y accéder facilement à l'aide de la méthode SelectToken() intégrée. Par exemple:

string distance = jObject.SelectToken("routes[0].legs[0].distance.text").ToString();

Si vous avez besoin de trouver toutes les occurrences d'un jeton portant un nom donné dans votre code JSON, quel que soit l'endroit où elles se produisent, alors vous aurez besoin d'une méthode récursive. En voici un qui pourrait faire l'affaire:

public static class JsonExtensions
{
    public static List<JToken> FindTokens(this JToken containerToken, string name)
    {
        List<JToken> matches = new List<JToken>();
        FindTokens(containerToken, name, matches);
        return matches;
    }

    private static void FindTokens(JToken containerToken, string name, List<JToken> matches)
    {
        if (containerToken.Type == JTokenType.Object)
        {
            foreach (JProperty child in containerToken.Children<JProperty>())
            {
                if (child.Name == name)
                {
                    matches.Add(child.Value);
                }
                FindTokens(child.Value, name, matches);
            }
        }
        else if (containerToken.Type == JTokenType.Array)
        {
            foreach (JToken child in containerToken.Children())
            {
                FindTokens(child, name, matches);
            }
        }
    }
}

Voici une démo:

class Program
{
    static void Main(string[] args)
    {
        string json = @"
        {
            ""routes"": [
                {
                    ""bounds"": {
                        ""northeast"": {
                            ""lat"": 50.4639653,
                            ""lng"": 30.6325177
                        },
                        ""southwest"": {
                            ""lat"": 50.4599625,
                            ""lng"": 30.6272425
                        }
                    },
                    ""legs"": [
                        {
                            ""distance"": {
                                ""text"": ""1.7 km"",
                                ""value"": 1729
                            },
                            ""duration"": {
                                ""text"": ""4 mins"",
                                ""value"": 223
                            }
                        },
                        {
                            ""distance"": {
                                ""text"": ""2.3 km"",
                                ""value"": 2301
                            },
                            ""duration"": {
                                ""text"": ""5 mins"",
                                ""value"": 305
                            }
                        }
                    ]
                }
            ]
        }";

        JObject jo = JObject.Parse(json);

        foreach (JToken token in jo.FindTokens("text"))
        {
            Console.WriteLine(token.Path + ": " + token.ToString());
        }
    }
}

Voici la sortie:

routes[0].legs[0].distance.text: 1.7 km
routes[0].legs[0].duration.text: 4 mins
routes[0].legs[1].distance.text: 2.3 km
routes[0].legs[1].duration.text: 5 mins
63
Brian Rogers

Si vous souhaitez que toutes les valeurs d'une propriété, quel que soit leur emplacement, voici une alternative à la récursion décrite par @ brian-rogers en utilisant SelectToken comme suggéré par @mhand:

Pour obtenir toutes les valeurs de duration.text, vous pouvez utiliser SelectToken et Linq:

var list = jObject.SelectTokens("$..duration.text")
           .Select(t => t.Value<string>())
           .ToList();

Plus d'infos: Interrogation de JSON avec SelectToken

0
andersh