c# How do I parse a non array array - c#

I need to parse a jsonfile that has a structure like this:
"number": {
"1": {
"branch": null,
"build": 1,
"files": [
[
"zip",
"client",
"4d96d6e8f1543c5fa1184f4771ce16e2"
],
[
"zip",
"src",
"fd397591148fac49a7d57aafdccac6a3"
],
[
"zip",
"server",
"d7e1df9a91ded33be81ee8226b027c2f"
],
[
"txt",
"changelog",
"df98aec1a868ce99532c64f246387d55"
]
],
"jobver": "1.3.2",
"mcversion": "1.1",
"modified": 1328269373.0,
"version": "1.3.2.01"
},
"2": {
"branch": null,
"build": 2,
"files": [
[
"zip",
"server",
"80fbd5d837a5867c2dd7b7967e3aa2a9"
],
[
"zip",
"client",
"0cedb5e9844e490f877b6cf04601f929"
],
[
"txt",
"changelog",
"87e9fba9322e9dbc2ea482a2c3edeec6"
],
[
"zip",
"src",
"292d5596879bd13c159a2afe571ec5eb"
]
],
"jobver": "1.3.2",
"mcversion": "1.1",
"modified": 1328613907.0,
"version": "1.3.2.2"
}
(The entire json file can be found here: http://files.minecraftforge.net/maven/net/minecraftforge/forge/json)
I have figure out the internals, in the "1" and the externals that leads to this code part, however using the Json.NET library I can't figure out how to deal with the "1" and "2"s without writing a seperate class for each. I have over 1000 of these to parse trough, so I need some way that can do it relatively simple.
My current class for parsing looks something like this:
public class forgemaven
{
public string homepage { get; set; }
public string name { get; set; }
public List<Number> number { get; set; }
public string webpath { get; set; }
}
public class Number
{
public string branch { get; set; }
public int build { get; set; }
public List<String> files { get; set; }
public string jobver { get; set; }
public string mcversion { get; set; }
public string modified { get; set; }
public string version { get; set; }
}
Note: I removed some of the things, like the first 1000 lines of version/build, since they aren't needed and json.net seems fine with that.
I have tried parsing it with http://json2csharp.com/ sadly that crashes my webbrowser. I also tried the desktop version of it, but that give me almost a MB of classes, which again isn't optimal, since new builds are constantly added to this file, so I would have to change my structure all the time, and it would be horrible to use the data from here.
So for my question: How do I do this in a maintainable way?

Your problem is that {"1" : something, "2" ; something} is not a json array, it's a json map.
In .net, you will want to deserialize that to a Dictionary<int,TObject>. Then you can process it afterwards if it really should be a `List' or an array, but you can't do that while deserializing: you got bad json in the first place, you have to deal with it.
Here is a fiddle demonstrating the thing (with the json you gave and your own classes only very slightly modified: the files property is a List<List<string>> instead of a List<String>) using Json.Net : https://dotnetfiddle.net/feqFZd

You must replace
public List<Number> number { get; set; }
with
public Dictionary<int,Number> number { get; set; }

Related

I want to convert api json data to value c#

Hi i'm newbie in c# dev and i'm not good at english i try to get value from json but it gives error [https://www.tutorialsteacher.com/articles/convert-json-string-to-object-in-csharp]
If anyone can help me with simple code I would be very grateful.
{
"result": [{
"company": "Server",
"results": [{
"name": "Server-01",
"access": ["8.8.8.8:443", "1.1.1.1:443"],
"is_ok": "0"
}, {
"name": "Server-02",
"access": ["8.8.8.8:443", "1.1.1.1:443"],
"is_ok": "0"
}, {
"name": "Server-03",
"access": ["8.8.8.8:443", "1.1.1.1:443"],
"is_ok": "1"
}, {
"name": "Server-04",
"access": ["8.8.8.8:443", "1.1.1.1:443"],
"is_ok": "0"
}, {
"name": "Server-05",
"access": ["8.8.8.8:443", "1.1.1.1:443"],
"is_ok": "0"
}]
}]
}
C# can be different. Like .Net Framework or .Net Core / .Net, so next time please provide which framework do you use.
The are two common ways to deserialize JSON string - Json.NET (3rd party) or System.Text.Json (part of .Net).
For correct deserealization first of all you must provide valid models. But sometimes JSON properties violates C# Naming Conventions or they even can't be represented in code (e.g. property name with whitespace or "is_ok" from your JSON). To avoid this you must to use property attribute that connect your property in code and property in JSON. It's:
[JsonProperty("PropertyName")] for Json.NET
[JsonPropertyName("PropertyName")] for System.Text.Json
So, summing up the above, you must add models similar to this:
public class ResultWrapper
{
[JsonProperty("result")] //use one of it based on selected library
[JsonPropertyName("result")]
public List<Result> Result { get; set; }
}
public class Result
{
[JsonProperty("company")]
[JsonPropertyName("company")]
public string Company { get; set; }
[JsonProperty("results")]
[JsonPropertyName("results")]
public List<ResultItem> Results { get; set; }
}
public class ResultItem
{
[JsonProperty("name")]
[JsonPropertyName("name")]
public string Name { get; set; }
[JsonProperty("access")]
[JsonPropertyName("access")]
public List<string> Access { get; set; }
[JsonProperty("is_ok")]
[JsonPropertyName("is_ok")]
public string IsOk { get; set; }
}
and use one of next deserealization methods:
//Json.Net
var deserializedJsonNet = JsonConvert.DeserializeObject<ResultWrapper>(jsonFromQuestion);
//System.Text.Json
var deserializedSystemTextJson = JsonSerializer.Deserialize<ResultWrapper>(jsonFromQuestion);

Cross-referencing two parts of one JSON file in C#?

Newbie question. I have a semi-complex JSON file that I have parsed in my program. The relevant parts are below:
{
"version": "36",
"released": "20220223",
"samples": {
"Samp1": [
{
"code": "A01",
"status": "Optimal",
"bestBy": "20210918",
"expires": "20211018",
"elementKeys": {
"H": [
"Hydrogen-std1-slt4"
]
}
},
{
"code": "A02",
"status": "Optimal",
"bestBy": "20211201",
"expires": "20220501",
"elementKeys": {
"H": [
"Hydrogen-std1-slt5"
]
}
},
{
"code": "A03",
"status": "Optimal",
"bestBy": "20230201",
"expires": "20230801",
"elementKeys": {
"H": [
"Hydrogen-std1-slt6"
]
}
}
],
"Samp2": [ ...
"Samp3": [ ...
"Samp4": [ ...
},
"element": {
"Hydrogen-std1-slt4": {
"format": "1.0",
"position": 4,
"standard": "std1",
...
...
}
What I need to do is populate some windows form controls with data from this file. However, thanks to the odd architecture, I'm a little frustrated over how to populate the controls for "code", "status", "bestBy", etc contained within the "samples" arrays (Samp1, 2, 3, and 4).
Only some of the samples are relevant and the relevancy is defined by whether or not the name of the element key is found further below in the JSON file. So, using the example above, within "element", the object "Hydrogen-std1-slt4" is found in the body of the JSON file with its own key-value pairs. I would like the program to see that and recognize that "Hydrogen-std1-slt4" is also found within the object in the "Samp1" array with the code "A01", the status of "Optimal", the best-by date of "20210918", and that it expires on "20211018". Since it isn't found in any other place in "Samp1", the program can ignore the other objects.
What would be the easiest, most logical way to go about making a conditional for that?
try this code
var jsonParsed = JObject.Parse(json);
string[] elementKeys = ((JObject)jsonParsed["element"]).Properties().Select(x => x.Name).ToArray();
List<Samp> data= GetData(((JObject) jsonParsed["samples"]), elementKeys);
public List<Samp> GetData(JObject samples, string[] elementKeys)
{
List<Samp> result = new List<Samp>();
foreach (var element in samples.Properties())
foreach (var item in element.Value)
if ( item["elementKeys"]["H"]!=null
&& item["elementKeys"]["H"].ToObject<string[]>()
.Any(x => elementKeys.Contains(x)) )
result.Add(item.ToObject<Samp>());
return result;
}
classes
public class Samp
{
public string code { get; set; }
public string status { get; set; }
public string bestBy { get; set; }
public string expires { get; set; }
public ElementKeys elementKeys { get; set; }
}
public class ElementKeys
{
public List<string> H { get; set; }
}

C# Deserialize JSON array

I am having an issue deserializing and defining this JSON structure would be great to get some assistance. I have reverted this back to last known working position because I am just going off the rails here.
my JSON stucture is:
[{
"name": "Name1",
"description": "Description of this process",
"Location": "ANY",
"SubItems": [{
"name": "sub1",
"required": true,
"description": "This is a short description"
}, {
"name": "sub2",
"required": true,
"description": "This is a short description"
}, {
"name": "sub3",
"required": true,
"description": "This is a short description"
}],
"outputs": [{
"name": "out1",
"required": false
}, {
"name": "exit code",
"required": false
}]
}, {
"name": "Name2",
"description": "This is a short description",
"Location": "ANY",
"SubItems": [{
"name": "sub1",
"required": false,
"description": "This is a short description"
}]
}]
Here are my C# Json definitions that were last working.
public class JsonObject
{
[JsonProperty("name")]
public string ProcessName { get; set; }
[JsonProperty("description")]
public string ProcessDescription { get; set; }
[JsonProperty("Location")]
public string KnownLocation { get; set; }
}
I am only capturing a couple of definitions at the moment for testing.
Here is my deserializing object
var Object = JsonConvert.DeserializeObject <List<JsonObject>>(txt);
foreach (JsonObject JsonObject in Object)
{
Console.WriteLine("Name: " + JsonObject.ProcessName);
Console.WriteLine();
Console.WriteLine("Description: " +JsonObject.ProcessDescription);
Console.WriteLine();
}
So as I had stated, I can get at least the first 3 top-most level JSON elements in the output. The problem starts when I start trying to get the "SubItems" and "outputs"
I followed the structure of the below linked post and tried very hard to understand it, but after a while I realized that solution is not for this issue. I simply have a multi-dimentional array JSON object. Literally has a top tier, and 2 sub tiers
I attempted to try and do...
List<List<JsonObject>>Object = JsonConvert.DeserializeObject <List<List<JsonObject>>>(txt);
and tried to have 2 lists of the same with different names with 3 sets of JSON Definitions.
and implemented the tiered foreach loops, but then I wasn't able to access the definitions for the top most JSON, and nothing was writing for the actual elements for "SubItems"
What I need is to get to each object, really.
How to deserialize a json file with multidimensional array to convert it to object in c#
Related Issue
It is not a multi dimentional array. Just an array objects containing arrays.
So your model can be as follows
public class SubItem
{
public string Name { get; set; }
public bool Required { get; set; }
public string Description { get; set; }
}
public class Output
{
public string Name { get; set; }
public bool Required { get; set; }
}
public class JsonObject
{
public string Name { get; set; }
public string Description { get; set; }
public string Location { get; set; }
public List<SubItem> SubItems { get; set; }
public List<Output> Outputs { get; set; }
}
and you can deserialize as
var obj = JsonConvert.DeserializeObject<List<JsonObject>>(jsonstring);
PS: you can use JsonProperty to decorate that model as you do in question

How to deserialize json string in windows phone?

I just got my json response as a string.My json is given below,
"code": 0,
"message": "success",
"students": {
"details":{
"hjeke": {
"id": "257633000000070001",
"name": "hjeke",
"percentage": 36,
"type": "Good",
},
"Second": {
"id": "257633000000073001",
"name": "Second",
"percentage": 4,
"type": "bad",
}
}
}
Like hjeke and Second there are many key value pairs,how can i deserialize my json using Newtonsoft.json
Try to understand my solution in your previous question
How to deserialize json data in windows phone?
Your first JSON in that question was good and simple to use.
JSON, where field names are unique not convinient to deserialize. So, you got problems such as public class Hjeke and public class Second for each instance, when you use code generator.
Use JSON-structure with list of students:
"code": 0,
"message": "success",
"students": [
{
"id": "257633000000070001",
"name": "hjeke",
"percentage": 36,
"type": "Good",
},
{
"id": "257633000000073001",
"name": "Second",
"percentage": 4,
"type": "bad",
}]
is good and flexible structure. Using this, you don't need to parse not obvious fields like
"details":{
"hjeke": {
and so on.
And work with them using classes, from my previous answer. The main idea - you need list of objects. public List<StudentDetails> students. Then, all students objects deserialized in List, which is easy to use.
As everybody mentioned your json seems to be very unflexible, huh.
You can extract the data you are interested in.
So this is your model:
public class StudentDetails
{
public string id { get; set; }
public string name { get; set; }
public int percentage { get; set; }
public string type { get; set; }
}
And this is how you can extract it:
var jsonObj = JObject.Parse(str);
// get JSON result objects into a list
var results = jsonObj["students"]["details"].Children().Values();
// serialize JSON results into .NET objects
var details = new List<StudentDetails>();
foreach (JToken result in results)
{
var st = result.ToString();
var searchResult = JsonConvert.DeserializeObject<StudentDetails>(st);
details.Add(searchResult);
}
I'm using a newtonsoft.json library here.
Your Response string has some mistakes man, its not a valid json
just small modification to be done as below:
{
"code": 0,
"message": "success",
"students": {
"details": {
"hjeke": {
"id": "257633000000070001",
"name": "hjeke",
"percentage": 36,
"type": "Good"
},
"Second": {
"id": "257633000000073001",
"name": "Second",
"percentage": 4,
"type": "bad"
}
}
}
}
you can make out the difference
Now Follow these steps:
1.Go to this link Json to C#
2.place your Json string there and generate C# class object
3.Now create this class in your solution
4.Now deserialize As below
var DeserialisedObject = JsonConvert.DeserializeObject<Your Class>(YourJsonString);
First, create the classes:
public class Hjeke
{
public string id { get; set; }
public string name { get; set; }
public int percentage { get; set; }
public string type { get; set; }
}
public class Second
{
public string id { get; set; }
public string name { get; set; }
public int percentage { get; set; }
public string type { get; set; }
}
public class Details
{
public List<Hjeke> hjeke { get; set; }
public List<Second> Second { get; set; }
}
public class Students
{
public List<Details> details { get; set; }
}
public class RootObject
{
public int code { get; set; }
public string message { get; set; }
public List<Students> students { get; set; }
}
After that, use JSON.NET to deserialize:
var deserialized = JsonConvert.DeserializeObject<Class1>(YourStringHere);
Do you have any influence over the json response? Details should probably be a JSONArray in this case, not an object with a varying amount of properties, since I assume that's what you mean is the issue here.

Json modelling issue

I'm currently working with the following json structure and I'm not sure how to model it on my classes, since I've never run into this kind of structure before. Would appreciate any leads or help:
{ "messages": { "1": { "tid": "309", "status": "0", "timestamp": "1379795079", "uid": "1111111111", "txt": "sometext" }, "2": { "tid": "310", "status": "0", "timestamp": "1379795523", "uid": "2222222222", "txt": "sometext2" } }, "status": 1 }
The messages value objects are not a common json structure that i know of, I understand that these are objects, but I don't know how to map them with my classes.
I Use json2csharp, to model my objects for me. Consider the following json object:
{
"employees": [
{ "firstName":"John" , "lastName":"Doe" },
{ "firstName":"Anna" , "lastName":"Smith" },
{ "firstName":"Peter" , "lastName":"Jones" }]
}
I get these objects from the tool:
public class Employee
{
public string firstName { get; set; }
public string lastName { get; set; }
}
public class RootObject
{
public List<Employee> employees { get; set; }
}
Source: http://json2csharp.com/
Technically, your json object is a dictionary, associative array or even hash-table (select appropriate for your target language). Such a data structure is a perfectly reasonable thing to serialize.
However, that particular object would probably have been better serialized as something like:
{ "messages":
[
{ "tid": "309"
, "status": "0"
, "timestamp": "1379795079"
, "uid": "1111111111"
, "txt": "sometext"
}
,
{ "tid": "310"
, "status": "0"
, "timestamp": "1379795523"
, "uid": "2222222222"
, "txt": "sometext2" }
}
]
, "status": 1
}
(unless the sender wanted the option of sending the individual messages items out of order). That's certainly how I would represent it.
This is how I've solved it:
public class MessagesResponse
{
[JsonProperty("messages")]
public Dictionary Messages { get; set; }
[JsonProperty("status")]
public int Status { get; set; }
}
THanks to #rici, I've realized that the use of a dictionary would solve the problem

Categories