• Stars
    star
    880
  • Rank 51,881 (Top 2 %)
  • Language
    Go
  • License
    MIT License
  • Created about 5 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

YAML support for the Go language

YAML support for the Go language

PkgGoDev Go codecov Go Report Card

Why a new library?

As of this writing, there already exists a de facto standard library for YAML processing for Go: https://github.com/go-yaml/yaml. However we feel that some features are lacking, namely:

  • Pretty format for error notifications
  • Direct manipulation of YAML abstract syntax tree
  • Support for Anchor and Alias when marshaling
  • Allow referencing elements declared in another file via anchors

Features

  • Pretty format for error notifications
  • Supports Scanner or Lexer or Parser as public API
  • Supports Anchor and Alias to Marshaler
  • Allow referencing elements declared in another file via anchors
  • Extract value or AST by YAMLPath ( YAMLPath is like a JSONPath )

Installation

go get -u github.com/goccy/go-yaml

Synopsis

1. Simple Encode/Decode

Has an interface like go-yaml/yaml using reflect

var v struct {
	A int
	B string
}
v.A = 1
v.B = "hello"
bytes, err := yaml.Marshal(v)
if err != nil {
	//...
}
fmt.Println(string(bytes)) // "a: 1\nb: hello\n"
	yml := `
%YAML 1.2
---
a: 1
b: c
`
var v struct {
	A int
	B string
}
if err := yaml.Unmarshal([]byte(yml), &v); err != nil {
	//...
}

To control marshal/unmarshal behavior, you can use the yaml tag.

	yml := `---
foo: 1
bar: c
`
var v struct {
	A int    `yaml:"foo"`
	B string `yaml:"bar"`
}
if err := yaml.Unmarshal([]byte(yml), &v); err != nil {
	//...
}

For convenience, we also accept the json tag. Note that not all options from the json tag will have significance when parsing YAML documents. If both tags exist, yaml tag will take precedence.

	yml := `---
foo: 1
bar: c
`
var v struct {
	A int    `json:"foo"`
	B string `json:"bar"`
}
if err := yaml.Unmarshal([]byte(yml), &v); err != nil {
	//...
}

For custom marshal/unmarshaling, implement either Bytes or Interface variant of marshaler/unmarshaler. The difference is that while BytesMarshaler/BytesUnmarshaler behaves like encoding/json and InterfaceMarshaler/InterfaceUnmarshaler behaves like gopkg.in/yaml.v2.

Semantically both are the same, but they differ in performance. Because indentation matters in YAML, you cannot simply accept a valid YAML fragment from a Marshaler, and expect it to work when it is attached to the parent container's serialized form. Therefore when we receive use the BytesMarshaler, which returns []byte, we must decode it once to figure out how to make it work in the given context. If you use the InterfaceMarshaler, we can skip the decoding.

If you are repeatedly marshaling complex objects, the latter is always better performance wise. But if you are, for example, just providing a choice between a config file format that is read only once, the former is probably easier to code.

2. Reference elements declared in another file

testdata directory contains anchor.yml file:

├── testdata
   └── anchor.yml

And anchor.yml is defined as follows:

a: &a
  b: 1
  c: hello

Then, if yaml.ReferenceDirs("testdata") option is passed to yaml.Decoder, Decoder tries to find the anchor definition from YAML files the under testdata directory.

buf := bytes.NewBufferString("a: *a\n")
dec := yaml.NewDecoder(buf, yaml.ReferenceDirs("testdata"))
var v struct {
	A struct {
		B int
		C string
	}
}
if err := dec.Decode(&v); err != nil {
	//...
}
fmt.Printf("%+v\n", v) // {A:{B:1 C:hello}}

3. Encode with Anchor and Alias

3.1. Explicitly declared Anchor name and Alias name

If you want to use anchor or alias, you can define it as a struct tag.

