github.com/kbehouse/nsc@v0.0.6/cmd/jsonpath.go (about)

     1  /*
     2   * Copyright 2020 The NATS Authors
     3   * Licensed under the Apache License, Version 2.0 (the "License");
     4   * you may not use this file except in compliance with the License.
     5   * You may obtain a copy of the License at
     6   *
     7   * http://www.apache.org/licenses/LICENSE-2.0
     8   *
     9   * Unless required by applicable law or agreed to in writing, software
    10   * distributed under the License is distributed on an "AS IS" BASIS,
    11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12   * See the License for the specific language governing permissions and
    13   * limitations under the License.
    14   */
    15  
    16  package cmd
    17  
    18  import (
    19  	"encoding/json"
    20  	"fmt"
    21  	"strconv"
    22  	"strings"
    23  )
    24  
    25  // Extracts a value from a JSON path - keys can be "name" or "person.name" or "persons[0].name"
    26  func GetField(data []byte, jp string) ([]byte, error) {
    27  	m := make(map[string]interface{})
    28  	if err := json.Unmarshal(data, &m); err != nil {
    29  		return nil, fmt.Errorf("error parsing json: %v", err)
    30  	}
    31  	var tokens []string
    32  	for _, v := range strings.Split(jp, ".") {
    33  		ob := strings.Index(v, "[")
    34  		if ob != -1 {
    35  			cb := strings.Index(v, "]")
    36  			if cb == -1 {
    37  				return nil, fmt.Errorf("bad path - unterminated index expression: %q in %q", v, jp)
    38  			}
    39  			n := v[:ob]
    40  			i := v[ob+1 : cb]
    41  			tokens = append(tokens, n, i)
    42  		} else {
    43  			tokens = append(tokens, v)
    44  		}
    45  	}
    46  
    47  	var d interface{}
    48  	d = m
    49  	for _, t := range tokens {
    50  		switch v := d.(type) {
    51  		case map[string]interface{}:
    52  			d = v[t]
    53  		case []interface{}:
    54  			idx, err := strconv.Atoi(t)
    55  			if err != nil {
    56  				return nil, fmt.Errorf("error parsing index: %q in %q", t, jp)
    57  			}
    58  			if idx > len(v) {
    59  				return nil, fmt.Errorf("index is out of bounds: %d in %q", idx, jp)
    60  			}
    61  			d = v[idx]
    62  		default:
    63  			return nil, fmt.Errorf("unable to extract %q in %q from %v", t, jp, v)
    64  		}
    65  	}
    66  	return json.Marshal(d)
    67  }