User Tools

Site Tools


Sidebar

Network and communication

k24:k24.6:k24.6.9:k24.6.9.1:start

24.6.9.1 Project formatter for JSON text

You will encounter more applications in the future that rely on the compact JSON format as the format for exporting or importing data. The data is serialised as JSON text.

For processing data in JSON format, the JSON.Decode(…) method implements both a validator and a parser for a JSON text. Data in JSON format becomes data of the Gambas type Variant and can be of the type Collection or JSONCollection.

For example, the following JSON text with weather data is very compact:

{"coord":{"lon":11.77,"lat":52.78},"weather":[{"id":801,"main":"Clouds","description":"few  clouds","icon": "02d"}],
"base":"cmc stations","main":{"temp":12.48,"pressure":1017.3,"humidity":85,"temp_min":12.48, "temp_max":12.48,
"sea_level":1021.8,"grnd_level":1017.3},"wind":{"speed":6.67,"deg":242.504},"clouds":{"all":24},"dt":1459947946,
"sys":{"message":0.0075,"country":"DE","sunrise":1459917197,"sunset": 1459965476},"id":2856639,"name":"Osterburg","cod":200}

The same text is much easier to read if it is output formatted. Since the formatted JSON text is well structured, it is also easy to read:

{
  coord: {
    lon: 11,77,
    lat: 52,78
  },
  weather: [
    {
      id: 801,
      main: "Clouds",
      description: "few clouds",
      icon: "02d"
    }
  ],
  base: "cmc stations",
  main: {
    temp: 12,48,
    pressure: 1017,3,
    humidity: 85,
    temp_min: 12,48,
    temp_max: 12,48,
    sea_level: 1021,8,
    grnd_level: 1017,3
  },
  wind: {
    speed: 6,67,
    deg: 242,504
  },
  clouds: {
    all: 24
  },
  dt: 1459947946,
  sys: {
    message: 0,0075,
    country: "DE",
    sunrise: 1459917197,
    sunset: 1459965476
  },
  id: 2856639,
  name: "Osterburg",
  cod: 200
}

