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

使用gopkg.in/yaml.v3读取多文档YAML文件并重新编组单个文档时出现错误的技术问询

问题分析与解决方案

这个问题我之前也碰到过,根源在于你用yaml.Decoder解码得到的yaml.Node是一个文档节点(yaml.DocumentNode),而非文档内的实际内容节点,直接对它执行yaml.Marshal就会触发错误。

为什么会出错?

当你通过dec.Decode(&node)读取每个YAML文档时,返回的node的Kind字段值是yaml.DocumentNode。这个节点相当于一个容器,它的Content切片里才存放着你真正需要的内容(比如示例中的name: docX映射节点)。

yaml.Marshal函数默认处理的是普通YAML节点(映射、序列、标量等),而不是包含文档边界标记的文档节点。直接Marshal文档节点时,它会尝试输出文档起始标记,从而触发你看到的yaml: expected SCALAR, SEQUENCE-START, MAPPING-START, or ALIAS, but got document start错误。

修正后的代码

你只需要取出node.Content中的第一个元素(也就是文档的实际内容节点),再对它执行Marshal即可。同时建议增加空文档的判断,避免索引越界:

package main

import (
    "errors"
    "fmt"
    "io"
    "os"
    "gopkg.in/yaml.v3"
)

func main() {
    reader := io.Reader(os.Stdin)
    dec := yaml.NewDecoder(reader)
    for {
        var node yaml.Node
        err := dec.Decode(&node)
        if errors.Is(err, io.EOF) {
            break
        }
        if err != nil {
            panic(err)
        }
        
        // 处理空文档的情况
        if len(node.Content) == 0 {
            fmt.Println("Found an empty doc\n")
            continue
        }
        
        // 对文档内的实际内容节点进行Marshal
        content, err := yaml.Marshal(node.Content[0])
        if err != nil {
            panic(err)
        }
        fmt.Printf("Found a doc\n\n%s\n", content)
    }
}

运行结果

用你的示例输入运行修正后的代码,会得到预期输出:

Found a doc

name: doc1

Found a doc

name: doc2

Found a doc

name: doc3

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 16:52:34