参考文档: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
在互联网上传输 TOML 文件时,恰当的 MIME 类型是 application/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]
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"]
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]
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)