golang解析 yaml 格式内容可以使用 yaml.v3 库来解决。下载 go 依赖

go get -u gopkg.in/yaml.v3

1. 示例 yaml 数据

config_mail_template:
  description: 验证码
  one: Verification Code
  other: Verification Code

config_mail_template_reset_code:
  description: 重置密码
  one: Reset password
  other: Reset password
  
# 注释内容1
config_custom_tag: # 注释内容2
  description: 自定义
  one: Custom Tag
  other: Custom Tag

#注释内容3

2. 普通解析

普通解析流程解析map 对象,会失去对 key定义顺序

package yaml_demo

import (
	"os"
	"testing"

	"gopkg.in/yaml.v3"
)

type Asset struct {
	Description string `yaml:"description"`
	One         string `yaml:"one"`
	Other       string `yaml:"other"`
}

func TestParseNormal(t *testing.T) {
	file, err := os.ReadFile("data.yaml")
	if err != nil {
		t.Error(err.Error())
		return
	}

	var assets map[string]Asset
	err = yaml.Unmarshal(file, &assets)
	if err != nil {
		t.Error(err.Error())
		return
	}
	t.Log(len(assets))
}

3. 顺序解析 yaml 中的 key

yaml3 定义了 yaml.Node 对象
第一种方式
可以通过实现 UnmarshalYAML() 接口,来实现自定义对象的解析,并且保证解析 key顺序

第二种方式
直接将 bytes 解析到 yaml.Node 中,此时 yaml.Node 就是文档对象

var node yaml.Node
yaml.Unmarshal(bytes,&node)
package yaml_demo

import (
	"gopkg.in/yaml.v3"
	"os"
	"testing"
)

type Item struct {
	Name        string
	Description string `yaml:"description"`
	One         string `yaml:"one"`
	Other       string `yaml:"other"`
}

type Items []Item

// UnmarshalYAML 自定义解析
func (a *Items) UnmarshalYAML(value *yaml.Node) error {
	for i := 0; i < len(value.Content); i += 2 {
		var item Item
		if err := value.Content[i+1].Decode(&amp;item); err != nil {
			return err
		}
		item.Name = value.Content[i].Value

		*a = append(*a, item)
	}
	return nil
}

func TestParseToSlice(t *testing.T) {
	bytes, err := os.ReadFile("data.yaml")
	if err != nil {
		t.Error(err.Error())
		return
	}

	var items Items
	err = yaml.Unmarshal(bytes, &amp;items)
	if err != nil {
		t.Error(err.Error())
		return
	}

	t.Log(len(items))
}

4. 顺序解析后回写问题

yaml 中的 node更新完成后,回写内容时,虽然保留了注释,但是会去掉空白行
为了保证和原来的文件相同的空白行和注释内容,可以对 yaml 内容做如下处理

  1. 将 yaml 文件读取bytes.Buffer 中,并对其中的空白行处理,使用占位符替代空白??行,例如使用 “#placehold字符串,因为 “#” 是 yaml 中的注释,所以对文件内容本身没有影响
  2. bytes.Buffer 中的内容解析成 yaml.Node 对象,并对其中需要更新的内容进行更新
  3. 回写时,首先使用 yaml.Marshal 将 yaml.Node 对象转换bytes.Buffer,然后将占位符再替换换行符,写入文件
// 加载 yaml 文件,将空白行使用占位符替换
func loadYamlNode(file string) (*yaml.Node, error) {
	dataBytes, err := os.ReadFile(file)
	if err != nil {
		return nil, err
	}

	buffer := bytes.NewBuffer(dataBytes)
	storeBytes := make([]byte, 0, 2*buffer.Len())
	storeBuffer := bytes.NewBuffer(storeBytes)

	for {
		line, err := buffer.ReadString('n')
		if err != nil &amp;&amp; err == io.EOF {
			break
		}
		if line != "n" {
			storeBuffer.WriteString(line)
		} else {
			storeBuffer.WriteString("#placeholdn")
		}
	}

	var dataNode yaml.Node
	err = yaml.Unmarshal(storeBuffer.Bytes(), &amp;dataNode)
	if err != nil {
		return nil, err
	}
	return &amp;dataNode, nil
}

// 回写更新内容,将占位符使用空白行替换
func saveUpdatedContent(docNode *yaml.Node, file string) error {
	var bytesData []byte
	buffer := bytes.NewBuffer(bytesData)
	encoder := yaml.NewEncoder(buffer)
	encoder.SetIndent(2)
	err := encoder.Encode(docNode)
	if err != nil {
		return err
	}

	store := make([]byte, 0, buffer.Len())
	storeBuffer := bytes.NewBuffer(store)

	for {
		line, err := buffer.ReadString('n')
		if err != nil &amp;&amp; err == io.EOF {
			break
		}
		if line == "#placeholdn" {
			storeBuffer.WriteString("n")
		} else {
			storeBuffer.WriteString(line)
		}
	}

	err = os.WriteFile(file, storeBuffer.Bytes(), 0666)
	return err
}

原文地址:https://blog.csdn.net/tianwenxue/article/details/130789746

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。

如若转载,请注明出处:http://www.7code.cn/show_11091.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注