Documentation
¶
Overview ¶
Package jsonpath implements RFC 9535 JSONPath query expressions.
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 [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 := []any{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 [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": []any{"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 [NormalizedPath] values in list.
func (LocatedNodeList) Sort ¶ added in v0.3.0
func (list LocatedNodeList) Sort()
Sort sorts list by the [NormalizedPath] of each node.
Example ¶
package main
import (
"fmt"
"github.com/theory/jsonpath"
)
func main() {
// Load some JSON.
pallet := map[string]any{"colors": []any{"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{
[]any{1, 2, 3, 4, 5},
[]any{6, 7, 8, 9},
[]any{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.
paths := []*jsonpath.Path{}
for _, path := range []string{
"$.store.book[*].author",
"$..author",
"$.store..color",
"$..book[2].author",
"$..book[2].publisher",
"$..book[?@.isbn].title",
"$..book[?@.price<10].title",
} {
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. |