I'm working with an API that is returning JSON.
I have a method that calls the api, and parses the JSON response for the desired nodes.
Up to this point everything has been working fine, except the latest JSON response appears to be malformed.
Other responses come back like:
{
"Keyword":"\"marhope\"",
"TermKey":null,
"Customers":[
{
"Memberships":[ ],
"CompanyId":0,
"ObjectId":112974,
"ObjectType":"Customer",
}
]
}
I use JObject.Parse to bring back the appropriate nodes by name.
The latest JSON response comes back as:
{
[
{
"AnimalId":9079117,
"SpeciesCode":"XX",
}
]
}
As you can see, there is no "name", and the JSON is slightly invalid.
How can I parse this. For the first example I was using the code below, but now that the JSON has no "name", I don't know how to approach this, thoughts?
JObject results = JObject.Parse(csr.SearchCustomer(1, 1, 870, term));
foreach (var resp in results["Customers"])
{
string obj = (string)resp["CompanyId"];
}
Jon Skeet is correct, the second JSON is invalid: you cannot have an array directly inside an object with no property name. The best course of action is to get the API developers to fix the JSON. However, if you're just looking for a quick and dirty workaround, you could strip off the the first and last brace from the invalid JSON and then parse it as an array using JArray.Parse.
string json = #"{
[
{
""AnimalId"":9079117,
""SpeciesCode"":""XX"",
}
]
}";
json = json.Substring(1, json.Length - 2);
JArray array = JArray.Parse(json);
foreach (JObject item in array.Children<JObject>())
{
Console.WriteLine("AnimalId: " + item["AnimalId"]);
Console.WriteLine("SpeciesCode: " + item["SpeciesCode"]);
}
Related
Hey everyone i'm trying to use the v3 Data Youtube API, already have the Request itself and the response looks like this
{
"items": [
{
"snippet": {
"publishedAt": "2016-12-07T16:04:40.472Z",
"displayMessage": "a"
}
}
]
}
The Problem is that i only want the last Comment and not the whole 200(cant be set lower) my first Idea was to Save the whole Response and Compare it to the next one so i know whats new, but that wont really work out
Ok, so from the comments, I gather you are talking about the Live Streaming API.
What you get back are messages, not comments. And yes, as the doc says, "Acceptable values are 200 to 2000, inclusive. The default value is 500." So, you could get the whole 200, and then sort on the timestamp to get the latest message.
How to do that?
As you are doing this in C#, once you have the json string, you need to use some library such as Json.NET. Once you add a NuGet package reference to this, you will need
using Newtonsoft.Json.Linq;
and say your json string is
var json = #"{
""items"": [
{
""snippet"": {
""publishedAt"": ""2016-12-07T16:04:40.472Z"",
""displayMessage"": ""a""
}
}
,
{
""snippet"": {
""publishedAt"": ""2016-12-12T16:04:40.472Z"",
""displayMessage"": ""b""
}
}
]
}";
Then, as described in this documentation, use JObject.Parse to use LINQ to JSON.
var parsedJson = JObject.Parse(json);
JArray items = parsedJson.SelectToken("items") as JArray;
var sortedItems = items.OrderByDescending(item => item["snippet"]["publishedAt"]);
// sortedItems.First() will give you the item with the newest timestamp
Have put all of this at https://dotnetfiddle.net/ubQAZV.
Alternately, you can use JsonConvert if you prefer to deserialize to strongly-typed code.
More about it here.
I am trying to read child elements in the Json object below. Below is the Json example. I want to read RecommendedCount and TotalReviewCount in testdata1, testdata2 and testdata3.
{
"HasErrors": false,
"Includes": {
"test ": {
"testdata1": {
"ReviewStatistics": {
"RecommendedCount": 0,
"TotalReviewCount": 2
}
},
"testdata2": {
"ReviewStatistics": {
"RecommendedCount": 0,
"TotalReviewCount": 2
}
},
"testdata3": {
"ReviewStatistics": {
"RecommendedCount": 0,
"TotalReviewCount": 2
}
}
}
}
}
I tried the code below.
RecommendedCount = apiResponse.Includes.Products[key].ReviewStatistics.RecommendedCount,
TotalReviewCount = apiResponse.Includes.Products[key].ReviewStatistics.TotalReviewCount
But this is very slow as the Json response has more than 1000 lines so it is taking time. I want to know is there any linq i can use to find the relevant data or any other methods i can use?
Thanks in advance.
var jObj = (JObject)JsonConvert.DeserializeObject(rawJson);
foreach (var child in jObj["test"].Children())
{
}
The above is the deserialize code i am trying to use but getting Object reference not set to an instance of an object. error
My solution:
JObject obj = JObject.Parse(jsonString);
var recList= obj.SelectTokens("$..ReviewStatistics.RecommendedCount").ToList();
var totalList= obj.SelectTokens("$..ReviewStatistics.TotalReviewCount").ToList();
Then you can get the data that you want. For example, if you want RecommendedCount from testdata2, you do like this
var dataYouWant = (int)recList[1];
References:
http://www.newtonsoft.com/json/help/html/LINQtoJSON.htm
Deserializing JSON to .NET object using Newtonsoft (or LINQ to JSON maybe?)
https://msdn.microsoft.com/en-us/library/cc197957(v=vs.95).aspx
If there is anything wrong, please feel free to correct my answer. Thanks!
I suspect the problem is in your Json you have a space in the field "test " which is causing a null reference exception.
I'm not entirely sure whether is it copy paste mistake or your getting Json string in this format.
Check this working code on removing the space.
I receive this JSON response (but I'm not even sure if this is valid JSON. is it?):
"{\"fields\":\"Name,ParentName,Description,StartDate,EndDate,StartMinute,EndMinute\",\"pos\":0,\"start\":0,\"totalRecords\":1001881,\"data\":[[null,\"AAEC 3400 76142\",null,\"2014-05-15T00:00:00\",\"2014-05-15T00:00:00\",840,1050],[null,\"AAEC 3400 76142\",null,\"2014-05-28T00:00:00\",\"2014-05-28T00:00:00\",840,1050],[null,\"ACCT 5400 25030\",null,\"2014-01-08T00:00:00\",\"2014-01-08T00:00:00\",1215,1290],[null,\"ACCT 5400 25030\",null,\"2014-02-19T00:00:00\",\"2014-02-19T00:00:00\",1215,1290]]}"
Is it possible to deserialize this response and access particular values using Newtonsoft JSON package, with or without the LINQ namespace? Can I access specific values from the "data" key?
Currently, my approach is to manipulate this JSON response into regular JSON, so instead of just having a "fields" key and a "data" key followed by lists of values, I end up deserializing normal JSON key/value pairs (like "Name":"null", "ParentName":"AAEC 3400 76142\", . . . ). Then I can access each object in the list's values by key.
But is it possible to access specific values keeping the response the way it came, without parsing/manipulating it, using Newtonsoft JSON package with/without methods in LINQ namespace?
This is how I'm deserializing the json string that I parse/manipulated manually into normal JSON:
var myList = JsonConvert.DeserializeObject<List<MyClass>>(json);
Then I can access values by key off of specific objects in the response by index:
String name = myList[0].Name;
But can I access the value of myList[0].Name without reformatting the JSON response into typical key:value pairs? Does Newtonsoft provide a way to access the value I want from the response the way it came?
Looks like that JSON has been double-serialized. I.e. some class was serialized as a JSON string, then that string was serialized as JSON again, causing JSON control characters including {,} and " characters to be escaped.
This is almost certainly a bug on the server side, you should try to get it fixed there. But if you cannot (for political reasons, say), you can check for this and work around it on the client side:
var token = JToken.Parse(json);
if (token.Type == JTokenType.String)
token = JToken.Parse((string)token);
var myList = token.ToObject<List<MyClass>>();
Update: your root JSON container is an object, not an array, so ToObject<List<MyClass>> won't work. The unwrapped JSON looks like:
{
"fields": "Name,ParentName,Description,StartDate,EndDate,StartMinute,EndMinute",
"pos": 0,
"start": 0,
"totalRecords": 1001881,
"data": [
[
null,
"AAEC 3400 76142",
null,
"2014-05-15T00:00:00",
"2014-05-15T00:00:00",
840,
1050
],
// More of the same
]
}
If you wanted to reformat that into a more traditional array of JSON objects, you could restructure your root JToken like so:
var token = JToken.Parse(json);
if (token.Type == JTokenType.String)
token = JToken.Parse((string)token);
var fields = (string)token.SelectToken("fields");
var fieldList = fields.Split(',');
var root = new JArray();
root.Add(token.SelectTokens("data[*]").OfType<JArray>().Select(a => new JObject(a.Zip(fieldList, (t, s) => new JProperty(s, t)))));
Debug.WriteLine(root);
With the result:
[
{
"Name": null,
"ParentName": "AAEC 3400 76142",
"Description": null,
"StartDate": "2014-05-15T00:00:00",
"EndDate": "2014-05-15T00:00:00",
"StartMinute": 840,
"EndMinute": 1050
},
// More of the same
]
Yes. It is straightforward and simple to deserialize a JSON response formatted in this way using the Newtonsoft JSON package with LINQ namespace. You don't have to manipulate the response string by hand. Set the JSON response string to a string object named "response", use JObject.Parse() to create a dynamic object "jobject", then you can access the "data" JSON key and set it to a JArray object. Then you can loop through each JToken in "jArray". Finally, get the values by their index in the JArray:
dynamic jobject = JObject.Parse(response);
JArray jArray = jobject.data;
foreach (JToken appointment in jArray)
{
parentName = appointment[1];
startMinute = appointment[5];
. . .
}
I am having trouble working with an API, first time I've worked with one. I've managed to use GET to read the data I need and that part is working perfectly, now I need to deserialize the JSON data I am getting back, and I am using Newtonsoft's JSON .NET library. The problem seems to come when I deserialize the data as its exploding and the debugger isn't being helpful. I tried a few suggestions online but no go, so if someone can enlighten me it'd be appreciated. This is the code:
string url = "";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream receiveStream = response.GetResponseStream();
StreamReader readStream = new StreamReader(receiveStream, Encoding.UTF8);
string responseData = readStream.ReadToEnd();
var results = JsonConvert.DeserializeObject<dynamic>(responseData);
var id = results["id"].Value;
// var name = results.Name;
When I run it the debugger throws the following exception at the last line of code:
{"Accessed JArray values with invalid key value: \"id\". Array position index expected."}
I am fairly sure that ID exists in the data I am getting back.
Json data I am getting back from Smarty Streets:
[
{
"id": 0,
"candidate_index": 0,
"delivery_line_1": "1600 Amphitheatre Pkwy",
"last_line": "Mountain View CA 94043-1351",
"delivery_point_barcode": "940431351000",
"components": {
"primary_number": "1600",
"street_name": "Amphitheatre",
"street_suffix": "Pkwy",
"city_name": "Mountain View",
"state_abbreviation": "CA",
"zipcode": "94043",
"plus4_code": "1351",
"delivery_point": "00",
"delivery_point_check_digit": "0"
},
]
Your response is an array not a single object. So You should use
JArray results = JArray.Parse(responseData)
to parse the result (like results[0]["id"]). If you go the dynamic way then
dynamic results = JArray.Parse(responseData)
Now, you can use it like results[0].id
Another option is to "Paste JSON as classes" so it can be deserialised quick and easy.
Simply copy your entire JSON
In VS: Click Edit > Paste Special >
Paste JSON as classes
Here is a better explanation n piccas...
https://blogs.msdn.microsoft.com/webdev/2012/12/18/paste-json-as-classes-in-asp-net-and-web-tools-2012-2-rc/
Your result appears to be an array of objects, not an array itself. Try setting id to results["id"][0].Value and see if you get something.
See this: Accessed JArray values with invalid key value: "fields". Array position index expected
I'm having trouble converting a string of json facebook graph api, I used the facebook C# and json.Net.
But at conversion time it returns this error: Name can not begin with the '0 'character, hexadecimal value 0x30.
This is the code:
dynamic result = await _fb.GetTaskAsync ("me / feed");
FBxml JsonConvert.DeserializeXNode string = (result.ToString ()). ToString ();
It looks like there is a problem with portion of the json string as mentioned below (taken from your link http://jsfiddle.net/btripoloni/PaLC2/)
"story_tags": {
"0": [{
"id": "100000866891334",
"name": "Bruno Tripoloni",
"offset": 0,
"length": 15,
"type": "user"}]
},
Json cannot create class that begins with a numeric value such as '0'. Try creating the classes using the link http://json2csharp.com/ you will get an idea.
To solve this problem you can create a dynamic object and go through each properties OR create a JsonConverter and write your code in the ReadJson to convert the "0" to a meaningful name. May be this can help you http://blog.maskalik.com/asp-net/json-net-implement-custom-serialization
If this is not your problem then update the question with more information like class structure of FBxml, call stack of the exception (from which line of the json code is throwing the exception), Json version etc.
As keyr says, the problem is with those JSON properties that have numeric names. In XML names can contain numeric characters but cannot begin with one: XML (see the Well-formedness and error-handling section).
My idea was to recursively parse the JSON with JSON.Net, replacing properties that had numeric names:
var jsonObject = JObject.Parse(json);
foreach (var obj in jsonObject)
{
Process(obj.Value);
}
XDocument document = JsonConvert.DeserializeXNode(jsonObject.ToString());
....
private static void Process(JToken jToken)
{
if (jToken.Type == JTokenType.Property)
{
JProperty property = jToken as JProperty;
int value;
if (int.TryParse(property.Name, out value))
{
JToken token = new JProperty("_" + property.Name, property.Value);
jToken.Replace(token);
}
}
if (jToken.HasValues)
{
//foreach won't work here as the call to jToken.Replace(token) above
//results in the collection modifed error.
for(int i = 0; i < jToken.Values().Count(); i++)
{
JToken obj = jToken.Values().ElementAt(i);
Process(obj);
}
}
}
This seemed to work well, prefixing numeric names with _. At this line:
XDocument document = JsonConvert.DeserializeXNode(jsonObject.ToString());
it crashed with an error saying that invalid/not well formed XML had been created. I don't have the actual error with me, but you can run the above code to replicate it.
I think from here you may need to revisit converting the JSON to XML in the first place. Is this a specific requirement?