mirror of
https://github.com/json-iterator/go.git
synced 2025-04-01 21:24:21 +02:00
support skip
This commit is contained in:
parent
f96cc49fd4
commit
05a9df4749
134
jsoniter.go
134
jsoniter.go
@ -43,7 +43,7 @@ func ParseString(input string) *Iterator {
|
|||||||
|
|
||||||
func (iter *Iterator) skipWhitespaces() {
|
func (iter *Iterator) skipWhitespaces() {
|
||||||
c := iter.readByte()
|
c := iter.readByte()
|
||||||
for c == ' ' {
|
for c == ' ' || c == '\n' {
|
||||||
c = iter.readByte()
|
c = iter.readByte()
|
||||||
}
|
}
|
||||||
iter.unreadByte()
|
iter.unreadByte()
|
||||||
@ -326,7 +326,9 @@ func (iter *Iterator) ReadArray() (ret bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
case ']': return false
|
case ']': return false
|
||||||
case ',': return true
|
case ',':
|
||||||
|
iter.skipWhitespaces()
|
||||||
|
return true
|
||||||
default:
|
default:
|
||||||
iter.ReportError("ReadArray", "expect [ or , or ]")
|
iter.ReportError("ReadArray", "expect [ or , or ]")
|
||||||
return
|
return
|
||||||
@ -397,18 +399,8 @@ func (iter *Iterator) readObjectField() (ret string) {
|
|||||||
func (iter *Iterator) ReadFloat64() (ret float64) {
|
func (iter *Iterator) ReadFloat64() (ret float64) {
|
||||||
str := make([]byte, 0, 10)
|
str := make([]byte, 0, 10)
|
||||||
for c := iter.readByte(); iter.Error == nil; c = iter.readByte() {
|
for c := iter.readByte(); iter.Error == nil; c = iter.readByte() {
|
||||||
switch {
|
switch c {
|
||||||
case c == '+':
|
case '-', '+', '.', 'e', 'E', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
||||||
fallthrough
|
|
||||||
case c == '-':
|
|
||||||
fallthrough
|
|
||||||
case c == '.':
|
|
||||||
fallthrough
|
|
||||||
case c == 'e':
|
|
||||||
fallthrough
|
|
||||||
case c == 'E':
|
|
||||||
fallthrough
|
|
||||||
case c > '0' && c < '9':
|
|
||||||
str = append(str, c)
|
str = append(str, c)
|
||||||
default:
|
default:
|
||||||
iter.unreadByte()
|
iter.unreadByte()
|
||||||
@ -430,3 +422,117 @@ func (iter *Iterator) ReadFloat64() (ret float64) {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (iter *Iterator) Skip() {
|
||||||
|
c := iter.readByte()
|
||||||
|
if iter.Error != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch c {
|
||||||
|
case '"':
|
||||||
|
iter.skipString()
|
||||||
|
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
||||||
|
iter.skipNumber()
|
||||||
|
case '[':
|
||||||
|
iter.skipArray()
|
||||||
|
case '{':
|
||||||
|
iter.skipObject()
|
||||||
|
default:
|
||||||
|
iter.ReportError("Skip", fmt.Sprintf("do not know how to skip: %v", c))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (iter *Iterator) skipString() {
|
||||||
|
for c := iter.readByte(); iter.Error == nil; c = iter.readByte() {
|
||||||
|
switch c {
|
||||||
|
case '"':
|
||||||
|
return // end of string found
|
||||||
|
case '\\':
|
||||||
|
iter.readByte() // " after \\ does not count
|
||||||
|
if iter.Error != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (iter *Iterator) skipNumber() {
|
||||||
|
for c := iter.readByte(); iter.Error == nil; c = iter.readByte() {
|
||||||
|
switch c {
|
||||||
|
case '-', '+', '.', 'e', 'E', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
||||||
|
continue
|
||||||
|
default:
|
||||||
|
iter.unreadByte()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (iter *Iterator) skipArray() {
|
||||||
|
for {
|
||||||
|
iter.skipWhitespaces()
|
||||||
|
c := iter.readByte()
|
||||||
|
if iter.Error != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if c == ']' {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
iter.unreadByte()
|
||||||
|
iter.Skip()
|
||||||
|
iter.skipWhitespaces()
|
||||||
|
c = iter.readByte()
|
||||||
|
if iter.Error != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch c {
|
||||||
|
case ',':
|
||||||
|
iter.skipWhitespaces()
|
||||||
|
continue
|
||||||
|
case ']':
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
iter.ReportError("skipArray", "expects , or ]")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (iter *Iterator) skipObject() {
|
||||||
|
for {
|
||||||
|
iter.skipWhitespaces()
|
||||||
|
c := iter.readByte()
|
||||||
|
if c != '"' {
|
||||||
|
iter.ReportError("skipObject", `expects "`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
iter.skipString()
|
||||||
|
iter.skipWhitespaces()
|
||||||
|
c = iter.readByte()
|
||||||
|
if iter.Error != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if c != ':' {
|
||||||
|
iter.ReportError("skipObject", `expects :`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
iter.skipWhitespaces()
|
||||||
|
iter.Skip()
|
||||||
|
iter.skipWhitespaces()
|
||||||
|
c = iter.readByte()
|
||||||
|
if iter.Error != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch c {
|
||||||
|
case ',':
|
||||||
|
iter.skipWhitespaces()
|
||||||
|
continue
|
||||||
|
case '}':
|
||||||
|
return // end of object
|
||||||
|
default:
|
||||||
|
iter.ReportError("skipObject", "expects , or }")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
138
jsoniter_skip_test.go
Normal file
138
jsoniter_skip_test.go
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
package jsoniter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"encoding/json"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_skip_string(t *testing.T) {
|
||||||
|
iter := ParseString(`["a", "b"]`)
|
||||||
|
iter.ReadArray()
|
||||||
|
iter.Skip()
|
||||||
|
iter.ReadArray()
|
||||||
|
if iter.ReadString() != "b" {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_skip_string_with_escape(t *testing.T) {
|
||||||
|
iter := ParseString(`["a\"", "b"]`)
|
||||||
|
iter.ReadArray()
|
||||||
|
iter.Skip()
|
||||||
|
iter.ReadArray()
|
||||||
|
if iter.ReadString() != "b" {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_skip_number(t *testing.T) {
|
||||||
|
iter := ParseString(`[-0.12, "b"]`)
|
||||||
|
iter.ReadArray()
|
||||||
|
iter.Skip()
|
||||||
|
iter.ReadArray()
|
||||||
|
if iter.ReadString() != "b" {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_skip_array(t *testing.T) {
|
||||||
|
iter := ParseString(`[[1, [2, [3], 4]], "b"]`)
|
||||||
|
iter.ReadArray()
|
||||||
|
iter.Skip()
|
||||||
|
iter.ReadArray()
|
||||||
|
if iter.ReadString() != "b" {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_skip_object(t *testing.T) {
|
||||||
|
iter := ParseString(`[ {"a" : {"b": "c"}, "d": 102 }, "b"]`)
|
||||||
|
iter.ReadArray()
|
||||||
|
iter.Skip()
|
||||||
|
iter.ReadArray()
|
||||||
|
if iter.ReadString() != "b" {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_skip_nested(t *testing.T) {
|
||||||
|
iter := ParseString(`[ {"a" : [{"b": "c"}], "d": 102 }, "b"]`)
|
||||||
|
iter.ReadArray()
|
||||||
|
iter.Skip()
|
||||||
|
iter.ReadArray()
|
||||||
|
if iter.ReadString() != "b" {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type TestResp struct {
|
||||||
|
Code uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func Benchmark_jsoniter_skip(b *testing.B) {
|
||||||
|
for n := 0; n < b.N; n++ {
|
||||||
|
result := TestResp{}
|
||||||
|
iter := ParseString(`
|
||||||
|
{
|
||||||
|
"_shards":{
|
||||||
|
"total" : 5,
|
||||||
|
"successful" : 5,
|
||||||
|
"failed" : 0
|
||||||
|
},
|
||||||
|
"code": 200,
|
||||||
|
"hits":{
|
||||||
|
"total" : 1,
|
||||||
|
"hits" : [
|
||||||
|
{
|
||||||
|
"_index" : "twitter",
|
||||||
|
"_type" : "tweet",
|
||||||
|
"_id" : "1",
|
||||||
|
"_source" : {
|
||||||
|
"user" : "kimchy",
|
||||||
|
"postDate" : "2009-11-15T14:12:12",
|
||||||
|
"message" : "trying out Elasticsearch"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}`)
|
||||||
|
for field := iter.ReadObject(); field != ""; field = iter.ReadObject() {
|
||||||
|
switch field {
|
||||||
|
case "code":
|
||||||
|
result.Code = iter.ReadUint64()
|
||||||
|
default:
|
||||||
|
iter.Skip()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Benchmark_json_skip(b *testing.B) {
|
||||||
|
for n := 0; n < b.N; n++ {
|
||||||
|
result := TestResp{}
|
||||||
|
json.Unmarshal([]byte(`
|
||||||
|
{
|
||||||
|
"_shards":{
|
||||||
|
"total" : 5,
|
||||||
|
"successful" : 5,
|
||||||
|
"failed" : 0
|
||||||
|
},
|
||||||
|
"code": 200,
|
||||||
|
"hits":{
|
||||||
|
"total" : 1,
|
||||||
|
"hits" : [
|
||||||
|
{
|
||||||
|
"_index" : "twitter",
|
||||||
|
"_type" : "tweet",
|
||||||
|
"_id" : "1",
|
||||||
|
"_source" : {
|
||||||
|
"user" : "kimchy",
|
||||||
|
"postDate" : "2009-11-15T14:12:12",
|
||||||
|
"message" : "trying out Elasticsearch"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}`), &result)
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user