1. 程式人生 > >Golang 解析Yaml格式

Golang 解析Yaml格式

Golang官方並沒有提供Yaml解析包,所以需要使用第三方包。可用的第三方包有不少,這裡選擇的是
gopkg.in/yaml.v2,這個包在github上有不少的star,也的確挺好用。其使用的是Apache License。

這個包提供的函式還是很少了,這真是一件好事(〃∀〃)

如果你不瞭解yaml,檢視YAML簡要入門


func Marshal(in interface{}) (out []byte, err error)將提供的物件解析為YAML文件格式。
但要注意這裡返回不是string型別


func Unmarshal(in []byte, out interface{}) (err error)

解析給定的位元組切片,儲存在第二引數中。你必須保證儲存型別可以接受被解析的資料,否則yaml.TypeError將被返回

讓我們來看一下這個例子:

package main

import (
    "fmt"
    "gopkg.in/yaml.v2"
)

func main() {
    var t T
    s := `a: 1
x: 333
B: 2
F:
  c: 3
開心: 10
愉悅: 30
S: 9
`
    yaml.Unmarshal([]byte(s), &t)   //輸出為{0 1 0 0 0 0 30 333 0}
    //a不會獲得值,說明 結構欄位名首字母大小控制是否接受值,首字母大寫為接受
    //b和B都沒有獲得值,未設定鍵時,預設解析時會將struct中欄位的首字母轉為小寫,再去匹配Yaml,
    //這樣就沒有能與yaml中B想匹配的了
    //C 不能獲得值說明,對應層次的欄位才會賦值
    //開心與D的例子,顯示如何使用中文作為鍵
    //X可以獲得值說明,解析與宣告的順序無關
    fmt.Println(t)
}

type T struct {
    a int
    A int   //yaml中a的值會給哪一個?
    b int
    B int   //yaml中B的值會給B還是b,或者兩者都不?
    C int   //能獲得yaml中c的值嗎?
    開心 int  //能獲得yaml開心的值嗎?
    D int `yaml:"愉悅"`   //使用struct標籤,為D int設定鍵為“愉悅”
    //`yaml:"key[, tag]"`
    X int   //X能獲得值嗎
    s int `yaml:"S"`
}

你可以拷貝執行一下這段程式碼,自己感受下。

如果如何struct中還有struct呢?

package main

import (
    "fmt"
    "log"

    "gopkg.in/yaml.v2"
)

type StructA struct {
    A string `yaml:"a"`
}

type StructB struct {
    StructA
    C StructA
    B       string `yaml:"b"`
}

var data = `
a: a string from struct A
b: a string from struct B
c:
  a: a string from c.a
`

func main() {
    var b StructB

    err := yaml.Unmarshal([]byte(data), &b)
    if err != nil {
        log.Fatalf("cannot unmarshal data: %v", err)
    }
    fmt.Println(b.B)
    fmt.Println(b.A)
    fmt.Println(b.C.A)
    /*
    輸出為:
    a string from struct B  //可以看到匿名struct沒有獲得值

    a string from c.a
    */
}

要為匿名結構也作為YAML的一部分解析,需要inline標記

type StructB struct {
    StructA`yaml:",inline"`
    C StructA
    B       string `yaml:"b"`
}

func UnmarshalStrict(in []byte, out interface{}) (err error)

UnmarshalStrict和Unmarshal基本上一樣,但是多了一點限制。
Yaml中的欄位必須要有給定的接收物件,而在Unmarshal中它們會被忽略。


type DecoderDecoder從輸入流中讀取和解析YAML值

func NewDecoder(r io.Reader) *Decoder使用r建立Decoder

func (dec *Decoder) Decode(v interface{}) (err error)從YAML中解析v的值

package main

import (
    "fmt"
    "os"

    "gopkg.in/yaml.v2"
)

type StructA struct {
    A string `yaml:"a"`
}

type StructB struct {
    StructA
    C StructA
    B       string `yaml:"b"`
}

func main() {
    var b StructB

    yfile, _ := os.Open("test.yaml")    //test.yaml由下一個例子生成
    defer yfile.Close()

    ydecode:= yaml.NewDecoder(yfile)
    ydecode.Decode(&b)  //注意這裡為指標
    fmt.Println(b)
}

type Encoder編碼並將YAML寫入輸出流

func NewEncoder(w io.Writer) *Encoder返回一個寫入r中的Encoder
Encoder帶有緩衝,所以一定記得呼叫func (e *Encoder) Close() (err error),以防資料未寫入

func (e *Encoder) Encode(v interface{}) (err error)編碼v並寫入流,如果多次呼叫,每次存入的YAML以---分隔

package main

import (
    "log"
    "os"

    "gopkg.in/yaml.v2"
)

type StructA struct {
    A string `yaml:"a"`
}

type StructB struct {
    StructA
    C StructA
    B       string `yaml:"b"`
}

var data = `
a: a string from struct A
b: a string from struct B
c:
  a: a string from c.a
`

func main() {
    var b StructB
    x := 22

    err := yaml.Unmarshal([]byte(data), &b)
    if err != nil {
        log.Fatalf("cannot unmarshal data: %v", err)
    }

    yfile, _ := os.Create("test.yaml")
    defer yfile.Close()

    yencoder := yaml.NewEncoder(yfile)
    defer yencoder.Close()
    yencoder.Encode(b)
    yencoder.Encode(b)
    yencoder.Encode(x)
    yencoder.Encode(44)
}

這篇文章根據官方文件寫成,我可能沒有表述的很清楚,請查閱官方文件


知識共享許可協議
本作品採用知識共享署名-非商業性使用-禁止演繹 4.0 國際許可協議進行許可。轉載請註明出處!