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)

猜你喜欢

转载自blog.csdn.net/luslin1711/article/details/106135891