REQUEST A DEMO

Consuming JSON in ClearBasic

Recently I had the need to consume JSON in ClearBasic.

For example, I make a request to a web service, and the service returns a result set in JSON format. I want to display those results within Clarify.

JSON

JSON (JavaScript Object Notation) is a lightweight data-interchange format. JSON is a pretty popular data transfer format, especially for the web.

Here’s an example of a simple JSON object:

{
FirstName: Joe, 
LastName: SixPack, 
Programming Languages: 
[ClearBasic, Perl, Ruby]
}

A real-world JSON example

I can make an HTTP request to a Google API to perform a web search. The result will be in a JSON format.

For example, a search for “fcsdk powershell” can be made by using this URL:

http://ajax.googleapis.com/ajax/services/search/web?v=1.0&q=fcsdk%20powershell

The result will be this:

{"responseData": 
{"results":[{"GsearchResultClass":"GwebSearch",
"unescapedUrl":"http://blogs.dovetailsoftware.com/blogs/gsherman/archive/2007/04/25/using-the-fcsdk-in-powershell.aspx",
"url":"http://blogs.dovetailsoftware.com/blogs/gsherman/archive/2007/04/25/using-the-fcsdk-in-powershell.aspx",
"visibleUrl":"blogs.dovetailsoftware.com",
"cacheUrl":"http://www.google.com/search?qu003dcache:u9RLwKjiIPYJ:blogs.dovetailsoftware.com",
"title":"Gary Sherman : Using the u003cbu003efcSDKu003c/bu003e in u003cbu003ePowerShellu003c/bu003e",
"titleNoFormatting":"Gary Sherman : Using the fcSDK in PowerShell",
"content":"Apr 25, 2007 u003cbu003e...u003c/bu003e Years ago, if I wanted to u0026quot;scriptu0026quot; Clarify , 
I would use UNIX shell scripts, including UNIX mini languages such as sed and awk, u003cbu003e...u003c/bu003e"},
{"GsearchResultClass":"GwebSearch",
"unescapedUrl":
"http://blogs.dovetailsoftware.com/blogs/gsherman/archive/2007/05/14/configuring-logging-in-the-fcsdk-without-a-config-file.aspx",
"url":"http://blogs.dovetailsoftware.com/blogs/gsherman/archive/2007/05/14/configuring-logging-in-the-fcsdk-without-a-config-file.aspx",
"visibleUrl":"blogs.dovetailsoftware.com",
"cacheUrl":"http://www.google.com/search?qu003dcache:VNz7QDYq4l4J:blogs.dovetailsoftware.com",
"title":"Gary Sherman : Configuring logging in the u003cbu003efcSDKu003c/bu003e without a config file",
"titleNoFormatting":"Gary Sherman : Configuring logging in the fcSDK without a config file",
"content":"May 14, 2007 u003cbu003e...u003c/bu003e This same scenario will apply not only to u003cbu003ePowerShellu003c/bu003e scripts,
 but to any .NET app (such as C# or VB.NET) that uses the u003cbu003efcSDKu003c/bu003e. u003cbu003e...u003c/bu003e"}],
"cursor":{"pages":[{"start":"0","label":1}],"estimatedResultCount":"2","currentPageIndex":0,
"moreResultsUrl":"http://www.google.com/search?oeu003dutf8u0026ieu003dutf8u0026sourceu003dudsu0026startu003d0u0026hlu003denu0026qu003dfcsdk+powershell"}}, 
"responseDetails": null, "responseStatus": 200}

It may look a little scary, but its really not once you break it down.

There’s an object called responseData, and it has a properties such as estimatedResultCount, responseStatus, and results. results is actually an array of objects. Each of these objects has its own properties, such as url, title and visibleUrl,

I want to be able to parse that in ClearBasic and do something with that data – for example, show it in a grid or a some other type of list.

HTTP Request

First, lets make the HTTP request to get the string of data back.

Function GetHTTPResponse (url As String, method As String, data As String) as String
    Dim oHttp as Object
    Set oHttp = CreateObject("microsoft.XmlHttp")
    oHttp.open method, url, False
    oHttp.send ByVal data
    GetHTTPResponse = oHttp.ResponseText
End Function

Dim url as String
Dim terms as String
Dim json as String
terms = "dovetail software"
terms = "fcsdk powershell"
url = "http://ajax.googleapis.com/ajax/services/search/web?v=1.0&q=" & terms
json = GetHTTPResponse (url,"GET", "")

Turn the JSON string into an object

Next, we’ll turn that big ugly string of data into an object.

Typically, I would use a JSON parser. The JSON website has links to parsers in a boatload of languages. Not surprisingly, Clarify’s proprietary ClearBasic languages isn’t one of them. But that’s OK, because JavaScript can do this for us.

To convert a JSON text into an object, you can use the eval() function in JavaScript. eval() invokes the JavaScript compiler. Since JSON is a proper subset of JavaScript, the compiler will correctly parse the text and produce an object structure.

But how can we call JavaScript from within ClearBasic?

We’ll use the Microsoft Script Control. This gives us access to the Microsoft scripting engine, including JScript.

Set scriptControl = CreateObject("MSScriptControl.ScriptControl")
scriptControl.Language = "JScript"    
Set searchResultObject = scriptControl.Eval("(" + json + ")")

The code creates a ScriptControl object, sets its language to JScript, and then does an eval() on our json, which gives us back a proper object.

We can then access the properties of the object, such as the responseStatus:

Debug.Print "Search Response Status: " & searchResultObject.responseStatus

Accessing an array within an object

This is where things get a little tricky. I would like to simply put the searchResultObject.results array into a ClearBasic array, but this doesn’t work. So, I’ll inject some Javascript functions into the ScriptControl , and then pull the data out of the ScriptControl via primitive datatypes (string, integer, etc.).

A JavaScript function to get the number of results

Here’s the Javascript that I want:

function getNumberOfResults (searchResultObject) {
   return searchResultObject.responseData.results.length;
}

To “inject” that function into the ScriptControl, I put the function into a string, and then call on the AddCode method:

Sub AddFunctionToScriptObject(scriptControl, functionDefinition)
   scriptControl.AddCode functionDefinition
End Sub

Dim getNumberOfResultsFunction As String
getNumberOfResultsFunction = "function getNumberOfResults(searchResultObject){ return searchResultObject.responseData.results.length;}"
AddFunctionToScriptObject scriptControl, getNumberOfResultsFunction

Now, I can call on this function to get the number of results

numberOfResults = scriptControl.Run("getNumberOfResults", searchResultObject)
Debug.Print "Number of Search Results: " & CStr(numberOfResults)

Getting a property of an object within an array

Similarly, I’ll inject a function to return a property of one result object.

getResultByIndexFunction = "function getPropertValueForResultByIndex (searchResultObject, index, prop){ return searchResultObject.responseData.results[index][prop];}"   

AddFunctionToScriptObject scriptControl, getResultByIndexFunction

Notice that the index of the results array, and the property to return, are inputs to the function.

I can now get the url of the first result (index = 0) like this:

URL = scriptControl.Run("getPropertValueForResultByIndex", resultObject, 0, "url")

That’s all the hard part. Now I can rinse, lather, repeat for all the other properties, and I can loop over each result.

Rinse, Lather, Repeat

For convenience, I’ve created a user-defined type for a search result:

Type SearchResult
    Url as String
    Id as String
    Title as String
    Content as String
End Type

A subroutine to populate a Search Result object:

Sub getSearchResultByIndex(scriptControl as Object, resultObject as Object, index as Integer)
    oneResult.Title = scriptControl.Run("getPropertValueForResultByIndex", resultObject, index, "titleNoFormatting")
    oneResult.Content = scriptControl.Run("getPropertValueForResultByIndex", resultObject, index, "content")
    oneResult.Id = index
    oneResult.URL = scriptControl.Run("getPropertValueForResultByIndex", resultObject, index, "url")
End Sub

And a loop to get and print each result:

For index = 0 to numberOfResults - 1
    getSearchResultByIndex scriptControl, searchResultObject, index
    Debug.Print ""
    Debug.Print "Search Result # " & cstr(index)
    Debug.Print "Title: " & oneResult.Title    
    Debug.Print "URL: " & oneResult.Url
    Debug.Print ""
Next index

 

An example of the output (using cbbatch as the ClearBasic engine):

json

And there you have it – from ClearBasic, we’ve made an HTTP request to Google, performed a search which returned a result set in JSON, parsed the JSON, and got access to all that data from within CB.

Code

The complete code example is available on Pastie.

 

Summary

Now that you know how to consume JSON from ClearBasic, you can consume data from all sorts of sources, including many web services.

Rock on.