First of all, thanks to hoffmcs for the original JSON Parser!
viewtopic.php?f=34&t=30688&p=186934#p186934I was originally going to use his library for one of my channels, but found the performance was a bit slow for my liking, so I started looking into either optimizing it, or coming up with a better way to do it. Realizing that the BrightScript array and associative array syntax is
very similar to the JSON syntax, that's the route I started down first, and ultimately what I stuck with. My resulting SimpleJSON functions have proven to be as much as 100 times faster than hoffmcs's full blown parser, depending on how long the JSON string is. They're certainly not ideal in every situation, but they've worked for me with everything I've thrown at them so far...
(Handy tip: I've found the SimpleJSONBuilder function to be a very convenient way of serializing "objects" for stuffing into the registry.)
Consider the following JSON string:
{
"Books": [
{
"Title": "Book 1",
"Author": "Author 1",
"Page Count": 25
},
{
"Title": "Book 2",
"Author": null,
"Page Count": 15
}
]
}
In this example, there are three things that prevent us from using it directly as a BrightScript array...
- The key names are quoted
- Some key names have spaces in them
- "null" is not a valid BrightScript value
Using a little creative regex, I was able to address #1 and #2 by removing the quotes and spaces from the JSON string keys (NOTE: this results in a "PageCount" key instead of a "Page Count" key in the resulting associative array). #3 is addressed simply by declaring a variable named "null" and setting it to invalid:
null = invalid
With all of that accomplished, we can now directly Eval the resulting string, and we get a BrightScript associative array!
First, and example of how to use these functions...
' Parse JSON string
jsonString = urlTransfer.GetToString( "http://my.json.url/blah.json" )
brightScriptAArray = SimpleJSONParser( jsonString )
' Build JSON string
brightScriptAArray = {
Books: [
{ Title: "Book 1", Author: "Author 1", PageCount: 25 },
{ Title: "Book 2", Author: "Author 2", PageCount: 15 }
]
}
jsonString = SimpleJSONBuilder( brightScriptAArray )
And now the source...
Function SimpleJSONParser( jsonString As String ) As Object
' setup "null" variable
null = invalid
regex = CreateObject( "roRegex", Chr(34) + "([a-zA-Z0-9_\-\s]*)" + Chr(34) + "\:", "i" )
regexSpace = CreateObject( "roRegex", "[\s]", "i" )
regexQuote = CreateObject( "roRegex", "\\" + Chr(34), "i" )
' Replace escaped quotes
jsonString = regexQuote.ReplaceAll( jsonString, Chr(34) + " + Chr(34) + " + Chr(34) )
jsonMatches = regex.Match( jsonString )
iLoop = 0
While jsonMatches.Count() > 1
' strip spaces from key
key = regexSpace.ReplaceAll( jsonMatches[ 1 ], "" )
jsonString = regex.Replace( jsonString, key + ":" )
jsonMatches = regex.Match( jsonString )
' break out if we're stuck in a loop
iLoop = iLoop + 1
If iLoop > 5000 Then
Exit While
End If
End While
jsonObject = invalid
' Eval the BrightScript formatted JSON string
Eval( "jsonObject = " + jsonString )
Return jsonObject
End Function
Function SimpleJSONBuilder( jsonArray As Object ) As String
Return SimpleJSONAssociativeArray( jsonArray )
End Function
Function SimpleJSONAssociativeArray( jsonArray As Object ) As String
jsonString = "{"
For Each key in jsonArray
jsonString = jsonString + Chr(34) + key + Chr(34) + ":"
value = jsonArray[ key ]
If Type( value ) = "roString" Then
jsonString = jsonString + Chr(34) + value + Chr(34)
Else If Type( value ) = "roInt" Or Type( value ) = "roFloat" Then
jsonString = jsonString + value.ToStr()
Else If Type( value ) = "roBoolean" Then
jsonString = jsonString + IIf( value, "true", "false" )
Else If Type( value ) = "roArray" Then
jsonString = jsonString + SimpleJSONArray( value )
Else If Type( value ) = "roAssociativeArray" Then
jsonString = jsonString + SimpleJSONBuilder( value )
End If
jsonString = jsonString + ","
Next
If Right( jsonString, 1 ) = "," Then
jsonString = Left( jsonString, Len( jsonString ) - 1 )
End If
jsonString = jsonString + "}"
Return jsonString
End Function
Function SimpleJSONArray( jsonArray As Object ) As String
jsonString = "["
For Each value in jsonArray
If Type( value ) = "roString" Then
jsonString = jsonString + Chr(34) + value + Chr(34)
Else If Type( value ) = "roInt" Or Type( value ) = "roFloat" Then
jsonString = jsonString + value.ToStr()
Else If Type( value ) = "roBoolean" Then
jsonString = jsonString + IIf( value, "true", "false" )
Else If Type( value ) = "roArray" Then
jsonString = jsonString + SimpleJSONArray( value )
Else If Type( value ) = "roAssociativeArray" Then
jsonString = jsonString + SimpleJSONAssociativeArray( value )
End If
jsonString = jsonString + ","
Next
If Right( jsonString, 1 ) = "," Then
jsonString = Left( jsonString, Len( jsonString ) - 1 )
End If
jsonString = jsonString + "]"
Return jsonString
End Function
Function IIf( Condition, Result1, Result2 )
If Condition Then
Return Result1
Else
Return Result2
End If
End Function
I hope you find it useful. All questions, comments, and criticisms are welcome! Thanks...
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)