I am trying to find a more elegant solution than foreach
loops for the following problem.
Sample JSON Structure:
[{
"OpportunityId": "ABC-123-XYZ",
"Status": "Active",
"Milestones": {
"Milestone": [
{
"Name": "Award",
"Date": "8\/27\/2021"
}
]
},
"Staff": {
"Pocs": [
{
"Role": "Development Lead",
"Name": "Doe, John",
"Email": "john.doe@company.com"
},
{
"Role": "Capture Manager",
"Name": "Doe, Jane",
"Email": "jane.doe@company.com"
}
]
}
}]
I can get the data I want using the following:
string json = [see above];
JArray? obj = JsonConvert.DeserializeObject<JArray>(json);
foreach (var single in obj)
{
JToken? pocs = single.Value<JToken>("Staff")?.Value<JToken>("Pocs");
if (pocs != null)
{
foreach(var poc in pocs)
{
if (poc.Value<string>("Role") == "Capture Manager")
{
[Do something with the resulting JToken/values]
}
}
}
}
I feel like there has to be some Linq to help me here, but everything I've tried thus far has been unsuccessful. I have no control over the JSON input, I just need to deal with it as is. Any help would be greatly appreciated!
As mentioned by @gunr2171 in the comment, you can work with JSON Path.
using Newtonsoft.Json.Linq;
using System.Collections.Generic;
JArray jArray = JArray.Parse(json);
IEnumerable<JToken> jTokens = jArray.SelectTokens("$..Staff.Pocs[?(@.Role == 'Capture Manager')]");
The above JSON Path:
$
- From root element.
..Staff
- Deep scan the element node with the Staff
field.
.Pocs
- Access to the dot-notated Pocs
child.
[?(<expression>)]
- Filter expression.
@.Role == 'Capture Manager'
- Current node with the filter expression that matches the Role
field value equal to "Capture Manager".
Reference:
Working with System.Linq and Newtonsoft.Json.Linq.
using Newtonsoft.Json.Linq;
using System.Collections.Generic;
using System.Linq;
IEnumerable<JToken> jTokens = jArray.Children()
.Values("Staff")
.SelectMany(x => x["Pocs"])
.Where(x => x.SelectToken("Role").Value<string>() == "Capture Manager")
.ToList()