type T struct {
  A int
  B string
}
var v struct {
  C *T `yaml:"c,anchor=x"`
  D *T `yaml:"d,alias=x"`
}
v.C = &T{A: 1, B: "hello"}
v.D = v.C
bytes, err := yaml.Marshal(v)
if err != nil {
  panic(err)
}
fmt.Println(string(bytes))
/*
c: &x
  a: 1
  b: hello
d: *x
*/

3.2. Implicitly declared Anchor and Alias names

If you do not explicitly declare the anchor name, the default behavior is to use the equivalent of strings.ToLower($FieldName) as the name of the anchor.

If you do not explicitly declare the alias name AND the value is a pointer to another element, we look up the anchor name by finding out which anchor field the value is assigned to by looking up its pointer address.

type T struct {
	I int
	S string
}
var v struct {
	A *T `yaml:"a,anchor"`
	B *T `yaml:"b,anchor"`
	C *T `yaml:"c,alias"`
	D *T `yaml:"d,alias"`
}
v.A = &T{I: 1, S: "hello"}
v.B = &T{I: 2, S: "world"}
v.C = v.A // C has same pointer address to A
v.D = v.B // D has same pointer address to B
bytes, err := yaml.Marshal(v)
if err != nil {
	//...
}
fmt.Println(string(bytes)) 
/*
a: &a
  i: 1
  s: hello
b: &b
  i: 2
  s: world
c: *a
d: *b
*/

3.3 MergeKey and Alias

Merge key and alias ( <<: *alias ) can be used by embedding a structure with the inline,alias tag.

type Person struct {
	*Person `yaml:",omitempty,inline,alias"` // embed Person type for default value
	Name    string `yaml:",omitempty"`
	Age     int    `yaml:",omitempty"`
}
defaultPerson := &Person{
	Name: "John Smith",
	Age:  20,
}
people := []*Person{
	{
		Person: defaultPerson, // assign default value
		Name:   "Ken",         // override Name property
		Age:    10,            // override Age property
	},
	{
		Person: defaultPerson, // assign default value only
	},
}
var doc struct {
	Default *Person   `yaml:"default,anchor"`
	People  []*Person `yaml:"people"`
}
doc.Default = defaultPerson
doc.People = people
bytes, err := yaml.Marshal(doc)
if err != nil {
	//...
}
fmt.Println(string(bytes))
/*
default: &default
  name: John Smith
  age: 20
people:
- <<: *default
  name: Ken
  age: 10
- <<: *default
*/

4. Pretty Formatted Errors

Error values produced during parsing have two extra features over regular error values.

First, by default, they contain extra information on the location of the error from the source YAML document, to make it easier to find the error location.

Second, the error messages can optionally be colorized.

If you would like to control exactly how the output looks like, consider using yaml.FormatError, which accepts two boolean values to control turning these features on or off.

5. Use YAMLPath

yml := `
store:
  book:
    - author: john
      price: 10
    - author: ken
      price: 12
  bicycle:
    color: red
    price: 19.95
`
path, err := yaml.PathString("$.store.book[*].author")
if err != nil {
  //...
}
var authors []string
if err := path.Read(strings.NewReader(yml), &authors); err != nil {
  //...
}
fmt.Println(authors)
// [john ken]

5.1 Print customized error with YAML source code

package main

import (
  "fmt"

  "github.com/goccy/go-yaml"
)

func main() {
  yml := `
a: 1
b: "hello"
`
  var v struct {
    A int
    B string
  }
  if err := yaml.Unmarshal([]byte(yml), &v); err != nil {
    panic(err)
  }
  if v.A != 2 {
    // output error with YAML source
    path, err := yaml.PathString("$.a")
    if err != nil {
      panic(err)
    }
    source, err := path.AnnotateSource([]byte(yml), true)
    if err != nil {
      panic(err)
    }
    fmt.Printf("a value expected 2 but actual %d:\n%s\n", v.A, string(source))
  }
}

output result is the following:

Tools

ycat

print yaml file with color

ycat

Installation

go install github.com/goccy/go-yaml/cmd/ycat@latest

Looking for Sponsors