There is no method in Gambas for the formatted display of data in JSON format. In this project, you will therefore be presented with two variants of how to output a JSON text in a formatted way.

  • Variant 1: The JSON grammar in RFC 7159 (→ https://tools.ietf.org/html/rfc7159) is very simple. It is a good idea to use this grammar as a template when analysing the structure of a JSON text, because it clearly describes the structure of JSON text.
  • Variant 2: Using the JSON tool of the Python language via a shell call.

24.6.9.1.1 Variant 1

The RFC text says that a JSON value is constructed like this:

value = object | array | number | string | 'true' | 'false' | 'null'

An array, for example, is described according to the grammar like this:

array = "[" [value *("," value)] "]"

This description, along with the others, can be carried over into the following Gambas procedures:

Private Sub PutValue()
  txaOutput.Insert(Space$(iIndent) & IIf(sKey, "\"" & sKey & "\"" & ": ", ""))
  Select Case TypeOf(vValue)
    Case gb.Object
      If vValue Is JSONCollection Then
         PutObject()
      Else If vValue Is Variant[] Then
         PutArray()
      Endif
    Case gb.Integer, gb.Long, gb.Float
      PutNumber()
    Case gb.String
      PutString()
    Case gb.Boolean
      PutBoolean()
    Case gb.Null
      PutNull()
  End Select
End ' PutValue()
 
Private Sub PutObject()
  Dim vElement As Variant, iElement As Integer, jCol As JSONCollection = vValue
 
  txaOutput.Insert("{" & gb.NewLine)
  iIndent += 2
  iElement = 1
  For Each vElement In jCol
    sKey = jCol.Key
    vValue = vElement
    PutValue()
    txaOutput.Insert(IIf(iElement < jCol.Count, ",", "") & gb.NewLine)
    Inc iElement
  Next
  iIndent -= 2
  txaOutput.Insert(Space$(iIndent) & "}")
 
End ' PutObject()
 
Private Sub PutArray()
  Dim iIndex As Integer, aArray As Variant[] = vValue
 
  txaOutput.Insert("[" & gb.NewLine)
  iIndent += 2
  For iIndex = 0 To aArray.Max
    sKey = ""
    vValue = aArray[iIndex]
    PutValue()
    txaOutput.Insert(IIf(iIndex < aArray.Max, ",", "") & gb.NewLine)
  Next
  iIndent -= 2
  txaOutput.Insert(Space$(iIndent) & "]")
 
End ' PutArray()
 
Private Sub PutBoolean()
  txaOutput.Insert(IIf(vValue, "true", "false"))
End ' PutBoolean()
 
Private Sub PutNumber()
  txaOutput.Insert(Str$(vValue))
End ' PutNumber()
 
Private Sub PutString()
  txaOutput.Insert(Subst$("\"&1\"", vValue))
End ' PutString()
 
Private Sub PutNull()
  txaOutput.Insert("null")
End ' PutNull()

Note that the project source code maps the JSON grammar 1:1. A non-terminal symbol in the grammar - for example, string - always corresponds to a function that recognises and outputs the non-terminal symbol, with the functions calling each other.

The procedure EditData(…) is passed the JSON text as a parameter, which is decoded and then available in the global variable vValue of the procedure PutValue():

Private Sub EditData(Data As String)
 
  Dim jCollection As JSONCollection
 
  Try jCollection = JSON.Decode(Data, True) ' VALIDATOR
 
  If Error Then
     Message.Error("<b>Error decoding!</b><br>" & Error.Text & "  Error-Code = " & Error.Code)
     Return
  Endif
 
  sKey = Null
  vValue = jCollection
  iIndent = 0
  PutValue()
 
End ' EditData(Data As String)
<code>
 
Ausgelöst wird die strukturierte Anzeige des JSON-Textes durch die folgende Prozedur:
 
<code gambas>
Public Sub btnFormattingJSON_Click()
  txaOutput.Clear()
  EditData(txaInput.Text)
End ' btnFormattingJSON_Click()

B1
Figure 24.6.9.1.1: Formatted Display - Variant 1

The formatted JSON text is displayed if the JSON text is syntactically OK.

Try jCollection = JSON.Decode(Data, True) ' VALIDATOR

If an error occurs when decoding the JSON text, this is displayed - the project thus also contains a validator for JSON text:

B2
Figure 24.6.9.1.2: Error message (validator)

Project example 3 shows the JSON text for the data of a TreeView. In the → Chapter 17.9 TreeView project, the data is exported and imported in JSON format. This makes it possible to access the exported elements of the TreeView at any time during the testing of the project and to generate and display the elements of the TreeView from the imported data:

B3
Figure 24.6.9.1.3: GUI for testing properties and methods of a TreeView.

24.6.9.1.2 Variant 2

You can also achieve the formatted output of JSON text - sorted by the individual key values - like this:

Public Sub btnFormattingJSONPython_Click()
 
 txaOutput.Clear()
 Try Shell "echo '" & txaInput.Text & "' | python -m json.tool" To txaOutput.Text
 txaOutput.Pos = 0
 
End ' btnFormattingJSONPython_Click()

24.6.9.1.3 Extension

An extension was included in the project to help you determine and display the mapping between the key and the value type of the decoded JSON text (Collection or JSONCollection type). You will only realise the advantage of using the procedure GetStructure(…) and the function GetType(…) when you try out the project in → Chapter 24.6.9.2:

Private Sub GetStructure(Data As String)
 
  Dim i As Integer = 1, vVariant As Variant
  Dim jCollection As JSONCollection
 
  Try jCollection = JSON.Decode(Data, True)
  If Error Then
     Message.Error("<b>Error decoding!</b><br>" & Error.Text & "  Error-Code = " & Error.Code)
     Return
  Endif
 
  txaOutput.Insert(gb.NewLine)
  txaOutput.Insert("Anzahl der Elemente in der JSON-Collection: " & jCollection.Count & gb.NewLine)
  txaOutput.Insert(gb.NewLine)
  txaOutput.Insert(String$(100, "-") & gb.NewLine & gb.NewLine)
 
  For Each vVariant In jCollection
    txaOutput.Insert(("Key ") & Str(i) & " : \"" & jCollection.Key & "\"" & (" ---> Value-Type: ") & /
                      GetType(vVariant) & gb.NewLine)
    Inc i
  Next
End ' GetStructure(...)
 
Private Function GetType(Value As Variant) As String
  Select Case TypeOf(Value)
    Case gb.Boolean ' 1
      Return "Boolean"
    Case gb.Integer ' 4
      Return "Integer"
    Case gb.Long ' 5
      Return "Long-Integer"
    Case gb.Float ' 7
      Return "Float"
    Case gb.String '9
      Return "String"
    Case gb.Null ' 15
      Return "NULL OR JSON-Null"
    Case gb.Object ' 16
      If Value Is JSONCollection Then Return "JSONCollection"
      If Value Is Collection Then Return "Collection"
      If Value Is Variant[] Then Return "Variant[]"
  End Select
  Return "?"
End ' GetType(...)

B4
Figure 24.6.9.1.4: Assignment between key and value type

Download

The website uses a temporary session cookie. This technically necessary cookie is deleted when the browser is closed. You can find information on cookies in our privacy policy.
k24/k24.6/k24.6.9/k24.6.9.1/start.txt · Last modified: 16.08.2022 (external edit)

Page Tools