B4R Code Snippet JSON Parsing

Two methods to help parse JSON strings:
B4X:
Sub Process_Globals
   Public Serial1 As Serial
   Private jsontext() As Byte = "{  ""id"": ""84F3EBE3621A"",  ""name"": ""Kitchen"",  ""get_status"": ""0,1,1,1,0,1,1,0"",  ""set_status"": ""0,1,1,1,0,1,1,0"",  ""get"": {    ""index"": 8,    ""value"": 1  },  ""set"": {    ""index"": 8,    ""value"": 2  }}"
   Private quotearray() As Byte = """"
   Private LastIndex As Int
End Sub

Private Sub AppStart
   Serial1.Initialize(115200)
   Delay(100)
   Dim MaxSize As Int = 20
   Dim buffer(MaxSize) As Byte
   GetTextValueFromKey(jsontext, "name", 0, buffer, MaxSize)
   Log(buffer)
   GetTextValueFromKey(jsontext, "get_status", 0, buffer, MaxSize)
   Log(buffer)
   Log(GetNumberValueFromKey(jsontext, "value", 0))
   Log(GetNumberValueFromKey(jsontext, "value", LastIndex)) 'second value
End Sub

Sub GetTextValueFromKey (json() As Byte, Key() As Byte, StartIndex As Int, ResultBuffer() As Byte, MaxLength As UInt)
   Dim bc As ByteConverter
   Dim qkey() As Byte = JoinBytes(Array(quotearray, Key, quotearray))
   Dim i As Int = bc.IndexOf2(json, qkey, StartIndex)
   If i = -1 Then
       bc.ArrayCopy(Array As Byte(), ResultBuffer)
       Return
   End If
   Dim i1 As Int = bc.IndexOf2(json, quotearray, i + qkey.Length + 1)
   Dim i2 As Int = bc.IndexOf2(json, quotearray, i1 + 1)
   bc.ArrayCopy(bc.SubString2(json, i1 + 1, Min(i2, i1 + 1 + MaxLength)), ResultBuffer)
   LastIndex = i2
End Sub

Sub GetNumberValueFromKey (json() As Byte, Key() As Byte, StartIndex As Int) As Double
   Dim bc As ByteConverter
   Dim qkey() As Byte = JoinBytes(Array(quotearray, Key, quotearray))
   Dim i As Int = bc.IndexOf2(json, qkey, StartIndex)
   If i = -1 Then Return 0
   Dim colon As Int = bc.IndexOf2(json, ":", i + qkey.Length)
   Dim i2 As Int = 0
   For Each c As String In Array As String(",", "}", "]")
       i2 = bc.IndexOf2(json, c, colon + 1)
       If i2 <> -1 Then
           Exit       
       End If
   Next
   Dim res() As Byte = bc.SubString2(json, colon + 1, i2)
   LastIndex = i2 + 1
   res = bc.Trim(res)
   Dim s As String = bc.StringFromBytes(res)
   Dim value As Double = s
   Return value
End Sub

Depends on rRandomAccessFile.
 

peacemaker

Expert
Licensed User
Longtime User
Maybe useful, @Erel, please, check the fixes and delete if no relevant:

B4X:
Sub Process_Globals
    Public Serial1 As Serial
    Private jsontext() As Byte = "{  ""id"": ""84F3EBE3621A"",  ""name"": ""Kitchen"",  ""get_status"": ""0,1,1,1,0,1,1,0"",  ""set_status"": ""0,1,1,1,0,1,1,0"",  ""get"": {    ""index"": 8,    ""value"": 1  },  ""set"": {    ""index"": 8,    ""value"": 2  }}"
    Private quotearray() As Byte = """"
    Private LastIndex As Int
End Sub

Private Sub AppStart
    Serial1.Initialize(115200)
    Delay(100)
    Dim MaxSize As Int = 20
    Dim buffer(MaxSize) As Byte
    GetTextValueFromKey(jsontext, "name", 0, buffer, MaxSize)
    Log(buffer)
    GetTextValueFromKey(jsontext, "get_status", 0, buffer, MaxSize)
    Log(buffer)
    Log(GetNumberValueFromKey(jsontext, "value", 0))
    Log(GetNumberValueFromKey(jsontext, "value", LastIndex)) 'second value
End Sub

