When you don’t have a struct for the data, parse it into a Document and read values by JSON Pointer, or walk its nodes. A node also gives you its position and its comments.
package main import ( "fmt" "log" oneyaml "oneyaml.dev/go" ) func main() { doc, err := oneyaml.Parse([]byte(`server: host: 0.0.0.0 port: 8080 # behind the load balancer features: [auth, metrics] limits: cpu: 0.5 memory: 512Mi `)) if err != nil { log.Fatal(err) } // Read one value into a Go type, by JSON Pointer. var port int if err := doc.Get("/server/port", &port); err != nil { log.Fatal(err) } fmt.Println("port:", port) // Or walk the nodes: values, comments and positions. root := doc.Root() server, _ := root.Lookup("server") p, _ := server.Lookup("port") line, col := p.Position() fmt.Printf("port %s at %d:%d, comment %q\n", p.Value(), line, col, p.LineComment()) features, _ := root.Lookup("features") for f := range features.Items() { fmt.Println("feature:", f.Value()) } limits, _ := root.Lookup("limits") for k, v := range limits.Entries() { fmt.Printf("limit %s = %s\n", k.Value(), v.Value()) } // A missing path is ErrNotFound, never a panic. var tls bool fmt.Println(doc.Get("/server/tls", &tls)) }
port: 8080 port 8080 at 3:9, comment "# behind the load balancer" feature: auth feature: metrics limit cpu = 0.5 limit memory = 512Mi oneyaml: get "/server/tls": path not found
Good to know
doc.Get(ptr, &v)decodes the node at a JSON Pointer into any Go value, with the same rules asUnmarshal. A missing path returns an error that matchesoneyaml.ErrNotFoundwitherrors.Is.Lookupfinds a key in a mapping;Finddoes the same but returns an error.Entries()andItems()are range-over-func iterators, in file order.Position()is the 1-based line and column,Span()the byte range, andHeadComment()andLineComment()the comments above and after the node.- To read into plain Go values instead,
Unmarshalintoany: a mapping becomesmap[string]any, a sequence[]any, an integerint.
A longer walk-through, with yaml.v2 and v3 compared: Golang: read a YAML file without a struct.