Interactive PowerBasic Forum

IT-Consultant: Charles Pegge => OxygenBasic Examples => Topic started by: Charles Pegge on February 08, 2025, 11:00:03 AM

Title: Notes on JSON format
Post by: Charles Pegge on February 08, 2025, 11:00:03 AM
JSON
JavaScript Object Notation

https://www.w3schools.com/whatis/whatis_json.asp

JSON Syntax Rules
Data is in name/value pairs
Data is separated by commas
Curly braces hold objects
Square brackets hold arrays
example
{
"employees":[
    {"firstName":"John", "lastName":"Doe"},
    {"firstName":"Anna", "lastName":"Smith"},
    {"firstName":"Peter", "lastName":"Jones"}
]
}
JSON Data - A Name and a Value
JSON objects are written inside curly braces
JSON arrays are written inside square brackets

-->

https://www.w3schools.com/js/js_json_intro.asp
--
Valid Data Types
a string
a number
an object (JSON object)
an array
a boolean
a null
--
Values in JSON can be objects
{
"employee":{"name":"John", "age":30, "city":"New York"}
}
Values in JSON can be arrays
{
"employees":["John", "Anna", "Peter"]
}
--
representing inner quotes (backslash to escape)
{
  "message": "He said, \"Hello, world!\""
}

Title: Re: Notes on JSON format
Post by: Theo Gottwald on February 08, 2025, 02:16:05 PM
FUNCTION JSON_Parse (jsonString AS STRING) AS VARIANT

    ' Entferne führende und nachfolgende Leerzeichen
    jsonString = TRIM$(jsonString)

    ' Überprüfe, ob es sich um ein Objekt oder ein Array handelt
    IF LEFT$(jsonString, 1) = "{" THEN
        ' Objekt parsen
        JSON_Parse = ParseObject(jsonString)
    ELSEIF LEFT$(jsonString, 1) = "[" THEN
        ' Array parsen
        JSON_Parse = ParseArray(jsonString)
    ELSE
        ' Wert parsen
        JSON_Parse = ParseValue(jsonString)
    END IF

END FUNCTION

FUNCTION ParseObject (jsonString AS STRING) AS OBJECT

    ' Erstelle ein leeres Objekt
    DIM obj AS OBJECT
    CREATE OBJECT obj

    ' Entferne die geschweiften Klammern
    jsonString = MID$(jsonString, 2, LEN(jsonString) - 2)

    ' Teile den String in Schlüssel-Wert-Paare auf
    DIM pairs AS STRING
    pairs = SPLIT$(jsonString, ",")

    ' Verarbeite jedes Schlüssel-Wert-Paar
    DIM i AS INTEGER
    FOR i = 0 TO UBOUND(pairs)

        ' Teile das Paar in Schlüssel und Wert auf
        DIM pair AS STRING
        pair = TRIM$(pairs(i))
        DIM keyValue AS STRING
        keyValue = SPLIT$(pair, ":")

        ' Extrahiere Schlüssel und Wert
        DIM key AS STRING
        key = TRIM$(MID$(keyValue(0), 2, LEN(keyValue(0)) - 2))
        DIM value AS STRING
        value = TRIM$(keyValue(1))

        ' Füge den Wert dem Objekt hinzu
        obj.Add key, JSON_Parse(value)

    NEXT i

    ParseObject = obj

END FUNCTION

FUNCTION ParseArray (jsonString AS STRING) AS VARIANT

    ' Erstelle ein leeres Array
    DIM arr AS VARIANT
    REDIM arr(0)

    ' Entferne die eckigen Klammern
    jsonString = MID$(jsonString, 2, LEN(jsonString) - 2)

    ' Teile den String in Werte auf
    DIM values AS STRING
    values = SPLIT$(jsonString, ",")

    ' Verarbeite jeden Wert
    DIM i AS INTEGER
    FOR i = 0 TO UBOUND(values)

        ' Füge den Wert dem Array hinzu
        arr(i) = JSON_Parse(TRIM$(values(i)))

    NEXT i

    ParseArray = arr

END FUNCTION

