Skip to content

Instantly share code, notes, and snippets.

@salex
Created January 2, 2011 18:10
Show Gist options
  • Save salex/762698 to your computer and use it in GitHub Desktop.
Save salex/762698 to your computer and use it in GitHub Desktop.
A JSON Parse Routine for Active4D with some limitations
<%
/**********************************************************************************
jsonParseSimple
In => $json -> Text in JavaScript Object Notation(JSON)
Out => The JSON text parsed to an Active4D collection with some limitations.
Active4D cannot do everything that you can in JSON (JavaScript, Ruby, PHP etc).
You cannot have an array of mixed types as you can in other languages.
This was written for 4D 2004 so there is the 32K text limit on $json
The JSON must be enclosed in an object {} or array [] notation
It will probably do 100% of what you'd like it to do if you control boths sides (create and parse JSON). It will convert
just about any sane JSON I've found at a web service. It will convert anything created with the a4d.json libary.
Dates use the "Jan 2, 2011" format as does the a4d.json libary
Objects are converted to collection with calls to execute "new collection"
Arrays are restricted to text, longint, and real arrays.
If a longint array is an array of collections, it will create those collections.
This parse process is in five steps.
A regex is used to convert dates
The JSON is parsed by each character and certain characters (",:\n\r) are changed to high ASCII values or removed
A regex replace is set up to change the JSON object notation to Active4D notation
The high ASCII characters are returned to their original value
The result is executed, which productes the collection.
**********************************************************************************/
method "jsonParseSimple"($json)
// First convert any dates in IETF format to 4d date
$re1 := "~\"?(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)( \\d\\d*, \d{4})\"~"
$rp1 := "newDate(\"\1\2\")"
regex replace($re1; $json; $rp1; $json)
$json := trim($json)
if ($json[[1]] = "[") // if json is just an array, wrap in in an object
$json := '{"array":$json}'
end if
//Next, hide commas, colons, apostrophe between quotes
$inQuote := false
for each ($json; $char; $index)
case of
:($char = '"')
$inQuote := not($inQuote)
:(($char = ",") & $inQuote)
$json[[$index]] := char(254)
:(($char = ":") & $inQuote)
$json[[$index]] := char(253)
:(($char = "'") & $inQuote)
$json[[$index]] := char(252)
:(($char = "\n") & not($inQuote))
$json[[$index]] := " "
:(($char = "\r") & not($inQuote))
$json[[$index]] := " "
:(($char = "\n") & ($inQuote))
$json[[$index]] := char(251)
:(($char = "\r") & ($inQuote))
$json[[$index]] := char(251)
end case
end for each
//Now convert objects
array text($pattern;0) // regex pattern array
array text($replace;0) // reqex replace array
// set the reqex array - first the patterns to match
$pattern{} := "|:\\s*{|" // object => convert :{ to ;new collection(
$pattern{} := "|\\[\\]|" // replace empty array with empty text array -> a call to emptyArray
$pattern{} := "|:\\s*\\[|" // text, real, or longint array -> a call to newArray(''' JSON ARRAY ''')
$pattern{} := "|\\]|" // end array => convert ] to )
$pattern{} := "|}|" // end object => convert } to )
$pattern{} := "|[:,]|" // replace comma and colon with semi-colon
$pattern{} := "|{|" // replace begining object with new collection()
$pattern{} := "|new collection\\(\\)|" // replace empty collection convert new collection() with new collection
//set the replacement array
$replace{} := ";new collection(" // ojects that have a key
$replace{} := "emptyArray" // []
$replace{} := ";newArray( ''' " // [..,..,..]
$replace{} := " ''')"
$replace{} := ")"
$replace{} := ";"
$replace{} := "new collection(" // collections without a key (an array of collections)
$replace{} := "new collection"
regex replace($pattern; $json; $replace; $results) // do the replacements
//put commas, colon, apos back
$results := replace string($results;char(254);",")
$results := replace string($results;char(253);":")
$results := replace string($results;char(252);"'")
$results := replace string($results;char(251);"\\n")
// crate the collection from the parsed $results - make Active4D work
$collection := execute("return ("+ $results+ ")")
//writebr('<textarea>$results</textarea>')
//$collection := new collection
return($collection)
end method
/**********************************************************************************
emptyArray
The response to finding and empty array [] in a JSON object is to
return an empty text array
**********************************************************************************/
method "emptyArray"
array text($result;0)
return($result)
end method
/**********************************************************************************
newArray
$inList -> Text The JSON array os enclosed in a ''' ''' herdoc string.
JSON comma delimiters for the array had been changed to semi-colons at this point.
Return either a text array, a longint array, an array of collections, or a real array based in contents.
A parenthesis will assume a text array
A decimal (.) will assume a real array
An array of new collection(...) will create an array of collections (longint) after creating the collections
If none of the above, it assumes an array of longint.
**********************************************************************************/
method "newArray"($inList)
$inList := trim($inList)
$isNC := $inList = "new collection@"
// Handle an array of collections separately - just deal with top level if nested collection
if ($isNC)
$level := 0
for each ($inList; $char; $index)
case of
:($char = "(")
$level++
:(($char = ")") )
$level--
:(($char = ";") & ($level = 0))
$inList[[$index]] := "|"
end case
end for each
$cnt := split string($inList;"|";$chunks)
array longint($result;size of array($chunks))
for each ($chunks; $value; $index)
$ncoll := trim($value)
$result{$index} := execute("return ("+ $ncoll+ ")") // execute the new collection text
end for each
return($result)
end if
$isReal := "." ~ $inList
$isText := '"' ~ $inList
$count := split string($inList;";";$chunks)
case of
:($isText)
array text($result;$count)
for each ($chunks; $value; $index)
$result{$index} := trim(replace string($value;'"';''))
end for each
:($isReal)
array real($result;$count)
for each ($chunks; $value; $index)
$result{$index} := num($value)
end for each
else
array longint($result;$count)
for each ($chunks; $value; $index)
$result{$index} := num($value)
end for each
end case
return($result)
end method
/**********************************************************************************
null
The response to finding and Null word in a JSON object is to
return a nil pointer ( or could return char(0))
**********************************************************************************/
method "null"
return(nil pointer)
end method
/**********************************************************************************
newDate
The response to finding and date in a JSON object that is a string formatted
in the "Jan 2, 2011" format is to replace it with a 4D date
**********************************************************************************/
method "newDate"($date)
// replace date in Jan 2, 2011 with 4D date
array string(3; $months; *; "Jan"; "Feb"; "Mar"; "Apr"; "May"; "Jun"; "Jul"; "Aug"; "Sep"; "Oct"; "Nov"; "Dec")
$date := replace string($date;",";"")
$cnt := split string($date;" ";$chunks)
$tmp := string(find in array($months;$chunks{1}))+'/$chunks{2}/$chunks{3}'
return(date($tmp))
end method
$json := """
{
"test-null":null,
"test-empty-array": [],
"test-empty-collection": {},
"test_true":true,
"test_false":false,
"test_reala":[3.34,43.5,445.2232],
"test_integera":[3,5,66,77,88],
"test_texta":["3uj","wd","wm","ib77","iu88"],
"jobstageid":1852,
"selected":
[
{
"citizen":
{
"citizen.phone1":"5552149891",
"citizen.phone2":"5554799657",
"citizen.Address":"51 Lefevere",
"citizen.City":"Somewhere",
"citizen.state":"AL",
"citizen.zip":"01010",
"citizen.firstName":"Aladrienne",
"citizen.lastName":"Odom",
"citizen.mi":"C",
"citizen.emailAddress":"[email protected]",
"citizen.birthMMDD":"1209",
"action":"update",
"id":153517
},
"cs_ad":
{
"citizen_stage.jobstageid":1852,
"citizen_stage.score":"90.7761037140855",
"application_data.answers":"g0102g0202g0302g0401g0501g0601g0701g0801g0901g1001g1101g1201g1301e0105e0110",
"applicant_id":279
}
},
{
"citizen":
{
"citizen.phone1":"5552357646",
"citizen.phone2":"5552850789",
"citizen.Address":"4612 Meridian Street",
"citizen.City":"Somewhere",
"citizen.state":"MS",
"citizen.zip":"01010",
"citizen.firstName":"Farrah",
"citizen.lastName":"Warren",
"citizen.mi":"D",
"citizen.emailAddress":"[email protected]",
"citizen.birthMMDD":"0828",
"action":"update",
"id":153843
},
"cs_ad":
{
"citizen_stage.jobstageid":1852,
"citizen_stage.score":"90.78486334968466",
"application_data.answers":"g0102g0202g0301g0401g0501g0601g0701g0801g0901g1001g1101g1201g1301e0105",
"applicant_id":417
}
},
{
"citizen":
{
"citizen.phone1":"5552325995",
"citizen.phone2":"5554318634",
"citizen.Address":"6527 Old Shell Rd. #64",
"citizen.City":"Somewhere",
"citizen.state":"AL",
"citizen.zip":"01010",
"citizen.firstName":"Ballery",
"citizen.lastName":"Johnson",
"citizen.mi":"",
"citizen.emailAddress":"[email protected]",
"citizen.birthMMDD":"1220",
"action":"update",
"id":154260
},
"cs_ad":
{
"citizen_stage.jobstageid":1852,
"citizen_stage.score":"90.7761037140855",
"application_data.answers":"g0102g0202g0301g0402g0501g0601g0701g0801g0901g1001g1101g1201g1301e0105e0111",
"applicant_id":562
}
}
]
} """
$c := global.jsonParseSimple($json)
a4d.debug.dump collection($c; "test";true)
// an array of collections will not dump, but they are collections.
for each ($c{"selected"}; $citizen; $index)
a4d.debug.dump collection($citizen)
end for each
%>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment