Discard items when deserializing Json collection with Json.net - c#

I have a JSON stream that sends collections looking like this:
[{"channel":"24e67e0d-1cad-4cc09e7af8523ef460fe",
"op":"private",
"origin":"broadcast",
"stamp":1388680103991749},
"13886801043507640",
"24e67e0d-1cad-4cc0-9e7a-f8523ef460fe"]
The first object is no problem, but the last two ones ("13886801043507640" and "24e67e0d-1cad-4cc0-9e7a-f8523ef460fe") make Json.Net throw exceptions they don't even follow the format {field:name,field:name}.
How can I handle these objects properly (or at least discard them) using Json.Net?
Cheers, any input is appreciated.

Here is one approach to extract the object data from the JSON using Json.Net.
First define a class for the object:
class Item
{
public string channel { get; set; }
public string op { get; set; }
public string origin { get; set; }
public long stamp { get; set; }
}
Then use Json.Net's LINQ-to-JSON API to parse and filter the array, extracting only the object part:
JArray array = JArray.Parse(json);
Item item = array.Children<JObject>().First().ToObject<Item>();
If there can be multiple objects, you can get them into a list like this (assuming they all have the same structure):
List<Item> items = array.Children<JObject>()
.Select(jo => jo.ToObject<Item>())
.ToList();
Similarly, you can get the string values from the array like this:
List<string> strings = array.Children<JValue>()
.Select(jv => jv.ToString())
.ToList();

Related

Newsoft Json deserialize into products Collection not working

