# README
Tree
Tree is a simple structure for dealing with dynamic or unknown JSON/YAML in Go.
Features
- Parses json/yaml of unknown structure to get to nodes with fluent interface.
- Syntax similar to Go standard and map and slice.
- Find function can be specified the Query expression.
- Edit function can be specified the Edit expression.
- Bundled 'tq' that is a portable command-line JSON/YAML processor.
Road to 1.0
- Placeholders in query.
- Merging nodes.
Syntax
Go
tree.Map{
"ID": tree.ToValue(1),
"Name": tree.ToValue("Reds"),
"Colors": tree.ToArrayValues("Crimson", "Red", "Ruby", "Maroon"),
}
JSON
{
"ID": 1,
"Name": "Reds",
"Colors": ["Crimson", "Red", "Ruby", "Maroon"]
}
YAML
ID: 1
Name: Reds
Colors:
- Crimson
- Red
- Ruby
- Maroon
Marshal and Unmarshal
func ExampleMarshalJSON() {
group := tree.Map{
"ID": tree.ToValue(1),
"Name": tree.ToValue("Reds"),
"Colors": tree.ToArrayValues("Crimson", "Red", "Ruby", "Maroon"),
}
b, err := json.Marshal(group)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(b))
// Output:
// {"Colors":["Crimson","Red","Ruby","Maroon"],"ID":1,"Name":"Reds"}
}
func ExampleUnmarshalJSON() {
data := []byte(`[
{"Name": "Platypus", "Order": "Monotremata"},
{"Name": "Quoll", "Order": "Dasyuromorphia"}
]`)
var animals tree.Array
err := json.Unmarshal(data, &animals)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%+v\n", animals)
// Output:
// [map[Name:Platypus Order:Monotremata] map[Name:Quoll Order:Dasyuromorphia]]
}
Using other parsers
Tree may works on other parsers those has compatible with "encoding/json" or "gopkg.in/yaml.v2". See examples directory.
Alternate json.RawMessage
For example, Dynamic JSON in Go shows an example of using json.RawMessage.
It may be simpler to use tree.Map instead of json.RawMessage.
package main
import (
"encoding/json"
"fmt"
"log"
"github.com/jarxorg/tree"
)
const input = `
{
"type": "sound",
"msg": {
"description": "dynamite",
"authority": "the Bruce Dickinson"
}
}
`
type Envelope struct {
Type string
Msg tree.Map
}
func main() {
env := Envelope{}
if err := json.Unmarshal([]byte(input), &env); err != nil {
log.Fatal(err)
}
fmt.Printf("%#v\n", env)
fmt.Printf("%#v\n", env.Msg.Get("description"))
// Output:
// main.Envelope{Type:"sound", Msg:tree.Map{"authority":"the Bruce Dickinson", "description":"dynamite"}}
// "dynamite"
}
Get
func ExampleGet() {
group := tree.Map{
"ID": tree.ToValue(1),
"Name": tree.ToValue("Reds"),
"Colors": tree.ToArrayValues("Crimson", "Red", "Ruby", "Maroon"),
"Nil": nil,
}
fmt.Println(group.Get("Colors").Get(1))
fmt.Println(group.Get("Colors", 2))
fmt.Println(group.Get("Colors").Get(5).IsNil())
fmt.Println(group.Get("Nil").IsNil())
// Output:
// Red
// Ruby
// true
// true
}
Find
func ExampleFind() {
group := tree.Map{
"ID": tree.ToValue(1),
"Name": tree.ToValue("Reds"),
"Colors": tree.ToArrayValues("Crimson", "Red", "Ruby", "Maroon"),
}
rs, err := group.Find(".Colors[1:3]")
if err != nil {
log.Fatal(err)
}
for _, r := range rs {
fmt.Println(r)
}
// Output:
// Red
// Ruby
}
Query
Query | Description | Results |
---|---|---|
.store.book[0] | The first book | {"category": "reference", "author": "Nigel Rees", "title": "Sayings of the Century", "price": 8.95} |
.store.book[0].price | The price of the first book | 8.95 |
.store.book.0.price | The price of the first book (using dot) | 8.95 |
.store.book[:2].price | All prices of books[0:2] (index 2 is exclusive) | 8.95, 12.99 |
.store.book[].author | All authors of all books | "Nigel Rees", "Evelyn Waugh", "Herman Melville", "J. R. R. Tolkien" |
..author | All authors | "Nigel Rees", "Evelyn Waugh", "Herman Melville", "J. R. R. Tolkien" |
..author | [0] | The first author | "Nigel Rees" |
.store.book[(.category == "fiction" or .category == "reference") and .price < 10].title | All titles of books these are categoried into "fiction", "reference" and price < 10 | "Sayings of the Century", "Moby Dick" |
.store.book[.title ~= "^S"].title | Titles beginning with "S" | "Sayings of the Century", "Sword of Honour" |
.store.book.count() | Count books | 4 |
.store.book[0].keys() | Sorted keys of the first book | ["author", "category", "price", "title"] |
.store.book[0].values() | Values of the first book | ["Nigel Rees", "reference", 8.95, "Sayings of the Century"] |
Illustrative Object
{
"store": {
"book": [{
"category": "reference",
"author": "Nigel Rees",
"title": "Sayings of the Century",
"price": 8.95
},
{
"category": "fiction",
"author": "Evelyn Waugh",
"title": "Sword of Honour",
"price": 12.99
},
{
"category": "fiction",
"author": "Herman Melville",
"title": "Moby Dick",
"isbn": "0-553-21311-3",
"price": 8.99
},
{
"category": "fiction",
"author": "J. R. R. Tolkien",
"title": "The Lord of the Rings",
"isbn": "0-395-19395-8",
"price": 22.99
}
],
"bicycle": {
"color": "red",
"price": 19.95
}
}
}
Edit
func ExampleEdit() {
var group tree.Node = tree.Map{
"ID": tree.ToValue(1),
"Name": tree.ToValue("Reds"),
"Colors": tree.ToArrayValues("Crimson", "Red", "Ruby", "Maroon"),
}
if err := tree.Edit(&group, ".Colors += \"Pink\""); err != nil {
log.Fatal(err)
}
fmt.Printf("Append Pink to Colors:\n %+v\n", group)
if err := tree.Edit(&group, ".Name = \"Blue\""); err != nil {
log.Fatal(err)
}
fmt.Printf("Set Blue to Name:\n %+v\n", group)
if err := tree.Edit(&group, ".Colors ^?"); err != nil {
log.Fatal(err)
}
fmt.Printf("Delete Colors:\n %+v\n", group)
// Output:
// Append Pink to Colors:
// map[Colors:[Crimson Red Ruby Maroon Pink] ID:1 Name:Reds]
// Set Blue to Name:
// map[Colors:[Crimson Red Ruby Maroon Pink] ID:1 Name:Blue]
// Delete Colors:
// map[ID:1 Name:Blue]
}
tq
tq is a portable command-line JSON/YAML processor.
Installation
go install github.com/jarxorg/tree/cmd/tq@latest
Using Homebrew
brew tap jarxorg/tree
brew install jarxorg/tree/tq
Download binary
VERSION=0.8.0 GOOS=Darwin GOARCH=arm64; curl -fsSL "https://github.com/jarxorg/tree/releases/download/v${VERSION}/tree_${VERSION}_${GOOS}_${GOARCH}.tar.gz" | tar xz tq && mv tq /usr/local/bin
Usage
tq is a command-line JSON/YAML processor.
Usage:
tq [flags] [query] ([file...])
Flags:
-c, --color output with colors
-e, --edit stringArray edit expression
-x, --expand expand results
-h, --help help for tq
-U, --inplace update files, inplace
-i, --input-format string input format (json or yaml)
-j, --input-json alias --input-format json
-y, --input-yaml alias --input-format yaml
-O, --output string output file
-o, --output-format string output format (json or yaml, default json)
-J, --output-json alias --output-format json
-Y, --output-yaml alias --output-format yaml
-r, --raw output raw strings
-s, --slurp slurp all results into an array
-t, --template string golang text/template string
-v, --version print version
Examples:
% echo '{"colors": ["red", "green", "blue"]}' | tq '.colors[0]'
"red"
% echo '{"users":[{"id":1,"name":"one"},{"id":2,"name":"two"}]}' | tq -x -t '{{.id}}: {{.name}}' '.users'
1: one
2: two
% echo '{}' | tq -e '.colors = ["red", "green"]' -e '.colors += "blue"' .
{
"colors": [
"red",
"green",
"blue"
]
}
for jq user
tq | jq |
---|---|
tq '.store.book[0]' | jq '.store.book[0]' |
tq '.store.book[]' | jq '.store.book[]' |
tq '.store.book[:2].price' | jq '.store.book[:2][] | .price' |
tq '.store.book[.category == "fiction" and .price < 10].title' | jq '.store.book[] | select(.category == "fiction" and .price < 10) | .title' |
Third-party library licenses
# Packages
No description provided by the author
# Functions
DecodeJSON decodes JSON as a node using the provided decoder.
DecodeYAML decodes YAML as a node using the provided decoder.
No description provided by the author
Find finds a node from n using the Query.
MarshalJSON returns the JSON encoding of the specified node.
MarshalViaJSON returns the node encoding of v via "encoding/json".
MarshalViaYAML returns the node encoding of v via "gopkg.in/yaml.v2".
MarshalYAML returns the YAML encoding of the specified node.
OutputColorJSON writes JSON values with color to out.
OutputColorYAML writes YAML values with color to out.
ParseQuery parses the provided expr to a Query.
No description provided by the author
ToArrayValues calss ToValues for each provided vs and returns them as an Array.
ToNode converts the specified v to an Node.
ToNodeValues calss ToValues for each provided vs and returns them as []Node.
ToValue converts the specified v to a Value as Node.
UnmarshalJSON parses the JSON-encoded data to a Node.
UnmarshalViaJSON stores the node in the value pointed to by v via "encoding/json".
UnmarshalViaYAML stores the node in the value pointed to by v via "gopkg.in/yaml.v2".
UnmarshalYAML returns the YAML encoding of the specified node.
Walk walks the node tree rooted at root, calling fn for each node or that children in the tree, including root.
# Constants
These variables are the Node types.
These variables are the Node types.
These variables are the Node types.
These variables are the Node types.
These variables are the Node types.
These variables are the Node types.
These variables are the Node types.
VERSION is the version number.
# Structs
Any is an interface that defines any node.
ColorEncoder writes JSON or YAML values with color to an output stream.
Comparator represents a comparable selector.
No description provided by the author
No description provided by the author
No description provided by the author
NopQuery is a query that implements no-op Exec method.
SelectQuery returns nodes that matched by selectors.
SlurpQuery is a special query that works in FilterQuery.
ValueQuery is a query that returns the constant value.
No description provided by the author
# Interfaces
EditorNode is an interface that defines the methods to edit this node.
EditorQuery is an interface that defines the methods to edit a node.
A Node is an element on the tree.
Query is an interface that defines the methods to query a node.
Selector checks if a node is eligible for selection.
Value provides the accessor of primitive value.
# Type aliases
And represents selectors that combines each selector with and.
Array represents an array of Node.
ArrayQuery is an index of the Array that implements methods of the Query.
ArrayRangeQuery represents a range of the Array that implements methods of the Query.
A BoolValue represents a bool value.
FilterQuery consists of multiple queries that filter the nodes in order.
Map represents a map of Node.
MapQuery is a key of the Map that implements methods of the Query.
A NumberValue represents an number value.
Operator represents an operator.
Or represents selectors that combines each selector with or.
A StringValue represents a string value.
Type represents the Node type.
WalkFunc is the type of the function called by Walk to visit each nodes.
WalkQuery is a key of each nodes that implements methods of the Query.