Deserialize json with c# with random root names - c#

I have a json file which has random names in roots but same structure in child elements. I would like to get all the child elements in an array or a list.
Sample json file :
{
"-LeHl495vL6vh-8CaLbD":{
"apiKey":"sr-tr-137-beea04e44cb452ba0da0ca090b7e61b4ec6ffc69"
},
"-LeHl6jrhUEMb7slZcpB":{
"apiKey":"sr-tr-137-aef7a23095c0c7baef1ef681bdd8bf9756ac2a17"
}
}
I have tried these classes but could not do it.
public class RequestedReport
{
public Dictionary<string, List<ReportData>> ReportDatas { get; set; }
}
public class ReportData
{
public string apiKey { get; set; }
}
So my expected output from deserialization is like List which contains all the apiKeys in json file.
Thanks in advance.

It looks to me like your JSON represents a Dictionary<string, ReportData> directly. There's no wrapper object, and no lists involved. If you deserialize your JSON to that type, it should be fine. Here's a complete example:
using System;
using System.Collections.Generic;
using System.IO;
using Newtonsoft.Json;
class Program
{
static void Main()
{
var json = File.ReadAllText("test.json");
var reports = JsonConvert.DeserializeObject<Dictionary<string, ReportData>>(json);
foreach (var pair in reports)
{
Console.WriteLine($"{pair.Key}: {pair.Value.ApiKey}");
}
}
}
public class ReportData
{
[JsonProperty("apiKey")]
public string ApiKey { get; set; }
}
If you just want the list of API keys, and you don't care about the field names associated with them, you can use:
var apiKeys = reports.Values.Select(x => x.ApiKey).ToList();

Related

How to deserialize json with incorrect repetitive structure

Getting results back from Shopify's graphql which it not in a standard structure to be able to deserialize simply.
Here's the result, but note the list of item1, item2, etc which can be from 1 to 100 items returned and this is the part I'm not sure how to deserialize and is my main question. Specifically, to a strongly typed List<Item> collection of items such that I can they query for any UserErrors, i.e. something like: lstItems.Any(l => l.UserErrors.Any()).
The second issue is that data will not always have these contents...other GraphQL queries will have different responses. Perhaps in this case, I should rename data in the string to another class name that will have these contents, then deserialize?
{
"data":{
"item1":{
"userErrors":[
]
},
"item2":{
"userErrors":[
]
}
},
"extensions":{
...
}
}
Here's what QuickType comes up with, but again, it assumes a discrete list of Items:
namespace QuickType
{
using System;
using System.Collections.Generic;
using System.Globalization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
public partial class InventoryUpdateResult
{
[JsonProperty("data")]
public Data Data { get; set; }
[JsonProperty("extensions")]
public Extensions Extensions { get; set; }
}
public partial class Data
{
[JsonProperty("item1")]
public Item Item1 { get; set; }
[JsonProperty("item2")]
public Item Item2 { get; set; }
}
public partial class Item
{
[JsonProperty("userErrors")]
public UserError[] UserErrors { get; set; }
}
public partial class UserError
{
[JsonProperty("field")]
public string[] Field { get; set; }
[JsonProperty("message")]
public string Message { get; set; }
}
public partial class Extensions
{
....
}
}
Thanks #Charlieface for pointing me in the right direction. Here's what I ultimately did. The other part I was trying to figure out, which I didn't know and articulate at the time of writing the question, was how to separate out the data portion of the response, which had this issue from the extensions portion, which is structured properly and can be simply deserialized to a class.
So to split out the data portion, you parse the string to a JObject
Then deserialize just that portion to the Dictionary as suggested
Then you can iterate through the Dictionary to get all the standard class objects and do as you with with them (add them to their own list, etc.)
code:
var jsonObject = JObject.Parse(response);
Dictionary<string, InventoryUpdateResult> dicRawResults;
var data = (JObject)jsonObject["data"];
if (data != null)
{
dicRawResults = JsonConvert.DeserializeObject<Dictionary<string, InventoryUpdateResult>>(data.ToString());
foreach(var result in dicRawResults)
{
InventoryUpdateResult inventoryUpdateResult = result.Value;
}
}
Then I extracted the extensions portion and converted that to the class object as such:
jsonObject = JObject.Parse(shopifyResponse.Value);
var jExtension = (JObject)jsonObject["extensions"];
if (jExtension != null)
{
queryCost = jExtension.ToObject<GraphExtensions>();
.....
}

How to deserialize a xml string to a set of C# classes without having to declare a lot properties just for xml attributes?

