问题
Help me parse the json
with Newtonsoft.Json
.
{
"_id": 160,
"location": {
"type": "Point",
"coordinates": [43.59043144045182, 39.72119003534317]
},
},
{
"_id": 161,
"location": {
"type": "LineString",
"coordinates": [
[43.58780105200211, 39.719191789627075],
[43.58817794899264, 39.719465374946594]
]
},
},
{
"_id": 152,
"location": {
"type": "Polygon",
"coordinates": [
[43.590524759627954, 39.71930980682373],
[43.590474249766544, 39.71926689147949],
[43.59043151061995, 39.71934735774994],
[43.59073456936772, 39.71958339214325],
[43.59076565222992, 39.71949219703674]
]
},
}
Key coordinates
has type List<double>
or List<List<double>>
depending on the key type
(Polygon, LineString, Point).
回答1:
You can solve this problem using a custom JsonConverter
. The converter can load the data for each shape, look at the type
field and then populate the coordinates array accordingly. And actually, if you want, the converter can do double-duty here to flatten the data down into a simpler class structure while we're at it. Here's how I would do it, given the JSON you have presented.
First, define a class to hold the deserialized shape data. We'll deserialize into a list of these:
class Shape
{
public int Id { get; set; }
public string Type { get; set; }
public List<List<double>> Coordinates { get; set; }
}
Next create the converter class. This is responsible for transforming the JSON for each shape into a concrete Shape
object.
class ShapeConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(Shape));
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject jo = JObject.Load(reader);
Shape shape = new Shape();
shape.Id = (int)jo["_id"];
shape.Type = (string)jo["location"]["type"];
JArray ja = (JArray)jo["location"]["coordinates"];
if (shape.Type == "Point")
{
shape.Coordinates = new List<List<double>>();
shape.Coordinates.Add(ja.ToObject<List<double>>());
}
else
{
shape.Coordinates = ja.ToObject<List<List<double>>>();
}
return shape;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
Add a [JsonConverter]
attribute to the Shape
class to tie it to the ShapeConverter
:
[JsonConverter(typeof(ShapeConverter))]
class Shape
{
...
}
All that is left is to deserialize the JSON, which we can do like this:
List<Shape> shapes = JsonConvert.DeserializeObject<List<Shape>>(json);
Here is a test program to demonstrate:
class Program
{
static void Main(string[] args)
{
string json = @"
[
{
""_id"": 160,
""location"": {
""type"": ""Point"",
""coordinates"": [ 43.59043144045182, 39.72119003534317 ]
}
},
{
""_id"": 161,
""location"": {
""type"": ""LineString"",
""coordinates"": [
[ 43.58780105200211, 39.719191789627075 ],
[ 43.58817794899264, 39.719465374946594 ]
]
}
},
{
""_id"": 152,
""location"": {
""type"": ""Polygon"",
""coordinates"": [
[ 43.590524759627954, 39.71930980682373 ],
[ 43.590474249766544, 39.71926689147949 ],
[ 43.59043151061995, 39.71934735774994 ],
[ 43.59073456936772, 39.71958339214325 ],
[ 43.59076565222992, 39.71949219703674 ]
]
}
}
]";
List<Shape> shapes = JsonConvert.DeserializeObject<List<Shape>>(json);
foreach (Shape shape in shapes)
{
Console.WriteLine("Id: " + shape.Id);
Console.WriteLine("Type: " + shape.Type);
Console.WriteLine("Coordinates: ");
foreach (List<double> point in shape.Coordinates)
{
Console.WriteLine(" (" + point[0] + ", " + point[1] + ")");
}
Console.WriteLine();
}
}
}
Output:
Id: 160
Type: Point
Coordinates:
(43.5904314404518, 39.7211900353432)
Id: 161
Type: LineString
Coordinates:
(43.5878010520021, 39.7191917896271)
(43.5881779489926, 39.7194653749466)
Id: 152
Type: Polygon
Coordinates:
(43.590524759628, 39.7193098068237)
(43.5904742497665, 39.7192668914795)
(43.59043151062, 39.7193473577499)
(43.5907345693677, 39.7195833921433)
(43.5907656522299, 39.7194921970367)
If you want to get more fancy, you can use a Point
struct instead of a List<double>
for each coordinate, and/or you can create an actual class hierarchy for each type of complex shape (e.g. Line, Polygon) and compose them of Points
. It would not be difficult to modify the converter to create these objects if desired. I'll leave that part to you.
来源:https://stackoverflow.com/questions/22466790/parse-json-with-different-types-value-newtonsoft-json