DEV Community

mojatter
mojatter

Posted on • Edited on • Originally published at github.com

Tree - A simple structure for dealing with dynamic or unknown JSON/YAML in Go

Introduction

Go can parse dynamic json/yaml using the standard map[string]interface{}, etc. However, nested interface{} tends to result in ugly code.

Tree is one solution to this problem.

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.

Examples in Go

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"}
}
Enter fullscreen mode Exit fullscreen mode
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]]
}
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

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]
}
Enter fullscreen mode Exit fullscreen mode

tq

tq is a portable command-line JSON/YAML processor. For more information please refer to jarxorg/tree.

Usage

tq is a command-line JSON/YAML processor.

Usage:
  tq [flags] [query] ([file...])

Flags:
  -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)
  -O, --output string          output file
  -o, --output-format string   output format (json or yaml, default json)
  -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"
    ]
  }
Enter fullscreen mode Exit fullscreen mode

Top comments (0)