c# - 在 C# 中反序列化 Open Street Map JSON

标签 c# json json.net openstreetmap json-deserialization

如果我有这个 JSON,其中有一个 header 带有标签 versiongeneratorom3selementselements 可以是 nodeway 类型,关联的 JSON 键因类型而异。我正在尝试使用 JsonSubTypes将每个元素类型转换为 C# 类。

示例 JSON:

[
  {
    "version": 0.6,
    "generator": "Overpass API 0.7.55.7 8b86ff77",
    "osm3s": {
      "timestamp_osm_base": "2019-05-21T18:03:02Z",
      "copyright": "The data included in this document is from www.openstreetmap.org. The data is made available under ODbL."
    },
    "elements": [
      {
        "type": "node",
        "id": 4949106384,
        "lat": 32.2686857,
        "lon": -107.738218,
        "tags": {
          "highway": "turning_circle"
        }
      },
      {
        "type": "way",
        "id": 14527404,
        "nodes": [
          142882281,
          3048075541,
          1598998260
        ],
        "tags": {
          "highway": "residential",
          "name": "West Apple Street",
          "tiger:cfcc": "A41",
          "tiger:county": "Luna, NM",
          "tiger:name_base": "Apple",
          "tiger:name_direction_prefix": "W",
          "tiger:name_type": "St",
          "tiger:reviewed": "no"
        }
      }
    ]
  }
]

我正在尝试使用以下方法对其进行反序列化:

var json = JsonConvert.DeserializeObject<OSMdata>(jsonText);

OSMdata 看起来像:

[JsonConverter(typeof(JsonSubtypes), "type")]
[JsonSubtypes.KnownSubType(typeof(Element.Node), "node")]
[JsonSubtypes.KnownSubType(typeof(Element.Edge), "way")]

public abstract class OSMdata
{
    public float version { get; set; }
    public string generator { get; set; }
    public Osm3s osm3s { get; set; }
    public Element[] elements { get; set; }
}

public class Osm3s : OSMdata
{
    public DateTime timestamp_osm_base { get; set; }
    public string copyright { get; set; }
}

public class Element : OSMdata
{
    public class Node : Element
    {
        public string type { get; } = "node";
        public long id { get; set; }
        public float lat { get; set; }
        public float lon { get; set; }
        public NodeTags tags { get; set; }
    }

    public class NodeTags : Node
    {
        public string highway { get; set; }
        public string _ref { get; set; }
    }

    public class Edge : Element
    {
        public string type { get; } = "way";
        public long id { get; set; }
        public long[] nodes { get; set; }
        public EdgeTags tags { get; set; }
    }

    public class EdgeTags : Edge
    {
        public string highway { get; set; }
        public string name { get; set; }
        public string cfcc { get; set; }
        public string county { get; set; }
        public string oneway { get; set; }
    }
}

哪个返回:

Unhandled Exception: System.ArgumentNullException: Value cannot be null.
   at System.RuntimeType.MakeGenericType(Type[] instantiation)
   at JsonSubTypes.JsonSubtypes.CreateCompatibleList(Type targetContainerType, Type elementType)
   at JsonSubTypes.JsonSubtypes.ReadArray(JsonReader reader, Type targetType, JsonSerializer serializer)
   at JsonSubTypes.JsonSubtypes.ReadJson(JsonReader reader, Type objectType, JsonSerializer serializer)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.DeserializeConvertable(JsonConverter converter, JsonReader reader, Type objectType, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
   at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
   at Newtonsoft.Json.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings)
   at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value, JsonSerializerSettings settings)
   at newapp.Program.Main(String[] args) in C:\Users\RDCRLDDH\source\repos\newapp\newapp\Program.cs:line 23

虽然我不明白这个错误并正在寻找解决方案,但我想澄清以下几个问题:

问题

我是否正确构建了 OSMdata 类?我想我正确地遵循了示例,但不确定我是否正确地将类 NodeEdge 分配给父类 OSMdata

反序列化器如何知道将标记 "tiger:cfcc" 分配给 EdgeTags 中的 Cfcc 属性?

最佳答案

声明你的类如下:


    // no longer abstract
    public class OSMdata
    {
        public float version { get; set; }
        public string generator { get; set; }
        public Osm3s osm3s { get; set; }

        // for arrays or collection this line must be present here
        [JsonConverter(typeof(JsonSubtypes), "type")]
        public Element[] elements { get; set; }
    }

    // no need to inherits from OSMData
    public class Osm3s
    {
        public DateTime timestamp_osm_base { get; set; }
        public string copyright { get; set; }
    }


    [JsonConverter(typeof(JsonSubtypes), "type")]
    [JsonSubtypes.KnownSubType(typeof(Node), "node")]
    [JsonSubtypes.KnownSubType(typeof(Edge), "way")]
    public abstract class Element : OSMdata
    {
        public abstract string type { get; }
    }

    public class Node : Element
    {
        public override string type { get; } = "node";
        public long id { get; set; }
        public float lat { get; set; }
        public float lon { get; set; }
        public NodeTags tags { get; set; }
    }

    public class NodeTags
    {
        public string highway { get; set; }
        public string _ref { get; set; }
    }

    public class Edge : Element
    {
        public override string type { get; } = "way";
        public long id { get; set; }
        public long[] nodes { get; set; }
        public EdgeTags tags { get; set; }
    }

    public class EdgeTags
    {
        public string highway { get; set; }
        public string name { get; set; }
        public string cfcc { get; set; }
        public string county { get; set; }
        public string oneway { get; set; }
    }

反序列化:

var json = JsonConvert.DeserializeObject<OSMdata>(jsonText);

查看运行示例:https://dotnetfiddle.net/pdJ0ab

关于c# - 在 C# 中反序列化 Open Street Map JSON,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56284030/

相关文章:

python - XML 转换成 JSON 返回对象失败

java - 在 Spring 应用程序中使用 RestTemplate 从 JSON 获取值

javascript - 如何在传单上放置带有 geojson 的数字标记

c# - SqlCommand.Dispose() 没有处理其中的 SqlParameters - 内存泄漏 - C#.NET

c# - "Copy Local = false"引用的项目显示 "Could not load file or assembly"

c# - 更快更便宜的线程安全计数器?

c# - 在重用对象和替换数组的地方填充对象?

c# - 将 JSON 反序列化为子类

asp.net-mvc - mvc 返回 Json() 与基于 JSON 的 Web 服务

C# Chained ContinueWith 不等待上一个任务完成