FUNCTION ParseValue (jsonString AS STRING) AS VARIANT

    ' Überprüfe den Datentyp des Werts
    IF LEFT$(jsonString, 1) = """ THEN
        ' String
        ParseValue = MID$(jsonString, 2, LEN(jsonString) - 2)
    ELSEIF jsonString = "true" THEN
        ' Boolesch (wahr)
        ParseValue = TRUE
    ELSEIF jsonString = "false" THEN
        ' Boolesch (falsch)
        ParseValue = FALSE
    ELSEIF ISNUMERIC(jsonString) THEN
        ' Zahl
        ParseValue = VAL(jsonString)
    ELSE
        ' Null
        ParseValue = NULL
    END IF

END FUNCTION

' JSON-String
DIM jsonString AS STRING
jsonString = "{""name"": ""John Doe"", ""age"": 30, ""city"": ""New York""}"

' JSON parsen
DIM jsonObject AS OBJECT
SET jsonObject = JSON_Parse(jsonString)

' Auf Werte zugreifen
DIM name AS STRING
name = jsonObject.name
DIM age AS INTEGER
age = jsonObject.age
DIM city AS STRING
city = jsonObject.city

' Werte ausgeben
PRINT "Name: " + name
PRINT "Age: " + STR$(age)
PRINT "City: " + city

[Source: Gemini KI (https://gemini.google.com/app/35f1525de9bd6656)]
Title: Re: Notes on JSON format
Post by: Charles Pegge on February 08, 2025, 03:27:39 PM
Thanks Theo, that has given me some ideas for a compact JSON parser. I can almost visualize the code.
Title: Re: Notes on JSON format
Post by: Theo Gottwald on February 08, 2025, 06:22:55 PM
In fact i tested Gemini and got that response.
Title: Re: Notes on JSON format
Post by: Frank Brübach on February 08, 2025, 08:24:02 PM
For Charles: you can also have a Look at Here:

https://github.com/StringEpsilon/fbJson/tree/master

#include "fbJson.bi"

' JSON-Daten als String
dim as string jsonString = "{""name"": ""Max"", ""age"": 25, ""skills"": [""FreeBASIC"", ""JSON""]}"

' JSON-Daten parsen
dim as jsonItem jsonData = JsonItem(jsonString)

' Zugriff auf JSON-Elemente
print "Name: " & jsonData["name"].asString()
print "Alter: " & jsonData["age"].asInteger()

' Zugriff auf Array-Werte
dim as jsonItem skillsArray = jsonData["skills"]
for i as integer = 0 to skillsArray.count() - 1
    print "Skill " & (i + 1) & ": " & skillsArray[i].asString()
next

' JSON-Daten manipulieren
jsonData["city"] = JsonItem("Berlin") ' Neues Element hinzufügen
print "Stadt: " & jsonData["city"].asString()

' Serialisieren (zurück in einen JSON-String)
print "Serialisiertes JSON: " & jsonData.toString()
Title: Re: Notes on JSON format
Post by: Theo Gottwald on February 09, 2025, 09:20:52 AM
Quote from: Charles Pegge on February 08, 2025, 03:27:39 PMThanks Theo, that has given me some ideas for a compact JSON parser. I can almost visualize the code.


If you can visualize code you can use that ability to create new commands that can shorten the code.
Title: Re: Notes on JSON format
Post by: Charles Pegge on February 10, 2025, 12:01:33 AM
A one piece JSON parser for testing. It should be able to cope with deeply recursive JSON structures.

'JSON PARSING
'10/02/2025
'
uses console
'
'INPUT
'
string s=quote
~~~

{
"employees":[
    {"firstName":"John", "lastName":"Doe", value:30.5 },
    {"firstName":"Anna", "lastName":"Smith"},
    {"firstName":"Peter", "lastName":"Jones"}
]
}

~~~

interface
=========
'
's source strung
'
'outputs:
'
string name[1000] 'names of objects
string  dat[1000] 'data of objects
int    dmap[1000] 'location of name:object
int    dlvl[1000] 'nesting level of objects
int    je         'count of all objects
'
====================
subroutine JsonParse
====================
'
indexbase 1 'arrays lbound
int i,j
int gf,bf,be,cc,sc,db,ty,dm
int qc,qf,qe,td,tf,te,sa,sd,nc
byte*b
@b=strptr(s)-1 'byte overlay
i=0            'char iterator
j=0            'index items
sa=0           'array capture flag
sd=0           'array items flag
nc=0           'nesting depth
'
'
===================================
NextItem: 'clear flags and counters
===================================
'
j++            'increment name / dat index
qf=0           'quote flag start
qe=0           'quote end
qc=0           'quote toggle
tf=0           'text flag
bf=0           'object flag
gf=0           'array fkag stt
cc=0           '{} object depth
sc=0           '[] array depth
td=0           'end of text flag
ty=0           'type of direct data
dm=0           'dmap assigned flag
ty=0           'raw data flgs
db=sa          'data flag

================
do 'parsing loop
================
'
@b++
i++
td=0 'assume delimiting char
'
select b 'byte pointer
'
=========
case   0 ' ' end of string
=========
  '
  exit do
  '
=========
case 1 to 32 ' ' white space
=========
  '
  continue do
  '
=========
case  "\" 'escape char
=========
  @b++ : i++ : td=1
  'itr edit out '\'
  if b=0 then exit do
=========
case  34 '"' quote flag toggle
=========
  qc xor=1
  if qc then
    qf=i
  else
    qe=i
    if gf+bf=0
      if db
        dat(j)=mid(s,qf+1,qe-qf-1)
        if dm=0
          dmap[j]=qf+1
          dlvl[j]=nc
        endif
        goto nextitem
      else
        name(j)=mid(s,qf+1,qe-qf-1)
        dmap[j]=qf+1
        dlvl[j]=nc
        dm=1
        tf=0 'text flag
        db=1 'data flag (expecting)
        continue do
      endif
    endif
  endif
==========
case qc<>0
==========
  '
  continue do 'till the quote ends
  '
=========
case ","
=========
  'capture unquoted data
  gosub captData
  if ty
    goto nextitem
  endif
=========
case  ":"
=========
  if gf+bf=0
    if qf=0 then
      name[j]=mid(s,tf,te-tf+1) 'raw name
      dmap[j]=tf
      dlvl[j]=nc
      dm=1
    endif
    qf=0 'clear quote flag
    tf=0 'text flag
    db=1 'data flag (expecting)
    continue do
  endif
=========
case  "["
=========
  nc++
  if db
    sc++
    if gf+bf=0
      if sc=1 'start array
        bf=i
        sa=1 'array capture flag
      endif
    endif
  else 'db=0
    'splitting array into separate items
    'no name assigned
    name(j)=""
    sd=1
  endif
=========
case  "]"
=========
  nc--
  sc--
  gosub CaptData
  if sc=0 'end inner array
    sa=0
    if ty=0
      dat[j]=mid(s,bf,i-bf+1)   'brackets included
      if dm=0
        dmap[j]=bf
        dlvl[j]=nc
      endif
    endif
    goto nextitem
  elseif sc<0
    sc=0
    sa=0
    sd=0
    if nc<=0
      if ty
        j++
      endif
      exit do 'splitting array complete
    else
      goto nextitem
    endif
  endif
=========
case "{"
=========
  nc++
  if sa+sd
    db=1 'objects inside an array
  endif
  if db
    cc++
    if cc=1 'inner object
      gf=i  'start of {} block
    endif
  else 'db=0
    'splitting an object into parts
  endif
=========
case "}"
=========
  nc--
  cc--
  gosub CaptData
  if cc=0 'end inner object
    if sa=0 'not inside array
      dat[j]=mid(s,gf,i-gf+1) 'brackets included
      if dm=0
        dmap[j]=gf
        dlvl[j]=nc
      endif
      goto nextitem
    endif
  elseif cc<0
    cc=0
    if nc<=0
      if ty
        j++
      endif
      exit do 'splitting array complete
    else
      goto nextitem
    endif
  endif
=========
case else 'covers all other ascii
=========
  td=1
  if gf+bf=0
    if tf=0
      tf=i
      'start of unquoted /
      'name/number/true/flse/null
    endif
    te=i
  endif
end select
'
'
end do 'parsing loop


SubRoutine CaptData 'internal
=============================
'
ty=0
if gf+bf+td+qf=0
  if tf
    if db
      'unquoted data
      dat[j]=mid(s,tf,te-tf+1)
      if dm=0
        dmap[j]=tf
        dlvl[j]=nc
      endif
      'numbers/true/falsr/null
      ty=1
    endif
  endif
endif
end subroutine 'CaptData


je=j-1 'set end of data

end subroutine 'JsonParse
'
'===========
'TEST OUTPUT
'===========
'
int i
print cr
gosub JsonParse
for i=1 to je
  print i " NAME: " name[i] cr
  print i " DATA: " dat[i] cr
next
print cr cr
'
print "split array" cr
s=dat(1)
gosub JsonParse
for i=1 to je
  print i " NAME: " name[i] cr
  print i " DATA: " dat[i] cr
next
print cr

print "split object" cr
s=dat(1)
gosub JsonParse
for i=1 to je
  print i " NAME: " name[i] cr
  print i " DATA: " dat[i] cr
next
print cr

wait

Title: Re: Notes on JSON format , 2D Array
Post by: Charles Pegge on February 12, 2025, 03:55:05 AM
Representing 2D Arrays:

'12/02/2025
'2d array to JSON
'
dim int ar[10,10]
int x,y
'
'DATA
'
for y=1 to 10
  for x=1 to 10
    ar[y,x]=x-11+y*10
  next
next
'
'JSON FORMAT 2D ARRAY
'
uses console
int le
string s
int i=1
string buf=nuls 100000 '100k
'
def append
  le=len  s
  mid buf,i,s
  i+=le
end def
'
s="{"+cr+"  "+qu+"array"+qu+":["+cr
append
for y=1 to 10
  s="    [ "
  append
  for x=1 to 10
    s=str(ar[y,x])
    if x<10
      s+=","
    endif
    append
  next
  s="  ]"+cr
  append
next
s=cr+"  ]"+cr+"}"+cr
append
'
buf=left buf, i-1
print buf
wait

Result:
{
  "array":[
    [ 0,1,2,3,4,5,6,7,8,9  ]
    [ 10,11,12,13,14,15,16,17,18,19  ]
    [ 20,21,22,23,24,25,26,27,28,29  ]
    [ 30,31,32,33,34,35,36,37,38,39  ]
    [ 40,41,42,43,44,45,46,47,48,49  ]
    [ 50,51,52,53,54,55,56,57,58,59  ]
    [ 60,61,62,63,64,65,66,67,68,69  ]
    [ 70,71,72,73,74,75,76,77,78,79  ]
    [ 80,81,82,83,84,85,86,87,88,89  ]
    [ 90,91,92,93,94,95,96,97,98,99  ]

  ]
}