Skip to content

Commit

Permalink
Enhance it a bit
Browse files Browse the repository at this point in the history
  • Loading branch information
jastBytes committed Aug 10, 2020
1 parent 03b3d67 commit 90170cc
Show file tree
Hide file tree
Showing 5 changed files with 148 additions and 34 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1 @@
/jsonpath
/jp
23 changes: 23 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
GO ?= go
LINTER ?= golangci-lint
BUILDFLAGS += -installsuffix cgo --tags release

BUILD_PATH ?= $(shell pwd)

CMD = $(BUILD_PATH)/jp
CMD_SRC = cmd/*.go

all: lint clean build

.PHONY: build lint clean

clean:
rm -f $(CMD)

lint:
$(LINTER) run -v --no-config --deadline=5m

$(CMD):
CGO_ENABLED=0 GOOS=linux $(GO) build -o $(CMD) -a $(BUILDFLAGS) $(LDFLAGS) $(CMD_SRC)

build: $(CMD)
43 changes: 23 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,25 +1,28 @@
# jsonpath
# jp (jsonPath)

Find a path to a key in nested JSON structures.
A simple commandline tool to find the path to a key in nested JSON structures. Reads json from stdin.

## Example
## Usage

```
Usage:
jp [flags]
Flags:
-h, --help help for jp
-k, --key string Key to search for
-v, --show-value If enabled, will show the value for found path
```
$ cat example.json
{"items":{"item":[{"id":"0001","type":"donut","name":"Cake","ppu":0.55,"batters":{"batter":[{"id":"1001","type":"Regular"},{"id":"1002","type":"Chocolate"},{"id":"1003","type":"Blueberry"},{"id":"1004","type":"Devil's Food"}]},"topping":[{"id":"5001","type":"None"},{"id":"5002","type":"Glazed"},{"id":"5005","type":"Sugar"},{"id":"5007","type":"Powdered Sugar"},{"id":"5006","type":"Chocolate with Sprinkles"},{"id":"5003","type":"Chocolate"},{"id":"5004","type":"Maple"}]}]}}
$ jsonpath topping < example.json
.items.item[0].topping
$ jsonpath type < example.json
.items.item[0].type
.items.item[0].batters.batter[0].type
.items.item[0].batters.batter[1].type
.items.item[0].batters.batter[2].type
.items.item[0].batters.batter[3].type
.items.item[0].topping[0].type
.items.item[0].topping[1].type
.items.item[0].topping[2].type
.items.item[0].topping[3].type
.items.item[0].topping[4].type
.items.item[0].topping[5].type
.items.item[0].topping[6].type

## Example

```bash
$ kubectl get node node01 -ojson | jp -k osImage
.status.nodeInfo.osImage
$ kubectl get node node01 -ojson | jp -k osImage -v
.status.nodeInfo.osImage [Flatcar Container Linux by Kinvolk 2512.2.0 (Oklo)]
```

## Acknowledgements

* [cespare/jsonpath](https://github.com/cespare/jsonpath) - The source of this codebase
88 changes: 88 additions & 0 deletions cmd/jp.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package main

import (
"bufio"
"encoding/json"
"flag"
"fmt"
"os"

"gopkg.in/spf13/cobra.v0"
)

var (
key string
showValue bool
)

var jpCmd = &cobra.Command{
Use: "jp action [flags]",
Short: "JsonPath finds paths to a key in nested JSON structures.",
RunE: func(cmd *cobra.Command, args []string) error {
if key == "" {
return fmt.Errorf("key must not be empty")
}

scanner := bufio.NewScanner(os.Stdin)
bytes := make([]byte, 0)

for scanner.Scan() {
b := scanner.Bytes()
if len(b) == 0 {
continue
}
bytes = append(bytes, b...)
}

var v interface{}
if err := json.Unmarshal(bytes, &v); err != nil {
fmt.Fprintf(os.Stderr, "JSON parsing error: %s\n", err)
}
printPaths(v, key, "")

if err := scanner.Err(); err != nil {
return err
}

return nil
},
}

func init() {
flags := jpCmd.PersistentFlags()
flags.AddGoFlagSet(flag.CommandLine)
flags.StringVarP(&key, "key", "k", "", "Key to search for")
flags.BoolVarP(&showValue, "show-value", "v", false, "If enabled, will show the value for found path")
}

func printPaths(v interface{}, key, path string) {
switch v := v.(type) {
case map[string]interface{}:
for mk, mv := range v {
p := path + "." + mk
if mk == key {
if showValue {
fmt.Printf("%v [%v]\n", p, mv)
} else {
fmt.Println(p)
}
}
printPaths(mv, key, p)
}
case []interface{}:
for i, sv := range v {
printPaths(sv, key, fmt.Sprintf("%s[%d]", path, i))
}
}
}

func fatalln(args ...interface{}) {
fmt.Fprintln(os.Stderr, args...)
os.Exit(1)
}

func main() {
if err := jpCmd.Execute(); err != nil {
fatalln(err)
}
}
26 changes: 13 additions & 13 deletions jsonpath.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ func printPaths(v interface{}, key, path string) {
for mk, mv := range v {
p := path + "." + mk
if mk == key {
fmt.Println(p)
fmt.Printf("%v [%v]\n", p, mv)
}
printPaths(mv, key, p)
}
Expand All @@ -25,6 +25,18 @@ func printPaths(v interface{}, key, path string) {
}
}

func usage() {
fmt.Fprintf(os.Stderr, `usage:
%s key
where key is the key to search for in JSON structures passed to standard input.
`, os.Args[0])
}

func fatalln(args ...interface{}) {
fmt.Fprintln(os.Stderr, args...)
os.Exit(1)
}

func main() {
flag.Usage = usage
flag.Parse()
Expand Down Expand Up @@ -56,15 +68,3 @@ func main() {
fatalln(err)
}
}

func usage() {
fmt.Fprintf(os.Stderr, `usage:
%s key
where key is the key to search for in JSON structures passed to standard input.
`, os.Args[0])
}

func fatalln(args ...interface{}) {
fmt.Fprintln(os.Stderr, args...)
os.Exit(1)
}

0 comments on commit 90170cc

Please sign in to comment.