toml文及其解析方法(golang)

toml文及其解析方法(golang)

tomal簡介

參考文檔:https://github.com/toml-lang/toml#user-content-offset-date-time

TOML 旨在成爲一個語義顯著而易於閱讀的最低限度的配置文件格式。
TOML 被設計地能夠無歧義地轉化爲哈希表。
TOML 應當能簡單地解析成形形色色的語言中的數據結構。
TOML 是大小寫敏感的。
TOML 文件必須是有效的 UTF-8 編碼的 Unicode 文檔。
空白的意思是 Tab(0x09)或空格(0x20)。
換行的意思是 LF(0x0A)或 CRLF(0x0D 0x0A)。

示例

# 這是一個 TOML 文檔。

title = "TOML 示例"

[owner]
name = "//湯姆·普雷斯頓—維爾納"    #  鍵名和鍵值周圍的空白會被忽略, 有鍵必須有值,鍵值對後必須換行 
dob = 1979-05-27T07:32:00-08:00 # 第一類日期時刻 

[database]
server = "192.168.1.1"   
ports = [ 8001, 8001, 8002 ]
connection_max = 5000 # 鍵名可以是裸露的,引號引起來的,或點分隔的。裸鍵只能包含 ASCII 字母,ASCII 數字,下劃線和短橫線(A-Za-z0-9_-)
enabled = true

[servers]

  # 允許縮進(Tab 和/或空格),不過不是必要的
  [servers.alpha]
  ip = "10.0.0.1"
  dc = "eqdc10"

  [servers.beta]
  ip = "10.0.0.2"
  dc = "eqdc10"

[clients]
data = [ ["gamma", "delta"], [1, 2] ]

# 數組中是可以換行的
hosts = [
  "alpha",
  "omega"
]
[[products]]
name = "Hammer"
sku = 738594937

[[products]]

[[products]]
name = "Nail"
sku = 284758393

color = "gray"

類似於json

{
	“title“:"TOML 示例”
	“owner”:{”name“:”/湯姆·普雷斯頓—維爾納“, ”dob“:”1979-05-27T07:32:00-08:00“},
	”database“:{”server“: "192.168.1.1",”ports“:[ 8001, 8001, 8002 ],”connection_max”:5000,“enabled”:true},
	"servers":  {"alpha":{"ip":"10.0.0.1","dc":"eqdc10" }, "beta": { "ip": "10.0.0.2", dc:"eqdc10" }}},
	"clients": { data:[["gamma", "delta"], [1, 2]] },
	"hosts": ["alpha","omega"],
	"products": [
   		  { "name": "Hammer", "sku": 738594937 },
  		  { },
	      { "name": "Nail", "sku": 284758393, "color": "gray" }
      ]
}

任何 Unicode 字符都可以使用,除了那些必須轉義的:引號,反斜槓,以及除 Tab 外的控制字符。
想書寫長字符串卻不想引入無關空白,可以用“行末反斜槓”。
當一行的最後一個非空白字符是一個未轉義的 \ 時,它會連同它後面的所有空白(包括換行)一起被去除,直到下一個非空白字符或結束引號爲止。

organization = """\\GitHub               \
asdfsadf"""
解析結果:\GitHub               asdfsadf

MIME 類型

在互聯網上傳輸 TOML 文件時,恰當的 MIME 類型是 application/toml。

golang 使用 toml

截止當前時間, github star 13.5k, https://github.com/toml-lang/toml

go toml
go1.13.5 v0.3.1

example.toml

# This is a TOML document. Boom.

title = "TOML Example"

[owner]
name = "Tom Preston-Werner"
organization = """\\GitHub               \
asdfsadf"""
bio = "GitHub Cofounder & CEO\nLikes tater tots and beer."
dob = 1979-05-27T07:32:00Z # First class dates? Why not?

[database]
server = "192.168.1.1"
ports = [ 8001, 8001, 8002 ]
connection_max = 5000
enabled = true

[servers]

  # You can indent as you please. Tabs or spaces. TOML don't care.
  [servers.alpha]
  ip = "10.0.0.1"
  dc = "eqdc10"

  [servers.beta]
  ip = "10.0.0.2"
  dc = "eqdc10"

[clients]
data = [ ["gamma","","","","", "delta","1  s"," #   ", "1","    "], [1, 2] ] # just an update to make sure parsers support it

