I have a JSON array where I need to get the CustomerId value from property where the CustomerId property exits for that section, I'm trying below to loop through the categories and skip the one that has no CustomerId property down its properties tree
var customerId = "";
foreach (var category in JObject.Parse(someData)?["categories"])
{
val = category?["sections"].FirstOrDefault()
?["areas"]?.FirstOrDefault()
?["components"]?.
?["variables"]?.FirstOrDefault()
?["properties"]
?["customerId"]?.ToString();
if (val == null)
continue;
else
{
customerId = val;
break;
}
}
Problem is this looks inefficient (less readable) in the sense that I imagine there is a nice .Select
that can be used to get the same result without going forEach element and check if the property is null.
Please not this is not an issue I have, this is working, I'd only like to do this in a more readable way using Select
instead of ForEach
.
Sample JSON Data
{
"categories": [
{
"identifier": "cat1",
"sections": [
{
"identifier": "030615e9-67f9-43ca-a06e-194e7afadccb",
"properties": {},
"areas": [
{
"identifier": "1206f27b-d354-4bfa-9b5e-1fe6b4f7cc83",
"componenets": [
{
"identifier": "49e4550f-8001-4d32-b796-a7ad4423e118",
"type": "Product",
"variables": [
{
"identifier": "0d260417-fa6d-492b-85f1-dc2565bc4805",
"properties": {
"description": ""
}
}
]
}
]
}
]
}
]
},
{
"identifier": "cat2",
"sections": [
{
"identifier": "00b5bfa6-f482-47c2-bdd7-aaac273b7772",
"properties": {},
"areas": [
{
"identifier": "1ca9d051-5ec0-45af-84bc-561cd7620efa",
"componenets": [
{
"identifier": "c73b1e52-3acd-4020-8fc5-adfef7d633b4",
"type": "Customer",
"variables": [
{
"identifier": "0064e872-5c7f-4ec7-a2d6-e8b35b94bd1d",
"properties": {
"customerId": { "Text":"MainId",
"Value":"A12123"
}
}
}
]
}
]
}
]
}
]
}
]
}
CodePudding user response:
An alternative approach is to use .SelectTokens
from the JSON.NET library (which it appears you are using). Assuming parsedJson
is your parsed root object as a JObject
:
var customerId = parsedJson.SelectTokens("$.categories..sections..areas..componenets[?(@.type == 'Customer')]..variables..properties.customerId.Value")
.FirstOrDefault()?
.ToString();
This essentially finds the first entry where a component has a type "Customer", and a property "customerId" and returns that customerId as a string.
Strictly speaking you don't need the query on type ([?(@.type == 'Customer')]
) but I got the impression that's what you were going for. Without it the query would look like this:
"$.categories..sections..areas..componenets..variables..properties.customerId.Value"
See more about SelectTokens
in the docs here.
CodePudding user response:
If you want to use the same logic as in you question, the code below is what you can use.
First you iterate over all the categories
where you select
the customerId
field from.
This will result in a list of customerIds where some are null
and some might have a value.
The next SingleOrDefault
takes the first item from that list which does have a value. This will be your string customerId
.
Note: When there are no customerId's in your json, the customerId
will be null
.
If you want to throw an exception instead of working with null, you can use First()
instead of FirstOrDefault
.
var customerId = JObject.Parse(someData)?["categories"]
.Select(category => category?["sections"].FirstOrDefault()
?["areas"]?.FirstOrDefault()?["components"]
?["variables"]?.FirstOrDefault()
?["properties"]
?["customerId"]?.ToString())
.SingleoOrDefault(customerId => customerId != null);
CodePudding user response:
I have an optimized version:
var pJson = JObject.Parse(someData);
JToken? customerToken = pJson.SelectToken($"$..customerId");
var customerId = customerToken?.ToString();
CodePudding user response:
I would first parse the JSON to list of objects and the use the Linq to fetch the list of CusomerIds where it is not null.
List<T> arrayItems = jsonBuidler?["categories"].ReadFromJson<List<T>>();
List<string> customerIds = arrayItems.Where(_ => CustomerId != null).Select(_ => _.CustomerId);