NewtonSoft json parsing - c#

Can somebody help me to parse the json and get the details.
Lets say i have Top2 input parameter as Police and i want to know the respective Top3 and in that Top3 array i need to check whether Test1Child value is there or not.
I am using newtonsoft json + c# and so far i can get till DeviceTypes using below code
var json = File.ReadAllText(jsonFile); // below json is stored in file jsonFile
var jObject = JObject.Parse(json);
JArray MappingArray =(JArray)jObject["Top1"];
string strTop1 = ObjZone.Top1.ToString();
string strTop2 = ObjZone.Top2.ToString();
var JToken = MappingArray.Where(obj => obj["Top2"].Value<string>() == strTop2).ToList();
//Json
{
"Top1": [
{
"Top2": "Test1",
"Top3": [
"Test1Child"
]
},
{
"Top2": "Test2",
"Top3": [
"Test2Child"
]
}
]
}

I'd use http://json2csharp.com/ (or any other json to c# parser) and then use C# objects (it's just easier for me)
This would look like that for this case:
namespace jsonTests
{
public class DeviceTypeWithResponseTypeMapper
{
public string DeviceType { get; set; }
public List<string> ResponseTypes { get; set; }
}
public class RootObject
{
public List<DeviceTypeWithResponseTypeMapper> DeviceTypeWithResponseTypeMapper { get; set; }
}
}
and the use it like that in code:
var rootob = Newtonsoft.Json.JsonConvert.DeserializeObject<RootObject>(str);
var thoseThatHaveNotUsed = rootob.DeviceTypeWithResponseTypeMapper.Where(dtwrtm =>
dtwrtm.ResponseTypes.Any(rt => rt == "NotUsed"));
foreach (var one in thoseThatHaveNotUsed)
{
Console.WriteLine(one.DeviceType);
}
this code lists all the Device types that have "NotUsed" among the responses.
version 2 (extending your code) would look like that, i believe:
static void Main(string[] args)
{
var json = str; // below json is stored in file jsonFile
var jObject = JObject.Parse(json);
JArray ZoneMappingArray = (JArray)jObject["DeviceTypeWithResponseTypeMapper"];
string strDeviceType = "Police";
string strResponseType = "NotUsed";
var JToken = ZoneMappingArray.Where(obj => obj["DeviceType"].Value<string>() == strDeviceType).ToList();
var isrespTypeThere = JToken[0].Last().Values().Any(x => x.Value<string>() == strResponseType);
Console.WriteLine($"Does {strDeviceType} have response type with value {strResponseType}? {yesorno(isrespTypeThere)}");
}
private static object yesorno(bool isrespTypeThere)
{
if (isrespTypeThere)
{
return "yes!";
}
else
{
return "no :(";
}
}
result:
and if you'd like to list all devices that have response type equal to wanted you can use this code:
var allWithResponseType = ZoneMappingArray.Where(jt => jt.Last().Values().Any(x => x.Value<string>() == strResponseType));
foreach (var item in allWithResponseType)
{
Console.WriteLine(item["DeviceType"].Value<string>());
}

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".

How would you add a JArray into a JObject without adding a new JObject key/name?

using .NET C#, I am trying to create a new JObject from a JArray. I have a FetchData JObject that I want to return a JObject of data for data driven testing. Here is what I have so far:
public static JObject FetchData(string testMethodName)
{
using (StreamReader r = new StreamReader("PathToJsonfile"))
{
string jsonstring = r.ReadToEnd();
JObject obj = JObject.Parse(jsonstring);
JArray jsonArray = JArray.Parse(obj[testMethodName].ToString());
JObject jObject = new JObject(new JProperty("test",jsonArray));
return jObject;
}
}
I want to return a JObject of test data that pertains to the testMethod which is being run. when I run this code, jObject returns:
"test": [
{
"loginId": "testuser1",
"userCase": "verify for user"
},
{
"loginId": "testuser2",
"userCase": "verify for user"
}
]
My issue is that I only want to return the following arrays within the JObject:
{"loginId":"testuser1","userCase":"verify for user"}
I have researched for a while and cannot find a solution without adding a key to the new JObject, in this case, key being "test".
Is this even possible in C#?
I have also tried adding the JArray directly to the JObject:
JObject jObject = new JObject(new JObject(jsonArray));
but get error : System.ArgumentException: 'Can not add Newtonsoft.Json.Linq.JArray to Newtonsoft.json.Linq.JObject
I have also tried adding the arrays to the JObject like this:
for (int i = 0; i < jsonArray.Count; i++)
{
jObject[i] = jsonArray[i];
}
but get error : System.ArgumentException : Set JObject values with invalid key value: 0. Object property name expected.
fwiw this is how I am doing this is Java and it works like a charm, but I cannot figure it out in C#. Java Code:
JSONObject[] jsonObject = new JSONObject[jsonArray.length()];
for (int i = 0; i < jsonArray.length(); i++) {
jsonObject[i] = jsonArray.getJSONObject(i);
}
To get first element of array you can do next:
var json = #"{
""test"": [
{
""loginId"": ""testuser1"",
""userCase"": ""verify for user""
},
{
""loginId"": ""testuser2"",
""userCase"": ""verify for user""
}]
}";
var testMethodName = "test";
var jObject = JObject.Parse(json);
var first = (JObject)jObject[testMethodName][0]; // note that this can throw for multiple reasons
Analog of your java code would be:
// parse jObject as earlier
var jArr = (JArray)jObject[testMethodName];
var jsonObjectArr = new JObject[jArr.Count];
for (int i = 0; i < jArr.Count; i++)
{
jsonObjectArr[i] = (JObject)jArr[i];
}
Or you can use LINQ to JSON:
// parse jObject as earlier
var jsonObjectArr = jObject[testMethodName]
.Children<JObject>()
.ToArray();
Why don't you return only the first object of your array like this:
public static JToken FetchOneDatum(string testMethodName)
{
string jsonString = GetFileContent("sampleTest.txt");
JObject obj = JObject.Parse(jsonString);
JArray jsonArray = JArray.Parse(obj[testMethodName].ToString());
return jsonArray[0];
}
You can find the whole visual Studio solution here:
solution on GitHub
C# approach ;)
public class Test
{
public string loginId { get; set; }
public string userCase { get; set; }
}
public class Scenario
{
public Test[] tests { get; set; }
}
// Usage
public static Test FetchData(string testMethodName)
{
using (var reader = new StreamReader("PathToJsonfile"))
{
var json = reader.ReadToEnd();
var scenario = JsonConvert.DeserializeObject<Scenario>(json);
return scenario.tests.First();
}
}

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.

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""
}]
}";
}
}

