Reading an array from a yaml file in GoLang

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

Reading an array from a yaml file in GoLang

问题

我正在尝试读取一个包含对象数组的 YAML 文件。

package config

import (
	"gopkg.in/yaml.v3"
	"log"
	"os"
	"path/filepath"
	"runtime"
)

type DocumentationInfo struct {
	docs []Document `yaml:"document"`
}

type Document struct {
	title    string `yaml:"title"`
	fileName string `yaml:"filename"`
}

func (c *DocumentationInfo) Init() map[string]Document {
	_, b, _, _ := runtime.Caller(0)
	basepath := filepath.Dir(b)

	yamlFile, err := os.ReadFile(basepath + "/documentation.yaml")
	if err != nil {
		log.Printf("yamlFile.Get err   #%v ", err)
	}
	err = yaml.Unmarshal(yamlFile, c.docs)
	if err != nil {
		log.Fatalf("Unmarshal: %v", err)
	}

	docInfo := make(map[string]Document)

	for _, doc := range c.docs {
		docInfo[doc.fileName] = doc
	}

	return docInfo
}

func NewDocumentConfig() *DocumentationInfo {
	return &DocumentationInfo{}
}

YAML 文件内容如下:

DocumentationInfo:
  document:
    - {fileName: "foo.md", title: "I am an foo title"}
    - {fileName: "test.md", title: "I am an test title"}
    - {fileName: "bar.md", title: "I am an bar title"}
    - {fileName: "nice.md", title: "I am an nice title"}

错误信息如下:

2023/06/27 13:44:44 Unmarshal: yaml: unmarshal errors:
  line 1: cannot unmarshal !!map into []config.Document

我不确定问题是否出在 YAML 文件的语法上,因为它与 JSON 类似,但是根据文档交叉引用,它看起来是正确的。

如果有任何建议,将不胜感激...

英文:

I am trying to read a yaml file that has an array of objects

package config

import (
	"gopkg.in/yaml.v3"
	"log"
	"os"
	"path/filepath"
	"runtime"
)

type DocumentationInfo struct {
	docs []Document `yaml:"document"`
}

type Document struct {
	title    string `yaml:"title"`
	fileName string `yaml:"filename"`
}

func (c *DocumentationInfo) Init() map[string]Document {
	_, b, _, _ := runtime.Caller(0)
	basepath := filepath.Dir(b)

	yamlFile, err := os.ReadFile(basepath + "/documentation.yaml")
	if err != nil {
		log.Printf("yamlFile.Get err   #%v ", err)
	}
	err = yaml.Unmarshal(yamlFile, c.docs)
	if err != nil {
		log.Fatalf("Unmarshal: %v", err)
	}

	docInfo := make(map[string]Document)

	for _, doc := range c.docs {
		docInfo[doc.fileName] = doc
	}

	return docInfo
}
func NewDocumentConfig() *DocumentationInfo {
	return &DocumentationInfo{}
}

yaml file

DocumentationInfo:
  document:
    - {fileName: "foo.md", title: "I am an foo title"}
    - {fileName: "test.md", title: "I am an test title"}
    - {fileName: "bar.md", title: "I am an bar title"}
    - {fileName: "nice.md", title: "I am an nice title"}

error

2023/06/27 13:44:44 Unmarshal: yaml: unmarshal errors:
  line 1: cannot unmarshal !!map into []config.Document

I am not sure if the issue is the yaml file syntax because it is similar to json, however cross referencing documentation it looks correct.

Any advice would be appreciated...

答案1

得分: 0

你已经将最外层的容器定义为一个包含一个名为document的数组的DocumentationInfo映射:

type DocumentationInfo struct {
  docs []Document `yaml:"document"`
}

但是这不是你的输入数据的结构,它看起来像这样:

DocumentationInfo:
  document:
    - {fileName: "foo.md", title: "I am an foo title"}
    - {fileName: "test.md", title: "I am an test title"}
    - {fileName: "bar.md", title: "I am an bar title"}
    - {fileName: "nice.md", title: "I am an nice title"}

最外层的元素是一个包含DocumentationInfo键的映射(而该键的值是包含document键的映射)。你需要重新定义你的类型,像这样(我将其转换为package main,以便我可以在本地进行测试):

