123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670 |
- package decoder
- import (
- "fmt"
- "reflect"
- "strconv"
- "github.com/goccy/go-json/internal/errors"
- "github.com/goccy/go-json/internal/runtime"
- )
- type PathString string
- func (s PathString) Build() (*Path, error) {
- builder := new(PathBuilder)
- return builder.Build([]rune(s))
- }
- type PathBuilder struct {
- root PathNode
- node PathNode
- singleQuotePathSelector bool
- doubleQuotePathSelector bool
- }
- func (b *PathBuilder) Build(buf []rune) (*Path, error) {
- node, err := b.build(buf)
- if err != nil {
- return nil, err
- }
- return &Path{
- node: node,
- RootSelectorOnly: node == nil,
- SingleQuotePathSelector: b.singleQuotePathSelector,
- DoubleQuotePathSelector: b.doubleQuotePathSelector,
- }, nil
- }
- func (b *PathBuilder) build(buf []rune) (PathNode, error) {
- if len(buf) == 0 {
- return nil, errors.ErrEmptyPath()
- }
- if buf[0] != '$' {
- return nil, errors.ErrInvalidPath("JSON Path must start with a $ character")
- }
- if len(buf) == 1 {
- return nil, nil
- }
- buf = buf[1:]
- offset, err := b.buildNext(buf)
- if err != nil {
- return nil, err
- }
- if len(buf) > offset {
- return nil, errors.ErrInvalidPath("remain invalid path %q", buf[offset:])
- }
- return b.root, nil
- }
- func (b *PathBuilder) buildNextCharIfExists(buf []rune, cursor int) (int, error) {
- if len(buf) > cursor {
- offset, err := b.buildNext(buf[cursor:])
- if err != nil {
- return 0, err
- }
- return cursor + 1 + offset, nil
- }
- return cursor, nil
- }
- func (b *PathBuilder) buildNext(buf []rune) (int, error) {
- switch buf[0] {
- case '.':
- if len(buf) == 1 {
- return 0, errors.ErrInvalidPath("JSON Path ends with dot character")
- }
- offset, err := b.buildSelector(buf[1:])
- if err != nil {
- return 0, err
- }
- return offset + 1, nil
- case '[':
- if len(buf) == 1 {
- return 0, errors.ErrInvalidPath("JSON Path ends with left bracket character")
- }
- offset, err := b.buildIndex(buf[1:])
- if err != nil {
- return 0, err
- }
- return offset + 1, nil
- default:
- return 0, errors.ErrInvalidPath("expect dot or left bracket character. but found %c character", buf[0])
- }
- }
- func (b *PathBuilder) buildSelector(buf []rune) (int, error) {
- switch buf[0] {
- case '.':
- if len(buf) == 1 {
- return 0, errors.ErrInvalidPath("JSON Path ends with double dot character")
- }
- offset, err := b.buildPathRecursive(buf[1:])
- if err != nil {
- return 0, err
- }
- return 1 + offset, nil
- case '[', ']', '$', '*':
- return 0, errors.ErrInvalidPath("found invalid path character %c after dot", buf[0])
- }
- for cursor := 0; cursor < len(buf); cursor++ {
- switch buf[cursor] {
- case '$', '*', ']':
- return 0, errors.ErrInvalidPath("found %c character in field selector context", buf[cursor])
- case '.':
- if cursor+1 >= len(buf) {
- return 0, errors.ErrInvalidPath("JSON Path ends with dot character")
- }
- selector := buf[:cursor]
- b.addSelectorNode(string(selector))
- offset, err := b.buildSelector(buf[cursor+1:])
- if err != nil {
- return 0, err
- }
- return cursor + 1 + offset, nil
- case '[':
- if cursor+1 >= len(buf) {
- return 0, errors.ErrInvalidPath("JSON Path ends with left bracket character")
- }
- selector := buf[:cursor]
- b.addSelectorNode(string(selector))
- offset, err := b.buildIndex(buf[cursor+1:])
- if err != nil {
- return 0, err
- }
- return cursor + 1 + offset, nil
- case '"':
- if cursor+1 >= len(buf) {
- return 0, errors.ErrInvalidPath("JSON Path ends with double quote character")
- }
- offset, err := b.buildQuoteSelector(buf[cursor+1:], DoubleQuotePathSelector)
- if err != nil {
- return 0, err
- }
- return cursor + 1 + offset, nil
- }
- }
- b.addSelectorNode(string(buf))
- return len(buf), nil
- }
- func (b *PathBuilder) buildQuoteSelector(buf []rune, sel QuotePathSelector) (int, error) {
- switch buf[0] {
- case '[', ']', '$', '.', '*', '\'', '"':
- return 0, errors.ErrInvalidPath("found invalid path character %c after quote", buf[0])
- }
- for cursor := 0; cursor < len(buf); cursor++ {
- switch buf[cursor] {
- case '\'':
- if sel != SingleQuotePathSelector {
- return 0, errors.ErrInvalidPath("found double quote character in field selector with single quote context")
- }
- if len(buf) <= cursor+1 {
- return 0, errors.ErrInvalidPath("JSON Path ends with single quote character in field selector context")
- }
- if buf[cursor+1] != ']' {
- return 0, errors.ErrInvalidPath("expect right bracket for field selector with single quote but found %c", buf[cursor+1])
- }
- selector := buf[:cursor]
- b.addSelectorNode(string(selector))
- b.singleQuotePathSelector = true
- return b.buildNextCharIfExists(buf, cursor+2)
- case '"':
- if sel != DoubleQuotePathSelector {
- return 0, errors.ErrInvalidPath("found single quote character in field selector with double quote context")
- }
- selector := buf[:cursor]
- b.addSelectorNode(string(selector))
- b.doubleQuotePathSelector = true
- return b.buildNextCharIfExists(buf, cursor+1)
- }
- }
- return 0, errors.ErrInvalidPath("couldn't find quote character in selector quote path context")
- }
- func (b *PathBuilder) buildPathRecursive(buf []rune) (int, error) {
- switch buf[0] {
- case '.', '[', ']', '$', '*':
- return 0, errors.ErrInvalidPath("found invalid path character %c after double dot", buf[0])
- }
- for cursor := 0; cursor < len(buf); cursor++ {
- switch buf[cursor] {
- case '$', '*', ']':
- return 0, errors.ErrInvalidPath("found %c character in field selector context", buf[cursor])
- case '.':
- if cursor+1 >= len(buf) {
- return 0, errors.ErrInvalidPath("JSON Path ends with dot character")
- }
- selector := buf[:cursor]
- b.addRecursiveNode(string(selector))
- offset, err := b.buildSelector(buf[cursor+1:])
- if err != nil {
- return 0, err
- }
- return cursor + 1 + offset, nil
- case '[':
- if cursor+1 >= len(buf) {
- return 0, errors.ErrInvalidPath("JSON Path ends with left bracket character")
- }
- selector := buf[:cursor]
- b.addRecursiveNode(string(selector))
- offset, err := b.buildIndex(buf[cursor+1:])
- if err != nil {
- return 0, err
- }
- return cursor + 1 + offset, nil
- }
- }
- b.addRecursiveNode(string(buf))
- return len(buf), nil
- }
- func (b *PathBuilder) buildIndex(buf []rune) (int, error) {
- switch buf[0] {
- case '.', '[', ']', '$':
- return 0, errors.ErrInvalidPath("found invalid path character %c after left bracket", buf[0])
- case '\'':
- if len(buf) == 1 {
- return 0, errors.ErrInvalidPath("JSON Path ends with single quote character")
- }
- offset, err := b.buildQuoteSelector(buf[1:], SingleQuotePathSelector)
- if err != nil {
- return 0, err
- }
- return 1 + offset, nil
- case '*':
- if len(buf) == 1 {
- return 0, errors.ErrInvalidPath("JSON Path ends with star character")
- }
- if buf[1] != ']' {
- return 0, errors.ErrInvalidPath("expect right bracket character for index all path but found %c character", buf[1])
- }
- b.addIndexAllNode()
- offset := len("*]")
- if len(buf) > 2 {
- buildOffset, err := b.buildNext(buf[2:])
- if err != nil {
- return 0, err
- }
- return offset + buildOffset, nil
- }
- return offset, nil
- }
- for cursor := 0; cursor < len(buf); cursor++ {
- switch buf[cursor] {
- case ']':
- index, err := strconv.ParseInt(string(buf[:cursor]), 10, 64)
- if err != nil {
- return 0, errors.ErrInvalidPath("%q is unexpected index path", buf[:cursor])
- }
- b.addIndexNode(int(index))
- return b.buildNextCharIfExists(buf, cursor+1)
- }
- }
- return 0, errors.ErrInvalidPath("couldn't find right bracket character in index path context")
- }
- func (b *PathBuilder) addIndexAllNode() {
- node := newPathIndexAllNode()
- if b.root == nil {
- b.root = node
- b.node = node
- } else {
- b.node = b.node.chain(node)
- }
- }
- func (b *PathBuilder) addRecursiveNode(selector string) {
- node := newPathRecursiveNode(selector)
- if b.root == nil {
- b.root = node
- b.node = node
- } else {
- b.node = b.node.chain(node)
- }
- }
- func (b *PathBuilder) addSelectorNode(name string) {
- node := newPathSelectorNode(name)
- if b.root == nil {
- b.root = node
- b.node = node
- } else {
- b.node = b.node.chain(node)
- }
- }
- func (b *PathBuilder) addIndexNode(idx int) {
- node := newPathIndexNode(idx)
- if b.root == nil {
- b.root = node
- b.node = node
- } else {
- b.node = b.node.chain(node)
- }
- }
- type QuotePathSelector int
- const (
- SingleQuotePathSelector QuotePathSelector = 1
- DoubleQuotePathSelector QuotePathSelector = 2
- )
- type Path struct {
- node PathNode
- RootSelectorOnly bool
- SingleQuotePathSelector bool
- DoubleQuotePathSelector bool
- }
- func (p *Path) Field(sel string) (PathNode, bool, error) {
- if p.node == nil {
- return nil, false, nil
- }
- return p.node.Field(sel)
- }
- func (p *Path) Get(src, dst reflect.Value) error {
- if p.node == nil {
- return nil
- }
- return p.node.Get(src, dst)
- }
- func (p *Path) String() string {
- if p.node == nil {
- return "$"
- }
- return p.node.String()
- }
- type PathNode interface {
- fmt.Stringer
- Index(idx int) (PathNode, bool, error)
- Field(fieldName string) (PathNode, bool, error)
- Get(src, dst reflect.Value) error
- chain(PathNode) PathNode
- target() bool
- single() bool
- }
- type BasePathNode struct {
- child PathNode
- }
- func (n *BasePathNode) chain(node PathNode) PathNode {
- n.child = node
- return node
- }
- func (n *BasePathNode) target() bool {
- return n.child == nil
- }
- func (n *BasePathNode) single() bool {
- return true
- }
- type PathSelectorNode struct {
- *BasePathNode
- selector string
- }
- func newPathSelectorNode(selector string) *PathSelectorNode {
- return &PathSelectorNode{
- BasePathNode: &BasePathNode{},
- selector: selector,
- }
- }
- func (n *PathSelectorNode) Index(idx int) (PathNode, bool, error) {
- return nil, false, &errors.PathError{}
- }
- func (n *PathSelectorNode) Field(fieldName string) (PathNode, bool, error) {
- if n.selector == fieldName {
- return n.child, true, nil
- }
- return nil, false, nil
- }
- func (n *PathSelectorNode) Get(src, dst reflect.Value) error {
- switch src.Type().Kind() {
- case reflect.Map:
- iter := src.MapRange()
- for iter.Next() {
- key, ok := iter.Key().Interface().(string)
- if !ok {
- return fmt.Errorf("invalid map key type %T", src.Type().Key())
- }
- child, found, err := n.Field(key)
- if err != nil {
- return err
- }
- if found {
- if child != nil {
- return child.Get(iter.Value(), dst)
- }
- return AssignValue(iter.Value(), dst)
- }
- }
- case reflect.Struct:
- typ := src.Type()
- for i := 0; i < typ.Len(); i++ {
- tag := runtime.StructTagFromField(typ.Field(i))
- child, found, err := n.Field(tag.Key)
- if err != nil {
- return err
- }
- if found {
- if child != nil {
- return child.Get(src.Field(i), dst)
- }
- return AssignValue(src.Field(i), dst)
- }
- }
- case reflect.Ptr:
- return n.Get(src.Elem(), dst)
- case reflect.Interface:
- return n.Get(reflect.ValueOf(src.Interface()), dst)
- case reflect.Float64, reflect.String, reflect.Bool:
- return AssignValue(src, dst)
- }
- return fmt.Errorf("failed to get %s value from %s", n.selector, src.Type())
- }
- func (n *PathSelectorNode) String() string {
- s := fmt.Sprintf(".%s", n.selector)
- if n.child != nil {
- s += n.child.String()
- }
- return s
- }
- type PathIndexNode struct {
- *BasePathNode
- selector int
- }
- func newPathIndexNode(selector int) *PathIndexNode {
- return &PathIndexNode{
- BasePathNode: &BasePathNode{},
- selector: selector,
- }
- }
- func (n *PathIndexNode) Index(idx int) (PathNode, bool, error) {
- if n.selector == idx {
- return n.child, true, nil
- }
- return nil, false, nil
- }
- func (n *PathIndexNode) Field(fieldName string) (PathNode, bool, error) {
- return nil, false, &errors.PathError{}
- }
- func (n *PathIndexNode) Get(src, dst reflect.Value) error {
- switch src.Type().Kind() {
- case reflect.Array, reflect.Slice:
- if src.Len() > n.selector {
- if n.child != nil {
- return n.child.Get(src.Index(n.selector), dst)
- }
- return AssignValue(src.Index(n.selector), dst)
- }
- case reflect.Ptr:
- return n.Get(src.Elem(), dst)
- case reflect.Interface:
- return n.Get(reflect.ValueOf(src.Interface()), dst)
- }
- return fmt.Errorf("failed to get [%d] value from %s", n.selector, src.Type())
- }
- func (n *PathIndexNode) String() string {
- s := fmt.Sprintf("[%d]", n.selector)
- if n.child != nil {
- s += n.child.String()
- }
- return s
- }
- type PathIndexAllNode struct {
- *BasePathNode
- }
- func newPathIndexAllNode() *PathIndexAllNode {
- return &PathIndexAllNode{
- BasePathNode: &BasePathNode{},
- }
- }
- func (n *PathIndexAllNode) Index(idx int) (PathNode, bool, error) {
- return n.child, true, nil
- }
- func (n *PathIndexAllNode) Field(fieldName string) (PathNode, bool, error) {
- return nil, false, &errors.PathError{}
- }
- func (n *PathIndexAllNode) Get(src, dst reflect.Value) error {
- switch src.Type().Kind() {
- case reflect.Array, reflect.Slice:
- var arr []interface{}
- for i := 0; i < src.Len(); i++ {
- var v interface{}
- rv := reflect.ValueOf(&v)
- if n.child != nil {
- if err := n.child.Get(src.Index(i), rv); err != nil {
- return err
- }
- } else {
- if err := AssignValue(src.Index(i), rv); err != nil {
- return err
- }
- }
- arr = append(arr, v)
- }
- if err := AssignValue(reflect.ValueOf(arr), dst); err != nil {
- return err
- }
- return nil
- case reflect.Ptr:
- return n.Get(src.Elem(), dst)
- case reflect.Interface:
- return n.Get(reflect.ValueOf(src.Interface()), dst)
- }
- return fmt.Errorf("failed to get all value from %s", src.Type())
- }
- func (n *PathIndexAllNode) String() string {
- s := "[*]"
- if n.child != nil {
- s += n.child.String()
- }
- return s
- }
- type PathRecursiveNode struct {
- *BasePathNode
- selector string
- }
- func newPathRecursiveNode(selector string) *PathRecursiveNode {
- node := newPathSelectorNode(selector)
- return &PathRecursiveNode{
- BasePathNode: &BasePathNode{
- child: node,
- },
- selector: selector,
- }
- }
- func (n *PathRecursiveNode) Field(fieldName string) (PathNode, bool, error) {
- if n.selector == fieldName {
- return n.child, true, nil
- }
- return nil, false, nil
- }
- func (n *PathRecursiveNode) Index(_ int) (PathNode, bool, error) {
- return n, true, nil
- }
- func valueToSliceValue(v interface{}) []interface{} {
- rv := reflect.ValueOf(v)
- ret := []interface{}{}
- if rv.Type().Kind() == reflect.Slice || rv.Type().Kind() == reflect.Array {
- for i := 0; i < rv.Len(); i++ {
- ret = append(ret, rv.Index(i).Interface())
- }
- return ret
- }
- return []interface{}{v}
- }
- func (n *PathRecursiveNode) Get(src, dst reflect.Value) error {
- if n.child == nil {
- return fmt.Errorf("failed to get by recursive path ..%s", n.selector)
- }
- var arr []interface{}
- switch src.Type().Kind() {
- case reflect.Map:
- iter := src.MapRange()
- for iter.Next() {
- key, ok := iter.Key().Interface().(string)
- if !ok {
- return fmt.Errorf("invalid map key type %T", src.Type().Key())
- }
- child, found, err := n.Field(key)
- if err != nil {
- return err
- }
- if found {
- var v interface{}
- rv := reflect.ValueOf(&v)
- _ = child.Get(iter.Value(), rv)
- arr = append(arr, valueToSliceValue(v)...)
- } else {
- var v interface{}
- rv := reflect.ValueOf(&v)
- _ = n.Get(iter.Value(), rv)
- if v != nil {
- arr = append(arr, valueToSliceValue(v)...)
- }
- }
- }
- _ = AssignValue(reflect.ValueOf(arr), dst)
- return nil
- case reflect.Struct:
- typ := src.Type()
- for i := 0; i < typ.Len(); i++ {
- tag := runtime.StructTagFromField(typ.Field(i))
- child, found, err := n.Field(tag.Key)
- if err != nil {
- return err
- }
- if found {
- var v interface{}
- rv := reflect.ValueOf(&v)
- _ = child.Get(src.Field(i), rv)
- arr = append(arr, valueToSliceValue(v)...)
- } else {
- var v interface{}
- rv := reflect.ValueOf(&v)
- _ = n.Get(src.Field(i), rv)
- if v != nil {
- arr = append(arr, valueToSliceValue(v)...)
- }
- }
- }
- _ = AssignValue(reflect.ValueOf(arr), dst)
- return nil
- case reflect.Array, reflect.Slice:
- for i := 0; i < src.Len(); i++ {
- var v interface{}
- rv := reflect.ValueOf(&v)
- _ = n.Get(src.Index(i), rv)
- if v != nil {
- arr = append(arr, valueToSliceValue(v)...)
- }
- }
- _ = AssignValue(reflect.ValueOf(arr), dst)
- return nil
- case reflect.Ptr:
- return n.Get(src.Elem(), dst)
- case reflect.Interface:
- return n.Get(reflect.ValueOf(src.Interface()), dst)
- }
- return fmt.Errorf("failed to get %s value from %s", n.selector, src.Type())
- }
- func (n *PathRecursiveNode) String() string {
- s := fmt.Sprintf("..%s", n.selector)
- if n.child != nil {
- s += n.child.String()
- }
- return s
- }
|