Created
February 17, 2014 11:27
-
-
Save seanbamforth/9048944 to your computer and use it in GitHub Desktop.
Pure VDF JSON Parser
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//***************************************************************************** | |
//*** 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