Parse JSON file using VBScript - QTP/UFT - json

I am using QTP/UFT for automating my UI application. I would like to compare the UI values with the values from the REST API response. I'm new to VBScript and I have coded the method to call the REST API and get the response but i'm trying to find a solution how to parse the JSON using VBScript.
Please help me how i could parse the json response? (Code below)
OR if it's easier to accept the REST response in xml and parse it in VBS?
Appreciate your help and ideas. Thanks!
userName = "abc#xyz.com"
password = "blah.123"
acctNumber = "01999994201"
URL1="https://CXaic-blah.blah.ocp.blah.com:243/ic/api/integration/v1/flows/rest/blah_ACCNTSEARCH/1.0/accountSearch?accountNumber="
URL=URL1&acctNumber
Set objXmlHttpMain = CreateObject("Msxml2.ServerXMLHTTP")
on error resume next
objXmlHttpMain.open "GET",URL, False , userName, password
objXmlHttpMain.setRequestHeader "Accept", "application/json"
objXmlHttpMain.setRequestHeader "charset", "UTF-8"
objXmlHttpMain.send
restjsonresp = objXmlHttpMain.responseText
Below is the format of the json response i get:
{
"searchResponse":{
"element":[
{
"accType":"R",
"accountNumber":"1111111",
"accountStatus":"A",
"taxId":""
}
]
}
}

While I don't have QTP/UFT to test or verify the following code, I offer-up these JSON parsing solutions as-is for experimentation...
1) Inject a JScript block into a "htmlfile" object
Dim y, html : Set html = CreateObject("htmlfile")
Dim window : Set window = html.parentWindow
window.execScript "var json=" & restjsonresp & ";var e=new Enumerator(json.searchResponse.element);", "JScript"
While Not window.e.atEnd()
Set y = window.e.item()
Print "acctType: " & y.accType
Print "accountNumber: " & y.accountNumber
Print "accountStatus: " & y.accountStatus
Print "taxId: " & y.taxId
window.e.moveNext
Wend
2) Calling JScript code using the "MSScriptControl.ScriptControl" (requires 32-bit)
Dim x, eng : Set eng = CreateObject("MSScriptControl.ScriptControl")
eng.Language = "JScript"
eng.AddCode "function json() { return " & restjsonresp & "; }"
Dim oResp : Set oResp = eng.Run("json")
For Each x In oResp.searchResponse.element
Print "acctType: " & x.accType
Print "accountNumber: " & x.accountNumber
Print "accountStatus: " & x.accountStatus
Print "taxId: " & x.taxId
Next
3) Injecting a JScript block into "InternetExplorer.Application" (overkill? perfomance hit)
Dim z, objIE : Set objIE = CreateObject("InternetExplorer.Application")
objIE.Navigate2 "about:blank"
objIE.Toolbar = False
objIE.StatusBar = False
objIE.MenuBar = False
Do While objIE.Busy
Wait 1
Loop
objIE.Visible = False
objIE.document.open "text/html"
objIE.document.write "<script type='text/javascript'>document.json=" & restjsonresp & ";document.jsonEnum = new Enumerator(document.json.searchResponse.element);</script>"
objIE.document.close
While Not objIE.document.jsonEnum.atEnd()
Set z = objIE.document.jsonEnum.item()
Print "acctType: " & z.accType
Print "accountNumber: " & z.accountNumber
Print "accountStatus: " & z.accountStatus
Print "taxId: " & z.taxId
objIE.document.jsonEnum.moveNext
Wend
objIE.Quit
4) Using Demon's VbsJson object (a pure VBScript solution; albeit, with more code)
https://github.com/eklam/VbsJson
5) Use regular expressions (only for simple, well-defined JSON responses)
Dim re : Set re = New RegExp
re.IgnoreCase = True
re.Pattern = "\{\s*""searchResponse""\s*\:\s*\{\s*""element""\s*\:\s*\[\s*(\{\s*""accType""\s*\:\s*""(.*)""\s*,\s*""accountNumber""\s*\:\s*""(.*)""\s*,\s*""accountStatus""\s*\:\s*""(.*)""\s*,\s*""taxId""\s*\:\s*""(.*)""\s*\})\s*\]\s*\}\s*\}"
If re.Test(restjsonresp) Then
Dim matches : Set matches = re.Execute(restjsonresp)
Print "acctType: " & matches(0).SubMatches(1)
Print "accountNumber: " & matches(0).SubMatches(2)
Print "accountStatus: " & matches(0).SubMatches(3)
Print "taxId: " & matches(0).SubMatches(4)
End If
6) Convert JSON to XML, then parse the XML (lots of code, potential overkill)
https://github.com/pravynandas/JSONToXML
If you can control the response, and deliver XML instead of JSON, then it may be preferable to stick with XML for VBScript in QTP/UFT. Regardless, I hope something here is helpful.
Enjoy.

