Roku Developer Program

Join our online forum to talk to Roku developers and fellow channel creators. Ask questions, share tips with the community, and find helpful resources.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
EnTerr
Roku Guru

toJSON() - a working JSON generator

I figured i will dip my toes where my mouth is (yay, a portmantidiom!), so i wrote a JSON serializer/stringifier function.

toJSON() takes nested BS data structures and returns passable JSON string. Unlike the undocumented built-in "formatJSON()", this one is
  • Published (for trivial reasons: source provided)

  • Documented (ditto; when in doubt, RTFS)

  • Works on v3 platform as well as on v5

  • Supports broader range of data (e.g. [1,2,3])

  • Does not crash-reboot the player if fed a cyclic structure

  • Malleable (oh, you would rather have tabs escaped as "\t"? so change it)

And so, without further adieu:
function toJSON(it, TTL=40):
if TTL > 0:
typ = type(it)
if typ = "String" or typ = "roString":
'escape " and \. NB: cannot deal with \ *after* others are escaped
res = createObject("roRegex", "([\x22\\])", "").replaceAll(it, "\\\1")

'control chars; likely no need but rfc4627 calls for it
re = createObject("roRegEx", "[\x00-\x1f]", "")
bArr = invalid
while true:
ch = re.match(res)[0]
if ch = invalid then exit while

if ch = chr(10):
toRE = "\\n"
elseif ch = chr(13):
toRE = "\\r"
else:
if bArr = invalid then bArr = createObject("roByteArray")
bArr.fromAsciiString(ch)
toRE = "\\u00" + bArr.toHexString()
end if
res = createObject("roRegEx", ch, "").replaceAll(res, toRE)
end while
return chr(34) + res + chr(34)

elseif typ = "roArray" or typ = "roList":
res = ""
for each item in it:
res = res + toJSON(item, TTL-1) + ","
end for
'drop the last comma (if any)
return "[" + left(res, len(res)-1) + "]"

elseif typ = "roAssociativeArray":
res = ""
for each key in it:
res = res + toJSON(key, 1) + ":" + toJSON(it[key], TTL-1) + ","
end for
'drop the last comma (if any)
return "{" + left(res, len(res)-1) + "}"

elseif typ = "Integer" or typ = "roInt" or typ = "roInteger":
'yes, Virginia, there is roInteger: ?type([0][0])
return it.toStr()

elseif typ = "Float" or typ = "Double" or typ = "roFloat" or typ = "roDouble":
'str() is our first, last and only hope
return str(it).trim()

elseif typ = "Boolean" or typ = "roBoolean":
if it:
return "true"
else:
return "false"
end if

elseif typ = "Invalid" or typ = "roInvalid":
return "null"

else:
' "Function", "<uninitialized>", "if"-interfaces, other "ro"-objects
print "toJSON: unsupported type", type(it), it
STOP
end if

else: 'TTL<=0, time-to-live counter expired
print "toJSON: too many nested structures (likely a cycle)", it
STOP
end if

end function

It is all straightforward, except maybe the string escapes, where some attention was needed. I limited nesting at 40 since interpreter croaks at depth ~56 (no idea why so low but should suffice for JSON practical purposes). Comments welcome, esp. if you have some interesting or big structures to stringify.
0 Kudos
3 REPLIES 3
TheEndless
Channel Surfer

Re: toJSON() - a working JSON generator

Sorry for the off-topic, but you have a curious syntactical structure to your code (mostly referring to the use of colons at the start of all of your conditional blocks). Where do your coding roots lie?
My Channels: http://roku.permanence.com - Twitter: @TheEndlessDev
Instant Watch Browser (NetflixIWB), Aquarium Screensaver (AQUARIUM), Clever Clocks Screensaver (CLEVERCLOCKS), iTunes Podcasts (ITPC), My Channels (MYCHANNELS)
0 Kudos
NewManLiving
Visitor

Re: toJSON() - a working JSON generator

And another one for the toolbox - thanks again EnTerr, keep them coming. Have not tried it yet , but I am sure its a good one !!!
My Channels: 2D API Framework Presentation: https://owner.roku.com/add/2M9LCVC
Updated: 11-11-2015 - Completed Keyboard interface
The Joel Channel ( Final Beta )
0 Kudos
EnTerr
Roku Guru

Re: toJSON() - a working JSON generator

"TheEndless" wrote:
Sorry for the off-topic, but you have a curious syntactical structure to your code (mostly referring to the use of colons at the start of all of your conditional blocks). Where do your coding roots lie?

The ":" after if/else/for/while? That one came from Python, all compound statements are like that there. I don't remember if i did it in BRS by habit at first - but at some point i consciously started doing it, since it looks that way more like pseudocode you'd sketch on paper (heck, Python is executable pseudocode). I just checked and the extra ":" in BRS does not increase the compiled result. Also, it is easy to strip with a regex /:$/ 8-)

But other than that i have perused about a dozen programming languages, of which i know well maybe half. Couple of BASICs, couple of Pascal off-shoots, five C off-shoots (java goes here to keep company to c++ and c#, thankyouverymuch), forth, even perl (in some dark moment of my life), et al. My first one was BASIC (just like Anthony Wood's but can't say i remained a fan) - on Apple2 COMECON clone. Even remember my very first program was a home assignment: write code that finds prime numbers by trial division. Memories... speaking of which, don't you think Roku is fast enough that emulator for say Apple2 (or other oldie) can be written in BRS?
0 Kudos