I'm looking for sponsors this library. This library is being developed as a personal project in my spare time. If you want a quick response or problem resolution when using this library in your project, please register as a sponsor. I will cooperate as much as possible. Of course, this library is developed as an MIT license, so you can use it freely for free.

License

MIT

More Repositories

1

go-json

Fast JSON encoder/decoder compatible with encoding/json for Go
Go
2,348
star
2

bigquery-emulator

BigQuery emulator server implemented in Go
Go
779
star
3

go-graphviz

Go bindings for Graphviz
Go
495
star
4

go-reflect

Zero-allocation reflection library for Go
Go
473
star
5

perl-motion

Perl for iOS and OS X
Objective-C
181
star
6

go-zetasql

Go bindings for ZetaSQL
Go
80
star
7

gperl

fastest perl like language
C++
72
star
8

go-jit

JIT compile library for Go
Go
71
star
9

rebirth

Supports live reloading for Go
Go
67
star
10

go-zetasqlite

A database driver library that interprets ZetaSQL queries and runs them using SQLite3
Go
52
star
11

p5-Compiler-Lexer

Lexical Analyzer for Perl5
Perl
46
star
12

p5-Compiler-CodeGenerator-LLVM

Create LLVM IR for Perl5
C++
40
star
13

kubejob

A library for managing Kubernetes Job in Go
Go
36
star
14

p5-Compiler-Parser

Create Abstract Syntax Tree for Perl5
Perl
33
star
15

p5-Compiler-Tools-CopyPasteDetector

detect Copy and Paste of Perl5 Codes
Perl
29
star
16

go-execbin

Analyze the binary outputted by `go build` to get type information etc.
Go
15
star
17

kubetest

A CLI for distributed execution of tasks on Kubernetes
Go
15
star
18

kpoward

kubernetes port forwarding utility library for Go
Go
10
star
19

p5-Test-AutoGenerator

automatically generate perl test code.
Perl
9
star
20

p5-App-Ikaros

distributed testing framework for jenkins
Perl
8
star
21

go-service-tracer

Visualize the dependencies between Microservices of gRPC methods implemented in Go
Go
7
star
22

iroonga

Groonga for iOS
C
6
star
23

treport

A fast scalable repository scanning tool
Go
5
star
24

go-json-fuzz

fuzzing test for goccy/go-json
Go
5
star
25

RecordKit

Record or stream video from the screen, and audio from the app and microphone
Objective-C
5
star
26

p5-Compiler-Tools-Transpiler

Transpile Perl5 code to JavaScript code
Perl
4
star
27

glisp

lisp based very fast functional language
C
4
star
28

p5-App-Harmonia

generate model layer codes of your application for Parse.com
Perl
4
star
29

echo-tools

utility tools for labstack/echo
Go
4
star
30

go-gcpurl

Parse the URL to get the GCP projectID in Go
Go
3
star
31

gmacs

emacs like editor
C++
3
star
32

cgo-math

Generate libm bridge for resolving undefined symbol in cgo
Go
2
star
33

cgo-multipkg-example

This contains of issues and solutions for binding multi-package libraries with cgo.
C
2
star
34

goccy

1
star
35

FilterGenerator

Automatically generate picture's filter code for iOS and Android.
Objective-C
1
star
36

p5-Compiler-Tools-UselessModuleDetector

detect useless modules
Perl
1
star
37

binarian

BinaryHack library for Gopher
Go
1
star
38

zetasql-proto

ZetaSQL Protocol Buffers
1
star
39

picoredis

header only redis client
C
1
star
40

earth-cupsule

Convert OpenStreetMap data around the world ( over 1TB ) to portable data
Go
1
star
41

PhotoFilterProcessor

generates photo filter data using CIFilter for iOS
Objective-C
1
star
42

nopbx

Provides method of removing project.pbxproj from your project. Also, release from conflict of project file.
Ruby
1
star
43

go-wasmbind-tools

A variety of tools for Go's wasm binding
Go
1
star