I am currently consuming JSON output from one source that contains an array and one that does not.
The one with an array is simple, as I can create a class that represents the object and the list of objects, then iterate through the list and get the properties for each object. In the source that does not have an array, however, it is throwing me for a loop.
I do not know how to iterate through this. It seems as if I would need to create separate classes for "abc" and "def" even though the properties of each class are the same. Is there a simple way to do this?
Example that does not contain an array:
{
"objectContainer": {
"count": 25,
"objects": {
"abc": {
"name": "object1",
"parent": "0",
"status": "0",
},
"def": {
"name": "object2",
"parent": "0",
"status": "0",
}
etc....
Thanks in advance for any assistance.
You could use inheritance to prevent repeating the properties for "abc" and "def" over and over again.
public class Base
{
public string name { get; set; }
public string parent { get; set; }
public string status { get; set; }
}
public class Abc : Base { }
public class Def : Base { }
public class Objects
{
public Abc abc { get; set; }
public Def def { get; set; }
}
public class ObjectContainer
{
public int count { get; set; }
public Objects objects { get; set; }
}
public class RootObject
{
public ObjectContainer objectContainer { get; set; }
}
Then using JSON.NET you can deserialize the string.
var root = JsonConvert.DeserializeObject<RootObject>( json );
The problem is you're going to have to change the code every time you get a new object in there (e.g. ghi).
Another option, particularly if you're going to have different object names showing up, would be to just parse the JSON serially yourself.
JsonTextReader reader = new JsonTextReader( new StringReader( json ) );
while( reader.Read() )
{
if( reader.Value != null )
{
Console.WriteLine( "Field: {0}, Value: {1}", reader.TokenType, reader.Value );
}
}
Obviously where it's writing output to the Console you'd have to examine the TokenType and Value and stuff those into an object.
Update
This is pretty ugly, but I was curious how I might parse this into the object structure. You'd need to change the receiving object definitions a bit.
public class Base
{
public string name { get; set; }
public string parent { get; set; }
public string status { get; set; }
}
public class Objects
{
public List<Base> bases { get; set; }
public Objects()
{
bases = new List<Base>();
}
}
public class ObjectContainer
{
public int count { get; set; }
public Objects objects { get; set; }
public ObjectContainer()
{
objects = new Objects();
}
}
public class RootObject
{
public ObjectContainer objectContainer { get; set; }
public RootObject()
{
objectContainer = new ObjectContainer();
}
}
Then you can parse into it using:
while( reader.Read() )
{
if( reader.Value != null )
{
switch( reader.Depth )
{
case 2:
if( reader.TokenType == JsonToken.PropertyName && reader.Value.ToString() == "count" )
{
reader.Read();
root.objectContainer.count = Convert.ToInt32( reader.Value );
}
break;
case 3:
newBase = new Base();
root.objectContainer.objects.bases.Add( newBase );
break;
case 4:
if( reader.TokenType == JsonToken.PropertyName && reader.Value.ToString() == "name" )
{
reader.Read();
newBase.name = reader.Value.ToString();
}
if( reader.TokenType == JsonToken.PropertyName && reader.Value.ToString() == "parent" )
{
reader.Read();
newBase.parent = reader.Value.ToString();
}
if( reader.TokenType == JsonToken.PropertyName && reader.Value.ToString() == "status" )
{
reader.Read();
newBase.status = reader.Value.ToString();
}
break;
}
}
}
Not the prettiest code in the world but as long as the structure of the JSON doesn't change you'll end up with a nice object model no matter how many child objects or what their names are.
Based on your JSON above, you would probably need to create classes for those objects. You can abstract some of it away with inheritance as well. If possible, it would make more sense for "objects" to be an array that way you don't need to create separate objects. The name, and implementation both suggest an array.
If you cannot change the structure of the JSON, have a look at the bottom of the page at http://json.org/ for different libraries. Some may be more helpful than others. Json.NET is the one I usually use and you may have better results using something like their JSonReader so you don't have to create an overly complex object structure.
You could use the excellent (and dynamic) JObject class from the JSON.NET library like this:
// example input
var json = #"{""objectContainer"": {
""count"": 25,
""objects"": {
""abc"": {
""name"": ""object1"",
""parent"": ""0"",
""status"": ""0"",
},
""def"": {
""name"": ""object2"",
""parent"": ""0"",
""status"": ""0"",
}
}}";
var obj = JsonConvert.DeserializeObject(json);
var objectContainer = ((JObject)obj)["objectContainer"];
var abc = objectContainer["objects"]["abc"];
Console.WriteLine(abc["name"]);
The output is:
output1
You could even use directly the JObject.Parse() method to load and parse just a JSON code portion (for example if you can extract only the abc part from the complete JSON string):
var abc = JObject.Parse(#"{""abc"": {
""name"": ""object1"",
""parent"": ""0"",
""status"": ""0"",
}}")["abc"];
Console.WriteLine(abc["name"]);
var abcd = JObject.Parse(#"{
""name"": ""object1"",
""parent"": ""0"",
""status"": ""0"",
}");
Console.WriteLine(abcd["name"]);
You could then assign the extracted values to your custom class.
Using the library and the JObject class you don't need to represent the JSON with a class. The downside is, that you don't have the type safety of the class and it's properties.
Update
You could iterate over the properties / objects without knowing their names:
var obj = JsonConvert.DeserializeObject(json);
var objectContainer = ((JObject)obj)["objectContainer"];
foreach (var o in objectContainer["objects"])
{
if (o is JProperty)
{
var op = ((JProperty)o);
Console.WriteLine("{0} - {1}", op.Name, op.Value);
}
}
The output is:
abc - {
"name": "object1",
"parent": "0",
"status": "0"
}
def - {
"name": "object2",
"parent": "0",
"status": "0"
}
Related
I have a JSON being received from a public API that follows the structure below.
[
{
"ID": "12345",
"company": [
{
"contract_ID": "abc5678",
"company": [
{
"company_name": "HelloWorld",
"company_logo": "HW",
"invested": "2000"
}
]
},
{
"contract_ID": "67891",
"company": [
{
"company_name": "GoodBye",
"company_logo": "GB",
"invested": "500"
}
]
},
{
"contract_ID": "32658",
"company": [
{
"company_name": "YesNo",
"company_logo": "YN",
"invested": "1500"
}
]
}
]
}
]
I've tried several different methods of parsing, whether it be JTokens/JArrays or various classes. Something like the following allows me to access the first group of values (company_name, company_logo, invested), but I cannot iterate through to find the other two.
//receiving the json data
var responseString = await response.Content.ReadAsStringAsync();
var fullJSON = JsonConvert.DeserializeObject(responseString);
Debug.Log(fullJSON);
//trying to parse it down to just the data I need
JToken token = JToken.Parse("{\"root\":" + responseString + "}");
Debug.Log(token);
JArray assets = (JArray)token.SelectToken("root[0].assets");
Debug.Log(assets);
JToken dig = JToken.Parse("{\"root\":" + assets + "}");
Debug.Log(dig);
JArray assetsNested = (JArray)dig.SelectToken("root[0].assets");
Debug.Log(assetsNested);
My goal is to extract the contract_ID and then the associated company_name, company_logo, and invested items. For example, abc5678, HelloWorld, HW, and 2000 would be one of the three datasets needed.
The easiest way to deserialize this properly and keep your code maintainable is to use concrete classes. For example:
public sealed class Company
{
[JsonProperty("contract_ID")]
public string ContractID { get; set; }
[JsonProperty("company")]
public List<CompanyDefinition> CompanyDefinitions { get; set; }
}
public sealed class CompanyDefinition
{
[JsonProperty("company_name")]
public string CompanyName { get; set; }
[JsonProperty("company_logo")]
public string CompanyLogo { get; set; }
[JsonProperty("invested")]
public string Invested { get; set; }
}
public sealed class RootCompany
{
[JsonProperty("ID")]
public string ID { get; set; }
[JsonProperty("company")]
public List<Company> Company { get; set; }
}
Then, you simply deserialize. For example, if you are pulling from a file you could do this:
using(var sr = new StreamReader(#"c:\path\to\json.json"))
using(var jtr = new JsonTextReader(sr))
{
var result = new JsonSerializer().Deserialize<RootCompany[]>(jtr);
foreach(var r in result)
{
Console.WriteLine($"Company ID: {r.ID}");
foreach(var c in r.Company)
{
Console.WriteLine($"ContractID: {c.ContractID}");
foreach(var d in c.CompanyDefinitions)
{
Console.WriteLine($"Name: {d.CompanyName}");
Console.WriteLine($"Invested: {d.Invested}");
Console.WriteLine($"Company Logo: {d.CompanyLogo}");
}
}
}
}
When something changes with your models, you won't have to dig through lines upon lines of hard-to-read token selection code. You just update your models.
I am trying to compare json value and based on that i want to update the existing value,for example, currently we have "value" : [r0] in json, i want to compare and if value : [r0] ,then update it to [r0,r1] but iam hiting error that it cannot compare and there is a cast issue, could someone suggest what could be done
public void updateJsonParameter(string file)
{
try
{
var list = new List<string> { "joe", "test" };
JArray array = new JArray(list);
var jobject = JObject.Parse(file);
var ringvalue = (string)jobject["properties"]["parameters"]["ringValue"]["value"]; // unable to case here and compare
jobject["properties"]["parameters"]["ringValue"]["value"] = array; // able to update value but i want to update after comparing the existing values
var result = JsonConvert.SerializeObject(jobject);
}
following is the json format
{
"properties": {
"displayName": "jayatestdefid",
"description": "test assignment through API",
"metadata": {
"assignedBy": "xyz#gmail.com"
},
"policyDefinitionId": "/providers/Microsoft.Management/managementgroups/MGTest/providers/Microsoft.Authorization/policyDefinitions/test",
"parameters": {
"ringValue": {
"value": ["r0"]
}
},
"enforcementMode": "DoNotEnforce",
}
}
jobject.properties.parameters.ringValue.value is an array ["r0"] with one element "r0". If you want to check if it's an array with one element and that element is "r0", do exactly that:
var ringvalue = jobject["properties"]["parameters"]["ringValue"]["value"];
if(ringvalue.length == 1 && ringvalue[0] == "r0")
jobject["properties"]["parameters"]["ringValue"]["value"] = array;
You could compare the ringvalue (which is an JArray) using JArray.DeepEquals and then replace if the comparison returns true. For example,
var list = new List<string> { "joe", "test" };
JArray array = new JArray(list);
JArray valueToCompare = new JArray(new[]{"r0"});
var ringvalue = (JArray)jobject["properties"]["parameters"]["ringValue"]["value"];
if(JArray.DeepEquals(ringvalue,valueToCompare))
{
jobject["properties"]["parameters"]["ringValue"]["value"] = array;
}
First, as Klaycon said in his answer, it's worth noting that your "value" is not a single string. In json, whenever you see [ and ] then you have a collection, or an array, or a list.
When I work with json strings, I always like to be able to convert them into a strongly typed object. There is a very handy online tool I use all the time: http://json2csharp.com/
I took your json string that you provided and pasted it into that website. Here is that your object(s) look like when converted into c# classes:
public class RootObject // You can name this whatever you want
{
public Properties properties { get; set; }
}
public class Metadata
{
public string assignedBy { get; set; }
}
public class RingValue
{
public List<string> value { get; set; }
}
public class Parameters
{
public RingValue ringValue { get; set; }
}
public class Properties
{
public string displayName { get; set; }
public string description { get; set; }
public Metadata metadata { get; set; }
public string policyDefinitionId { get; set; }
public Parameters parameters { get; set; }
public string enforcementMode { get; set; }
}
Now, we can easily do the logic you need as follows:
// This is your json string, escaped and turned into a single string:
string file = "{ \"properties\": { \"displayName\": \"jayatestdefid\", \"description\": \"test assignment through API\", \"metadata\": { \"assignedBy\": \"xyz#gmail.com\" }, \"policyDefinitionId\": \"/providers/Microsoft.Management/managementgroups/MGTest/providers/Microsoft.Authorization/policyDefinitions/test\", \"parameters\": { \"ringValue\": { \"value\": [\"r0\"] } }, \"enforcementMode\": \"DoNotEnforce\", }}";
// Convert your json string into an instance of the RootObject class
RootObject jobject = JsonConvert.DeserializeObject<RootObject>(file);
// Get a list of all the "values"
List<string> values = jobject.properties.parameters.ringValue.value;
// Loop over your colleciton of "value" and do your logic
for (int i = 0; i < values.Count; ++i)
{
if (values[i] == "r0")
{
values[i] = "r0,r1";
}
}
// And finally, turn your object back into a json string
var result = JsonConvert.SerializeObject(jobject);
And this is the final result:
{
"properties":{
"displayName":"jayatestdefid",
"description":"test assignment through API",
"metadata":{
"assignedBy":"xyz#gmail.com"
},
"policyDefinitionId":"/providers/Microsoft.Management/managementgroups/MGTest/providers/Microsoft.Authorization/policyDefinitions/test",
"parameters":{
"ringValue":{
"value":[
"r0,r1"
]
}
},
"enforcementMode":"DoNotEnforce"
}
}
Is there a way to declare a class where for a specific variable I can receive either a List or a string?
I trying to deserialize a JSON and it can come in one of the formats below:
"MercadoriasPresencaCarga": {
"Mercadoria": 7693066,
"Descarga": "08/07/2017 13:35:39"
},
or
"MercadoriasPresencaCarga": {
"Mercadoria": [
"7693066"
],
"Descarga": [
"08/07/2017 13:35:39"
]
},
The class for this block is created like this:
public class MercadoriasPresencaCarga
{
public List<string> Mercadoria { get; set; }
public List<string> Descarga { get; set; }
}
The problem is that if this block of JSON come as the first format that I showed where it is not a array, it will cause an error on it deserialization.
How could I solve this problem?
Ideally the json should always come in the same format, but if that's not a possibility there are some workarounds.
Both json strings will deserialize successfully using the following class:
public class Model
{
// other properties here
// ....
[JsonIgnore]
public string Mercadoria => GetValue("Mercadoria");
[JsonIgnore]
public string Descarga => GetValue("Descarga");
public JObject MercadoriasPresencaCarga { get; set; }
private string GetValue(string path)
{
if (MercadoriasPresencaCarga == null)
{
return null;
}
string value = null;
JToken token = MercadoriasPresencaCarga.SelectToken(path);
if (token.Type == JTokenType.Array && token.HasValues)
{
value = token.First.Value<string>();
}
else
{
value = token.Value<string>();
}
return value;
}
}
Please note that:
MercadoriasPresencaCarga will be deserialized as JObject
Both Mercadoria and Descarga are non-serializable properties (marked with [JsonIgnore])
Testing the code - json string with string properties (no arrays):
string json1 = #"{
""MercadoriasPresencaCarga"": {
""Mercadoria"": 7693066,
""Descarga"": ""08/07/2017 13:35:39""
}
}";
Model model1 = JsonConvert.DeserializeObject<Model>(json1);
Console.WriteLine($"Descarga: {model1.Descarga}, Mercadoria: {model1.Mercadoria}");
Testing the code - json string with arrays:
string json2 = #"{
""MercadoriasPresencaCarga"": {
""Mercadoria"": [
""7693066""
],
""Descarga"": [
""08/07/2017 13:35:39""
]
}
}";
Model model2 = JsonConvert.DeserializeObject<Model>(json2);
Console.WriteLine($"Descarga: {model2.Descarga}, Mercadoria: {model2.Mercadoria}");
I am trying to bind a drop-down with these lists in my View. Not able to convert the below JSON collections to LISTS.
My JSON string is in this format:
["AppTypes",
[
{
"AppTypeID": "5136",
"AppType": "ABC"
},
{
"AppTypeID": "dca6",
"AppType": "MNO"
},
{
"AppTypeID": "d8de",
"AppType": "PQR"
}
],
"CompTypes",
[
{
"CompTypeID": "0425",
"CompType": "STU"
},
{
"CompTypeID": "0426",
"CompType": "EDC"
},
{
"CompTypeID": "0444",
"CompType": "PLM"
}
]
]
I am trying to deserialize the code, but not getting through. My Class,
public class DAL
{
public DAL() { }
public CompList CompList { get; set; }
}
public class CompList
{
public CompList()
{
AppTypes = new List<AppTypes>();
CompType = new List<CompTypes>();
}
public List<AppTypes> AppTypes;
public List<ComTypes> CompType;
}
public class AppTypes
{
public Guid AppTypeID { get; set; }
public string AppType { get; set; }
}
public class CompTypes
{
public Guid CompTypeID { get; set; }
public string CompType { get; set; }
}
public class JSONSerializer
{
public static T ConvertFromJSON<T>(String json)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
return serializer.Deserialize<T>(json);
}
}
Controller Code:
dynamic obj = JSONSerializer.ConvertFromJSON<DAL>(JsonData);
Not able to get where I am going wrong. Any help would be really appreciated.
The main problem here is that your JSON represents a top-level array containing either strings or nested arrays containing objects, but you are trying to deserialize this into a top-level object - not an array. Your class design is quite reasonable, but a serializer such as JavaScriptSerializer isn't really designed to completely restructure a data model in this way during deserialization. You may need to deserialize into a more literal representation of the JSON, then restructure the data with, say, Linq.
A secondary problem is that you are declaring your ID properties to be Guids, but the corresponding JSON properties (such as "AppTypeID": "5136") do not have enough digits to be Guids. JavaScriptSerializer expects a Guid to have 32 digits, optionally separated by hyphens, e.g.: "d70d7583-b2e6-4f6e-8d99-2022d3ca2b10" or "d70d7583b2e64f6e8d992022d3ca2b10".
Thus, if I change your Guid properties to strings:
public class AppTypes
{
public string AppTypeID { get; set; }
public string AppType { get; set; }
}
public class CompTypes
{
public string CompTypeID { get; set; }
public string CompType { get; set; }
}
Then I can deserialize and convert to a CompList as follows:
var js = new JavaScriptSerializer();
var array = js.Deserialize<List<object>>(JsonData); // Deserialize outer array
var compList = new CompList
{
AppTypes = array
.OfType<IEnumerable<object>>() // Enumerate through nested arrays
.SelectMany(o => o) // Enumerate through elements in nested arrays
.OfType<IDictionary<string, object>>() // Pick out those which are JSON objects (deserialized as dictionaries)
.Where(d => d.ContainsKey("AppType")) // Filter those that are AppTypes
.Select(d => js.ConvertToType<AppTypes>(d)) // Deserialize to the AppTypes class
.ToList(),
CompType = array
.OfType<IEnumerable<object>>()
.SelectMany(o => o)
.OfType<IDictionary<string, object>>()
.Where(d => d.ContainsKey("CompType"))
.Select(d => js.ConvertToType<CompTypes>(d))
.ToList(),
};
FYI, your original code could deserialize JSON that looks like this into a CompList:
{
"AppTypes": [
{
"AppTypeID": "5136",
"AppType": "ABC"
},
{
"AppTypeID": "dca6",
"AppType": "MNO"
},
{
"AppTypeID": "d8de",
"AppType": "PQR"
}
],
"CompType": [
{
"CompTypeID": "0425",
"CompType": "STU"
},
{
"CompTypeID": "0426",
"CompType": "EDC"
},
{
"CompTypeID": "0444",
"CompType": "PLM"
}
]
}
Note that the outermost JSON is an object with two array-valued properties rather than an array of two strings and two arrays.
I have Called a Json Web Service and got the result in c#.The Json Web service data is available in format:
{
"Count": 9862,
"Items": [
{
"Admin": {
"S": "false"
},
"UserId": {
"S": "e9633477-978e-4956-ab34-cc4b8bbe4adf"
},
"Age": {
"N": "76.24807963806055"
},
"Promoted": {
"S": "true"
},
"UserName": {
"S": "e9633477"
},
"Registered": {
"S": "true"
}
},
{
"Admin": {
"S": "false"
},
"UserId": {
"S": "acf3eff7-36d6-4c3f-81dd-76f3a8071bcf"
},
"Age": {
"N": "64.79224276370684"
},
"Promoted": {
"S": "true"
},
"UserName": {
"S": "acf3eff7"
},
"Registered": {
"S": "true"
}
},
I have got the Response like this in c#:
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://localhost:8000/userdetails");
try
{
WebResponse response = request.GetResponse();
using (Stream responseStream = response.GetResponseStream())
{
StreamReader reader = new StreamReader(responseStream, Encoding.UTF8);
return reader.ReadToEnd();
}
}
after finally successfully get the response i have got all the Data in string. and then parse this string in list of objects .Now I have list of objects where it showing the count in debugging.Now I want to access the values like UserId:acf3eff7-36d6-4c3f-81dd-76f3a8071bcf like properties.I dont know how to do it.Please help me and any help will be appreciated.
You can use the following code to get the values from json as:
JObject obj = JObject.Parse(json);
int count = (int)obj["Count"];
var Items = obj["Items"];
foreach (var item in Items)
var admin = item["Admin"];
Quick and dirty way:
//deserialize your string json using json.net
dynamic jsonObj = Newtonsoft.Json.JsonConvert.DeserializeObject(json);
//get value of UserId in first Item
var UserId = jsonObj["Items"][0]["UserId"]["S"];
//OR get the value of UserId for each Item in Items
//foreach(dynamic item in jsonObj["Items"])
//item["UserId"]["S"];
Advice is to use c# objects as mentioned by #yousuf
To be able to access Json property like common C# object property, you need to deserialize json string to strongly typed object (you can use, for example, JSON.NET to do deserialization).
Another handy tool is http://json2csharp.com/. Paste your Json there then you can generate classes definitions that suitable to map the Json automatically :
//RootObject class definition generated using json2csharp.com
//the rest of class definition removed for brevity.
public class RootObject
{
public int Count { get; set; }
public List<Item> Items { get; set; }
}
........
........
//in main method
var jsonString = .....;
//deserialize json to strongly-typed object
RootObject result = JsonConvert.DeserializeObject<RootObject>(jsonString);
foreach(var item in result.Items)
{
//then you can access Json property like common object property
Console.WriteLine(item.UserId.S);
}
you are deserializing string to c# object. you will need to create object that reperesents the json .
For example -
public class Admin
{
public string S { get; set; }
}
public class UserId
{
public string S { get; set; }
}
public class Age
{
public string N { get; set; }
}
public class Promoted
{
public string S { get; set; }
}
public class UserName
{
public string S { get; set; }
}
public class Registered
{
public string S { get; set; }
}
public class RootObject
{
public Admin Admin { get; set; }
public UserId UserId { get; set; }
public Age Age { get; set; }
public Promoted Promoted { get; set; }
public UserName UserName { get; set; }
public Registered Registered { get; set; }
}
Then deserialize json string to object using jsonSerializer
JavaScriptSerializer serializer = new JavaScriptSerializer();
var result =
(RootObject)serializer .DeserializeObject("Json String")
string json = #"{
""Name"": ""Apple"",
""Expiry"": new Date(1230422400000),
""Price"": 3.99,
""Sizes"": [
""Small"",
""Medium"",
""Large""
]
}";
JObject o = JObject.Parse(json);
//This will be "Apple"
string name = (string)o["Name"];