使用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
相关产品推荐
相关产品推荐