I have the xml below and I am wondering how can it be deserialized to a set of classes without having to add tons of fields (to those classes) just for the sake of representing the different xml attributes (and their respective values).
I thought I could have something which support declarative xml attributes as .NET attributes on top properties that define xml elements.
<y:input xmlns:y='http://www.stuff.com/blahblah/42'>
<y:datas>
<y:instance yclass='Report' yid="report">
<language yid='LANG_fr'/>
<threshold>0.8</threshold>
<typePeriod>predefinedPeriod</typePeriod>
<interval>month</interval>
<valuePeriod>April</valuePeriod>
<fund yclass="Fund">
<name>K</name>
<performance yclass="Performance">
<typeValue>percent</typeValue>
<value>-0.05</value>
</performance>
[... lot of other fields ...]
</fund>
</y:instance>
</y:datas>
</y:input>
You should be able to use ExpandoObject (part of System.Dynamic).
I tried a quick solution myself and was able to parse that xml successfully to a dynamic object.
What you need to do is:
Parse the string data to XDocument so you have an xml document object.
var doc = XDocument.Parse(xmlData);
I then converted the doc to a json string, you don't need to do this but it was the quickest way for me to test if this will work.
(For this I needed to add the Newtonsoft.Json NuGet package.)
string jsonText = JsonConvert.SerializeXNode(doc);
Then lastly I deserilzed the object like this:
dynamic dyn = JsonConvert.DeserializeObject<ExpandoObject>(jsonText);
I like using xml linq along with a nested dictionary :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
XNamespace yNs = doc.Root.GetNamespaceOfPrefix("y");
Datas data = doc.Descendants(yNs + "datas").Select(x => new Datas() {
instances = x.Descendants(yNs + "instance").Select(y => new Instance() {
instance = (string)y.Attribute("yid"),
language = (string)y.Element("language").Attribute("yid"),
threshold = (decimal)y.Element("threshold"),
typePeriod = (string)y.Element("typePeriod"),
interval = (string)y.Element("interval"),
valuePeriod = (string)y.Element("valuePeriod"),
fund = y.Elements("fund").Select(z => new Fund() {
fields = z.Elements().GroupBy(a => a.Name.LocalName, b => b.Elements()
.GroupBy(c => c.Name.LocalName, d => (string)d)
.ToDictionary(c => c.Key, d => d.FirstOrDefault()))
.ToDictionary(a => a.Key, b => b.FirstOrDefault())
}).FirstOrDefault()
}).ToList()
}).FirstOrDefault();
}
}
public class Datas
{
public List<Instance> instances { get; set; }
}
public class Instance
{
public string instance { get; set; }
public string language { get; set; }
public decimal threshold { get; set; }
public string typePeriod { get; set; }
public string interval { get; set; }
public string valuePeriod { get; set; }
public Fund fund { get; set; }
}
public class Fund
{
public Dictionary<string, Dictionary<string,string>> fields { get; set; }
}
}

C# JSON deserialize same object that acts like an array without being an array

I feel like I'm making this much harder than it needs to be.
In C# using Netwonsoft JSON Compact with external data. Trying to figure out how to deserialize/parse data that looks like
{"http":{"0":{"title":"arbitrary","value":"arbitrary"},"1":{"title":"arbitrary","value":"arbitrary"}},"sip":{"1003":{"title":"arbitrary","value":"none"}}}
It's essentially an array of notifications and the ID -- "0", "1", and "1003" in the above examples is an arbitrary value and appears to have a valid range of 0 and roughly 65535.
But it's not formatted as an array (or I wouldn't be here) -- need help figuring out how to deserialize the value object while essentially ignoring the string identifier.
Thanks in advance
You can't easily deserialize it as an array, but you can deserialize it to a dictionary with integer keys. I don't know about Json.NET Compact, but this works fine with regular Json.NET:
using System;
using System.Collections.Generic;
using System.IO;
using Newtonsoft.Json;
class Root
{
public Dictionary<int, Property> Http { get; set; }
public Dictionary<int, Property> Sip { get; set; }
}
class Property
{
public string Title { get; set; }
public string Value { get; set; }
}
class Test
{
static void Main()
{
string json = File.ReadAllText("test.json");
var root = JsonConvert.DeserializeObject<Root>(json);
foreach (var entry in root.Http)
{
Console.WriteLine($"{entry.Key}: {entry.Value.Title}/{entry.Value.Value}");
}
}
}
If you really need the properties as arrays, I'd suggest having two separate classes: one for the JSON representation, and then another for real usage. For example:
class RootJson
{
public Dictionary<int, Property> Http { get; set; }
public Dictionary<int, Property> Sip { get; set; }
}
class Root
{
// TODO: Control access more :)
public Property[] Http { get; set; }
public Property[] Sip { get; set; }
}
Then:
var rootJson = ...;
var root = new Root
{
Http = rootJson.Http.Values.ToArray(),
Sip = rootJson.Sip.Values.ToArray(),
};
If you can't change the structure of the JSON, you can always do something like this. The dynamic type figures out what to do on runtime.
dynamic d = JsonConvert.DeserializeObject("{'http':{'0':{'title':'arbitrary','value':'arbitrary'},'1':{'title':'arbitrary','value':'arbitrary'}},'sip':{'1003':{'title':'arbitrary','value':'none'}}}");
Console.WriteLine(d.http["0"].title); // arbitrary
foreach(var prop in d.http) {
Console.WriteLine(prop);
}
foreach(var prop in d.sip) {
Console.WriteLine(prop);
}
Final output:
arbitrary
"0": {
"title": "arbitrary",
"value": "arbitrary"
}
"1": {
"title": "arbitrary",
"value": "arbitrary"
}
"1003": {
"title": "arbitrary",
"value": "none"
}

