Documentation
¶
Overview ¶
Package jsonpath implements RFC 9535 JSONPath query expressions. It operates on any type of slice or string-keyed map.
Example ¶
Select all the authors of the books in a bookstore object.
package main
import (
"encoding/json"
"fmt"
"log"
"github.com/theory/jsonpath"
)
func main() {
// Parse a jsonpath query.
p, err := jsonpath.Parse(`$.store.book[*].author`)
if err != nil {
log.Fatal(err)
}
// Select values from unmarshaled JSON input.
store := bookstore()
nodes := p.Select(store)
// Show the selected values.
items, err := json.Marshal(nodes)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s\n", items)
}
// bookstore returns an unmarshaled JSON object.
func bookstore() any {
src := []byte(`{
"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": 399
}
}
}`)
var value any
if err := json.Unmarshal(src, &value); err != nil {
log.Fatal(err)
}
return value
}
Output: ["Nigel Rees","Evelyn Waugh","Herman Melville","J. R. R. Tolkien"]
Index ¶
- Variables
- type LocatedNodeList
- func (list LocatedNodeList) All() iter.Seq[*spec.LocatedNode]
- func (list LocatedNodeList) Clone() LocatedNodeList
- func (list LocatedNodeList) Deduplicate() LocatedNodeList
- func (list LocatedNodeList) Nodes() iter.Seq[any]
- func (list LocatedNodeList) Paths() iter.Seq[spec.NormalizedPath]
- func (list LocatedNodeList) Sort()
- type NodeList
- type Option
- type Parser
- type Path
- func (p *Path) MarshalBinary() ([]byte, error)
- func (p *Path) MarshalText() ([]byte, error)
- func (p *Path) Query() *spec.PathQuery
- func (p *Path) Select(input any) NodeList
- func (p *Path) SelectLocated(input any) LocatedNodeList
- func (p *Path) String() string
- func (p *Path) UnmarshalBinary(data []byte) error
- func (p *Path) UnmarshalText(data []byte) error
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ErrPathParse = parser.ErrPathParse
ErrPathParse errors are returned for path parse errors.
Functions ¶
This section is empty.
Types ¶
type LocatedNodeList ¶ added in v0.3.0
type LocatedNodeList []*spec.LocatedNode
LocatedNodeList is a list of nodes selected by a JSONPath query, along with their spec.NormalizedPath locations. Returned by Path.SelectLocated.
Example ¶
package main
import (
"fmt"
"github.com/theory/jsonpath"
)
func main() {
// Load some JSON.
menu := map[string]any{
"apps": map[string]any{
"guacamole": 19.99,
"salsa": 5.99,
},
}
// Parse a JSONPath and select from the input.
p := jsonpath.MustParse(`$.apps["salsa", "guacamole"]`)
nodes := p.SelectLocated(menu)
// Show the nodes.
fmt.Println("Nodes:")
for n := range nodes.Nodes() {
fmt.Printf(" %v\n", n)
}
// Show the paths.
fmt.Println("\nPaths:")
for p := range nodes.Paths() {
fmt.Printf(" %v\n", p)
}
}
Output: Nodes: 5.99 19.99 Paths: $['apps']['salsa'] $['apps']['guacamole']
func (LocatedNodeList) All ¶ added in v0.3.0
func (list LocatedNodeList) All() iter.Seq[*spec.LocatedNode]
All returns an iterator over all the nodes in list.
Range over list itself to get indexes and node values.
func (LocatedNodeList) Clone ¶ added in v0.3.0
func (list LocatedNodeList) Clone() LocatedNodeList
Clone returns a shallow copy of list.
Example ¶
package main
import (
"fmt"
"github.com/theory/jsonpath"
)
func main() {
// Load some JSON.
items := []int{1, 2, 3, 4, 5}
// Parse a JSONPath and select from the input.
p := jsonpath.MustParse("$[2, 0, 1, 0, 1]")
nodes := p.SelectLocated(items)
// Clone the selected nodes then deduplicate.
orig := nodes.Clone()
nodes = nodes.Deduplicate()
// Cloned nodes have the original count.
fmt.Printf("Unique Count: %v\nOriginal Count: %v\n", len(nodes), len(orig))
}
Output: Unique Count: 3 Original Count: 5
func (LocatedNodeList) Deduplicate ¶ added in v0.3.0
func (list LocatedNodeList) Deduplicate() LocatedNodeList
Deduplicate deduplicates the nodes in list based on their spec.NormalizedPath values, modifying the contents of list. It returns the modified list, which may have a shorter length, and zeroes the elements between the new length and the original length.
Example ¶
package main
import (
"fmt"
"github.com/theory/jsonpath"
)
func main() {
// Load some JSON.
pallet := map[string]any{"colors": []string{"red", "blue"}}
// Parse a JSONPath and select from the input.
p := jsonpath.MustParse("$.colors[0, 1, 1, 0]")
nodes := p.SelectLocated(pallet)
fmt.Printf("Items: %v\n", len(nodes))
// Deduplicate
nodes = nodes.Deduplicate()
fmt.Printf("Items: %v\n", len(nodes))
}
Output: Items: 4 Items: 2
func (LocatedNodeList) Nodes ¶ added in v0.3.0
func (list LocatedNodeList) Nodes() iter.Seq[any]
Nodes returns an iterator over all the nodes in list. This is the same data as returned by Path.Select.
func (LocatedNodeList) Paths ¶ added in v0.3.0
func (list LocatedNodeList) Paths() iter.Seq[spec.NormalizedPath]
Paths returns an iterator over all the spec.NormalizedPath values in list.
func (LocatedNodeList) Sort ¶ added in v0.3.0
func (list LocatedNodeList) Sort()
Sort sorts list by the spec.NormalizedPath of each node.
Example ¶
package main
import (
"fmt"
"github.com/theory/jsonpath"
)
func main() {
// Load some JSON.
pallet := map[string]any{"colors": []string{"red", "blue", "green"}}
// Parse a JSONPath and select from the input.
p := jsonpath.MustParse("$.colors[2, 0, 1]")
nodes := p.SelectLocated(pallet)
// Show selected.
fmt.Println("Selected:")
for _, node := range nodes {
fmt.Printf(" %v: %v\n", node.Path, node.Node)
}
// Sort by normalized paths and show selected again.
nodes.Sort()
fmt.Println("\nSorted:")
for _, node := range nodes {
fmt.Printf(" %v: %v\n", node.Path, node.Node)
}
}
Output: Selected: $['colors'][2]: green $['colors'][0]: red $['colors'][1]: blue Sorted: $['colors'][0]: red $['colors'][1]: blue $['colors'][2]: green
type NodeList ¶ added in v0.3.0
type NodeList []any
NodeList is a list of nodes selected by a JSONPath query. Each node represents a single JSON value selected from the JSON query argument. Returned by Path.Select.
type Option ¶
type Option func(*Parser)
Option defines a parser option.
func WithRegistry ¶
WithRegistry configures a Parser with a registry.Registry, which may contain function extensions.
Example ¶
Use WithRegistry to create a Parser that uses a registry.Registry containing function extensions, as defined by the standard. This example creates a function named "first" that returns the first item in a list of nodes.
package main
import (
"errors"
"fmt"
"log"
"github.com/theory/jsonpath"
"github.com/theory/jsonpath/registry"
"github.com/theory/jsonpath/spec"
)
func main() {
// Register the first function.
reg := registry.New()
err := reg.Register(
"first", // name
spec.FuncValue, // returns a single value
validateFirstArgs, // parse-time validation defined below
firstFunc, // function defined below
)
if err != nil {
log.Fatalf("Error %v", err)
}
// Create a parser with the registry that contains the extension.
parser := jsonpath.NewParser(jsonpath.WithRegistry(reg))
// Use the function to select lists that start with 6.
path, err := parser.Parse("$[? first(@.*) == 6]")
if err != nil {
log.Fatalf("Error %v", err)
}
// Do any of these arrays start with 6?
input := []any{
[]int{1, 2, 3, 4, 5},
[]int{6, 7, 8, 9},
[]int{4, 8, 12},
}
nodes := path.Select(input)
fmt.Printf("%v\n", nodes)
}
// validateFirstArgs validates that a single argument is passed to the first()
// function, and that it can be converted to [spec.NodesType], so that first()
// can return the first node. It's called by the parser.
func validateFirstArgs(args []spec.FuncExprArg) error {
if len(args) != 1 {
return fmt.Errorf("expected 1 argument but found %v", len(args))
}
if !args[0].ConvertsTo(spec.FuncNodes) {
return errors.New("cannot convert argument to nodes")
}
return nil
}
// firstFunc defines the custom first() JSONPath function. It converts its
// single argument to a [spec.NodesType] value and returns a [spec.ValueType]
// that contains the first node. If there are no nodes it returns nil.
func firstFunc(jv []spec.PathValue) spec.PathValue {
nodes := spec.NodesFrom(jv[0])
if len(nodes) == 0 {
return nil
}
return spec.Value(nodes[0])
}
Output: [[6 7 8 9]]
type Parser ¶
type Parser struct {
// contains filtered or unexported fields
}
Parser parses JSONPath strings into Path values.
Example ¶
Use the Parser to parse a collection of paths.
package main
import (
"encoding/json"
"fmt"
"log"
"github.com/theory/jsonpath"
)
func main() {
// Create a new parser using the default function registry.
parser := jsonpath.NewParser()
// Parse a list of paths.
strings := []string{
"$.store.book[*].author",
"$..author",
"$.store..color",
"$..book[2].author",
"$..book[2].publisher",
"$..book[?@.isbn].title",
"$..book[?@.price<10].title",
}
paths := make([]*jsonpath.Path, 0, len(strings))
for _, path := range strings {
p, err := parser.Parse(path)
if err != nil {
log.Fatal(err)
}
paths = append(paths, p)
}
// Later, use the paths to select from JSON inputs.
store := bookstore()
for _, p := range paths {
items := p.Select(store)
array, err := json.Marshal(items)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s\n", array)
}
}
// bookstore returns an unmarshaled JSON object.
func bookstore() any {
src := []byte(`{
"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": 399
}
}
}`)
var value any
if err := json.Unmarshal(src, &value); err != nil {
log.Fatal(err)
}
return value
}
Output: ["Nigel Rees","Evelyn Waugh","Herman Melville","J. R. R. Tolkien"] ["Nigel Rees","Evelyn Waugh","Herman Melville","J. R. R. Tolkien"] ["red"] ["Herman Melville"] [] ["Moby Dick","The Lord of the Rings"] ["Sayings of the Century","Moby Dick"]
func (*Parser) MustParse ¶
MustParse parses path, a JSONPath query string, into a Path. Panics with an ErrPathParse on parse failure.
type Path ¶
type Path struct {
// contains filtered or unexported fields
}
Path represents a RFC 9535 JSONPath query.
func MustParse ¶
MustParse parses path into a Path. Panics with an ErrPathParse on parse failure.
func Parse ¶
Parse parses path, a JSONPath query string, into a Path. Returns an ErrPathParse on parse failure.
func (*Path) MarshalBinary ¶ added in v0.10.0
MarshalBinary encodes p into UTF-8-encoded bytes and returns the result. Implements encoding.BinaryMarshaler.
func (*Path) MarshalText ¶ added in v0.10.0
MarshalText encodes p into UTF-8-encoded text and returns the result. Implements encoding.TextMarshaler.
func (*Path) Select ¶
Select returns the nodes that JSONPath query p selects from input.
Example ¶
package main
import (
"fmt"
"github.com/theory/jsonpath"
)
func main() {
// Load some JSON.
menu := map[string]any{
"apps": map[string]any{
"guacamole": 19.99,
"salsa": 5.99,
},
}
// Parse a JSONPath and select from the input.
p := jsonpath.MustParse("$.apps.*")
nodes := p.Select(menu)
// Show the selected values.
for node := range nodes.All() {
fmt.Printf("%v\n", node)
}
}
Output: 19.99 5.99
func (*Path) SelectLocated ¶ added in v0.3.0
func (p *Path) SelectLocated(input any) LocatedNodeList
SelectLocated returns the nodes that JSONPath query p selects from input as spec.LocatedNode values that pair the nodes with the normalized paths that identify them. Unless you have a specific need for the unique spec.NormalizedPath for each value, you probably want to use Path.Select.
Example ¶
package main
import (
"fmt"
"github.com/theory/jsonpath"
)
func main() {
// Load some JSON.
menu := map[string]any{
"apps": map[string]any{
"guacamole": 19.99,
"salsa": 5.99,
},
}
// Parse a JSONPath and select from the input.
p := jsonpath.MustParse("$.apps.*")
nodes := p.SelectLocated(menu)
// Show the selected nodes.
for node := range nodes.All() {
fmt.Printf("%v: %v\n", node.Path, node.Node)
}
}
Output: $['apps']['guacamole']: 19.99 $['apps']['salsa']: 5.99
func (*Path) UnmarshalBinary ¶ added in v0.10.0
UnmarshalBinary decodes UTF-8-encoded bytes into p. Implements encoding.BinaryUnmarshaler.
func (*Path) UnmarshalText ¶ added in v0.10.0
UnmarshalText decodes UTF-8-encoded text into p. Implements encoding.TextUnmarshaler.
Directories
¶
| Path | Synopsis |
|---|---|
|
internal
|
|
|
wasm
command
Package main performs a basic JSONPath query in order to test WASM compilation.
|
Package main performs a basic JSONPath query in order to test WASM compilation. |
|
Package parser parses RFC 9535 JSONPath queries into parse trees.
|
Package parser parses RFC 9535 JSONPath queries into parse trees. |
|
Package registry provides a RFC 9535 JSONPath function extension registry.
|
Package registry provides a RFC 9535 JSONPath function extension registry. |
|
Package spec provides the [RFC 9535 JSONPath] [AST] and execution for github.com/theory/jsonpath.
|
Package spec provides the [RFC 9535 JSONPath] [AST] and execution for github.com/theory/jsonpath. |