+//*****************************************************************************
+//*** Author: Sean Bamforth ***
+//*** SELECT Computer Systems Ltd ***
+//*** April / May 2011 ***
+//*** JSON Client interface for talking to JSON / restful services. ***
+//*** You're free to use and modify this library in your own projects. ***
+//*** You're not free to redistribute this package without permission ***
+//*** from SELECT Computer Systems. ***
+//*****************************************************************************
+// cSelectJSON is the JSON Class, but there's a global object called oSelectJSON
+// set psData to your JSON Structure (as a string)
+// You can directly access JSON Values via dot notation
+// e.g. get JSONValue of oSelectJSON "results[0].geometry.location.lat" to nLAT
+// or you can pull the JSON structure into a tJSONDictionary and move through that.
+//Usage examples (with google maps api):
+// tJSONDictionary[] dctLocation
+// move '["statusCode":200,"statusDescription":"OK",numList={1,2,3,4}]' to sData
+// set psData of oSelectJSON to sData //sData is a string containing a JSON Structure.
+// get JSONDictionary of oSelectJSON "" to dctLocation
+// get JSONValue of oSelectJSON "statusCode" to iStatusCode
+// get JSONValue of oSelectJSON "numlist" to aStrings
+// showln dctLocation[0].sItem ":" dctLocation[0].sValue
+// get GoogleMapsResult to sData
+// set psData of oSelectJSON to sData //sData is a string containing a JSON Structure.
+// get JSONValue of oSelectJSON "results[0].geometry.location.lat" to nLAT
+// get JSONDictionary of oSelectJSON "results[0].geometry.location to dctLocation //array of tJSONDictionary
+// get JSONArray of oSelectJSON "results" to aStrings //array of string
+// Set psData of oSelectJSON to (psDirections(oDirectionReader))
+// Get JSONArray of oSelectJSON "routes[0].legs" to aLegs
+// Move (SizeOfArray(aLegs)) to iMax
+// For iPos from 0 to (iMax-1)
+// Set psData of oSelectJSON to aLegs[iPos]
+// Get JSONArray of oSelectJSON "steps" to aSteps
+//There's no support. Sorry.
+Object oJSON is a cObject
+ Property String[] pCacheValueArray
+ Property String psArrayCacheText
+ Property tJSONDictionary[] pCacheDictionary
+ Property String psDictionaryCacheText
+ Function isWhiteSpace String sChar Returns Boolean
+ If (sChar = " ") Function_Return (True)
+ If (sChar = Character(13)) Function_Return (True)
+ If (sChar = Character(10)) Function_Return (True)
+ If (sChar = Character(9)) Function_Return (True)
+ Function_Return (False)
+ Function isJSONDictionary String sInp Returns Boolean
+ For iPos from 1 to (Length(sInp))
+ Move (Mid(sInp,1,iPos)) to sChar
+ If (not(isWhiteSpace(Self,sChar))) Function_Return (sChar = "{")
+ Function_Return (False)
+ Function isJSON String sInp Returns Boolean
+ For iPos from 1 to (Length(sInp))
+ Move (Mid(sInp,1,iPos)) to sChar
+ If (not(isWhiteSpace(Self,sChar))) Begin
+ If (sChar = "[") Function_Return (True)
+ If (sChar = "{") Function_Return (True)
+ If (sChar = '"') Function_Return (True)
+ Function_Return (False)
+ Function_Return (False)
+ Function isJSONArray String sInp Returns Boolean
+ For iPos from 1 to (Length(sInp))
+ Move (Mid(sInp,1,iPos)) to sChar
+ If (not(isWhiteSpace(Self,sChar))) Function_Return (sChar = "[")
+ Function_Return (False)
+ Function theTime Returns String
+ Sysdate dDate iHrs iMins iSecs
+ Showln iHrs ":" iMins ":" iSecs
+ Function SplitJSONDictionary String sInp Returns tJSONDictionary[]
+ tJSONDictionary[] aDictionary
+ tJSONDictionary jsonItem
+ If (sInp = (psDictionaryCacheText(Self))) Begin
+ Function_Return (pCacheDictionary(Self))
+ Move "outside" to sState
+ Move (False) to isInsideQuote
+ Move (False) to isEscape
+ Move (Length(sInp)) to iMax
+ Move (ResizeArray(myCharArray,iMax+5)) to myCharArray
+ Move (AddressOf(myCharArray)) to pStr
+ For iPos from 0 to (iMax-1)
+ //Move (Mid(sInp,1,iPos)) to sToken
+ Move (character(myCharArray[iPos])) to sToken
+ If ((not(isEscape)) and (sToken = '"')) Move (not(isInsideQuote)) to isInsideQuote
+ If (sState = "outside") Begin
+ If (sToken="{") Move "objectname" to sState
+ Else If (sState = "objectname") Begin
+ If (isWhiteSpace(Self,sToken)) Begin
+ Else If (sToken = '"') Begin
+ Move "quotedobjectname" to sState
+ Else If (sToken = ":") Begin
+ Move "objectvalue" to sState
+ Append sProperty sToken
+ Else If (sState = "quotedobjectname") Begin
+ If (sToken = '"') Begin
+ Move "objectname" to sState
+ Append sProperty sToken
+ Else If (sState = "objectvalue") Begin
+ If (isWhiteSpace(Self,sToken)) Begin
+ If (isInsideQuote) Append sValue sToken
+ Else If ((sToken = '"') and (iQuoteLevel = 0)) Begin
+ Move "quotedobjectvalue" to sState
+ Else If ((sToken = ",") and (iQuoteLevel = 0)) Begin
+ Move (trim(sProperty)) to jsonItem.sItem
+ Move (trim(sValue)) to jsonItem.sValue
+ Move jsonItem to aDictionary[ (SizeOfArray(aDictionary)) ]
+ Move "objectname" to sState
+ Else If ((sToken = "}") and (iQuoteLevel = 0)) Begin
+ Move (trim(sProperty)) to jsonItem.sItem
+ Move (trim(sValue)) to jsonItem.sValue
+ Move jsonItem to aDictionary[ (SizeOfArray(aDictionary)) ]
+ Move "outside" to sState
+ If (not(isInsideQuote)) Begin
+ If (sToken = "[") Move (iQuoteLevel+1) to iQuoteLevel
+ If (sToken = "{") Move (iQuoteLevel+1) to iQuoteLevel
+ If (sToken = "]") Move (iQuoteLevel-1) to iQuoteLevel
+ If (sToken = "}") Move (iQuoteLevel-1) to iQuoteLevel
+ If (iQuoteLevel < 0) Move 0 to iQuoteLevel
+ Else If (sState = "quotedobjectvalue") Begin
+ If (sToken = '"') Append sValue '"'
+ Else If (sToken = '\') Append sValue '\'
+ Else If (sToken = '/') Append sValue '/'
+ Else If (sToken = 'f') Append sValue (Character(13))
+ Else If (sToken = 'n') Append sValue (Character(10)) (Character(13))
+ Else If (sToken = 'r') Append sValue (Character(10))
+ Else If (sToken = 't') Append sValue (Character(9))
+ Else If (sToken = 'u') Begin
+ Move (character(myCharArray[iPos+1])) to sUnicode
+ Append sUnicode (character(myCharArray[iPos+2]))
+ Append sUnicode (character(myCharArray[iPos+3]))
+ Append sUnicode (character(myCharArray[iPos+4]))
+ Move (Integer("$"+sUnicode)) to iUnicode
+ If (iUnicode > 254) Move 254 to iUnicode
+ Append sValue (Character(iUnicode))
+ Move (False) to isEscape
+ If (sToken = "\") Move (True) to isEscape
+ Else If (sToken = '"') Begin
+ Move "objectvalue" to sState
+ Set psDictionaryCacheText to sInp
+ Set pCacheDictionary to aDictionary
+ Function_Return aDictionary
+ Function SplitJSONArray String sInp Returns String[]
+ If (sInp = (psArrayCacheText(Self))) Begin
+ Function_Return (pCacheValueArray(Self))
+ Move "outside" to sState
+ Move (False) to isEscape
+ Move (Length(sInp)) to iMax
+ Move (ResizeArray(myCharArray,iMax+1)) to myCharArray
+ Move (AddressOf(myCharArray)) to pStr
+ Move "outside" to sState
+ For iPos from 0 to (iMax-1)
+ Move (character(myCharArray[iPos])) to sToken
+ If ((not(isEscape)) and (sToken = '"')) Move (not(isInsideQuote)) to isInsideQuote
+ If (sState = "outside") Begin
+ If (sToken="[") Move "objectvalue" to sState
+ Else If (sState = "objectvalue") Begin
+ If (isWhiteSpace(Self,sToken)) Begin
+ If (isInsideQuote) Append sValue sToken
+ Else If ((sToken = '"') and (iQuoteLevel = 0)) Begin
+ Move "quotedobjectvalue" to sState
+ Else If ((sToken = ",") and (iQuoteLevel = 0)) Begin
+ Move (trim(sValue)) to ValueArray[ (SizeOfArray(ValueArray)) ]
+ Move "objectvalue" to sState
+ Else If ((sToken = "]") and (iQuoteLevel = 0)) Begin
+ Move (trim(sValue)) to ValueArray[ (SizeOfArray(ValueArray)) ]
+ Move "outside" to sState
+ If (not(isInsideQuote)) Begin
+ If (sToken = "[") Move (iQuoteLevel+1) to iQuoteLevel
+ If (sToken = "{") Move (iQuoteLevel+1) to iQuoteLevel
+ If (sToken = "]") Move (iQuoteLevel-1) to iQuoteLevel
+ If (sToken = "}") Move (iQuoteLevel-1) to iQuoteLevel
+ If (iQuoteLevel < 0) Move 0 to iQuoteLevel
+ Else If (sState = "quotedobjectvalue") Begin
+ If (sToken = '"') Append sValue '"'
+ Else If (sToken = '\') Append sValue '\'
+ Else If (sToken = '/') Append sValue '/'
+ Else If (sToken = 'f') Append sValue (Character(13))
+ Else If (sToken = 'n') Append sValue (Character(10)) (Character(13))
+ Else If (sToken = 'r') Append sValue (Character(10))
+ Else If (sToken = 't') Append sValue (Character(9))
+ Else If (sToken = 'u') Begin
+ Move (character(myCharArray[iPos+1])) to sUnicode
+ Append sUnicode (character(myCharArray[iPos+2]))
+ Append sUnicode (character(myCharArray[iPos+3]))
+ Append sUnicode (character(myCharArray[iPos+4]))
+ Move (Integer("$"+sUnicode)) to iUnicode
+ If (iUnicode > 254) Move 254 to iUnicode
+ Append sValue (Character(iUnicode))
+ Move (False) to isEscape
+ If (sToken = "\") Move (True) to isEscape
+ Else If (sToken = '"') Begin
+ Move "objectvalue" to sState
+ Set pCacheValueArray to ValueArray
+ Set psArrayCacheText to sInp
+ Function_Return ValueArray
+ Function JSONValue String sTmp Returns String
+ Move (Trim(sTmp)) to sTmp
+ If ((left(sTmp,1))='"') Move (Mid(sTmp,(Length(sTmp))-1,2)) to sTmp
+ If ((right(sTmp,1))='"') Move (Mid(sTmp,(Length(sTmp))-1,1)) to sTmp
+ Move (Replaces('\"',sTmp,'"')) to sTmp
+ Move (Replaces('\t',sTmp, (Character(9)) )) to sTmp
+ Move (Replaces('\r"',sTmp, (Character(10)))) to sTmp
+ Move (Replaces('\f"',sTmp, (Character(13)))) to sTmp
+ Move (Replaces('\\"',sTmp, "\")) to sTmp
+ Function DictionaryMatches tJSONDictionary DictItem tJSONDictionary sSearchDict Returns Integer
+ Move (lowercase(DictItem.sItem)) to sTest
+ Move (Lowercase(sSearchDict.sItem)) to sSearchFor
+ If (sSearchFor = sTest) Function_Return (EQ)
+ Else Function_Return (NE)
+ End_Function // MyComparison
+ Function DictionaryValue tJSONDictionary[] aDictionary String sSearch Returns String
+ tJSONDictionary sSearchDict
+ Move sSearch to sSearchDict.sItem
+ Move (SearchArray( sSearchDict, aDictionary, Self, get_DictionaryMatches )) to iPos
+ If (iPos = -1) Function_Return ""
+ Function_Return aDictionary[iPos].sValue
+Class cSelectJSON is a cObject
+ Procedure Construct_Object
+ Forward Send Construct_Object
+ Function JSONisNumeric String sCode Returns Integer
+ Move (Replace(".",sCode,"")) to sCode
+ Move (length(sCode)) to iLength
+ For iPos from 1 to iLength
+ Move (mid(sCode,1,iPos)) to sTmpChar
+ If (pos(sTmpChar,'01234567890')) eq 0 Function_Return (False)
+ Function JSONSplitToArray String sVal String sChar Returns String[]
+ While (Pos(sChar, sVal)>0)
+ Move (Left(sVal, Pos(sChar, sVal)-1)) to sHold
+ // store value in array
+ Move sHold to astVal[iCount]
+ // remove value from string
+ Move (Replace(sHold+sChar, sVal, "")) to sVal
+ // move whatever is last to the end of the array
+ Move sVal to astVal[iCount]
+ Function JSONValue String sSearch Returns String
+ tJSONDictionary[] aDictionary
+ Move (Replaces("[",sSearch,".[")) to sSearch
+ Move (Replaces("..",sSearch,".")) to sSearch
+ If ((Left(sSearch,1))=".") Move (Mid(sSearch,(Length(sSearch)),2)) to sSearch
+ Move (JSONSplitToArray(Self,sSearch,".")) to aCrumbs
+ Move (SizeOfArray(aCrumbs)) to iMax
+ For iPos from 0 to (iMax-1)
+ Move aCrumbs[iPos] to sCrumb
+ If ((sCrumb = "") or (sCrumb=".")) Begin
+ Else If ((Pos("[",sCrumb)) = 1) Begin
+ Move (Replaces("[",sCrumb,"")) to sCrumb
+ Move (Replaces("]",sCrumb,"")) to sCrumb
+ If (JSONisNumeric(Self,sCrumb)) Move sCrumb to iArrayPos
+ Move (SplitJSONArray(oJSON,sresults)) to arJSON
+ If (iArrayPos >= (sizeOfArray(arJSON))) Function_Return ""
+ Else Move arJSON[iArraypos] to sResults
+ Move (SplitJSONDictionary(oJSON,sResults)) to aDictionary
+ Move (DictionaryValue(oJSON,aDictionary,sCrumb)) to sresults
+ Function_Return sresults
+ Function JSONDictionary String sSearch Returns tJSONDictionary[]
+ tJSONDictionary[] aDictionary
+ Move (JSONValue(Self,sSearch)) to sresults
+ Move (SplitJSONDictionary(oJSON,sResults)) to aDictionary
+ Function_Return aDictionary
+ Function JSONArray String sSearch Returns String[]
+ Move (JSONValue(Self,sSearch)) to sresults
+ Move (SplitJSONArray(oJSON,sresults)) to arJSON
+ //set psData of oSelectJSON to sData
+ //get JSONValue of oSelectJSON "results[0].geometry.location.lat" to nLAT
+ //get JSONDictionary of oSelectJSON "results[0].geometry.location to dctLocation
+ //get JSONArray of oSelectJSON "results" to aStrings
+Object oSelectJSON is a cSelectJSON