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
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 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 normalized paths, modifying the contents of list. It returns the modified list, which may have a smaller 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 effectively the same data a 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 normalized paths in list.
func (LocatedNodeList) Sort ¶ added in v0.3.0
func (list LocatedNodeList) Sort()
Sort sorts list by the normalized path 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 Parser ¶
type Parser struct {
// contains filtered or unexported fields
}
Parser parses JSONPath strings into [*Path]s.
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"]
Example (FunctionExtension) ¶
The second use case for the Parser is to provide 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.PathNodes], so that first() // can return the first node. It's called by the parser. func validateFirstArgs(fea []spec.FunctionExprArg) error { if len(fea) != 1 { return fmt.Errorf("expected 1 argument but found %v", len(fea)) } if !fea[0].ResultType().ConvertsTo(spec.PathNodes) { return errors.New("cannot convert argument to PathNodes") } 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.JSONPathValue) spec.JSONPathValue { nodes := spec.NodesFrom(jv[0]) if len(nodes) == 0 { return nil } return spec.Value(nodes[0]) }
Output: [[6 7 8 9]]
type Path ¶
type Path struct {
// contains filtered or unexported fields
}
Path represents a RFC 9535 JSONPath query.
func Parse ¶
Parse parses path, a JSONPath query string, into a Path. Returns an ErrPathParse on parse failure.
func (*Path) Select ¶
Select returns the values 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 values that JSONPath query p selects from input as spec.LocatedNode structs pair the values with the normalized paths that identify them. Unless you have a specific need for the unique normalized path 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
Directories
¶
Path | Synopsis |
---|---|
internal
|
|
wasm
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 registry.
|
Package registry provides a RFC 9535 JSONPath function registry. |
Package spec provides object definitions and execution for RFC 9535 JSONPath query expressions.
|
Package spec provides object definitions and execution for RFC 9535 JSONPath query expressions. |