Author Topic: JSON Reader  (Read 3392 times)

0 Members and 1 Guest are viewing this topic.

Offline Ashish

  • Forum Resident
  • Posts: 630
  • Never Give Up!
    • View Profile
JSON Reader
« on: August 03, 2021, 07:00:49 am »
Hello everyone!
I have coded a JSON reader. It can read a JSON string and it supports nested list, nested JSON objs and the mix of both
JSON obj and list.

Here is the code which contain JSON reader function -
Code: QB64: [Select]
  1. Dim test$, l$
  2.  
  3. Open "test.json" For Binary As #1
  4. test$ = Space$(LOF(1))
  5. Get #1, , test$
  6.  
  7. 'label$ is case-sensitive
  8.     Input "label : ", l$ 'try .server-name or .roles.special.devs or roles.common.regulars.[1]
  9.     Print json$(test$, l$)
  10.  
  11. 'JSON Reader in QB64
  12. 'By AshishKingdom
  13. Function json$ (json_data_0$, l$)
  14.     If Len(json_data_0$) = 0 Or Len(l$) = 0 Then Exit Function
  15.     If _Trim$(l$) = "." Then json$ = json_data_0$: Exit Function
  16.  
  17.     Dim As Long startPos, endPos, label_pos1, label_pos2, num_of_br
  18.     Dim As Long f0, f1, f2, f3, f4, f5, f6, list_obj_pos
  19.     Dim As _Byte value_type, in_quote '1=object, 2=array, 0=string or number
  20.     Dim As String sep_type, curr_label, ca, label, json_data, tmp_str
  21.     Dim As Long list_pos1, list_pos2, list_index
  22.  
  23.     label$ = l$
  24.     json_data$ = json_data_0$
  25.  
  26.     json_list_sec:
  27.  
  28.     label_pos1 = InStr(label$, ".")
  29.     If label_pos1 = 0 Then json$ = json_data$: Exit Function
  30.     label_pos2 = InStr(label_pos1 + 1, label$, ".")
  31.  
  32.  
  33.     list_pos1 = InStr(label$, "[")
  34.     If list_pos1 Then
  35.         If label_pos2 = 0 Then
  36.             list_pos2 = InStr(list_pos1 + 1, label$, "]")
  37.  
  38.             If list_pos1 < label_pos1 Then Print "json_parser_error: '.' inside [] ": Exit Function
  39.             If list_pos2 = 0 Then Print "json_parser_error: missing ] in label": Exit Function
  40.  
  41.             list_index = Val(Mid$(label$, list_pos1 + 1, list_pos2 - list_pos1 - 1))
  42.             tmp_str = _Trim$(json_list(json_data$, list_index))
  43.             json_data$ = tmp_str
  44.             label$ = Right$(label$, Len(label$) - list_pos2)
  45.             GoTo json_list_sec 'for nested list (if present), it will keep on parsing it
  46.         Else
  47.             If list_pos1 > label_pos1 And list_pos1 < label_pos2 Then
  48.                 'list index present
  49.                 list_pos2 = InStr(list_pos1 + 1, label$, "]")
  50.                 If list_pos2 = 0 Then Print "json_parser_error: missing ] in label": Exit Function
  51.                 If list_pos2 > label_pos2 Then Print "json_parser_error: '.' inside [] ": Exit Function
  52.                 list_index = Val(Mid$(label$, list_pos1 + 1, list_pos2 - list_pos1 - 1))
  53.                 tmp_str = _Trim$(json_list(json_data$, list_index))
  54.                 json_data$ = tmp_str
  55.                 label$ = Right$(label$, Len(label$) - list_pos2)
  56.                 GoTo json_list_sec 'for nested list (if present), it will keep on parsing it
  57.             End If
  58.         End If
  59.     End If
  60.  
  61.     startPos = getAbsCharPos(json_data$, "{", 1)
  62.     If startPos = 0 Then json$ = json_data$: Exit Function 'its not a json object then
  63.     list_obj_pos = getAbsCharPos(json_data$, "[", 1)
  64.     If startPos > list_obj_pos And list_obj_pos <> 0 Then Exit Function 'its probably a list
  65.     endPos = charFind(json_data$, "}", 1, 1, 1)
  66.     f0 = startPos + 1
  67.     While 1
  68.  
  69.         f2 = getAbsCharPos(json_data$, ":", f0)
  70.  
  71.         If f2 = 0 Then Exit Function
  72.         f1 = getAbsCharPos(json_data$, ",", f2 + 1)
  73.  
  74.         f5 = getAbsCharPos(json_data$, "[", f0)
  75.         f6 = getAbsCharPos(json_data$, "{", f0)
  76.         sep_type = ""
  77.         If f5 = 0 And f6 = 0 Then
  78.             f3 = 0
  79.         ElseIf f5 = 0 And f6 > 0 Then
  80.             f3 = f6
  81.             sep_type = "}"
  82.         ElseIf f6 = 0 And f5 > 0 Then
  83.             f3 = f5
  84.             sep_type = "]"
  85.         ElseIf f5 < f6 And f5 <> 0 Then
  86.             f3 = f5
  87.             sep_type = "]"
  88.         ElseIf f6 < f5 And f6 <> 0 Then
  89.             f3 = f6
  90.             sep_type = "}"
  91.         End If
  92.  
  93.         If f3 = 0 Then
  94.             value_type = 0
  95.         Else
  96.             'check if ',' was before [ or {
  97.  
  98.             If f1 < f3 And f1 <> 0 Then
  99.                 ' comma present before [ or {
  100.                 value_type = 0
  101.             Else
  102.                 'comma present after.. so it may be inside {}/[] or outside of it.
  103.                 'finding end of position of json_obj/list present
  104.                 num_of_br = 1
  105.                 f4 = f3
  106.                 in_quote = 1
  107.                 While num_of_br > 0
  108.                     f4 = f4 + 1
  109.                     If f4 > endPos Then Print "json_parser_error: missing "; sep_type: Exit Function
  110.  
  111.                     ca = Mid$(json_data$, f4, 1)
  112.                     If ca = Chr$(34) Then in_quote = in_quote * -1
  113.                     If in_quote = 1 Then
  114.                         If ca = "{" Or ca = "[" Then num_of_br = num_of_br + 1
  115.                         If ca = "}" Or ca = "]" Then num_of_br = num_of_br - 1
  116.                     End If
  117.                 Wend
  118.                 If sep_type = "}" Then value_type = 1 Else value_type = 2
  119.             End If
  120.         End If
  121.  
  122.  
  123.         If f2 > f1 And f1 <> 0 Then
  124.             Print "json_parser_error: ',' before ':'"
  125.             Exit Function
  126.         End If
  127.         'Print value_type, f3, f4
  128.         'Sleep
  129.         If value_type = 0 Then
  130.  
  131.             If getData(Mid$(json_data$, f0, f2 - 1 - f0)) = Right$(label$, Len(label$) - 1) Then
  132.                 If f1 = 0 Then
  133.                     json$ = getData(Mid$(json_data$, f2 + 1, endPos - f2 - 1))
  134.                 Else
  135.                     json$ = getData(Mid$(json_data$, f2 + 1, f1 - f2 - 1))
  136.                 End If
  137.                 Exit Function
  138.             Else
  139.                 If f1 = 0 Then Exit Function Else f0 = f1 + 1
  140.             End If
  141.         Else
  142.             If label_pos2 = 0 Then
  143.                 curr_label = Right$(label$, Len(label$) - 1)
  144.             Else
  145.                 curr_label = Mid$(label$, label_pos1 + 1, label_pos2 - label_pos1 - 1)
  146.             End If
  147.             'Print curr_label, getData(Mid$(json_data$, f0, f2 - 1 - f0))
  148.             'Sleep
  149.             If getData(Mid$(json_data$, f0, f2 - 1 - f0)) = curr_label Then
  150.                 If label_pos2 = 0 Then
  151.                     json$ = Mid$(json_data$, f3, f4 - f3 + 1)
  152.                     Exit Function
  153.                 Else
  154.                     'Print Mid$(json_data$, f3, f4 - f3 + 1)
  155.                     'Print Right$(label$, Len(label$) - label_pos2 + 1)
  156.                     json$ = json$(Mid$(json_data$, f3, f4 - f3 + 1), Right$(label$, Len(label$) - label_pos2 + 1))
  157.                     Exit Function
  158.                 End If
  159.             Else
  160.                 f1 = getAbsCharPos(json_data$, ",", f4 + 1)
  161.                 If f1 = 0 Then f0 = f4 + 1 Else f0 = f1 + 1
  162.                 'Print "hha ", f1, f0
  163.             End If
  164.         End If
  165.     Wend
  166.  
  167. Function json_list$ (list_data$, index As _Unsigned Long)
  168.     If list_data$ = "" Then Exit Function
  169.  
  170.     Dim As Long startPos, endPos, curr_index, json_obj_pos, value_type
  171.     Dim As Long f0, f1, f2, f3, f4, f5, f6, i
  172.     Dim As Long num_of_br
  173.     Dim As String ca, sep_type
  174.     Dim As _Byte element_present, in_quote
  175.  
  176.     startPos = InStr(list_data$, "[")
  177.     endPos = charFind(list_data$, "]", 0, 1, 1)
  178.     If startPos = 0 Then json_list$ = list_data$: Exit Function 'its not a list
  179.     json_obj_pos = getAbsCharPos(list_data$, "{", 1)
  180.     If startPos > json_obj_pos And json_obj_pos <> 0 Then Exit Function 'probably its a json object
  181.  
  182.     f0 = startPos + 1
  183.     curr_index = 0
  184.     While 1
  185.         f1 = getAbsCharPos(list_data$, ",", f0)
  186.         '  f2 = getAbsCharPos(list_data$, "[", f0)
  187.         f5 = getAbsCharPos(list_data$, "[", f0)
  188.         f6 = getAbsCharPos(list_data$, "{", f0)
  189.         sep_type = ""
  190.         If f5 = 0 And f6 = 0 Then
  191.             f3 = 0
  192.         ElseIf f5 = 0 And f6 > 0 Then
  193.             f3 = f6
  194.             sep_type = "}"
  195.         ElseIf f6 = 0 And f5 > 0 Then
  196.             f3 = f5
  197.             sep_type = "]"
  198.         ElseIf f5 < f6 And f5 <> 0 Then
  199.             f3 = f5
  200.             sep_type = "]"
  201.         ElseIf f6 < f5 And f6 <> 0 Then
  202.             f3 = f6
  203.             sep_type = "}"
  204.         End If
  205.  
  206.         If f3 = 0 Then
  207.             value_type = 0
  208.         Else
  209.             'check if ',' was before [ or {
  210.  
  211.             If f1 < f3 And f1 <> 0 Then
  212.                 ' comma present before [ or {
  213.                 value_type = 0
  214.             Else
  215.                 'comma present after.. so it may be inside {}/[] or outside of it.
  216.                 'finding end of position of json_obj/list present
  217.                 num_of_br = 1
  218.                 f4 = f3
  219.                 in_quote = 1
  220.                 While num_of_br > 0
  221.                     f4 = f4 + 1
  222.                     If f4 > endPos Then Print "json_parser_error: missing "; sep_type: Exit Function
  223.  
  224.                     ca = Mid$(list_data$, f4, 1)
  225.                     If ca = Chr$(34) Then in_quote = in_quote * -1
  226.                     If in_quote = 1 Then
  227.                         If ca = "{" Or ca = "[" Then num_of_br = num_of_br + 1
  228.                         If ca = "}" Or ca = "]" Then num_of_br = num_of_br - 1
  229.                     End If
  230.                 Wend
  231.                 f1 = f4 + 1
  232.                 If sep_type = "}" Then value_type = 1 Else value_type = 2
  233.             End If
  234.         End If
  235.         'Print f0, f1, ca, curr_index, index
  236.  
  237.         If f1 = 0 Then
  238.             'check if there's any value here
  239.             If curr_index = index Then
  240.                 element_present = 0
  241.  
  242.                 For i = f0 To endPos - 1
  243.                     If Asc(Mid$(list_data$, i, 1)) <> 32 Then element_present = 1
  244.                 Next
  245.                 If element_present = 1 Then
  246.                     If value_type = 0 Then
  247.                         json_list$ = getData(Mid$(list_data$, f0, endPos - f0))
  248.                     Else
  249.                         json_list$ = Mid$(list_data$, f0, endPos - f0 + 1)
  250.                     End If
  251.                 End If
  252.             End If
  253.             Exit Function
  254.         Else
  255.             If curr_index = index Then
  256.                 If value_type = 0 Then
  257.                     json_list$ = getData(Mid$(list_data$, f0, f1 - f0))
  258.                 Else
  259.                     json_list$ = Mid$(list_data$, f0, f1 - f0)
  260.                 End If
  261.                 Exit Function
  262.             Else
  263.                 f0 = f1 + 1
  264.             End If
  265.         End If
  266.         curr_index = curr_index + 1
  267.     Wend
  268.  
  269. Function getAbsCharPos~& (main_str As String, char As String, s As _Unsigned Long) 'give position of char which is outside of quotes
  270.     Dim As _Unsigned Long i, qp
  271.     Dim ca$, q$
  272.  
  273.     qp = 1
  274.     For i = s To Len(main_str)
  275.         ca$ = Mid$(main_str, i, 1)
  276.         If ca$ = Chr$(34) Then q$ = ca$: qp = qp * -1
  277.         If ca$ = char And qp = 1 Then
  278.             getAbsCharPos~& = i
  279.             Exit Function
  280.         End If
  281.     Next
  282. Function getData$ (main_str As String) 'quote_type=1("), 2=(')
  283.     Dim quote$, i As _Unsigned Long, j As _Unsigned Long
  284.     Dim c$
  285.     If InStr(main_str, Chr$(34)) = 0 Then
  286.         getData$ = _Trim$(main_str)
  287.         'Print "yes"
  288.         'Print main_str
  289.         Exit Function
  290.     End If
  291.     For i = 1 To Len(main_str)
  292.         c$ = Mid$(main_str, i, 1)
  293.         If c$ = Chr$(34) Then
  294.             quote$ = c$
  295.             For j = i + 1 To Len(main_str)
  296.                 c$ = Mid$(main_str, j, 1)
  297.                 If c$ = quote$ Then Exit Function
  298.                 getData$ = getData$ + c$
  299.             Next
  300.         End If
  301.     Next
  302. Function charFind~& (main_str As String, search As String, p As _Unsigned Long, fromEnd As _Byte, ignore_quote As _Byte)
  303.     If Len(main_str) = 0 Or Len(search) = 0 Then Exit Function
  304.     If fromEnd Then
  305.         Dim reversed$
  306.         For i = Len(main_str) To 1 Step -1
  307.             reversed$ = reversed$ + Mid$(main_str, i, 1)
  308.         Next
  309.         'Print reversed$
  310.         If ignore_quote Then charFind~& = -getAbsCharPos(reversed$, search, p) + 1 + Len(main_str) Else charFind~& = -InStr(p, reversed$, search) + 1 + Len(main_str)
  311.     Else
  312.         If ignore_quote Then charFind~& = getAbsCharPos(main_str, search, p) Else charFind~& = InStr(p, main_str, search)
  313.     End If
  314.  

Here is the test.json file which you need. Save the below JSON string into a file named test.json
Code: Text: [Select]
  1. {
  2.     "server-name" : "QB64",
  3.     "description" : "Server for qb64, qbasic and gw-basic fans.",
  4.     "roles" : {
  5.         "special": {
  6.             "devs" : ["Fellippe", "Luke", "Spriggsy", "SteveMcNeill"],
  7.             "Crew-Members" : ["Ashish", "Cobalt", "Qwerky", "STxAxTIC"]
  8.         },
  9.         "common" : {
  10.             "regulars" : ["Shalin", "Monke", "ChiaPet", "onecoding", "garbage", "loudar"]
  11.         }
  12.     },
  13.     "total-members" : 296
  14. }
  15.  

Use "." followed a by label to get value. Use "[ index ]" for a list to get a value.
if (Me.success) {Me.improve()} else {Me.tryAgain()}


My Projects - https://github.com/AshishKingdom?tab=repositories
OpenGL tutorials - https://ashishkingdom.github.io/OpenGL-Tutorials