We are trying to write a way to consume a JSON feed from a third party but unfortunately it's not well written, there appears to be no rules on what is sometimes there or not and also the structure changes depending on the key, I have no way of changing this we have to work with what we have. We know what we want based on certain keys but we are struggling to find them as the nested structure changes.
Is it possible to flatten the JSON down to a single List> that we can query and the key would be the fully qualified name including parents so the following JSON:
{
"employees": [
{ "firstName":"John" , "lastName":"Doe" },
{ "firstName":"Anna" , "lastName":"Smith" },
{ "firstName":"Peter" , "lastName":"Jones" }
]
}
Would become a list with keys like:
"employees.firstName" and a value of "John".
I think if we could get to this we could query the data for what we want, we have been trying to use dynamic objects but as I said the JSON changes and properties are missing sometimes and it's proving impossible to handle all scenarios.
If you don't know reliably the structure of a JSON but you are sure about property name ex "firstName". You can use the JSON.NET JObject and recursively loop through it and check if the property you are looking for exists in the current JToken.
The code should look something Like that, note the code I didn't compile it can have some typing mistakes:
private List<string> LoadFirstNames(string json)
{
JObject o = JObject.Parse(json);
List<string> firstNames = new List<string>();
foreach(var token in o.GetPropertyValues())
{
FindFirstName(token, firstNames);
}
return firstNames;
}
private void FindFirstName(JToken currentProperty, List<string> firstNamesCollection)
{
if(currentProperty == null)
{
return;
}
if(currentProperty["firstName"] != null)
{
firstNamesCollection.Add(currentProperty["firstName"]);
}
foreach(var token into currentProperty.Values())
{
FindFirstName(token , firstNamesCollection);
}
}
Related
This particular set up continues to elude me. I'm on .NET Core 6, so all of the set up stuff is gone. I'm left with the code below (I think). I have a json array of objects. I've seen where people say that this is a dictionary, so I've tried this, but the values within the array don't populate.
I'm able to get simpler objects to populate their values. I've also tried this pattern according to other SO posts, but no dice.
I keep getting close, but no cigar - What am I doing wrong?
Appsettings.json:
"TimeSlotMenuIds": [
{
"FounderWallEvening": 900000000001136943
},
{
"BravoClubEvening": 900000000001136975
}
]
My mapping class:
public class TimeSlotMenuIds
{
public Dictionary<string, long> TimeSlotMenuId { get; set; }
}
The thing that doesn't populate the values from my json file:
var test = _configuration.GetSection("TimeSlotMenuIds").Get<TimeSlotMenuIds[]>();
var t2 = _configuration.GetSection("TimeSlotMenuIds").GetChildren();
Your JSON structure doesn't really lend itself to being deserialised as a Dictionary directly, instead it would work as an array of dictionaries e.g. Dictionary<string, long>[]. I'm sure you don't want this, so an option would be to manually process the configuration:
var test = Configuration.GetSection("TimeSlotMenuIds")
.GetChildren()
.ToDictionary(
x => x.GetChildren().First().Key,
x => long.Parse(x.GetChildren().First().Value));
Though I would suggest this is a nasty hack. Instead, you should fix the JSON to something like this:
"TimeSlotMenuIds": {
"FounderWallEvening": 900000000001136943,
"BravoClubEvening": 900000000001136975
}
Which would then allow you to do this:
var test = Configuration.GetSection("TimeSlotMenuIds").Get<Dictionary<string, long>>();
I am new to C# and JSON and need some help in getting the Key name(s) in a list of a nested JSON object. The keys are dynamic so I won't necessarily know the keys.
sample code I've tried.
```
protected void test()
{
var mystring = #"{
""zone1"": {
""sites"": {
""site1"": {
""to"": ""email1"",
""subject"": ""subjecttxt"",
""link"": ""somesite""
},
""site2"": {
""to"": ""email1"",
""subject"": ""subject"",
""link"": ""somesite""
}
},
""zone2"": {
""to"": ""email1"",
""subject"": ""subject"",
""link"": ""somelink""
}}";
var rss = JObject.Parse(mystring);
foreach (var section in rss)
{
Console.Write(section.Key);
IList<JToken> result = rss["zone1"]["sites"].Children().ToList();
var zone = section.Key;
var site = rss[zone]["sites"];
foreach (var subsite in rss["zone1"]["sites"])
{
var subs = subsite.Parent.ToString();
// some other code
}
}
}
```
Looking for a result:
site1,
site2,
...
I can get the children as IList but looking for something similar to "section.Key" as noted above.
Thank you for your help.
I believe what you are looking for is to get the properties of the sites. Since accessing the rss["zone1"]["sites"] returns a JToken, you will need to convert that to JObject and then use Properties() method to get the data you need.
var sites = ((JObject)rss["zone1"]["sites"]).Properties();
Then you can simply iterate over the IEnumerable<Jproperty> to get the Name of the property or whatever else you need from under it.
To get the section.Key for the sites, you can use the following code.
foreach(var site in (JObject)rss["zone1"]["sites"]) {
Console.WriteLine(site.Key);
}
Output:
site1
site2
Your first call to JObject.Parse already does all the work of converting a string into a structured JSON object. The currently-accepted answer redoes some of this work by (1) turning a structured JSON object back into a string, and then (2) re-parsing it with JObject.Parse. There is a simpler way.
Instead, you can cast the value stored at rss["zone1"]["sites"] into a JObject. (The expression rss["zone1"]["sites"] has type JToken, which is a parent class of JObject, but in this case we happen to know that rss["zone1"]["sites"] is always JSON object, i.e. a collection of key-value pairs. Therefore, this cast is safe to perform.)
This is what the code might look like:
var sites = (JObject) rss["zone1"]["sites"];
foreach (var site in sites)
{
Console.WriteLine(site.Key);
}
I am working on JArray in .NET CORE and I am getting random structure of this one specific key, hence getting different error. I need to know if JArray has specific child Array and if Child JArray have specific key pair (NOT VALUE) i.e. value{ "Id":""} one of error is following;
Accessed JArray values with invalid key value: "id". Int32 array index expected.
at Newtonsoft.Json.Linq.JArray.get_Item(Object key) at
the standard structure I am expecting is as following;
{[value, [
{
"id": "7ef82869-e235-69a2-f81e-3a9664e89bc4",
"value": ""
}
]]}
sometime I get as, meaning throw null error where I am trying to map Id.
{[value, [
{
"value": ""
}
]]}
and some Time I don't get this property at all
I am trying following check to cover all scenario but Its not really working.
code
if (answerItems.value != null && answerItems.value.HasValues && answerItems.value["id"]!=null)
{
I received some constructive criticism on the brevity of my answer so I figured I would elaborate to help you through your issue.
First, let's take a look at your JSON. In short, it isn't valid. In fact, it isn't even close to valid JSON. I can only assume you meant something like this:
{
"values" : [{ "id" : "7ef82869-e235-69a2-f81e-3a9664e89bc4", "value": "" }]
}
I would suggest that anytime you are trying to parse data like this and you run into issues you start trouble shooting by validating the data itself. I like to use JSONLint for this.
Next, it is difficult from your example code to tell exactly what you are trying to do. I can only guess that you are attempting to use the dynamic object method of parsing and working with the data. A downside to this method is it is difficult to validate your data before you work with it.
Instead, I would use the Newtonsoft.Json.Linq.JObject.Parse method. This gives you some tools for working with and validating the information. Below I have included a very simple example of how this would be done.
using System;
using Newtonsoft.Json.Linq;
public class Program
{
public static void Main()
{
string json = "{ \"values\": [{ \"id\": \"7ef82869-e235-69a2-f81e-3a9664e89bc4\", \"value\": \"\" }] }";
JObject obj = JObject.Parse(json);
// Check to see if we got our value array
if (obj.ContainsKey("values")) {
JArray values = (JArray)obj["values"];
// Do we have any values in our array?
if (values.Count > 0) {
JObject firstItem = (JObject)values[0];
// We check to see if we have an ID parameter
if (firstItem.ContainsKey("id")) {
Console.WriteLine(firstItem["id"]);
}
}
}
}
}
As I mentioned in my original post, I would strongly recommend reviewing the Newtonsoft.Json documentation.
I'm deserializing (or parsing) a json string to a c# object (using Json.NET) and getting a JObject. I want to iterate all the properties with the key "bla", in the same way iterating all xml elements that named "bla" with XElement.Elements("bla").
If it's not possible, I would like to deserialize my json string into a c# object, and work dynamically and recursively on my deserialized json object (my json string can have lists / arrays that can have objects of 2 types.
In the end after editing my object (changing values and removing or adding properties) I need to serialize my object back to a json string.
Which is the best and easiest way to use json serializing and deserializing?
my Json looks like this:
{"Families":{"Family":[{"propA":"dhsj", "propB":"dhdisb"}, {"propA":"krbsbs", "propC":"ksndbd", "propD":"odndns", "Families":{"Family":[....]}}, {"propA":"dhsj", "propB":[{"propA":"dhsj", "propB":"dhdisb"}, {"propA":"krbsbs", "propC":"ksndbd", "propD":"odndns", "Families":{"Family":[....]}}, {"propA":"dhsj", "propB":"fghfgh"}]}]}
in conclusion, the json value is a json object that it's value is a list/array, the list/array can contain 2 "types" of objects, and one of these types also has a property which it's value is a json object that it's value is a list/array, and it goes like this recursively. sometimes the value of one of the props of the type that doesn't have a property which it's value is a json object that it's value is a list/array, can be a list/array itself, that can contain only 1 type of the two mentioned.
If you don't need a strongly-typed object, you can deserialize to a dictionary:
Dictionary<string, object> myObject = JsonConvert.DeserializeObject<Dictionary<string, object>>(jsonString);
And then just use it as a dictionary:
myObject["Property"] = value;
Or
foreach(var propertyKey in myObject.Keys)
{
// do something with each property
Console.WriteLine($"{propertyKey} = {myObject[propertyKey]}");
}
Here's a fiddle
You can serialize it back after you are done
My json looks more like this:
{"Familys":{"Family":[{"propA":"dhsj", "propB":"dhdisb"}, {"propA":"krbsbs", "propC":"ksndbd", "propD":"odndns", "Families":{"Family":[....]}}]}
For JSON like this:
var json = #"{
""Families"":{
""Family"":[
{
""propA"":""Top""
},
{
""propA"":""Top.Lower"",
""Families"":{
""Family"":[
{
""propB"":""propB value""
},
{
""propA"":""Top.Lower.EvenLower"",
""Families"":{
""Family"":[
{
""propA"":""Top.Lower.EvenLower.EvenLower""
}
]
}
}
]
}
}
]
}
}";
Do something like this:
//calling code makes use of "dynamic" to make things clean and readable.
dynamic parsedJson = JsonConvert.DeserializeObject(json);
var allPropAValues = GetPropAValues(parsedJson);
//**** NOTE: this has our extra property ****
var jsonWithExtraStuffProperty = JsonConvert.SerializeObject(parsedJson);
//recursive function that reads AND writes properties
public static List<string> GetPropAValues(dynamic obj)
{
var propAValues = new List<string>();
//**** NOTE: the use of an added property ****
obj.ExtraStuff = new Random().Next();
//if we have a propA value, get it.
if (obj.propA != null)
propAValues.Add(obj.propA.Value);
//iterate through families if there are any. your JSON had Families.Family.
if (obj.Families != null)
foreach (dynamic family in obj.Families.Family)
propAValues.AddRange(GetPropAValues(family));
return propAValues;
}
I have JSON String which I am reading from file.
I don't have the source of the JSON Object.
So I can't call JsonConvert.DeserializeObject.
However I want check if the JSON String has specific structure, if yes, append some string or If not append the structure.
allmodules {
feature: 'test-a'
}
submodules {
//some data
}
Assume if there's not allmodules, I would like to append my structure
allmodules {
feature: 'debug-a'
}
If it's already available, just append feature: 'debug-a'
And so on I have some custom work to do. Is there any efficient way to do this without breaking JSON format. Most of the questions regarding String to Object de-serialization, however as I mentioned I don't have original Object, and can't do that.
You can do this using JObject and doing a little manual parsing. It could look something like this:
public string AppendAllModules(string json)
{
var obj = JObject.Parse(json);
JToken token;
if (obj.TryGetValue("allmodules", out token))
return json;
obj.Add(new JProperty("allmodules", new JObject(new JProperty("feature", "test-a"))));
return obj.ToString();
}
Given:
{
"submodules": {
"name": "yuval"
}
}
Would yield:
{
"submodules": {
"name": "yuval"
},
"allmodules": {
"feature": "test-a"
}
}
I don't have the source of the JSON Object.
No worries, you can simply construct a new C# object that it compatible with the JSON definition. There are a number of options listed at
How to auto-generate a C# class file from a JSON object string
Once you have a compatible C# class in your project, you can deserialize the JSON and manipulate it as an object, just as if you had the original object.
use either JObject.FromObject or JObject.Parse to get your file json string into a JObject.
Then the below example code may help. I am going via an If/else way because you mentioned you can not get the exact structure.
JObject obj = JObject.FromObject(
new {Id = 5, Name = "Foo"}
);
JToken jtok = null;
bool found = obj.TryGetValue("Bar",StringComparison.CurrentCultureIgnoreCase, out jtok);
if (!found)
{
obj.Add("Bar","this is added");
}
else
{
Console.WriteLine(jtok);
}
Console.WriteLine(obj["Bar"]);
Of course after you are done editing your JObject you can use the JObject.ToString() method to get the string representation and send it over to the file.