mirror of https://github.com/goccy/go-json.git
Fix json path
This commit is contained in:
parent
d8329d56f9
commit
1de494fd9a
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
10
path.go
|
@ -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...)
|
||||||
|
|
Loading…
Reference in New Issue