Поиск определенного JToken по имени в иерархии JObject
У меня есть какой-то ответ 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
},
И я хочу получить значение токена 'text' из
"legs" : [
{
"distance" : {
"text" : "1.7 km",
"value" : 1729
},
которая является строкой со значением "1,7 км".
Вопрос: есть ли встроенная функция в NewtonsoftJson lib, которая может выглядеть так:
public string(or JToken) GetJtokenByName(JObject document, string jtokenName)
или мне нужно реализовать какой-то рекурсивный метод, который будет искать JToken по имени во всех JTokens и JArrays в JObject?
2 ответа
Если вы ищете очень специфический токен и знаете путь к нему, вы можете легко перейти к нему с помощью встроенного 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
Это довольно просто, используя пути JavaScript и SelectTokens
метод на JToken
, Этот метод довольно замечательный и поддерживает такие шаблоны, как:
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
Если вам нужны все значения свойства, независимо от того, где оно встречается, здесь есть альтернатива рекурсии, как описано в @brian-rogers, используя SelectToken
как предложено @mhand:
Чтобы получить все значения duration.text, вы можете использовать SelectToken
и Линк:
var list = jObject.SelectTokens("$..duration.text")
.Select(t => t.Value<string>())
.ToList();
Дополнительная информация: запрос JSON с помощью SelectToken