Check JSON root element - c#

I'm working with C#, trying to parse JSON to XML, but first i need to validate the JSON and then check if it have a root element, there is my problem.
Suppose I got these two JSON strings:
string jsonWithoutRoot = "{'name': 'Fran', 'roles':['Admin','Coder']}";
string jsonWithRoot = "{'person': {'name': 'Fran','roles':['Admin','Coder']}}";
I want to get TRUE if the string have a root element like jsonWithRoot and FALSE in the other case.

A JSON string has one root object by definition. You're simply trying to count whether this root object has only one element.
This is trivially done by parsing the JSON into a JObject and getting the element count:
var jObject = JObject.Parse(jsonString);
bool hasOneElement = jObject.Count == 1;

I have been recently using this method to check what you are looking for. It might be helpfull.
public static bool HasOneProperty(string json)
{
JObject jsonObj = JObject.Parse(json);
if (jsonObj.Count > 1)
{
return false;
}
return true;
}

Related

How to empty a JObject array in C#

I have the following json
{
"audit_date": "2020-05-13T11:27:10.3187798Z",
"client_uuid": "2fd77dd8-ed76-4bba-b0e1-5cda454c8d6e",
"audit_entry": {
"where_uri": "test.com/dataservice/apps/171f0841-825b-4964-8f8c-0869650f14a6",
"why_uri": "test.com/dataservice/reference/reasons_for_change/61acc173-7168-4ae5-9f04- afa228941f8b",
"who_uri": "test.com/securityservice/users/4977dae1-a307-425f-980c-53413fef1b0f",
"when_audited": "2018-11-13T20:20:39+00:00",
"what_uri": "test.com/dataservice/study_subjects/1bc67a71-8549-4ab8-9dd9-e44238198860",
"what_changed": [
{
"attribute_name": "birth_year",
"attribute_value": "1969",
"attribute_change": null
},
{
"attribute_name": "subject_reference",
"attribute_value": "TEST-WOO3444",
"attribute_change": null
}
]
}
}
But I want to empty the nest array "what_changed"
So I need the output to be
{
"audit_date": "2020-05-13T11:27:10.3187798Z",
"client_uuid": "2fd77dd8-ed76-4bba-b0e1-5cda454c8d6e",
"audit_entry": {
"where_uri": "test.com/dataservice/apps/171f0841-825b-4964-8f8c-0869650f14a6",
"why_uri": "test.com/dataservice/reference/reasons_for_change/61acc173-7168-4ae5-9f04-afa228941f8b",
"who_uri": "test.com/securityservice/users/4977dae1-a307-425f-980c-53413fef1b0f",
"when_audited": "2018-11-13T20:20:39+00:00",
"what_uri": "test.com/dataservice/study_subjects/1bc67a71-8549-4ab8-9dd9-e44238198860",
"what_changed": []
}
}
I have written the following code
JObject jObj = JObject.Parse(jsonText);
jObj["audit_entry"]["what_changed"] = null;
string json = jObj.ToString(Formatting.None);
but this makes the field null rather than empty array.
I have also tried
JObject jObj = JObject.Parse(jsonText);
jObj["audit_entry"]["what_changed"] = "";
string json = jObj.ToString(Formatting.None);
but that still doesn't give an empty array.
I also tried using the Array.Clear() method, but this is a JObject array rather than a normal array.
Arrays are represented by the JArray type, not JObject. Cast the value of "what_changed" to the proper type and use the methods you need. Eg:
JObject jObj = JObject.Parse(jsonText);
JArray changed=(JArray)(jObj["audit_entry"]["what_changed"]);
changed.Clear();
Working with JSON elements is rather unusual though. It's typically a lot easier to deserialize JSON strings into strongly typed objects, modify them as needed and then serialize them back to a string.
Generating the necessary DTOs can be done easily in Visual Studio by selecting Paste Special > Paste JSON as Classes from the Edit menu
I can see several possibilities...
1.- instead of clearing the array, create a new one, an empty one. This does not solve the problem but it is a work around.
2.- using newtonsoft (a nuget package that you can download), you may be able to find different utilities there.
2.1.- Instead of parsing with JObject, parse with JArray, and then use Clear:
https://www.newtonsoft.com/json/help/html/ParseJsonArray.htm
https://www.newtonsoft.com/json/help/html/M_Newtonsoft_Json_Linq_JArray_Clear.htm.
2.2.- use Remove, for this you need the property name, so you need to iterate within the array (a foreach), getting the name of the property, and delete one by one.
https://www.newtonsoft.com/json/help/html/M_Newtonsoft_Json_Linq_JObject_Remove.htm
You need to cast it to a JArray first, then you can use its Clear() method;
((JArray)(jObj["audit_entry"]["what_changed"])).Clear();
Alternatively, you could simply create a new JArray in place of the old one.
jObj["audit_entry"]["what_changed"] = new JArray();
Try this :
JObject jObj = JObject.Parse(jsonText);
JToken jToken = jObj["audit_entry"]["what_changed"];
jToken.Replace(JToken.Parse("[]"));
string json = jObj.ToString(Formatting.None);