I am creating a windows phone silver light 8 app.
I have a Json string and I am trying to convert it into a List of objects and each object is a object of a class classed "Product" and list is supposed to be products. ultimately I want it to convert into Observable collection so that I can bind that collection to my listbox in my windows Silverlight phone app.
Here is my class
public class Product
{
public string _id { get; set; }
public string code { get; set; }
public string name { get; set; }
public string imgAddress { get; set; }
public int queryCount { get; set; }
}
Here is code to deserialize the json
var PDS = "{\"products\":[{\"_id\":\"58b2\",\"code\":\"59034\",\"name\":\"somename1\",\"imgAddress\":\"https://someimageurl/.../.jpg\",\"queryCount\":0},{\"_id\":\"58b3\",\"code\":\"59035\",\"name\":\"somename2\",\"imgAddress\":\"https://someimageurl2/.../.jpg\",\"queryCount\":1}]}";
var pds = JsonConvert.DeserializeObject<List<Product>>(PDS);
//PDS is actually very long string and the array products has a lot of objects but I am only writing 2 products here for simplicity.
Here is my collection for binding
public ObservableCollection<Product> Products { get; set; }
ERRORS
>> First I was getting parsing error so I escaped all quotes within the string like this \"
**>>**But then it was only converting to a normal string like object but I want to convert to a collection of products of type "Product"
>> Exception
Additional information: Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.List`1[PivotApp1.Product]' 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 'products', line 1, position 12.
Thanks in advance
You can deserialize it this way (but you'll have somehow to reformat your JSON string):
from
var PDS = "{"products":[{"_id":"58b2","code":"59034","name":"somename1","imgAddress":"https://someimageurl/.../.jpg","queryCount":0},{"_id":"58b3","code":"59035","name":"somename2","imgAddress":"https://someimageurl2/.../.jpg","queryCount":1}]}";
//PDS is actually very long string and the array products has a lot of objects but I am only writing 2 products here for simplicity.
to
var PDS = "[{'_id':'58b2','code':'59034','name':'somename1','imgAddress':'https://someimageurl/.../.jpg','queryCount':0},{'_id':'58b3','code':'59035','name':'somename2','imgAddress':'https://someimageurl2/.../.jpg','queryCount':1}]";
//PDS is actually very long string and the array products has a lot of objects but I am only writing 2 products here for simplicity.
Then
var pds = JsonConvert.DeserializeObject<List<Product>>(PDS);
More infos --> Deserialize a collection
No need of creating another class as suggested!
EDIT:
Actually you get this exception because your JSON string represents an object 'products' containing a list of 'Product' and this doesn't directly relate to your root class.
This is what your current JSON look like:
Your JSON string result should be something like that instead:
var PDS = "[{'_id':'58b2','code':'59034','name':'somename1','imgAddress':'https://someimageurl/.../.jpg','queryCount':0},{'_id':'58b3','code':'59035','name':'somename2','imgAddress':'https://someimageurl2/.../.jpg','queryCount':1}]";
Represented as following (notice the slight difference):
Using this JSON string, it will work with no exception raised:
var pds = JsonConvert.DeserializeObject<List<Product>>(PDS);
Or, if you can't change the resulting JSON string in PDS, you can do what J. Tuc suggested (via a new "RootClass").
your JSON string had to be changed to get the code to compile:
var PDS = "{'products':[{'_id':'58b2','code':'59034','name':'somename1','imgAddress':'https://someimageurl/.../.jpg','queryCount':0},{'_id':'58b3','code':'59035','name':'somename2','imgAddress':'https://someimageurl2/.../.jpg','queryCount':1}]}";
You need another object with a collection of Product as a property called products in order to deserialize your JSON
This may not be the best solution but it works:
Create another class:
public class RootObject
{
public List<Product> products;
}
use this code to deserialize your JSON:
var pds = JsonConvert.DeserializeObject(PDS, typeof(RootObject));
if you are in control of your JSON string you might consider changing it to this (removing 'products' property and ending up with just an array of products in the JSON string):
var PDS = "[{'_id':'58b2','code':'59034','name':'somename1','imgAddress':'https://someimageurl/.../.jpg','queryCount':0},{'_id':'58b3','code':'59035','name':'somename2','imgAddress':'https://someimageurl2/.../.jpg','queryCount':1}]";
Then you might be able to use the solution proposed by TaiT's (deserializing directly to a List of Product) :
var pds = JsonConvert.DeserializeObject<List<Product>>(PDS);

Deserializing an unnamed array

I am having difficulty writing the appropriate annotations to represent data which is returned from a JSON Get request which returns data like so:
[{"ProductCode":"0129923083091","Description":"DIESEL ","SalesLitres":6058.7347,"SalesValue":6416.2000},{"ProductCode":"0134039344902","Description":"UNLEADED ","SalesLitres":3489.8111,"SalesValue":3695.7100},
...
]
(ellipsis above just indicating that I could have variable number of these items returned)
In my model class (I am using MVVM approach for a Xamarin project but that's not over relevant here) I am using annotations to represent the model attributes
namespace App8.Models
{
public class ReportRow
{
[JsonProperty("ProductCode")]
public string ProductCode { get; set; } = string.Empty;
[JsonProperty("Description")]
public string Description { get; set; } = string.Empty;
[JsonProperty("SalesLitres")]
public double SalesLitres { get; set; } = 0.0;
[JsonProperty("SalesValue")]
public double SalesValue { get; set; } = 0.0;
}
}
I would like to annote another class which shows the container/contained relationship. However, I coming unstuck as there is no JSON attribute to provide in the annotation to represent the "root" of the returned collection.
I'd have no problem mapping the JSON to an object model for any JSON arrays which are named within the returned JSON. In that case I could create another class with a named JSON attribute which contained a C# List but I am trying to provide an appropriate model mapping for JSON which returns a list of items within an unnamed array.
Any ideas how I could approach this?
To deserialize that JSON, use:
JsonConvert.DeserializeObject<List<ReportRow>>(json)
(or any variant you wish, the key here is asking to deserialize a ICollection of ReportRow. It could be your own class implementing ICollection, or any of the builtins)
The same idea follows to JsonTextReader or whatever other means of deserializing JSON.NET offers. Just use a ICollection<YourType> as target type.

.NET Json Serialization Exception for C#

I'm using JSON.net in C# for an Excel VSTO Add in and pulling in JSON via web service.
I have verified the JSON I pull is valid (online JSON Validator) but am unable to convert the JSON into Objects in C# to use.
When I run the code below I get the exception below.
Any ideas on who I can covert the JSON correctly?
Exception:
Newtonsoft.Json.JsonSerializationException:
Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'Bliss.Ribbon1+RootObject[]'
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<T>)
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.
Code:
public async Task<string> getline()
{
<--- Set Client, Execute Request --->
//JSON content shown below
string content = await response.Content.ReadAsStringAsync();
RootObject[] dims = JsonConvert.DeserializeObject<RootObject[]>(content);
return content;
}
public class RootObject
{
public List<string> ledger { get; set; }
public List<string> ledgerAlias { get; set; }
public List<string> entity { get; set; }
public List<string> entityAlias { get; set; }
public List<string> scenario { get; set; }
public List<string> period { get; set; }
public List<string> location { get; set; }
public List<string> measures { get; set; }
}
JSON:
{
"acc":["A","B"],
"accAlias":["ACE","BCE"],
"company":["PEP", "KO"],
"companyAlias":["Pepsi", "Coco-Cola"],
"scenario":["Sales", "Expenses"],
"year": ["2016","2017"],
"areaCode":["123","131","412"],
"clients":["32340-0120","3031-0211","3412-0142"]
}
The JSON represents a single instance of the object, not an array. So instead of this:
RootObject[] dims = JsonConvert.DeserializeObject<RootObject[]>(content)
use this:
RootObject dims = JsonConvert.DeserializeObject<RootObject>(content)
Conversely, if it should be an array, make the JSON itself an array (containing a single element) by surrounding it with brackets:
[{
"acc":["A","B"],
"accAlias":["ACE","BCE"],
"company":["PEP", "KO"],
"companyAlias":["Pepsi", "Coco-Cola"],
"scenario":["Sales", "Expenses"],
"year": ["2016","2017"],
"areaCode":["123","131","412"],
"clients":["32340-0120","3031-0211","3412-0142"]
}]
Edit: As others have also been pointing out, the properties on the JSON object don't actually match that class definition. So while it may "successfully" deserialize, in doing so it's going to ignore the JSON properties it doesn't care about and initialize to default values the class properties.
Perhaps you meant to use a different class? Or different JSON? Or rename one or more properties in one or the other?
Either way, the difference between a single instance and an array of instances is the immediate problem. But in correcting that problem you're going to move on to this next one.
The RootObject and the json are not compatible. You could deserialize using a dictionary. Try this:
var dims = JsonConvert.DeserializeObject<Dictionary<string, string[]>>(content);

iterating through objects of response JSON

I'm doing a query and get as result something like this, which i put into a Hashtable
{"success":"true", "result":[{"type":"email", "address":"aaasd#asd.com"},{"type":"email", "address":"aaasddee#dse.com"}]}
then i do
return hashtable["result"];
so I only have this left
[{"type":"email", "address":"aaasd#asd.com"},{"type":"email", "address":"aaasddee#dse.com"}]
but my problem is that I don't know how to iterate through every object from "result" to fill my own objects. I was searching for a solution but the only answer I found was to use
foreach(DictionaryEntry entry in searchResult) {
//do something<br>
}
When I iterate through the Hashtable like this I can only use the properties entry.Key and entry.Value but I can't say which value for a specific key I need. Any suggestions are welcome.
You can get it using deserialising using JSON.NET as shown below :-
var result = JsonConvert.DeserializeObject<dynamic>(searchResult);
You can create your class like below :-
public class RootObject
{
public string type { get; set; }
public string address { get; set; }
}
For more information :-
http://james.newtonking.com/json/help/index.html?topic=html/SerializingJSON.htm
Create a class that matches the signature of the result collection like:
public class Result
{
public string Type { get; set; }
public string Address { get; set; }
}
Then use Json.NET to parse the result node into a List<Result>. There is plenty of documentation online on how to use the Json.NET library.
Hope that helps,
Rob

Separating array and element from a JSON string

I am connecting you Google Places API to retrive results in the form of a JSON string. You can view the complete format of the string Here.
If you a look at it you will see that the actual results array starts after two elements which are html_attributions and next_page_token.
So When i try to deserialize it in this way:
var serializer = new JavaScriptSerializer();
var arr= serializer.Deserialize(result,typeof(string[]));
I get an empty array.
My question is how is there a way i can separate html_attributions and next_page_token fields and the pass the valid results array from the string to be deserialized?
I don't understand the part where you wish to seperate the html_attributions and the next_page_token.
Wouldn't it be sufficient to just deserialize the response with whatever properties that you need?
For example, you can deserialize the response to only retrieve the values that you desire;
// I represent the wrapper result
class Result
{
public List<string> html_attributions { get; set; }
public string next_page_token { get; set; }
public List<ResultItem> results { get; set; }
}
// I represent a result item
class ResultItem
{
public string id { get; set; }
public string name { get; set; }
}
// the actual deserialization
Result Deserialize(string json)
{
var serializer = new JavaScriptSerializer();
return serializer.Deserialize(json, typeof(Result));
}
Edit:
The reason that your deserialization doesn't return you a array of strings is because the response that you retrieve is infact an object and not an array, however the parameter within that object which is named results is an array. In order for you to deserialize more properties you'll have to define them in your "ResultItem" class, sorry for my poor naming here.
For instance, if you'd wish to also retrieve the icon property per result you'll have to add a property named "icon" of type string.
Meanwhile the property "photos" is an array, in order to deserialize it you'll have to create another class and add a property of type list/array of that newly created class, and it has to be named "photos" unless you use a different serializer or use DataContract and DataMember attributes (using the Name property for field mapping).
// the representation of a photo within a result item
class Photo
{
public int height { get; set; }
public List<string> html_attributions { get; set; }
public string photo_reference { get; set; }
public int width { get; set; }
}
// I represent a result item
class ResultItem
{
public string id { get; set; }
public string name { get; set; }
// the added icon
public string icon { get; set; }
// the added photos collection, could also be an array
public List<Photo> photos { get; set; }
}
Just look at the JSON result to figure out what other properties that you might want to add, for instance the "scope" property is an string whilst the "price_level" is an integer.
If I understand your comment correctly you're only interested in the actual results, you'll still have to deserialize the response correctly with its wrapper.
// the actual deserialization
List<ResultItem> Deserialize(string json)
{
var serializer = new JavaScriptSerializer();
var result = serializer.Deserialize(json, typeof(Result));
return result.results;
}
Edit2:
If you really want a string[] as a result you could simply take use of System.Linq using the code above.
string[] stringArray = result.results.Select(r => string.Format("id:{0} - name:{1}", r.id, r.name)).ToArray();
Edit3:
Instead of using the JavascriptSerializer you could use JObject functionality which can be found in the Newtonsoft.Json.Linq library.
var jsonObject = JObject.Parse(json);
string[] results = jsonObject.SelectTokens("results").Select(r => r.ToString()).ToArray();
This will give you an array of strings where each value within the array is the actual json string for each result.
If you however would like to query for the coordinates only:
var jsonObject = JObject.Parse(json);
var coordinates = jsonObject["results"]
.Select(x => x.SelectToken("geometry").SelectToken("location"))
.Select(x => string.Format("{0},{1}", (string)x.SelectToken("lat"), (string)x.SelectToken("lng")))
.ToArray();
This would give you an array of coordinates, eg:
[
"-33.867217,151.195939",
"-33.866786,151.195633",
...
]
Whatever approach you choose you'll be able to accomplish same results using either Newtonsoft or the .net serializer, whilst the Newtonsoft approach would allow you to query without creating strong types for deserialization.
I don't find the point of "[...] pass the valid results array from the string to be deserialized".
Maybe you need to switch to JSON.NET and do something like this:
// You simply deserialize the entire response to an ExpandoObject
// so you don't need a concrete type to deserialize the whole response...
dynamic responseEntity = JsonConvert.DeserializeObject<ExpandoObject>(
googlePlacesJson, new ExpandoObjectConverter()
);
// Now you can access result array as an `IEnumerable<dynamic>`...
IEnumerable<dynamic> results = responseEntity.results;
foreach(dynamic result in results)
{
// Do stuff for each result in the whole response...
}

Categories

Resources