In Excel VBA on Windows, how to mitigate issue of dot syntax traversal of parsed JSON broken by IDE's capitalisation behaviour?
Asked Answered
T

1

2

In Excel VBA on Windows, how to mitigate problem of dot syntax traversal of parsed JSON broken by IDE's capitalisation behaviour?

Hi, answering my own question here. I have done some work with JSON in Excel VBA and lots of findings to post which I will do so in Q & A format https://stackoverflow.com/help/self-answer https://blog.stackoverflow.com/2011/07/its-ok-to-ask-and-answer-your-own-questions/

So elsewhere on stackoverflow one can see questions about parsing JSON in VBA but they seem to miss a trick or two.

To begin with, I resile from using custom JSON parsing libraries and instead use the ScriptControl's Eval method as the basis of all my JSON code. And also we express a preference from native Microsoft solutions.

In this first question I will show that in Excel VBA one can in fact use the dot syntax to traverse a JSON structure but that unfortunately this is broken by the VBA IDE's "helpfulness" with regards to capitalisation.

Below is some sample code where on the line labelled 1: we can see the text "objJSON.key1" and this code works until one uncomments

'Tools->References->
'Microsoft Script Control 1.0;  {0E59F1D2-1FBE-11D0-8FF2-00A0D10038BC}; C:\Windows\SysWOW64\msscript.ocx

Option Explicit
Option Private Module

Private Sub TestJSONParsingWithVBACallByName()

    Dim oScriptEngine As ScriptControl
    Set oScriptEngine = New ScriptControl
    oScriptEngine.Language = "JScript"
    
    Dim sJsonString As String
    sJsonString = "{'key1': 'value1'  ,'key2': { 'key3': 'value3' } }"
    
    
    Dim objJSON As Object
    Set objJSON = oScriptEngine.Eval("(" + sJsonString + ")")
1:  Debug.Assert objJSON.key1 = "value1"
    Debug.Assert objJSON.key2.key3 = "value3"
    
    '**** BUT IF UNCOMMENT NEXT LINE THIS AFFECTS ALL CAPITALISATION INSTANCES OF KEY1 INCLUDING LINE 1 WHICH THENCE BREAKS
2:  'Dim Key1 as Long

End Sub

Here is a screenshot before BeforeUncommentedAnnotated And after uncommenting Line 2 then Line1 is rewritten with the symbol 'key1' now given a capital 'K'.

AfterCommentedAnnoted

Now after some experimenting it seems that rewriting effect is limited to project scope, so other projects are not affected. This means one could isolate the issue by always using a separate project but then how would one marshall the object to the consuming project and thence access it, surely one hits the same issue again. So, project isolation is not really a solution.

One way is to ensure that the symbols do not clash and give the JSON keys some kind of prefix so here is an example

'Tools->References->
'Microsoft Script Control 1.0;  {0E59F1D2-1FBE-11D0-8FF2-00A0D10038BC}; C:\Windows\SysWOW64\msscript.ocx

Private Sub TestJSONParsingWithDotSyntaxAndKeyPrefixesToAvoidNameClash()

    Dim oScriptEngine As ScriptControl
    Set oScriptEngine = New ScriptControl
    oScriptEngine.Language = "JScript"
    
    Dim sJsonString As String
    sJsonString = "{'kKey1': 'value1'  ,'kKey2': { 'kKey3': 'value3' } }"
    
    
    Dim objJSON As Object
    Set objJSON = oScriptEngine.Eval("(" + sJsonString + ")")
1:  Debug.Assert objJSON.kKey1 = "value1"
    Debug.Assert objJSON.kKey2.kKey3 = "value3"
    
    '**** SAFE TO UNCOMMENT AS SYMBOLS DO NOT CLASH NOW
2:  'Dim Key1 As Long
End Sub

Somehow I do not like this, seems odd to have to change the JSON just so that VBA can access it. Besides, one may not have control of the source JSON.

There are other methods such as adding some javscript to the script engine to allow Javascript to do the accessing. With a hat-tip to user Codo https://stackoverflow.com/users/413337/codo here is a sample based on this approach...

'Tools->References->
'Microsoft Script Control 1.0;  {0E59F1D2-1FBE-11D0-8FF2-00A0D10038BC}; C:\Windows\SysWOW64\msscript.ocx