Mapping JSON objects with incremental names to C# models

What is the best way to map a JSON object that has a structure whereby it contains a list of objects whose names are dynamically created through incrementation?
e.g.
{"data":
{
"object-0":[{"id":"1","name":"John"},{"id":"2","name":"Mary"}],
"object-1":[{"id":"3","name":"Gary"},{"id":"4","name":"Mark"}]
}
}
Assuming you've got a class like
public class User
{
public int Id { get; set; }
public string Name { get; set; }
}
You could deserialize this into a Dictionary<string, IEnumerable<User>> like so
Dictionary<string, IEnumerable<User>> values =
JsonConvert.DeserializeObject<Dictionary<string, IEnumerable<User>>>(json);
This also assumes the use of json.net
You can use Json.NET library to transform any JSON string to arbitrary dynamic object in .NET. This should do:
dynamic jsonObject = JsonConvert.DeserializeObject(jsonString);
In your case I suppose you need object-0, object-1 etc in a list/array (since they are incrementally generated by the looks of it) and not as typed properties as such, in which case you can trivially transform the obtained dynamic object to whatever you want. For an e.g.
public class User
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Data
{
public Dictionary<string, List<User>> Objects { get; set; }
}
string jsonString = '...';
dynamic jsonObject = JsonConvert.DeserializeObject(jsonString);
// could have made use of LINQ to shorten this bit of code
// but unfortunately dynamic doesn't play well with extension methods
var data = new Data { Objects = new Dictionary<string, List<User>>() };
foreach (var obj in jsonObject.data)
data.Objects[obj.Name] = obj.Value.ToObject<List<User>>();
// now you have everything in `data` instance.
To replicate the exact json structure, you can have a root class to hold the data. Something like:
class Root { public Data data { get; set; } }
var root = new Root { data = data };
If you need the entire user objects in one flat structure, you can flatten it too:
var users = data.Objects.SelectMany(kv => kv.Value);

C# JSON deserializing to Custom Class

I would like to deserialize a JSON object like this:
[{"Response":"OK","UUID":"89172"},{"Response":"OK","UUID":"10304"}]
into a custom class where it has variables storing Response and UUID. However I would want to deserialize multiple data response such as above example. It will be great if I can use the method ForEach such that I can pop the data out accordingly. Can anyone advise? Many Thanks!
write this class
public class MyClass
{
public string Response { get; set; }
public string UUID { get; set; }
}
then you can deserialize it using the library newtonsoft.json
string jsonString = "[{"Response":"OK","UUID":"89172"},{"Response":"OK","UUID":"10304"}]";
...
...
var myListOfItems= JsonConvert.DeserializeObject<List<MyClass>>(jsonString);
foreach(var item in myListOfItems)
{
....
}
FULL CODE IN CONSOLE APPLICATION
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Newtonsoft.Json;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string jsonString = "[{'Response':'OK','UUID':'89172'},{'Response':'OK','UUID':'10304'}]";
var items= JsonConvert.DeserializeObject<List<MyClass>>(jsonString);
foreach (var item in items)
{
Console.WriteLine("UUUID: "+item.UUID);
Console.WriteLine("Response: " + item.Response);
Console.WriteLine();
}
Console.ReadKey();
}
}
public class MyClass
{
public string Response { get; set; }
public string UUID { get; set; }
}
}
I would use Json.Net for that.
Have a look at Json.Net help in the "Serializing and Deserializing JSON" section.
There they show you how to deserialize the json-string into an object.
You will need Newtonsoft.Json library for this to work:
public class A
{
public string Response { get; set; }
public string UUID { get; set; }
}
static void Main(string[] args)
{
var json = "[{\"Response\":\"OK\",\"UUID\":\"89172\"}, \"Response\":\"OK\",\"UUID\":\"10304\"}]";
var result = JsonConvert.DeserializeObject<IEnumerable<A>>(json);
foreach (var a in result)
Console.WriteLine("Response: {0} UUID: {1}", a.Response, a.UUID);
Console.ReadKey();
}
I've finally resolved this problem thanks with the help of #Newton Sheikh. Thank you first of all.
First I created a class (Student)
public class Student
{
public string Response { get; set; }
public string UUID { get; set; }
}
Then I imported the JSON.NET and created a function:
public List<Student> ReturnAllStudentsList()
{
string jsonString = "[{'Response':'OK','UUID':'89172'},{'Response':'OK','UUID':'10304'}]";
List<Student> Students = new List<Student>(); //Creates a list of custom Type: Student
var result = JsonConvert.DeserializeObject<List<Student>>(jsonString);
foreach (var student in result)
{
Students.Add(student);
}
return Students;
}
From this point, I have a list of Students. Then in my main program, I call this function:
private void button1_Click(object sender, EventArgs e)
{
List<Student> Students = ReturnAllStudentsList(); // Gets the list from JSON.
foreach(Student student in Students)
{
// Here I can access to each student for every loop cycle.
MessageBox.Show(student.Response);
}
}
Thank you #Newton Sheikh and others help! I hope this example code can help others too! Cheers.

Categories

Resources