Json C# : deserializing a changing content or a piece of json response
I use an Api that is returning not everytime the same response based in the place demanded. Some places have more details, some contents have more attributes that others. The resulting serialized object is not the same everytime resulting in deserializing error when not match. The object of this project is not match the entire content response, but only one piece of this content : the Centroid.
{
"place":{
"woeid":12345,
"placeTypeName":"State",
"placeTypeName attrs":{
"code":8
},
"name":"My Region",
"country":"",
"country attrs":{
"type":"Country",
"code":"XX"
},
"admin1":"My Region",
"admin1 attrs":{
"type":"Region",
"code":""
},
"admin2":"",
"admin3":"",
"locality1":"",
"locality2":"",
"postal":"",
"centroid":{
"latitude":30.12345,
"longitude":40.761292
},
"boundingBox":{
"southWest":{
"latitude":32.2799,
"longitude":50.715958
},
"northEast":{
"latitude":29.024891,
"longitude":12.1234
}
},
"areaRank":10,
"popRank":0,
"uri":"http:\/\/where.yahooapis.com",
"lang":"en-US"
}
}
Can someone point the best method to deserialize a piece of content instead the complete response (centroid not at same place), or to deserialize a changing response schema.
I use ServiceStack C# serializer but all propositions are wel开发者_JS百科come. Thanks.
There's actually a few ways you can parse this using ServiceStack's JsonSerializer as can be seen in this example of parsing one of GitHub's JSON API.
I would take the JsonObject approach as you get to end up with the C# class of your choice, although it does require more than the 1-liner that you're used to with ServiceStack's JsonSerializer. Anyway here's the resulting code:
Func<JsonObject, Centroid> toCentroid = map =>
new Centroid(map.Get<decimal>("latitude"), map.Get<decimal>("longitude"));
var place = JsonObject.Parse(JsonCentroid)
.Object("place")
.ConvertTo(x => new Place
{
WoeId = x.Get<int>("woeid"),
PlaceTypeName = x.Get(""),
PlaceTypeNameAttrs = x.Object("placeTypeName attrs"),
Name = x.Get("Name"),
Country = x.Get("Country"),
CountryAttrs = x.Object("country attrs"),
Admin1 = x.Get("admin1"),
Admin1Attrs = x.Object("admin1 attrs"),
Admin2 = x.Get("admin2"),
Admin3 = x.Get("admin3"),
Locality1 = x.Get("locality1"),
Locality2 = x.Get("locality2"),
Postal = x.Get("postal"),
Centroid = x.Object("centroid")
.ConvertTo(toCentroid),
BoundingBox = x.Object("boundingBox")
.ConvertTo(y => new BoundingBox
{
SouthWest = y.Object("southWest").ConvertTo(toCentroid),
NorthEast = y.Object("northEast").ConvertTo(toCentroid)
}),
AreaRank = x.Get<int>("areaRank"),
PopRank = x.Get<int>("popRank"),
Uri = x.Get("uri"),
Lang = x.Get("lang"),
});
Here is the full source code of this example.
You could use the DataContractJsonSerializer that's part of the standard .NET framework. You define just those attributes you're interested in. The other ones will be ignored.
class CentroidReader
{
public static Centroid ReadControid(Stream stream)
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(Response));
Response response = serializer.ReadObject(stream) as Response;
return response.Place.Centroid;
}
}
[DataContract]
class Response
{
[DataMember(Name = "place")]
public Place Place { get; set; }
}
[DataContract]
class Place
{
[DataMember(Name = "centroid")]
public Centroid Centroid { get; set; }
}
[DataContract]
class Centroid
{
[DataMember(Name = "latitude")]
public double? Latitude { get; set; }
[DataMember(Name = "longitude")]
public double? Longitude { get; set; }
}
精彩评论