Deserialize only one property of a JSON file - c#

I am faced with a problem.
I want to deserialize a complex JSON response from a server, but I only need one part of it.
Here is an example:
{
"menu": {
"id": "file",
"value": "File",
"popup": {
"menuitem": [
{"value": "New", "onclick": "CreateNewDoc()"},
{"value": "Open", "onclick": "OpenDoc()"},
{"value": "Close", "onclick": "CloseDoc()"}
]
}
}
}
I also used Csharp2json to get the class objects that I need, I just modified the menu class according to my needs :
public class Menuitem
{
public string value { get; set; }
public string onclick { get; set; }
}
public class Popup
{
public IList<Menuitem> menuitem { get; set; }
}
public class Menu
{
public Popup popup { get; set; }
}
public class RootObjectJourney
{
public Menu menu { get; set; }
}
Now, how do I deserialize if I only need the popup value and his children?

You can actually utilize the Linq namespace of the NewtonSoft.Json and modify your code little bit to get only the "popup" elements from the JSON.
your class structure remains the same. Make sure you use the namespace(s)
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
then in your code once you have the JSON string with you, you can use the "JObject" static method "Parse" to parse the JSON, like
var parsedObject = JObject.Parse(jsonString);
This will give you the JObject with which you can access all your JSON Keys just like a Dictionary.
var popupJson = parsedObject["menu"]["popup"].ToString();
This popupJson now has the JSON only for the popup key.
with this you can use the JsonConvert to de- serialize the JSON.
var popupObj = JsonConvert.DeserializeObject<Popup>(popupJson);
this popupObj has only list of menuitems.

If you do not use Newtonsoft and are using System.Text.Json in .NET Core, you can use this:
var post = JsonDocument.Parse(stringifiedJson);
var cat = post.RootElement.GetProperty("category").GetString();
You see GetString here to cast the value to string, there are other overloads available to cast the json value to Int32 etc.

If the intend is to deserialize only one property, I generally perefer to use JsonPath due to its flexibility. Please check the code below
var jsonQueryString = "{ 'firstName': 'John',
'lastName' : 'doe',
'age' : 26,}";
JObject o = JObject.Parse(jsonQueryString);
JToken token= o.SelectToken("$.age");
Console.WriteLine(token);
If your Json is complex, you can use power of JsonPath.
you can check https://support.smartbear.com/readyapi/docs/testing/jsonpath-reference.html#examples for JsonPath detailed documentation and examples.
I also included example below for further usage information:
JObject o = JObject.Parse(#"{
'store': {
'book': [
{
'category': 'history',
'author': 'Arnold Joseph Toynbee',
'title': 'A Study of History',
'price': 5.50
},
...
]
},
'expensive': 10
}");
//gets first book object
Console.WriteLine(o.SelectToken("$..book[0]"));
//get first book's title
Console.WriteLine(o.SelectToken("$..book[0].title"));
// get authors of the books where the books are cheaper then 10 $
foreach (var token in o.SelectTokens("$..[?(#.price < 10)].author"))
Console.WriteLine(token);

.NET 5+
The solution is very simple:
using System.Text.Json;
var doc = JsonDocument.Parse(response.Content);
var popupJson= doc.RootElement.GetProperty("menu").GetProperty("popup");

Related

In C#, can I edit/change the types in a json string?

