C# 在 JObject 层次结构中按名称搜索特定 JToken

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19645501/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 15:31:29  来源:igfitidea点击:

Searching for a specific JToken by name in a JObject hierarchy

c#jsonjson.net

提问by Dima Serdechnyi

I have some Json response from server, for example:

我有一些来自服务器的 Json 响应,例如:

{"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
           },

And I want to get the value of token 'text' from

我想从

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

which is string with value "1.7 km".

这是值为“1.7 km”的字符串。

Question:is there any build-in function in NewtonsoftJson lib which can be look like:

问题:NewtonsoftJson lib 中是否有任何内置函数,如下所示:

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

or do I need to implement some recursive method which will search JToken by name in all JTokens and JArrays in JObject?

或者我是否需要实现一些递归方法,该方法将在 JObject 中的所有 JToken 和 JArray 中按名称搜索 JToken?

采纳答案by Brian Rogers

If you are looking for a very specific token and know the path to it, you can navigate to it easily using the built-in SelectToken()method. For example:

如果您正在寻找一个非常具体的令牌并知道它的路径,您可以使用内置SelectToken()方法轻松导航到它。例如:

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

If you need to find all occurences of a token with a given name in your JSON, no matter where they occur, then yes you'd need a recursive method. Here is one that might do the trick:

如果您需要在 JSON 中查找具有给定名称的令牌的所有出现,无论它们出现在何处,那么是的,您需要一个递归方法。这是一个可以解决问题的方法:

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

Here is a demo:

这是一个演示:

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

Here is the output:

这是输出:

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

回答by mhand

This is pretty simple using the json paths and the SelectTokensmethod on JToken. This method is pretty awesome and supports wilds cards such as the following:

使用 json 路径和 上的SelectTokens方法非常简单JToken。这个方法非常棒,支持如下的通配符:

jObject.SelectTokens("routes[*].legs[*].*.text")

jObject.SelectTokens("routes[*].legs[*].*.text")

Check out this sample code:

查看此示例代码:

private class Program
{
    public static void Main(string[] args)
    {
        string json = GetJson();
        JObject jObject = JObject.Parse(json);

        foreach (JToken token in jObject.SelectTokens("routes[*].legs[*].*.text"))
        {
            Console.WriteLine(token.Path + ": " + token);
        }
    }

    private static string GetJson()
    {
        return @" {
        ""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
                    }
                }
            ]
        }]}";
    }
}

And here's the output:

这是输出:

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

回答by andersh

In case you want all values of a property, regardless of where it occurs, here is an alternative to recursion as described by @brian-rogers, using SelectTokenas suggested by @mhand:

如果您想要一个属性的所有值,无论它出现在哪里,这里是@brian-rogers 描述的递归的替代方法,使用SelectToken@mhand 的建议:

To get all values of duration.text, you can use SelectTokenand Linq:

要获取duration.text 的所有值,可以使用SelectToken和Linq:

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

More info: Querying JSON with SelectToken

更多信息:使用 SelectToken 查询 JSON