Howto C# DeserializeObject, where variable name is number? - c#

How do I Deserialize the following. The problem is that the variable name is a number. So how should MyClass be defined?
json_str:
{"23521952": {"b": [], "o": []}, "23521953": {"b": [], "o": []}}
class MyClass { //? };
var var = JsonConvert.DeserializeObject<MyClass>(json_str);

This sounds like the outer object is actually a dictionary:
using System.Collections.Generic;
using Newtonsoft.Json;
class Foo
{
// no clue what b+o look like from the question; modify to suit
public int[] b { get; set; }
public string[] o { get; set; }
}
static class P
{
static void Main()
{
var json = #"{""23521952"": {""b"": [], ""o"": []}, ""23521953"": {""b"": [], ""o"": []}}";
var obj = JsonConvert.DeserializeObject<Dictionary<string, Foo>>(json);
foreach(var pair in obj)
{
System.Console.WriteLine($"{pair.Key}, {pair.Value}");
}
}
}

You can use anonymous type deserialization for your data like this, without creating classes for properties of JSON. Hope it works.
var finalResult=JsonConvert.DeserializeAnonymousType(
json_str, // input
new
{
Id=
{
new
{
b=new[], o=new[]
}
}
}
);
foreach(var id in finalResult.Id)
{
console.write(id); // gives ids like 23521952
console.write(id.b[0]) // gives first elemnt in 'b' array
}

Related

Get the value of the Key from a Json Array

I have the below Json Array and I need to get the value of the key inside my "relation" object. How do I do that? The relation object has different set of key-value pair for each object in the array.
[
{
"data": {
"_hash": null,
"kind": "ENTITY",
"id": "test122",
"payload": {
"attributes": {
"bbl:27": false
},
"relations": {
"bbl:45": "P18",
"bbl:P18": "P562"
},
"type": [
"P185"
]
}
}
}
]
In above inside relations the keys are "bbl:45" and "bbl:P18". I need these values, in specific I need to extract 45 and P18, considering bbl remain constant inside relation object. how do i do it. There are multiple objects in the Jarray, I have shown only one.
I would mention, if you can change data format, consider doing so, having payload as part as a member proper name is highly unusual but you could do like this:
[Fact]
public void DynamicJsonHandlingTest()
{
var serialized = "[{\"data\":{\"_hash\":null,\"kind\":\"ENTITY\",\"id\":\"test122\",\"payload\":{\"attributes\":{\"bbl:27\":false},\"relations\":{\"bbl:45\":\"P18\",\"bbl:P18\":\"P562\"},\"type\":[\"P185\"]}}}]";
using var jDoc = JsonDocument.Parse(serialized);
var enumerator = jDoc.RootElement.EnumerateArray();
foreach(var JsonElement in enumerator)
{
var relationsElement = JsonElement.GetProperty("data").GetProperty("payload").GetProperty("relations");
foreach (var ele in relationsElement.EnumerateObject())
{
var sought = ele.Name.Split(":")[1];
//sought now cointains first 45 then P18
}
}
}
The following Code solves your problem.
using Newtonsoft.Json.Linq;
using System;
using System.Linq;
using Json.Net;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
string json = "{\"data\":{\"_hash\":null,\"kind\":\"ENTITY\",\"id\":\"test122\",\"payload\":{\"attributes\":{\"bbl:27\":false},\"relations\":{\"bbl:45\":\"P18\",\"bbl:P18\":\"P562\"},\"type\":[\"P185\"]}}}";
JObject jsonObject = JObject.Parse(json);
var results = jsonObject["data"]["payload"]["relations"];
foreach (var item in results)
{
string propName = ((JProperty)item).Name;
string requiredValue = propName.Split(':')[1];
Console.WriteLine($"Required: {requiredValue} !");
}
}
}
}
You should add some error handling when the property name does not contains :
For dynamic keys you can use dictionary:
public class Root
{
public Data data { get; set; }
}
public class Data
{
public Payload payload { get; set; }
}
public class Payload
{
public Dictionary<string, string> relations { get; set; }
}
var result = JsonConvert.DeserializeObject<List<Root>>(sourcejson);
And then next will contain all keys:
var keys = result
.Select(r => r.data)
.Select(r => r.payload)
.SelectMany(r => r.relations.Keys)
Or use the LINQ to JSON API:
var result = JsonConvert.DeserializeObject<JArray>(sourcejson);
var list = result
.Children()
.SelectMany(c => c["data"]["payload"]["relations"].Children<JProperty>())
.Select(p => p.Name)
.ToList(); // list is {"bbl:45", "bbl:P18"}
And then you can process the keys as you need - for example using Split(':') to turn "bbl:45" into array of "bbl" and `"45".

Deserializing JSON with numbers as field using JsonSerializer

I need to deserialize this weird JSON (image below). I've seen some deserialization hints using Dictionary<>, etc. but the problem is that "parameters" contains different data, then previous keys.
Can I somehow get it to work using JsonSerializer deserializator without doing foreach loops and other suspicious implementations? I do need data from "data" in my application.
Here's some of my code:
using var client = new WebClient();
var json = client.DownloadString(GetJsonString());
var invoicesData = JsonSerializer.Deserialize<JsonMyData>(json, options);
If using Newtonsoft is necessary I might start using it.
With Newtonsoft you can parse and access arbitrary JSON documents, even ones that can't reasonably be deserialized into a .NET object. So something like:
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
namespace ConsoleApp35
{
class Program
{
static void Main(string[] args)
{
var json = #"
{
""myData"" :
{
""0"" : { ""data"": { ""A"":1,""B"":2} },
""1"" : { ""data"": { ""A"":1,""B"":2} },
""2"" : { ""data"": { ""A"":1,""B"":2} },
""3"" : { ""data"": { ""A"":1,""B"":2} },
""parameters"" : { ""p"":""a""}
},
""status"":{ }
}";
var foo = JObject.Parse(json);
var a = foo["myData"]["1"]["data"];
Console.WriteLine(a);
Console.WriteLine("Hit any key to continue");
Console.ReadKey();
}
}
}
I think you should really consider using Newtonsoft.Json instead of default JsonDeserializer, it is much easier to use in such situations.
If you are interested in processing this without foreach loops and wanting to access the data in a list format, I would suggest using Dictionary for this. When you use dictionary, you can use Objects as values that would compensate for differences in numbers (0, 1, 2, ..) and words (parameters).
// Classes to Deserialize data we need.
public class MyObject
{
[JsonProperty("data")]
public Data Data { get; set; }
}
public class Data
{
public int A { get; set; }
public int B { get; set; }
}
Usage in Main
// Read in the JSON
var myData = JsonConvert.DeserializeObject<dynamic>(jsonString)["myData"];
// Convert To Dictionary
Dictionary<string, dynamic> dataAsObjects = myData.ToObject<Dictionary<string, dynamic>>();
string searchFor = "3";
dataAsObjects.TryGetValue(searchFor, out dynamic obj);
if (obj != null)
{
// Conversion to int and matching against searchFor is to ensure its a number.
int.TryParse(searchFor, out int result);
if (result == 0 && result.ToString().Equals(searchFor))
{
MyObject myObject = obj.ToObject<MyObject>();
Console.WriteLine($"A:{myObject.Data.A} - B:{myObject.Data.B}");
}
else if (result == 8 && result.ToString().Equals(searchFor))
{
// I am not clear on whats your parameters class look like.
MyParameters myParams = obj.ToObject<MyParameters>();
}
}
Output
A:1 - B:2
With this method you can either access the numbers or the parameters element.

Parse JSON Objects with unique strings as parents using JSON.Net

Let's say I have this example JSON:
"Test": {
"KIf42N7OJIke57Dj6dkh": {
"name": "test 1"
},
"xsQMe4WWMu19qdULspve": {
"name": "test 2"
}
}
I want to parse this into an Array of a custom class I have, which will be exampled below:
class Class1 {
public string Name { get; set; }
Class1(string name) {
Name = name;
}
}
How can I parse this using Json.NET's JObject.Parse?
You can achieve your goal with JPath query like this :
var myArray = JObject
.Parse(json)
.SelectTokens("$.Test..name")
.Values<string>()
.Select(s => new Class1(s))
.ToArray();
But probably not the best way to do it.
I personnaly prefere to create classes to represent the json structure and then apply transformations.
void Main()
{
var json = #"{""Test"": {
""KIf42N7OJIke57Dj6dkh"": {
""name"": ""test 1""
},
""xsQMe4WWMu19qdULspve"": {
""name"": ""test 2""
}
}
}";
var root = JsonConvert.DeserializeObject<Root>(json);
var array = root.Test.Select(i => i.Value).ToArray();
array.Dump();
}
public class Root
{
public Dictionary<string, Class1> Test { get; set; }
}
public class Class1
{
public string Name { get; set; }
public Class1(string name)
{
Name = name;
}
}
To begin with, your Json is missing starting/closing braces. The Json needs to have wrapping braces around the Test value.
{
'Test':
{
'KIf42N7OJIke57Dj6dkh': {'name': 'test 1'},
'xsQMe4WWMu19qdULspve': {'name': 'test 2'}
}
}
If you are missing it in the original Json, you could wrap the current input Json as following.
var correctedJson = $"{{{inputJsonString}}}";
If you want to parse the Json Objects to Array of Class1 without creating additional concrete data structures and using JPath Queries, you could use Anonymous Types for the purpose using the DeserializeAnonymousType Method proved by Json.Net. For example,
var sampleObject = new {Test = new Dictionary<string,Class1>()};
var data = JsonConvert.DeserializeAnonymousType(correctedJson,sampleObject);
var result = data.Test.Select(x=>x.Value).ToArray();
You could also achieve it using JPath Query or creating Concrete Data Structures as #Kalten as described in his answer.

How to iterate through JObject Properties via Foreach/LINQ

I have an established JObject object. Trying to loop through it to acquire a Key/value based on anothers Key/value (example of json below with code currently stuck on)
For a tad more detail - looking to loop through "value", get the "KeyID" based on "MailState"
definitely feel like I am missing the step of filtering by MailState/ColName apparently - I have searched through threads a bunch but if someone knows of one that answered this that i was unable to find i will happily pull this down/reference it
// JSON DATA
{
"odata.metadata": "https://..com/odata/$metadata#JCJMCDXes",
"value": [
{
"KeyID": "10379",
"MailCity": "Chicago",
"MailState": "IL"
},
{
"KeyID": "9846",
"MailCity": "Chicago",
"MailState": "IL"
},
{
"KeyID": "2234",
"MailCity": "Madison",
"MailState": "WI"
}]
}
// Current code example
// class in play
public class datastorage
{
public string ID { get; set; }
public string Col { get; set; }
}
public class listData
{
public string ColName {get;set;}
}
// getVPData is a string response from a call to an API
getVPData.Replace(System.Environment.NewLine, "");
JObject jobj = (JObject)Newtonsoft.Json.JsonConvert.DeserializeObject(getVPData);
List<datastorage> data = new List<datastorage>();
// Loop
foreach(var r in listData) // has distinct State abeviations so only 1 occurence
{
foreach (var j in jobj) // This the right path?
{
//add KeyID into ID
data.add(new datastorage
{
ID = ,//add KeyID into ID
Col = r.ColName
});
}
}
You can use Newtonsoft.Json library to parse and loop to the items of value
here is a sample code:
dynamic json = JsonConvert.DeserializeObject(getVPData);
foreach (dynamic item in json["value"])
{
//you can access the fields inside value.
var KeyID = item["KeyID"];
var MailCity = item["MailCity"];
var MailState = item["MailState"];
//just for showing...
Console.WriteLine("KeyID:{0}, MailCity:{1}, MailState:{2}", KeyID, MailCity, MailState);
}
Let me know if the snippet works.
Straightforward ways are:
using System;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace ConsoleApp7
{
internal class Program
{
private static void Main(string[] args)
{
var mailStates = new[] {"IL", "WI"};
var jObject = (JObject) JsonConvert.DeserializeObject(json);
var values = (JArray) jObject["value"];
// 1st way
foreach (var mailState in mailStates)
{
var key = values
.Where(v => mailState == v.SelectToken("MailState").Value<string>())
.Select(v => v.Value<string>("KeyID"))
.FirstOrDefault();
Console.WriteLine($"1st case: {mailState} - {key}");
}
/* 2nd way based on JSONPath
* api: https://www.newtonsoft.com/json/help/html/QueryJsonSelectTokenJsonPath.htm
* dox: https://support.smartbear.com/alertsite/docs/monitors/api/endpoint/jsonpath.html
* tester: https://jsonpath.curiousconcept.com/
*/
foreach (var mailState in mailStates)
{
var key = values.SelectTokens($"$[?(#.MailState == '{mailState}')].KeyID")
.Select(v => v.ToString())
.FirstOrDefault();
Console.WriteLine($"2nd case: {mailState} - {key}");
}
Console.ReadKey();
}
private static string json = #"
{
""odata.metadata"": ""https://cdxapiclient.palmercg.com/odata/$metadata#JCJMCDXes"",
""value"": [
{
""KeyID"": ""10379"",
""MailCity"": ""Chicago"",
""MailState"": ""IL""
},
{
""KeyID"": ""9846"",
""MailCity"": ""Chicago"",
""MailState"": ""IL""
},
{
""KeyID"": ""2234"",
""MailCity"": ""Madison"",
""MailState"": ""WI""
}]
}";
}
}

Unsure how to define a C# class to handle JSON with variable property names

I am calling a REST api that returns their data in the following format:
{
"facets": [
{
"M": 100
},
{
"F": 210
}
]
}
I am not sure how to define a C# class that maps to this JSON since the M/F property name could be anything. This is currently a facet for gender, but for something else like language it might be "English", "Spanish", "Japanese", etc. Ideally I would like something like a dictionary.
Where the keys can vary, use a dictionary to represent the object:
public class Criteria
{
public List<Dictionary<string, int>> facets { get; set; }
}
(If the dictionary value isn't always an int, use object instead.)
Fiddle: https://dotnetfiddle.net/IwyXby
This is how I use json.net to both serialize and deserialize:
public static bool SerializeStudentsFile(string fileStorageLoc)
{
var jsonStudents = JsonConvert.SerializeObject(StudentsList);
System.IO.File.WriteAllText(fileStorageLoc, jsonStudents);
return true;
}
public static List<Student> DeserializeStudentsFile()
{
List<Student> studentList;
if (!System.IO.File.Exists(STUDENTS_FILENAME))
{
var studentFile = System.IO.File.Create(STUDENTS_FILENAME);
studentFile.Close();
}
var studentContentsFile = System.IO.File.ReadAllText(STUDENTS_FILENAME);
var studentContentsFileDeserialized = JsonConvert.DeserializeObject<List<Student>>(studentContentsFile);
if (null != studentContentsFileDeserialized) return studentContentsFileDeserialized;
studentList = new List<Student>();
return studentList;
}

Categories

Resources