Go语言 将YAML解析为带有子结构数组的结构Map

mf98qq94  于 2023-11-14  发布在  Go
关注(0)|答案(2)|浏览(142)

我正在使用github.com/goccy/go-yaml通过PATH读取YAML值
示例yaml文件

tree:
  branch:
    slices:
      slice1:
        - w: 1
        - w: 2
          h: 3
      slice2:
        - w: 11
          h: 22

字符串
我使用下面的代码来解封它使用YAML路径
主程序包

import (
    "fmt"
    "log"
    "strings"

    "github.com/goccy/go-yaml"
)

type slice struct {
    W int
    H int
}

type sliceObject struct {
    Slices []slice
}

func main() {
    yml := `
tree:
  branch:
    slices:
      slice1:
        - w: 1
        - w: 2
          h: 3
      slice2:
        - w: 11
          h: 22
`

    pathStr := "$.tree.branch.slices"
    path, err := yaml.PathString(pathStr)
    if err != nil {
        log.Panicf("failed to construct YAML path %s", err)
    }

    var sl map[string]sliceObject
    if err := path.Read(strings.NewReader(yml), &sl); err != nil {
        log.Panicf("failed to read value for path %s error %+v", pathStr, err)
    }

    fmt.Printf("object: %+v", sl)
}


上面的代码失败,出现以下错误

- failed to get map node:
    github.com/goccy/go-yaml.(*Decoder).keyToNodeMap
        /Users/.../go/pkg/mod/github.com/goccy/[email protected]/decode.go:977
  - [2:9] sequence was used where mapping is expected:
    github.com/goccy/go-yaml.errUnexpectedNodeType
        /Users/.../go/pkg/mod/github.com/goccy/[email protected]/decode.go:542


但如果我将var sl map[string]sliceObject更改为var sl map[string][]slice
我真的不想在YAML中添加另一个级别。

9vw9lbht

9vw9lbht1#

由于您定义的sliceObject包含Slices属性,因此需要在声明sliceObjectslice1slice2示例后添加一个名为slices的额外级别:

...
type sliceObject struct {
    Slices []slice
}

func main() {
    yml := `
tree:
  branch:
    slices:
      slice1:   // <<< A sliceObject instance
        slices: // <<< A sliceObject.Slices property
          - w: 1
          - w: 2
            h: 3
      slice2:   // <<< A sliceObject instance
        slices: // <<< A sliceObject.Slices property
          - w: 11
            h: 22
`

    pathStr := "$.tree.branch.slices"
    path, err := yaml.PathString(pathStr)
    if err != nil {
        log.Panicf("failed to construct YAML path %s", err)
    }

    var sl map[string]sliceObject
    if err := path.Read(strings.NewReader(yml), &sl); err != nil {
        log.Panicf("failed to read value for path %s error %+v", pathStr, err)
    }

    fmt.Printf("object: %+v", sl)
}

字符串
输出量:

$ go run .
object: map[slice1:{Slices:[{W:1 H:0} {W:2 H:3}]} slice2:{Slices:[{W:11 H:22}]}]


但是,由于您不想添加另一个层,您可以简单地将sliceObject定义为slice类型的切片(个人不推荐,因为它可能会引起混淆,它应该可以工作:

...
type sliceObject []slice

func main() {
    yml := `
tree:
  branch:
    slices:
      slice1:  // A sliceObject with two slices below
        - w: 1
        - w: 2
          h: 3
      slice2:  // A sliceObject with one slice below
        - w: 11
          h: 22
`

    pathStr := "$.tree.branch.slices"
    path, err := yaml.PathString(pathStr)
    if err != nil {
        log.Panicf("failed to construct YAML path %s", err)
    }

    var sl map[string]sliceObject
    if err := path.Read(strings.NewReader(yml), &sl); err != nil {
        log.Panicf("failed to read YAML %s", err)
    }
    fmt.Printf("object: %+v", sl)

}


输出量:

$ go run .
object: map[slice1:[{W:1 H:0} {W:2 H:3}] slice2:[{W:11 H:22}]]


顺便说一句,将var sl map[string]sliceObject更改为var sl map[string][]slice之所以有效,是因为您基本上告诉解析器寻找将slice1slice2转换为[]slice而不是Slices的方法(同样,因为您缺少slices键)--基本上与将sliceObject重新定义为[]slice相同,如上面的第二个代码示例所示

soat7uwm

soat7uwm2#

实际上你并不需要将sliceObject定义为一个结构体。相反,你可以修改如下来使它工作:

type sliceObject []slice

字符串

相关问题