ASP JSON Accessing key and value in loop - json

I'm using ASPJSON (https://www.aspjson.com/) to write JSON in Classic ASP / VBScript. I'm then attempting to loop through the JSON and access both the key and value. As it stands I can only access the value.
JSON
Set InitialGlaDataJsonForm = New aspJSON
With InitialGlaDataJsonForm.data
.Add "glaFormContent", InitialGlaDataJsonForm.Collection()
With .item("glaFormContent")
.Add "form", "myform"
.Add "email", "email#address"
.Add "phone", "012345"
.Add "name", "Joe Bloggs"
End With
End With
JSON Looks like this
{
"glaFormContent": {
"form": "myform",
"email": "email#address",
"phone": "012345",
"name": "Joe Bloggs"
}
}
Looping through the JSON, accessing the value
For Each element In InitialGlaDataJsonForm.data("glaFormContent")
response.write InitialGlaDataJsonForm.data("glaFormContent").item(element) & "<br>"
Next
The above returns the value of during each iteration, however I need to be able to get hold of the key, without writing it out.
So my question is how do I access the key in the same manner as the value?
Many thanks

When iterating the dictionary collection using a For statement the enumerator used by ASPJSON is the "key", in your case the variable element. If you use;
Response.Write element
the current key will be returned, you can then use;
Response.Write InitialGlaDataJsonForm.data("glaFormContent").item(element)
to retrieve the underlying value associated with the key.
Useful Links
Answer to How do you retrieve a JSON property from an array in aspJSON?

Related

VB Variable JSON String

In Visual Basic code, when I try to insert a variable into this JSON string it comes back
as a 400 bad request. How do I correctly feed this JSON string a variable?
Dim myJSON As String = "{""StoreId"":""12345"",""TerminalId"":""12345"",""CaptureMode"":""true"",""MerchantReferenceCode"":""VARIABLEINSERTEDHERE"",""InvoiceNumber"":""12345"",""TimeoutMinutes"":""5"",""ShowAddress"":""true"",""AddressRequired"":""true"",""TransactionTotal"":""33.33"",""TaxTotal"":""2.00"",""CustomerCode"":""12345""}"
Your JSON as it sits right now is an Object that looks like this:
{
"StoreId": "12345",
"TerminalId": "12345",
"CaptureMode": "true",
"MerchantReferenceCode": "VARIABLEINSERTEDHERE",
"InvoiceNumber": "12345",
"TimeoutMinutes": "5",
"ShowAddress": "true",
"AddressRequired": "true",
"TransactionTotal": "33.33",
"TaxTotal": "2.00",
"CustomerCode": "12345"
}
One option that you have is to create a new JObject, use the Add method (documentation) to build the object's properties, and then the ToString method (documentation) to serialize the object to JSON. This way you don't have to worry about properly formatting the JSON, just let the library do it for you.
Take a look at this example:
Dim myVariable = "VARIABLEINSTEREDHERE"
Dim request = New JObject()
request.Add("StoreId", 12345)
request.Add("TerminalId", 12345)
request.Add("CaptureMode", True)
request.Add("MerchantReferenceCode", myVariable)
request.Add("InvoiceNumber", 12345)
request.Add("TimeoutMinutes", 5)
request.Add("ShowAddress", True)
request.Add("AddressRequired", True)
request.Add("TransactionTotal", 33.33)
request.Add("TaxTotal", 2.00) ' taxation is theft
request.Add("CustomerCode", 12345)
Dim myJson = request.ToString()
Example: https://dotnetfiddle.net/FQDpVq
The short answer to the question you asked:
myjson = myjson.replace("VALUEPLACEHOLDER1","SoMeTHiNGeLSe")
Now, if you are talking about tricky pattern matching, then you will need to use regex if you want to approach this from a string-manipulation perspective. That sets you up for all sorts of unanticipated problems down the road with things you didn't anticipate, though, and you'll probably be happier in the long run if you embrace using JSON.
Try using the NewtonSoft JSON libraries. Then you can do something like:
dim myobj as new MyClass
myobj = jsonconvert.deserializeobject(of MyClass)(myjson)
That will turn your JSON string into an instance of MyClass called myobj, and you can access its properties directly, changing whatever you want:
myobj.MerchantReferenceCode = "SpecialMerchant"
Note that if the class definition for MyClass has properties that the JSON has no values for, they'll be present in the new class instance with no values. You can then set those values as you wish.
If the JSON has properties that don't exist in your class, they'll be dropped/lost in the conversion, so you do need to study your source data.
And you turn it back into a string again easily:
dim newjson as string = jsonconvert.serializeobject(myobj)