Private Sub TestJSONParsingWithMiniScript()
    'hat tip to Codo https://stackoverflow.com/users/413337/codo
    'Based on https://mcmap.net/q/56983/-excel-vba-parsed-json-object-loop#7300963  
    Dim oScriptEngine As ScriptControl
    Set oScriptEngine = New ScriptControl
    oScriptEngine.Language = "JScript"
    oScriptEngine.AddCode "function getProperty(jsonObj, propertyName) { return jsonObj[propertyName]; } "


    Dim sJsonString As String
    sJsonString = "{'key1': 'value1'  ,'key2': { 'key3': 'value3' } }"
    
    Dim objJSON As Object
    Set objJSON = oScriptEngine.Eval("(" + sJsonString + ")")
    Debug.Assert oScriptEngine.Run("getProperty", objJSON, "key1") = "value1"
    Debug.Assert oScriptEngine.Run("getProperty", oScriptEngine.Run("getProperty", objJSON, "key2"), "key3") = "value3"

End Sub

I like the technique of adding a script to the script engine however, I discovered a more native technique and that is to use VBA.CallByName and this is the technique shown in my answer.

I have not selected my own answer as definitive because I think (1) it seems the community can continue to improve our knowledge on JSON parsing in Excel VBA and (2) if someone discovers how to stop the capitalisation then that is an obvious winner.

This is Question 1 of series of 5. Here is the full series

Q1 In Excel VBA on Windows, how to mitigate issue of dot syntax traversal of parsed JSON broken by IDE's capitalisation behaviour?

Q2 In Excel VBA on Windows, how to loop through a JSON array parsed?

Q3 In Excel VBA on Windows, how to get stringified JSON respresentation instead of “[object Object]” for parsed JSON variables?

Q4 In Windows Excel VBA,how to get JSON keys to pre-empt “Run-time error '438': Object doesn't support this property or method”?

Q5 In Excel VBA on Windows, for parsed JSON variables what is this JScriptTypeInfo anyway?

Tickler answered 8/6, 2016 at 19:13 Comment(1)
exceldevelopmentplatform.blogspot.com/2018/05/… uses the bang syntax to solve this problem.Tickler
T
2

In the end I progressed with the following which uses the native VBA.CallByName

'Tools->References->
'Microsoft Script Control 1.0;  {0E59F1D2-1FBE-11D0-8FF2-00A0D10038BC}; C:\Windows\SysWOW64\msscript.ocx

Private Sub TestJSONParsingWithCallByName()

    Dim oScriptEngine As ScriptControl
    Set oScriptEngine = New ScriptControl
    oScriptEngine.Language = "JScript"

    Dim sJsonString As String
    sJsonString = "{'key1': 'value1'  ,'key2': { 'key3': 'value3' } }"


    Dim objJSON As Object
    Set objJSON = oScriptEngine.Eval("(" + sJsonString + ")")
    Debug.Assert VBA.CallByName(objJSON, "key1", VbGet) = "value1"
    Debug.Assert VBA.CallByName(VBA.CallByName(objJSON, "key2", VbGet), "key3", VbGet) = "value3"

End Sub
Tickler answered 8/6, 2016 at 19:13 Comment(7)
Debug.Assert calls shouldn't have side effects. You should extract the results into a local variable and assert in separate instructions, off these local variables. Debug calls should be treated as code that's only there, well, for debugging purposes; making them run your actual logic just isn't right.Tillie
Thanks for looking. I use Debug.Asserts all the time to no ill effect.Tickler
I'm not saying not to use Debug.Assert. I'm saying you should be able to completely remove Debug.Assert calls from your code without altering its behavior in any way.Tillie
Ok, I agree one removes them before going to production. Normally they sit in my test scripts and not in the main code. I use them here so the reader can see the value of the expressions.Tickler
I think it would be a pretty nice and welcome contribution to Code Review if you assembled your whole JSON-parsing solution into a CR post (the VBA tag over there has a number of similar "public knowledge" posts) - if you're open to receive feedback on any & all aspects of your working code anyway (that's what CR answers do). Got a CR account?Tillie
I have just now joined. The whole solution was in fact in response to some Google Maps API stack overflow question. I spent today breaking my findings into 5 question because I think they are interesting in their own separate ways. Do I go Ask Question in CodeReview and post the google maps solution?Tickler
Take a look at how to get the best value of Code Review, and Simon's checklist for writing a good Code Review question - that and of course the site's help center should answer most if not all of your questions. Also feel free to hop into The 2nd Monitor if you want to chat about the site and/or meet the regulars! =)Tillie

© 2022 - 2024 — McMap. All rights reserved.