' Extracts a string value from JSON by key with robust error handling
' Parameters:
'   JSON() - source JSON byte array
'   Key() - key to search for
'   StartIndex - position to start searching from
'   ResultBuffer() - output buffer for the value
'   MaxLength - maximum characters to copy
Sub GetTextValueFromKey (JSON() As Byte, Key() As Byte, StartIndex As Int, ResultBuffer() As Byte, MaxLength As UInt)
    Dim bc As ByteConverter
    Dim qkey() As Byte = JoinBytes(Array(quotearray, Key, quotearray))
    Dim i As Int = bc.IndexOf2(JSON, qkey, StartIndex)
    If i = -1 Then
        bc.ArrayCopy(Array As Byte(), ResultBuffer)
        Return
    End If
   
    ' Find opening quote of the value
    Dim i1 As Int = bc.IndexOf2(JSON, quotearray, i + qkey.Length + 1)
   
    ' CRITICAL FIX: Validate that the opening quote exists
    If i1 = -1 Then
        bc.ArrayCopy(Array As Byte(), ResultBuffer)
        Return
    End If
   
    ' Find closing quote of the value
    Dim i2 As Int = bc.IndexOf2(JSON, quotearray, i1 + 1)
   
    ' CRITICAL FIX: Validate that the closing quote exists
    If i2 = -1 Then
        bc.ArrayCopy(Array As Byte(), ResultBuffer)
        Return
    End If
   
    ' Extract the value with length limit
    bc.ArrayCopy(bc.SubString2(JSON, i1 + 1, Min(i2, i1 + 1 + MaxLength)), ResultBuffer)
    LastIndex = i2
End Sub

'=============================================================================
' Extracts a numeric value from a JSON byte array by searching for a specific key
' 
' @param json() As Byte - The JSON data as a byte array
' @param Key() As Byte - The key to search for (without quotes)
' @param StartIndex As Int - Starting position to begin the search
' @return Double - The numeric value found, or 0 if not found
' 
' The extracted number is stored in the global variable LastIndex for further parsing
'=============================================================================
Sub GetNumberValueFromKey (json() As Byte, Key() As Byte, StartIndex As Int) As Double
    ' Initialize ByteConverter for byte array operations
    Dim bc As ByteConverter
    
    ' Create the quoted key by wrapping the key with double quotes
    Dim qkey() As Byte = JoinBytes(Array(quotearray, Key, quotearray))
    
    ' Find the position of the quoted key in the JSON
    Dim i As Int = bc.IndexOf2(json, qkey, StartIndex)
    If i = -1 Then
        Log("GetNumberValueFromKey: Key not found")
        Return 0
    End If
    
    ' Find the colon that separates the key from its value
    Dim colon As Int = bc.IndexOf2(json, ":", i + qkey.Length)
    If colon = -1 Then
        Log("GetNumberValueFromKey: Colon not found")
        Return 0
    End If
    
    ' Start searching for the number after the colon
    Dim pos As Int = colon + 1
    
    ' Skip any whitespace characters (space = ASCII 32)
    Do While pos < json.Length And json(pos) = 32
        pos = pos + 1
    Loop
    
    If pos >= json.Length Then
        Log("GetNumberValueFromKey: End of JSON reached")
        Return 0
    End If
    
    '======================================================================
    ' ENHANCED NUMBER PARSING
    ' Supports: integers, decimals, negative numbers, and scientific notation
    '======================================================================
    Dim numStart As Int = pos
    Dim numEnd As Int = pos
    
    ' Allowed characters in a number: digits, period, minus, plus, e, E
    Dim IsItNumber As Boolean = False
    
    ' Scan through the JSON to extract the complete number
    Do While numEnd < json.Length
        Dim ch As Byte = json(numEnd)
        
        ' Check if the character is part of a valid number
        If (ch >= 48 And ch <= 57) Or _      ' 0-9 digits
           ch = 46 Or _                       ' . decimal point
           ch = 45 Or _                       ' - minus sign
           ch = 43 Or _                       ' + plus sign
           ch = 101 Or ch = 69 Then           ' e or E for scientific notation
            IsItNumber = True
            numEnd = numEnd + 1
        Else
            ' Reached a delimiter (comma, brace, bracket, etc.) - stop parsing
            Exit
        End If
    Loop
    
    ' CRITICAL FIX: Validate that a delimiter was found
    If Not(IsItNumber) Or numEnd = numStart Then
        Log("GetNumberValueFromKey: No number found")
        LastIndex = numEnd
        Return 0
    End If
    
    ' Extract the number bytes and convert to string
    Dim numBytes() As Byte = bc.SubString2(json, numStart, numEnd)
    Dim numStr As String = bc.StringFromBytes(numBytes)
    
    Log("GetNumberValueFromKey: Extracted number: '", numStr, "'")
    
    ' Convert string to Double (B4R will handle invalid conversion gracefully)
    Dim value As Double = numStr
    
    ' Update the global LastIndex to continue parsing from after this number
    LastIndex = numEnd + 1
    Return value
End Sub
 
Last edited:
Top