I have slightly annoying use case.
So, I am calling an API . The APi returns some json, which contains a json object with x amount of fields:
{
"status": "ok",
"result": {
"firstprovider": [ .... ],
"secondprovider": [ ...],
"thirdprovider": [ ... ]
}
}
In this example, only three provider are returned, but I could get more or less than that, and their names may vary. It's quite important that I save those names.
The "providers" inside of "result" are of the same type, so I can easily deserialize those to a certain model.
Now, I would normally expext "result" to be a json array of elements, so I could easily deserialize "result" into a List<LiveShopperEventModel>.
Currently, I made a hacky solution, creating a Dictionary<string,Provider> where the key is the name of the provider, and then I later use selectmany to flatten it into a list.
But, I was wondering if there exists some way in c#, that would allow me to convert the "result", into an array, which would make deserialization a lot simpler for me.
So, does anyone know of a way, or a resource that in c# can help in changing the types of json elements, and in this case, making a json object into a json array, with the fields becoming elements in the list?
Reproducing concept with minimal example
So, let's say my json looks like this:
{
"status": "ok",
"result": {
"firstprovider": [ {"name":"John"}, {"car":"BMW"}, {"surname":"Johnson"} ],
"secondprovider": [ {"name":"Zoe"}, {"car":"Ford"}, {"surname":"johnsøn"}],
"thirdprovider": [{"name":"Elliot"}, {"car":"Volkswagen"}, {"surname":"Jackson"} ]
}
}
Then I can deserialize it as in the following code snippet:
string json = "{\r\n\"status\": \"ok\", \r\n\"result\": { \r\n \"firstprovider\": [ {\"name\":\"John\"}, {\"car\":\"BMW\"}, {\"surname\":\"Johnson\", \"age\":30, \"car\":\"fast\"} ],\r\n \"secondprovider\": [ {\"name\":\"Zoe\"}, {\"car\":\"Ford\"}, {\"surname\":\"johnsøn\", \"age\":31, \"car\":null}], \r\n \"thirdprovider\": [{\"name\":\"Elliot\"}, {\"car\":\"Volkswagen\"}, {\"surname\":\"Jackson\", \"age\":32, \"car\":null} ] \r\n }\r\n }\r\n";
// deserializing to a dictionary
var resultDict = JsonConvert.DeserializeObject<ResultModel>(json);
// and now flattening the structure, so that it is a list of "ProviderModel"
// this is the part that feels hacky to me
var providerModelList = resultDict.result.SelectMany(listOfEvents => {
listOfEvents.Value.Select(Provider =>
{
Provider.provider = listOfEvents.Key;
return Provider;
}).ToList();
return listOfEvents.Value;
}).ToList();
public class ResultModel
{
[JsonProperty("result")]
public Dictionary<string, List<ProviderModel>> result { get; set; }
}
public class ProviderModel
{
public string provider { get; set; }
public string name { get; set; }
public string surname { get; set; }
}
The `selectmany" part feels hacky to me, since, i'm combining linq queries in a way that feels overly complicated
Instead, I think it would be much nicer, is the result class could just look like:
public class ResultModel
{
[JsonProperty("result")]
public List<ProviderModel> result { get; set; }
}
you can try something like this
List<ProviderModel> providerModelList = ((JObject)JObject.Parse(json)["result"])
.Properties()
.Select(x => GetValues(x))
.ToList();
public ProviderModel GetValues(JProperty jProp)
{
var providerModel = new JObject(((JArray)jProp.Value)
.Select(jo => ((JObject)jo).Properties().First()))
.ToObject<ProviderModel>();
providerModel.provider = jProp.Name;
return providerModel;
}

What is the best practice for receiving/handling json data in c#?

C#
Let's say that I want to make a winform page that receives a certain amount of random features read from the contents of a json file. (while using the 'Newtonsoft.Json' library)
Code that Deserializes the json file
Root myDeserializedClass = JsonConvert.DeserializeObject<Root>(File.ReadAllText(#"..\..\Json\features.json"));
These classes are set to represent the contents and structure of the json file within the same c# file, but outside of the main class of course.
class Root
{
public List<Category> category { get; set; }
}
class Category
{
public string name { get; set; }
public List<Feature> feature { get; set; }
}
class Feature
{
public string name { get; set; }
public string frequency { get; set; }
}
I have followed the practices to make this happen here:
https://www.newtonsoft.com/json/help/html/DeserializeWithJsonSerializerFromFile.htm
Can not deserialize JSON with array in array
https://json2csharp.com/
It works, however there are two main problems I can see with this:
It can end up visually cluttering the .cs file with lots of classes that you'll never need to look or edit, especially when it is interpreting multiple json files
It isn't dynamic, and it will only work for one json file that you have to make compatible by creating these classes for every subclass that exists within the json file.
My question: Is there a way to deserialize the json file without having to resort to creating multiple classes for every sub-category of data in the json string?
I believe you don't need the classes, because you don't need the whole JSON string, is that correct?
If so, instead of deserializing the whole json file, you could partially deserialize only the parts which you are interested in.
Have a look at this example from the Newtonsoft.Json documentation, where we have a long json string representing a response from a Google search, but are only interested in the responseData/results part of it, and only in some fields of that result object:
Object to partially desierialize:
public class SearchResult
{
public string Title { get; set; }
public string Content { get; set; }
public string Url { get; set; }
}
Deserializing Partial JSON Fragment Example:
string googleSearchText = #"{
'responseData': {
'results': [
{
'GsearchResultClass': 'GwebSearch',
'unescapedUrl': 'http://en.wikipedia.org/wiki/Paris_Hilton',
'url': 'http://en.wikipedia.org/wiki/Paris_Hilton',
'visibleUrl': 'en.wikipedia.org',
'cacheUrl': 'http://www.google.com/search?q=cache:TwrPfhd22hYJ:en.wikipedia.org',
'title': '<b>Paris Hilton</b> - Wikipedia, the free encyclopedia',
'titleNoFormatting': 'Paris Hilton - Wikipedia, the free encyclopedia',
'content': '[1] In 2006, she released her debut album...'
},
{
'GsearchResultClass': 'GwebSearch',
'unescapedUrl': 'http://www.imdb.com/name/nm0385296/',
'url': 'http://www.imdb.com/name/nm0385296/',
'visibleUrl': 'www.imdb.com',
'cacheUrl': 'http://www.google.com/search?q=cache:1i34KkqnsooJ:www.imdb.com',
'title': '<b>Paris Hilton</b>',
'titleNoFormatting': 'Paris Hilton',
'content': 'Self: Zoolander. Socialite <b>Paris Hilton</b>...'
}
],
'cursor': {
'pages': [
{
'start': '0',
'label': 1
},
{
'start': '4',
'label': 2
},
{
'start': '8',
'label': 3
},
{
'start': '12',
'label': 4
}
],
'estimatedResultCount': '59600000',
'currentPageIndex': 0,
'moreResultsUrl': 'http://www.google.com/search?oe=utf8&ie=utf8...'
}
},
'responseDetails': null,
'responseStatus': 200
}";
// Parse JSON into a JObject, which we can easily traverse
JObject googleSearch = JObject.Parse(googleSearchText);
// get JSON result objects into a list
IList<JToken> results = googleSearch["responseData"]["results"].Children().ToList();
// serialize JSON results into .NET objects
IList<SearchResult> searchResults = new List<SearchResult>();
foreach (JToken result in results)
{
// JToken.ToObject is a helper method that uses JsonSerializer internally
SearchResult searchResult = result.ToObject<SearchResult>();
searchResults.Add(searchResult);
}
// Title = <b>Paris Hilton</b> - Wikipedia, the free encyclopedia
// Content = [1] In 2006, she released her debut album...
// Url = http://en.wikipedia.org/wiki/Paris_Hilton
// Title = <b>Paris Hilton</b>
// Content = Self: Zoolander. Socialite <b>Paris Hilton</b>...
// Url = http://www.imdb.com/name/nm0385296/
This way, we only need to create a class for SearchResult and for nothing else, which sounds like what you want to have. While traversing the JSON object with code like googleSearch["responseData"]["results"] you can check whether the result is null and act accordingly, which means you can have optional fields in your JSON file, which are not present in other files, without your code breaking.
Does this help you solve your issues?
I believe that best practice is using classes.
Here are my arguments for using classes in your case:
You can read json bit by bit, use JObject.Parse or even dynamic (ugh) but it think your code should depend on a class (a dto) not on a json string. This input structure happens to be stored in json, but may not be. Most of your unit tests should take in an object, not a string.
I find the argument of deserialising to classes not being dynamic weak because you need to write the code that will handle the added elements. In other words if you add a new feature to json it won't just work, you need to write the code to support it and each time you change the json structure you need to update your code anyway.

Deserializes JSON to an object in c# using json.net

I am trying to convert my json into a rule object. I have been following this guide from Newtonsoft http://www.newtonsoft.com/json/help/html/deserializeobject.htm.
public class Rule{
public string Field { get; set; }
public string Test { get; set; }
public Rule[] Cases { get; set; }
}
public class Rules {
public List<Rule> Root{ get; set; }
}
My Json from rules.js
{
"Rules": [{
"Field": "Subject",
"Test": "^(Azure Exception)",
"Cases": [{
"Field": "Content",
"Test": "Hostname: az.....(?<Hostname>[^\n])",
"Cases": [{
"Field": "Content",
"Test": "Hostname:\\s+(?<Hostname>.*)\\s+Site name:\\s+(?<SiteName>.*)"
}]
}]
}]
}
In my main method:
String RulesFile = "cSharp/rules.js";
String Json = System.IO.File.ReadAllText(RulesFile);
Rule rule = JsonConvert.DeserializeObject<Rule>(Json);
var rules = JsonConvert.DeserializeObject<Rules>(Json);
//rule.Cases
//rule.Field
//rule.Test
//rules.Root
Console.Write(rule.Field);
I've tested my json and i can output it in my terminal. I'm unsure how to assign each field in json to my rules objects. Looking at the newtonsoft docs this should work, but I'm not getting any output.
I want to be able to print these fields out, anyone know to do it?
Cheers all in advance.
In your JSON string, the root object is an object with a Rules property. That property is an array of objects. You need to define and deserialize the root object, eg
class Rules
{
public Rule[] Rules{get;set;}
}
var rules = JsonConvert.DeserializeObject<Rules>(Json);
You can generate the DTOs requires for deserialization in Visual Studio by copying the JSON string and select Paste JSON as Classes in the Edit menu. You can also generate classes by using an online converter like json2csharp

Get specific json elements

I couln't find a similar case here, hence my question. I have a json like this:
{
"prop1": "bla",
"propn": "bla",
"Data": {
"42": {
"prop1": "bla",
"prop2": "bla",
"Symbol": "42"
},
"abc": {
"prop1": "bla",
"prop2": "bla",
"Symbol": "abc"
}
},
"Type": 100
}
Now, how do I get all elements from Data, and the most I am interested in the ones that have the symbol property set. I tried Newtonsoft.json.linq and jobject, but got really no clue what to do here. Any guidance anyone? Thanks!
Ronald
What you're looking for is called 'deserialize'. You have a string (the json in you post) and you want to turn it into an object.
The first steps you need to do are:
Create a class that matches your data.
Simply copy your json string in your post and use the option in Visual Studio to 'paste JSON as class'. Perhaps clean it up by changing the name RootObject to something more descriptive.
Install the NuGet package Newtonsoft in Visual Studio.
Now you can use MyClass myObject = JsonConvert.DeserializeObject<MyClass>(myString);
To access Symboljust use myObject.Data.Symbol
I imagine that once you extract partial data from json, if you still need to pass the data through your application, a dedicated model will come handy.
public class Data
{
public Element abc { get; set; }
}
public class Element
{
public string prop1 { get; set; }
public string prop2 { get; set; }
public string Symbol { get; set; }
}
While you certainly can rely on JObject handling the deserialization, i find it more intuitive to work with anonymous templates, especially for partial data retrieval.
var template = new
{
Data = default(Data)
};
var instance = JsonConvert.DeserializeAnonymousType(json, template);
will give you something like
I recomend you to use Jil library, is faster and more simple than Newtonsoft.json

Alter Json or ExtensionDataObject

I have a Json service I cannot alter as it is not mine.
Their Json is a formatted in a way that parsing it is difficult. It looks something like this.
"people": {
"Joe Bob": {
"name": "Joe Bob",
"id": "12345"
},
"Bob Smith": {
"name": "Bob Smith",
"id": "54321"
}
},
I would really prefer this was laid out like a JSon array, however it presently is not.
I am wondering the best approach here. Should I alter the Json to look like an array before I parse it or load up the ExtensionData and parse it from that?
There are other items in the feed that I do not have issue with. Just stuck with this one section.
Thanks
You can use json.net to deserialize the data (the json you pasted, and doing only one parsing, without modifying anything).
using dynamic foo = JsonConvert.DeserializeObject<dynamic>(data)
than, you can iterate the list using foo.people, accessing the Name and Value.
you can create a class (if you know what the schema is, and to deserialize the data into a list of the given class such as:
public class People
{
[JsonProperty(PropertyName="people")]
public IDictionary<string, Person> Persons { get; set; }
}
public class Person
{
[JsonProperty(PropertyName="name")]
public string Name { get; set; }
[JsonProperty(PropertyName = "id")]
public string Id { get; set; }
}
and than call:
var obj = JsonConvert.DeserializeObject<People>(data);
foreach (var item in obj.Persons.Values)
{
//item is instance of Person
}
Another good and possible option will be:
How can I navigate any JSON tree in c#?

Categories