-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathJSON.cls
More file actions
3091 lines (2546 loc) · 95.5 KB
/
Copy pathJSON.cls
File metadata and controls
3091 lines (2546 loc) · 95.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
VERSION 1.0 CLASS
BEGIN
MultiUse = -1 'True
END
Attribute VB_Name = "JSON"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = False
'/**
' * JSON - JSON Reader and Writer
' * @description A high-performance zero-copy JSON reader and lightweight JSON writer for VBA (x86/x64 compatible).
' * Uses compact token trees, crash-safe character buffers, native InStr quote scanning, lazy node wrappers,
' * typed accessors, Exists/ExistsKey/ExistsIndex/Keys helpers, raw field access, token iteration for huge arrays, and Stringify support for parsed JSON,
' * primitive VBA values, arrays, Collections, Dictionaries, and nested JSON nodes.
' * Designed for fast parsing and traversal without Dictionary, Collection, or per-node object allocation during parse.
' * @author UesleiDev
' * @version 1.0.4
' */
Option Explicit
#If VBA7 Then
'/** @description Fast memory block copy used to attach and clear SAFEARRAY descriptors. */
Private Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByRef Destination As Any, ByRef Source As Any, ByVal length As LongPtr)
'/** @description Returns the internal address of a dynamic array descriptor. */
Private Declare PtrSafe Function VarPtrArray Lib "vbe7" Alias "VarPtr" (ByRef Var() As Any) As LongPtr
'/** @description Performs ordinal UTF-16 string comparison without allocating key substrings. */
Private Declare PtrSafe Function CompareStringOrdinal Lib "kernel32" (ByVal lpString1 As LongPtr, ByVal cchCount1 As Long, ByVal lpString2 As LongPtr, ByVal cchCount2 As Long, ByVal bIgnoreCase As Long) As Long
'/** @description Native pointer size used when copying SAFEARRAY descriptor pointers. */
Private Const PTR_SIZE As LongPtr = 8
#Else
'/** @description Fast memory block copy used to attach and clear SAFEARRAY descriptors. */
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByRef Destination As Any, ByRef Source As Any, ByVal Length As Long)
'/** @description Returns the internal address of a dynamic array descriptor. */
Private Declare Function VarPtrArray Lib "msvbvm60" Alias "VarPtr" (ByRef Var() As Any) As Long
'/** @description Performs ordinal UTF-16 string comparison without allocating key substrings. */
Private Declare Function CompareStringOrdinal Lib "kernel32" (ByVal lpString1 As Long, ByVal cchCount1 As Long, ByVal lpString2 As Long, ByVal cchCount2 As Long, ByVal bIgnoreCase As Long) As Long
'/** @description Native pointer size used when copying SAFEARRAY descriptor pointers. */
Private Const PTR_SIZE As Long = 4
#End If
'/** @description Default minimum token capacity used for parsed documents. */
Private Const JSON_MIN_TOKEN_CAPACITY As Long = 65536
'/** @description Maximum initial token capacity guessed from text length before growth begins. */
Private Const JSON_MAX_INITIAL_TOKEN_CAPACITY As Long = 3000000
'/** @description Token capacity threshold after which growth changes from 2x to 1.5x. */
Private Const JSON_LARGE_TOKEN_CAPACITY As Long = 1048576
'/** @description Number of spaces used by default when pretty-printing JSON. */
Private Const JSON_DEFAULT_INDENT_SIZE As Long = 2
'/** @description Minimum initial character capacity used by the JSON string writer. */
Private Const JSON_WRITER_MIN_CAPACITY As Long = 4096
'/** @description Initial writer capacity used when serializing external VBA values. */
Private Const JSON_VALUE_WRITER_CAPACITY As Long = 65536
'/** @description Minimum object width that justifies a lazy key index. */
Private Const JSON_KEY_INDEX_MIN_CHILDREN As Long = 32
'/**
' * @struct SAFEARRAY1D
' * @brief Minimal one-dimensional SAFEARRAY descriptor used to alias a VBA String as Integer().
' */
Private Type SAFEARRAY1D
cDims As Integer
fFeatures As Integer
cbElements As Long
cLocks As Long
#If VBA7 Then
pvData As LongPtr
#Else
pvData As Long
#End If
cElements As Long
lLbound As Long
End Type
'/**
' * @enum JSType
' * @brief Internal JSON token type identifiers.
' */
Private Enum JSType
jsNone = 0
jsObject = 1
jsArray = 2
jsString = 3
jsNumber = 4
jsBool = 5
jsNull = 6
End Enum
'/**
' * @struct JSToken
' * @brief Compact parsed JSON token storing hierarchy links and key/value slices.
' */
Private Type JSToken
Type As Integer
Parent As Long
NextSibling As Long
FirstChild As Long
LastChild As Long
ChildCount As Long
KeyStart As Long
KeyLen As Long
ValStart As Long
ValLen As Long
KeyIndexBuilt As Boolean
KeyLookupCount As Integer
ChildIndexStart As Long
IndexLookupCount As Integer
End Type
Private m_Chars() As Integer
Private m_Text As String
Private m_Length As Long
Private m_Index As Long
Private m_Tokens() As JSToken
Private m_TokenCount As Long
Private m_TokenCap As Long
Private m_KeyIndex As Object
Private m_ChildIndexTokens() As Long
Private m_ChildIndexCount As Long
Private m_ChildIndexCap As Long
Private m_RootId As Long
Private m_NodeId As Long
Private m_Document As JSON
Private m_CharAliasActive As Boolean
Private m_DecodedValueCache As Object
'/**
' * @method Class_Terminate
' * @brief Releases the active SAFEARRAY alias before the object is destroyed.
' */
Private Sub Class_Terminate()
ClearCharAlias
Set m_KeyIndex = Nothing
Set m_DecodedValueCache = Nothing
End Sub
'/**
' * @method Parse
' * @brief Parses JSON text into a tokenized JSON document.
' * @param Text Source JSON string.
' * @return Parsed JSON document.
' */
Public Function Parse(ByRef Text As String) As JSON
Dim doc As JSON
Set doc = New JSON
doc.LoadText Text
Set Parse = doc
End Function
'/**
' * @method Stringify
' * @brief Serializes the current JSON document or node to JSON text.
' * @param Pretty Enables formatted output with line breaks and indentation.
' * @param IndentSize Number of spaces per indentation level.
' * @return JSON text.
' */
Public Function Stringify(Optional ByVal Pretty As Boolean = False, Optional ByVal IndentSize As Long = JSON_DEFAULT_INDENT_SIZE) As String
Stringify = StringifyCurrent(Pretty, Space$(IndentSize))
End Function
'/**
' * @method StringifyWithIndent
' * @brief Serializes the current JSON document or node using a custom indentation string.
' * @param Pretty Enables formatted output with line breaks and indentation.
' * @param IndentText Text used for each indentation level, such as spaces or vbTab.
' * @return JSON text.
' */
Public Function StringifyWithIndent(Optional ByVal Pretty As Boolean = False, Optional ByVal IndentText As String = " ") As String
StringifyWithIndent = StringifyCurrent(Pretty, IndentText)
End Function
'/**
' * @method StringifyValue
' * @brief Serializes an external VBA value to JSON text.
' * @param Value VBA value, array, Collection, Dictionary, or JSON node.
' * @param Pretty Enables formatted output with line breaks and indentation.
' * @param IndentSize Number of spaces per indentation level.
' * @return JSON text.
' */
Public Function StringifyValue(ByVal Value As Variant, Optional ByVal Pretty As Boolean = False, Optional ByVal IndentSize As Long = JSON_DEFAULT_INDENT_SIZE) As String
StringifyValue = StringifyAny(Value, Pretty, Space$(IndentSize), 0)
End Function
'/**
' * @method StringifyValueWithIndent
' * @brief Serializes an external VBA value using a custom indentation string.
' * @param Value VBA value, array, Collection, Dictionary, or JSON node.
' * @param Pretty Enables formatted output with line breaks and indentation.
' * @param IndentText Text used for each indentation level, such as spaces or vbTab.
' * @return JSON text.
' */
Public Function StringifyValueWithIndent(ByVal Value As Variant, Optional ByVal Pretty As Boolean = False, Optional ByVal IndentText As String = " ") As String
StringifyValueWithIndent = StringifyAny(Value, Pretty, IndentText, 0)
End Function
'/**
' * @method LoadText
' * @brief Initializes this instance as a root JSON document.
' * @param Text Source JSON string.
' */
Friend Sub LoadText(ByRef Text As String)
ClearCharAlias
m_Text = Text
m_Length = Len(m_Text)
m_Index = 0
m_RootId = 0
m_NodeId = 0
Set m_Document = Nothing
Set m_KeyIndex = Nothing
Set m_DecodedValueCache = Nothing
Erase m_Chars
Erase m_Tokens
Erase m_ChildIndexTokens
m_ChildIndexCount = 0
m_ChildIndexCap = 0
If m_Length = 0 Then Exit Sub
m_TokenCap = m_Length \ 24
If m_TokenCap < JSON_MIN_TOKEN_CAPACITY Then
m_TokenCap = JSON_MIN_TOKEN_CAPACITY
End If
If m_TokenCap > JSON_MAX_INITIAL_TOKEN_CAPACITY Then
m_TokenCap = JSON_MAX_INITIAL_TOKEN_CAPACITY
End If
m_TokenCount = 0
ReDim m_Tokens(1 To m_TokenCap)
ReDim m_Chars(0 To m_Length - 1)
#If VBA7 Then
CopyMemory m_Chars(0), ByVal StrPtr(m_Text), CLngPtr(m_Length) * 2
#Else
CopyMemory m_Chars(0), ByVal StrPtr(m_Text), m_Length * 2&
#End If
m_CharAliasActive = False
m_RootId = ParseValue(0, 0, 0)
End Sub
'/**
' * @method InitNode
' * @brief Initializes this instance as a lightweight wrapper around a token from another document.
' * @param TokenId Token to wrap.
' * @param Document Root document that owns the token buffer.
' */
Friend Sub InitNode(ByVal TokenId As Long, ByVal Document As JSON)
m_NodeId = TokenId
Set m_Document = Document
End Sub
'/**
' * @property Item
' * @brief Gets a child value by object key or array index.
' * @param Key Object key as String or array index as Long.
' * @return Primitive Variant or JSON node wrapper.
' */
Public Property Get Item(ByVal key As Variant) As Variant
Attribute Item.VB_UserMemId = 0
Dim doc As JSON
Dim baseId As Long
Dim id As Long
ResolveBase doc, baseId
If baseId = 0 Then Exit Property
id = doc.ResolveToken(baseId, key)
If id = 0 Then Exit Property
If doc.TokenTypeOf(id) = jsObject Or doc.TokenTypeOf(id) = jsArray Then
Dim node As JSON
Set node = New JSON
node.InitNode id, doc
Set Item = node
Else
Item = doc.PrimitiveValue(id)
End If
End Property
'/**
' * @property Value
' * @brief Gets the current node value. Objects and arrays return the node itself.
' * @return Primitive Variant or current JSON node.
' */
Public Property Get Value() As Variant
Dim doc As JSON
Dim baseId As Long
ResolveBase doc, baseId
If baseId = 0 Then Exit Property
If doc.TokenTypeOf(baseId) = jsObject Or doc.TokenTypeOf(baseId) = jsArray Then
Set Value = Me
Else
Value = doc.PrimitiveValue(baseId)
End If
End Property
'/**
' * @property Count
' * @brief Gets the amount of direct children in the current object or array.
' * @return Direct child count.
' */
Public Property Get Count() As Long
Dim doc As JSON
Dim baseId As Long
ResolveBase doc, baseId
If baseId = 0 Then Exit Property
Count = doc.TokenChildCountOf(baseId)
End Property
'/**
' * @property JsonType
' * @brief Gets the JSON type name of the current node.
' * @return object, array, string, number, boolean, null, or empty string.
' */
Public Property Get JsonType() As String
Dim doc As JSON
Dim baseId As Long
ResolveBase doc, baseId
If baseId = 0 Then Exit Property
Select Case doc.TokenTypeOf(baseId)
Case jsObject
JsonType = "object"
Case jsArray
JsonType = "array"
Case jsString
JsonType = "string"
Case jsNumber
JsonType = "number"
Case jsBool
JsonType = "boolean"
Case jsNull
JsonType = "null"
End Select
End Property
'/**
' * @property IsObject
' * @brief Returns True when the current node is a JSON object.
' * @return Boolean state.
' */
Public Property Get IsObject() As Boolean
Dim doc As JSON
Dim baseId As Long
ResolveBase doc, baseId
If baseId = 0 Then Exit Property
IsObject = (doc.TokenTypeOf(baseId) = jsObject)
End Property
'/**
' * @property IsArray
' * @brief Returns True when the current node is a JSON array.
' * @return Boolean state.
' */
Public Property Get IsArray() As Boolean
Dim doc As JSON
Dim baseId As Long
ResolveBase doc, baseId
If baseId = 0 Then Exit Property
IsArray = (doc.TokenTypeOf(baseId) = jsArray)
End Property
'/**
' * @property IsNull
' * @brief Returns True when the current node is JSON null.
' * @return Boolean state.
' */
Public Property Get IsNull() As Boolean
Dim doc As JSON
Dim baseId As Long
ResolveBase doc, baseId
If baseId = 0 Then Exit Property
IsNull = (doc.TokenTypeOf(baseId) = jsNull)
End Property
'/**
' * @method Exists
' * @brief Returns True when an object key or array index exists.
' * @param Key Object key as String or array index as Long.
' * @return Boolean state.
' */
Public Function Exists(ByVal key As Variant) As Boolean
Dim doc As JSON
Dim baseId As Long
ResolveBase doc, baseId
If baseId = 0 Then Exit Function
Exists = (doc.ResolveToken(baseId, key) <> 0)
End Function
'/**
' * @method ExistsKey
' * @brief Returns True when an object key exists without using a Variant key parameter.
' * @param Key Object key.
' * @return Boolean state.
' */
Public Function ExistsKey(ByVal key As String) As Boolean
Dim doc As JSON
Dim baseId As Long
ResolveBase doc, baseId
If baseId = 0 Then Exit Function
If doc.TokenTypeOf(baseId) <> jsObject Then Exit Function
ExistsKey = (doc.FindChildFast(baseId, key) <> 0)
End Function
'/**
' * @method ExistsIndex
' * @brief Returns True when an array/object child index exists without using a Variant key parameter.
' * @param Index Zero-based child index.
' * @return Boolean state.
' */
Public Function ExistsIndex(ByVal Index As Long) As Boolean
Dim doc As JSON
Dim baseId As Long
ResolveBase doc, baseId
If baseId = 0 Then Exit Function
If Index < 0 Then Exit Function
ExistsIndex = (Index < doc.TokenChildCountOf(baseId))
End Function
'/**
' * @method Keys
' * @brief Gets all direct object keys or array indexes as a zero-based Variant array.
' * @return String array for objects, Long array for arrays, or an empty Variant array.
' */
Public Function keys() As Variant
Dim doc As JSON
Dim baseId As Long
Dim child As Long
Dim i As Long
Dim total As Long
ResolveBase doc, baseId
If baseId = 0 Then
keys = Array()
Exit Function
End If
total = doc.TokenChildCountOf(baseId)
If total <= 0 Then
keys = Array()
Exit Function
End If
If doc.TokenTypeOf(baseId) = jsObject Then
Dim objectKeys() As String
ReDim objectKeys(0 To total - 1)
child = doc.TokenFirstChildOf(baseId)
Do While child > 0
objectKeys(i) = doc.GetRawKey(child)
i = i + 1
child = doc.TokenNextSiblingOf(child)
Loop
keys = objectKeys
ElseIf doc.TokenTypeOf(baseId) = jsArray Then
Dim arrayKeys() As Long
ReDim arrayKeys(0 To total - 1)
For i = 0 To total - 1
arrayKeys(i) = i
Next i
keys = arrayKeys
Else
keys = Array()
End If
End Function
'/**
' * @method Node
' * @brief Gets a child object or array by key/index without returning through Variant.
' * @param Key Object key as String or array index as Long.
' * @return JSON node wrapper.
' */
Public Function node(ByVal key As Variant) As JSON
Dim doc As JSON
Dim baseId As Long
Dim id As Long
ResolveBase doc, baseId
If baseId = 0 Then Exit Function
id = doc.ResolveToken(baseId, key)
If id = 0 Then Exit Function
If doc.TokenTypeOf(id) = jsObject Or doc.TokenTypeOf(id) = jsArray Then
Dim nodeObj As JSON
Set nodeObj = New JSON
nodeObj.InitNode id, doc
Set node = nodeObj
End If
End Function
'/**
' * @method NodeKey
' * @brief Gets an object child node by key without using Variant dispatch.
' * @param Key Object key.
' * @return JSON node wrapper.
' */
Public Function NodeKey(ByVal key As String) As JSON
Dim doc As JSON
Dim baseId As Long
Dim id As Long
ResolveBase doc, baseId
If baseId = 0 Then Exit Function
If doc.TokenTypeOf(baseId) <> jsObject Then Exit Function
id = doc.FindChildFast(baseId, key)
If id = 0 Then Exit Function
If doc.TokenTypeOf(id) = jsObject Or doc.TokenTypeOf(id) = jsArray Then
Dim nodeObj As JSON
Set nodeObj = New JSON
nodeObj.InitNode id, doc
Set NodeKey = nodeObj
End If
End Function
'/**
' * @method NodeIndex
' * @brief Gets an array/object child node by zero-based index without using Variant dispatch.
' * @param Index Zero-based child index.
' * @return JSON node wrapper.
' */
Public Function NodeIndex(ByVal Index As Long) As JSON
Set NodeIndex = NodeAt(Index)
End Function
'/**
' * @method NodeAt
' * @brief Gets an array/object child node by zero-based child index.
' * @param Index Zero-based child index.
' * @return JSON node wrapper.
' */
Public Function NodeAt(ByVal Index As Long) As JSON
Dim doc As JSON
Dim baseId As Long
Dim id As Long
ResolveBase doc, baseId
If baseId = 0 Then Exit Function
id = doc.FindIndexChild(baseId, Index)
If id = 0 Then Exit Function
If doc.TokenTypeOf(id) = jsObject Or doc.TokenTypeOf(id) = jsArray Then
Dim nodeObj As JSON
Set nodeObj = New JSON
nodeObj.InitNode id, doc
Set NodeAt = nodeObj
End If
End Function
'/**
' * @method ValueAt
' * @brief Gets any child value by zero-based child index.
' * @param Index Zero-based child index.
' * @return Primitive Variant or JSON node wrapper.
' */
Public Function ValueAt(ByVal Index As Long) As Variant
Dim doc As JSON
Dim baseId As Long
Dim id As Long
ResolveBase doc, baseId
If baseId = 0 Then Exit Function
id = doc.FindIndexChild(baseId, Index)
If id = 0 Then Exit Function
If doc.TokenTypeOf(id) = jsObject Or doc.TokenTypeOf(id) = jsArray Then
Dim node As JSON
Set node = New JSON
node.InitNode id, doc
Set ValueAt = node
Else
ValueAt = doc.PrimitiveValue(id)
End If
End Function
'/**
' * @method KeyAt
' * @brief Gets the key of an object child by zero-based child index.
' * @param Index Zero-based child index.
' * @return Object key text.
' */
Public Function KeyAt(ByVal Index As Long) As String
Dim doc As JSON
Dim baseId As Long
Dim id As Long
ResolveBase doc, baseId
If baseId = 0 Then Exit Function
id = doc.FindIndexChild(baseId, Index)
If id = 0 Then Exit Function
KeyAt = doc.GetRawKey(id)
End Function
'/**
' * @method StringValue
' * @brief Gets a child value as String by key/index, applying basic JSON unescape.
' * @param Key Object key as String or array index as Long.
' * @return String value.
' */
Public Function StringValue(ByVal key As Variant) As String
Dim doc As JSON
Dim baseId As Long
Dim id As Long
ResolveBase doc, baseId
If baseId = 0 Then Exit Function
id = doc.ResolveToken(baseId, key)
If id = 0 Then Exit Function
StringValue = doc.ValueAsString(id)
End Function
'/**
' * @method NumberValue
' * @brief Gets a child value as Double by key/index.
' * @param Key Object key as String or array index as Long.
' * @return Double value.
' */
Public Function NumberValue(ByVal key As Variant) As Double
Dim doc As JSON
Dim baseId As Long
Dim id As Long
ResolveBase doc, baseId
If baseId = 0 Then Exit Function
id = doc.ResolveToken(baseId, key)
If id = 0 Then Exit Function
NumberValue = doc.ValueAsDouble(id)
End Function
'/**
' * @method BoolValue
' * @brief Gets a child value as Boolean by key/index.
' * @param Key Object key as String or array index as Long.
' * @return Boolean value.
' */
Public Function BoolValue(ByVal key As Variant) As Boolean
Dim doc As JSON
Dim baseId As Long
Dim id As Long
ResolveBase doc, baseId
If baseId = 0 Then Exit Function
id = doc.ResolveToken(baseId, key)
If id = 0 Then Exit Function
BoolValue = doc.ValueAsBool(id)
End Function
'/**
' * @method RawStringValue
' * @brief Gets a child value as raw String by key/index without unescaping.
' * @param Key Object key as String or array index as Long.
' * @return Raw string slice.
' */
Public Function RawStringValue(ByVal key As Variant) As String
Dim doc As JSON
Dim baseId As Long
Dim id As Long
ResolveBase doc, baseId
If baseId = 0 Then Exit Function
id = doc.ResolveToken(baseId, key)
If id = 0 Then Exit Function
RawStringValue = doc.GetRawSlice(id)
End Function
'/**
' * @method StringKey
' * @brief Gets a string field by object key without using Variant dispatch.
' * @param Key Object key.
' * @return String value.
' */
Public Function StringKey(ByVal key As String) As String
Dim doc As JSON
Dim baseId As Long
Dim id As Long
ResolveBase doc, baseId
If baseId = 0 Then Exit Function
If doc.TokenTypeOf(baseId) <> jsObject Then Exit Function
id = doc.FindChildFast(baseId, key)
If id = 0 Then Exit Function
StringKey = doc.ValueAsString(id)
End Function
'/**
' * @method NumberKey
' * @brief Gets a numeric field by object key without using Variant dispatch.
' * @param Key Object key.
' * @return Double value.
' */
Public Function NumberKey(ByVal key As String) As Double
Dim doc As JSON
Dim baseId As Long
Dim id As Long
ResolveBase doc, baseId
If baseId = 0 Then Exit Function
If doc.TokenTypeOf(baseId) <> jsObject Then Exit Function
id = doc.FindChildFast(baseId, key)
If id = 0 Then Exit Function
NumberKey = doc.ValueAsDouble(id)
End Function
'/**
' * @method BoolKey
' * @brief Gets a Boolean field by object key without using Variant dispatch.
' * @param Key Object key.
' * @return Boolean value.
' */
Public Function BoolKey(ByVal key As String) As Boolean
Dim doc As JSON
Dim baseId As Long
Dim id As Long
ResolveBase doc, baseId
If baseId = 0 Then Exit Function
If doc.TokenTypeOf(baseId) <> jsObject Then Exit Function
id = doc.FindChildFast(baseId, key)
If id = 0 Then Exit Function
BoolKey = doc.ValueAsBool(id)
End Function
'/**
' * @method RawStringKey
' * @brief Gets a raw JSON field by object key without using Variant dispatch.
' * @param Key Object key.
' * @return Raw JSON slice.
' */
Public Function RawStringKey(ByVal key As String) As String
Dim doc As JSON
Dim baseId As Long
Dim id As Long
ResolveBase doc, baseId
If baseId = 0 Then Exit Function
If doc.TokenTypeOf(baseId) <> jsObject Then Exit Function
id = doc.FindChildFast(baseId, key)
If id = 0 Then Exit Function
RawStringKey = doc.GetRawSlice(id)
End Function
'/**
' * @method StringAt
' * @brief Gets an indexed child value as String, applying basic JSON unescape.
' * @param Index Zero-based child index.
' * @return String value.
' */
Public Function StringAt(ByVal Index As Long) As String
Dim doc As JSON
Dim baseId As Long
Dim id As Long
ResolveBase doc, baseId
If baseId = 0 Then Exit Function
id = doc.FindIndexChild(baseId, Index)
If id = 0 Then Exit Function
StringAt = doc.ValueAsString(id)
End Function
'/**
' * @method NumberAt
' * @brief Gets an indexed child value as Double.
' * @param Index Zero-based child index.
' * @return Double value.
' */
Public Function NumberAt(ByVal Index As Long) As Double
Dim doc As JSON
Dim baseId As Long
Dim id As Long
ResolveBase doc, baseId
If baseId = 0 Then Exit Function
id = doc.FindIndexChild(baseId, Index)
If id = 0 Then Exit Function
NumberAt = doc.ValueAsDouble(id)
End Function
'/**
' * @method BoolAt
' * @brief Gets an indexed child value as Boolean.
' * @param Index Zero-based child index.
' * @return Boolean value.
' */
Public Function BoolAt(ByVal Index As Long) As Boolean
Dim doc As JSON
Dim baseId As Long
Dim id As Long
ResolveBase doc, baseId
If baseId = 0 Then Exit Function
id = doc.FindIndexChild(baseId, Index)
If id = 0 Then Exit Function
BoolAt = doc.ValueAsBool(id)
End Function
'/**
' * @method RawStringAt
' * @brief Gets an indexed child value as raw String without unescaping.
' * @param Index Zero-based child index.
' * @return Raw string slice.
' */
Public Function RawStringAt(ByVal Index As Long) As String
Dim doc As JSON
Dim baseId As Long
Dim id As Long
ResolveBase doc, baseId
If baseId = 0 Then Exit Function
id = doc.FindIndexChild(baseId, Index)
If id = 0 Then Exit Function
RawStringAt = doc.GetRawSlice(id)
End Function
'/**
' * @method FirstChildToken
' * @brief Gets the first direct child token of the current node.
' * @return First child token id.
' */
Public Function FirstChildToken() As Long
Dim doc As JSON
Dim baseId As Long
ResolveBase doc, baseId
If baseId = 0 Then Exit Function
FirstChildToken = doc.TokenFirstChildOf(baseId)
End Function
'/**
' * @method LastChildToken
' * @brief Gets the last direct child token of the current node.
' * @return Last child token id.
' */
Public Function LastChildToken() As Long
Dim doc As JSON
Dim baseId As Long
ResolveBase doc, baseId
If baseId = 0 Then Exit Function
LastChildToken = doc.TokenLastChildOf(baseId)
End Function
'/**
' * @method NextToken
' * @brief Gets the next sibling token for a token.
' * @param TokenId Current token id.
' * @return Next sibling token id.
' */
Public Function NextToken(ByVal TokenId As Long) As Long
Dim doc As JSON
Dim baseId As Long
ResolveBase doc, baseId
If baseId = 0 Then Exit Function
If TokenId < 1 Or TokenId > doc.TokenCount Then Exit Function
NextToken = doc.TokenNextSiblingOf(TokenId)
End Function
'/**
' * @method NodeFromToken
' * @brief Wraps a token as a JSON node when the token is an object or array.
' * @param TokenId Token id.
' * @return JSON node wrapper.
' */
Public Function NodeFromToken(ByVal TokenId As Long) As JSON
Dim doc As JSON
Dim baseId As Long
ResolveBase doc, baseId
If baseId = 0 Then Exit Function
If TokenId < 1 Or TokenId > doc.TokenCount Then Exit Function
If doc.TokenTypeOf(TokenId) = jsObject Or doc.TokenTypeOf(TokenId) = jsArray Then
Dim node As JSON
Set node = New JSON
node.InitNode TokenId, doc
Set NodeFromToken = node
End If
End Function
'/**
' * @method TokenKey
' * @brief Gets the object key associated with a token.
' * @param TokenId Token id.
' * @return Token key text.
' */
Public Function TokenKey(ByVal TokenId As Long) As String
Dim doc As JSON
Dim baseId As Long
ResolveBase doc, baseId
If baseId = 0 Then Exit Function
If TokenId < 1 Or TokenId > doc.TokenCount Then Exit Function