Related

Harvesting few fields from json response

I've written a script in vba to get some fields from a link which contains json data. As I've never worked with json in combination with vba, I don't have any idea which way I pursue. I heard that power query is an option but that would be difficult for me to cope up. Any alternative solution as to how I can get those fields depicted in the below image.
This is I've tried:
Sub CollectInformation()
Dim ReqHttp As New XMLHTTP60, Ohtml As New HTMLDocument
weblink = "https://torontolife.com/wp-content/themes/sjm-underscores/inc/neighbourhoods/2015/compiled.json"
With ReqHttp
.Open "GET", weblink, False
.send
Ohtml.body.innerHTML = .responseText
MsgBox .responseText ''I can see the valid response in the messagebox
End With
End Sub
Fields I'm interested in:
A piece of scattered chunck:
"features":[{"type":"Feature","properties":{"HOOD":"Trinity-Bellwoods","center":"43.65241687364585 -79.41651445205076","streetview":{"lat":43.6452785,"lng":-79.4131849,"heading":-25.74,"pitch":"-1.34"},"rankings":{"Housing":19.7,"Crime":39.4,"Transit":73.9,"Shopping":88,"Health":33.1,"Entertainment":97.9,"Community":61.3,"Diversity":9.9,"Schools":64.8,"Employment":73.2},"irank":42,"urank":42},
To be clearer:
The keys are "HOOD","Housing","Crime","Shopping".
I want to get their values.
This will do it
Option Explicit
Sub GetInfo()
'"HOOD","Housing","Crime","Shopping"
Dim strURL As String, strJSON As String, http As Object, json As Object
strURL = "https://torontolife.com/wp-content/themes/sjm-underscores/inc/neighbourhoods/2015/compiled.json"
Set http = CreateObject("MSXML2.XMLHTTP")
http.Open "GET", strURL, False
http.send
strJSON = http.responseText
Set json = JsonConverter.ParseJson(strJSON)("features")
Dim i As Long, key As Variant
For i = 1 To json.count
For Each key In json(i)
Select Case True
Case key = "properties"
Dim a As Object, key2 As Variant
Set a = json(i)(key)
For Each key2 In a.Keys
Select Case key2
Case "HOOD"
Debug.Print "Hood" & " " & a(key2)
Case "rankings"
Dim b As Object
Set b = a(key2)
Debug.Print "Housing" & " : " & b("Housing")
Debug.Print "Crime" & " : " & b("Crime")
Debug.Print "Shopping" & " : " & b("Shopping")
End Select
Next key2
End Select
Next key
Next i
End Sub
Example output:
Notes:
If you examine the JSON structure you can see it is as follows (sample)
The information we want in the dictionary returned is within "features" so we can extract that initially with:
Set json = JsonConverter.ParseJson(strJSON)("features")
This yields a collection (see the "[" at the start) of dictionaries. Within those dictionaries, we are interested in whenever the key "properties" appears, as those hold the items of interest. We can use a Select Case statement to filter for that key:
Select Case True
Case key = "properties"
We then set that to a variable, which is again a dictionary:
Set a = json(i)(key)
From the JSON image we can see again that we are interested in specific keys: HOOD and rankings; in order to get the items of interest ("HOOD","Housing","Crime","Shopping") .
HOOD and rankings return different datatypes.
HOOD returns a string:
So we can directly access the required value with the associated key:
a(key2)
I have added Debug.Print "Hood" & " " & a(key2) into the code to make it clear for you but have dropped the "Hood" prefix for my run as looks cleaner, in my opinion, in output.
rankings returns a dictionary, see the "{":
So, if we initially set that to a variable:
Set b = a(key2)
We can avoid looping the keys and directly access via the keys of interest i.e.:
Debug.Print "Housing" & " : " & b("Housing")
Debug.Print "Crime" & " : " & b("Crime")
Debug.Print "Shopping" & " : " & b("Shopping")
I have added some descriptor text so make the output clearer.
You don't need any external converter to play around with json data. There is already a robust method out there. To run the script you don't even add anything to the reference library other than what you did for xmlhttp requests. To get the corresponding values you need to use . dot operator to call it's keys. However, in some cases you might find some contradictory names like Status,Ranking,Properties which are already available in vba built-in items so you have to handle them using CallByName function like I've done below. It's even easier (the usage of it) than pulling any item from html elements out of a regular webpage.
This is how you can get your required items:
Sub FetchJsonInfo()
Const URL As String = "https://torontolife.com/wp-content/themes/sjm-underscores/inc/neighbourhoods/2015/compiled.json"
Dim Http As New XMLHTTP60, SC As Object, elem As Object
Dim resobject As Object, post As Object, R&
Set SC = CreateObject("ScriptControl")
SC.Language = "JScript"
With Http
.Open "GET", URL, False
.send
Set resobject = SC.Eval("(" + .responseText + ")")
.abort
For Each post In resobject.features
Set elem = CallByName(post, "properties", VbGet)
R = R + 1: Cells(R, 1) = elem.HOOD
Cells(R, 2) = elem.rankings.Housing
Cells(R, 3) = elem.rankings.Crime
Cells(R, 4) = elem.rankings.Shopping
Next post
End With
End Sub
Reference to add to the library:
Microsoft XML, v6.0

VBA POST json to API

I am trying to write VBA to post json to an api and parse the results into a worksheet. I can generate the JSON and am confident I can parse the result into what I need.
I know there are online tools to convert json to vba and back and browser add ins to post requests but I am the only one in the office that can do this so if I'm sick or on leave I would like to automate it. To do that I need to send the json and maybe store the response so I can parse it.
I'm new to coding so posting a request like this is over my head.
So far I have the following code to write the json. I would appreciate any help in getting me started. If needed I can post a sample of the json or the api I would like to post it to.
Apologies for the poor code I know I can improve it but want to get the json response as I think it will be the most challenging part.
EDIT Have made some progress. Can now send a JSON string to the URL and get the response. However it is always returning a failure:
"{
""message"": ""An error has occurred.""
}"
If I manually send the json with httpRequestor the result is returned correctly.
This seems to suggest that somewhere in the code the JSON is getting mixed up or modified somehow when it is being posted.
Updated code below. (Have removed any reference to actual data)
EDIT 2 fixed and working.
Removed quotes from
objHTTP.send ("Json")
Private Sub CommandButton21_Click()
Dim h_1 As String
Dim h_2 As String
h_1 = Range("A1")
h_2 = Range("B1")
h_3 = Range("C1")
h_4 = Range("D1")
h_5 = Range("E1")
h_6 = Range("F1")
sv_1 = 2
sv_2 = 2
sv_3 = 2
sv_4 = 2
sv_5 = 2
sv_6 = 2
For f = 15 To 21
v_1 = Range("A" & sv_1)
v_2 = Range("B" & sv_2)
v_3 = Range("C" & sv_3)
v_4 = Range("D" & sv_4)
v_5 = Range("E" & sv_5)
v_6 = Range("F" & sv_6)
y = "[{""" & h_1 & """:""" & v_1 & """,""" & h_2 & """:""" & v_2 & """,""" & h_3 & """:""" & v_3 & """,""" & h_4 & """:""" & v_4 & """,""" & h_5 & """:""" & v_5 & """,""" & h_6 & """:""" & v_6 & """ }]"
Range("A" & f).Value = y
sv_1 = sv_1 + 1
sv_2 = sv_2 + 1
sv_3 = sv_3 + 1
sv_4 = sv_4 + 1
sv_5 = sv_5 + 1
sv_6 = sv_6 + 1
Next f
Dim objHTTP As Object
Dim Json As String
Json = Range("A15")
Dim result As String
'Set objIE = CreateObject("InternetExplorer.Application") ' Don't think this is needed
'objIE.navigate "about:blank" ' Don't think this is needed
'objIE.Visible = False ' Don't think this is needed
Set objHTTP = CreateObject("MSXML2.ServerXMLHTTP")
URl = "http://myApi/iSendJsonTo"
objHTTP.Open "POST", URl, False
'objHTTP.setRequestHeader "User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)"
objHTTP.setRequestHeader "Content-type", "application/json"
objHTTP.send ("Json")
result = objHTTP.responseText
'objIE.document.Write result ' Don't think this is needed
'Some simple debugging
Range("A25").Value = result
Range("A26").Value = Json
Set objHTTP = Nothing
Here is the code that is sending the JSON, cleaned up a little.
Dim objHTTP As Object
Dim Json As String
Json = Range("A15") 'here I am pulling in an existing json string to test it. String is created in other VBA code
Dim result As String
Set objHTTP = CreateObject("MSXML2.ServerXMLHTTP")
URl = "http://myApi/iSendJsonto/"
objHTTP.Open "POST", URl, False
objHTTP.setRequestHeader "Content-type", "application/json"
objHTTP.send (Json)
result = objHTTP.responseText
'Some simple debugging
Range("A25").Value = result
Range("A26").Value = Json
Set objHTTP = Nothing

Google Maps Directions Only

I am working on a project where I want to display a google map in a WebBrowser object in on an excel sheet. I have accomplished this using this URL....
http://maps.google.com/?saddr=29.9390146,-90.0696139&daddr=29.962506,-90.1930133&f=d&output=embed
I would like to also display the driving directions only for this same link (or a different one).
I cannot find any info on how to get google maps to return the directions only via URL.
AHIA,
LarryR
You would want to check out the GoogleMaps Api:
Static Map API
Directions API
These API provides you with XML response where you can parse them to get the results displayed.
I made one to find time and distance which you can use as an example:
This is one of my earlier attempts so no XML is used but it will give you an idea how to work with responses from google.
Public Function GMap(origin_address As String, destination_address As String, Optional mode As Integer = 1, Optional datatype As Integer = 1)
Dim surl As String
Dim oXH As Object
Dim bodytxt As String
Dim time_e As String
Dim distanc_e As String
Dim strmode As String
If mode = 1 Then
strmode = "walking"
ElseIf mode = 2 Then
strmode = "driving"
ElseIf mode = 3 Then
strmode = "bicycling"
Else
GMap = "Invalid Mode"
Exit Function
End If
surl = "http://maps.googleapis.com/maps/api/distancematrix/xml?origins=;" & _
Replace(origin_address, " ", "+") & "&destinations=" & Replace(destination_address, " ", "+") & _
"&mode=" & strmode & "&sensor=false&units=metric"
Set oXH = CreateObject("msxml2.xmlhttp")
With oXH
.Open "get", surl, False
.send
bodytxt = .responseText
End With
bodytxt = Right(bodytxt, Len(bodytxt) - InStr(1, bodytxt, "<text>") - 5)
tim_e = Left(bodytxt, InStr(1, bodytxt, "</text>") - 1)
bodytxt = Right(bodytxt, Len(bodytxt) - InStr(1, bodytxt, "<text>") - 5)
distanc_e = Left(bodytxt, InStr(1, bodytxt, "</text>") - 1)
If datatype = 1 Then
GMap = CDbl(Replace(tim_e, "mins", ""))
ElseIf datatype = 2 Then
GMap = CDbl(Replace(distanc_e, "km", ""))
Else
GMap = "Invalid Data"
End If
Set oXH = Nothing
End Function
I have an Excel addin which does what you want: http://www.calvert.ch/geodesix/

Excel VBA macro using iTunes search API - fastest way to query & parse JSON results

I am trying to build Excel page from iTunes query data.
An example for Angry Birds app my query would look like:
https://itunes.apple.com/lookup?id=343200656&country=AL checking Albania iTunes
https://itunes.apple.com/lookup?id=343200656&country=DZ checking Algeria iTunes
... 150 more stores
My question is the most efficient way to do this query and parse response.
I only know how to to xmlhttp query. Please enlighten me as the better way to do this.
I have read some documentation for VB-JSON, Json.net, CDataSet, fastJSON, but cannot figure out how to get started trying those tools. Anyone have more VBA code examples pulling JSON or way to explain usage of these frameworks to a newb?
Dim innerHTML As Object
Dim myText As String
JsonCheck = ""
Set innerHTML = CreateObject("Microsoft.XMLHTTP")
With innerHTML
.Open "GET", iTunesAPI_link, False
.send
myText = .responsetext
End With
Set innerHTML = Nothing
If InStr(myText, ":0") = 20 Then 'no results found
result = "Down"
ElseIf InStr(myText, "Your request produced an error.") = 46 Then 'link error
result = HTMLCheck(human iTunes link)
Else 'found the app
result = call function which parses myText for desired fields
Endif
Here's a basic approach using the scriptcontrol:
Sub Tester()
Dim json As String
Dim sc As Object
Dim o
Set sc = CreateObject("scriptcontrol")
sc.Language = "JScript"
json = HttpGet("https://itunes.apple.com/lookup?id=343200656&country=AL")
'some json property names may be keywords in VBA, so replace with
' something similar....
json = Replace(json, """description""", """description_r""")
Debug.Print json
sc.Eval "var obj=(" & json & ")" 'evaluate the json response
'add some accessor functions
sc.AddCode "function getResultCount(){return obj.resultCount;}"
sc.AddCode "function getResult(i){return obj.results[i];}"
Debug.Print sc.Run("getResultCount")
Set o = sc.Run("getResult", 0)
Debug.Print o.kind, o.features, o.description_r
End Sub
Function HttpGet(url As String) As String
Dim oHTML As Object
Set oHTML = CreateObject("Microsoft.XMLHTTP")
With oHTML
.Open "GET", url, False
.send
HttpGet = .responsetext
End With
End Function
There's a worked-out approach in Codo's answer to this question: Excel VBA: Parsed JSON Object Loop
I had a similar issue with querying Salesforce's REST API and found dealing with JSON through ScriptControl ended up being unmanageable. I used the following library for parsing and converting to JSON and it's worked perfectly for me: https://code.google.com/p/vba-json/.
Dim JSON As New JSONLib
Dim Parsed As Object
Set Parsed = JSON.parse(jsonValue)
Debug.Print Parsed("resultCount")
Debug.Print Parsed("results")(0)
Using that library, I then wrapped up some of the common functionality for making web requests that I think would help you out: https://github.com/timhall/Excel-REST
Using these libraries, your code would look something like the following:
Dim iTunesClient As New RestClient
iTunesClient.BaseUrl = "https://itunes.apple.com/"
Dim Request As New RestRequest
Request.Format = json
Request.Resource = "lookup"
Request.AddQuerystringParam "id", "343200656"
Request.AddQuerystringParam "country", "AL"
Dim Response As RestResponse
Set Response = iTunesClient.Execute(Request)
' => GET https://itunes.apple.com/lookup?id=343200656&country=AL
If Response.StatusCode = 200 Then
' Response.Data contains converted JSON Dictionary/Collection
Debug.Print "Result Count: " & Response.Data("resultCount")
Dim i As Integer
For i = LBound(Response.Data("results")) To UBound(Response.Data("results"))
Debug.Print "Result " & i & ": " & Response.Data("results")(i)
Next i
Else
Debug.Print "Error: " & Response.Content
End If

Parsing JSON data from classic asp server?

After looking at several questions/answers here, I'm not seeing what I think I need. I have a page posting to an asp server page via ajax. The returning json string is showing up in the console on Firefox. I can see the post data going to the asp page, I can see the response which is
{ "firstname": "Christopher","lastname": "Romero","email": "cromero#marketscout.com","adminlvl": "00","message": "Thanks for logging in!" }
I can also see the values of the string above in the JSON tab in Console --> ALL --> JSON. There are no errors being reported inside the console. Here is my javascript:
$('#loginsub').click(function() {
$.ajax({
url: "logincheck.asp",
type: "POST",
data: $('#loginform').serialize(),
dataType: "json",
success: function(data) {
console.log(data);
//alert(data.firstname + ' ' + data.lastname);
//alert(data[0].firstname + ' ' + data[0].lastname);
$.trim(data);
var json = $.parseJSON(data);
alert(json.firstname);
}
});
});
Here is the asp that is running on the server on logincheck.asp:
set cmd = Server.CreateObject("ADODB.Command")
with cmd
.ActiveConnection = cnnopen
.CommandText = storedproc
.CommandType = adCmdStoredProc
dim intCount,intItem
for each item in odcformdata
select case vartype(odcformdata(item)) 'this is searching for the correct data type to put into the parameter [type] argument below. (integers, currency, dates, & strings)
case 2 : .Parameters.Append .CreateParameter("#"&cstr(item),adInteger,adParamInput,len(odcformdata(item)),odcformdata(item))
case 6 : .Parameters.Append .CreateParameter("#"&cstr(item),adCurrency,adParamInput,len(odcformdata(item)),odcformdata(item))
case 7 : .Parameters.Append .CreateParameter("#"&cstr(item),adDate,adParamInput,len(odcformdata(item)),odcformdata(item))
case 8 : .Parameters.Append .CreateParameter("#"&cstr(item),adVarChar,adParamInput,len(odcformdata(item)),odcformdata(item))
end select
next
end with
set rs = cmd.execute
'do stuff with returned results from select or leave blank if insert/delete/etc stored procedure
if rs.EOF = false then
'Build json array based on fields returned from stored proc.
dim arrJSON
arrJSON = "{ "
while not rs.EOF
for each fields in rs.Fields
arrJSON = arrJSON & """" & fields.name & """: """ & fields & ""","
next
rs.movenext
wend
arrJSON = arrJSON & """message"": ""Thanks for logging in!"","
arrJSON = left(arrJSON, len(arrJSON)-1) & " }"
response.write arrJSON
end if
set rs = nothing
set cmd = nothing
odcformdata.removeall
The alerts() in the javascript are not returning values that I would expect, I'm getting [object Object] returning on the alert when I'm expecting the JSON array/string to get printed out.
Anyone with some advice for me? I'm a jquery rookie and getting better, but this is getting on my nerves!
What does your first console.log(data) show?
This works for me:
http://jsfiddle.net/2tvCf/