JSON.NET。从其子项导航到 JArray 对象
JSON.NET. Navigate to JArray object from its children
有一个这样的 JSON 文件:
{
"men": [
{
"name": "Jordan",
"phone": "333-333-33"
},
{
"name": "Timothey",
"phone": "444-444-44"
}
],
"women": [
{
"name": "Jordan",
"phone": "111-111-11"
},
{
"name": "Sasha",
"phone": "222-222-22"
}
]
}
我想找出所有名字以J开头的人,并判断这个人是男是女。
var jsonProps = jsonDoc.Descendants().Where(t => t.Type == JTokenType.Property && ((JProperty)t).Name == prop);
var startsWithJ = jsonProps.Where(t => ((JProperty)t).Value.ToString().StartsWith("J"));
foreach (var person in startsWithJ)
{
Console.WriteLine(person.Value<string>());
Console.WriteLine(person.Parent.Parent.Value<string>());
}
问题是 person.Parent.Parent 为 null,我希望它不是 JArray,或者至少是 JToken,或者至少是一些 JToken,这样我才能得到它的值。
更新:
我有 100 种使用相似数据结构的类型。这些集合(男性、女性)可以位于任何嵌套级别,例如employee包含男女集合,或者student包含男女集合。我无法为解决方案中的每种类型创建强类型对象。有时我需要从 men/women 集合中移除对象并检查集合是否有此之后的任何元素。
这不是对 "how you query with LINQ to Json" 的直接回答,而是我发现使用强类型对象更容易的方法。
通过简单地创建以下数据结构(注意 POCO 用 JsonProperty
修饰,这是一个 Json.NET 属性):
public class RootObject
{
public List<Person> Men { get; set; }
public List<Person> Women { get; set; }
}
public class Person
{
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("phone")]
public string PhoneNumber { get; set; }
public Sex Sex { get; set }
}
public enum Sex
{
Man,
Women
}
现在,您可以使用 LINQ to Objects 轻松查询所需内容:
var rootObject = JsonConvert.DeserializeObject<RootObject>(json);
foreach (var male in rootObject.Men)
{
male.Sex = Sex.Man;
}
foreach (var female in rootObject.Women)
{
female.Sex = Sex.Women;
}
var startsWithJ = rootObject.Men.Concat(rootObject.Women)
.Where(x => x.Name.StartsWith("J",
StringComparison.OrdinalIgnoreCase))
.ToList();
foreach (var personStartsWithJ in startsWithJ)
{
Console.WriteLine (personStartsWithJ.Name);
Console.WriteLine (personStartsWithJ.Sex);
}
您的代码不起作用,因为您操作的是值以 "J" 开头的所有 name
属性,而不是包含 name
属性的 person 对象具有以 "J" 开头的值。所以当你向上导航时,你走的还不够远。 name
属性 的父对象是 person 对象。 person对象的父对象是数组,数组的父对象是men
(或women
)JProperty
。 (此外,要确定包含 属性 的数组的名称是 "men" 还是 "women",您需要获取它的 Name
,而不是它的 Value
.)
因此,如果您将代码更改为以下内容,您应该会得到预期的结果:
foreach (JProperty nameProp in startsWithJ)
{
Console.WriteLine(nameProp.Value);
Console.WriteLine(((JProperty)nameProp.Parent.Parent.Parent).Name);
}
Fiddle: https://dotnetfiddle.net/J7WxiF
就我个人而言,我发现 JObject
级别比 JProperty
级别更容易工作。这是获得相同结果的另一种方法:
var people = jsonDoc["men"]
.Children<JObject>()
.Union(jsonDoc["women"].Children<JObject>())
.Where(obj => obj["name"] != null && obj["name"].ToString().StartsWith("J"));
foreach (JObject person in people)
{
Console.WriteLine(person["name"]);
Console.WriteLine(((JProperty)person.Parent.Parent).Name);
}
Fiddle: https://dotnetfiddle.net/jzUOFT
如果你发现你总是想通过这种方式找到这个人的父集合名称,你甚至可以定义一个扩展方法:
public static class JHelper
{
public static bool IsMale(this JObject person)
{
return ((JProperty)person.Parent.Parent).Name == "men";
}
}
然后您可以简单地在 JObject
上调用 IsMale()
。它使代码更具可读性。
foreach (JObject person in people)
{
Console.WriteLine("Name: " + person["name"]);
Console.WriteLine("Gender: " + (person.IsMale() ? "male" : "female"));
}
有一个这样的 JSON 文件:
{
"men": [
{
"name": "Jordan",
"phone": "333-333-33"
},
{
"name": "Timothey",
"phone": "444-444-44"
}
],
"women": [
{
"name": "Jordan",
"phone": "111-111-11"
},
{
"name": "Sasha",
"phone": "222-222-22"
}
]
}
我想找出所有名字以J开头的人,并判断这个人是男是女。
var jsonProps = jsonDoc.Descendants().Where(t => t.Type == JTokenType.Property && ((JProperty)t).Name == prop);
var startsWithJ = jsonProps.Where(t => ((JProperty)t).Value.ToString().StartsWith("J"));
foreach (var person in startsWithJ)
{
Console.WriteLine(person.Value<string>());
Console.WriteLine(person.Parent.Parent.Value<string>());
}
问题是 person.Parent.Parent 为 null,我希望它不是 JArray,或者至少是 JToken,或者至少是一些 JToken,这样我才能得到它的值。
更新: 我有 100 种使用相似数据结构的类型。这些集合(男性、女性)可以位于任何嵌套级别,例如employee包含男女集合,或者student包含男女集合。我无法为解决方案中的每种类型创建强类型对象。有时我需要从 men/women 集合中移除对象并检查集合是否有此之后的任何元素。
这不是对 "how you query with LINQ to Json" 的直接回答,而是我发现使用强类型对象更容易的方法。
通过简单地创建以下数据结构(注意 POCO 用 JsonProperty
修饰,这是一个 Json.NET 属性):
public class RootObject
{
public List<Person> Men { get; set; }
public List<Person> Women { get; set; }
}
public class Person
{
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("phone")]
public string PhoneNumber { get; set; }
public Sex Sex { get; set }
}
public enum Sex
{
Man,
Women
}
现在,您可以使用 LINQ to Objects 轻松查询所需内容:
var rootObject = JsonConvert.DeserializeObject<RootObject>(json);
foreach (var male in rootObject.Men)
{
male.Sex = Sex.Man;
}
foreach (var female in rootObject.Women)
{
female.Sex = Sex.Women;
}
var startsWithJ = rootObject.Men.Concat(rootObject.Women)
.Where(x => x.Name.StartsWith("J",
StringComparison.OrdinalIgnoreCase))
.ToList();
foreach (var personStartsWithJ in startsWithJ)
{
Console.WriteLine (personStartsWithJ.Name);
Console.WriteLine (personStartsWithJ.Sex);
}
您的代码不起作用,因为您操作的是值以 "J" 开头的所有 name
属性,而不是包含 name
属性的 person 对象具有以 "J" 开头的值。所以当你向上导航时,你走的还不够远。 name
属性 的父对象是 person 对象。 person对象的父对象是数组,数组的父对象是men
(或women
)JProperty
。 (此外,要确定包含 属性 的数组的名称是 "men" 还是 "women",您需要获取它的 Name
,而不是它的 Value
.)
因此,如果您将代码更改为以下内容,您应该会得到预期的结果:
foreach (JProperty nameProp in startsWithJ)
{
Console.WriteLine(nameProp.Value);
Console.WriteLine(((JProperty)nameProp.Parent.Parent.Parent).Name);
}
Fiddle: https://dotnetfiddle.net/J7WxiF
就我个人而言,我发现 JObject
级别比 JProperty
级别更容易工作。这是获得相同结果的另一种方法:
var people = jsonDoc["men"]
.Children<JObject>()
.Union(jsonDoc["women"].Children<JObject>())
.Where(obj => obj["name"] != null && obj["name"].ToString().StartsWith("J"));
foreach (JObject person in people)
{
Console.WriteLine(person["name"]);
Console.WriteLine(((JProperty)person.Parent.Parent).Name);
}
Fiddle: https://dotnetfiddle.net/jzUOFT
如果你发现你总是想通过这种方式找到这个人的父集合名称,你甚至可以定义一个扩展方法:
public static class JHelper
{
public static bool IsMale(this JObject person)
{
return ((JProperty)person.Parent.Parent).Name == "men";
}
}
然后您可以简单地在 JObject
上调用 IsMale()
。它使代码更具可读性。
foreach (JObject person in people)
{
Console.WriteLine("Name: " + person["name"]);
Console.WriteLine("Gender: " + (person.IsMale() ? "male" : "female"));
}