@@ -17,64 +17,62 @@ Go-toml provides the following features for using data parsed from TOML document
|
|||||||
|
|
||||||
* Load TOML documents from files and string data
|
* Load TOML documents from files and string data
|
||||||
* Easily navigate TOML structure using Tree
|
* Easily navigate TOML structure using Tree
|
||||||
|
* Mashaling and unmarshaling to and from data structures
|
||||||
* Line & column position data for all parsed elements
|
* Line & column position data for all parsed elements
|
||||||
* [Query support similar to JSON-Path](query/)
|
* [Query support similar to JSON-Path](query/)
|
||||||
* Syntax errors contain line and column numbers
|
* Syntax errors contain line and column numbers
|
||||||
|
|
||||||
Go-toml is designed to help cover use-cases not covered by reflection-based TOML parsing:
|
|
||||||
|
|
||||||
* Semantic evaluation of parsed TOML
|
|
||||||
* Informing a user of mistakes in the source document, after it has been parsed
|
|
||||||
* Programatic handling of default values on a case-by-case basis
|
|
||||||
* Using a TOML document as a flexible data-store
|
|
||||||
|
|
||||||
## Import
|
## Import
|
||||||
|
|
||||||
import "github.com/pelletier/go-toml"
|
```go
|
||||||
|
import "github.com/pelletier/go-toml"
|
||||||
## Usage
|
|
||||||
|
|
||||||
### Example
|
|
||||||
|
|
||||||
Say you have a TOML file that looks like this:
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[postgres]
|
|
||||||
user = "pelletier"
|
|
||||||
password = "mypassword"
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Read the username and password like this:
|
## Usage example
|
||||||
|
|
||||||
|
Read a TOML document:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
config, _ := toml.LoadString(`
|
||||||
"fmt"
|
[postgres]
|
||||||
"github.com/pelletier/go-toml"
|
user = "pelletier"
|
||||||
)
|
password = "mypassword"`)
|
||||||
|
// retrieve data directly
|
||||||
|
user := config.Get("postgres.user").(string)
|
||||||
|
|
||||||
config, err := toml.LoadFile("config.toml")
|
// or using an intermediate object
|
||||||
if err != nil {
|
postgresConfig := config.Get("postgres").(*toml.Tree)
|
||||||
fmt.Println("Error ", err.Error())
|
password = postgresConfig.Get("password").(string)
|
||||||
} else {
|
```
|
||||||
// retrieve data directly
|
|
||||||
user := config.Get("postgres.user").(string)
|
|
||||||
password := config.Get("postgres.password").(string)
|
|
||||||
|
|
||||||
// or using an intermediate object
|
Or use Unmarshal:
|
||||||
configTree := config.Get("postgres").(*toml.Tree)
|
|
||||||
user = configTree.Get("user").(string)
|
|
||||||
password = configTree.Get("password").(string)
|
|
||||||
fmt.Println("User is ", user, ". Password is ", password)
|
|
||||||
|
|
||||||
// show where elements are in the file
|
```go
|
||||||
fmt.Println("User position: %v", configTree.GetPosition("user"))
|
type Postgres struct {
|
||||||
fmt.Println("Password position: %v", configTree.GetPosition("password"))
|
User string
|
||||||
|
Password string
|
||||||
|
}
|
||||||
|
type Config struct {
|
||||||
|
Postgres Postgres
|
||||||
|
}
|
||||||
|
|
||||||
// use a query to gather elements without walking the tree
|
doc := []byte(`
|
||||||
results, _ := config.Query("$..[user,password]")
|
[postgres]
|
||||||
for ii, item := range results.Values() {
|
user = "pelletier"
|
||||||
fmt.Println("Query result %d: %v", ii, item)
|
password = "mypassword"`)
|
||||||
}
|
|
||||||
|
config := Config{}
|
||||||
|
Unmarshal(doc, &config)
|
||||||
|
fmt.Println("user=", config.Postgres.User)
|
||||||
|
```
|
||||||
|
|
||||||
|
Or use a query:
|
||||||
|
|
||||||
|
```go
|
||||||
|
// use a query to gather elements without walking the tree
|
||||||
|
results, _ := config.Query("$..[user,password]")
|
||||||
|
for ii, item := range results.Values() {
|
||||||
|
fmt.Println("Query result %d: %v", ii, item)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,8 @@
|
|||||||
|
// Tomljson reads TOML and converts to JSON.
|
||||||
|
//
|
||||||
|
// Usage:
|
||||||
|
// cat file.toml | tomljson > file.json
|
||||||
|
// tomljson file1.toml > file.json
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
@@ -1,3 +1,8 @@
|
|||||||
|
// Tomll is a linter for TOML
|
||||||
|
//
|
||||||
|
// Usage:
|
||||||
|
// cat file.toml | tomll > file_linted.toml
|
||||||
|
// tomll file1.toml file2.toml # lint the two files in place
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
@@ -1,79 +1,18 @@
|
|||||||
// Package toml is a TOML markup language parser.
|
// Package toml is a TOML parser and manipulation library.
|
||||||
//
|
//
|
||||||
// This version supports the specification as described in
|
// This version supports the specification as described in
|
||||||
// https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.4.0.md
|
// https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.4.0.md
|
||||||
//
|
//
|
||||||
// TOML Parsing
|
// Marshaling
|
||||||
//
|
//
|
||||||
// TOML data may be parsed in two ways: by file, or by string.
|
// Go-toml can marshal and unmarshal TOML documents from and to data
|
||||||
|
// structures.
|
||||||
//
|
//
|
||||||
// // load TOML data by filename
|
// TOML document as a tree
|
||||||
// tree, err := toml.LoadFile("filename.toml")
|
|
||||||
//
|
//
|
||||||
// // load TOML data stored in a string
|
// Go-toml can operate on a TOML document as a tree. Use one of the Load*
|
||||||
// tree, err := toml.Load(stringContainingTomlData)
|
// functions to parse TOML data and obtain a Tree instance, then one of its
|
||||||
//
|
// methods to manipulate the tree.
|
||||||
// Either way, the result is a Tree object that can be used to navigate the
|
|
||||||
// structure and data within the original document.
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// Getting data from the Tree
|
|
||||||
//
|
|
||||||
// After parsing TOML data with Load() or LoadFile(), use the Has() and Get()
|
|
||||||
// methods on the returned Tree, to find your way through the document data.
|
|
||||||
//
|
|
||||||
// if tree.Has("foo") {
|
|
||||||
// fmt.Println("foo is:", tree.Get("foo"))
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Working with Paths
|
|
||||||
//
|
|
||||||
// Go-toml has support for basic dot-separated key paths on the Has(), Get(), Set()
|
|
||||||
// and GetDefault() methods. These are the same kind of key paths used within the
|
|
||||||
// TOML specification for struct tames.
|
|
||||||
//
|
|
||||||
// // looks for a key named 'baz', within struct 'bar', within struct 'foo'
|
|
||||||
// tree.Has("foo.bar.baz")
|
|
||||||
//
|
|
||||||
// // returns the key at this path, if it is there
|
|
||||||
// tree.Get("foo.bar.baz")
|
|
||||||
//
|
|
||||||
// TOML allows keys to contain '.', which can cause this syntax to be problematic
|
|
||||||
// for some documents. In such cases, use the GetPath(), HasPath(), and SetPath(),
|
|
||||||
// methods to explicitly define the path. This form is also faster, since
|
|
||||||
// it avoids having to parse the passed key for '.' delimiters.
|
|
||||||
//
|
|
||||||
// // looks for a key named 'baz', within struct 'bar', within struct 'foo'
|
|
||||||
// tree.HasPath([]string{"foo","bar","baz"})
|
|
||||||
//
|
|
||||||
// // returns the key at this path, if it is there
|
|
||||||
// tree.GetPath([]string{"foo","bar","baz"})
|
|
||||||
//
|
|
||||||
// Note that this is distinct from the heavyweight query syntax supported by
|
|
||||||
// Tree.Query() and the Query() struct (see below).
|
|
||||||
//
|
|
||||||
// Position Support
|
|
||||||
//
|
|
||||||
// Each element within the Tree is stored with position metadata, which is
|
|
||||||
// invaluable for providing semantic feedback to a user. This helps in
|
|
||||||
// situations where the TOML file parses correctly, but contains data that is
|
|
||||||
// not correct for the application. In such cases, an error message can be
|
|
||||||
// generated that indicates the problem line and column number in the source
|
|
||||||
// TOML document.
|
|
||||||
//
|
|
||||||
// // load TOML data
|
|
||||||
// tree, _ := toml.Load("filename.toml")
|
|
||||||
//
|
|
||||||
// // get an entry and report an error if it's the wrong type
|
|
||||||
// element := tree.Get("foo")
|
|
||||||
// if value, ok := element.(int64); !ok {
|
|
||||||
// return fmt.Errorf("%v: Element 'foo' must be an integer", tree.GetPosition("foo"))
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // report an error if an expected element is missing
|
|
||||||
// if !tree.Has("bar") {
|
|
||||||
// return fmt.Errorf("%v: Expected 'bar' element", tree.GetPosition(""))
|
|
||||||
// }
|
|
||||||
//
|
//
|
||||||
// JSONPath-like queries
|
// JSONPath-like queries
|
||||||
//
|
//
|
||||||
|
|||||||
+26
-2
@@ -6,7 +6,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Example_comprehensiveExample() {
|
func Example_tree() {
|
||||||
config, err := LoadFile("config.toml")
|
config, err := LoadFile("config.toml")
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -20,10 +20,34 @@ func Example_comprehensiveExample() {
|
|||||||
configTree := config.Get("postgres").(*Tree)
|
configTree := config.Get("postgres").(*Tree)
|
||||||
user = configTree.Get("user").(string)
|
user = configTree.Get("user").(string)
|
||||||
password = configTree.Get("password").(string)
|
password = configTree.Get("password").(string)
|
||||||
fmt.Println("User is ", user, ". Password is ", password)
|
fmt.Println("User is", user, " and password is", password)
|
||||||
|
|
||||||
// show where elements are in the file
|
// show where elements are in the file
|
||||||
fmt.Printf("User position: %v\n", configTree.GetPosition("user"))
|
fmt.Printf("User position: %v\n", configTree.GetPosition("user"))
|
||||||
fmt.Printf("Password position: %v\n", configTree.GetPosition("password"))
|
fmt.Printf("Password position: %v\n", configTree.GetPosition("password"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Example_unmarshal() {
|
||||||
|
type Employer struct {
|
||||||
|
Name string
|
||||||
|
Phone string
|
||||||
|
}
|
||||||
|
type Person struct {
|
||||||
|
Name string
|
||||||
|
Age int64
|
||||||
|
Employer Employer
|
||||||
|
}
|
||||||
|
|
||||||
|
document := []byte(`
|
||||||
|
name = "John"
|
||||||
|
age = 30
|
||||||
|
[employer]
|
||||||
|
name = "Company Inc."
|
||||||
|
phone = "+1 234 567 89012"
|
||||||
|
`)
|
||||||
|
|
||||||
|
person := Person{}
|
||||||
|
Unmarshal(document, &person)
|
||||||
|
fmt.Println(person.Name, "is", person.Age, "and works at", person.Employer.Name)
|
||||||
|
}
|
||||||
|
|||||||
+18
-18
@@ -9,24 +9,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
|
||||||
Tree structural types and corresponding marshal types
|
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
*Tree (*)struct, (*)map[string]interface{}
|
|
||||||
[]*Tree (*)[](*)struct, (*)[](*)map[string]interface{}
|
|
||||||
[]interface{} (as interface{}) (*)[]primitive, (*)[]([]interface{})
|
|
||||||
interface{} (*)primitive
|
|
||||||
|
|
||||||
Tree primitive types and corresponding marshal types
|
|
||||||
-----------------------------------------------------------
|
|
||||||
uint64 uint, uint8-uint64, pointers to same
|
|
||||||
int64 int, int8-uint64, pointers to same
|
|
||||||
float64 float32, float64, pointers to same
|
|
||||||
string string, pointers to same
|
|
||||||
bool bool, pointers to same
|
|
||||||
time.Time time.Time{}, pointers to same
|
|
||||||
*/
|
|
||||||
|
|
||||||
type tomlOpts struct {
|
type tomlOpts struct {
|
||||||
name string
|
name string
|
||||||
include bool
|
include bool
|
||||||
@@ -115,6 +97,22 @@ function for sub-structs, and currently only definite types can be marshaled
|
|||||||
Note that pointers are automatically assigned the "omitempty" option, as TOML
|
Note that pointers are automatically assigned the "omitempty" option, as TOML
|
||||||
explicity does not handle null values (saying instead the label should be
|
explicity does not handle null values (saying instead the label should be
|
||||||
dropped).
|
dropped).
|
||||||
|
|
||||||
|
Tree structural types and corresponding marshal types:
|
||||||
|
|
||||||
|
*Tree (*)struct, (*)map[string]interface{}
|
||||||
|
[]*Tree (*)[](*)struct, (*)[](*)map[string]interface{}
|
||||||
|
[]interface{} (as interface{}) (*)[]primitive, (*)[]([]interface{})
|
||||||
|
interface{} (*)primitive
|
||||||
|
|
||||||
|
Tree primitive types and corresponding marshal types:
|
||||||
|
|
||||||
|
uint64 uint, uint8-uint64, pointers to same
|
||||||
|
int64 int, int8-uint64, pointers to same
|
||||||
|
float64 float32, float64, pointers to same
|
||||||
|
string string, pointers to same
|
||||||
|
bool bool, pointers to same
|
||||||
|
time.Time time.Time{}, pointers to same
|
||||||
*/
|
*/
|
||||||
func Marshal(v interface{}) ([]byte, error) {
|
func Marshal(v interface{}) ([]byte, error) {
|
||||||
mtype := reflect.TypeOf(v)
|
mtype := reflect.TypeOf(v)
|
||||||
@@ -247,6 +245,8 @@ func (t *Tree) Unmarshal(v interface{}) error {
|
|||||||
// is no concept of an Unmarshaler interface or UnmarshalTOML function for
|
// is no concept of an Unmarshaler interface or UnmarshalTOML function for
|
||||||
// sub-structs, and currently only definite types can be unmarshaled to (i.e. no
|
// sub-structs, and currently only definite types can be unmarshaled to (i.e. no
|
||||||
// `interface{}`).
|
// `interface{}`).
|
||||||
|
//
|
||||||
|
// See Marshal() documentation for types mapping table.
|
||||||
func Unmarshal(data []byte, v interface{}) error {
|
func Unmarshal(data []byte, v interface{}) error {
|
||||||
t, err := LoadReader(bytes.NewReader(data))
|
t, err := LoadReader(bytes.NewReader(data))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -177,6 +177,25 @@ func TestDocUnmarshal(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ExampleUnmarshal() {
|
||||||
|
type Postgres struct {
|
||||||
|
User string
|
||||||
|
Password string
|
||||||
|
}
|
||||||
|
type Config struct {
|
||||||
|
Postgres Postgres
|
||||||
|
}
|
||||||
|
|
||||||
|
doc := []byte(`
|
||||||
|
[postgres]
|
||||||
|
user = "pelletier"
|
||||||
|
password = "mypassword"`)
|
||||||
|
|
||||||
|
config := Config{}
|
||||||
|
Unmarshal(doc, &config)
|
||||||
|
fmt.Println("user=", config.Postgres.User)
|
||||||
|
}
|
||||||
|
|
||||||
func TestDocPartialUnmarshal(t *testing.T) {
|
func TestDocPartialUnmarshal(t *testing.T) {
|
||||||
result := testDocSubs{}
|
result := testDocSubs{}
|
||||||
|
|
||||||
|
|||||||
@@ -54,8 +54,7 @@ func (t *Tree) HasPath(keys []string) bool {
|
|||||||
return t.GetPath(keys) != nil
|
return t.GetPath(keys) != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keys returns the keys of the toplevel tree.
|
// Keys returns the keys of the toplevel tree (does not recurse).
|
||||||
// Warning: this is a costly operation.
|
|
||||||
func (t *Tree) Keys() []string {
|
func (t *Tree) Keys() []string {
|
||||||
keys := make([]string, len(t.values))
|
keys := make([]string, len(t.values))
|
||||||
i := 0
|
i := 0
|
||||||
|
|||||||
Reference in New Issue
Block a user