I am trying to get JSON data from an api.
I have this json with me:
{
"elements": [
{
"id": 1,
"name": "Bob",
"address": "abc street",
"hobbies": {
"indoor": "Games, reading books",
"outdoor": ""
}
},
{
"id": 2,
"name": "Mark",
"address": "def street",
"hobbies": {
"indoor": "Games, reading books",
"outdoor": ""
}
}
]
}
I have this code with me:
using(var httpClient = new HttpClient()) {
HttpResponseMessage response = httpClient.GetAsync("api_url_here").Result;
var studentJsonString = response.Content.ReadAsStringAsync().Result;
var Jsresult = new JavaScriptSerializer().Deserialize<dynamic>(studentJsonString).ToString();
JObject jObject = JObject.Parse(Jsresult);
IEnumerable<dynamic> listDyn = jObject[0].Select(items => new StudentModel// gives error here as whole
{
id = items["id"].ToString(),
name = items["name"].ToString(),
address= items["address"].ToString()
});
}
But when I am calling the above method but it is giving me an error:
'Accessed JObject values with invalid key value: 1. Object property name expected.'
What am I missing?
Why are you deserializing twice? The result of
JavaScriptSerializer().Deserialize(customerJsonString)
is already an object. You don't need to parse it again with JObject.Parse(). You can just do
JObject jObject= JObject.Parse(customerJsonString)
Furthermore the result of JObject.Parse() is a dictionary and not an array. It has properties, which you can access by their names. For instance
jObject["elements"]
But of course, the compiler can't possibly predict, that jObject["elements"] will be an IEnumerable, so you will have to make sure of that.
jObject.Value<JArray>("elements").Select(item => ...)
This reads the property elements, of jObject as a JArray.
Related
So I have below call to a method where my argument is a json string of this type
var jsonWithSearchData = await querySearchData(jsonOut);
jsonOut ->
[
{
"data": {
"_hash": null,
"kind": "ENY",
"id": "t123",
"payload": {
"r:attributes": {
"lok:934": "#0|I"
},
"r:relations": {
"lok:1445": "15318",
"lok:8538": "08562"
},
"r:searchData": "",
"r:type": [
"5085"
]
},
"type": "EQT",
"version": "d06"
}
}
]
The querySearchData() returns me two list something like this :["P123","P124","P987"] and ["Ba123","KO817","Daaa112"]
I want to add this list in my r:searchData key above. The key inside my searchData i.e. r:Porelation and ClassA and ClassB remains static. So I would like my searchData in my input Json to finally become something like this.
"r:searchData": {
"r:Porelation":{
"ClassA": ["P123","P124","P987"],
"ClassB": ["Ba123","KO817","Daaa112"]
}
},
How can I do this? What I tried:
JArray jfinObject = JArray.Parse(jobjects);
jfinObject["r:searchData"]["r:relations"]["ClassA"] = JArray.Parse(ListofCode.ToString());
And I get below error:
System.Private.CoreLib: Exception while executing function: Function1.
Newtonsoft.Json: Accessed JArray values with invalid key value:
"r:searchData". Int32 array index expected.
There are a few ways you can add a node/object/array to existing json.
One option is to use Linq-to-Json to build up the correct model.
Assuming you have the json string described in your question, the below code will add your desired json to the r:searchData node:
var arr = JArray.Parse(json); // the json string
var payloadNode = arr[0]["data"]["payload"];
// use linq-to-json to create the correct object
var objectToAdd = new JObject(
new JProperty("r:Porelation",
new JObject(
new JProperty("r:ClassA", array1),
new JProperty("r:ClassB", array2))));
payloadNode["r:searchData"] = objectToAdd;
where array1 and array2 above could come from a linq query (or just standard arrays).
// Output:
{
"data": {
"_hash": null,
"kind": "ENY",
"id": "t123",
"payload": {
"r:attributes": {
"lok:934": "#0|I"
},
"r:relations": {
"lok:1445": "15318",
"lok:8538": "08562"
},
"r:searchData": {
"r:Porelation": {
"r:ClassA": [
"P123",
"P456"
],
"r:ClassB": [
"Ba123",
"Ba456"
]
}
},
"r:type": [
"5085"
]
},
"type": "EQT",
"version": "d06"
}
}
Online demo
Another option is to create the json from an object, which could be achieved using JToken.FromObject(). However, this will only work if you have property names which are also valid for C# properties. So, this won't work for your desired property names as they contain invalid characters for C# properties, but it might help someone else:
// create JToken with required data using anonymous type
var porelation = JToken.FromObject(new
{
ClassA = new[] { "P123", "P456" }, // replace with your arrays here
ClassB = new[] { "Ba123", "Ba456" } // and here
});
// create JObject and add to original array
var newObjectToAdd = new JObject(new JProperty("r:Porelation", porelation));
payloadNode["r:searchData"] = newObjectToAdd;
I have a JSON like this
{
"Customer": {
"$type": "Dictionary`2",
"Id": "6448DE37E2F3D9588118A1950"
},
"Databases": [
{
"$type": "Pime",
"Id": 1,
"Name": "Peter",
"MobNo": 78877629,
"PAN": "SAKKJKJ",
"Defaulter": true,
},
{
"$type": "Pime",
"Id": 2,
"Name": "James",
"MobNo": 58277699,
"PAN": "NAQKJKJ",
"Defaulter": false,
},
{
"$type": "Pime",
"Id": 3,
"Name": "Norton",
"MobNo": 38877699,
"PAN": "TAKKJKJ",
"Defaulter": true,
},
]
}
I'm using a token to select the node and return the customer information whose Id=2
My code goes like this:
StreamReader r = new StreamReader("C:\TestJson\Test.db");
string json = r.ReadToEnd();
JObject o = JObject.Parse(json);
JToken result = o.SelectToken("$.Databases[?(#.Id == '2')]");
But I am getting the result as null. Am I using the wrong token in the SelectToken() method?
First of all given JSON is invalid, in database array value of Name and PAN keys should be of type string. You are missing "(double qoutes) in above json.
Second and most important thing, type of Id is an integer and in your Json Path you are trying to search with string type i.e '2', try to search Id by integer without quoute it will work.
//No single qoutes for 2.
JToken result = o.SelectToken("$.Databases[?(#.Id == 2)]");
How to covert the below json
{"data":{"id":12,"name":"jeremy","email":"jeremy#test.com"}}
to
{"id":12,"name":"jeremy","email":"jeremy#test.com"}
I want to remove the "data" element from json.
With json.net it's fairly straightforward
var input = "{\"data\":{\"id\":12,\"name\":\"jeremy\",\"email\":\"jeremy#test.com\"}}";
var result = JObject.Parse(input)["data"].ToString(Formatting.None);
Console.WriteLine(result);
Note : Formatting.None is only to preserve the formatting you had in your original example
Or Text.Json
var result = JsonDocument.Parse(input).RootElement.GetProperty("data").ToString();
Output
{"id":12,"name":"jeremy","email":"jeremy#test.com"}
Additional Resources
JObject.Parse Method (String)
Load a JObject from a string that contains JSON.
JObject.Item Property (String)
Gets or sets the JToken with the specified property name.
JToken.ToString Method (Formatting,JsonConverter[])
Returns the JSON for this token using the given formatting and
converters.
Formatting Enumeration
None 0 No special formatting is applied.
Text.Json
JsonDocument.Parse Method
Provides a mechanism for examining the structural content of a JSON
value without automatically instantiating data values.
JsonDocument.RootElement Property
Gets the root element of this JSON document
JsonElement.GetProperty Method
Gets a JsonElement representing the value of a required property
identified by propertyName.
I have a follow up question on a scenario where I don't want to remove the root element.
{
"keepMe": {
"removeMe": [
{
"id": "1",
"name": "Foo",
"email": "Foo#email.com"
},
{
"id": "2",
"name": "Bar",
"email": "Bar#email.com"
}
]
}
But I wanted it to look like
{
"keepMe": {
{
"id": "1",
"name": "Foo",
"email": "Foo#email.com"
},
{
"id": "2",
"name": "Bar",
"email": "Bar#email.com"
}
}
Using below would not work. Is there another way to do this?
var result = JObject.Parse(input)["keepMe"]["removeMe"].ToString(Formatting.None);
//{
// "id": "1",
// "name": "Foo",
// "email": "Foo#email.com"
//},
//{
// "id": "2",
// "name": "Bar",
// "email": "Bar#email.com"
//}
var result = JObject.Parse(input)["removeMe"].ToString(Formatting.None); //Null Reference
Found the answer using the SelectToken and Replace keyword
var jObj = JObject.Parse(input);
jObj.SelectToken("keepMe").Replace(jObj.SelectToken("keepMe.removeMe"));
string result = jObj.ToString();
I am trying to get only Unique IDs from a JSON response. I tried to parse and select only token Ids but it is failing. What is the best and fastest way to get only the Ids?
Code:
JArray jArray = new JArray();
var response = new HttpResponseMessage(System.Net.HttpStatusCode.OK);
response.Content = new StringContent(jArray.ToString(Formatting.Indented));
var resp = await response.Content.ReadAsStringAsync();
Here is my sample JSON Array:
[
{
"Timestamp": "2020-11-24T08:25:46.6531855Z",
"ID": "8c316aca-b930-421f-851c-17d618b61fa1",
"Message": "New User Registered"
},
{
"Timestamp": "2020-11-24T08:25:46.6531855Z",
"ID": "8c316aca-b930-421f-851c-17d618b61fa1",
"Message": "User details updated"
},
{
"Timestamp": "2020-11-24T08:25:46.6531855Z",
"ID": "a23shaga-2wd3-fky6-851c-43524fbfgsa",
"Message": "New User Registered"
}
]
Desired Output:
8c316aca-b930-421f-851c-17d618b61fa1
a23shaga-2wd3-fky6-851c-43524fbfgsa
This will give you the distinct ID values from your JArray, filtering out possible nulls:
jArray = JArray.Parse(resp);
var ids = jArray.Children<JObject>()
.Select(jo => (string)jo["ID"]) // NOTE: this is case sensitive
.Where(s => s != null)
.Distinct()
.ToList();
Demo here: https://dotnetfiddle.net/gaQ1n0
Best way is to create the object with the properties timestamp, id and message- then deserialize the json to this object.
But for now you can try below and should work out well for you.
JArray jArray = new JArray();
jArray = JArray.Parse(#"[
{
""Timestamp"": ""2020-11-24T08:25:46.6531855Z"",
""ID"": ""8c316aca-b930-421f-851c-17d618b61fa1"",
""Message"": ""New User Registered""
},
{
""Timestamp"": ""2020-11-24T08:25:46.6531855Z"",
""ID"": ""8c316aca-b930-421f-851c-17d618b61fa1"",
""Message"": ""User details updated""
},
{
""Timestamp"": ""2020-11-24T08:25:46.6531855Z"",
""ID"":""a23shaga-2wd3-fky6-851c-43524fbfgsa"",
""Message"": ""New User Registered""
}]");
var newList = jArray.Where(y=> !string.IsNullOrEmpty(y["ID"].ToString()))
.GroupBy(x => x["ID"])
.Select(x => x.First()).ToList();
foreach (var item in newList)
{
Console.WriteLine(item["ID"]);
}
Here newList contains only unique data w.r.t 'ID'
Just replace the entire string in my example with the async resp you are getting.
NOTE : You should either make the source return unique or create a new object and deserialize it instead of using JObject, this will help you when you have bigger lists
So below is the outcome i think you are looking for
I got the json response from dialogflow. Now I want to get the "q1" value. So I've tried this:
var stringjson = ApiAiJson<QueryResponse>.Serialize(queryResponse);
var deserializejson =ApiAiJson<QueryResponse>.Deserialize(stringjson);
if (deserializejson.Result.Action == "web.search")
{
JObject jsonob = JObject.Parse(stringjson);
string q = jsonob["parameters"]["q1"].ToString();
System.Console.WriteLine(q);
}
But string q returns "null".
Maybe the deserialisation is wrong. The value is embedded in parameters and not the root value. But I don't know how to get the root value of json.
Plus,here's the json response:
"result": {
"source": "agent",
"resolvedQuery": "search for apple",
"action": "web.search",
"actionIncomplete": false,
"parameters": {
"q1": "apple",
"q2": ""
},
Help!
Use below code:
q = jsonob["result"]["parameters"]["q1"].ToString();