Get a specific nested JSON property using JObject - c#

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();

Related

Checking if properties with specific values exist with JSON Path in Json.net

Given the following JSON:
{
"pos":123,
"name":"Bla"
}
I'm trying to validate that the JSON provided has a name property with the value Bla
Following the documentation on json.net I established that this should work:
$.[?(#.name == 'Bla')]
I validated this idea on https://jsonpath.herokuapp.com/ and it seems to return the object if it is true, and nothing if it isn't
However, when trying the same in json.net it never seems to return a valid JToken.
Example code here: https://dotnetfiddle.net/0agXyZ (passing true into SelectToken says it should throw an error if the result is not found, I'm not seeing this either).
Is this something I'm doing wrong here?
What I'm trying to do is write a test That will allow developers to specify expected JSON to be returned from their tests, so it made sense to me that if there was a way to provide them a way to input a validation string in JSON path format I can hide the details of this validation in my framework.
Thanks.
As indicated by #dbc in the comment above, the JSONPath search filter is meant for arrays. You can still go after an individual property in an object just to see if it exists.
Expanding the example posted at dotnetfiddle.
using System;
using System.Xml;
using System.Xml.Linq;
using System.Linq;
using Newtonsoft.Json.Linq;
using System.Text.RegularExpressions;
public class Program
{
public static void Main()
{
var json = #"{'pos':123,'name':'Bla'}";
var jobj = JObject.Parse(json);
Console.WriteLine("Looking for 'name'");
JToken token = jobj.SelectToken("$.name");
if (token == null) Console.WriteLine("error");
Console.WriteLine(token);
Console.WriteLine("Looking for 'names'");
token = jobj.SelectToken("$.names");
if (token == null) Console.WriteLine("error");
Console.WriteLine(token);
var json2 = #"{
'data': [
{
'pos':123,
'name':'Bla'
},
{
'pos':123,
'name':'Bla2'
},
{
'pos':123,
'name':'Bla3'
}
]
}";
var jobj2 = JObject.Parse(json2);
Console.WriteLine("Looking for 'name == 'Bla2'' in array.");
JToken token2 = jobj2.SelectToken("$.data[?(#.name == 'Bla2')]");
if (token2 == null) Console.WriteLine("error");
Console.WriteLine(token2);
}
}
The result is:
Looking for 'name'
Bla
Looking for 'names'
error
Looking for 'name == 'Bla2'' in array.
{
"pos": 123,
"name": "Bla2"
}
json path is not valid with jobject, it is used with collections. For your json you can use this
var json=#"{
""pos"":123,
""name"":""Bla""
}";
var jsonObject=JObject.Parse(json);
bool thereIsName =(string)jsonObject.SelectToken("name")=="Bla"; //True
you can use a json path for a similar json
var json=#"[{
""pos"":123,
""name"":""Bla""
}]";
var jsonArray=JArray.Parse(json);
bool thereIsName = jsonArray.SelectToken("$[?(#.name == 'Bla')]")!=null; //True

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);

Trying to deserialize JSON with surrounding [] characters usig JSON.NET

I am using .NET 4.7, C#, JSON.NET, MVC 5
I have some input JSON:
[
{
"id" : 1
},
{
"id" : 2
},
{
"id" : 3
}
]
This is provided by a 3rd party API
Normally I would use code such as, to deserialize:
var content = await response.Content.ReadAsStringAsync();
JObject json = JObject.Parse(content);
orderList = JsonConvert.DeserializeObject<OrderList>(json.ToString());
However I am finding that:
JObject json = JObject.Parse(content);
Crashes out with the JSON in question. I strongly suspect that the surrounding "[" and "]" is the cause.
I would normally add :
{
items: [
to correct the input JSON.
Is there a better way, to deserialize it, as it seems this input JSON is incomplete although when I test it, it does seem to be valid JSON.
Possibly I should be using JArray instead of JObject?
Thanks in advance.
You are missing commas "," in the JSON. It should be like this:
[
{
"id" : 1
},
{
"id" : 2
},
{
"id" : 3
}
]
And you can deserialize it like that:
var content = await response.Content.ReadAsStringAsync();
var list = JsonConvert.DeserializeObject<List<MyClass>>(content);
Where list is a List<MyClass>
public class MyClass
{
public int id { get; set; }
}
You have 3 options:
Instead of JObject.Parse, use JArray.Parse because the JSON is an array, not an object. This is not the best way to achieve what you want.
Deserialise to a List<T> where T is a concrete class that contains the matching properties of the object. for example:
var result = JsonConvert.DeserializeObject<List<Order>>(json);
This is better, but...
The best option is not to read the HttpClient response as a string in the first place and let the framework do the work for you. You should use the ReadAsAsync<T> extension method. Internally, this uses a stream and is more efficient than first going to string. So for example:
List<Order> orders = await response.Content.ReadAsAsync<List<Order>>();

Check JSON root element

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

Deserialize JSON with json.NET into C# dynamic

I have following problem: I have a json file that looks like this
{
"Path": {
"FirstPath": "/1/2/text()"
}
}
If I parse this JSON-File with Newtonsoft like this
dynamic dyn = JObject.Parse(json);
or this
dynamic dyn = JsonConvert.DeserializeObject(json);
I get a dynamic object that needs to be used like this
dyn.Path.FirstPath.Value
How can I get rid of the Value stuff? All of my objects in the JSON end up being a string. I don't want to always write ".Value" at the end if it is not necessary.
I tested this using Newtonsoft 8.0.2 and it works fine.
dynamic dyn = JObject.Parse(json);
string value = dyn.Path.FirstPath;
Value should equal /1/2/text().

Categories

Resources