如何在Go中解析JSON,其中数组维度取决于同一JSON中的其他字段?

huangapple go评论73阅读模式
英文:

How to parse JSON when array dimension depends on some other field of the same JSON in Go?

问题

任务是将GeoJSON存储到Go数据结构中。我面临的问题是JSON中有一个名为coordinates的数组,其维度随同一JSON中的另一个字段type而变化。

例如:

{
         "type": "Point",
         "coordinates": [100.0, 0.0]
}

{
         "type": "LineString",
         "coordinates": [
             [100.0, 0.0],
             [101.0, 1.0]
         ]
}

{
         "type": "MultiPolygon",
         "coordinates": [
             [
                 [
                     [102.0, 2.0],
                     [103.0, 2.0],
                     [103.0, 3.0],
                     [102.0, 3.0],
                     [102.0, 2.0]
                 ]
             ],
             [
                 [
                     [100.0, 0.0],
                     [101.0, 0.0],
                     [101.0, 1.0],
                     [100.0, 1.0],
                     [100.0, 0.0]
                 ],
                 [
                     [100.2, 0.2],
                     [100.2, 0.8],
                     [100.8, 0.8],
                     [100.8, 0.2],
                     [100.2, 0.2]
                 ]
             ]
         ]
     }

现在,如果我创建一个2D、1D、3D和4D的数组,那么会缺少相应的情况。

我的数据结构如下:

type Geometry struct {
     Type string `json:"type"`
     Coordinates[][][][] float64 `json:"coordinates"`
}

...


var data Geometry
json.Unmarshal([]byte(geoJsonString), &data)

我对Go语言和JSON都不太熟悉。请帮帮我。

英文:

The task is to store GeoJSON into Go data structure. Problem I am facing that there is an array named coordinate in the JSON whose dimension changes with an other field in the same JSON named type.

For example:

{
         "type": "Point",
         "coordinates": [100.0, 0.0]
}

{
         "type": "LineString",
         "coordinates": [
             [100.0, 0.0],
             [101.0, 1.0]
         ]
}

{
         "type": "MultiPolygon",
         "coordinates": [
             [
                 [
                     [102.0, 2.0],
                     [103.0, 2.0],
                     [103.0, 3.0],
                     [102.0, 3.0],
                     [102.0, 2.0]
                 ]
             ],
             [
                 [
                     [100.0, 0.0],
                     [101.0, 0.0],
                     [101.0, 1.0],
                     [100.0, 1.0],
                     [100.0, 0.0]
                 ],
                 [
                     [100.2, 0.2],
                     [100.2, 0.8],
                     [100.8, 0.8],
                     [100.8, 0.2],
                     [100.2, 0.2]
                 ]
             ]
         ]
     }

Now if I am making an array of 2D then 1D, 3D and 4D cases are missing.

My data structure is something like this:

type Geometry struct {
     Type string `json:"type"`
     Coordinates[][][][] float64 `json:"coordinates"`
}

...


var data Geometry
json.Unmarshal([] byte(geoJsonString), &data)

I am new to language Go and JSON. Please help me out.

答案1

得分: 1

最好使用现有的包来处理。例如:https://pkg.go.dev/github.com/paulmach/go.geojson#UnmarshalGeometry

如果你想要手动处理具有不同JSON结构的数据,可以使用encoding/json中的两种主要方法:

  1. 将可变类型字段解码为json.RawMessage,然后继续解码为所需的具体类型。
type geometry struct {
  Type   string          `json:"type"`
  Coords json.RawMessage `json:"coordinates"`
}

type lineStringCoords [][]float64

var data geometry
if err := json.Unmarshal(input, &data); err != nil {
  return err
}

switch data.Type {
case "LineString":
  var lineString lineStringCoords
  if err := json.Unmarshal(data.Coords, &lineString); err != nil {
    ...
  }
...
}
  1. 将可变类型字段解码为interface{},然后使用类型断言提取数据。这或多或少是github.com/paulmac/go.geojson使用的方法。这允许你解码/探索任意的JSON,但实现起来更加复杂。
type geometry struct {
  Type   string      `json:"type"`
  Coords interface{} `json:"coordinates"`
}

var data geometry
if err := json.Unmarshal(input, &data); err != nil {
  return err
}

switch data.Type {
case "LineString":
  slice, ok := data.Coords.([]interface{})
  // 继续手动提取切片并复制到适当的输出结构中。
...
}
英文:

It's probably best to use a pre-existing package. Eg: https://pkg.go.dev/github.com/paulmach/go.geojson#UnmarshalGeometry

There are 2 main approaches if you would like to handle varied JSON structures manually with encoding/json:

  1. Decode the variable type field into a json.RawMessage and continue decoding into the specific type you need.
type geometry struct {
  Type string `json:"type"`
  Coords json.RawMessage `json:"coordinates"`
}

type lineStringCoords [][]float64

var data geometry
if err := json.Unmarshal(input, &data); err != nil {
  return err
}

switch data.Type {
case "LineString":
  var lineString lineStringCoords
  if err := json.Unmarshal(data.Coords, &lineString); err != nil {
    ...
  }  ​
...
}
  1. Decode the variable type field into an interface{} and use type assertions to extract the data. This is more or less the approach used by github.com/paulmac/go.geojson. This allows you to decode/explore arbitrary JSON but is more complicated to implement.
type geometry struct {
 ​Type string `json:"type"`
 ​Coords interface{} `json:"coordinates"`
}

var data geometry
if err := json.Unmarshal(input, &data); err != nil {
 ​return err
}

switch data.Type {
case "LineString":
 ​slice, ok := data.Coords.([]interface{})
 ​// Continue manually extracting the slices and copy into the appropriate output struct.
...
}

huangapple
  • 本文由 发表于 2021年9月23日 02:16:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/69289382.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定