Get the path of a key from nested JSON using Json.Net

I have a big nested JSON. I don't know the structure of the JSON.
I just have a set of keys which are present in the JSON but I don't know where exactly in the JSON.
How do I find out the path of a key from an unknown JSON structure assuming the key exists somewhere in it?
If your JSON structure is unknown, you can parse it into a JToken like this:
JToken token = JToken.Parse(json);
From there, you can use either SelectToken() or SelectTokens() with a recursive descent JsonPath expression to find the property (or properties) matching a key:
JToken match = token.SelectToken("$.." + keyToFind);
Once you have the matching token, you can get the path to it using its Path property:
string path = match?.Path;
Here is a working demo which assumes you have multiple keys to find and each key can appear multiple times in the JSON: https://dotnetfiddle.net/9Em9Iq
For an unknown structure you can iterate over the objects :
var reader = new JsonTextReader(new StringReader(jsonText))
while (reader.Read())
{
// Do a condition on the variables reader.TokenType, reader.ValueType, reader.Value
}
This method will log all paths in your top level json that have a key equal to "key"
var keys = jobject.Properties().Where(p => p.Name == key).ToList();
keys.ForEach(i => Console.WriteLine(i.Path));
This will NOT work in a recursive way but it is easy from this to do a recursive search from there
you can use
JObject o = JObject.Parse(<yourjson>);
dynamic obj = o.SelectTokens("$..Product");

Get a specific nested JSON property using JObject

