# VBForums CodeBank > CodeBank - Visual Basic 6 and earlier >  VB6 - JsonBag, Another JSON Parser/Generator

## dilettante

With SOAP basically a dead duck and XML itself fading in importance, JSON is becoming more and more important as a serialization format today.

I've seen a number of VB6 JSON implementations around, including a couple posted right here in the CodeBank.  Sadly none of them are very good, with little quirks and latent bugs (like improperly handling numeric data).  Most of these ignore and flout the JSON standards at JSON too!

In any case I have my own implementation designed to conform as closely as possible to the standard, and now at version 1.6 it seems mature enough to share.  I rewrote my notes into six pages of documentation which should make it a bit easier for others to use.


Bug reports are welcome.  Though it seems to be working fine it is hard to prove code to be correct and there are probably edge cases I've never encountered.

Performance seems more than adequate for its purpose, which is mainly access to cloud computing services.  Local config files are probably best still handled as plain old INI format files, though one could use JSON for that as well I suppose.


There is just one Class involved: JsonBag.cls, and as the documentation suggests it should be easy enough to import into a VBA host (Excel, etc.) as long as you tweak the API calls for 64-bit hosts when required.


The attachment includes this Class along with the documentation in RTF format, packaged up as a testbed Project JsonBagTest.vbp:


As you can see JsonBag supports a Whitespace property to format JSON for readability.  By default compact JSON is generated.


Accessing the "document model" and creating JSON documents in code is easy enough.  This is illustrated by a fragment from the test Project:



```
Private Sub cmdGenSerialize_Click()
    With JB
        .Clear
        .IsArray = False 'Actually the default after Clear.

        ![First] = 1
        ![Second] = Null
        With .AddNewArray("Third")
            .Item = "These"
            .Item = "Add"
            .Item = "One"
            .Item = "After"
            .Item = "The"
            .Item = "Next"
            .Item(1) = "*These*" 'Should overwrite 1st Item, without moving it.

            'Add a JSON "object" to this "array" (thus no name supplied):
            With .AddNewObject()
                .Item("A") = True
                !B = False
                !C = 3.14E+16
            End With
        End With
        With .AddNewObject("Fourth")
            .Item("Force Case") = 1 'Use quoted String form to force case of names.
            .Item("force Case") = 2
            .Item("force case") = 3

            'This syntax can be risky with case-sensitive JSON since the text is
            'treated like any other VB identifier, i.e. if such a symbol ("Force"
            'or "Case" here) is already defined in the language (VB) or in your
            'code the casing of that symbol will be enforced by the IDE:

            ![Force Case] = 666 'Should overwrite matching-case named item, which
                                'also moves it to the end.
            'Safer:
            .Item("Force Case") = 666
        End With
        'Can also use implied (default) property:
        JB("Fifth") = Null

        txtSerialized.Text = .JSON
    End With
End Sub
```


*Newst version here.*

----------


## dilettante

Here is another demo that may be helpful in understanding how to use JsonBag.

It loads and parses a big complicated JSON document and displays it.  Then it traverses and dumps the parsed JSON in the JsonBag object hierarchy.  Finally it displays an item from within the hierarchy using two possible VB syntaxes.

----------


## milena

great, works like a charm. here is an online one http://newexception.com/tools/json-validator

----------


## y2kdeuce

> Here is another demo that may be helpful in understanding how to use JsonBag.
> 
> It loads and parses a big complicated JSON document and displays it.  Then it traverses and dumps the parsed JSON in the JsonBag object hierarchy.  Finally it displays an item from within the hierarchy using two possible VB syntaxes.




This was really fun to watch work until it blew up with an "invalid procedure call or argument - 5" error on this line;
If IsObject(Values.Item(PrefixedKey)) Then

PrefixedKey value was; 6D0D431Eweb-app

----------


## dilettante

> This was really fun to watch work until it blew up with an "invalid procedure call or argument - 5" error on this line;
> If IsObject(Values.Item(PrefixedKey)) Then
> 
> PrefixedKey value was; 6D0D431Eweb-app


It is worth noting that any test done within the IDE should have _Break on Unhandled Errors_ selected, or false stops are inevitable.  This of course doesn't matter in compiled programs.

----------


## coolcurrent4u

Is it possible to parse json string without the recursive example? for example, how do i parse this string in a for/foreach loop



```
{
  "status": "error",
  "request": [
    "sdgsdg",
    "sgdgsdg",
  ],
  "update": [
    {
      "id": "1",
      "val": "rqrq",
    },
    {
      "id": "3",
      "val": "rqwerq",
    }
  ]
}
```

----------


## dilettante

I don't see why not, but that would be an entirely different solution.

----------


## coolcurrent4u

in php for the json string above, i could do



```
$decoded=json_decode($json_string);
$status=$decoded->status
$request=$decoded->request
foreach($request as $value){
echo $value
}
```

can i do the same way with jsonbag?

----------


## dilettante

Ahh.

I misunderstood your question.  You aren't asking about _parsing_ at all.

Scroll down to the blue lines here:



```
Option Explicit

Private Sub Echo(ByVal Value As Variant)
    With Text1
        .SelStart = &H7FFF
        If IsNull(Value) Then
            .SelText = "#NULL"
        ElseIf IsEmpty(Value) Then
            .SelText = "#EMPTY"
        ElseIf VarType(Value) = vbObject Then
            If TypeOf Value Is JsonBag Then
                If Value.IsArray Then
                    .SelText = "#JSON array"
                Else
                    .SelText = "#JSON list"
                End If
            Else
                .SelText = "#instance of " & TypeName(Value)
            End If
        Else
            .SelText = CStr(Value)
        End If
        .SelText = vbNewLine
    End With
End Sub

Private Sub Form_Load()
    Dim F As Integer
    Dim JSON As String
    Dim JB As JsonBag
    Dim I As Long
    Dim Value As Variant

    F = FreeFile(0)
    Open "json.txt" For Input As #F
    JSON = Input$(LOF(F), #F)
    Close #F

    Set JB = New JsonBag
    JB.JSON = JSON
    Echo JB.Item("status")
    'Must enumerate JSON arrays by index, not with For...Each:
    With JB.Item("request")
        For I = 1 To .Count
            Echo .Item(I)
        Next
    End With
End Sub
```

You can use For...Each with lists however.

----------


## coolcurrent4u

thank you, you are the man

I tried to check if an item exists in the above json string



```
JB.Exists("status")
```

but it return false

----------


## coolcurrent4u

You used collections in the jsonbag, i suggest dictionary as they are 10x faster than collections

----------


## dilettante

> thank you, you are the man
> 
> I tried to check if an item exists in the above json string
> 
> 
> 
> ```
> JB.Exists("status")
> ```
> ...


Thanks, you're right.  There was a bug in one line.  New version attached here.

----------


## dilettante

> You used collections in the jsonbag, i suggest dictionary as they are 10x faster than collections


Feel free to do so if you wish.

I considered Scripting.Dictionary and discarded the idea.  They can actually be _much slower_ than Collections for enumeration, and you have a large library loaded that you normally don't need.  Normally you don't do much local batch processing of JSON documents, so performance is far more limited by network speeds than Collections.

About the only place they were faster for this purpose was doing "exists" checks so if you are doing a huge amount of that Dictionary might be worth considering.  Notice that I never stumbled over the "Exists bug" in JsonBag 1.6 myself?  I hardly ever use it so when I created the bug I never even knew it.

If you have to validate every chunk of JSON ever sent to your code... you're going to have a ton of validation logic in there!  You'll be far better off just using error trapping.

----------


## wqweto

With collections existence check performance suffers greatly when key is not present because the built-in `Err` object has to be populated with error details. I use a typelib declared `IVbCollection` interface that returns `Long` instead of `HRESULT` on `Item` property (actually method) that is 10x times faster on [non-]existence check. A performace optimized `SearchCollection` function with this typelib looks like this:


```
Public Function SearchCollection(ByVal pCol As Object, Index As Variant, Optional RetVal As Variant) As Boolean
    Const DISPID_VALUE  As Long = 0
    Dim pVbCol          As IVbCollection
    
    If pCol Is Nothing Then
        '--- do nothing
    ElseIf TypeOf pCol Is IVbCollection Then
        Set pVbCol = pCol
        SearchCollection = pVbCol.Item(Index, RetVal) = 0
    Else
        SearchCollection = DispInvoke(pCol, DISPID_VALUE, ucsIclPropGet, Result:=RetVal, Args:=Index)
        If Not SearchCollection Then
            '--- some weird collections have default (Item) method
            SearchCollection = DispInvoke(pCol, DISPID_VALUE, ucsIclMethod, Result:=RetVal, Args:=Index)
        End If
    End If
End Function
```

My tests with `Scripting.Dictionary` vs `VB.Collection` for JSON containers resulted in 10x more memory usage with `Dictionaries`. Nevertheless I prefer using `Dictionaries` for JSON containers as I can use `CompareMode` property to distinguish object vs array containers.

cheers,
</wqw>

----------


## Jonney

> Thanks, you're right.  There was a bug in one line.  New version attached here.


In your v1.7, testing code got error:

Debug.Print JB.Item("web-app").Item("servlet")(1).Item("init-param").Item("templateProcessorClass")

----------


## dilettante

Seems to be working fine here.

What does "got error" mean?  What error number?  Error description?

----------


## Jonney

> Seems to be working fine here.
> 
> What does "got error" mean?  What error number?  Error description?


Runtime error '438'
Object doesn't support this property and method.

I paste your v1.7 class to your demo2.

----------


## dilettante

I did that here too, but it runs with no problem.  I even copied your Debug line into the program and it still works.

Can you track down which line of code fails in the class?

----------


## Jonney

> I did that here too, but it runs with no problem.  I even copied your Debug line into the program and it still works.
> 
> Can you track down which line of code fails in the class?




```
Private Sub Form_Load()
    Dim F As Integer
    Dim JsonData As String
    Dim JB As JsonBag
    
    GapHorizontal = lblJson.Left
    GapVertical = lblJson.Top
    
    F = FreeFile(0)
    Open "JsonSample.txt" For Input As #F
    JsonData = Input$(LOF(F), #F)
    Close #F
    txtJson.Text = JsonData

    Set JB = New JsonBag
    JB.JSON = JsonData
    Show
    JbDump "*anonymous outer JsonBag*", JB
    HomeDump
    
    Debug.Print JB.Item("web-app").Item("servlet")(1).Item("init-param").Item("templateProcessorClass")

End Sub
```

I debug into the loop, seems to fail at .Item("servlet")(1).

----------


## jpbro

If you copy and pasted the code, perhaps the procedure attributes did not come across? Therefore, you would not have a default attribute of the JsonBag class (Item), which would cause the error.

The following code should fix the problem, proving the above assertion:

Debug.Print JB.Item("web-app").Item("servlet")*.Item*(1).Item("init-param").Item("templateProcessorClass") 

Instead of copying the code, you should replace the code file directly in its entirety to get all of the procedure attributes that Dilettante has defined.

----------


## Jonney

> If you copy and pasted the code, perhaps the procedure attributes did not come across? Therefore, you would not have a default attribute of the JsonBag class (Item), which would cause the error.
> 
> The following code should fix the problem, proving the above assertion:
> 
> Debug.Print JB.Item("web-app").Item("servlet")*.Item*(1).Item("init-param").Item("templateProcessorClass") 
> 
> Instead of copying the code, you should replace the code file directly in its entirety to get all of the procedure attributes that Dilettante has defined.


You are right. The Item should set "Default" and the NewEnum set -4 in Procedure Attributes.

Now it is OK.

Thanks.

----------


## dilettante

Thanks for tracking the issue down.  I was going around in circles trying to reproduce it!

----------


## Jonney

> Thanks for tracking the issue down.  I was going around in circles trying to reproduce it!


I roughly go through the codes, the parser is very intelligent and a complicated process but the code is very neat. 

