I use that to parse yaml with several docs in one file:
package main
import (
"errors"
"fmt"
"io"
"os"
"gopkg.in/yaml.v3"
)
type Spec struct {
Name string `yaml:"name"`
}
func main() {
f := io.Reader(os.Stdin)
d := yaml.NewDecoder(f)
for {
var spec Spec
err := d.Decode(&spec)
if errors.Is(err, io.EOF) {
break
}
if err != nil {
panic(err)
}
fmt.Printf("name is '%s'\n", spec.Name)
}
}
Now I want to decode the current object twice.
Depending on the name in the current doc has, I want to parse that:
type Special struct {
Integer string `yaml:"integer"`
}
but if I use d.Decode() I would parse the next doc ...
How to solve that?
Unmarshal the doc to a Node
first, and then decode the resulting node as much times as you want using the Node
's Decode
method (see the docs).
A modified example would look like this:
package main
import (
"errors"
"fmt"
"io"
"strings"
"gopkg.in/yaml.v3"
)
const data = `
---
name: "foo"
integer: 42
---
name: "bar"
integer: 12
`
type Spec struct {
Name string `yaml:"name"`
}
type Special struct {
Integer string `yaml:"integer"`
}
func main() {
dec := yaml.NewDecoder(strings.NewReader(data))
for {
var node yaml.Node
err := dec.Decode(&node)
if errors.Is(err, io.EOF) {
break
}
if err != nil {
panic(err)
}
spec := new(Spec)
err = node.Decode(&spec)
if err != nil {
panic(err)
}
// check it was parsed
if spec == nil {
fmt.Println("# spec is nil")
continue
}
fmt.Printf("name is '%s'\n", spec.Name)
var si Special
err = node.Decode(&si)
if err != nil {
panic(err)
}
fmt.Println("integer is: ", si.Integer)
}
}