You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Golang yaml.v3 Node类型处理YAML嵌套节点的方法咨询

关于使用Go yaml.v3包Node类型提取子节点的解决方案

问题场景

现有如下YAML配置文件(example.yaml):

## example.yaml

locationSection:
  firstLoc: Canada
  secondLoc: Korea
  thirdLoc: Italy

numberSection:
  person1: 12345
  person2: 98765
  person3: 56789

需求是使用yaml.v3的Node类型解析该文件,生成代表整个文件的exampleNode,再从中提取locationSectionNode和numberSectionNode两个子节点,当前已有未完成的Go代码:

### this is not an exact go code but just an example...

locationSectionStructure

...
data, err := os.ReadFile(yamlFileFullPath)
if err != nil {
   fmt.Printf("[I/O Error] Falied to read this file from os.ReadFile: %s", cfgFileFullPath)
   panic(err)
}

if err := yaml.Unmarshal(data, exampleNode); err != nil {
   fmt.Printf("[Unmarshal Error] Failed to unmarshal into a yaml Node")
   panic(err)
}
...
if err := exampleNode.Decode(locationSectionNode); err != nil {
...

简便实现方案

yaml.v3的Node类型提供了直接操作映射节点的方法,Decode是用来将Node转换为Go结构体的,不是提取子Node的正确方式,以下是完整实现:

package main

import (
	"fmt"
	"os"

	"gopkg.in/yaml.v3"
)

func main() {
	yamlFileFullPath := "example.yaml"
	data, err := os.ReadFile(yamlFileFullPath)
	if err != nil {
		fmt.Printf("[I/O Error] Failed to read file: %s\n", yamlFileFullPath)
		panic(err)
	}

	// 定义代表整个YAML的根Node,必须传指针给Unmarshal
	var exampleNode yaml.Node
	if err := yaml.Unmarshal(data, &exampleNode); err != nil {
		fmt.Println("[Unmarshal Error] Failed to unmarshal into yaml Node")
		panic(err)
	}

	// 校验根节点是否为映射类型(YAML顶层是键值对结构)
	if exampleNode.Kind != yaml.MappingNode {
		fmt.Println("Root node is not a mapping structure")
		panic("invalid yaml format")
	}

	// 方法1:用FieldByName直接获取子节点(最简便)
	var locationSectionNode yaml.Node
	locField := exampleNode.Content[0].FieldByName("locationSection")
	if locField == nil {
		fmt.Println("[Error] locationSection not found in yaml")
		panic("missing key")
	}
	if err := locField.Decode(&locationSectionNode); err != nil {
		fmt.Println("[Error] Failed to parse locationSection node")
		panic(err)
	}
	fmt.Println("locationSectionNode content:")
	fmt.Println(locationSectionNode.String())

	var numberSectionNode yaml.Node
	numField := exampleNode.Content[0].FieldByName("numberSection")
	if numField == nil {
		fmt.Println("[Error] numberSection not found in yaml")
		panic("missing key")
	}
	if err := numField.Decode(&numberSectionNode); err != nil {
		fmt.Println("[Error] Failed to parse numberSection node")
		panic(err)
	}
	fmt.Println("\nnumberSectionNode content:")
	fmt.Println(numberSectionNode.String())

	// 方法2:手动遍历Content获取子节点(适合复杂场景)
	// for i := 0; i < len(exampleNode.Content); i += 2 {
	// 	keyNode := exampleNode.Content[i]
	// 	valueNode := exampleNode.Content[i+1]
	// 	if keyNode.Value == "locationSection" {
	// 		locationSectionNode = *valueNode
	// 	} else if keyNode.Value == "numberSection" {
	// 		numberSectionNode = *valueNode
	// 	}
	// }
}

关键注意点

  • yaml.Unmarshal必须传入*yaml.Node指针,否则无法正确加载YAML结构
  • 映射类型的Node,Content切片是按[key, value, key, value]的顺序存储的,手动遍历需要步长为2
  • FieldByName是映射节点的快捷方法,能直接根据键名找到对应的子节点,比手动遍历更高效

内容的提问来源于stack exchange,提问作者HONG JI

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 12:57:28