Skip to content

Instantly share code, notes, and snippets.

@seanbamforth
Created February 17, 2014 11:27
Show Gist options
  • Save seanbamforth/9048944 to your computer and use it in GitHub Desktop.
Save seanbamforth/9048944 to your computer and use it in GitHub Desktop.
Pure VDF JSON Parser
//*****************************************************************************
//*** json.pkg ***
//*** ***
//*** Author: Sean Bamforth ***
//*** SELECT Computer Systems Ltd ***
//*** April / May 2011 ***
//*** ***
//*** Purpose: ***
//*** JSON Client interface for talking to JSON / restful services. ***
//*** ***
//*** License: ***
//*** 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. ***
//*** ***
//*****************************************************************************
//Description
// 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):
// string sData
// tJSONDictionary[] dctLocation
// string[] aStrings
// 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
// showln aStrings[0]
//
// 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
// showln aSteps[0]
// Loop
//Support
//There's no support. Sorry.
Struct tJSONDictionary
String sItem
String sValue
End_Struct
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)
End_Function
Function isJSONDictionary String sInp Returns Boolean
Integer iPos
String sChar
For iPos from 1 to (Length(sInp))
Move (Mid(sInp,1,iPos)) to sChar
If (not(isWhiteSpace(Self,sChar))) Function_Return (sChar = "{")
Loop
Function_Return (False)
End_Function
Function isJSON String sInp Returns Boolean
Integer iPos
String sChar
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)
End
Loop
Function_Return (False)
End_Function
Function isJSONArray String sInp Returns Boolean
Integer iPos
String sChar
For iPos from 1 to (Length(sInp))
Move (Mid(sInp,1,iPos)) to sChar
If (not(isWhiteSpace(Self,sChar))) Function_Return (sChar = "[")
Loop
Function_Return (False)
End_Function
Function theTime Returns String
Date dDate
Integer iHrs
Integer iMins
Integer iSecs
Sysdate dDate iHrs iMins iSecs
Showln iHrs ":" iMins ":" iSecs
End_Function
// {
Function SplitJSONDictionary String sInp Returns tJSONDictionary[]
tJSONDictionary[] aDictionary
tJSONDictionary jsonItem
Integer iPos
Integer iMax
String sToken
Boolean isEscape
Integer iType
String sState
String sProperty
String sValue
Integer iQuoteLevel
Boolean isInsideQuote
String sUnicode
Integer iUnicode
If (sInp = (psDictionaryCacheText(Self))) Begin
Function_Return (pCacheDictionary(Self))
End
Move "outside" to sState
Move (False) to isInsideQuote
Move "" to sProperty
Move (False) to isEscape
Move (Length(sInp)) to iMax
Char[] myCharArray
Address pStr
Move (ResizeArray(myCharArray,iMax+5)) to myCharArray
Move (AddressOf(myCharArray)) to pStr
Move sInp 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
Move "" to sProperty
If (sToken="{") Move "objectname" to sState
End
Else If (sState = "objectname") Begin
If (isWhiteSpace(Self,sToken)) Begin
End
Else If (sToken = '"') Begin
Move "" to sProperty
Move "quotedobjectname" to sState
End
Else If (sToken = ":") Begin
Move "objectvalue" to sState
Move "" to sValue
End
Else Begin
Append sProperty sToken
End
End
Else If (sState = "quotedobjectname") Begin
If (sToken = '"') Begin
Move "objectname" to sState
End
Else Begin
Append sProperty sToken
End
End
Else If (sState = "objectvalue") Begin
If (isWhiteSpace(Self,sToken)) Begin
If (isInsideQuote) Append sValue sToken
End
Else If ((sToken = '"') and (iQuoteLevel = 0)) Begin
Move "quotedobjectvalue" to sState
Move 0 to iQuoteLevel
End
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
Move "" to sProperty
Move "" to sValue
End
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
Move "" to sProperty
Move "" to sValue
End
Else Begin
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
End
Append sValue sToken
End
End
Else If (sState = "quotedobjectvalue") Begin
If (isEscape) 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 (iPos+4) to iPos
End
Move (False) to isEscape
End
Else Begin
If (sToken = "\") Move (True) to isEscape
Else If (sToken = '"') Begin
Move "objectvalue" to sState
End
Else Begin
Append sValue sToken
End
End
End
Loop
Set psDictionaryCacheText to sInp
Set pCacheDictionary to aDictionary
Function_Return aDictionary
End_Function
Function SplitJSONArray String sInp Returns String[]
String[] ValueArray
Integer iPos
Integer iMax
String sToken
Boolean isEscape
Integer iType
String sState
String sValue
Integer iQuoteLevel
Boolean isInsideQuote
String sUnicode
Integer iUnicode
If (sInp = (psArrayCacheText(Self))) Begin
Function_Return (pCacheValueArray(Self))
End
Move "outside" to sState
Move 0 to iQuoteLevel
Move "" to sValue
Move (False) to isEscape
Move (Length(sInp)) to iMax
Char[] myCharArray
Address pStr
Move (ResizeArray(myCharArray,iMax+1)) to myCharArray
Move (AddressOf(myCharArray)) to pStr
Move sInp 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
Move "" to sValue
If (sToken="[") Move "objectvalue" to sState
End
Else If (sState = "objectvalue") Begin
If (isWhiteSpace(Self,sToken)) Begin
If (isInsideQuote) Append sValue sToken
End
Else If ((sToken = '"') and (iQuoteLevel = 0)) Begin
Move "quotedobjectvalue" to sState
End
Else If ((sToken = ",") and (iQuoteLevel = 0)) Begin
Move (trim(sValue)) to ValueArray[ (SizeOfArray(ValueArray)) ]
Move "" to sValue
Move "objectvalue" to sState
End
Else If ((sToken = "]") and (iQuoteLevel = 0)) Begin
Move (trim(sValue)) to ValueArray[ (SizeOfArray(ValueArray)) ]
Move "outside" to sState
End
Else Begin
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
End
Append sValue sToken
End
End
Else If (sState = "quotedobjectvalue") Begin
If (isEscape) 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 (iPos+4) to iPos
End
Move (False) to isEscape
End
Else Begin
If (sToken = "\") Move (True) to isEscape
Else If (sToken = '"') Begin
Move "objectvalue" to sState
End
Else Begin
Append sValue sToken
End
End
End
Loop
Set pCacheValueArray to ValueArray
Set psArrayCacheText to sInp
Function_Return ValueArray
End_Function
Function JSONValue String sTmp Returns String
String sPos
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_Return sTmp
End_Function
Function DictionaryMatches tJSONDictionary DictItem tJSONDictionary sSearchDict Returns Integer
Integer iRetVal
String sTest
String sSearchFor
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
Integer iPos
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
End_Function
End_Object
Class cSelectJSON is a cObject
Procedure Construct_Object
Forward Send Construct_Object
Property String psData
End_Procedure
Function JSONisNumeric String sCode Returns Integer
Integer iLength
Integer iPos
String sTmpChar
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)
Loop
Function_Return (True)
End_Function
Function JSONSplitToArray String sVal String sChar Returns String[]
String[] astVal
String sHold
Integer iCount
While (Pos(sChar, sVal)>0)
// fetch first string
Move (Left(sVal, Pos(sChar, sVal)-1)) to sHold
// store value in array
Move sHold to astVal[iCount]
Increment iCount
// remove value from string
Move (Replace(sHold+sChar, sVal, "")) to sVal
Loop
// move whatever is last to the end of the array
Move sVal to astVal[iCount]
Function_Return astVal
End_Function // Split
Function JSONValue String sSearch Returns String
String[] aCrumbs
Integer iPos
Integer iMax
String sresults
tJSONDictionary[] aDictionary
String[] arJSON
String sCrumb
Integer iArrayPos
Get psData to sResults
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
//nothing
End
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
End
Else Begin
Move (SplitJSONDictionary(oJSON,sResults)) to aDictionary
Move (DictionaryValue(oJSON,aDictionary,sCrumb)) to sresults
End
Loop
Function_Return sresults
End_Function
Function JSONDictionary String sSearch Returns tJSONDictionary[]
String sresults
tJSONDictionary[] aDictionary
Move (JSONValue(Self,sSearch)) to sresults
Move (SplitJSONDictionary(oJSON,sResults)) to aDictionary
Function_Return aDictionary
End_Function
Function JSONArray String sSearch Returns String[]
String[] arJSON
String sresults
Move (JSONValue(Self,sSearch)) to sresults
Move (SplitJSONArray(oJSON,sresults)) to arJSON
Function_Return arJSON
End_Function
//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
End_Class
Object oSelectJSON is a cSelectJSON
End_Object
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment