55 "errors"
66 "fmt"
77 "math"
8+ "strconv"
89)
910
1011// Errors
@@ -116,6 +117,10 @@ func searchKeys(data []byte, keys ...string) int {
116117 ln := len (data )
117118 lk := len (keys )
118119
120+ if lk == 0 {
121+ return 0
122+ }
123+
119124 var stackbuf [unescapeStackBufSize ]byte // stack-allocated array for allocation-free unescaping of small strings
120125
121126 for i < ln {
@@ -168,11 +173,34 @@ func searchKeys(data []byte, keys ...string) int {
168173 case '}' :
169174 level --
170175 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+ }
174197 } 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+ }
176204 }
177205 }
178206
@@ -191,15 +219,12 @@ func init() {
191219}
192220
193221func 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 )
196225 }
197226
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 ] {
203228 if p2 [pi_1 ] != p_1 {
204229 return false
205230 }
@@ -209,11 +234,19 @@ func sameTree(p1, p2 []string) bool {
209234}
210235
211236func EachKey (data []byte , cb func (int , []byte , ValueType , error ), paths ... []string ) int {
212- var pathFlags , ignorePathFlags int64
237+ var pathFlags int64
213238 var level , pathsMatched , i int
214239 ln := len (data )
215240
241+ var maxPath int
242+ for _ , p := range paths {
243+ if len (p ) > maxPath {
244+ maxPath = len (p )
245+ }
246+ }
247+
216248 var stackbuf [unescapeStackBufSize ]byte // stack-allocated array for allocation-free unescaping of small strings
249+ pathsBuf := make ([]string , maxPath )
217250
218251 for i < ln {
219252 switch data [i ] {
@@ -252,58 +285,41 @@ func EachKey(data []byte, cb func(int, []byte, ValueType, error), paths ...[]str
252285 keyUnesc = ku
253286 }
254287
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+ }
259295
260- if equalStr (& keyUnesc , p [level - 1 ]) {
261296 match = pi
262297
263- if len (p ) == level {
264- i ++
265- pathsMatched ++
266- pathFlags |= bitwiseFlags [pi ]
298+ i ++
299+ pathsMatched ++
300+ pathFlags |= bitwiseFlags [pi + 1 ]
267301
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 )
270304
271- if of != - 1 {
272- i += of
273- }
305+ if of != - 1 {
306+ i += of
307+ }
274308
275- if pathsMatched == len (paths ) {
276- return i
277- }
309+ if pathsMatched == len (paths ) {
310+ return i
278311 }
279312 }
280313 }
281314
282315 if match == - 1 {
283- ignorePathFlags = 0
284316 tokenOffset := nextToken (data [i + 1 :])
285317 i += tokenOffset
286318
287319 if data [i ] == '{' {
288320 blockSkip := blockEnd (data [i :], '{' , '}' )
289321 i += blockSkip + 1
290322 }
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- }
307323 }
308324
309325 switch data [i ] {
@@ -318,12 +334,61 @@ func EachKey(data []byte, cb func(int, []byte, ValueType, error), paths ...[]str
318334 case '}' :
319335 level --
320336 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
324382 } 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+ }
326389 }
390+ case ']' :
391+ level --
327392 }
328393
329394 i ++
@@ -476,28 +541,28 @@ func Get(data []byte, keys ...string) (value []byte, dataType ValueType, offset
476541}
477542
478543// 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 ) {
480545 if len (data ) == 0 {
481- return MalformedObjectError
546+ return - 1 , MalformedObjectError
482547 }
483548
484- offset : = 1
549+ offset = 1
485550
486551 if len (keys ) > 0 {
487552 if offset = searchKeys (data , keys ... ); offset == - 1 {
488- return KeyPathNotFoundError
553+ return offset , KeyPathNotFoundError
489554 }
490555
491556 // Go to closest value
492557 nO := nextToken (data [offset :])
493558 if nO == - 1 {
494- return MalformedJsonError
559+ return offset , MalformedJsonError
495560 }
496561
497562 offset += nO
498563
499564 if data [offset ] != '[' {
500- return MalformedArrayError
565+ return offset , MalformedArrayError
501566 }
502567
503568 offset ++
@@ -511,7 +576,7 @@ func ArrayEach(data []byte, cb func(value []byte, dataType ValueType, offset int
511576 }
512577
513578 if t != NotExist {
514- cb (v , t , o , e )
579+ cb (v , t , offset + o - len ( v ) , e )
515580 }
516581
517582 if e != nil {
@@ -522,7 +587,7 @@ func ArrayEach(data []byte, cb func(value []byte, dataType ValueType, offset int
522587
523588 skipToToken := nextToken (data [offset :])
524589 if skipToToken == - 1 {
525- return MalformedArrayError
590+ return offset , MalformedArrayError
526591 }
527592 offset += skipToToken
528593
@@ -531,13 +596,13 @@ func ArrayEach(data []byte, cb func(value []byte, dataType ValueType, offset int
531596 }
532597
533598 if data [offset ] != ',' {
534- return MalformedArrayError
599+ return offset , MalformedArrayError
535600 }
536601
537602 offset ++
538603 }
539604
540- return nil
605+ return offset , nil
541606}
542607
543608// ObjectEach iterates over the key-value pairs of a JSON object, invoking a given callback for each such entry
0 commit comments