# Line breaks are OK when inside arrays
hosts = [
  "alpha",
  "omega"
]

example.go

package main

import (
	"fmt"
	"time"

	"github.com/BurntSushi/toml"
)

type tomlConfig struct {
	Title   string
	Owner   ownerInfo
	DB      database `toml:"database"`
	Servers map[string]server
	Clients clients
}

type ownerInfo struct {
	Name string
	Org  string `toml:"organization"`
	Bio  string
	DOB  time.Time
}

type database struct {
	Server  string
	Ports   []int
	ConnMax int `toml:"connection_max"`
	Enabled bool
}

type server struct {
	IP string
	DC string
}

type clients struct {
	Data  [][]interface{}
	Hosts []string
}

func main() {
	var config tomlConfig
	if _, err := toml.DecodeFile("example.toml", &config); err != nil {
		fmt.Println(err)
		return
	}

	fmt.Printf("Title: %s\n", config.Title)
	fmt.Printf("Owner: %s (%s, %s), Born: %s\n",
		config.Owner.Name, config.Owner.Org, config.Owner.Bio,
		config.Owner.DOB)
	fmt.Printf("Database: %s %v (Max conn. %d), Enabled? %v\n",
		config.DB.Server, config.DB.Ports, config.DB.ConnMax,
		config.DB.Enabled)
	for serverName, server := range config.Servers {
		fmt.Printf("Server: %s (%s, %s)\n", serverName, server.IP, server.DC)
	}
	fmt.Printf("Client data: %v\n", config.Clients.Data)
	fmt.Printf("Client hosts: %v\n", config.Clients.Hosts)
}

結果:

Title: TOML Example
Owner: Tom Preston-Werner (\GitHub               asdfsadf, GitHub Cofounder & CEO
Likes tater tots and beer.), Born: 1979-05-27 07:32:00 +0000 UTC
Database: 192.168.1.1 [8001 8001 8002] (Max conn. 5000), Enabled? true
Server: alpha (10.0.0.1, eqdc10)
Server: beta (10.0.0.2, eqdc10)
Client data: [[gamma     delta 1  s  #    1     ] [1 2]]
Client hosts: [alpha omega]

基本方法

  1. StrictDecoding 判斷哪些鍵值沒有被解碼
func TestStrictDecoding(t *testing.T) {
	var blob = `
	key1 = "value1"
	key2 = "value2"
	key3 = "value3"
	key4 = "value4"
	`
	type config struct {
		Key1 string
		Key3 string
	}

	var conf config
	md, err := toml.Decode(blob, &conf)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Undecoded keys: %q\n", md.Undecoded())
}

結果:

Undecoded keys: ["key2" "key4"]
  1. Unmarshal 將數據綁定到結構體中,如果解析前數據未知,可以使用接口接收
type order struct {
	Parts []map[string]interface{}
}
func TestUnmarshal(t *testing.T) {
	var blob = `
			[[parts]]
			type = "valve"
			id = "valve-1"
			size = 1.2
			rating = 4
			
			[[parts]]
			type = "valve"
			id = "valve-2"
			size = 2.1
			rating = 5
			`
	o := &order{}
	err := toml.Unmarshal([]byte(blob), o)
	if err != nil {
		log.Fatal(err)
	}
	for _, part := range o.Parts {
		fmt.Println(part)
	}
}

結果:

map[id:valve-1 rating:4 size:1.2 type:valve]
map[id:valve-2 rating:5 size:2.1 type:valve]
  1. 使用自定義的結構接收解析結果
type duration struct {
	time.Duration
}

func (d *duration) UnmarshalText(text []byte) error {
	var err error
	d.Duration, err = time.ParseDuration(string(text))
	return err
}
func TestName(t *testing.T) {
	blob := `
		[[song]]
		name = "Thunder Road"
		duration = "4m49s"
		
		[[song]]
		name = "Stairway to Heaven"
		duration = "8m03s"
		`
	type song struct {
		Name     string
		Duration duration
	}
	type songs struct {
		Song []song
	}
	var favorites songs
	if _, err := toml.Decode(blob, &favorites); err != nil {
		log.Fatal(err)
	}
	for _, s := range favorites.Song {
		fmt.Printf("%s (%s)\n", s.Name, s.Duration)
	}
}

結果:

Thunder Road (4m49s)
Stairway to Heaven (8m3s)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章