Have you made a XML parser so that we can make XLSX or XML by codes. (Somebody told me Excel 2007's xlsx file is actually compressed XML.)

I Rated 5 stars for your excellent coding.

----------


## dilettante

Thanks.

While I do have a class for processing XML it only handles a form of "simplified XML." It is useful for me for a number of purposes where I have full control over the data sent between programs, but probably is not worth making available to others.

The main reason is that Microsoft's MSXML already handles XML very well, is present in any modern version of Windows (and even older ones with IE 5.0 or leter), and is much more complete.  This makes it much safer for general use because it can parse and generate very complete XML.

----------


## jpbro

Cheers, glad to help! I couldn't reproduce the problem for a while here either, then I just happen to notice the word "pasted" in Jonney's comment, and got suspicious...

----------


## dilettante

Update.

I hope this new version didn't create new bugs while trying to fix old things.

Raised exceptions now all use custom error numbers instead of trying to use stabdard VB error numbers.  These new numbers are all in the &H800499xx range.

The .Exists(key) method should now work for noth String "names" and numeric "index" values.

.Exists() is now called within Property Get Item(key) for keys passed as String names.  This may help with a confusing situation where the case-sensitive names will throw you off if you try to use the "bang" syntax (! operator)... the IDE may adjust the case of typed in names on you, leading to trouble.  Before this change calling Item() with a non-existant key name resulted in a very confusing exception being raised, and hopefully now you'll see a less confusing exception instead.

It all sort of comes down to the limitations of VB's Collection class.  I may be tempted to do a 2.0 rewrite at some point using Scripting.Dictionary instead.

The JsonBag.rtf document has also been updated.

----------


## Xpucmo

Hmm... I believe the current version is not compatible with 64-bit VB/Office VBA.  I tried to tweak some of the Long/LongPtr definitions, but I don't understand well how the arithmetic works. Would it be safe to just mass-replace Long with LongLong and add PtrSafe for a 64-bit version only?

----------


## dilettante

> Hmm... I believe the current version is not compatible with 64-bit VB/Office VBA.  I tried to tweak some of the Long/LongPtr definitions, but I don't understand well how the arithmetic works. Would it be safe to just mass-replace Long with LongLong and add PtrSafe for a 64-bit version only?


64-bit VBA will require some modification.  I wouldn't try to blindly replace one data type with another, but such changes will be required strategically in regard to the API calls that deal with pointers.

----------


## Nightwalker83

dilettante, anyway to modify the above code to read a Json that has two delimiters? As in this thread.

----------


## Vostok

I used  JsonBag 1.8. Received data as JSON 


```
{"_comment":"pair_id: 166, interval: 86400, candles: 120",
"candles":[[1404777600000,1963.71,0],[1404864000000,1972.83,0],[1404950400000,1964.6801,0],[1405036800000,1967.5699,0],[1405296000000,1977.1,0],[1405382400000,1973.28,0],[1405468800000,1981.5699,0],[1405555200000,1958.12,0],[1405641600000,1978.22,0],[1405900800000,1973.63,0],[1405987200000,1983.53,0],[1406073600000,1987.01,0],[1406160000000,1987.98,0],[1406246400000,1978.34,0],[1406505600000,1978.91,0],[1406592000000,1969.95,0],[1406678400000,1970.0699,0],[1406764800000,1930.67,0],[1406851200000,1925.15,0]
```

The first figure in brackets ([1404777600000,1963.71,0]) - is the date. How do I get the date in the usual format: 24/12/2014 11:00 ?
thank you.

----------


## dilettante

> The first figure in brackets ([1404777600000,1963.71,0]) - is the date. How do I get the date in the usual format: 24/12/2014 11:00 ?


Well you have to remember that JSON comes from the impoverished world of "web standards" and in particular JavaScript.  JavaScript has no decent native data type for date-time values so people tend to pass almost anything around.

Commonly they'll use Unix Timestamp format, though nice folks will scale (divide) that by 1000 since millisecond precision is (a.) kind of silly and (b.) just means more text to ship over the wire.

See On the nightmare that is JSON Dates and just know you are not alone.


So here is a demo based on your sample JSON fragment.

I'm pretty sure the Unix-to-Earth (i.e. VB Date) conversion works correctly though I have not throoughly tested values from #1/19/2038 3:14:08 AM# onward.

Your sample values have no time-part, so here I have skipped over the step of converting the UTC result to the local time zone but I don't think that matters for your case.  Additional functions to convert to local and to UTC are included, just not used here.


The demo converts the timestamps to VB Date type values, then inserts them back as formatted String values just for visual examination.  Remember, JavaScript and thus JSON are weak in this area and cannot use Date values, so only String values could be used.  In a real program you'd probably just convert and use the values and not stick them back into the JsonBag as this demo does.

----------


## dilettante

> dilettante, anyway to modify the above code to read a Json that has two delimiters? As in this thread.


Sorry, I hadn't seen your post before today.

Well wrapping a few completed instances of his text in proper bracketing JsonBag didn't have any problem handling it:

----------


## Vostok

> The demo converts the timestamps to VB Date type values, then inserts them back ....


Thank you for your response to my question. The procedure is called "test_HD_TimeFrame", module name's Download_TF. My operating system Windows XP. File is sent. Thank you.

P.S. Like everything worked as it should. I was not wrong in the code? 


```
Debug.Print UnixToDate(CDec(1411430400000#))
Debug.Print ToLocal(UnixToDate(CDec(1411430400000#)))
Debug.Print ToUTC(UnixToDate(CDec(1411430400000#)))

'[1410998400000,2003.0699,2012.34,2003.0699,2011.36,0]
'23.09.2014 
'23.09.2014 11:00:00 
'22.09.2014 13:00:00
```

----------


## dilettante

Your tests look good.

Just be wary about using Double values (such as 1411430400000#) because they have limited precision.

Decimal is safer for this, but we have no way to enter a Decimal literal in code.  I used Currency (1411430400000@) because it has greater precision.

See Data Type Summary for details.

----------


## Vostok

> ... I used Currency (1411430400000@) because it has greater precision.


Perhaps I will follow your example and do the same code as your own. Thank you.

----------


## dilettante

Major update.

Changed enumeration model, optimized parsing somewhat, minor new features, untested support for VBA7/WIN64 VBA7.  See JsonBag.rtf for more information.

Very simple Excel example included, which bulks up the attachment quite a bit.

Still largely compatibile with programs using earlier versions unless they were enumerating Names.

----------


## rdefulio

Thanks for this.  I recently discovered JsonBag and its a good fit for adding json support to some of our legacy vb6 projects.  I especially like how easy it is to build the object in code, and then serialize it and send it on its way.  It's also nice that there are no other dependencies outside of JsonBag.cls 

Thanks!

Ron

----------


## sksang

This is a helpfuly module. Where can we get a license?

We're using ver. 1.8.j1. In order to use it, I was told by our attorney that we need to have a license (something more tangible than posting to a publicly available forum because the original author still retains the copyright).

----------


## dilettante

Ok, here is a bundle of just the Class module and documentation.  Versions 1.7, 1.8, and 2.0 included (there was no 1.9 and 1.6 was pretty rough).

Apache 2.0 License added.  Should be liberal enough for most purposes.  :Wink:

----------


## dilettante

New version 2.1, should be compatibile with most programs written against 2.0 and remains largely compatible with those written against earlier versions.

I should probably note that the whitespace-related properties are really only useful for producing formatted "dumps" of JSON for easier development, testing, debugging, and documenting.  Parsing always ignores whitespace and adding whitespace just creates larger JSON payloads so production programs shouldn't do it.

*Changes for 2.1*

Even though just a "point release" this version makes quite a large number of changes.  However it should be highly compatible with version 2.0 and most programs should not require changes to accomodate these JsonBag changes:

Minor optimization of Public Property Get Item (Exists() calls now create the "prefixed" keys used internally).Other small optimizations.New Clone() method returns a deep-copy of the original JsonBag.New CloneItem read/write Property, like Item but deep-copies instead of returning/storing the original Object reference.New ItemIsJSON read-only Property, used to determine whether an item is a JsonBag rather than a simple value.New ItemJSON read/write Property, like Item but accepts and returns JSON text for JsonBag nodes.Property Let Item/CloneItem will only allow VB6 Objects of type JsonBag to be assigned (i.e. this is now validated).Bug fix: Parsing (Property Let JSON) did not detect "arrays" and "objects" with missing values between commas.Bug fix: Replacing an "array" item at the end of the "array" caused "Subscript out of range" error 9.Bug fix: Property Let JSON did not propagate .WhitespaceNewLine to child nodes as they were inserted.Bug fix: Methods AddNewArray() and AddNewObject() did not propagate .DecimalMode, .Whitespace, .WhitespaceIndent, or .WhitespaceNewLine to child nodes as they were inserted.Bug fix: Clear method did not reset .IsArray.  Now it gets cleared to the default value False.  This change might be the most likely one to have impact on existing programs relying on earlier behavior.New conditional compilation constant: NO_DEEPCOPY_WHITESPACE.  When True the .WhitespaceXXX properties are not propagated, which improves parsing performance.

Notes:

The whitespace propagation bug fixes resulted in a significant drop in parsing performance.  However getting things right is probably more important.  Massive JSON strings are not used very often, nor is heavy batch processing of vast numbers of smaller JSON strings.  But as mentioned above in the changes list, NO_DEEPCOPY_WHITESPACE has been provided where the tradeoff in functionality for better performance makes sense.

Setting the VB6 compiler's native code optimization switches has little impact on JsonBag's parsing performance.


General:

Bug reports are always appreciated.

The new "cloning" operations would probably only be used in programs performing complex operations on JsonBags.  That would be those needing to trim out parts of the tree as separate JsonBag writeable objects, copy nodes from one JsonBag to another, etc.  Without cloning, making a change to such JsonBag nodes alters the single instance that multiple JsonBags would point to by Object references.

The ItemJson property is more of a convenience feature.  It makes it easy to build a JsonJag partially from JSON fragements for the "constant" parts of a JSON payload being created.  This could simplify client code by saving on calls to individual properties and methods just to insert such constant data.  Previously a program might do quite a few calls or instead might create temporary JsonBags and assign JSON text to them via their JSON properties before adding them to the "main" JsonBag.

The attachment is bulky because of the Excel workbook included, which is just a tiny VBA usage demo.

----------


## dilettante

One sore point with JSON is its weak intrinsic type system.  In particular date/time values can be painful.

In the wild you'll encounter several workarounds.  Some will use ad-hoc formatted strings, and some will use either Unix "Epoch" timetamps (large numbers) or ISO 8601 date-time strings.

Here's a helper class JsonDate for performing conversions on the latter two date/time representations.


In this version IsoToDate() only handles ISO timestamps of the combined date and time type:

YYYY-MM-DDTHH:MM{.SS{.mmm}}{{Z}|+/-HH|+/-HHMM|+/-HH:MM}
Examples:

2015-04-20T15:51:38.001+05:01
1962-01-01T05:25Z
1962-01-01T05:25
In the last case there is no time zone specification and this can be ambiguous.  The default is to treat this as meaning you have a local time, but you can modify this by setting the property:

.AssumeZ = True
Since the VB Date type doesn't have the resolution to use milliseconds this method just truncates and ignores any .mmm part found in input strings.

While both Unix Epoch and ISO date/time values are considered Zulu/UTC/GMT values the VB Date type is normally considered a local time.  By default the format conversion methods in JsonBag will perform this adjustment.  However you can also choose to work entirely in UTC by setting the property:

.UtcMode = True
This causes the format conversions to skip the time zone adjustments.


There isn't a lot of code here.  So if you merely need a conversion or two it is easy enough to copy some of the code inline into your programs instead of using the JsonDate class at all, aside from maintenance issues if bugs are later discovered.  Everything but IsoToDate() is trivial code.

The code seems to be working properly, but having more eyes on it will help find and fix any lingering bugs.

A simple test using Excel 2003 (32-bit) seemed to work just fine, and I suspect newer versions of VBA can use it as well, both 32-bit and 64-bit.

The attachment has JsonDate.cls and a VB6 test Project and several test cases.  The Project reads the test cases and displays the results of various conversions.

----------


## dilettante

Thanks for the early feedback!

Yes, there were glitches so here is JsonDate 1.1 with these changes:


IsoToDate()'s AssumeZ handling was exactly backwards!  Desired and corrected behavior:



```
Given that the local time zone is -5, and the ISO input is:

    2015-04-20T15:51:38

UtcMode = False and AssumeZ = False mean ISO value with no
time zone should give a local time same as the ISO local time:

    2015-04-20 15:51:38

UtcMode = True and AssumeZ = False mean ISO value with no time
zone should give a UTC time converted from the ISO local time:

    2015-04-20 20:51:38

UtcMode = False and AssumeZ = True mean ISO value with no time
zone should give a local time converted from ISO UTC time:

    2015-04-20 10:51:38

UtcMode = True and AssumeZ = True mean ISO value with no time
zone should give a UTC time same as the ISO UTC time:

    2015-04-20 15:51:38
```


ISO date/time values are allowed to use 24:00 or 24:00:00 as midnight the next day.  IsoToDate() handles this now.


IsoToDate()'s signed time zone offset handling was exactly backwards!


These kinds of bugs show how hard it is to develop correct software on your own.  Even with test cases that cover most of the edge cases you can still miss some.  And even then one set of eyeballs is never enough.  This is part of the argument for open source software.

These bugs were embarassing because two of them were nothing but "dumb mistakes."  The important thing is finding the errors and fixing them, and for that I thank those who PMed me with feedback.

----------


## smileyoufu

Error  NO: 13

----------


## dilettante

Yes.  Sure enough a string like that is an error.  Examples like that were included to make sure they raised exceptions.

There isn't a whole lot more that could be done, and other methods of this class can also throw exceptions.  The only alternative would be to twist them up so that every method accepted a ByRef result parameter and returned an error code result.

As I wrote at the top of the demo's Form1:



```
'IDE TESTING: Set "Break on unhandled errors" in Tools|Options...
'             dialog's General tab!
```

----------


## Vostok

We take data from the site.


 Query result comes in the form of text:


```
jQuery18308002048165113468({ "label" : "AN", "data" : [[1417500000000,58769,-41110,-17659],[1418104800000,65280,-45013,-20267],[1418709600000,56235,-34253,-21982],[1419314400000,61321,-39236,-22085],[1419919200000,63170,-40697,-22473],[1420524000000,72169,-48652,-23517],[1421128800000,68844,-45365,-23479],[1421733600000,70448,-46580,-23868],[1422338400000,78541,-48943,-29598],[1422943200000,85786,-56159,-29627],[1423548000000,82727,-53182,-29545],[1424152800000,82494,-53831,-28663],[1424757600000,91479,-63154,-28325],[1425362400000,85162,-61545,-23617],[1425963600000,107717,-76851,-30866],[1426568400000,56113,-28807,-27306],[1427173200000,50321,-28368,-21953],[1427778000000,45893,-24356,-21537],[1428382800000,67838,-40281,-27557],[1428987600000,71396,-42433,-28963],[1429592400000,59245,-34663,-24582],[1430197200000,44578,-27405,-17173],[1430802000000,12836,626,-13462],[1431406800000,10325,4487,-14812],[1432011600000,4058,7323,-11381],[1432616400000,11898,6422,-18320],[1433221200000,33511,-13256,-20255],[1433826000000,34010,-14027,-19983],[1434430800000,19713,-4048,-15665]] });
```

How to load Web query results in a class module JsonBag? When I load a text query in a class module error.
Thank you.

----------


## dilettante

The stuff you posted is not legal JSON text.

However if you strip off the junk surrounding the valid JSON:



```
jQuery18308002048165113468();
```

... then it parses just fine.

As far as I can tell what you are getting back is JavaScript that calls into one of those flabby lazy-boy JavaScript libraries, in this case jQuery.  If you need to do that then a JSON parser isn't going to help you.  You'd probably have to use the Microsoft Script Control and load in a compatible version of jQuery, and then use that to evaluate your text.

----------


## Vostok

> The stuff you posted is not legal JSON text.
> However if you strip off the junk surrounding the valid JSON:


It'S Great. How could I not notice? Really everything is working fine. It is enough to extract JSON


```
jQuery18308002048165113468(...JSON...);
```



```
  DATA = Split((Split(XMLHTTP.responsetext, "(")(1)), ")")(0)
```



```
{ "label" : "AN", "data" : [[1417500000000,58769,-41110,-17659],[1418104800000,65280,-45013,-20267],[1418709600000,56235,-34253,-21982],[1419314400000,61321,-39236,-22085],[1419919200000,63170,-40697,-22473],[1420524000000,72169,-48652,-23517],[1421128800000,68844,-45365,-23479],[1421733600000,70448,-46580,-23868],[1422338400000,78541,-48943,-29598],[1422943200000,85786,-56159,-29627],[1423548000000,82727,-53182,-29545],[1424152800000,82494,-53831,-28663],[1424757600000,91479,-63154,-28325],[1425362400000,85162,-61545,-23617],[1425963600000,107717,-76851,-30866],[1426568400000,56113,-28807,-27306],[1427173200000,50321,-28368,-21953],[1427778000000,45893,-24356,-21537],[1428382800000,67838,-40281,-27557],[1428987600000,71396,-42433,-28963],[1429592400000,59245,-34663,-24582],[1430197200000,44578,-27405,-17173],[1430802000000,12836,626,-13462],[1431406800000,10325,4487,-14812],[1432011600000,4058,7323,-11381],[1432616400000,11898,6422,-18320],[1433221200000,33511,-13256,-20255],[1433826000000,34010,-14027,-199
83],[1434430800000,19713,-4048,-15665],[1435035600000,24475,-9052,-15423]] }
```

Thank you very much !!!  :Smilie:

----------


## Vostok

> ```
> { "label" : "AN", "data" : [[1417500000000,58769,-41110,-17659],[1418104800000,65280,-45013,-20267],[1418709600000,56235,-34253,-21982],[1419314400000,61321,-39236,-22085],[1419919200000,63170,-40697,-22473],[1420524000000,72169,-48652,-23517],[1421128800000,68844,-45365,-23479],[1421733600000,70448,-46580,-23868],[1422338400000,78541,-48943,-29598],[1422943200000,85786,-56159,-29627],[1423548000000,82727,-53182,-29545],[1424152800000,82494,-53831,-28663],[1424757600000,91479,-63154,-28325],[1425362400000,85162,-61545,-23617],[1425963600000,107717,-76851,-30866],[1426568400000,56113,-28807,-27306],[1427173200000,50321,-28368,-21953],[1427778000000,45893,-24356,-21537],[1428382800000,67838,-40281,-27557],[1428987600000,71396,-42433,-28963],[1429592400000,59245,-34663,-24582],[1430197200000,44578,-27405,-17173],[1430802000000,12836,626,-13462],[1431406800000,10325,4487,-14812],[1432011600000,4058,7323,-11381],[1432616400000,11898,6422,-18320],[1433221200000,33511,-13256,-20255],[1433826000000,34010,-14027,-199
> 83],[1434430800000,19713,-4048,-15665],[1435035600000,24475,-9052,-15423]] }
> ```


I can not understand. What is the function of the given search can be used to convert the date to the correct view. Help me please. Thanks.

----------


## Vostok

> I can not understand. What is the function of the given search can be used to convert the date to the correct view. Help me please. Thanks.


I think I found the answer


```
  Dim JD As JsonDate, dateD as Variant 
  Set JD = New JsonDate
  dateD = JD.UnixToDate(CDec(....JSON Date....)
```

----------


## dilettante

No need for CDec() there.  The very first thing that the UnixToDate() method does is call CDbl(UnixTimestampValue).

Also your dateD should be As Date in most cases.

----------


## Vostok

> No need for CDec() there.  The very first thing that the UnixToDate() method does is call CDbl(UnixTimestampValue).


 I see. Thank's

----------


## SWo777

Hi .. so I'm havving a play with v2.1 of JsonBag. I have an instantiated jsonbag which produces the following json.

{"Document":{"SectionSet":"True","Copy":"C:\\InfoFlex v5\\Data\\","Convert":"[Do not convert]","UseFilename":"True","UseExtension":"[Not Set]","Filename":{"SectionSet":"False","FilenameExpr":[],"CharReplacement":{"/":"",":":"","*":"","?":"","<":"",">":"","\"":"","|":"-","^":"-","&":"-","TILDE":"-","\\":"-","(Carriage Return)":"","(Line Feed)":"","(Tab)":""}}},"Replacements":{"Prefix":"","Suffix":"","Tags":[]},"Metafile":{"SectionSet":"False","Document":"","Destination":"C:\\InfoFlex v5\\Data\\","UseFilename":"Use Primary Filename","UseExtension":"[Not Set]","Filename":{"SectionSet":"False","FilenameExpr":[],"CharReplacement":{"/":"",":":"","*":"","?":"","<":"",">":"","\"":"","|":"-","^":"-","&":"-","TILDE":"-","\\":"-","(Carriage Return)":"","(Line Feed)":"","(Tab)":""}},"Encode":"[No encoding]"},"Actions":{"Perform":"[Not Set]","Action":{"SectionSet":"False","ActionConfig":{}}}}

but when I try and load it back into a new jsonbag via the json property, it generates an "Empty value at character 192".

Now I can copy/paste that same json into a json validator website and it seems to parse ok (e.g. http://jsonlint.com/). I am struggling to work out just why it may be failing. 

Any chance of a helping hand?

Many thx IA

S

----------


## SWo777

Actually I worked out that the problem seemed to be that empty arrays and empty objects throw an exception.

See methods ParseArray line 664 and ParseObject line 711. For the time being I've just commented out the throwing of the exception but obviously I am unsure of the side-effects of theis change.

Thx

S

----------


## dilettante

Glad you found it.

But if you look at the JSON specs at http://json.org/ you will see that empty arrays and objects are not legal JSON, so throwing an exception is the correct thing to do.

----------


## Schmidt

> Glad you found it.
> 
> But if you look at the JSON specs at http://json.org/ you will see that empty arrays and objects are not legal JSON, so throwing an exception is the correct thing to do.


From what I read from the specs (and especially the flow-diagrams), empty Objects and Arrays 
are definitely allowed.

Wellknown Online-Validators like http://jsonlint.com/  are useful - and there for a reason.

Olaf

----------


## dilettante

Here is a new update with a few small but important changes relating to /LARGEADDRESSAWARE programs and the presence of Unicode characters above &H7FFF& which were being mishandled due to the nature of VB/VBA's AscW() function.  That latter could have caused false "bad character" exceptions to be raised or even crashes when parsing JSON string values.

There was also a change in the conditional code for VBA7.

The documentation (JsonBag.rtf) included has been updated with more details.

For most programs this should be a drop-in replacement for JsonBag 2.1: no changes were made to method or property signatures or usage.  I suggest everyone upgrade to this version and _test, test, test!_  :Wink:

----------


## dilettante

> From what I read from the specs (and especially the flow-diagrams), empty Objects and Arrays 
> are definitely allowed.


I have looked again and discovered I was misinterpreting what I saw, so I agree.  Thank you for that important feedback!

Version 2.3 makes a change to allow this, so it should be preferred over any earlier versions.

----------


## drecks4

Hi!

I've just downloaded v2.3, and when I open the *.xls demo file I get a 'Type Mismatch' error in the 'PtrWhiteSpace' variable.

I am using Office 2013 64bit.

Could you take a look please?

Thanks!

----------


## dilettante

Sorry for the trouble!

Here is a new version 2.4 that may address this problem.  I don't have any VBA7 hosts (either 32- or 64-bit) right now so I can only test in VBA6.  This means the problem might not be fixed since I have to make the VBA7 differences by reading documentation, guessing, and just putting them in there for others to try.

These changes should have no impact on VB6 users and probably not on VBA6 users either - at least none I have discovered.

----------


## dilettante

JsonBag now has a "little brother" that is smaller and might be easier to use in VBA hosts.  See: JNode - JSON revisited

----------


## bPrice

Have already incorporated JsonBag2.4 into my own projects. So far it works perfectly well. 
The documentation is very good.

Will come back and report bugs, if any.  :Wink:

----------


## dilettante

An update to the JsonDate.cls companion class.  Breaking changes, so read the "Changes" text file.  Now version 2.0 but no new JsonBag.cls here.

Handles Unix timetamp values in both seconds and milliseconds.  Corrects conversions to/from local time to handle DST better.  This means it won't work on Windows XP and earlier dead versions of Windows... but see the comments for "fallback" code you can use if you need XP support as well.


*ISS Plot Demo*

This demo makes use of the super simple "Where the ISS at?" REST API web service to plot the position of the International Space Station over the Earth against a simple "equirectangular projection" map.



Much of the size of the attachment is images.

The program uses JsonBag 2.4 and JsonDate 2.0 along with WinHTTP to make a position request every 5 seconds.  Since this is a free web service that doesn't even require a free account, anyone should be able to unzip and run the demo on Windows Vista SP1 or later.

With tweaks mentioned above to JsonDate.cls it should even run on Windows XP.

It's a quick and dirty demo, so there might be some errors in the offsets and arithmetic used to position the IIS icon and "drop" the red trail of breadcrumbs.  But it works well enough for demo purposes.


If you are interested in this sort of thing, the API might be expanded in the future to track more orbital objects as well as the ISS.  There are other similar web services from other sources for more data regarding orbiting stuff and astronomy more generally.

----------


## dilettante

JsonBag 2.5:

No logic changes of any significance.  Just a change to several properties that accepted an "Optional ByVal Arg As Variant = Null" argument.

If you have any of these your Class cannot be compiled into a VB6 DLL, OCX, etc.  This involves a subtle point of COM Marshalling.

The fix is to remove the default Null value and early in the procedure test for IsMissing() and if True assign Null to the Optional argument.  The result should compile and work identically to the original.


Thanks to *engowen* for bringing this up.  Thanks to VB and C# Watcha's, Gotcha's, Tips & Tricks for the solution.

----------


## wrayman

Hello,

I have installed (Excel Demo (2.4) ) and with sample works as expected

I am trying to figure out how to use another JSON data file (prefer to get by WinHttp method) 

I have read through the documentation but can not figure out how to get to array that have objects and then strings.

the sample file lib.json (lib.txt) JRA-9 .txt

How would I get "issuelinks" (an array) and then create _headers_ from the objects "id" ,"self","type" : object+{"id","name","inward" ,"outward" "self}..., etc and then populate rows. Maybe to complex JSON?

This json can be retrieved from: https://jira.atlassian.com/rest/api/2/issue/JRA-9.json

I am using VBA and tried VBA-JSON but can't get it to work.


I am sorry that I don't understand how this works, any help would be appreciated.


I am using VBA and tried VBA-JSON but can't get it to work.

----------


## mjk1165

I am trying to parse a JSON file and am getting an error at this step:
Private Sub SkipWhitespace(ByRef Text As String)
    CursorIn = CursorIn + StrSpn(StrPtr(Text) + 2 * (CursorIn - 1), PtrWhiteSpace)
End Sub

Compile error: type mismatch

Using VBA and Jsonbag 2.1

----------


## dilettante

> Using VBA and Jsonbag 2.1


VBA support isn't thoroughly tested, especially in a 64-bit VBA host.  I suggest you try a newer version though, there were some VBA-related changes made in version 2.4 that might address this.

----------


## mjk1165

I have updated to version 2.5.     The JSON function seems to works and return the information but I am not able to access the data.

in the Locals window I see:
myJB
...
Names
...
Values
...
Item 1
Item 2
...

the .item() functiont returns, "key not found"
the .itemJOSN() functions gives compile error "type mismatch"

I have not sure I have the right syntax:
Date from I

----------


## mjk1165

I have updated to version 2.5.     The JSON function seems to works and return the information but I am not able to access the data.

in the Locals window I see:
myJB
...
Names
...
Values
...
Item 1
Item 2
...

the .item() functiont returns, "key not found"
the .itemJOSN() functions gives compile error "type mismatch"

I have not sure I have the right syntax:
Date from I

----------


## dilettante

Perhaps this might help?

sample.js


```
{"sample":
  { "fudge": "vanilla",
    "story":
      { "title": "Konfabulator Magnifico",
        "author": "Fred G. Poobles",
        "pages": 53,
        "words": 12000
      },
    "text":
      [ "Click Here",
        "Bold",
        "Fresh"
      ]
  }
}
```



```
    Dim JB As JsonBag
    Dim F As Integer
    Dim I As Integer
    Dim JBText As JsonBag

    Set JB = New JsonBag
    F = FreeFile(0)
    Open "sample.js" For Input As #F
    JB.JSON = Input$(LOF(F), #F)
    Close #F

    Print " Single sample:fudge:"
    Print , JB.Item("sample").Item("fudge")
    Print
    Print " Single sample:story:title:"
    Print , JB.Item("sample").Item("story").Item("title")
    Print
    Print " List sample:story:"
    With JB.Item("sample").Item("story")
        For I = 1 To .Count
            Print , .Item(I)
        Next
    End With
    Print
    Print " Single sample:text(1):"
    Print , JB.Item("sample").Item("text")(1)
    Print

    Set JBText = JB.Item("sample").Item("text")
    Print " List JBText:"
    For I = 1 To JBText.Count
        Print , JBText.Item(I)
    Next
```

----------


## mjk1165

I have made progress with reading the jsonbag. 

The function fails still when retriving some keys, with a error 3265 - 'Item not found in Collection'.     What is odd is the that when I a follow the code, it seems to find the key and retrieve the value, but falls out of the 'Property Get' function with the 'Item not found... error or Run-time -424 - Object Required.    The key is 'message' which appears to be a nested json, but I have another routine where it fails on string values.

I included a link to the file I am trying to parse.
https://www.dropbox.com/s/b91uhc8lfr...Logs.json?dl=0

I appreciate any direction you could provide.

Mike

----------


## dilettante

I'm not seeing a problem.  I had no trouble parsing and using your sample document.






```
Option Explicit

Private Sub Form_Load()
    Dim JB As JsonBag
    Dim F As Integer
    Dim JBLogs As JsonBag
    Dim LogName As String
    Dim JBLog As JsonBag
    Dim Row As Long
    Dim Col As Long
    Dim JBMessage As JsonBag

    Set JB = New JsonBag
    F = FreeFile(0)
    Open "SD_Logs.json" For Input As #F
    JB.JSON = Input$(LOF(F), #F)
    Close #F

    'Discard all but "logs" from here on:
    Set JBLogs = JB.Item("logs")
    Set JB = Nothing

    Caption = "Dump of SD_Logs.json ""logs"""

    With MSHFlexGrid1
        .WordWrap = True
        .ColWidth(0) = TextWidth("..log..")
        .Rows = JBLogs.Count + 1
        Set JBLog = JBLogs.Item(1)
        .Cols = JBLog.Count + 1
        .Row = 0
        .Col = 0
        .Text = "log"
        For Col = 1 To .Cols - 1
            .Col = Col
            .Text = JBLog.Name(Col)
            .ColAlignment(Col) = flexAlignLeftTop
        Next
        'JBLog item 4 is the very long embedded JSON "message" value:
        .ColWordWrapOption(4) = flexWordBreakEllipsis
        .ColWidth(4) = 4320
        Set JBMessage = New JsonBag
        For Row = 1 To .Rows - 1
            .Row = Row
            If Row > 1 Then Set JBLog = JBLogs.Item(Row)
            .Col = 0
            .Text = JBLogs.Name(Row)
            For Col = 1 To .Cols - 1
                .Col = Col
                If Col = 4 Then
                    'Parse the embedded JSON and extract the first "error" value:
                    JBMessage.JSON = JBLog.Item(Col)
                    .Text = JBMessage.Item("errors").Item(1)
                Else
                    .Text = CStr(JBLog.Item(Col))
                End If
            Next
            .RowHeight(Row) = TextHeight("Wjgy") * 4
        Next
    End With
End Sub

Private Sub Form_Resize()
    If WindowState <> vbMinimized Then
        MSHFlexGrid1.Move 0, 0, ScaleWidth, ScaleHeight
    End If
End Sub
```

Your sample JSON is in the attachment.

----------


## dilettante

Turns out that:



```
Dim LogName As String
```

... wasn't used above.  I was coding on the fly so I declared something I didn't use.  Just ignore it but I didn't want to add confusion.

----------


## Schmidt

Just tested your last example, and you might want to fix your "parsing-handler for numeric data" - 
in the last column you convert the (quite large) integer into a double, which could lead to imprecise output or calculations
(in the RichClient I start with mapping Integer-Numbers to Longs I think, then Currencies, and then Decimals, in case 
the incoming Numbers "cross" the "fitting-boundaries" of the types in question).

The Field(Values) I mean (which are mapped to a Double-Type), are the last ones in the records of the larger JSON-array:
..., "_version_":1556427511093526531}

Olaf

----------


## DEXWERX

That's a funny edge case.
The JSON spec allows integers (Number) of unlimited size, but Javascript itself treats integers that large the same as a "Double".

What do you do when it doesn't fit in a Decimal? keep it a string?

----------


## dilettante

As it says in the documention (not included in the example above but in the other uploads before it):




> *DecimalMode As Boolean [read/write]*
> 
> Defaults to False.
> 
> The setting of this property determines how numbers are parsed and serialized.  See the discussion Impact Of DecimalMode Setting above.
> 
> This should only be set on a JsonBag instance that is being used as a "root" document node when it is empty.


So most JSON parsers deal with it one way or another, and that's how JsonBag does it.  The default is _Double_ which is what the spec calls for even though that is widely violated.  JSON inherits the weak type system of JavaScript.

Slopping a "number" into an Integer for example can lead to unexpected overflows when somebody works with it.  That's one of the reasons why trying to get clever can blow up in users' faces.  Badly.

But you have to make a decision one way or the other, and that's just how the JSON game goes.

----------


## Schmidt

> But you have to make a decision one way or the other, and that's just how the JSON game goes.


It was just a hint, to not leave anything to chance (or to some Usage-Properties, which might not be switched away from their defaults)...
In my understanding, the usage of Doubles (IEEE754) is just a suggestion (since it's a commonly available type between languages).

But VB6 *does* have support for higher precision (per Decimal-Variants) - so why not switch *automatically* to 
the  Dec-Types (in the Variant-holding Collection), when e.g. a large Int64 value comes along (often used in DB-Tables as Record-ID)

To detect, whether the text-representation of a number is an integer, is a no-brainer - 
it can be easily determined at the parsing-stage, by checking for the local-invariant: "."

Sure, JavaScript cannot deal with the large Integer-Value (as shown in post #73), 
and for example, when it's meant as an ID (e.g. to identify a Record in a DB-Table)...:
alert( JSON.stringify( JSON.parse('{"ID":1556427511093526531}') ) );
... will give the serialized output: {"ID":1556427511093526500} - which is a loss of information,
... so a potential next roundtrip back to the WebServer (and its DB) will cause errors due to not matching IDs
(e.g. when the purpose is an Update-Query, to store some piggy-back-traveling extra-JSON-fields under that ID).

Though many other languages (and JSON-Parsers) will not have any problem with such a large Integer-Value (VB6 among them) - 
in the meantime JSON is not a "JavaScript-only"-thing anymore - it's a quite wide-spread serialization-format - 
and the usage of RPCs is not limited to (WebBrowser+JavaScript)<->(WebServer) communication.

Just my 0.02$... <shrug>

Olaf

----------


## mjk1165

Thank you for all your help.    My biggest challenge is my lack of experience with JSON's.

I am working my way thru each nested JSON using your example. Is there way to tell if a key exists in a JSON?  For example, the message block could have messages warnings or errors, and I would want to handle the information differently.

----------


## dilettante

As it says in the JsonBag.rtf document:




> *Exists(ByVal Key As Variant) As Boolean*
> 
> Only meaningful on "Object" JsonBags.  Used to determine whether a named Item exists, by name or index.
> 
> "Array" type JsonBag list members indices always range from one (1) to Count.

----------


## DEXWERX

The way Javascript and PHP deals with overly large integers - is to export them as a JSON strings.
I remember this being a fiasco when facebook went to 64bit IDs, and broke a bunch of APIs.

The best thing about this class - is it's open source. We can modify it to suit specific needs, and edge case behavior.

----------


## Schmidt

> The way Javascript and PHP deals with overly large integers - is to export them as a JSON strings.
> I remember this being a fiasco when facebook went to 64bit IDs, and broke a bunch of APIs.


Yep, and that raises the question, which toolset (or language) did produce the JSON-serialization
(containing that large Integer-Value in mjk1165's example)... 
Apparently it expects a JSON-parser (on the other end), which is capable to understand
(and not mangle) that Integer-Value.




> The best thing about this class - is it's open source. We can modify it to suit specific needs, and edge case behavior.


Well, I hope mjk1165 is capable of doing that... 

As it is currently, I hope he understood from what was said, that he has to use a specific non-default-setting on diles JSON-Bag, 
to not run into issues with that Integer (e.g. on a potential back-posting roundtrip with "re-serialized" content to the ServerSide).

The "automatic-fallback-mode to Decimal" I was suggesting (when Integer-Numbers get too large) would hurt nobody 
(even in the Default-Setting "Parse-Numbers-into-Doubles") and would require the least efforts, when dile does it himself.

But as said, it was only a well-meant suggestion (take it or leave it)...

Olaf

----------


## DEXWERX

> The "automatic-fallback-mode to Decimal" I was suggesting (when Integer-Numbers get too large) would hurt nobody 
> (even in the Default-Setting "Parse-Numbers-into-Doubles") and would require the least efforts, when dile does it himself.
> 
> But as said, it was only a well-meant suggestion (take it or leave it)...
> 
> Olaf


I'm not arguing with you - It's definitely a good suggestion.

----------


## dilettante

The JsonBag has a property for this, just as documented (unlike so much undocumented closed-source code of dubious attribution people promote):




> *DecimalMode As Boolean [read/write]*
> 
> Defaults to False.
> 
> The setting of this property determines how numbers are parsed and serialized.  See the discussion Impact Of DecimalMode Setting above.
> 
> This should only be set on a JsonBag instance that is being used as a "root" document node when it is empty.


It is a trivial matter to assign True to this property or even to alter its default value to True.  The latter is spelled out pretty explicitly:



```
Private Sub Class_Initialize()
    TypeNameOfMe = TypeName(Me)
    PtrWhiteSpace = StrPtr(WHITE_SPACE)
    Clear 'Creates Collections.
    DecimalMode = False 'Default
    Whitespace = False 'Default
    WhitespaceIndent = 4 'Default.
    WhitespaceNewLine = vbNewLine 'Default.
End Sub
```

If somebody can't figure out how to change the default value to True they have a bigger problem.  :Wink:

----------


## Schmidt

> The JsonBag has a property for this, ...


You're repeating yourself. 
My point was, that this property would be completely unnecessary (with just a slight addition in your parsing-code).

As it is, it is just confusing - especially since it behaves inconsistently (and is **not** adhering to your "documentation").

Since you say in your Doc: "...this property determines how numbers are parsed *and serialized*..."
Example: 


```
    Dim JB1 As New JsonBag
        JB1.DecimalMode = False '<- use Double-Mode
        JB1.JSON = "{""longNumber"":1556427511093526531}"
    Debug.Print JB1("longNumber") 'will print 1.55642751109353E+18
    
    Dim JB2 As New JsonBag
        JB2.DecimalMode = False '<- use Double-Mode
        JB2("longNumber") = CDec("1556427511093526531")
    Debug.Print JB2.JSON 'will print {"longNumber":1556427511093526531}
```

So - the latter result (of JB2 above) is not holding its promise (to *serialize* in Double-Format, as the Doc states),
since a Double clearly cannot hold an integer-value in that precision (as the first printout of JB1 shows).

So, as already suggested - either fix your code - or your wrong documentation 
(now curious whether you're able to manage one of the two things without further sidekicks,
a simple "dear fellow-developer, thank you for pointing that out" would already be enough... <g>).

Olaf

----------


## dilettante

Perhaps you didn't _read_ the documentation?

Under the discussion on DecimalMode it says:




> This property setting only impacts assignments to the JSON property, i.e. parsing serialized JSON.  If you directly assign a numeric value the actual type your code used is stored in the object hierarchy data.  Of course as noted it may also impact retrieval from the JSON property, i.e. serializing the tree into JSON text.


The behavior you showed above matches this _exactly_.  If anything perhaps there is a small flaw there (the bold text you quoted), but unlike some people I provide both the source and documentation.  I'll keep this documentation change in mind for a future release.  At least it has been covered to death here now though.

----------


## FunkyDexter

Let's cut back on the sniping shall we... in both directions.  You've both provided some excellent work in this forum and both deserve to have that acknowledged.

keep any criticism friendly and constructive and let's receive it in the same vein.

----------


## paul-ac

Hey guys,
i' on was on the version 1,6, it was working perfectly, thanks for great job. 
But  :Smilie:  One week ago our IT updatet the Office 2010 to 64 bit and it didn't work
Ok, i updatet the JsonBag to version 2,5 and now i have the problem with "Names"
"Set ContractNames = JsRoot.Item(x1).Item("rows").Item(x2).Item("data").Names" 
unfortunately after set the object is always ContractNames = nothing
Can you help me please? 
json is attached

----------


## paul-ac

Hey guys! 
our it updated the office to the 64 bit version, so i updated jsonbag to the 2.5 version and now i have a problem with the "names"

Set ContractNames = JsRoot.Item(x1).Item("rows").Item(x2).Item("data").Names

after set is the object *ContractNames* = nothing
can you tell me, what i am doing wrong? thanks in advance
PS: json is attached
PSS: sorry for my bad english

----------


## paul-ac

> Hey guys! 
> our it updated the office to the 64 bit version, so i updated jsonbag to the 2.5 version and now i have a problem with the "names"
> 
> Set ContractNames = JsRoot.Item(x1).Item("rows").Item(x2).Item("data").Names
> 
> after set is the object *ContractNames* = nothing
> can you tell me, what i am doing wrong? thanks in advance
> PS: json is attached
> PSS: sorry for my bad english


PSSS: Dim ContractNames As Collection

----------


## dilettante

Names will never return a Collection.  The value will either be a simple value type or else a JsonBag instance.

We have no way to guess what your "x1" variable is or what value it has.  That makes it very difficult to explore for possible problems.

The Json text in your attachment seems to parse just fine in JsonBag.

I see nothing here to suggest that moving to 64-bit VBA makes any difference.  Are you sure this ever worked before in 32-bit VBA?

----------


## paul-ac

> Names will never return a Collection.  The value will either be a simple value type or else a JsonBag instance.
> 
> We have no way to guess what your "x1" variable is or what value it has.  That makes it very difficult to explore for possible problems.
> 
> The Json text in your attachment seems to parse just fine in JsonBag.
> 
> I see nothing here to suggest that moving to 64-bit VBA makes any difference.  Are you sure this ever worked before in 32-bit VBA?


Yes, it worked for me.
Now i changed the code and it works, thanks !

----------


## beic

Hi there,

I'm trying to parse Json data but without any luck with v1.8 on Windows 7 64-bit:



```
{
  "ESP8266": {
    "NTC": {
      "temperature": 18.03633
    },
    "DHT11": {
      "temperature": 19,
      "humidity": 59
    },
    "SHT30": {
      "temperature": 19.48043,
      "humidity": 63.17846
    },
    "BMP180": {
      "temperature": 19.7,
      "pressure": 997.52
    },
    "WU": {
      "temperature": 1.6,
      "humidity": 98,
      "pressure": 1006
    }
  }
}
```

I'm unable to get any readings by:



```
Debug.Print objJson.Item("ESP8266").Item("NTC").Item("temperature")
```

Also got some error saying:


```
Requested Item by key doesn't exist (case mismatch?)
```

But, if I check the feeded JSON Object, it's clear reading.



```
Debug.Print objJson.JSON
```



```
{"ESP8266":{"NTC":{"temperature":18.03633},"DHT11":{"temperature":19,"humidity":58},"SHT30":{"temperature":19.73144,"humidity":62.63981},"BMP180":{"temperature":20.1,"pressure":997.25},"WU":{"temperature":1.6,"humidity":97,"pressure":1006}}}
```

So, I don't know what I'm doing wrong.

Please advise!

Kind regards,
Viktor

----------


## beic

Anyway, after one and a half day strugling, I figured out that I was destroying the Json Object on the half way!  :Big Grin:

----------


## yokesee

I use the JsonBag 2.5
and this code works perfect for me


```
    Dim J As New JsonBag
    J.JSON = Text1.Text
    Debug.Print J.Item("ESP8266").Item("NTC").Item("temperature")
```

----------


## beic

> I use the JsonBag 2.5
> and this code works perfect for me
> 
> 
> ```
>     Dim J As New JsonBag
>     J.JSON = Text1.Text
>     Debug.Print J.Item("ESP8266").Item("NTC").Item("temperature")
> ```


As I wrote before, I forgot to remove 

```
Set objJson = Nothing
```

 and the JSON Object was empty always

----------


## beic

Hi there,

Why I'm getting this from the Jeson parser:



```
{
  "ESP8266": {
    "NTC": {
      "temperature": 18.65
    },
    "DHT11": {
      "temperature": 21,
      "humidity": 48
    },
    "SHT30": {
      "temperature": 21.59,
      "humidity": 56.03
    },
    "BMP180": {
      "temperature": 22.1,
      "pressure": 999.06
    },
    "WU": {
      "temperature": 8.6,
      "humidity": 77,
      "pressure": 1006
    }
  }
}
```

when I'm feeding with these values:



```
{
  "ESP8266": {
    "NTC": {
      "temperature": 18.65
    },
    "DHT11": {
      "temperature": 21.00,
      "humidity": 48.00
    },
    "SHT30": {
      "temperature": 21.59,
      "humidity": 56.03
    },
    "BMP180": {
      "temperature": 22.10,
      "pressure": 999.06
    },
    "WU": {
      "temperature": 8.60,
      "humidity": 77.00,
      "pressure": 1006.00
    }
  }
}
```

So, where are my decimals gone?

Kind regards,
Viktor

----------


## dilettante

They are gone because they're supposed to be gone.  That isn't from the parser but the serializer.

JSON has just a simple "number" type for numeric values.  On decoding these become Double (or optionally Decimal).  Don't be confused about the text representation once re-encoded back to JSON.  JSONBag serializes numeric values back to a compact form, desirable to keep transmission costs down.


Nothing in the JSON spec requires retaining the original formatting of a value within the parsed JSON text.  Even if it did, there are no rules to tell you how to format the value if changed or a new value is added, etc.  JSON makes no provision for formatting numeric values any particular way as long as they result in a legal JSON "number."

If you really, really wanted this for some odd reason you would have to add another property to each numeric JSONBag item for "format" though I have no idea how reliable the parser could be at deciding what "format string" to assign when values are parsed.

----------


## Dragokas

dilettante, thank you.
This parser is very very necessary thing for a modern format of settings storage.

----------


## vb6forever

dilettante:

FWIW:
Just ran your JSON 2.5 Firefox bookmarks.
Stuck in loop and had to use Ctrl-Alt_Delete to exit.
For further discussion see here:

http://www.vbforums.com/showthread.p...lete-Bookmarks

----------


## dilettante

Sounds like you have found a bug.  Can you provide sample data that reproduces the problem?

If you break execution in the IDE what line is it on?

----------


## vb6forever

dilettante:

Happy New Year.   Decided to come off my break early so in response to your questions:




> If you break execution in the IDE what line is it on?


Running your Demo2 from Version 2.5, with my bookmarks.json file.
Everytime I break it end up in Form1:Proc:  "DumpText"
At break bookmarks.json values are valid as I search bookmarks file to verify.
Just seems to repeat -- stuck in loop.




> Can you provide sample data that reproduces the problem?


This is a tough one as using a copy of my actual bookmarks file.
See what I can do.

----------


## Dragokas

You can try make regexp-replacements of personal data.

----------


## dilettante

As soon as this line of code finishes:



```
JB.JSON = JsonData
```

... the parsing is done.  So the problem is probably not in JsonBag at all.

The rest of that program (mainly JbDump) just tries to walk the JsonBag tree and dump everything.

After that it queries a couple of items and displays than in MsgBox dialogs, but you probably deleted that part since it was specific to the original sample JSON document.


If JbDump has a problem I don't see it.  Did you alter it?  When you break try View|Call Stack... to walk back and find out where DumpText was called from.  What are the values of Name, Level, JB.Count, and ItemIndex?  


Without a sample file that produces this problem there isn't a lot we can do remotely.

----------


## vb6forever

Dragokas:




> You can try make regexp-replacements of personal data.


Have never worked with regexp so a non-starter.
Was looking at a possible Search / Replace but Not sure amount effort involved.
I would think any Firefox bookmark file would give the same problems as IMHO it is more in their JSON format than in my data.

dilettante

Give me a couple days to see what I can come up with.





> Without a sample file that produces this problem there isn't a lot we can do remotely.


If my data agree, if Firefox bookmark format is issue then any Firefox JSON bookmark file should give same error.  Firefox appears to use arrays of objects (children) which may be nested fairly deep.

----------


## vb6forever

Quick Followup:




> Did you alter it?


No, other than to substitute path to bookmarks.json which I copied to same directory as the program.



> When you break try View|Call Stack... to walk back and find out where DumpText was called from. What are the values of Name, Level, JB.Count, and ItemIndex?


Did three different breaks and followed Call Stack each time to JbDump
Checked the values for the variables suggested at each break.
All variables at EACH break had different values, but values look good -- from my bookmarks.json file.

=================
When I run Demo2 using the bookmarks.json file the left side "RTB" is stable and appears to show the bookmarks.json file (source) correctly from a cursory review.   the right side "RTB" is the one that scrolls continuously as if stuck in a loop.
==================
After the 3 breaks ran again until appeared locked.





> IGNORE THE FOLLOWING -  POSTED IN ERROR because:
> Since I broke on JbTest I would expect JbDump to have "Subscript out of Range" errors
> and other variables to be questionable
> ==================================================
> 
> In checking JbDump the key issue appears to be "Subscript out of Range"
> 
> 
> ```
> ...

----------


## dilettante

What if you add two lines to remove the overhead of the control's UI updating?



```
    Set JB = New JsonBag
    JB.JSON = JsonData
    Show
    txtJsonBagDump.Visible = False
    JbDump "*anonymous outer JsonBag*", JB
    txtJsonBagDump.Visible = True
    HomeDump
```

----------


## vb6forever

Thanks for the code and suggestion.
Sadly, let run for 10 minutes and no output in Right Textbox.

This weekend will try and debug and see if I can pinpoint where hangup is occurring.

----------


## vb6forever

FWIW:  Dumped just the first few lines of the file and grouped them (blank lines between groups)
to get some idea of the format.  



 Lot of embedding.

----------


## k_zeon

Hi, Wonder if anyone can help.
I am using jsonbag and works very well. However, i send a query to a website and expect to get a list of stuff back.
This all works good. However if i send an incorrect code i get a json respone that gives me
P.Item("name") = "Not Found"

If when i check P.Item("name") = "Not Found"  everything works and i exit the sub , but when i send a valid query and 
everything is ok i get P.Item(Row).Item("xxxxxxx")

How do i check the error raised when P.Item("name")  is not even returned. 

I am using VB6 and get Runtime error 5 . invalid call or procedure.

i have tried  checking    Not IsNull(P.Item("name"))  and some other variations but the only way i can 
see is to use Goto err handler which i did not want to do.

Is there a way to catch this error of an item not being avail.

many thanks

----------


## dilettante

Try turning the circled option on in the IDE:

----------


## hbrofman

Nice Library. Has anyone used it to serialize a recordset? Any examples?

thanks

----------


## hbrofman

Nice Library. Has anyone used it to serialize a recordset? Any examples?

thanks

----------


## dilettante

> Nice Library. Has anyone used it to serialize a recordset? Any examples?


The problem with this is that something like an ADO Recordset is incredibly far richer than JSON.

JSON is so feature poor it is hard to know where to begin.  Just look at data types:

JSON only has one numeric type: "number."  That's instead of bytes, 16-bit and 32-bit integers, single-precision and double precision floating point, and more.  JSON has no byte array.  JSON has no date and time types.  The list just goes on and on and on.  Most of the culprit here is the incredibly type-poor JavaScript that JSON is based upon.

JSON lacks all kinds of metadata.  For example a Recordset tracks whether a row has been modified, which is important when marshalling data back to a server for updating so you can send only the modified rows back... and if you send it all back the server can see which rows are to be updated to the underlying datastore at its end.  The Fields within a Recordset also carry lots of metadata like the data type, ActualSize and DefinedSize, NumericScale, Precision, the Value and OriginalValue and UnderlyingValue, and more.


If you really want to serialize ADO Recordsets you may be far better off using one of the two formats it supports natively: ADO's own XML format or its ADTG binary format (far more compact).

Now, if you must have JSON and your needs are really meager you can cobble something up.  However it is hard to imagine any generic way of doing this for all Recordsets.  You must make massive compromises and those must be chosen for every use case.

Nothing says you can't invent some sort of JSON schema for doing this, much as ADO has its XML schema for representing Recordsets.  i haven't seen anyone even attempt it yet though.  There just isn't enough demand.


I suspect most people dealing with JSON are also dealing with servers that can't handle a Recordset anyway.  So in that case they just use some ad hoc JSON schema that implements some tiny fraction of the metadata, if any at all, and live with the data type limitations.

But in that case there just isn't much to it.  Any example would have to imply so many assumptions about the specific application as to be meaningless, probably useless for any other application.

----------


## DllHell

> Nice Library. Has anyone used it to serialize a recordset? Any examples?
> 
> thanks


the built-in one on the recordset is pretty good if you don't mind using the disk:

to disk:


```
rs.save("c:\temp.dat",adPersistADTG)
```

from disk:


```
rs.open("c:\temp.dat","Provider=MSPersist")
```

----------


## k_zeon

hi. looking to used JsonBag and did an initial test to check the existence of keys.
how can i do the following as below raises an error



```
  If JB.Exists("sample").Item("fudge") = True Then

        Debug.Print JB.Item("sample").Item("fudge")

    End If
```

i know JB.Exists("sample") works fine,  but checking for a 2nd key ie JB.Exists("fudge") does not

thanks

----------


## Eduardo-

Hello,

Look, I think there is a bug in the Exists method of the last version, copy this code and replace the Exists procedure:



```
Public Function Exists(ByVal Key As Variant) As Boolean
    Dim Name As String
    
    If VarType(Key) = vbString Then
        On Error Resume Next
        Name = Names.Item(PrefixHash(Key))
    Else
        On Error Resume Next
        Name = Names.Item(Key)
    End If
    Exists = Err.Number = 0
    Err.Clear
End Function
```

About how to use it in chain:



```
If JB.Exists("sample") Then
    If JB("sample").Exists("fudge") Then
        Debug.Print JB.Item("sample").Item("fudge")
        ' Or
        Debug.Print JB("sample")("fudge")
    End If
End If
```

The word _.Item_ is optional. (whether you put it or not it works anyway)

----------


## k_zeon

> Hello,
> 
> Look, I think there is a bug in the Exists method of the last version, copy this code and replace the Exists procedure:
> 
> 
> 
> ```
> Public Function Exists(ByVal Key As Variant) As Boolean
>     Dim Name As String
> ...


thanks Eduardo.   If JB("sample").Exists("fudge") Then  was what i needed. Did not change the Exists though. left it as is and works fine



```
Public Function Exists(ByVal Key As Variant) As Boolean
    Dim Hash As Long
    Dim PrefixedKey As String
    Dim Name As String
    
    If VarType(Key) = vbString Then
        HashData StrPtr(Key), Len(Key) * 2, VarPtr(Hash), 4
        PrefixedKey = Right$("0000000" & Hex$(Hash), 8) & Key
        On Error Resume Next
        Name = Names.Item(PrefixedKey)
    Else
        On Error Resume Next
        Name = Names.Item(Key)
    End If
    Exists = Err.Number = 0
    Err.Clear
End Function
```

----------


## k_zeon

I am looking to load  json data to a treeview but don't know how.
can anyone help or give small example to help

many thanks.

----------


## dilettante

I'm not sure how useful something like that is.

Normally you don't expose JSON to users any more than they should be looking at XML, INI, or any other persistence format.  These are meant to store things like program settings that seldom change, descriptions of things like user interface layouts, or as data interchange formats.

If you really want this for some weird reason though it seems simple enough, for example:



Here I used different icon images to illustrate whether a node contains an "Object," "Array," "Property," or "Element."  Blue for parent nodes and red for leaf nodes.

----------


## k_zeon

> I'm not sure how useful something like that is.
> 
> Normally you don't expose JSON to users any more than they should be looking at XML, INI, or any other persistence format.  These are meant to store things like program settings that seldom change, descriptions of things like user interface layouts, or as data interchange formats.
> 
> If you really want this for some weird reason though it seems simple enough, for example:
> 
> 
> 
> Here I used different icon images to illustrate whether a node contains an "Object," "Array," "Property," or "Element."  Blue for parent nodes and red for leaf nodes.


thanks dilettante, that's just what i was looking for. i am trying to make a little app to help me create code that gets the json from web data.
usually i go through the json picking what i want and some times its hard to get the right combination
ie  p.item("root").item("blah").item("bitmore")

then sometimes i create a for next to load in arrays of data and type this all manually.

With this i can create a rightclick on a node and poss create the path and bits of code i need to paste into my own apps
saves me typing and trial and error to get the right path.

again , many thanks

----------


## k_zeon

> I'm not sure how useful something like that is.
> 
> Here I used different icon images to illustrate whether a node contains an "Object," "Array," "Property," or "Element."  Blue for parent nodes and red for leaf nodes.


Don't suppose you would have any example of syntax highlighting json similar to this



again, thanks

----------


## dilettante

First, be sure to note that my TreeView example is incomplete.

You have to consider that both property name values and string type data values can contain characters that are incompatible with an ANSI TreeView control.  Any characters outside the printable 7-bit ASCII range can be problematic, even if some ANSI printables might come out acceptably depending on the locale settings when your program gets run.

So you really need to escape funky characters or at least zap them to ? or some other place-filler symbol.


As for color-coding formatted JSON goes, no I do not have anything on hand for that.

But it seems simple enough to copy and hack JsonBag's Property Get JSON() serialization to create a Property Get JSONRTF() or a Property Get JSONHTML() that returns marked up JSON with colors.  It is just a matter of doing the necessary busy work.

----------


## Eduardo-

> Attachment 166227


I think a Rich TextBox could be more appropriate for this.

----------


## k_zeon

> First, be sure to note that my TreeView example is incomplete.
> 
> You have to consider that both property name values and string type data values can contain characters that are incompatible with an ANSI TreeView control.  Any characters outside the printable 7-bit ASCII range can be problematic, even if some ANSI printables might come out acceptably depending on the locale settings when your program gets run.
> 
> So you really need to escape funky characters or at least zap them to ? or some other place-filler symbol.
> 
> 
> As for color-coding formatted JSON goes, no I do not have anything on hand for that.
> 
> But it seems simple enough to copy and hack JsonBag's Property Get JSON() serialization to create a Property Get JSONRTF() or a Property Get JSONHTML() that returns marked up JSON with colors.  It is just a matter of doing the necessary busy work.


Hi dilettante. tks for reply. I will look in to hacking the JSON() and see if poss to create JSONRTF.

----------


## k_zeon

> I think a Rich TextBox could be more appropriate for this.


Hi Eduardo. Yes i have used this before to display VB6 code and works very well. However i dont know how to modify the existing code to take care of Json / Javascript
as above post , i will see about modifying the JsonBag to create a JsonRTF as that would be quite good as i use JsonBag to show in a textbox and nicely spaced out.
maybe i can take it a step closer to use a RichtextBox to display data. would be a good addition to JsonBag.

If i try to create a JsonRTF would i create a string that contains the Json and the richtext code and then apply to the richtextbox
or once text is on the Richtextbox loop through and colour code the text accordingly.

I am thinking option one as it goes through the serailisation to add richtext formatting as we go.

what do you think

thanks

----------


## Dancingbear1965

Hi
I am using JSONBag 2.5 with VB6 to try and create a series of Json messages. I have managed to write working procedures for all the messages bar one. This one needs an array within it. I don't seem to be able to grasp the way to contruct this code. Can somebody give me a few pointers?
So the complete message should look like this:




> {
>   "MaintenanceType": "Preventive",
>   "MaintenanceOrderNumber": "MO676578576",
>   "MaintenanceJobCode": "MNT113334",
>   "Tasks": [
>     {
>       "Task": "Changed hydraulic fluid in resovoir 1",
>       "TaskId": "HYD233432432",
>       "Operator": {
> ...


and my code looks like this:



```
'---------------------------------------------------------------------------------------
' Method : CFXMaintenancePerformed
' Author : Simon Smith
' Date   : 07/12/2016
' Purpose: Create CFX.ResourcePerformance.MaintenancePerformed message
' Updated:  13/12/2018
'---------------------------------------------------------------------------------------
Public Sub CFXMaintenancePerformed()

    CFXEnvelope                                             ' Add envelope data
    With JB
        ![MessageName] = "CFX.ResourcePerformance.MaintenancePerformed"
        With .AddNewObject("MessageBody")                     ' Add Message Body specifics
            .Item("MaintenanceType") = "Preventive"
            .Item("MaintenanceOrderNumber") = "MO676578576"
            .Item("MaintenanceJobCode") = "MNT113334"
            With .AddNewArray("Tasks")
                With .AddNewArray()
                    .Item("Task") = "Changed hydraulic fluid in resovoir 1"
                    .Item("TaskId") = "HYD233432432"
                    With .AddNewObject("Operator")
                        .Item("OperatorIdentifier") = "BADGE489435"
                        .Item("ActorType") = "Human"
                        .Item("LastName") = "Smith"
                        .Item("FirstName") = "Joseph"
                        .Item("LoginName") = "joseph.smith@abcdrepairs.com"
                    End With
                    .Item("ManHoursConsumed") = 0.75
                End With
                With .AddNewArray()
                    .Item("Task") = "Checked torque on main mount bolts"
                    .Item("TaskId") = "CHK3432434"
                    With .AddNewObject("Operator")
                        .Item("OperatorIdentifier") = "UID235434324"
                        .Item("ActorType") = "Human"
                        .Item("LastName") = "Smith"
                        .Item("FirstName") = "Joseph"
                        .Item("LoginName") = "joseph.smith@abcdrepairs.com"
                    End With
                    .Item("ManHoursConsumed") = "0.25"
                End With
            End With
        End With
    End With
    SendSmartMessage JB.JSON
End Sub
```

The issue is to do with the array formation I think.

Thanks Simon

----------


## dreammanor

Hi dilettante, I'd like to know if your JsonBag can read JavaScript objects, for example:



```
{
    start: 0,
    end: 15,
    source: "AAA",
    type: "BBB"
}
```

IMO, the main difference between JavaScript objects and JSON strings is that Key names have no double quotes.

----------


## wqweto

The format is called JSON5 - JSON for humans.

cheers,
</wqw>

----------


## dreammanor

> The format is called JSON5 - JSON for humans.
> 
> cheers,
> </wqw>


Oh, great. I like JavaScript. Thank you very much, wqweto.

----------


## fresh33

hi I can get the json report of the products between the date I want on my opencart site but how to write this incoming data in a text file with 6.0 etc. thanks


sample:

[{"UrunKodu":"7209","UrunAdi":"Apple phone 7 Plus Dolu Kasa Jet Black","Ucret":"35.0000"}]


write txt sample data

UrunKodu=7209,UrunAdi=Apple phone 7 Plus Dolu Kasa Jet Black,Ucret=35.0000


orjinal file:


[{"UrunKodu":"7209","UrunAdi":"Apple \u0130phone 7 Plus Dolu Kasa- Jet Black","Ucret":"35.0000","StokMiktari":"7"},{"UrunKodu":"7206","UrunAdi":"Apple \u0130phone 6S Plus Dolu Kasa- Gold","Ucret":"40.5000","StokMiktari":"7"},{"UrunKodu":"11821","UrunAdi":"Huawei GR5 \u015earj Ve Mikrofon Bordu","Ucret":"8.0000","StokMiktari":"2"},{"UrunKodu":"11765","UrunAdi":"Apple Iphone 8 \u00d6n Kamera+Sens\u00f6r Filmi","Ucret":"15.0000","StokMiktari":"8"},{"UrunKodu":"7230","UrunAdi":"Samsung Galaxy J2 Pro (J250) Kasa+ Kapak- Silver","Ucret":"10.0000","StokMiktari":"12"},{"UrunKodu":"7204","UrunAdi":"Apple \u0130phone 6S Plus Dolu Kasa- Beyaz","Ucret":"30.0000","StokMiktari":"7"},................]

----------


## xiaoyao

i test json2.js is the best(used time :16 ms,JsonBag,38ms)
---------------------------
In the case of large files, I eventually lost to the JS object
After all, that is native JS, VB still has to parse

50K JSON string to object, object to character
Json1, time: 18.162882
Json2, time: 16.407462
Json3, time: 41.214192
vbjson, time: 125.604048
JsonConverter, time: 40.81495
cDataJSON, time: 48.869498
JsonBag, time: 38.097204
---------------------------

50K large file, Json object to string
Json1, time: 28.468988
Json2, time: 17.008122
Json3, time: 38.91001
vbjson, time: 83.524864
JsonConverter, time: 18.332476
cDataJSON, time: 7.14318
JsonBag, time: 21.876478

----------


## Schmidt

> i test json2.js is the best(used time :16 ms,JsonBag,38ms)
> ---------------------------
> In the case of large files, I eventually lost to the JS object...


Your results are not really meaningfull, unless you include:
- the data you did use
- and your test-code

Here is an example, which shows, where the (JSON-)data came from (a Download-URL),
and it includes the complete test-code as well (based on the RC5-JSON-functions).



```
Option Explicit

Private sJSONinp As String

Private Sub Form_Load()
  Dim D As cDownloads
  Set D = New_c.Downloads 'download a larger JSON-file into an inp-string first
  With D.Download("https://www.sba.gov/sites/default/files/data.json")
    If .WaitForCompletion(15) Then sJSONinp = New_c.Crypt.UTF8ToVBString(.GetContentData)
  End With
End Sub

Private Sub Form_Click()
  New_c.Timing True
    Dim oJSON As cCollection
    Set oJSON = New_c.JSONDecodeToCollection(sJSONinp)  'decode the JSON-string to Object
  Debug.Print "JSON-decoding of " & Len(sJSONinp) & " Chars took:" & New_c.Timing
  
  New_c.Timing True
    Dim sJSONout As String
        sJSONout = oJSON.SerializeToJSONString 'serialize the Object back into a JSON-string
  Debug.Print "JSON-encoding to " & Len(sJSONout) & " Chars took:" & New_c.Timing
End Sub
```

Here the results on the quite large (*1.3MB*, not 50kB) test-input:


```
JSON-decoding of 1342902 Chars took: 43.84msec
JSON-encoding to 1321953 Chars took: 26.87msec
```

Olaf

----------


## xiaoyao

cConstructor ,RC5-JSON(cConstructor vbRichClient5.DLL)
This method runs the fastest, can you share the source code?
thank you.


```
Json1Code = "var JSON=function(){var m={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','""':'\\""','\\':'\\\\'},s={'boolean':function(x){return String(x)},number:function(x){return isFinite(x)?String(x):'null'},string:function(x){if(/[""\\\x00-\x1f]/.test(x)){x=x.replace(/([\x00-\x1f\\""])/g,function(a,b){var c=m[b];if(c){return c}c=b.charCodeAt();return'\\u00'+Math.floor(c/16).toString(16)+(c%16).toString(16)})}return'""'+x+'""'},object:function(x){if(x){var a=[],b,f,i,l,v;if(x instanceof Array){a[0]='[';l=x.length;for(i=0;i<l;i+=1){v=x[i];f=s[typeof v];if(f){v=f(v);if(typeof v=='string'){if(b){a[a.length]=','}a[a.length]=v;b=true}}}a[a.length]=']'}else if(x instanceof Object){a[0]='{';for(i in x){v=x[i];f=s[typeof v];if(f){v=f(v);if(typeof v=='string'){if(b){a[a.length]=','}a.push(s.string(i),':',v);b=true}}}a[a.length]='}'}else{return}return a.join('')}return'null'}};return{"
Json1Code = Json1Code & "copyright: '(c)2005 JSON.org',license:'http://www.crockford.com/JSON/license.html',stringify:function(v){var f=s[typeof v];if(f){v=f(v);if(typeof v=='string'){return v}}return null},parse:function(text){try{return!(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(text.replace(/""(\\.|[^""\\])*""/g,'')))&&eval('('+text+')')}catch(e){return false}}}}();"

Htm = "{""a"":""3333"",""b"":""abc"",""arr1"":[{""c"":""aa"",""d"":""bb""},{""e"":""dd""}]}"

Dim Js As ScriptControl, JsonStr As String
Set Js = New ScriptControl
Js.Language = "Javascript"
Js.AddCode "var JsonObj=" & Htm 

Js.AddCode Json1Code
JsonStr = Js.Eval("JSON.stringify(JsonObj)")  

MsgBox "JsonStr=" & JsonStr
```

Jsontxt from:"https://www.sba.gov/sites/default/files/data.json" （1.3MB SIZE)
----------------
StrToJsonObject+ObjectToSTR:

cConstructor ,Time(ms)：74.62878
Json1        ,Time(ms)：193.73442
Json2        ,Time(ms)：173.22444
Json3        ,Time(ms)：1166.90108
vbjson       ,Time(ms)：7827.51336
JsonConverter,Time(ms)：6587.33684
cDataJSON    ,Time(ms)：1351.50216
JsonBag      ,Time(ms)：2364.81656
----------------
JsonObjectToStr:

cConstructor ,Time(ms)：32.69154
Json1        ,Time(ms)：172.668
Json2        ,Time(ms)：155.47996
Json3        ,Time(ms)：1149.53676
vbjson       ,Time(ms)：7333.60354
JsonConverter,Time(ms)：6136.69794
cDataJSON    ,Time(ms)：558.91872
JsonBag      ,Time(ms)：1812.21622

----------


## Montclair

Searched the thread but couldn't find the fact that you need a reference to "OLE Automation" in your project, if you intend on using this class outside of the test project, otherwise you'll get compile errors of "User-defined type not defined" regarding "IUnknown" as used in at least one of the functions.

I'll also add that this is the best and easiest to use JSON parser I've tried for VB, and I've tried them all.  I was able to rewrite a custom DLL that interfaces with a web API that switched over from XML to JSON, with minimal work.  Changed a few object declarations and re-wrote how to reference the data in the collections, and this just works, allowing me to reference the JSON data as a VB collection, like I had been with MS' XML parser.  That made the transition a lot less work for me.

One thing to be careful of is not to ask for keys that may not be present (depending on the data you're getting from your source).  The .exists function, however, makes that a cinch. 

I wish the documentation was a little clearer on the various functions, as I had to dig through the sample code a bit to figure out how to do some things, but, like I said -- it just plain works.  

Well done and kudos to the author.

----------


## yokesee

> Searched the thread but couldn't find the fact that you need a reference to "OLE Automation" in your project, if you intend on using this class outside of the test project, otherwise you'll get compile errors of "User-defined type not defined" regarding "IUnknown" as used in at least one of the functions.
> 
> I'll also add that this is the best and easiest to use JSON parser I've tried for VB, and I've tried them all.  I was able to rewrite a custom DLL that interfaces with a web API that switched over from XML to JSON, with minimal work.  Changed a few object declarations and re-wrote how to reference the data in the collections, and this just works, allowing me to reference the JSON data as a VB collection, like I had been with MS' XML parser.  That made the transition a lot less work for me.
> 
> One thing to be careful of is not to ask for keys that may not be present (depending on the data you're getting from your source).  The .exists function, however, makes that a cinch. 
> 
> I wish the documentation was a little clearer on the various functions, as I had to dig through the sample code a bit to figure out how to do some things, but, like I said -- it just plain works.  
> 
> Well done and kudos to the author.


I've also been using it for a long time and it's one of the best.
You could pass your dll or the part of the code to convert to xml and if you can xml to json

a greeting

----------


## Montclair

> I've also been using it for a long time and it's one of the best.
> You could pass your dll or the part of the code to convert to xml and if you can xml to json
> 
> a greeting


Yeah, I tried some of the JSON to XML converters I found, and they pretty much don't work for my needs. Plus, the vendor changed the names of many of the fields, and it's just easier to rewrite (now) thanks to JsonBag.

If I'm misunderstanding and you're asking for code that I used when I switched from my vendor's XML API to their JSON API, it really wouldn't be much help as it's pretty vendor specific.

----------


## Dragokas

Suggestion:

2 new methods ItemSafe, ArraySafe:



```
Public Property Get ItemSafe(ByVal Key As Variant) As Variant
    If Me.Exists(Key) Then ItemSafe = Me.Item(Key)
End Property

Public Property Get ArraySafe(ByVal Key As Variant) As Variant
    
    If Me.Exists(Key) Then
        If IsNull(Key) Then Error9904
        If VarType(Key) = vbString Then
            If mIsArray Then Error9908
            
            If ExistsStr(Key) Then
                If IsObject(Values.Item(PrefixedKey)) Then
                    Set ArraySafe = Values.Item(PrefixedKey)
                Else
                    ArraySafe = Values.Item(PrefixedKey)
                End If
            Else
                Error990C
            End If
        Else
            If IsObject(Values.Item(Key)) Then
                Set ArraySafe = Values.Item(Key)
            Else
                ArraySafe = Values.Item(Key)
            End If
        End If
    Else
        Set ArraySafe = New Collection
    End If
    
End Property
```

Allowing to decrease the size of production code from this:

Example:


```
Private Sub JSON_ParseOzonAttrib(JB As JsonBag)
    
    Dim i As Long
    If JB.Exists("result") Then
    
        If JB.ItemIsJSON("result") Then

            For i = 1 To JB.Item("result").Count
                
                With JB.Item("result")(i)
                
                    If .Exists("name") Then
                    
                        Debug.Print .Item("name")
                    End If
                End With
            Next
        End If
    End If
End Sub
```

to this:


```
Private Sub JSON_ParseOzonAttrib2(JB As JsonBag)
    
    Dim i As Long
    For i = 1 To JB.ArraySafe("result").Count
                
        With JB.Item("result")(i)
                
            Debug.Print .ItemSafe("name")
        End With
    Next
End Sub
```

.ItemSafe / .ArraySafe - is a shortcut for .Item (not Object) / .Item (Object / Array) with additional check for .Exist( Key ) 

allowing to use them in-place without throwing the error exception.

PS. Yeah, better to merge both methods in one. Just my quick 5 cents.

----------


## dz32

trying to decide how useful a GetPath("obj1.obj2.obj3.value") function is. and maybe adding a .dumpKeys() method (from elroys CollectionEx class) for when you get lost in the hierarchy

the ability to handle single quoted strings would be great as well.



```
'quick external to class version todo: support element array indexes?
Function GetPath(o As JsonBag, path As String) As Variant

    Dim tmp() As String, o2 As JsonBag, isLast As Boolean
    
    If InStr(path, ".") < 1 Then
        If o.ItemIsJSON(path) Then
            Set GetPath = o.Item(path)
        Else
            GetPath = o.Item(path)
        End If
        Exit Function
    End If
    
    Set o2 = o
    tmp = Split(path, ".")
    For i = 0 To UBound(tmp)
        If i = UBound(tmp) Then isLast = True
        If o2.ItemIsJSON(tmp(i)) Then
            Set o2 = o2.Item(tmp(i))
            If isLast Then Set GetPath = o2
        Else
            If Not isLast Then Err.Raise 2121, "GetPath", "Object path terminates at " & tmp(i)
            GetPath = o2.Item(tmp(i))
        End If
    Next
    
End Function
```

----------


## dz32

tweaked it to add support for single quoted strings, None type, toArray(), getPath(path) (to sub object or value) and a fromFile(path) method

----------


## wqweto

This is a project that would benefit a lot from being hosted on github IMO, provided that it's the goto solution for JSON handling in VB6 land.

@dilletante: Send me a DM if you want to host it under https://github.com/VBForumsCommunity org with your user account there.

cheers,
</wqw>

----------


## xxdoc123

> tweaked it to add support for single quoted strings, None type, toArray(), getPath(path) (to sub object or value) and a fromFile(path) method


Function toArray() As Variant()
   Dim i As Integer
    If Not Me.IsArray Then Err.Raise 2122, "JsonBag", "Item is not an array"

    Dim ret()
    For i = 1 To o.Count ------which is o?
        push ret, o(i)
    Next

    toArray = ret
End Function

----------


## dz32

my bad i ported toarray and getpath in by eye from a previous version, fixed now with test code in place. thanks

----------


## germano.barbosa

Where do I get the official version of this file, is there a repository on gitHub? What's the latest version?

----------


## xiaoyao

how to put josn data by jsonbag?



```
{
    "projectCode":"xel0010",
    "productCode":"121",
    "plannedNum":1000,
    "planStartTime":"2021-09-08 00:00:00",
    "planEndTime":"2021-09-08 23:59:59",
    "workOrderCustomFieldsValue":[
        {
            "name":"key1",
            "value":"v1"
        },
        {
            "name":"key2",
            "value":"v2"
        }
    ]
}
```

----------


## dilettante

Something like:



```
Option Explicit

Private Sub Main()
    With New JsonBag
        .Whitespace = True
        .Item("projectCode") = "xel0010"
        .Item("productCode") = "121"
        .Item("plannedNum") = 100
        .Item("planStartTime") = "2021-09-08 00:00:00"
        .Item("planEndTime") = "2021-09-08 23:59:59"
        With .AddNewArray("workOrderCustomFieldsValue")
            With .AddNewObject()
                .Item("name") = "key1"
                .Item("value") = "v1"
            End With
            With .AddNewObject()
                .Item("name") = "key2"
                .Item("value") = "v2"
            End With
        End With
        MsgBox .JSON
    End With
End Sub
```

Result:



```
{
    "projectCode":"xel0010",
    "productCode":"121",
    "plannedNum":100,
    "planStartTime":"2021-09-08 00:00:00",
    "planEndTime":"2021-09-08 23:59:59",
    "workOrderCustomFieldsValue":[
        {
            "name":"key1",
            "value":"v1"
        },
        {
            "name":"key2",
            "value":"v2"
        }
    ]
}
```

----------


## xiaoyao

> Something like:
> 
> 
> 
> ```
> Option Explicit
> 
> Private Sub Main()
>     With New JsonBag
> ...


Its amazing, thank you great programmer, you are our role model

----------


## BooksRUs

I couldn't find another reference to a "Subscript out of range" error, except for this post...




> [*]Bug fix: Replacing an "array" item at the end of the "array" caused "Subscript out of range" error 9.


I have been successfully using JSON Bag version 2.4 for a long time, but just recently I'm running into this error.  I updated to 2.6 and am still getting the error here:




> Public Property Get ItemIsJSON(ByVal Key As Variant) As Boolean
>     'Reports True if an item is a JSON "array" or "object" and False
>     'if a simple value.
> 
>     If IsNull(Key) Then Error9904
>     If VarType(Key) = vbString Then
>         If mIsArray Then Error9908
> 
>         If ExistsStr(Key) Then
> ...


I'm testing to see if a sub-item is a JSON collection also, so I can pick and choose a few values out if it is.

A quick glance at the code and it appears that ExistsStr(Key) is the way to see if there is a Value before actually trying to use it.  Since I just need a TRUE or FALSE telling me if the subitem is JSON, I changed the code to below:




> Public Property Get ItemIsJSON(ByVal Key As Variant) As Boolean
>     'Reports True if an item is a JSON "array" or "object" and False
>     'if a simple value.
> 
>     If IsNull(Key) Then Error9904
>     If VarType(Key) = vbString Then
>         If mIsArray Then Error9908
> 
>         If ExistsStr(Key) Then
> ...


Hopefully this helps someone else.

----------


## dilettante

Using ExistsStr() there makes no sense.  It has already been established that Key is numeric (not String), and thus an index.  So using ExistsStr() there is invalid.

What your hack does is coerce the numeric Key to a String and then look for a child node that happens to match (by luck?) this String.  Most of the time this won't be true, so you have basically turned ItemIsJSON() into a random-usually-False generator when Key is numeric.

Frankly I don't see a bug at all there.  An error 9 exception _should_ be raised when a numeric Key value out of range is supplied.


Perhaps I'm not seeing it?  A small test case demonstrating the problem would help clarify the issue if it exists.

----------


## BooksRUs

> Using ExistsStr() there makes no sense.  It has already been established that Key is numeric (not String), and thus an index.  So using ExistsStr() there is invalid.
> 
> What your hack does is coerce the numeric Key to a String and then look for a child node that happens to match (by luck?) this String.  Most of the time this won't be true, so you have basically turned ItemIsJSON() into a random-usually-False generator when Key is numeric.
> 
> Frankly I don't see a bug at all there.  An error 9 exception _should_ be raised when a numeric Key value out of range is supplied.
> 
> 
> Perhaps I'm not seeing it?  A small test case demonstrating the problem would help clarify the issue if it exists.


So, I un-did the changes I made and let it run through the JSON file again to see where it was breaking.

Unfortunately, it looks like I should've looked at the JSON source before reacting.  For some reason, 1 record out of over 3,500 was passing in some invalid JSON characters.  I contacted the external source of the JSON and they fixed the problem on their end.  I re-ran the data through again without any issues.

Sorry for the trouble... looks like a false alarm!

----------


## webbiz

I know this is an old thread but it was provided to me as an example for parsing JSON.

I'm just not getting how it applies to what I need to do.

In the code provided in this JsonBag, I swapped out the example JSON with an actual response from finnhub.io that I wish to parse out.

Yes, I know that such a simple bit of JSON can be parsed using a simple string parser:




> {"c":165.02,"d":-0.56,"dp":-0.3382,"h":165.85,"l":163,"o":163.21,"pc":165.58,"t":1659728304}


For now, all I need is to extract the price located after the "c":.

However, I figured I'd try to learn something about JSON and parsing in the event I need to pull in a large amount of data to grab multiple items from it.

I notice that Parse/Reser button just makes a copy to the other textbox.  Not sure how that is parsing.  What am I missing?



And checking off 'Add Whitespace':



So it formats it nicely.  But exactly how does one use this to retrieve specific data values from the JSON based on the key?

I guess I misunderstand what JSON code parsing is.

Is there any parsing code for JSON where you supply the key name and get the data value back?

Obviously there is much I need to learn about this format.

TIA

----------


## loquat

seems newest version is v2.6?
https://www.vbforums.com/showthread....=1#post5366455

----------