package main

import (
	"fmt"
	"log"
	"os"
	"path/filepath"
	"runtime"

	"gopkg.in/yaml.v3"
)

type DocumentationInfoFile struct {
	DocumentationInfo DocumentationInfo `yaml:"DocumentationInfo"`
}

type DocumentationInfo struct {
	Docs []Document `yaml:"document"`
}

type Document struct {
	Title    string `yaml:"title"`
	FileName string `yaml:"fileName"`
}

func (docinfo *DocumentationInfoFile) Init() map[string]Document {
	_, b, _, _ := runtime.Caller(0)
	basepath := filepath.Dir(b)

	yamlFile, err := os.ReadFile(basepath + "/documentation.yaml")
	if err != nil {
		log.Printf("yamlFile.Get err   #%v ", err)
	}
	err = yaml.Unmarshal(yamlFile, docinfo)
	if err != nil {
		log.Fatalf("Unmarshal: %v", err)
	}

	docmap := make(map[string]Document)
	for _, doc := range docinfo.DocumentationInfo.Docs {
		docmap[doc.FileName] = doc
	}

	return docmap

}
func NewDocumentConfig() *DocumentationInfoFile {
	return &DocumentationInfoFile{}
}

func main() {
	d := NewDocumentConfig()
	docmap := d.Init()
	fmt.Printf("%+v\n", docmap)
}

运行上述代码会产生以下结果:

map[bar.md:{Title:I am an bar title FileName:bar.md} foo.md:{Title:I am an foo title FileName:foo.md} nice.md:{Title:I am an nice title FileName:nice.md} test.md:{Title:I am an test title FileName:test.md}]
英文:

You have defined the outermost container as a map with a document key containing an array of Documents:

type DocumentationInfo struct {
  docs []Document `yaml:"document"`
}

But that is not the structure of your input data, which looks like this:

DocumentationInfo:
  document:
    - {fileName: "foo.md", title: "I am an foo title"}
    - {fileName: "test.md", title: "I am an test title"}
    - {fileName: "bar.md", title: "I am an bar title"}
    - {fileName: "nice.md", title: "I am an nice title"}

The outer element is a map that contains a DocumentationInfo key (and the value of that key is your map with the document key). You would need to redefine your types like this (I've turned this into package main so I can run it locally for testing):

package main

import (
	"fmt"
	"log"
	"os"
	"path/filepath"
	"runtime"

	"gopkg.in/yaml.v3"
)

type DocumentationInfoFile struct {
	DocumentationInfo DocumentationInfo `yaml:"DocumentationInfo"`
}

type DocumentationInfo struct {
	Docs []Document `yaml:"document"`
}

type Document struct {
	Title    string `yaml:"title"`
	FileName string `yaml:"fileName"`
}

func (docinfo *DocumentationInfoFile) Init() map[string]Document {
	_, b, _, _ := runtime.Caller(0)
	basepath := filepath.Dir(b)

	yamlFile, err := os.ReadFile(basepath + "/documentation.yaml")
	if err != nil {
		log.Printf("yamlFile.Get err   #%v ", err)
	}
	err = yaml.Unmarshal(yamlFile, docinfo)
	if err != nil {
		log.Fatalf("Unmarshal: %v", err)
	}

	docmap := make(map[string]Document)
	for _, doc := range docinfo.DocumentationInfo.Docs {
		docmap[doc.FileName] = doc
	}

	return docmap

}
func NewDocumentConfig() *DocumentationInfoFile {
	return &DocumentationInfoFile{}
}

func main() {
	d := NewDocumentConfig()
	docmap := d.Init()
	fmt.Printf("%+v\n", docmap)
}

Running the above code produces:

map[bar.md:{Title:I am an bar title FileName:bar.md} foo.md:{Title:I am an foo title FileName:foo.md} nice.md:{Title:I am an nice title FileName:nice.md} test.md:{Title:I am an test title FileName:test.md}]

huangapple
  • 本文由 发表于 2023年6月27日 22:25:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/76565886.html
匿名

发表评论

匿名网友

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

确定