How do I get a specific nested property from a JSON using JObject?
For example i want to get the uri:
{
"embed": {
"uri": "/presets/88930"
...
There's many ways to access the property you're interested in.
Here's one:
String jsonData = "{ 'embed': { 'uri': '/presets/88930'}}";
var jObject = Newtonsoft.Json.Linq.JObject.Parse(jsonData);
Console.WriteLine((string)jObject["embed"]["uri"]);
if your jObject looks like:
var j = JObject.Parse(#"{""embed"": { ""uri"": ""/presets/88930"" } }");
dynamics makes accessing the object pretty easy:
string value = ((dynamic)j).embed.uri.ToString();

Converting API call Json URL string (Json Objects) into C# Datatable (Without using any constructive class with getters and setters or poco)

I'm new to Json API call string parsing in C#, I have a requirement where I need to get Json string from a API call and convert that into C# data-table then show the results in a web page using Asp.Net GridView.
I tried several ways. I faced different type of issues in each approach only succeed with my Approach 4(mentioned below). But I don't want to create a separate class (With getter and setters) and converting Json string into object of that class. As I have more than 150 fields for each record in my Json file and also object names are dynamic they are generated randomly. I don't want one to one mapping (Class field to Json field).
Here is my Json file format,
{
"R_aabdcDgjZwp0ch":{ Record 1 information key value pair } // Here R_aabdcDgjZwp0ch are randomly generated value
"R_lkYnksdY6qXaPb":{ Record 2 information key value pair } //R_lkYnksdY6qXaPb random
………
"R_7GhjsnB29xWBjp":{ Record n information key value pair }//R_7GhjsnB29xWBjp not fixed value
}
Sample Records from Json string:
{
"R_3dSKpqkb0JuH0TW":{"ResponseSet":"Default Response Set","Name":"John, Smith","ExternalDataReference":"811221273","EmailAddress":"smithaa#gmail.com","IPAddress":"123.232.12.21","Status":"","StartDate":"2015-07-06 11:10:26","EndDate":"2015-07-06 11:10:55","Finished":"1","RecipientEmail":"smithaa#gmail.com","RecipientLastName":"John","RecipientFirstName":"Smith","MI":"Mia","EntryTerm":"","Classification":"","Type":"","MajorCode":"","Major":"","DeptCode":"","Dept":"","College":"","Age":"","Ethnicity":"","Gender":"","CB1":"","PIDM":"71121027","Military":"","OrientationDate":"4\/7\/2016","H1":1,"H2":1,"H3":2,"H4":2,"H5":"","Q1":"","Q2":"","Q3_1":"","Q3_2":"","Q3_3":"","Q3_4":"","Q3_5":"","Q3_6":"","Q3_7":"","Q3_7_TEXT":"","Q4_1":"","Q4_2":"","Q4_3":"","Q4_4":"","Q4_5":"","Q4_6":"","Q4_7":"","Q4_8":"","Q4_9":"","Q4_10":"","Q4_11":"","Q4_12":"","Q4_12_TEXT":"","Q5":"","Q5_TEXT":"","Q6_1":"","Q6_2":"","Q6_3":"","Q7":"","Q8":"","Q9":"","Q10_1":"","Q10_2":"","Q10_3":"","Q10_4":"","Q11_1":"","Q11_2":"","Q11_3":"","Q11_4":"","Q12_1":"","Q12_2":"","Q12_3":"","Q12_4":"","Q13":"","Q13_TEXT":"","Q14":"","Q14_TEXT":"","Q15_1":"","Q15_2":"","Q15_3":"","Q15_4":"","Q15_5":"","Q15_6":"","Q15_7":"","Q15_8":"","Q16_1":"","Q16_2":"","Q16_3":"","Q16_4":"","Q16_5":"","Q16_6":"","Q16_7":"","Q16_8":"","Q17_1":"","Q17_2":"","Q17_3":"","Q17_4":"","Q17_5":"","Q17_6":"","H6":"","Q18_1":"","Q18_2":"","Q18_3":"","Q19_1":"","Q19_2":"","Q19_3":"","Q19_4":"","Q20":"","Q21_1":"","Q21_2":"","Q22_1":"","Q22_2":"","Q23_1":"","Q23_2":"","Q23_3":"","Q23_4":"","Q24":"","Q24_TEXT":"","Q25":"","Q26":"","Q27":"","Q28":"","H7":"","Q29_1":"","Q29_2":"","Q29_3":"","Q29_4":"","Q29_5":"","Q30":"","Q30_TEXT":"","Q31":"","Q31_TEXT":"","Q32":"","Q33_1":"","Q33_2":"","Q33_3":"","Q33_4":"","Q33_5":"","Q33_6":"","Q33_6_TEXT":"","Q34":"","Q34_TEXT":"","Q35":"","Q35_TEXT":"","Q36_1":"","Q36_2":"","Q36_3":"","Q36_4":"","Q36_5":"","Q36_6":"","Q36_7":"","Q36_7_TEXT":"","Q37":"","H8":1,"H9":1},
"R_1kYrTV300hwdvPP":{"ResponseSet":"Default Response Set","Name":"priya, Sam","ExternalDataReference":"8901212","EmailAddress":"sam12#gmail.com","IPAddress":"123.232.12.21","Status":"","StartDate":"2015-07-06 11:14:18","EndDate":"2015-07-06 11:14:59","Finished":"1","RecipientEmail":"sam#gmail.com","RecipientLastName":"sam","RecipientFirstName":"priya","MI":"","EntryTerm":"","Classification":"","Type":"","MajorCode":"","Major":"","DeptCode":"","Dept":"","College":"","Age":"","Ethnicity":"","Gender":"","CB1":"","PIDM":"71121028","Military":"","OrientationDate":"6\/27\/2016","H1":1,"H2":1,"H3":2,"H4":2,"H5":"","Q1":"","Q2":"","Q3_1":"","Q3_2":"","Q3_3":"","Q3_4":"","Q3_5":"","Q3_6":"","Q3_7":"","Q3_7_TEXT":"","Q4_1":"","Q4_2":"","Q4_3":"","Q4_4":"","Q4_5":"","Q4_6":"","Q4_7":"","Q4_8":"","Q4_9":"","Q4_10":"","Q4_11":"","Q4_12":"","Q4_12_TEXT":"","Q5":"","Q5_TEXT":"","Q6_1":"","Q6_2":"","Q6_3":"","Q7":"","Q8":"","Q9":"","Q10_1":"","Q10_2":"","Q10_3":"","Q10_4":"","Q11_1":"","Q11_2":"","Q11_3":"","Q11_4":"","Q12_1":"","Q12_2":"","Q12_3":"","Q12_4":"","Q13":"","Q13_TEXT":"","Q14":"","Q14_TEXT":"","Q15_1":"","Q15_2":"","Q15_3":"","Q15_4":"","Q15_5":"","Q15_6":"","Q15_7":"","Q15_8":"","Q16_1":"","Q16_2":"","Q16_3":"","Q16_4":"","Q16_5":"","Q16_6":"","Q16_7":"","Q16_8":"","Q17_1":"","Q17_2":"","Q17_3":"","Q17_4":"","Q17_5":"","Q17_6":"","H6":"","Q18_1":"","Q18_2":"","Q18_3":"","Q19_1":"","Q19_2":"","Q19_3":"","Q19_4":"","Q20":"","Q21_1":"","Q21_2":"","Q22_1":"","Q22_2":"","Q23_1":"","Q23_2":"","Q23_3":"","Q23_4":"","Q24":"","Q24_TEXT":"","Q25":"","Q26":"","Q27":"","Q28":"","H7":"","Q29_1":"","Q29_2":"","Q29_3":"","Q29_4":"","Q29_5":"","Q30":"","Q30_TEXT":"","Q31":"","Q31_TEXT":"","Q32":"","Q33_1":"","Q33_2":"","Q33_3":"","Q33_4":"","Q33_5":"","Q33_6":"","Q33_6_TEXT":"","Q34":"","Q34_TEXT":"","Q35":"","Q35_TEXT":"","Q36_1":"","Q36_2":"","Q36_3":"","Q36_4":"","Q36_5":"","Q36_6":"","Q36_7":"","Q36_7_TEXT":"","Q37":"","H8":1,"H9":1}
}
I have tried several ways to parse/consume Json url string to Datatable. I’m receiving below errors.
Approach 1: Using Json.Net and directly converting from Json string to Data Table using Newtonsoft.Json. JsonConvert.DeserializeObject
Sample Code:
string url ="test.com/json...etc"; //Here actual url to call api
var json_data = string.Empty;
// attempt to download JSON data as a string
json_data = w.DownloadString(url); // we are passing API url here
DataTable items = JsonConvert.DeserializeObject<DataTable>(json_data); // Exception coming here
Exception: Newtonsoft.Json.JsonSerializationException: Unexpected JSON token when reading DataTable. Expected StartArray, got StartObject. Path '', line 1, position 1.
Approach 2: I have used http://json2csharp.com/# (Which Converts Json input file/Json url into constructive class which will have getters and setters with Root Object to access data from sub classes). But I end up with an exception. However I don't want this approach.
Exception: Newtonsoft.Json.JsonSerializationException: Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.List`1[matrix+RANFpZfdGjZwp0ch]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.
To fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.
Path 'R_ANFpZfdGjZwp0ch', line 1, position 21.
Approach 3: I have tried using below. But ended with an exception.
DataTable dt = (DataTable)JsonConvert.DeserializeObject(json, (typeof(DataTable)));
Exception: Newtonsoft.Json.JsonSerializationException: Unexpected JSON token when reading DataTable. Expected StartArray, got StartObject. Path '', line 1, position 1.
Tried below to solve this Approach 3 issue. But didn't work.
Newtonsoft.Json JsonConvert To Datatable
http://www.codeproject.com/Questions/817608/Newtonsoft-Json-JsonConvert-To-Datatable
Converting JSON string to DataTable
Parsing with Json.NET: "Unexpected token: StartObject"
Approach 4: With this approach I succeed using constructive class with getters and setters.
string url ="test.com/json...etc"; //Here actual url to call api
using (var w = new WebClient())
{
var json = string.Empty;
// attempt to download JSON data as a string
try
{
json = w.DownloadString(url);
}
catch (Exception) { }
User obj = new User(json);
Response.Write(obj.name);
}
public class User
{
/********* Used from https://stackoverflow.com/questions/2246694/how-to-convert-json-object-to-custom-c-sharp-object **********/
public User(string json)
{
JObject jObject = JObject.Parse(json);
JToken jUser = jObject["R_XYZanOp0ch"]; //R_XYZanOp0ch this value is randomly generated. I gave it constant to check for one record. In actual Json file there are so many randomly generated object names exist.
name = (string)jUser["Name"];
email = (string)jUser["Email"];
ExternalDataReference = (string)jUser["NumberReference"];
}
public string name { get; set; }
public string ExternalDataReference { get; set; } // student ID
public string email { get; set; }
}
I got some result using this Approach 4. But problem is that we have more than 150 fields and we don't want to make getters and setters for each field and object names are dynamic not fixed. Unfortunately we need all fields data.
Below are my references I used for above approaches.
Convert Json String to C# Object List
Convert JSON to DataTable
How to convert json into datatable?
Thanks for reading. Sorry for my long text. Don't consider this post as duplicate, As I tried all ways but still I didn't get desired outcome, hence posting here.
Can anyone help me or guide me as per my Json string structure, do I need to change any of code? Any samples or reading notes would be helpful.
Thank you.
Update : I tried both, I got System.FormatException: Input string was not in a correct format exception at array.ToObject(); please let me know If I miss any step in between.
var obj = JObject.Parse(json);
var array = new JArray(obj.Values());
//Response.Write("<br/>array[0]" + array[0].ToString()); // I could able to view the record 1 data
var dt = array.ToObject<DataTable>(); // Having issue here.
Json.NET has a built-in converter for DataTable. It formats the table as an array, like so:
[
{
"Column1Name" : value11,
"Column2Name" : value21
},
{
"Column1Name" : value12,
"Column2Name" : value22
},
// And so on
}
What you have is a dictionary with random keys, not an array, so you need to transform your JSON to an array before deserialization. This can be done with LINQ to JSON. If you do not need the random key names, you can do:
var obj = JObject.Parse(json);
var array = new JArray(obj.Values());
var dt = array.ToObject<DataTable>();
If you need the random key names, you could add them as a column to the DataTable like so:
var obj = JObject.Parse(json);
string keyColumnName = "__key";
var query = from p in obj.Properties()
select new JObject(p.Value.OfType<JProperty>().Concat(new [] { new JProperty(keyColumnName, p.Name) }));
var array = new JArray(query);
var dt = array.ToObject<DataTable>();
Sample fiddle.
Thank you dbc. I appreciate your input it helped me to figure out middle layer (Converting Json to Array) in between Json to DataTable.
I modified your code little bit and used data-table conversion method call from https://stackoverflow.com/a/24339121/4425471
At movement we are ignoring the Random Key. Finally I got my desired outcome. I can able to convert Json to DataTable and then to the GridView.
Here is my final code. Thank you SO.
string json = "test.com/json..."; // actual API call url
DataTable dt = toDataTable(json);
GridView1.DataSource = dt;
GridView1.DataBind();
public static DataTable toDataTable(string json)
{
var result = new DataTable();
var obj = JObject.Parse(json);
var jArray = new JArray(obj.Values());
//Initialize the columns
foreach (var row in jArray)
{
foreach (var jToken in row)
{
var jproperty = jToken as JProperty;
if (jproperty == null) continue;
if (result.Columns[jproperty.Name] == null)
result.Columns.Add(jproperty.Name,typeof(string));
}
}
foreach (var row in jArray)
{
var datarow = result.NewRow();
foreach (var jToken in row)
{
var jProperty = jToken as JProperty;
if (jProperty == null) continue;
datarow[jProperty.Name] = jProperty.Value.ToString();
}
result.Rows.Add(datarow);
}
return result;
}

How to check if dynamic is empty.

I am using Newtonsoft's Json.NET to deserialize a JSON string:
var output = JsonConvert.DeserializeObject<dynamic>("{ 'foo': 'bar' }");
How can I check that output is empty? An example test case:
var output = JsonConvert.DeserializeObject<dynamic>("{ }");
Assert.IsNull(output); // fails
The object you get back from DeserializeObject is going to be a JObject, which has a Count property. This property tells you how many properties are on the object.
var output = JsonConvert.DeserializeObject<dynamic>("{ }");
if (((JObject)output).Count == 0)
{
// The object is empty
}
This won't tell you if a dynamic object is empty, but it will tell you if a deserialized JSON object is empty.
You can also check with following code:
var output = JsonConvert.DeserializeObject<dynamic>("{ }");
if (output as JObject == null)
{
}
That worked for me.
You can just have a string conversion and check if its equal to "{ }".
var output = JsonConvert.DeserializeObject<dynamic>("{ }");
if (output.ToString() =="{ }")
{
// The object is empty
}

Categories

Resources