5
5
"errors"
6
6
"fmt"
7
7
"math"
8
+ "strconv"
8
9
)
9
10
10
11
// Errors
@@ -31,7 +32,7 @@ func tokenEnd(data []byte) int {
31
32
}
32
33
}
33
34
34
- return - 1
35
+ return len ( data )
35
36
}
36
37
37
38
// Find position of next character which is not whitespace
@@ -116,6 +117,10 @@ func searchKeys(data []byte, keys ...string) int {
116
117
ln := len (data )
117
118
lk := len (keys )
118
119
120
+ if lk == 0 {
121
+ return 0
122
+ }
123
+
119
124
var stackbuf [unescapeStackBufSize ]byte // stack-allocated array for allocation-free unescaping of small strings
120
125
121
126
for i < ln {
@@ -168,11 +173,34 @@ func searchKeys(data []byte, keys ...string) int {
168
173
case '}' :
169
174
level --
170
175
case '[' :
171
- // Do not search for keys inside arrays
172
- if arraySkip := blockEnd (data [i :], '[' , ']' ); arraySkip == - 1 {
173
- return - 1
176
+ // If we want to get array element by index
177
+ if keyLevel == level && keys [level ][0 ] == '[' {
178
+ aIdx , _ := strconv .Atoi (keys [level ][1 : len (keys [level ])- 1 ])
179
+
180
+ var curIdx int
181
+ var valueFound []byte
182
+ var valueOffset int
183
+
184
+ ArrayEach (data [i :], func (value []byte , dataType ValueType , offset int , err error ) {
185
+ if (curIdx == aIdx ) {
186
+ valueFound = value
187
+ valueOffset = offset
188
+ }
189
+ curIdx += 1
190
+ })
191
+
192
+ if valueFound == nil {
193
+ return - 1
194
+ } else {
195
+ return i + valueOffset + searchKeys (valueFound , keys [level + 1 :]... )
196
+ }
174
197
} else {
175
- i += arraySkip - 1
198
+ // Do not search for keys inside arrays
199
+ if arraySkip := blockEnd (data [i :], '[' , ']' ); arraySkip == - 1 {
200
+ return - 1
201
+ } else {
202
+ i += arraySkip - 1
203
+ }
176
204
}
177
205
}
178
206
@@ -191,15 +219,12 @@ func init() {
191
219
}
192
220
193
221
func sameTree (p1 , p2 []string ) bool {
194
- if len (p1 ) == 1 && len (p2 ) == 1 {
195
- return true
222
+ minLen := len (p1 )
223
+ if len (p2 ) < minLen {
224
+ minLen = len (p2 )
196
225
}
197
226
198
- for pi_1 , p_1 := range p1 [:len (p1 )- 1 ] {
199
- if len (p2 )- 2 < pi_1 {
200
- break
201
- }
202
-
227
+ for pi_1 , p_1 := range p1 [:minLen ] {
203
228
if p2 [pi_1 ] != p_1 {
204
229
return false
205
230
}
@@ -209,11 +234,19 @@ func sameTree(p1, p2 []string) bool {
209
234
}
210
235
211
236
func EachKey (data []byte , cb func (int , []byte , ValueType , error ), paths ... []string ) int {
212
- var pathFlags , ignorePathFlags int64
237
+ var pathFlags int64
213
238
var level , pathsMatched , i int
214
239
ln := len (data )
215
240
241
+ var maxPath int
242
+ for _ , p := range paths {
243
+ if len (p ) > maxPath {
244
+ maxPath = len (p )
245
+ }
246
+ }
247
+
216
248
var stackbuf [unescapeStackBufSize ]byte // stack-allocated array for allocation-free unescaping of small strings
249
+ pathsBuf := make ([]string , maxPath )
217
250
218
251
for i < ln {
219
252
switch data [i ] {
@@ -252,58 +285,41 @@ func EachKey(data []byte, cb func(int, []byte, ValueType, error), paths ...[]str
252
285
keyUnesc = ku
253
286
}
254
287
255
- for pi , p := range paths {
256
- if len (p ) < level || (pathFlags & bitwiseFlags [pi ]) != 0 || (ignorePathFlags & bitwiseFlags [pi ] != 0 ) {
257
- continue
258
- }
288
+ if maxPath >= level {
289
+ pathsBuf [level - 1 ] = bytesToString (& keyUnesc )
290
+
291
+ for pi , p := range paths {
292
+ if len (p ) != level || pathFlags & bitwiseFlags [pi + 1 ] != 0 || ! equalStr (& keyUnesc , p [level - 1 ]) || ! sameTree (p , pathsBuf [:level ]) {
293
+ continue
294
+ }
259
295
260
- if equalStr (& keyUnesc , p [level - 1 ]) {
261
296
match = pi
262
297
263
- if len (p ) == level {
264
- i ++
265
- pathsMatched ++
266
- pathFlags |= bitwiseFlags [pi ]
298
+ i ++
299
+ pathsMatched ++
300
+ pathFlags |= bitwiseFlags [pi + 1 ]
267
301
268
- v , dt , of , e := Get (data [i :])
269
- cb (pi , v , dt , e )
302
+ v , dt , of , e := Get (data [i :])
303
+ cb (pi , v , dt , e )
270
304
271
- if of != - 1 {
272
- i += of
273
- }
305
+ if of != - 1 {
306
+ i += of
307
+ }
274
308
275
- if pathsMatched == len (paths ) {
276
- return i
277
- }
309
+ if pathsMatched == len (paths ) {
310
+ return i
278
311
}
279
312
}
280
313
}
281
314
282
315
if match == - 1 {
283
- ignorePathFlags = 0
284
316
tokenOffset := nextToken (data [i + 1 :])
285
317
i += tokenOffset
286
318
287
319
if data [i ] == '{' {
288
320
blockSkip := blockEnd (data [i :], '{' , '}' )
289
321
i += blockSkip + 1
290
322
}
291
- } else {
292
- m_p := paths [match ]
293
-
294
- for pi , p := range paths {
295
- if pi == match {
296
- continue
297
- }
298
-
299
- if len (p ) < level || (pathFlags & bitwiseFlags [pi ]) != 0 || (ignorePathFlags & bitwiseFlags [pi ] != 0 ) {
300
- continue
301
- }
302
-
303
- if ! sameTree (m_p , p ) {
304
- ignorePathFlags |= bitwiseFlags [pi ]
305
- }
306
- }
307
323
}
308
324
309
325
switch data [i ] {
@@ -318,12 +334,61 @@ func EachKey(data []byte, cb func(int, []byte, ValueType, error), paths ...[]str
318
334
case '}' :
319
335
level --
320
336
case '[' :
321
- // Do not search for keys inside arrays
322
- if arraySkip := blockEnd (data [i :], '[' , ']' ); arraySkip == - 1 {
323
- return - 1
337
+ var arrIdxFlags int64
338
+ var pIdxFlags int64
339
+ for pi , p := range paths {
340
+ if len (p ) < level + 1 || pathFlags & bitwiseFlags [pi + 1 ] != 0 || p [level ][0 ] != '[' || ! sameTree (p , pathsBuf [:level ]) {
341
+ continue
342
+ }
343
+
344
+ aIdx , _ := strconv .Atoi (p [level ][1 : len (p [level ]) - 1 ])
345
+ arrIdxFlags |= bitwiseFlags [aIdx + 1 ]
346
+ pIdxFlags |= bitwiseFlags [pi + 1 ]
347
+ }
348
+
349
+ if arrIdxFlags > 0 {
350
+ level ++
351
+
352
+ var curIdx int
353
+ arrOff , _ := ArrayEach (data [i :], func (value []byte , dataType ValueType , offset int , err error ) {
354
+ if (arrIdxFlags & bitwiseFlags [curIdx + 1 ] != 0 ) {
355
+ for pi , p := range paths {
356
+ if pIdxFlags & bitwiseFlags [pi + 1 ] != 0 {
357
+ aIdx , _ := strconv .Atoi (p [level - 1 ][1 : len (p [level - 1 ]) - 1 ])
358
+
359
+ if curIdx == aIdx {
360
+ of := searchKeys (value , p [level :]... )
361
+
362
+ pathsMatched ++
363
+ pathFlags |= bitwiseFlags [pi + 1 ]
364
+
365
+ if of != - 1 {
366
+ v , dt , _ , e := Get (value [of :])
367
+ cb (pi , v , dt , e )
368
+ }
369
+ }
370
+ }
371
+ }
372
+ }
373
+
374
+ curIdx += 1
375
+ })
376
+
377
+ if pathsMatched == len (paths ) {
378
+ return i
379
+ }
380
+
381
+ i += arrOff - 1
324
382
} else {
325
- i += arraySkip - 1
383
+ // Do not search for keys inside arrays
384
+ if arraySkip := blockEnd (data [i :], '[' , ']' ); arraySkip == - 1 {
385
+ return - 1
386
+ } else {
387
+ i += arraySkip - 1
388
+ }
326
389
}
390
+ case ']' :
391
+ level --
327
392
}
328
393
329
394
i ++
@@ -476,28 +541,28 @@ func Get(data []byte, keys ...string) (value []byte, dataType ValueType, offset
476
541
}
477
542
478
543
// ArrayEach is used when iterating arrays, accepts a callback function with the same return arguments as `Get`.
479
- func ArrayEach (data []byte , cb func (value []byte , dataType ValueType , offset int , err error ), keys ... string ) (err error ) {
544
+ func ArrayEach (data []byte , cb func (value []byte , dataType ValueType , offset int , err error ), keys ... string ) (offset int , err error ) {
480
545
if len (data ) == 0 {
481
- return MalformedObjectError
546
+ return - 1 , MalformedObjectError
482
547
}
483
548
484
- offset : = 1
549
+ offset = 1
485
550
486
551
if len (keys ) > 0 {
487
552
if offset = searchKeys (data , keys ... ); offset == - 1 {
488
- return KeyPathNotFoundError
553
+ return offset , KeyPathNotFoundError
489
554
}
490
555
491
556
// Go to closest value
492
557
nO := nextToken (data [offset :])
493
558
if nO == - 1 {
494
- return MalformedJsonError
559
+ return offset , MalformedJsonError
495
560
}
496
561
497
562
offset += nO
498
563
499
564
if data [offset ] != '[' {
500
- return MalformedArrayError
565
+ return offset , MalformedArrayError
501
566
}
502
567
503
568
offset ++
@@ -511,7 +576,7 @@ func ArrayEach(data []byte, cb func(value []byte, dataType ValueType, offset int
511
576
}
512
577
513
578
if t != NotExist {
514
- cb (v , t , o , e )
579
+ cb (v , t , offset + o - len ( v ) , e )
515
580
}
516
581
517
582
if e != nil {
@@ -522,7 +587,7 @@ func ArrayEach(data []byte, cb func(value []byte, dataType ValueType, offset int
522
587
523
588
skipToToken := nextToken (data [offset :])
524
589
if skipToToken == - 1 {
525
- return MalformedArrayError
590
+ return offset , MalformedArrayError
526
591
}
527
592
offset += skipToToken
528
593
@@ -531,13 +596,13 @@ func ArrayEach(data []byte, cb func(value []byte, dataType ValueType, offset int
531
596
}
532
597
533
598
if data [offset ] != ',' {
534
- return MalformedArrayError
599
+ return offset , MalformedArrayError
535
600
}
536
601
537
602
offset ++
538
603
}
539
604
540
- return nil
605
+ return offset , nil
541
606
}
542
607
543
608
// ObjectEach iterates over the key-value pairs of a JSON object, invoking a given callback for each such entry
0 commit comments