【问题标题】:Searching for a specific JToken by name in a JObject hierarchy在 JObject 层次结构中按名称搜索特定 JToken
【发布时间】:2013-11-07 20:34:23
【问题描述】:

我有一些来自服务器的 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
           },

我想从

中获取令牌“文本”的值
      "legs" : [
        {
           "distance" : {
              "text" : "1.7 km",
              "value" : 1729
           },

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

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

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

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

【问题讨论】:

    标签: c# json json.net


    【解决方案1】:

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

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

    如果您需要在 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);
                }
            }
        }
    }
    

    这是一个演示:

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

    这是输出:

    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
    

    【讨论】:

    • 感谢@Brian Rogers,这非常有帮助。
    • 谢谢,你拯救了我的一天!
    • 有效,但最好使用 JToken.Parse,因为它可以解析数组
    【解决方案2】:

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

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

    查看此示例代码:

    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
                        }
                    }
                ]
            }]}";
        }
    }
    

    这是输出:

    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
    

    【讨论】:

    • 我不知道 * 通配符!我现在正在尝试这个。这样可以节省很多时间...
    【解决方案3】:

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

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

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

    更多信息:Querying JSON with SelectToken

    【讨论】:

      猜你喜欢
      • 2016-07-12
      • 1970-01-01
      • 2017-03-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多