I have a question about System.Text.Json.deserialize.
I have got the Json value like this
{
"id" :"1",
"ShopName" :"Paint Shop",
"Books" : [1,2]
}
It can easy convert to simple object as
public class bookstore {
public int id {get;set}
public string ShopName {get;set}
public IEnumerable<int> Books {get;set}
}
But I have a function which convert books array int into list of object like this
{
"id" :"1",
"ShopName" :"Paint Shop",
"Books" : [
{
"bookId":1,
"bookName":"Peter Pan",
"location":"A01"
},
{
"bookId":2,
"bookName":"Cooking Book",
"location":"A02"
}
]
}
Right now, I want to modify the value of Books[1].location value, by using jsonnode.parse(string) to convert the object.
Can I know how to do it ?
Thank you
Don't know why you want to use the JsonNode.Parse().
If you just want to modify the location's value, maybe you can use the JsonSerializer with BookStore and Book class to help you.
📌 The Book class is a IEnumerable property of BookStore.
an example by .NET6 Console App
📌 BookClass is a 2-level nested class
// See https://aka.ms/new-console-template for more information
using System.Text.Json;
// Initialize json string
string jsonStr = "{\"id\": 1, \"ShopName\" :\"Paint Shop\", \"Books\" : [\r\n {\r\n \"bookId\":1,\r\n \"bookName\":\"Peter Pan\",\r\n \"location\":\"A01\"\r\n },\r\n {\r\n \"bookId\":2,\r\n \"bookName\":\"Cooking Book\",\r\n \"location\":\"A02\"\r\n }\r\n ]\r\n }";
// Deserilize to object
Bookstore bookstore = JsonSerializer.Deserialize<Bookstore>(jsonStr);
// Write the location's value
Console.WriteLine(bookstore.Books.ToArray()[1].location);
// Modified the location's value
bookstore.Books.ToArray()[1].location += "_Modified";
// Write the modified location's value
Console.WriteLine(bookstore.Books.ToArray()[1].location);
// See result output
Console.ReadLine();
public class Bookstore
{
public int id { get; set; }
public string ShopName { get; set; }
public IEnumerable<Book> Books { get; set; }
}
public class Book
{
public int bookId { get; set; }
public string bookName { get; set; }
public string location { get; set; }
}
Result output image
If you persist to use JsonNode.Parse(), then need more steps. like this.
// See https://aka.ms/new-console-template for more information
using System.Text.Json;
using System.Text.Json.Nodes;
// Initialize json string
string jsonStr = "{\"id\": 1, \"ShopName\" :\"Paint Shop\", \"Books\" : [\r\n {\r\n \"bookId\":1,\r\n \"bookName\":\"Peter Pan\",\r\n \"location\":\"A01\"\r\n },\r\n {\r\n \"bookId\":2,\r\n \"bookName\":\"Cooking Book\",\r\n \"location\":\"A02\"\r\n }\r\n ]\r\n }";
// Parse to jsonNode
JsonNode jsonNode = JsonNode.Parse(jsonStr);
// Convert to JsonObject
JsonObject jsonObject = jsonNode.AsObject();
// Convert Books to Json Array
JsonArray jsonArray = jsonObject["Books"].AsArray();
// Convert index 1 in array to Json object
JsonObject book1Object = jsonArray[1].AsObject();
// Write the location value
Console.WriteLine(book1Object["location"]);
// Modify location value
book1Object["location"] += "_modified";
// Write the modified location value
Console.WriteLine(book1Object["location"]);
// See output
Console.ReadLine();
public class Bookstore
{
public int id { get; set; }
public string ShopName { get; set; }
public IEnumerable<Book> Books { get; set; }
}
public class Book
{
public int bookId { get; set; }
public string bookName { get; set; }
public string location { get; set; }
}
Other suggestion
Use Newtonsoft.Json is better. Because when convert a json to a C# object, will need to convert many properties with different value type.
The Newtonsoft.Json had already handle these situation, at the mean time the System.Text.Json does not.
You can use JObject to modify json directly
var jObject = JObject.Parse(json);
jObject["Books"][1]["location"] = "new value";
Result:
Note:
You should add Newtonsoft.Json package.
Since you are using System.Text.Json, you can change value using this code
var jsonParsed=JsonNode.Parse(json);
jsonParsed["Books"][1]["location"]="A03";
after this , if you need you can get an updated json
json = System.Text.Json.JsonSerializer.Serialize(jsonParsed, new JsonSerializerOptions {WriteIndented=true});
Related
I'm trying to parse a JSON response that includes something I'm not quite familiar with, nor have I seen in the wild that often.
Inside one of the JSON objects, there is a dynamically named JSON object.
In this example, there is a JSON object inside "bugs" named "12345" which correlates to a bug number.
{
"bugs" : {
"12345" : {
"comments" : [
{
"id" : 1,
"text" : "Description 1"
},
{
"id" : 2,
"text" : "Description 2"
}
]
}
}
}
What I'm curious about is: What would be the most effective way to parse a dynamically-named JSON object like this?
Given some JSON Utility tools like
http://jsonutils.com/
http://json2csharp.com/
They will take a JSON response like the one above and morph it into classes like the following respectfully:
jsonutils
public class Comment
{
public int id { get; set; }
public string text { get; set; }
}
public class 12345
{
public IList<Comment> comments { get; set; }
}
public class Bugs
{
public 12345 12345 { get; set; }
}
public class Root
{
public Bugs bugs { get; set; }
}
json2charp
public class Comment
{
public int id { get; set; }
public string text { get; set; }
}
public class __invalid_type__12345
{
public List<Comment> comments { get; set; }
}
public class Bugs
{
public __invalid_type__12345 __invalid_name__12345 { get; set; }
}
public class RootObject
{
public Bugs bugs { get; set; }
}
The problem about this is that it generates a class with a dynamic name. Thus subsequent queries with other identifiers to this API would result in a failure because the name does not match up nor would a generated [JsonProperty("")] as it would contain the dynamic class name as per the generated examples above.
Although the JSON is valid, this seems to be a limitation with JSON that is formatted this way. Unfortunately I do not have any control on this JSON API, so I'm curious what the best way to approach this problem would be?
Try Json.NET, available as a Nuget package (Newtonsoft.Json) or from http://www.newtonsoft.com/json.
Json.NET can perform class-based serialization/deserialization such as you show. It also provides a generic JObject and JToken classes for cases where the format of the Json is not known or not fixed at dev time.
Here's an example loading a json object from a file.
// load file into a JObject
JObject document;
using (var fileStream = File.OpenRead(someFilePath))
using (var streamReader = new StreamReader(fileStream))
using (var jsonReader = new JsonTextReader(streamReader))
document = JObject.Load(jsonReader);
// read the JObject
var bugs = (JObject) document["bugs"];
foreach (var bugEntry in bugs)
{
var bugID = bugEntry.Key;
var bugData = (JObject) bugEntry.Value;
var comments = (JArray) bugData["comments"];
foreach (JObject comment in comments)
Debug.Print(comment["text"]);
}
Newtonsoft.Json JsonConvert can parse it as a Dictionary<String, Comments> provided with appropriate model classes:
public class Comment
{
public int id { get; set; }
public string text { get; set; }
}
public class Comments
{
public List<Comment> comments { get; set; }
}
public class RootObject
{
public Dictionary<String, Comments> bugs { get; set; }
}
That can be checked with:
var json = "{\r\n \"bugs\" : {\r\n \"12345\" : {\r\n \"comments\" : [\r\n {\r\n \"id\" : 1,\r\n \"text\" : \"Description 1\"\r\n },\r\n {\r\n \"id\" : 2,\r\n \"text\" : \"Description 2\"\r\n }\r\n ]\r\n }\r\n }\r\n}";
Console.WriteLine(json);
var obj = JsonConvert.DeserializeObject<RootObject>(json);
Console.WriteLine(obj.bugs["12345"].comments.First().text);
i want to pass following json as an reference in my console application in c#
{"val1":["dfgdsfgdfgsdf"],"val2":258915,"val3":"PPaaaA","val4":null,
"valJSON":"[{\"TypeID\":\"Z_FI_MDG\",\"SeverityCode\":\"3\",\"Note\":\"\\\"zczczca \\\\\\\"leading zero\\\\\\\". \\\\\\\\r\\\\\\\\n•YYY: Institution\"}]"}
I am doing following , but it is not working
JsonSerializer serializer = new JsonSerializer();
dynamic item = serializer.Deserialize<object>("
{"val1":["dfgdsfgdfgsdf"],"val2":258915,"val3":"PPaaaA","val4":null,
"valJSON":"[{\"TypeID\":\"Z_FI_MDG\",\"SeverityCode\":\"3\",\"Note\":\"\\\"zczczca \\\\\\\"leading zero\\\\\\\". \\\\\\\\r\\\\\\\\n•YYY: Institution\"}]"}
");
any other way i can pass this to function ?
to simplyfy
when i try to assign this to string it gives error can anyon hlp me
You should remove object type from function call:
JsonSerializer serializer = new JsonSerializer();
dynamic item = serializer.Deserialize("...");
I would use Newtonsoft's solution, if it's possible, i never regreted.
In your case, i'd use:
string json = #"{
"val1": [
"dfgdsfgdfgsdf"
],
"val2": 258915,
"val3": "PPaaaA",
"val4": null,
"valJSON": "[{\"TypeID\":\"Z_FI_MDG\",\"SeverityCode\":\"3\",\"Note\":\"\\\"zczczca \\\\\\\"leading zero\\\\\\\". \\\\\\\\r\\\\\\\\n•YYY: Institution\"}]"
}"
dynamic rss = JObject.Parse(json);
And then accessing values from it like:
var val2 = rss.val2;
I'm not sure if that's what you was looking for, but i tried...
Read more: http://www.newtonsoft.com/json/help/html/QueryJson.htm
Then, if you want more how to "install" newtonsoft: How to install JSON.NET using NuGet?
If you want to parse Json to the exact class you can try this
RootObject item = JsonConvert.DeserializeObject<RootObject>(File.ReadAllText(#"D:\file.txt"));
public class RootObject
{
public List<string> val1 { get; set; }
public int val2 { get; set; }
public string val3 { get; set; }
public object val4 { get; set; }
public string valJSON { get; set; }
}
The following is my json string:
string json = #"{
'?xml' : {
'#version' : '1.0',
'#encoding' : 'UTF-8'
},
'DataFeed' : {
'#FeedName' : 'AdminData',
'Issuer' : {
'id' : '95',
'name' : 'Apple',
'symbol' : 'AAPL'
}
}
}";
When I try to do the following LINQ query:
JObject feed = JObject.Parse(json);
var compInfo = feed["DataFeed"]["Issuer"]
.Select(c => c["name"]);
I get the following error:
`Cannot access child value on Newtonsoft.Json.Linq.JProperty.`
However, the following works fine:
var test1 = feed["DataFeed"]["Issuer"]["name"];
Any idea why I can't use LINQ on this json string?
Think about what your JSON is. You're selecting from a dictionary so the result in the LINQ is the property. You're trying to then access "name" on a property which doesn't make sense which gives you the error.
You already have the working code:
var test1 = feed["DataFeed"]["Issuer"]["name"];
You can get the value you want using two methods:
Method 1:
First you need a cast from JToken to a JObject since the value of 'Issuer' is an object:
var compInfo = (JObject)feed["DataFeed"]["Issuer"];
Then loop through all the properties to find the one with the name "Name" then get its value as a string:
var str = compInfo.Properties().First(x => x.Name == "name").ToObject<string>();
// str will contain the value 'Apple'.
Method 2:
You can also deserialize the JSON into an object that is easier to handle. To do that first you'll need to create a .net object "equivalent" of your JSON . You can use Visual Studio to generate these for you from the Edit menu -> Paste Special -> Paste JSON as classes or use a website like JsonUtils.com
public class Xml
{
[JsonProperty("#version")]
public string Version { get; set; }
[JsonProperty("#encoding")]
public string Encoding { get; set; }
}
public class Issuer
{
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("symbol")]
public string Symbol { get; set; }
}
public class DataFeed
{
[JsonProperty("#FeedName")]
public string FeedName { get; set; }
[JsonProperty("Issuer")]
public Issuer Issuer { get; set; }
}
public class RootJsonObject
{
[JsonProperty("?xml")]
public Xml Xml { get; set; }
[JsonProperty("DataFeed")]
public DataFeed DataFeed { get; set; }
}
Then all you have to do to get the Issuer name is this:
var feed = JsonConvert.DeserializeObject<RootJsonObject>(json);
var issuer = feed.DataFeed.Issuer.Name;
i'm working with Vk.com api, in particular with this json string:
{
"response":
[338775,
{"aid":108787020,
"owner_id":2373452,
"artist":" Moby",
"title":"Flowers",
"duration":208,
"url":"https:\/\/cs1-50v4.vk-cdn.net\/p3\/c762273870cc49.mp3?extra=t9I-RMkSlAHkhe8JtOUUZBTZqkFVE9MJ_Q-TPmOhxPHTfHazQWEYBf4LqrOY64xLX9AuzaKwvLo4PECSFiHyWM53WMDWVcBAZVT5jlIbZ9X8ag","lyrics_id":"6060508",
"genre":22}
]
}
I have a class for parsing data:
public class AlbumResponse
{
[JsonProperty("artist")]
public string artist { get; set; }
[JsonProperty("title")]
public string title { get; set; }
[JsonProperty("duration")]
public string duration { get; set; }
[JsonProperty("url")]
public string url { get; set; }
}
And List for deserialization:
public class VkAlbum
{
public List<AlbumResponse> response { get; set; }
}
Than I use
var album = JsonConvert.DeserializeObject<VkAlbum>(responseText);
BUT it doesn't work (A first chance exception of type 'Newtonsoft.Json.JsonSerializationException') because of "338775" after "response".
So how can I deserialize it without using
public List<object> response { get; set; }
instead of my AlbumResponse class?
A primitive JSON sanitation for your disposal. Not the most elegant code, but i'm sure you can take it from here.
responseText = Regex.Replace(responseText, "[\t|\r\n]", "");
if (responseText.IndexOf("response\": [") != -1)
{
int start = responseText.IndexOf('[') + 1;
int end = responseText.IndexOf(',', start);
responseText = responseText.Substring(0, start) + responseText.Substring(end + 1);
}
var album = JsonConvert.DeserializeObject<VkAlbum>(responseText);
technically json response is not equivalent to C# List<AlbumResponse>. JSON array allows mixed types so essentially it can contains numbers and other nested objects, in your case AlbumResponse.
you can avoid exception by using List<object> and checking it's first element if it's number, if it is, ignore or do whatever you want to do and typecast 2nd element in list to AlbumResponse.
e.g.
var res = response [1] as AlbumResponse;
if(res!=null)
{
// do something interesting...
I have JSON like this:
{
'surveys': [
{
'title': 'first',
'id': 100,
},
{
'title': 'second',
'id': 101,
},
{
'title': 'third',
'id': 102,
},
]
}
I want to have the output like this:
title: first
title: second
title: third
and my program in C# is like this:
WebClient client = new WebClient();
var json = client.DownloadString("http://www.test.com/api/surveys/?api_key=123");
Debug.WriteLine(json); //write all data from json
//add
var example = JsonConvert.DeserializeObject<Example>(json);
Debug.WriteLine(example.Data.Length);
class Example
{
public surveys[] Data { get; set; }
}
class surveys
{
public string title { get; set; }
public int id { get; set; }
}
I get this error:
Thrown: "Object reference not set to an instance of an object." (System.NullReferenceException) Exception Message = "Object reference not set to an instance of an object.", Exception Type = "System.NullReferenceException", Exception WinRT Data = ""
at this line: Debug.WriteLine(example.Data.Length);
where is the problem?
One problem I see is that your outer class has a property named Data, which is an array of 'surveys' objects, but your Json has a list of 'surverys' objects under the property 'surveys'. Hence the 'Data' property is never populated.
Consider the following C# class structure:
class Example
{
public survey[] surveys{ get; set; }//Data renames to surveys
}
class survey //Singular
{
public string title { get; set; }
public int id { get; set; }
}
Why can't you do so?:
JObject data = JObject.Parse(json);
foreach (var survey in data["surveys"].Children())
{
Debug.WriteLine("title: " + survey["title"]);
}
You need to use JSON.Net and use the class JsonConvert and the method DeserializeObject<T>.
If you run this:
JsonConvert.DeserializeObject<JObject>();
Then you will get back a list of de-serialized JObject objects.
Use, NuGet to download the package. I think it is called JSON.net.
Here is the weblink
WebClient client = new WebClient();
var json = client.DownloadString("http://www.test.com/api/surveys/?api_key=123");
Debug.WriteLine(json); //write all data from json
//add
var example = JsonConvert.DeserializeObject<Survey>(json);
Debug.WriteLine(example.length); // this could be count() instead.
class Survey
{
public string title { get; set; }
public int id { get; set; }
}
This should work!
Use json2csharp to generate c# classes from json.
You will also need to use Json.NET.
public class Survey
{
public string title { get; set; }
public int id { get; set; }
}
public class RootObject
{
public List<Survey> surveys { get; set; }
}
Then you can do:
var client = new WebClient();
string json = client.DownloadString(some_url);
RootObject root = JsonConvert.DeserializeObject<RootObject>(json);
foreach (Survey s in root.surveys)
{
// Do something with your survey
}
Don't forget to use Newtonsoft.Json namespace once you add a reference to it within your project.
using Newtonsoft.Json;
Edit: I have tested it using:
string json = "{'surveys': [{'title': 'first','id': 100,},{'title': 'second','id': 101,},{'title': 'third','id': 102,},]}";
instead of using the WebClient, and it works.