mirror of
https://github.com/json-iterator/go.git
synced 2025-03-23 21:09:11 +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() {
|
||||
c := iter.readByte()
|
||||
for c == ' ' {
|
||||
for c == ' ' || c == '\n' {
|
||||
c = iter.readByte()
|
||||
}
|
||||
iter.unreadByte()
|
||||
@ -326,7 +326,9 @@ func (iter *Iterator) ReadArray() (ret bool) {
|
||||
}
|
||||
}
|
||||
case ']': return false
|
||||
case ',': return true
|
||||
case ',':
|
||||
iter.skipWhitespaces()
|
||||
return true
|
||||
default:
|
||||
iter.ReportError("ReadArray", "expect [ or , or ]")
|
||||
return
|
||||
@ -397,18 +399,8 @@ func (iter *Iterator) readObjectField() (ret string) {
|
||||
func (iter *Iterator) ReadFloat64() (ret float64) {
|
||||
str := make([]byte, 0, 10)
|
||||
for c := iter.readByte(); iter.Error == nil; c = iter.readByte() {
|
||||
switch {
|
||||
case c == '+':
|
||||
fallthrough
|
||||
case c == '-':
|
||||
fallthrough
|
||||
case c == '.':
|
||||
fallthrough
|
||||
case c == 'e':
|
||||
fallthrough
|
||||
case c == 'E':
|
||||
fallthrough
|
||||
case c > '0' && c < '9':
|
||||
switch c {
|
||||
case '-', '+', '.', 'e', 'E', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
||||
str = append(str, c)
|
||||
default:
|
||||
iter.unreadByte()
|
||||
@ -430,3 +422,117 @@ func (iter *Iterator) ReadFloat64() (ret float64) {
|
||||
}
|
||||
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