Fix json path

This commit is contained in:
Masaaki Goshima 2022-11-29 21:44:55 +09:00
parent d8329d56f9
commit 1de494fd9a
No known key found for this signature in database
GPG Key ID: 6A53785055537153
5 changed files with 40 additions and 7 deletions

View File

@ -88,6 +88,9 @@ var (
) )
func extractFromPath(path *Path, data []byte, optFuncs ...DecodeOptionFunc) ([][]byte, error) { 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 src := make([]byte, len(data)+1) // append nul byte to the end
copy(src, data) copy(src, data)

View File

@ -265,8 +265,9 @@ func (d *mapDecoder) DecodePath(ctx *RuntimeContext, cursor, depth int64) ([][]b
if err != nil { if err != nil {
return nil, 0, err return nil, 0, err
} }
cursor = skipWhiteSpace(buf, c) cursor = c
} }
cursor = skipWhiteSpace(buf, cursor)
if buf[cursor] == '}' { if buf[cursor] == '}' {
cursor++ cursor++
return ret, cursor, nil return ret, cursor, nil

View File

@ -30,6 +30,7 @@ func (b *PathBuilder) Build(buf []rune) (*Path, error) {
} }
return &Path{ return &Path{
node: node, node: node,
RootSelectorOnly: node == nil,
SingleQuotePathSelector: b.singleQuotePathSelector, SingleQuotePathSelector: b.singleQuotePathSelector,
DoubleQuotePathSelector: b.doubleQuotePathSelector, DoubleQuotePathSelector: b.doubleQuotePathSelector,
}, nil }, nil
@ -57,8 +58,8 @@ func (b *PathBuilder) build(buf []rune) (PathNode, error) {
} }
func (b *PathBuilder) buildNextCharIfExists(buf []rune, cursor int) (int, error) { func (b *PathBuilder) buildNextCharIfExists(buf []rune, cursor int) (int, error) {
if len(buf) > cursor+1 { if len(buf) > cursor {
offset, err := b.buildNext(buf[cursor+1:]) offset, err := b.buildNext(buf[cursor:])
if err != nil { if err != nil {
return 0, err return 0, err
} }
@ -166,14 +167,16 @@ func (b *PathBuilder) buildQuoteSelector(buf []rune, sel QuotePathSelector) (int
} }
selector := buf[:cursor] selector := buf[:cursor]
b.addSelectorNode(string(selector)) b.addSelectorNode(string(selector))
return b.buildNextCharIfExists(buf, cursor+1) b.singleQuotePathSelector = true
return b.buildNextCharIfExists(buf, cursor+2)
case '"': case '"':
if sel != DoubleQuotePathSelector { if sel != DoubleQuotePathSelector {
return 0, errors.ErrInvalidPath("found single quote character in field selector with double quote context") return 0, errors.ErrInvalidPath("found single quote character in field selector with double quote context")
} }
selector := buf[:cursor] selector := buf[:cursor]
b.addSelectorNode(string(selector)) 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") return 0, errors.ErrInvalidPath("couldn't find quote character in selector quote path context")
@ -256,7 +259,7 @@ func (b *PathBuilder) buildIndex(buf []rune) (int, error) {
return 0, errors.ErrInvalidPath("%q is unexpected index path", buf[:cursor]) return 0, errors.ErrInvalidPath("%q is unexpected index path", buf[:cursor])
} }
b.addIndexNode(int(index)) 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") return 0, errors.ErrInvalidPath("couldn't find right bracket character in index path context")
@ -311,18 +314,32 @@ const (
type Path struct { type Path struct {
node PathNode node PathNode
RootSelectorOnly bool
SingleQuotePathSelector bool SingleQuotePathSelector bool
DoubleQuotePathSelector bool DoubleQuotePathSelector bool
} }
func (p *Path) Field(sel string) (PathNode, bool, error) { func (p *Path) Field(sel string) (PathNode, bool, error) {
if p.node == nil {
return nil, false, nil
}
return p.node.Field(sel) return p.node.Field(sel)
} }
func (p *Path) Get(src, dst reflect.Value) error { func (p *Path) Get(src, dst reflect.Value) error {
if p.node == nil {
return nil
}
return p.node.Get(src, dst) return p.node.Get(src, dst)
} }
func (p *Path) String() string {
if p.node == nil {
return "$"
}
return p.node.String()
}
type PathNode interface { type PathNode interface {
fmt.Stringer fmt.Stringer
Index(idx int) (PathNode, bool, error) Index(idx int) (PathNode, bool, error)

View File

@ -350,14 +350,16 @@ func (d *sliceDecoder) DecodePath(ctx *RuntimeContext, cursor, depth int64) ([][
return nil, 0, err return nil, 0, err
} }
ret = append(ret, buf[start:end]) ret = append(ret, buf[start:end])
cursor = end
} }
} else { } else {
c, err := skipValue(buf, cursor, depth) c, err := skipValue(buf, cursor, depth)
if err != nil { if err != nil {
return nil, 0, err return nil, 0, err
} }
cursor = skipWhiteSpace(buf, c) cursor = c
} }
cursor = skipWhiteSpace(buf, cursor)
switch buf[cursor] { switch buf[cursor] {
case ']': case ']':
cursor++ cursor++

10
path.go
View File

@ -33,6 +33,11 @@ type Path struct {
path *decoder.Path 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. // UsedSingleQuotePathSelector whether single quote-based escaping was done when building the JSON Path.
func (p *Path) UsedSingleQuotePathSelector() bool { func (p *Path) UsedSingleQuotePathSelector() bool {
return p.path.SingleQuotePathSelector return p.path.SingleQuotePathSelector
@ -48,6 +53,11 @@ func (p *Path) Extract(data []byte, optFuncs ...DecodeOptionFunc) ([][]byte, err
return extractFromPath(p, data, optFuncs...) 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. // 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 { func (p *Path) Unmarshal(data []byte, v interface{}, optFuncs ...DecodeOptionFunc) error {
contents, err := extractFromPath(p, data, optFuncs...) contents, err := extractFromPath(p, data, optFuncs...)