mirror of
https://github.com/Luzifer/worktime.git
synced 2024-12-23 14:31:16 +00:00
250 lines
8.6 KiB
Go
250 lines
8.6 KiB
Go
// Package toml is a TOML markup language parser.
|
|
//
|
|
// This version supports the specification as described in
|
|
// https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.4.0.md
|
|
//
|
|
// TOML Parsing
|
|
//
|
|
// TOML data may be parsed in two ways: by file, or by string.
|
|
//
|
|
// // load TOML data by filename
|
|
// tree, err := toml.LoadFile("filename.toml")
|
|
//
|
|
// // load TOML data stored in a string
|
|
// tree, err := toml.Load(stringContainingTomlData)
|
|
//
|
|
// Either way, the result is a TomlTree object that can be used to navigate the
|
|
// structure and data within the original document.
|
|
//
|
|
//
|
|
// Getting data from the TomlTree
|
|
//
|
|
// After parsing TOML data with Load() or LoadFile(), use the Has() and Get()
|
|
// methods on the returned TomlTree, to find your way through the document data.
|
|
//
|
|
// if tree.Has('foo') {
|
|
// fmt.Prinln("foo is: %v", 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
|
|
// TomlTree.Query() and the Query() struct (see below).
|
|
//
|
|
// Position Support
|
|
//
|
|
// Each element within the TomlTree 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(""))
|
|
// }
|
|
//
|
|
// Query Support
|
|
//
|
|
// The TOML query path implementation is based loosely on the JSONPath specification:
|
|
// http://goessner.net/articles/JsonPath/
|
|
//
|
|
// The idea behind a query path is to allow quick access to any element, or set
|
|
// of elements within TOML document, with a single expression.
|
|
//
|
|
// result, err := tree.Query("$.foo.bar.baz")
|
|
//
|
|
// This is roughly equivalent to:
|
|
//
|
|
// next := tree.Get("foo")
|
|
// if next != nil {
|
|
// next = next.Get("bar")
|
|
// if next != nil {
|
|
// next = next.Get("baz")
|
|
// }
|
|
// }
|
|
// result := next
|
|
//
|
|
// err is nil if any parsing exception occurs.
|
|
//
|
|
// If no node in the tree matches the query, result will simply contain an empty list of
|
|
// items.
|
|
//
|
|
// As illustrated above, the query path is much more efficient, especially since
|
|
// the structure of the TOML file can vary. Rather than making assumptions about
|
|
// a document's structure, a query allows the programmer to make structured
|
|
// requests into the document, and get zero or more values as a result.
|
|
//
|
|
// The syntax of a query begins with a root token, followed by any number
|
|
// sub-expressions:
|
|
//
|
|
// $
|
|
// Root of the TOML tree. This must always come first.
|
|
// .name
|
|
// Selects child of this node, where 'name' is a TOML key
|
|
// name.
|
|
// ['name']
|
|
// Selects child of this node, where 'name' is a string
|
|
// containing a TOML key name.
|
|
// [index]
|
|
// Selcts child array element at 'index'.
|
|
// ..expr
|
|
// Recursively selects all children, filtered by an a union,
|
|
// index, or slice expression.
|
|
// ..*
|
|
// Recursive selection of all nodes at this point in the
|
|
// tree.
|
|
// .*
|
|
// Selects all children of the current node.
|
|
// [expr,expr]
|
|
// Union operator - a logical 'or' grouping of two or more
|
|
// sub-expressions: index, key name, or filter.
|
|
// [start:end:step]
|
|
// Slice operator - selects array elements from start to
|
|
// end-1, at the given step. All three arguments are
|
|
// optional.
|
|
// [?(filter)]
|
|
// Named filter expression - the function 'filter' is
|
|
// used to filter children at this node.
|
|
//
|
|
// Query Indexes And Slices
|
|
//
|
|
// Index expressions perform no bounds checking, and will contribute no
|
|
// values to the result set if the provided index or index range is invalid.
|
|
// Negative indexes represent values from the end of the array, counting backwards.
|
|
//
|
|
// // select the last index of the array named 'foo'
|
|
// tree.Query("$.foo[-1]")
|
|
//
|
|
// Slice expressions are supported, by using ':' to separate a start/end index pair.
|
|
//
|
|
// // select up to the first five elements in the array
|
|
// tree.Query("$.foo[0:5]")
|
|
//
|
|
// Slice expressions also allow negative indexes for the start and stop
|
|
// arguments.
|
|
//
|
|
// // select all array elements.
|
|
// tree.Query("$.foo[0:-1]")
|
|
//
|
|
// Slice expressions may have an optional stride/step parameter:
|
|
//
|
|
// // select every other element
|
|
// tree.Query("$.foo[0:-1:2]")
|
|
//
|
|
// Slice start and end parameters are also optional:
|
|
//
|
|
// // these are all equivalent and select all the values in the array
|
|
// tree.Query("$.foo[:]")
|
|
// tree.Query("$.foo[0:]")
|
|
// tree.Query("$.foo[:-1]")
|
|
// tree.Query("$.foo[0:-1:]")
|
|
// tree.Query("$.foo[::1]")
|
|
// tree.Query("$.foo[0::1]")
|
|
// tree.Query("$.foo[:-1:1]")
|
|
// tree.Query("$.foo[0:-1:1]")
|
|
//
|
|
// Query Filters
|
|
//
|
|
// Query filters are used within a Union [,] or single Filter [] expression.
|
|
// A filter only allows nodes that qualify through to the next expression,
|
|
// and/or into the result set.
|
|
//
|
|
// // returns children of foo that are permitted by the 'bar' filter.
|
|
// tree.Query("$.foo[?(bar)]")
|
|
//
|
|
// There are several filters provided with the library:
|
|
//
|
|
// tree
|
|
// Allows nodes of type TomlTree.
|
|
// int
|
|
// Allows nodes of type int64.
|
|
// float
|
|
// Allows nodes of type float64.
|
|
// string
|
|
// Allows nodes of type string.
|
|
// time
|
|
// Allows nodes of type time.Time.
|
|
// bool
|
|
// Allows nodes of type bool.
|
|
//
|
|
// Query Results
|
|
//
|
|
// An executed query returns a QueryResult object. This contains the nodes
|
|
// in the TOML tree that qualify the query expression. Position information
|
|
// is also available for each value in the set.
|
|
//
|
|
// // display the results of a query
|
|
// results := tree.Query("$.foo.bar.baz")
|
|
// for idx, value := results.Values() {
|
|
// fmt.Println("%v: %v", results.Positions()[idx], value)
|
|
// }
|
|
//
|
|
// Compiled Queries
|
|
//
|
|
// Queries may be executed directly on a TomlTree object, or compiled ahead
|
|
// of time and executed discretely. The former is more convienent, but has the
|
|
// penalty of having to recompile the query expression each time.
|
|
//
|
|
// // basic query
|
|
// results := tree.Query("$.foo.bar.baz")
|
|
//
|
|
// // compiled query
|
|
// query := toml.CompileQuery("$.foo.bar.baz")
|
|
// results := query.Execute(tree)
|
|
//
|
|
// // run the compiled query again on a different tree
|
|
// moreResults := query.Execute(anotherTree)
|
|
//
|
|
// User Defined Query Filters
|
|
//
|
|
// Filter expressions may also be user defined by using the SetFilter()
|
|
// function on the Query object. The function must return true/false, which
|
|
// signifies if the passed node is kept or discarded, respectively.
|
|
//
|
|
// // create a query that references a user-defined filter
|
|
// query, _ := CompileQuery("$[?(bazOnly)]")
|
|
//
|
|
// // define the filter, and assign it to the query
|
|
// query.SetFilter("bazOnly", func(node interface{}) bool{
|
|
// if tree, ok := node.(*TomlTree); ok {
|
|
// return tree.Has("baz")
|
|
// }
|
|
// return false // reject all other node types
|
|
// })
|
|
//
|
|
// // run the query
|
|
// query.Execute(tree)
|
|
//
|
|
package toml
|