How to convert client-side AJAX to classic ASP server-side logic to get JSON from api

So I have a request to a JSON api working using client-side jquery and AJAX. Unfortunately, another api insists this be done from the server because of security concerns regarding the token. I'm a bit stumped. To begin, what I got working from client-side JavaScript looks like:
$.getJSON("https://api.xyz.com/mytoken/specificargument",function(data){...})
The function then fills data with JSON fields (or are they called properties?) as data.field1, data.field2, etc. These are then placed into their appropriate inputs with jquery code that lives inside the {...}. It's very straightforward.
I have read that this (i.e., obtaining the JSON string, not parsing it) can be done on the server with
Set objJSON = jsObject()
objJSON("apikey") = "mytoken"
Set objJSON("arg1") = jsObject()
objJSON("arg1")("arg1") = "specificargument"
set objXMLhttp = Sever.Createobject("MSXML2.ServerXMLHTTP")
objXMLhttp.open "POST","https://api.abc.com", false
objXMLhttp.setRequestHeader "Content-type","application/json"
objXMLhttp.setRequestHeader "Accept","application/json"
objXMLhttp.send objJSON.jsString
strResponse = objXMLhttp.responseText
Set objXMLhttp = Nothing
So that's pretty useful, except the posting says I need to use "appropriate declarations, includes, etc." So I thought it would be simple to find these, but querying for classic ASP JSON yields very confusing results. Can someone help with these:
what do I need to do to properly use the aspjson library for the above?
how do I pass "specificargument" above. What I've written is a bit of a mess and I'm sure incorrect. On the client side, the token and argument are part of the querystring. How does this work for the jsObject?
Thank you.
The example code you have posted appears to be using the aspjson - JSON serializer for VBScript based ASP server technology library. One key thing in that statement is "JSON Serializer", it will only serialise from object to string, not the other way around which makes it kind of useless for most scenarios.
This is purely my opinion but a well-maintained library that will do both is JSON object class By RCDMK. The examples on the GitHub page are pretty simple to follow, but there are some examples of its usage on this very site.
Here is a quick example of its usage inside an ASP page;
<% Option Explicit %>
<!-- #include virtual="/scripts/jsonObject.class.asp" -->
<%
Dim JSON, parsedJSON
Dim jsonString: jsonString = "[{ ""strings"" : ""valorTexto"", ""numbers"": 123.456, ""arrays"": [1, ""2"", 3.4, [5, 6, [7, 8]]], ""objects"": { ""prop1"": ""outroTexto"", ""prop2"": [ { ""id"": 1, ""name"": ""item1"" }, { ""id"": 2, ""name"": ""item2"", ""teste"": { ""maisum"": [1, 2, 3] } } ] } }]"
Call init()
Sub init()
Response.LCID = 2057
Set JSON = New JSONobject
Call Response.Write("<h2>JSON String</h2>")
Call Response.Write("<pre>" & jsonString & "</pre>")
Call Test_ParseJSON()
Call Test_WriteJSON()
End Sub
Sub Test_ParseJSON()
Call Response.Write("<h2>Parsing JSON</h2>")
Set parsedJSON = JSON.Parse(jsonString)
Call Response.Write("<pre>parsedJSON(0).Value(""objects"").Value(""prop1"") = """ & parsedJSON(0).Value("objects").Value("prop1") & """</pre>")
End Sub
Sub Test_WriteJSON()
Call Response.Write("<h2>Writing JSON</h2>")
Call parsedJSON(0).Value("objects").Change("prop1", "hello test")
Call Response.Write("<pre>" & parsedJSON.Serialize() & "</pre>")
End Sub
%>
Outputs:
JSON String
[{ "strings" : "valorTexto", "numbers": 123.456, "arrays": [1, "2", 3.4, [5, 6, [7, 8]]], "objects": { "prop1": "outroTexto", "prop2": [ { "id": 1, "name": "item1" }, { "id": 2, "name": "item2", "teste": { "maisum": [1, 2, 3] } } ] } }]
Parsing JSON
parsedJSON(0).Value("objects").Value("prop1") = "outroTexto"
Writing JSON
[{"strings":"valorTexto","numbers":123.456,"arrays":[1,"2",3.4,[5,6,[7,8]]],"objects":{"prop1":"hello test","prop2":[{"id":1,"name":"item1"},{"id":2,"name":"item2","teste":{"maisum":[1,2,3]}}]}}]
From the original poster: Typically, my situation may not generalize well, but because I found a very simple solution, I'll post it here in case it helps anybody else finding this.
First of all, for this particular api, the token and other argument were passed in the querystring and the method was GET, not POST. Thus the .send command had no argument. That's all it took to get the JSON string returned. Thus:
set objXMLhttp = Server.Createobject("MSXML2.ServerXMLHTTP")
objXMLhttp.open "GET","https://api.abc.com/argument1/?token=mysecret", false
objXMLhttp.setRequestHeader "Content-type","application/json"
objXMLhttp.setRequestHeader "Accept","application/json"
objXMLhttp.send
strResponse = objXMLhttp.responseText
By the way, if I HAD needed to send a JSON-formatted argument, as has been pointed out by others, often (for simple structures) it is easy to simply create this instead of using a 3rd-party library. (E.g., from a post on this site: {"Email":"asdf#hotmail.com", "firstname":"joe", "lastname":"smith"} ).
Finally, just as it is easy to create simple JSON strings, returned data, if simple, can easily be parsed. In my case, the return always had a brace at the beginning and end, then was a simple JSON comma-delimited list of colon-pairs. This was easily split into a vbscript array (remember, my post was for classic ASP) and parsed into a dictionary (ParseJSON) as follows (note I needed to strip off all the quotation marks):
strResponse = Left(strResponse,Len(strResponse)-1) ' remove right-brace
strResponse = Right(strResponse,Len(strResponse)-1)
Dim ParseJSON
Set ParseJSON = CreateObject("Scripting.Dictionary")
ParseJSON.CompareMode = vbTextCompare
ArryJSON = Split(strResponse,",")
' parse into a dictionary
For Each jPair In ArryJSON
' take jPair apart and insert into dictionary
onePair = Split(jPair,":")
aa = onePair(0)
aa = Left(aa,Len(aa) - 1) ' remove quotation mark
aa = Right(aa,Len(aa) - 1)
bb = onePair(1)
bb = Left(bb,Len(bb) - 1)
bb = Right(bb,Len(bb) - 1)
ParseJSON.Add aa,bb
Next

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

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.
Here is a prior question In Excel VBA on Windows, how to mitigate issue of dot syntax traversal of parsed JSON broken by IDE's capitalisation behaviour? upon which this question builds. It shows how using VBA.CallByName is more robust
than using the dot syntax to traverse a parsed JSON object. Also another prior question In Excel VBA on Windows, how to loop through a JSON array parsed? shows how it also can
be used to access array elements. But CallByName returns a curious variable type that appears in Watch window as Object/JScriptTypeInfo
and if one type Debug.Print in the immediate window (or hovers over the variable) one gets the uninformative "[object Object]". In another question
in the series In Excel VBA on Windows, how to get stringified JSON respresentation instead of “[object Object]” for parsed JSON variables? I present some debugging "sugar" that allows nice inspection of variables. In a fourth question In Windows Excel VBA,how to get JSON keys to pre-empt “Run-time error '438': Object doesn't support this property or method”?, whilst investigating
how to query a JSON object for a member I discover a hasOwnProperty() method that seems attached to a JScriptTypeInfo object.
So in this question I ask, what exactly is this JScriptTypeInfo anyway?
This is Question 5 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?
One possible place to look is in the type library for the ScriptControl as this is the library which emanates this type.
The full details of this type on my machine are
Libary Name: Microsoft Script Control 1.0 (Ver 1.0)
LIBID: {0E59F1D2-1FBE-11D0-8FF2-00A0D10038BC}
Location: C:\wINDOWS\SysWOW64\msscript.ocx
Using both VBA IDE's Object Browser and OLEVIEW.exe which disassembles type library I can no trace of the interface JScriptTypeInfo or the method hasOwnProperty.
But isn't it the case that the script engine hosts language implementations, such as VBScript and JScript (Microsoft name for Javascript).
So perhaps we should hunt for a JScript implementation DLL and indeed there is one here are details
Libary Name: Microsoft JScript Globals
LIBID: {3EEF9759-35FC-11D1-8CE4-00C04FC2B085}
Location: C:\wINDOWS\SysWOW64\jscript.dll
which on my machine is not registered and so not in my list of Tools->References libraries or in OLEVIEW.exe. I was lucky to find whilst poking around.
Here is some output from OLEVIEW giving an exceprt of the type library
[
uuid(3EEF9758-35FC-11D1-8CE4-00C04FC2B097)
]
dispinterface ObjectInstance {
properties:
methods:
[id(0x0000044c)]
StringInstance* toString();
[id(0x0000044d)]
StringInstance* toLocaleString();
[id(0x0000044e)]
VARIANT hasOwnProperty(VARIANT propertyName);
[id(0x0000044f)]
VARIANT propertyIsEnumerable(VARIANT propertyName);
[id(0x00000450)]
VARIANT isPrototypeOf(VARIANT obj);
[id(0x00000451)]
ObjectInstance* valueOf();
};
This above shows the hasOwnProperty to be a method of a IDispatch interface (or dispinterface) necessary to work with VBA object's declared of type Object (e.g. Dim foo as Object)
Registering the type library with regsvr32 appears to do nothing. One must browse to the file in Tools References to view in VBA's object browser.
We can be pretty sure about this JScript.dll file because using Process Explorer we can see the dll being loaded when executing the line oScriptEngine.Language = "JScript"
In the lack of a registered type library I loaded the file JScript.dll into Notepad++ and searched for .J.S.c.r.i.p.t.T.y.p.e.I.n.f.o as a regular expression and found a hit. Bingo!
Not only is there an ObjectInstance which would describe most of the variables a VBA program encounters but also there is an ArrayInstance which is intriguing, perhaps we can use Javascript's own array functions
or at least a subset as documented in JScript.dll's type library. Here is some sample code
'Tools->References->
'Microsoft Script Control 1.0; {0E59F1D2-1FBE-11D0-8FF2-00A0D10038BC}; C:\Windows\SysWOW64\msscript.ocx
'and FYI/browsing capabilities Microsoft JScript Globals; C:\wINDOWS\SysWOW64\jscript.dll
Option Explicit
Private Sub TestJSONParsingWithCallByName5()
Dim oScriptEngine As ScriptControl
Set oScriptEngine = New ScriptControl
oScriptEngine.Language = "JScript"
Dim sJsonString(0 To 1) As String
sJsonString(0) = "{'key1': 'value1' ,'key2': { 'key3': 'value3' } }"
sJsonString(1) = "[ 1234, 2345, 3456, 4567, 5678, 6789 ]"
Dim objJSON(0 To 1) As Object
Set objJSON(0) = oScriptEngine.Eval("(" + sJsonString(0) + ")")
Set objJSON(1) = oScriptEngine.Eval("(" + sJsonString(1) + ")")
Debug.Assert objJSON(0).hasOwnProperty("key1")
Debug.Assert objJSON(0).hasOwnProperty("key2")
Debug.Assert CallByName(objJSON(1), "length", VbGet) = 6
Debug.Assert CallByName(objJSON(1), "0", VbGet) = "1234"
'* Is objJSON(1) an ArrayInstance?
'* does it support the reverse method of the ArrayInstance object?
'Call objJSON(1).Reverse '* reverse gets capitalised into Reverse ... grrrr
Call CallByName(objJSON(1), "reverse", VbMethod) '* so use CallByName as solution to "helpful" capitalisation
'* Yes, the elements are reversed!
Debug.Assert CallByName(objJSON(1), "length", VbGet) = 6
Debug.Assert CallByName(objJSON(1), "0", VbGet) = "6789"
Stop
'** And now we know objJSON(1) is an ArrayInstance we can have some fun with array operations
Dim objSplice As Object
Set objSplice = CallByName(objJSON(1), "splice", VbMethod, 2, 1)
Debug.Assert CallByName(objJSON(1), "length", VbGet) = 5
Debug.Assert CallByName(objSplice, "length", VbGet) = 1
Dim objSlice As Object
Set objSlice = CallByName(objJSON(1), "slice", VbMethod, 2)
Debug.Assert CallByName(objJSON(1), "length", VbGet) = 5
Debug.Assert CallByName(objSlice, "length", VbGet) = 3
Stop
Call CallByName(objJSON(1), "sort", VbMethod)
Debug.Assert CallByName(objJSON(1), "join", VbMethod) = "1234,2345,3456,5678,6789"
Debug.Assert CallByName(objJSON(1), "join", VbMethod, " ") = "1234 2345 3456 5678 6789"
Stop
Debug.Assert CallByName(objJSON(1), "pop", VbMethod) = "6789"
Debug.Assert CallByName(objJSON(1), "length", VbGet) = 4
Stop
End Sub
SUMMARY: JScriptTypeInfo is something to show in the VBA IDE watch window and the return of the VBA function TypeName() but which really hides a number of objects that can be found in JScript.dll.
I suppose it can be described as polymorphic, perhaps better to describe it as late binding. To view capabilities use Tools-References and browse to JScript.dll.

Extracting values by parsing JSON with Classic ASP

I am using Classic ASP and ASPJSON (http://www.aspjson.com/) to try to extract data returned in JSON format when sending an email via the SendGrid API.
This is some sample JSON data:
{
"message":"error",
"errors":[
"some errors"
]
}
I can access the values of the "message" section via:
Set oJSON = New aspJSON
oJSON.loadJSON(string_containing_json)
json_status = ap(oJSON.data("message"))
response.write(json_status)
However, I can't access the values of the "errors" section as it's sort of one level down.
Is it possible to get at that?
The errors are stored as a Dictionary object. You can enumerate them like this:
dim errors : set errors = oJSON.data("errors")
dim curError
for curError = 0 to errors.Count -1
Response.Write( errors(curError))
Response.Write( "<br />")
next

Object required: '[undefined]' error when looping through JSON data

I am working with the Google Translation API, which returns results in JSON format - e.g.
{
"data": {
"translations": [
{
"translatedText": "Hola mundo"
},
{
"translatedText": "Te amo"
},
{
"translatedText": "queso"
}
]
}
}
I am trying to parse the JSON data using Classic ASP.
I'm using ASPJSON (http://www.aspjson.com/) to parse the JSON data.
I can get so far with reading the data - e.g. (where "BackFromGoogle") is the objXML.responseText from a MSXML2.ServerXMLHTTP call.
Set oJSON = New aspJSON
oJSON.loadJSON(BackFromGoogle)
For Each translation In oJSON.data("data") 'iterate through data
Set this = oJSON.data("data").item(translation)
Next
If I then try:
For Each translation In oJSON.data("data") 'iterate through data
Set this = oJSON.data("data").item(translation)
Response.Write this.item("translations").item("translatedText")
Next
Then I get this error:
Microsoft VBScript runtime error '800a01a8'
Object required: '[undefined]'
For this line:
Response.Write this.item("translations").item("translatedText")
I am very stuck working out the syntax to allow me to access the individual values of the "translatedText" lines.
Is it possible to access them?
Got this working in the end.
Found the answer via the solution here:
VbScript Deserialize JSON
This sorted it:
Set oJSON = New aspJSON
oJSON.loadJSON(BackFromGoogle)
For Each result In oJSON.data("data")("translations")
Set this = oJSON.data("data")("translations").item(result)
response.Write this.item("translatedText") & "<br>"
Next