使用go-yaml v3编码时如何去除自动添加的!!merge标签
解决go-yaml v3生成YAML时自动添加!!merge标签的问题
go-yaml v3默认会把YAML里的合并键<<序列化为带!!merge标签的形式,要避开这个行为且不破坏注释(不用字符串替换),可以通过自定义编码器处理节点:
实现步骤
- 遍历解析后的YAML节点树,找到带有
!!merge标签的键节点,将其标签重置为空字符串 - 使用修改后的节点进行序列化输出
代码示例
自定义编码器函数
import ( "gopkg.in/yaml.v3" "io" "os" ) func encodeWithoutMergeTag(w io.Writer, node *yaml.Node) error { enc := yaml.NewEncoder(w) enc.SetIndent(2) // 匹配你需要的缩进格式 // 递归遍历节点处理merge标签 var traverse func(*yaml.Node) traverse = func(n *yaml.Node) { if n.Kind == yaml.MappingNode { updatedContent := make([]*yaml.Node, 0, len(n.Content)) for i := 0; i < len(n.Content); i += 2 { keyNode := n.Content[i] valNode := n.Content[i+1] // 识别merge节点:tag为!!merge且key值为<< if keyNode.Tag == "!!merge" && keyNode.Value == "<<" { keyNode.Tag = "" // 清空标签,让编码器输出普通的<< } updatedContent = append(updatedContent, keyNode, valNode) traverse(valNode) } n.Content = updatedContent } else if n.Kind == yaml.SequenceNode { for _, item := range n.Content { traverse(item) } } } traverse(node) return enc.Encode(node) }
使用示例
func main() { // 读取并解析原YAML文件 var root yaml.Node inputFile, err := os.Open("input.yaml") if err != nil { panic(err) } defer inputFile.Close() if err := yaml.NewDecoder(inputFile).Decode(&root); err != nil { panic(err) } // 在这里对节点进行你的修改操作... // 写入修改后的YAML,使用自定义编码器 outputFile, err := os.Create("output.yaml") if err != nil { panic(err) } defer outputFile.Close() if err := encodeWithoutMergeTag(outputFile, &root); err != nil { panic(err) } }
原理说明
go-yaml v3会把<<识别为合并类型(merge),所以序列化时自动加上!!merge标签。通过遍历节点树,把对应键节点的标签清空,编码器就会输出原生的<<: *meta_data格式,同时完全保留原YAML中的注释信息(因为yaml.Node结构会完整保存注释,遍历修改标签的操作不会破坏注释)。
内容的提问来源于stack exchange,提问作者Sameer
相关产品推荐
相关产品推荐