C# Json To Dictionary of Objects

I want to take some Json and parse it in to a collection of key/value pairs, but some of the values will be dictionaries themselves. I tried the usual Newtonsoft deserialization. It's close, but not quite right. The end result must be a dictionary, not a strongly typed class.
This is some example Json:
{
"JobNumber": 1010,
"Asset": null,
"JobNotes": [
{
"NoteText": "It's not working.",
"NoteType": "Complaint"
},
{
"NoteText": "Needs to be fixed",
"NoteType": "Job"
}
]
}
This is the code I used to deserialize:
var json = File.ReadAllText(#"c:\temp\job.json");
var result = JsonConvert.DeserializeObject<Dictionary<string, object>>(json);
The result is almost correct, but the value of the item with a key of "JobNotes" is just json string. I want the parser to recurse in and deserialise the inner Json to a further dictionary of strings and objects. Is there a way I can do this with the Newtonsoft library? Or, is there another library that will do the trick? Can I hook in to the parsing method to override the functionality at that point in time?
This is a modified version of #DanielKeogh's code. It works well.
class Program
{
static void Main(string[] args)
{
var json = File.ReadAllText(#"c:\temp\job3.json");
var result = JsonConvert.DeserializeObject<Dictionary<string, object>>(json);
RecurseDeserialize(result);
}
private static void RecurseDeserialize(Dictionary<string, object> result)
{
//Iterate throgh key/value pairs
foreach (var keyValuePair in result.ToArray())
{
//Check to see if Newtonsoft thinks this is a JArray
var jarray = keyValuePair.Value as JArray;
if (jarray != null)
{
//We have a JArray
//Convert JArray back to json and deserialize to a list of dictionaries
var dictionaries = JsonConvert.DeserializeObject<List<Dictionary<string, object>>>(jarray.ToString());
//Set the result as the dictionary
result[keyValuePair.Key] = dictionaries;
//Iterate throught the dictionaries
foreach (var dictionary in dictionaries)
{
//Recurse
RecurseDeserialize(dictionary);
}
}
}
}
}
This modified Json shows how deep it goes:
{
"JobNumber": 1010,
"Asset": null,
"JobNotes": [
{
"NoteText": "It's not working.",
"NoteType": "Complaint"
},
{
"NoteText": "Needs to be fixed",
"NoteType": "Job",
"JobNoteNotes": [
{
"Something": 1,
"Something2": "Test"
}
]
}
]
}
The result ends three dictionaries deep so that I can get at the "Something" value by key.
This can be done with a little recursion. I'll leave defining IsJson up to you as an academic exercise. :)
Dictionary<string, object> RecursiveDeserialize(string json)
{
var result = JsonConvert.DeserializeObject<Dictionary<string, object>>(json);
foreach (var pair in result.ToArray())
{
if(IsJson(pair.Value))
{
result[pair.Key] = RecursiveDeserialize(pair.Value);
}
}
return result;
}
Using this object for json string
public class JobNote
{
public string NoteText { get; set; }
public string NoteType { get; set; }
}
public class ListJob
{
public int JobNumber { get; set; }
public object Asset { get; set; }
public List<JobNote> JobNotes { get; set; }
}
Then you can deserialize it

Categories

Resources