Skip to content

Commit

Permalink
Fix json path
Browse files Browse the repository at this point in the history
  • Loading branch information
goccy committed Nov 29, 2022
1 parent d8329d5 commit 1de494f
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 7 deletions.
3 changes: 3 additions & 0 deletions decode.go
Expand Up @@ -88,6 +88,9 @@ var (
)

func extractFromPath(path *Path, data []byte, optFuncs ...DecodeOptionFunc) ([][]byte, error) {
if path.path.RootSelectorOnly {
return [][]byte{data}, nil
}
src := make([]byte, len(data)+1) // append nul byte to the end
copy(src, data)

Expand Down
3 changes: 2 additions & 1 deletion internal/decoder/map.go
Expand Up @@ -265,8 +265,9 @@ func (d *mapDecoder) DecodePath(ctx *RuntimeContext, cursor, depth int64) ([][]b
if err != nil {
return nil, 0, err
}
cursor = skipWhiteSpace(buf, c)
cursor = c
}
cursor = skipWhiteSpace(buf, cursor)
if buf[cursor] == '}' {
cursor++
return ret, cursor, nil
Expand Down
27 changes: 22 additions & 5 deletions internal/decoder/path.go
Expand Up @@ -30,6 +30,7 @@ func (b *PathBuilder) Build(buf []rune) (*Path, error) {
}
return &Path{
node: node,
RootSelectorOnly: node == nil,
SingleQuotePathSelector: b.singleQuotePathSelector,
DoubleQuotePathSelector: b.doubleQuotePathSelector,
}, nil
Expand Down Expand Up @@ -57,8 +58,8 @@ func (b *PathBuilder) build(buf []rune) (PathNode, error) {
}

func (b *PathBuilder) buildNextCharIfExists(buf []rune, cursor int) (int, error) {
if len(buf) > cursor+1 {
offset, err := b.buildNext(buf[cursor+1:])
if len(buf) > cursor {
offset, err := b.buildNext(buf[cursor:])
if err != nil {
return 0, err
}
Expand Down Expand Up @@ -166,14 +167,16 @@ func (b *PathBuilder) buildQuoteSelector(buf []rune, sel QuotePathSelector) (int
}
selector := buf[:cursor]
b.addSelectorNode(string(selector))
return b.buildNextCharIfExists(buf, cursor+1)
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))
return b.buildNextCharIfExists(buf, cursor)
b.doubleQuotePathSelector = true
return b.buildNextCharIfExists(buf, cursor+1)
}
}
return 0, errors.ErrInvalidPath("couldn't find quote character in selector quote path context")
Expand Down Expand Up @@ -256,7 +259,7 @@ func (b *PathBuilder) buildIndex(buf []rune) (int, error) {
return 0, errors.ErrInvalidPath("%q is unexpected index path", buf[:cursor])
}
b.addIndexNode(int(index))
return b.buildNextCharIfExists(buf, cursor)
return b.buildNextCharIfExists(buf, cursor+1)
}
}
return 0, errors.ErrInvalidPath("couldn't find right bracket character in index path context")
Expand Down Expand Up @@ -311,18 +314,32 @@ const (

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)
Expand Down
4 changes: 3 additions & 1 deletion internal/decoder/slice.go
Expand Up @@ -350,14 +350,16 @@ func (d *sliceDecoder) DecodePath(ctx *RuntimeContext, cursor, depth int64) ([][
return nil, 0, err
}
ret = append(ret, buf[start:end])
cursor = end
}
} else {
c, err := skipValue(buf, cursor, depth)
if err != nil {
return nil, 0, err
}
cursor = skipWhiteSpace(buf, c)
cursor = c
}
cursor = skipWhiteSpace(buf, cursor)
switch buf[cursor] {
case ']':
cursor++
Expand Down
10 changes: 10 additions & 0 deletions path.go
Expand Up @@ -33,6 +33,11 @@ type Path struct {
path *decoder.Path
}

// RootSelectorOnly whether only the root selector ($) is used.
func (p *Path) RootSelectorOnly() bool {
return p.path.RootSelectorOnly
}

// UsedSingleQuotePathSelector whether single quote-based escaping was done when building the JSON Path.
func (p *Path) UsedSingleQuotePathSelector() bool {
return p.path.SingleQuotePathSelector
Expand All @@ -48,6 +53,11 @@ func (p *Path) Extract(data []byte, optFuncs ...DecodeOptionFunc) ([][]byte, err
return extractFromPath(p, data, optFuncs...)
}

// PathString returns original JSON Path string.
func (p *Path) PathString() string {
return p.path.String()
}

// Unmarshal extract and decode the value of the part corresponding to JSON Path from the input data.
func (p *Path) Unmarshal(data []byte, v interface{}, optFuncs ...DecodeOptionFunc) error {
contents, err := extractFromPath(p, data, optFuncs...)
Expand Down

0 comments on commit 1de494f

Please sign in to comment.