spec

package
v0.10.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 11, 2025 License: MIT Imports: 7 Imported by: 4

Documentation

Overview

Package spec provides the RFC 9535 JSONPath AST and execution for github.com/theory/jsonpath. It will mainly be of interest to those wishing to implement their own parsers, to convert from other JSON path-style languages, and to implement functions for github.com/theory/jsonpath/registry.

Stability

The following types and constructors are considered stable:

The rest of the structs, constructors, and methods in this package remain subject to change, although we anticipate no significant revisions.

Example

Select all the authors of the books in a bookstore object.

package main

import (
	"encoding/json"
	"fmt"
	"log"

	"github.com/theory/jsonpath"
	"github.com/theory/jsonpath/spec"
)

func main() {
	// Construct a jsonpath query.
	p := jsonpath.New(spec.Query(
		true,
		spec.Child(spec.Name("store")),
		spec.Child(spec.Name("book")),
		spec.Child(spec.Wildcard()),
		spec.Child(spec.Name("author")),
	))

	// 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

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type BasicExpr

type BasicExpr interface {
	// contains filtered or unexported methods
}

BasicExpr defines the basic interface for filter expressions. Implementations:

type CompExpr added in v0.9.0

type CompExpr struct {
	// contains filtered or unexported fields
}

CompExpr is a filter expression that compares two values, which themselves may themselves be the output of expressions. Interfaces implemented:

Example

Create a comparison expression that compares a literal value to a path expression.

package main

import (
	"fmt"

	"github.com/theory/jsonpath/spec"
)

func main() {
	cmp := spec.Comparison(
		spec.Literal(42),
		spec.EqualTo,
		spec.SingularQuery(false, spec.Name("age")),
	)
	fmt.Printf("%v\n", cmp)
}
Output:

42 == @["age"]

func Comparison

func Comparison(left CompVal, op CompOp, right CompVal) *CompExpr

Comparison creates and returns a new CompExpr that uses op to compare left and right.

func (*CompExpr) String added in v0.9.0

func (ce *CompExpr) String() string

String returns the string representation of ce.

type CompOp

type CompOp uint8

CompOp defines the JSONPath filter comparison operators.

const (
	// EqualTo is the == operator.
	EqualTo CompOp = iota + 1 // ==
	// NotEqualTo is the != operator.
	NotEqualTo // !=
	// LessThan is the < operator.
	LessThan // <
	// GreaterThan is the > operator.
	GreaterThan // >
	// LessThanEqualTo is the <= operator.
	LessThanEqualTo // <=
	// GreaterThanEqualTo is the >= operator.
	GreaterThanEqualTo // >=
)

func (CompOp) String

func (i CompOp) String() string

type CompVal

type CompVal interface {
	// contains filtered or unexported methods
}

CompVal defines the interface for comparable values in filter expressions. Implemented by:

type Evaluator added in v0.9.0

type Evaluator func(args []PathValue) PathValue

Evaluator functions execute a FuncExtension against the values returned by args and returns a result.

type ExistExpr

type ExistExpr struct {
	*PathQuery
}

ExistExpr represents a PathQuery used as a filter expression, in which context it returns true if the PathQuery selects at least one node. Interfaces implemented:

Example

Create an existence expression as a filter expression.

package main

import (
	"fmt"

	"github.com/theory/jsonpath/spec"
)

func main() {
	filter := spec.Filter(spec.And(
		spec.Existence(
			spec.Query(false, spec.Child(spec.Name("x"))),
		),
	))
	fmt.Printf("%v\n", filter)
}
Output:

?@["x"]

func Existence

func Existence(q *PathQuery) *ExistExpr

Existence creates a new ExistExpr for q.

type FilterSelector

type FilterSelector struct {
	LogicalOr
}

FilterSelector is a filter selector, e.g., ?(), as defined by RFC 9535 Section 2.3.5. Interfaces implemented:

Example

Create a filter selector that selects nodes with a descendant that contains an object field named "x".

package main

import (
	"fmt"

	"github.com/theory/jsonpath/spec"
)

func main() {
	f := spec.Filter(spec.And(
		spec.Existence(
			spec.Query(false, spec.Descendant(spec.Name("x"))),
		),
	))
	fmt.Printf("%v\n", f)
}
Output:

?@..["x"]

func Filter

func Filter(expr ...LogicalAnd) *FilterSelector

Filter returns a new FilterSelector that ORs the evaluation of each expr.

func (*FilterSelector) Eval added in v0.2.0

func (f *FilterSelector) Eval(node, root any) bool

Eval evaluates the f's LogicalOr expression against node and root. Uses FilterSelector.Select as it iterates over nodes, and always passes the root value($) for filter expressions that reference it.

func (*FilterSelector) Select

func (f *FilterSelector) Select(current, root any) []any

Select selects and returns values that f filters from current. Filter expressions may evaluate the current value (@), the root value ($), or any path expression. Defined by the Selector interface.

func (*FilterSelector) SelectLocated added in v0.3.0

func (f *FilterSelector) SelectLocated(current, root any, parent NormalizedPath) []*LocatedNode

SelectLocated selects and returns LocatedNode values with values that f filters from current. Filter expressions may evaluate the current value (@), the root value ($), or any path expression. Defined by the Selector interface.

func (*FilterSelector) String

func (f *FilterSelector) String() string

String returns a string representation of f.

type FuncExpr added in v0.9.0

type FuncExpr struct {
	// contains filtered or unexported fields
}

FuncExpr represents a function expression, consisting of a named FuncExtension and its arguments. See github.com/theory/jsonpath/registry for an example defining a custom function. Interfaces Implemented:

Example

Use the standard match() function in a function expression.

package main

import (
	"fmt"

	"github.com/theory/jsonpath/registry"
	"github.com/theory/jsonpath/spec"
)

func main() {
	reg := registry.New()
	fe := spec.Function(
		reg.Get("match"),
		spec.Query(false, spec.Child(spec.Name("rating"))),
		spec.Literal("good$"),
	)
	fmt.Printf("%v\n", fe)
}
Output:

match(@["rating"], "good$")

func Function

func Function(fn *FuncExtension, args ...FuncExprArg) *FuncExpr

Function creates an returns a new FuncExpr that will execute fn against the return values of args.

func (*FuncExpr) ConvertsTo added in v0.9.0

func (fe *FuncExpr) ConvertsTo(ft FuncType) bool

ConvertsTo returns true if fe's result can be converted to ft.

func (*FuncExpr) ResultType added in v0.9.0

func (fe *FuncExpr) ResultType() FuncType

ResultType returns the result type of fe's FuncExtension. Defined by the FuncExprArg interface.

func (*FuncExpr) String added in v0.9.0

func (fe *FuncExpr) String() string

String returns a string representation of fe.

type FuncExprArg added in v0.9.0

type FuncExprArg interface {

	// ResultType returns the [FuncType] that defines the type of the return
	// value of the [FuncExprArg].
	ResultType() FuncType

	// ConvertsTo returns true if the function expression's result can be
	// converted to ft.
	ConvertsTo(ft FuncType) bool
	// contains filtered or unexported methods
}

FuncExprArg defines the interface for function argument expressions. Implementations:

type FuncExtension added in v0.9.0

type FuncExtension struct {
	// contains filtered or unexported fields
}

FuncExtension defines a JSONPath function extension as defined in RFC 9535 Section 2.4. Use github.com/theory/jsonpath/registry.Registry.Register to construct and register a new FuncExtension.

func Extension added in v0.9.0

func Extension(name string, returnType FuncType, validator Validator, evaluator Evaluator) *FuncExtension

Extension creates a new JSONPath function extension. Created by github.com/theory/jsonpath/registry.Registry.Register. The parameters are:

  • name: the name of the function extension as used in JSONPath queries.
  • returnType: The data type of the function return value.
  • validator: A validation function that will be called at parse time to validate that all the function args are compatible with the function.
  • evaluator: The implementation of the function itself that executes against args and returns the result of the type defined by resultType.

func (*FuncExtension) Evaluate added in v0.9.0

func (f *FuncExtension) Evaluate(args []PathValue) PathValue

Evaluate executes the FuncExtension against args and returns a result of type [ResultType].

func (*FuncExtension) Name added in v0.9.0

func (f *FuncExtension) Name() string

Name returns the name of the FuncExtension.

func (*FuncExtension) ReturnType added in v0.9.0

func (f *FuncExtension) ReturnType() FuncType

ReturnType returns the data type of the FuncExtension return value.

func (*FuncExtension) Validate added in v0.9.0

func (f *FuncExtension) Validate(args []FuncExprArg) error

Validate executes at parse time to validate that all the args to the are compatible with the FuncExtension.

type FuncType

type FuncType uint8

FuncType describes the types of function parameters and results as defined by RFC 9535 Section 2.4.1.

Implements fmt.Stringer.

const (
	// FuncValue represents a JSON value as provided by [ValueType].
	FuncValue FuncType = iota + 1

	// FuncNodes represents a list of nodes as provided by [NodesType].
	FuncNodes

	// FuncLogical represents a logical value as provided by [LogicalType].
	FuncLogical
)

func (FuncType) String

func (i FuncType) String() string

type Index

type Index int

Index is an array index selector, e.g., [3], as defined by RFC 9535 Section 2.3.3. Interfaces implemented:

Example

Create a few index selectors.

package main

import (
	"fmt"

	"github.com/theory/jsonpath/spec"
)

func main() {
	for _, indexSelector := range []any{
		spec.Index(0),  // first item
		spec.Index(3),  // fourth item
		spec.Index(-1), // last item
	} {
		fmt.Printf("%v\n", indexSelector)
	}
}
Output:

0
3
-1

func (Index) Select

func (i Index) Select(input, _ any) []any

Select selects i from input and returns it as a single value in a slice. Returns an empty slice if input is not a slice or if i it outside the bounds of input. Defined by the Selector interface.

func (Index) SelectLocated added in v0.3.0

func (i Index) SelectLocated(input, _ any, parent NormalizedPath) []*LocatedNode

SelectLocated selects i from input and returns it with its normalized path as a single LocatedNode in a slice. Returns an empty slice if input is not a slice or if i it outside the bounds of input. Defined by the Selector interface.

func (Index) String

func (i Index) String() string

String returns a string representation of i.

type LiteralArg

type LiteralArg struct {
	// contains filtered or unexported fields
}

LiteralArg represents a literal JSON value, excluding objects and arrays. Its underlying value there must be one of string, integer, float, json.Number, nil, true, or false.

Interfaces implemented:

Example

Pass a LiteralArg to a function.

package main

import (
	"fmt"

	"github.com/theory/jsonpath/registry"
	"github.com/theory/jsonpath/spec"
)

func main() {
	reg := registry.New()
	fe := spec.Function(
		reg.Get("length"),
		spec.Literal("some string"),
	)
	fmt.Printf("%v\n", fe)
}
Output:

length("some string")

func Literal

func Literal(lit any) *LiteralArg

Literal creates and returns a new LiteralArg consisting of lit, which must ge one of string, integer, float, json.Number, nil, true, or false.

func (*LiteralArg) ConvertsTo added in v0.9.0

func (*LiteralArg) ConvertsTo(ft FuncType) bool

ConvertsTo returns true if the result of the LiteralArg can be converted to ft.

func (*LiteralArg) ResultType

func (la *LiteralArg) ResultType() FuncType

ResultType returns FuncValue. Defined by the FuncExprArg interface.

func (*LiteralArg) String added in v0.9.0

func (la *LiteralArg) String() string

String returns the JSON string representation of la.

func (*LiteralArg) Value

func (la *LiteralArg) Value() any

Value returns the underlying value of la.

type LocatedNode added in v0.3.0

type LocatedNode struct {
	// Node is the value selected from a JSON query argument.
	Node any `json:"node"`

	// Path is the normalized path that uniquely identifies the location of
	// Node in a JSON query argument.
	Path NormalizedPath `json:"path"`
}

LocatedNode pairs a value with the NormalizedPath for its location within the JSON query argument from which it was selected. Returned by implementations of Selector's SelectLocated method.

Example
package main

import (
	"encoding/json"
	"fmt"
	"log"

	"github.com/theory/jsonpath"
	"github.com/theory/jsonpath/spec"
)

func main() {
	// Query all "author" object properties.
	p := jsonpath.New(spec.Query(
		true,
		spec.Descendant(spec.Name("author")),
	))

	// Select LocatedNodes from unmarshaled JSON input.
	store := bookstore()
	nodes := p.SelectLocated(store)

	// Show the LocatedNodes.
	items, err := json.MarshalIndent(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:

[
  {
    "node": "Nigel Rees",
    "path": "$['store']['book'][0]['author']"
  },
  {
    "node": "Evelyn Waugh",
    "path": "$['store']['book'][1]['author']"
  },
  {
    "node": "Herman Melville",
    "path": "$['store']['book'][2]['author']"
  },
  {
    "node": "J. R. R. Tolkien",
    "path": "$['store']['book'][3]['author']"
  }
]

type LogicalAnd

type LogicalAnd []BasicExpr

LogicalAnd represents a list of one or more expressions ANDed together by the && operator. Evaluates to true if all of its expressions evaluate to true. Short-circuits and returns false for the first expression that returns false. Interfaces implemented:

Example

Assemble a LogicalAnd consisting of multiple expressions.

package main

import (
	"fmt"

	"github.com/theory/jsonpath/spec"
)

func main() {
	and := spec.And(
		spec.Value(42),
		spec.Existence(
			spec.Query(false, spec.Child(spec.Name("answer"))),
		),
	)
	fmt.Printf("%v\n", and)
}
Output:

42 && @["answer"]

func And added in v0.9.0

func And(expr ...BasicExpr) LogicalAnd

And creates a LogicalAnd of all expr.

func (LogicalAnd) String added in v0.9.0

func (la LogicalAnd) String() string

String returns the string representation of la.

type LogicalOr

type LogicalOr []LogicalAnd

LogicalOr represents a list of one or more expressions ORed together by the || operator. Evaluates to true if any of its expressions evaluates to true. Short-circuits and returns true for the first expression that returns true.

Interfaces implemented:

Example

Assemble a LogicalOr consisting of multiple expressions.

package main

import (
	"fmt"

	"github.com/theory/jsonpath/spec"
)

func main() {
	and := spec.Or(
		spec.And(spec.Existence(
			spec.Query(false, spec.Child(spec.Name("answer"))),
		)),
		spec.And(spec.Value(42)),
	)
	fmt.Printf("%v\n", and)
}
Output:

@["answer"] || 42

func Or added in v0.9.0

func Or(expr ...LogicalAnd) LogicalOr

Or returns a LogicalOr of all expr.

func (LogicalOr) ConvertsTo added in v0.9.0

func (LogicalOr) ConvertsTo(ft FuncType) bool

ConvertsTo returns true if the result of the LogicalOr can be converted to ft.

func (LogicalOr) ResultType

func (lo LogicalOr) ResultType() FuncType

ResultType returns FuncLogical. Defined by the FuncExprArg interface.

func (LogicalOr) String added in v0.9.0

func (lo LogicalOr) String() string

String returns the string representation of lo.

type LogicalType

type LogicalType uint8

LogicalType encapsulates a true or false value for a function expression parameters or results, as defined by RFC 9535 Section 2.4.1. Interfaces implemented:

Example
package main

import (
	"fmt"

	"github.com/theory/jsonpath/spec"
)

func main() {
	fmt.Printf("%v\n", spec.Logical(true))
	fmt.Printf("%v\n", spec.Logical(false))
}
Output:

true
false
const (
	// LogicalFalse represents a true [LogicalType].
	LogicalFalse LogicalType = iota // false

	// LogicalTrue represents a true [LogicalType].
	LogicalTrue // true
)

func Logical added in v0.9.0

func Logical(boolean bool) LogicalType

Logical returns the LogicalType equivalent to boolean.

func LogicalFrom

func LogicalFrom(value any) LogicalType

LogicalFrom converts value to a LogicalType and panics if it cannot. Use in github.com/theory/jsonpath/registry.Registry.Register Evaluator functions. Avoid the panic by returning an error from the accompanying Validator function when [FuncExprArg.ConvertsToLogical] returns false for the FuncExprArg that returns value.

Converts each implementation of PathValue as follows:

Example

Of the implementations of PathValue, spec.LogicalType, spec.NodesType, and nil can be converted to spec.NodesType.

package main

import (
	"fmt"

	"github.com/theory/jsonpath/spec"
)

func main() {
	for _, val := range []spec.PathValue{
		spec.Nodes(1, 2, 3), // converts to logical (existence)
		spec.Logical(false), // converts to logical
		nil,
	} {
		fmt.Printf("logical: %v\n", spec.LogicalFrom(val))
	}
}
Output:

logical: true
logical: false
logical: false

func (LogicalType) Bool

func (lt LogicalType) Bool() bool

Bool returns the boolean equivalent to lt.

func (LogicalType) FuncType

func (LogicalType) FuncType() FuncType

FuncType returns FuncLogical. Defined by the PathValue interface.

func (LogicalType) String

func (i LogicalType) String() string

type Name

type Name string

Name is a key name selector, e.g., .name or ["name"], as defined by RFC 9535 Section 2.3.1. Interfaces implemented:

Example

Create a few name selectors.

package main

import (
	"fmt"

	"github.com/theory/jsonpath/spec"
)

func main() {
	for _, nameSelector := range []any{
		spec.Name("hello"),                 // ascii
		spec.Name(`Charlie "Bird" Parker`), // quoted
		spec.Name("އައްސަލާމް ޢަލައިކުމް"), // Unicode
		spec.Name("📡🪛🪤"),                   // emoji
	} {
		fmt.Printf("%v\n", nameSelector)
	}
}
Output:

"hello"
"Charlie \"Bird\" Parker"
"އައްސަލާމް ޢަލައިކުމް"
"📡🪛🪤"

func (Name) Select

func (n Name) Select(input, _ any) []any

Select selects n from input and returns it as a single value in a slice. Returns an empty slice if input is not a map[string]any or if it does not contain n. Defined by the Selector interface.

func (Name) SelectLocated added in v0.3.0

func (n Name) SelectLocated(input, _ any, parent NormalizedPath) []*LocatedNode

SelectLocated selects n from input and returns it with its normalized path as a single LocatedNode in a slice. Returns an empty slice if input is not a map[string]any or if it does not contain n. Defined by the Selector interface.

func (Name) String

func (n Name) String() string

String returns the quoted string representation of n.

type NodesType

type NodesType []any

NodesType defines a node list (a list of JSON values) for a function expression parameters or results, as defined by RFC 9535 Section 2.4.1. It can also be used in filter expressions. The underlying types should be string, integer, float, json.Number, nil, true, false, []any, or map[string]any. Interfaces implemented:

- PathValue - fmt.Stringer

Example

Use a spec.NodesType to create a list of nodes, a.k.a. a JSON array.

package main

import (
	"fmt"

	"github.com/theory/jsonpath/spec"
)

func main() {
	fmt.Printf("%v\n", spec.Nodes("hi", 42, true))
}
Output:

[hi 42 true]

func Nodes added in v0.9.0

func Nodes(val ...any) NodesType

Nodes creates a NodesType that contains val, all of which should be the Go equivalent of the JSON data types: string, integer, float, json.Number, nil, true, false, []any, or map[string]any.

func NodesFrom

func NodesFrom(value PathValue) NodesType

NodesFrom converts value to a NodesType and panics if it cannot. Use in github.com/theory/jsonpath/registry.Registry.Register Evaluator. Avoid the panic by returning an error from the accompanying Validator function when [FuncExprArg.ConvertsToNodes] returns false for the FuncExprArg that returns value.

Converts each implementation of PathValue as follows:

Example

Of the implementations of PathValue, only spec.NodesType and nil can be converted to spec.NodesType.

package main

import (
	"fmt"

	"github.com/theory/jsonpath/spec"
)

func main() {
	for _, val := range []spec.PathValue{
		spec.Nodes(1, 2, 3), // no conversion
		nil,                 // converts to empty NodesType
	} {
		fmt.Printf("nodes: %v\n", spec.NodesFrom(val))
	}
}
Output:

nodes: [1 2 3]
nodes: []

func (NodesType) FuncType

func (NodesType) FuncType() FuncType

FuncType returns FuncNodes. Defined by the PathValue interface.

func (NodesType) String added in v0.9.0

func (nt NodesType) String() string

String returns the string representation of nt.

type NonExistExpr

type NonExistExpr struct {
	*PathQuery
}

NonExistExpr represents a negated PathQuery used as a filter expression, in which context it returns true if the PathQuery selects no nodes. Interfaces implemented:

Example

Create a nonexistence expression as a filter expression.

package main

import (
	"fmt"

	"github.com/theory/jsonpath/spec"
)

func main() {
	filter := spec.Filter(spec.And(
		spec.Nonexistence(
			spec.Query(false, spec.Child(spec.Name("x"))),
		),
	))
	fmt.Printf("%v\n", filter)
}
Output:

?!@["x"]

func Nonexistence

func Nonexistence(q *PathQuery) *NonExistExpr

Nonexistence creates a new NonExistExpr for q.

type NormalSelector added in v0.3.0

type NormalSelector interface {
	// contains filtered or unexported methods
}

NormalSelector represents a single selector in a normalized path. Implemented by Name and Index.

type NormalizedPath added in v0.3.0

type NormalizedPath []NormalSelector

NormalizedPath represents a normalized path identifying a single value in a JSON query argument, as defined by RFC 9535. Defines a simplified string format that exclusively uses single quotation marks to quote names. Useful for converting to JSON Pointer (via NormalizedPath.Pointer) or other JSON pointer-type formats.

Interfaces implemented:

Example

Compare a normalized JSONPath and its JSON Pointer equivalent.

package main

import (
	"fmt"

	"github.com/theory/jsonpath/spec"
)

func main() {
	norm := spec.Normalized(
		spec.Name("x"),
		spec.Index(1),
		spec.Name("y"),
	)
	fmt.Printf("%v\n", norm)
	fmt.Printf("%v\n", norm.Pointer())
}
Output:

$['x'][1]['y']
/x/1/y

func Normalized added in v0.9.0

func Normalized(sel ...NormalSelector) NormalizedPath

Normalized creates and returns a NormalizedPath that contains sel.

func (NormalizedPath) Compare added in v0.3.0

func (np NormalizedPath) Compare(np2 NormalizedPath) int

Compare compares np to np2 and returns -1 if np is less than np2, 1 if it's greater than np2, and 0 if they're equal. Indexes are always considered less than names.

func (NormalizedPath) MarshalText added in v0.3.0

func (np NormalizedPath) MarshalText() ([]byte, error)

MarshalText marshals np into text. Implements encoding.TextMarshaler.

func (NormalizedPath) Pointer added in v0.4.0

func (np NormalizedPath) Pointer() string

Pointer returns an RFC 6901 JSON Pointer string representation of np.

func (NormalizedPath) String added in v0.3.0

func (np NormalizedPath) String() string

String returns the string representation of np.

type NotFuncExpr

type NotFuncExpr struct {
	*FuncExpr
}

NotFuncExpr represents a negated function expression. It reverses the result of the return value of the underlying FuncExpr. Interfaces implemented:

Example

Use the standard count() function in a function expression.

package main

import (
	"fmt"

	"github.com/theory/jsonpath/registry"
	"github.com/theory/jsonpath/spec"
)

func main() {
	reg := registry.New()
	nf := spec.NotFunction(spec.Function(
		reg.Get("length"),
		spec.Query(false, spec.Child(spec.Index(0))),
	))
	fmt.Printf("%v\n", nf)
}
Output:

!length(@[0])

func NotFunction

func NotFunction(fn *FuncExpr) NotFuncExpr

NotFunction creates and returns a new NotFuncExpr that will execute fn against the return values of args and return the inverse of its return value.

func (NotFuncExpr) String added in v0.9.0

func (nf NotFuncExpr) String() string

String returns the string representation of nf.

type NotParenExpr

type NotParenExpr struct {
	LogicalOr
}

NotParenExpr represents a negated parenthesized expression that groups the elements of a LogicalOr. Interfaces implemented (via the underlying LogicalOr):

Example

Use a spec.NotParenExpr to negate the result of a LogicalOr expression.

package main

import (
	"fmt"

	"github.com/theory/jsonpath/spec"
)

func main() {
	not := spec.NotParen(
		spec.And(
			spec.Existence(
				spec.Query(false, spec.Child(spec.Name("answer"))),
			),
		),
		spec.And(
			spec.Existence(
				spec.Query(false, spec.Child(spec.Name("question"))),
			),
		),
	)
	fmt.Printf("%v\n", not)
}
Output:

!(@["answer"] || @["question"])

func NotParen

func NotParen(expr ...LogicalAnd) *NotParenExpr

NotParen returns a new NotParenExpr that ORs each expr.

func (*NotParenExpr) String added in v0.9.0

func (np *NotParenExpr) String() string

String returns the string representation of np.

type ParenExpr

type ParenExpr struct {
	LogicalOr
}

ParenExpr represents a parenthesized expression that groups the elements of a LogicalOr. Interfaces implemented (via the underlying LogicalOr):

Example

Use a spec.ParenExpr to group the result of a LogicalOr expression.

package main

import (
	"fmt"

	"github.com/theory/jsonpath/spec"
)

func main() {
	paren := spec.Paren(
		spec.And(
			spec.Existence(
				spec.Query(false, spec.Child(spec.Name("answer"))),
			),
		),
		spec.And(
			spec.Existence(
				spec.Query(false, spec.Child(spec.Name("question"))),
			),
		),
	)
	fmt.Printf("%v\n", paren)
}
Output:

(@["answer"] || @["question"])

func Paren

func Paren(expr ...LogicalAnd) *ParenExpr

Paren returns a new ParenExpr that ORs the results of each expr.

func (*ParenExpr) String added in v0.9.0

func (p *ParenExpr) String() string

String returns the string representation of p.

type PathQuery

type PathQuery struct {
	// contains filtered or unexported fields
}

PathQuery represents a JSONPath query. Interfaces implemented:

Example

Construct a couple of different path queries.

package main

import (
	"fmt"

	"github.com/theory/jsonpath/spec"
)

func main() {
	// Create a query and its segments.
	q := spec.Query(
		true,
		spec.Child(spec.Name("store")),
		spec.Child(spec.Name("book")),
		spec.Child(spec.Wildcard()),
		spec.Child(spec.Name("author")),
	)
	fmt.Printf("%v\n", q)

	// Create a query with multi-selector segments.
	q = spec.Query(
		true,
		spec.Child(spec.Name("profile")),
		spec.Descendant(spec.Name("email"), spec.Name("phone")),
	)
	fmt.Printf("%v\n", q)

}
Output:

$["store"]["book"][*]["author"]
$["profile"]..["email","phone"]

func Query

func Query(root bool, segments ...*Segment) *PathQuery

Query returns a new PathQuery consisting of segments. When root is true it indicates a query from the root of a value. Set to false for filter subqueries.

func (*PathQuery) ConvertsTo added in v0.9.0

func (q *PathQuery) ConvertsTo(ft FuncType) bool

ConvertsTo returns true if fq's result can be converted to ft. A singular query can be converted to either FuncValue or FuncNodes. All other queries can only be converted to FuncNodes.

func (*PathQuery) Expression

func (q *PathQuery) Expression() FuncExprArg

Expression returns a SingularQueryExpr variant of q if q is a singular query, and otherwise returns q.

func (*PathQuery) ResultType added in v0.9.0

func (q *PathQuery) ResultType() FuncType

ResultType returns FuncValue if fq is a singular query, and FuncNodes if it is not. Defined by the FuncExprArg interface.

func (*PathQuery) Segments

func (q *PathQuery) Segments() []*Segment

Segments returns q's Segment values.

func (*PathQuery) Select

func (q *PathQuery) Select(current, root any) []any

Select selects the values from current or root and returns the results. Returns just current if q has no segments. Defined by the Selector interface.

func (*PathQuery) SelectLocated added in v0.3.0

func (q *PathQuery) SelectLocated(current, root any, parent NormalizedPath) []*LocatedNode

SelectLocated values from current or root into LocatedNode values and returns the results. Returns just current if q has no segments. Defined by the Selector interface.

func (*PathQuery) Singular

func (q *PathQuery) Singular() *SingularQueryExpr

Singular returns the SingularQueryExpr variant of q if q is a singular query. Otherwise it returns nil.

func (*PathQuery) String

func (q *PathQuery) String() string

String returns a string representation of q.

type PathValue

type PathValue interface {

	// FuncType returns the PathValue's [FuncType].
	FuncType() FuncType
	// contains filtered or unexported methods
}

PathValue defines the interface for JSONPath values used as comparison operands, filter expression results, and function parameters & return values.

Implemented by the function types defined by RFC 9535 Section 2.4.1:

Example

Print the spec.FuncType for each spec.PathValue implementation.

package main

import (
	"fmt"

	"github.com/theory/jsonpath/spec"
)

func main() {
	fmt.Printf("Implementation    FuncType\n")
	fmt.Printf("----------------- --------\n")
	for _, jv := range []spec.PathValue{
		spec.Value(nil),
		spec.Nodes(1, 2),
		spec.Logical(true),
	} {
		fmt.Printf("%-17T %v\n", jv, jv.FuncType())
	}
}
Output:

Implementation    FuncType
----------------- --------
*spec.ValueType   Value
spec.NodesType    Nodes
spec.LogicalType  Logical

type Segment

type Segment struct {
	// contains filtered or unexported fields
}

Segment represents a single segment as defined in RFC 9535 Section 1.4.2, consisting of a list of Selector values.

Example (Child)

Create a child segment that selects the name "hi", th index 2, or slice 1-3.

package main

import (
	"fmt"

	"github.com/theory/jsonpath/spec"
)

func main() {
	child := spec.Child(
		spec.Name("hi"),
		spec.Index(2),
		spec.Slice(1, 3, 1),
	)
	fmt.Printf("%v\n", child)
}
Output:

["hi",2,1:3]
Example (Descendant)

Create a descendant segment that selects the name "email" or array index zero from a node or any of its descendant nodes.

package main

import (
	"fmt"

	"github.com/theory/jsonpath/spec"
)

func main() {
	child := spec.Descendant(
		spec.Name("email"),
		spec.Index(0),
	)
	fmt.Printf("%v\n", child)
}
Output:

..["email",0]

func Child

func Child(sel ...Selector) *Segment

Child creates and returns a Segment that uses sel to select values from a JSON object or array.

func Descendant

func Descendant(sel ...Selector) *Segment

Descendant creates and returns a Segment that uses sel to select values from a JSON object or array or any of its descendant objects and arrays.

func (*Segment) IsDescendant added in v0.2.0

func (s *Segment) IsDescendant() bool

IsDescendant returns true if the segment is a Descendant selector that recursively select the children of a JSON value.

func (*Segment) Select

func (s *Segment) Select(current, root any) []any

Select selects and returns values from current or root, for each of s's selectors. Defined by the Selector interface.

func (*Segment) SelectLocated added in v0.3.0

func (s *Segment) SelectLocated(current, root any, parent NormalizedPath) []*LocatedNode

SelectLocated selects and returns values as LocatedNode values from current or root for each of seg's selectors. Defined by the Selector interface.

func (*Segment) Selectors

func (s *Segment) Selectors() []Selector

Selectors returns s's Selector values.

func (*Segment) String

func (s *Segment) String() string

String returns a string representation of seg. A Child Segment formats as:

[<selectors>]

A Descendant Segment formats as:

..⁠[<selectors>])

type Selector

type Selector interface {

	// Select selects values from current and/or root and returns them.
	Select(current, root any) []any

	// SelectLocated selects values from current and/or root and returns them
	// in [LocatedNode] values with their located normalized paths
	SelectLocated(current, root any, parent NormalizedPath) []*LocatedNode
	// contains filtered or unexported methods
}

Selector represents a single Selector in an RFC 9535 JSONPath query.

type SingularQueryExpr

type SingularQueryExpr struct {
	// contains filtered or unexported fields
}

SingularQueryExpr represents a query that produces a single ValueType (JSON value) or nothing. Used in contexts that require a singular value, such as comparison operations and function arguments. Interfaces implemented:

Example
package main

import (
	"fmt"

	"github.com/theory/jsonpath/spec"
)

func main() {
	singular := spec.SingularQuery(
		true,
		spec.Name("profile"),
		spec.Name("contacts"),
		spec.Index(0),
		spec.Name("email"),
	)
	fmt.Printf("%v\n", singular)
}
Output:

$["profile"]["contacts"][0]["email"]

func SingularQuery

func SingularQuery(root bool, selectors ...Selector) *SingularQueryExpr

SingularQuery creates and returns a SingularQueryExpr that selects a single value at the path defined by selectors.

func (*SingularQueryExpr) ConvertsTo added in v0.9.0

func (*SingularQueryExpr) ConvertsTo(ft FuncType) bool

ConvertsTo returns true if the result of the SingularQueryExpr can be converted to ft.

func (*SingularQueryExpr) ResultType

func (sq *SingularQueryExpr) ResultType() FuncType

ResultType returns FuncValue. Defined by the FuncExprArg interface.

func (*SingularQueryExpr) String added in v0.9.0

func (sq *SingularQueryExpr) String() string

String returns the string representation of sq.

type SliceSelector

type SliceSelector struct {
	// contains filtered or unexported fields
}

SliceSelector is a slice selector, e.g., [0:100:5], as defined by RFC 9535 Section 2.3.4. Interfaces implemented:

Example

Create a few slice selectors.

package main

import (
	"fmt"

	"github.com/theory/jsonpath/spec"
)

func main() {
	// Select all values in a slice.
	for _, sliceSelector := range []any{
		spec.Slice(),         // full slice
		spec.Slice(1, 4),     // items 1-3
		spec.Slice(nil, 8),   // items 0-7
		spec.Slice(4, -1, 3), // items 4-last step by 3
		spec.Slice(5, 1, -2), // items 5-2, step by -2

	} {
		fmt.Printf("%v\n", sliceSelector)
	}
}
Output:

:
1:4
:8
4:-1:3
5:1:-2

func Slice

func Slice(args ...any) SliceSelector

Slice creates a new SliceSelector. Pass up to three integers or nils for the start, end, and step arguments. Subsequent arguments are ignored.

func (SliceSelector) Bounds added in v0.2.0

func (s SliceSelector) Bounds(length int) (int, int)

Bounds returns the lower and upper bounds for selecting from a slice of length.

func (SliceSelector) End

func (s SliceSelector) End() int

End returns the end position.

func (SliceSelector) Select

func (s SliceSelector) Select(input, _ any) []any

Select selects and returns the values from input for the indexes specified by s. Returns an empty slice if input is not a slice. Indexes outside the bounds of input will not be included in the return value. Defined by the Selector interface.

func (SliceSelector) SelectLocated added in v0.3.0

func (s SliceSelector) SelectLocated(input, _ any, parent NormalizedPath) []*LocatedNode

SelectLocated selects values from input for the indexes specified by s and returns thm with their normalized paths as LocatedNode values. Returns an empty slice if input is not a slice. Indexes outside the bounds of input will not be included in the return value. Defined by the Selector interface.

func (SliceSelector) Start

func (s SliceSelector) Start() int

Start returns the start position.

func (SliceSelector) Step

func (s SliceSelector) Step() int

Step returns the step value.

func (SliceSelector) String

func (s SliceSelector) String() string

String returns a quoted string representation of s.

type Validator added in v0.9.0

type Validator func(args []FuncExprArg) error

Validator functions validate that the args expressions to a FuncExtension can be processed by the function.

type ValueType

type ValueType struct {
	// contains filtered or unexported fields
}

ValueType encapsulates a JSON value for a function expression parameter or result, as defined by RFC 9535 Section 2.4.1. It can also be used as in filter expression. The underlying value should be a string, integer, json.Number, float, nil, true, false, []any, or map[string]any. A nil ValueType pointer indicates no value. Interfaces implemented:

Example

Create A spec.ValueType for each supported JSON type.

package main

import (
	"encoding/json"
	"fmt"

	"github.com/theory/jsonpath/spec"
)

func main() {
	for _, val := range []any{
		"hello",
		42,
		98.6,
		json.Number("1024"),
		true,
		nil,
		map[string]any{"x": true},
		[]any{1, 2, false},
	} {
		fmt.Printf("%v\n", spec.Value(val))
	}
}
Output:

hello
42
98.6
1024
true
<nil>
map[x:true]
[1 2 false]

func Value

func Value(val any) *ValueType

Value returns a new ValueType for val, which must be the Go equivalent of a JSON data type: string, integer, float, json.Number, nil, true, false, []any, or map[string]any.

func ValueFrom

func ValueFrom(value PathValue) *ValueType

ValueFrom converts value to a ValueType and panics if it cannot. Use in github.com/theory/jsonpath/registry.Registry.Register Evaluator functions. Avoid the panic by returning an error from the accompanying Validator function when [FuncExprArg.ConvertsToValue] returns false for the FuncExprArg that returns value.

Converts each implementation of PathValue as follows:

Example

Of the implementations of PathValue, only spec.ValueType and nil can be converted to spec.ValueType.

package main

import (
	"fmt"

	"github.com/theory/jsonpath/spec"
)

func main() {
	for _, val := range []spec.PathValue{
		spec.Value("hello"), // no conversion
		nil,                 // equivalent to no value
	} {
		fmt.Printf("val: %v\n", spec.ValueFrom(val))
	}
}
Output:

val: hello
val: <nil>

func (*ValueType) FuncType

func (*ValueType) FuncType() FuncType

FuncType returns FuncValue. Defined by the PathValue interface.

func (*ValueType) String added in v0.9.0

func (vt *ValueType) String() string

String returns the string representation of vt.

func (*ValueType) Value

func (vt *ValueType) Value() any

Value returns the underlying value of vt.

type WildcardSelector added in v0.2.0

type WildcardSelector struct{}

WildcardSelector is a wildcard selector, e.g., * or [*], as defined by RFC 9535 Section 2.3.2. Interfaces implemented:

func Wildcard

func Wildcard() WildcardSelector

Wildcard returns a WildcardSelector singleton.

Example
package main

import (
	"fmt"

	"github.com/theory/jsonpath/spec"
)

func main() {
	fmt.Printf("%v\n", spec.Wildcard())
}
Output:

*

func (WildcardSelector) Select added in v0.2.0

func (WildcardSelector) Select(input, _ any) []any

Select selects the values from input and returns them in a slice. Returns an empty slice if input is not []any map[string]any. Defined by the Selector interface.

func (WildcardSelector) SelectLocated added in v0.3.0

func (WildcardSelector) SelectLocated(input, _ any, parent NormalizedPath) []*LocatedNode

SelectLocated selects the values from input and returns them with their normalized paths in a slice of LocatedNode values. Returns an empty slice if input is not []any map[string]any. Defined by the Selector interface.

func (WildcardSelector) String added in v0.2.0

func (WildcardSelector) String() string

String returns "*".

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL