0


golang yaml 解析问题

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
  
# 注释内容1config_custom_tag:# 注释内容2description: 自定义
  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"`}funcTestParseNormal(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(&item); err !=nil{return err
        }
        item.Name = value.Content[i].Value

        *a =append(*a, item)}returnnil}funcTestParseToSlice(t *testing.T){
    bytes, err := os.ReadFile("data.yaml")if err !=nil{
        t.Error(err.Error())return}var items Items
    err = yaml.Unmarshal(bytes,&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 文件,将空白行使用占位符替换funcloadYamlNode(file string)(*yaml.Node,error){
    dataBytes, err := os.ReadFile(file)if err !=nil{returnnil, 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&& err == io.EOF {break}if line !="\n"{
            storeBuffer.WriteString(line)}else{
            storeBuffer.WriteString("#placehold\n")}}var dataNode yaml.Node
    err = yaml.Unmarshal(storeBuffer.Bytes(),&dataNode)if err !=nil{returnnil, err
    }return&dataNode,nil}// 回写更新内容,将占位符使用空白行替换funcsaveUpdatedContent(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&& err == io.EOF {break}if line =="#placehold\n"{
            storeBuffer.WriteString("\n")}else{
            storeBuffer.WriteString(line)}}

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

本文转载自: https://blog.csdn.net/tianwenxue/article/details/130789746
版权归原作者 天文学 所有, 如有侵权,请联系我们删除。

“golang yaml 解析问题”的评论:

还没有评论