Make dynamic dictionary from json file - c#

I have json file like this:
{
"fields": {
"customfield_10008": {
"value": "c1"
},
"customfield_10009": {
"value": "c2"
}
...
}
}
and I would like to create dictionary in c# like:
key: value
"customfield_10008":"c1"
"customfield_10009":"c2"
How I can achive this? I load json in this way,
dynamic json = JsonConvert.DeserializeObject(File.ReadAllText("data.json");
and don't know how to create dict like above

A little bit linq tricks can help you
var dict = JObject.Parse(File.ReadAllText("data.json"))["fields"]
.Cast<JProperty>()
.ToDictionary(x => x.Name, x => (string)x.Value["value"]);

Come through the values and collect them:
var result = new Dictionary<string, string>();
foreach (var field in obj.fields)
{
result.Add(field.Name, Convert.ToString(field.Value.value));
}

If you have json which do not have type in compile time, you can use dynamic type at that time.
I would parse above json using dynamic type and generate dictionary with parsed value :
var dicValues = new Dictionary<string,string>(); // this dictionary contains key value pair result
dynamic res = JsonConvert.DeserializeObject<dynamic>(File.ReadAllText("data.json");
dynamic availableFields = res["fields"];
if (availableFields != null)
{
foreach (var field in availableFields)
dicValues.Add(field.Name, field.Value["value"].Value);
}

Related

C# deserialize selected properties in json

Given the following JSON
{
"enabled": true,
"name": "Name",
"description": "Test",
"rules": [
{
"propA": "a",
"propB": "b"
}
]
}
Is it possible in C# to deserialize on selected properties based on an input list:
var propertiesToInclude = new List<string> { "description", "rules.PropA" };
The example json is a simplified example, the real one can contain hundred of properties. The use case is to only return the fields that matches the input list in a dynamic or anonymous object and discard the other properties.
using Newtonsoft.Json.Linq;
var propertiesToInclude = new List<string> { "description", "rules.PropA" };
var splitted = propertiesToInclude.SelectMany(x => x.Split('.'));
string text = File.ReadAllText("test.json");
var json = JToken.Parse(text);
Process(json);
Console.WriteLine(json);
void Process(JToken token)
{
if (token is JObject jObject)
{
jObject.Properties()
.Where(x => !splitted.Contains(x.Name, StringComparer.OrdinalIgnoreCase))
.ToList()
.ForEach(x => x.Remove());
foreach (var x in jObject)
Process(x.Value);
}
else if (token is JArray jArray)
{
foreach (var x in jArray)
Process(x);
}
}
This code on the data shown will give the desired result.
The output is a JToken object containing the desired properties.
However, I used a simple search for all occurrences of names in a splited array. This will give false positives if, for example, the root object contains the propA property or the object in the array contains the description property.
To avoid this, you need to compare the JToken.Path property with the propertiesToInclude elements, taking into account the depth.

How to get property value from .net dynamic array object

I've got a json file containing
{
"Accounts": null,
"AccountTypes": null,
"Actions": null,
"Photos": [
{
"Instance": "...",
"Key": "..."
},
....
]
}
Now I want to get all the Instance properties from the Photo objects. I've got the following code:
var photos = new List<Photo>();
string json = File.ReadAllText(file);
dynamic jsonObj = Newtonsoft.Json.JsonConvert.DeserializeObject(json, typeof(object));
var jsonPhotos = jsonObj.Photos as IEnumerable<dynamic>;
var instances = jsonPhotos.Select(x => x.Instance);
foreach (var instance in instances)
photos.Add(new Photo
{
Document = Convert.FromBase64String(instance)
});
However, jsonPhotos.Select(x => x.Instance); isn't returning anything...
I am able to get things working by using
var instances = new List<string>();
foreach (var photo in jsonPhotos)
instances.Add(photo.Instance.Value);
But can I solve this in a LINQ way?
Why just don't use Json.Linq for that? Parse JSON to JObject instance, then map every token from Photos array to Photo instance (I've omitted Convert.FromBase64String because OP sample doesn't have a valid base64 data, but converting Instance value can be easily added)
var json = JObject.Parse(jsonString);
var photos = json["Photos"]
.Select(token => new Photo
{
Document = token["Instance"]?.Value<string>()
})
.ToList();
The .Select(x => x.Instance) indeed returns ... on .NET Core 3.1. Can you verify that the contents of the json variable are actually what you expect?
Specifically
jsonPhotos.Select(x => x.Instance);
works as expected, while
jsonPhotos.Select(x => x.SomeNonExistingProperty);
enumerates nothing / empty values.
For example, this code prints Instance A, then Instance B, then nothing twice:
var json = #"
{
""Photos"": [
{
""Instance"": ""Instance A"",
""Key"": ""...""
},
{
""Instance"": ""Instance B"",
""Key"": ""...""
}]
}";
var jsonObj = JsonConvert.DeserializeObject<dynamic>(json);
var jsonPhotos = jsonObj.Photos as IEnumerable<dynamic>;
var instances = jsonPhotos.Select(x => x.Instance);
foreach (var instance in instances)
{
Console.WriteLine(instance);
}
// In contrast, this one will print empty lines.
instances = jsonPhotos.Select(x => x.SomeNonExistingProperty);
foreach (string instance in instances)
{
Console.WriteLine(instance);
}
I took the liberty to change the deserialization to dynamic directly, but it also works with the original code from the question.

Why can I not parse Neo4jClient's query result (type string) into a Dictionary<string, string> using JsonConvert in C#

I am trying to parse Neo4jClient's query result of paths (of type string) using JsonConvert.
I was able to parse the query result for nodes using this method:
var _gClient = new GraphClient(new Uri("http://localhost:7474/db/data"));
_gClient.Connect();
var result = _gClient.Cypher
.Match("(n)")
.Return(n => n.As<string>())
.Results.ToList();
result.ForEach(n =>
{
var dict = JsonConvert.DeserializeObject<Dictionary<string, string>>(n);
Console.WriteLine("Keys: " + String.Join(",", dict.Keys));
Console.WriteLine("Values: " + String.Join(",", dict.Values));
});
However, when I tried to do the same with the query result of paths, JsonConvert's DeserializeObject method can't do the same thing:
var _gClient = new GraphClient(new Uri("http://localhost:7474/db/data"));
_gClient.Connect();
var result = _gClient.Cypher
.Match("p=(a)-[:ACTED_IN]->(m:Movie {title:'The Matrix'})")
.Return(p => new
{
Nodes = Return.As<IEnumerable<string>>("EXTRACT(p in nodes(p) | p)"),
Relationships = Return.As<IEnumerable<string>>("EXTRACT(p in relationships(p) | p)")
})
.Results.ToList();
foreach (var n in result)
{
foreach (var s in n.Nodes)
{
JsonConvert.DeserializeObject<Dictionary<string, string>>(s);
}
}
The error was Unexpected character encountered while parsing value: {. Path 'extensions', line 2, position 17.
This is part of the string to be parsed:
{
"extensions": {},
"metadata": {
"id": 8,
"labels": [
"Person"
]
},
Does that mean Json can't deserialize empty braces? If so is there any other way I can parse this huge structure out?
The problem is that you're trying to deserialize into a Dictionary<string,string> but your JSON isn't a Dictionary<string,string> the error about the unexpected { is because for it to be a Dictionary<string,string> the JSON would look like:
{
"Key1" : "Value1",
"Key2" : "Value2"
}
The { on both extensions and metadata imply that there is an object there, not just a string. To that end you can deserialize it using something like:
JsonConvert.DeserializeObject<Dictionary<string, object>>(s)
But if you want to access the properties, you may as well do:
JsonConvert.DeserializeObject<Dictionary<string, dynamic>>(s)

Json.NET (Newtonsoft) to parse somewhat dynamic data (c#)

using c# - I have a string of valid json, and am attempting to parse it into a Dictionary but am struggling with the syntax to do so.
Here's an example of the data I'd like to parse:
{
"data": {
"KeyOne": {
"val": "first!"
"fooBar": "invalid data not needed",
},
"anotherKey": {
"val": null
},
"TheThirdKey": {
"val": 999
"fooFooBarBar": "more unneeded data",
},
"KeyKeyKey": {
"val": "super neato something"
},
...
this needs to be moved into a Dictionary<string, object> with some fairly specific rules:
the ever changing element name is the key ('KeyOne', 'anotherKey'...) - this is unique within the dataset
for the dictionary value, I ONLY need the string or number or null that is the value of 'val' ('first', null, 999, ...)
so my final dictionary should be something like:
"KeyOne" : "first!"
"anotherKey" : null
"TheThirdKey": 999
"KeyKeyKey" : "super neato something"
I've tried to parse this using different variations of
JsonConvert.DeserializeObject<Dictionary<string, object>
I've also tried iterating over the jTokens as such:
JObject jObject = JObject.Parse(jsonString);
List<JToken> jTokens = jObject["data"].Children().ToList();
foreach (JToken jToken in jTokens) { ...
but after so many hours of trying, I am getting embarrassingly nowhere... Hopefully this is something that can be performed with Json.NET, but I have yet to figure it out.
Thoughts?
You could do it this way:
JObject jObject = JObject.Parse(jsonString);
var dataChildren = jObject["data"].Children().Cast<JProperty>();
Dictionary<string, object> result = dataChildren
.ToDictionary(x => x.Name, x => x.Value["val"].Value<JValue>().Value);
You will get a Dictionary<string,object> as a result

error of reading Json string in C# by JsonConvert

I need to read data from a Json string in C#.
The Json string is like:
{
"data_level":{
"performance":{
"#value":"1000",
"#size":"10",
},
"points":{
"#type":"profit",
"tier":{
"#below":"80",
"#above":"100"
},
"kids":[
{
"#kid":"150"
},
{
"#kid":"200"
}
]
}
}
My C# code:
var my_dic = JsonConvert.DeserializeObject<Dictionary<string, dynamic>>(json_string);
var my_data = my_dic["data_level"]
string v = my_data["performance"]["#size"];
For "kids", I have two child "kid" have the same name but differne value. How to get all of them instead of only the one last read ?
Any help would be appreciated.
You should leave out the last [0] .
For the updated question:
my_children = my_dic["points"]["kids"];
foreach (KeyValuePair<string, int> pair in my_children)
{
Console.WriteLine(pair.Key, pair.Value["#kid"]);
}
This should work...

Categories

Resources