Small tricks with JSON

Share your advanced PureBasic knowledge/code with the community.
Little John
Addict
Addict
Posts: 4527
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Small tricks with JSON

Post by Little John »

Here are tricks that make use of the JSON library, which is built into PB versions 5.30+.
Better do not use them in parts of your code where speed is crucial.
If you also have got JSON tricks, please post them here. :-)

Create an array
I originally posted the code in this thread.
The macro allows to quickly write concise and good readable code for creating and initializing an array at the same time.
It can create arrays of any standard type, with one or more dimensions.

//edit 2015-01-24
Changed
  • CreateArray()
    In order to make creation of string arrays easy, normally the character ' is used as quote, e.g.
    CreateArray(a$, "['dog', 'cat', 'mouse']").
    However, sometimes the character ' is part of the strings themselves. For handling this case, I've added the optional parameter _ersatzQuote_, which allows to use another character as quote (see 2nd example).
New
  • ComposeArray()
  • DebugArray()

Code: Select all

; <https://www.purebasic.fr/english/viewtopic.php?t=60589>
; by Little John

; Version 1.00
; successfully tested with
; [x] PB 5.30        (x86 and x64) on Windows
; [v] PB 6.03 beta 4 (x86 and x64) on Windows 11 – both ASM and C backend
; [v] PB 6.03 beta 4 (x64) on Linux Mint 20.3    – both ASM and C backend

; == Reusable macros

Macro CreateArray (_array_, _content_, _dimensions_=1, _ersatzQuote_="'")
   ; in : _array_      : name and type of array (without trailing brackets!),
   ;                     e.g. a.i
   ;      _content_    : content of array as string, e.g. "[1,2,3]"
   ;      _dimensions_ : number of array dimensions (1 or 2)
   ;      _ersatzQuote_: character used as quote in _content_, when _array_ is a string array
   ; out: _array_ (first index = 0)
   CompilerIf Not Defined(m_jArray,  #PB_Variable)
      Define m_jArray.i
   CompilerEndIf
   If Asc(_ersatzQuote_) <> 0
      ReplaceString(_content_, _ersatzQuote_, #DQUOTE$, #PB_String_InPlace)
   EndIf
   m_jArray = ParseJSON(#PB_Any, _content_)
   If m_jArray
      CompilerIf _dimensions_ = 1
         Dim _array_(0)
      CompilerElseIf _dimensions_ = 2
         Dim _array_(0, 0)
         ; If necessary, add code for more dimensions here.
      CompilerEndIf
      ExtractJSONArray(JSONValue(m_jArray), _array_())
      FreeJSON(m_jArray)
   EndIf
EndMacro

Macro ComposeArray (_array_, _content_, _ersatzQuote_="")
   ; in : _array_      : name of array (without trailing brackets!),
   ;                     e.g. a
   ;      _ersatzQuote_: character used as quote in _content_, when _array_ is a string array
   ; out: _content_: content of _array_ as string
   Define.i m_jArray = CreateJSON(#PB_Any)
   If m_jArray
      InsertJSONArray(JSONValue(m_jArray), _array_())
      _content_ = ComposeJSON(m_jArray)
      FreeJSON(m_jArray)
      If Asc(_ersatzQuote_) <> 0
         ReplaceString(_content_, #DQUOTE$, _ersatzQuote_, #PB_String_InPlace)
      EndIf
   EndIf
EndMacro

Macro DebugArray (_array_, _before_="", _after_="", _level_=0)
   ; in : _array_: name of array (without trailing brackets!),
   ;               e.g. a
   ;     _before_: text shown before array content
   ;     _after_ : text shown after  array content
   ;     _level_ : DebugLevel
   Define.i m_jArray = CreateJSON(#PB_Any)
   If m_jArray
      InsertJSONArray(JSONValue(m_jArray), _array_())
      Debug _before_ + ComposeJSON(m_jArray) + _after_, _level_
      FreeJSON(m_jArray)
   EndIf
EndMacro


; == Demo
EnableExplicit
Define i.i, k.i, ret$

CreateArray(a$, "['dog', 'cat', 'mouse']")

For i = 0 To ArraySize(a$())
   Debug a$(i)
Next

ComposeArray(a$, ret$)
Debug ret$

DebugArray(a$, "My zoo: ")

Debug "-----"

CreateArray(b$, "[|dog's collar|, |cat's tray|, |mouse's cheese|]", 1, "|")

For i = 0 To ArraySize(b$())
   Debug b$(i)
Next

ComposeArray(b$, ret$)
Debug ret$

DebugArray(b$)

Debug "-----"

CreateArray(x.d, "[1.5, 3.4, 5.3, 7.2, 9.1]")

For i = 0 To ArraySize(x())
   Debug StrD(x(i), 1)
Next

ComposeArray(x, ret$)
Debug ret$

DebugArray(x, "", "  <-- see here")

Debug "-----"

CreateArray(matrix.i, "[[1, 3, 5]," +
                      " [7, 8, 9]]", 2)

For i = 0 To ArraySize(matrix(), 1)
   ret$ = ""
   For k = 0 To ArraySize(matrix(), 2)
      ret$ + ", " + matrix(i, k)
   Next
   Debug "[" + Mid(ret$, 3) + "]"
Next

ComposeArray(matrix, ret$)
Debug ret$

DebugArray(matrix)

-------------------------------------------------

My best tricks & tips from 15+ years
Create arrays elegantly
Extended date library
Save JSON data with object members well-arranged
Evaluate and process math expressions
Functions for sets
Statistics with R
Thue-Morse sequence
Natural sorting
Sort array indexes and parallel arrays
Time profiling
VectorIcons
Last edited by Little John on Mon Aug 14, 2023 12:21 pm, edited 3 times in total.
Little John
Addict
Addict
Posts: 4527
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: Small tricks with JSON

Post by Little John »

Named parameters
Using named parameters for a procedure, the order of the parameters doesn't matter. This is the reason why handling optional parameters is very flexible when using named parameters. Since named parameters are self-documenting, using them results in good readable code.
The procedure in the following example has one normal parameter (which is always required), and three named parameters (which are optional).

Code: Select all

; PB 5.30+

EnableExplicit


Procedure Foo (alwaysRequired.i, optionalParams$)
   Protected x.d=10.5, y.d=20.3, msg.s="Hi!"   ; default values of parameters in 'optionalParams$'
   Protected.i jp, jv, jm
   
   ReplaceString(optionalParams$, "'", #DQUOTE$, #PB_String_InPlace)
   jp = ParseJSON(#PB_Any, "{"+optionalParams$+"}", #PB_JSON_NoCase)
   If jp
      jv = JSONValue(jp)
      
      jm = GetJSONMember(jv, "x")   : If jm : x   = GetJSONDouble(jm) : EndIf
      jm = GetJSONMember(jv, "y")   : If jm : y   = GetJSONDouble(jm) : EndIf
      jm = GetJSONMember(jv, "msg") : If jm : msg = GetJSONString(jm) : EndIf
      
      FreeJSON(jp)
   EndIf
   
   Debug alwaysRequired
   Debug x
   Debug y
   Debug msg
EndProcedure


Foo(-27, "'y':7.0, 'msg':'Hello, world!'")
User avatar
Derren
Enthusiast
Enthusiast
Posts: 313
Joined: Sat Jul 23, 2011 1:13 am
Location: Germany

Re: Small tricks with JSON

Post by Derren »

And here I thought the JSON lib was useless as you can't turn JS objects into PB objects (map) without writing your own parser, but this is actually great stuff right here.
The question is if the json lib is reasonable fast (overhead). Compared to two StringField()'s for the string parameter or direct memory peeks for example.
Little John
Addict
Addict
Posts: 4527
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: Small tricks with JSON

Post by Little John »

Derren wrote:And here I thought the JSON lib was useless as you can't turn JS objects into PB objects (map) without writing your own parser, but this is actually great stuff right here.
Thanks.
Derren wrote:The question is if the json lib is reasonable fast (overhead).
All I can say is, that the above code obviously is not optimized for speed.
In the above posts, I wanted to achieve the respective goal with code that is as simple as possible.
You'd have to do any speed tests yourself. :-)
User avatar
Kukulkan
Addict
Addict
Posts: 1352
Joined: Mon Jun 06, 2005 2:35 pm
Location: germany
Contact:

Re: Small tricks with JSON

Post by Kukulkan »

Very nice! :D Especially the first one is really useful!

Thanks!
Little John
Addict
Addict
Posts: 4527
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: Small tricks with JSON

Post by Little John »

I've improved the code in the first post.
For details see remarks in that post.
User avatar
djes
Addict
Addict
Posts: 1806
Joined: Sat Feb 19, 2005 2:46 pm
Location: Pas-de-Calais, France

Re: Small tricks with JSON

Post by djes »

Nice tricks :)
User avatar
the.weavster
Addict
Addict
Posts: 1537
Joined: Thu Jul 03, 2003 6:53 pm
Location: England

Re: Small tricks with JSON

Post by the.weavster »

Derren wrote:And here I thought the JSON lib was useless as you can't turn JS objects into PB objects (map) without writing your own parser...
I like JS objects because they can morph into different shapes but you can still have functions that work with all the different variations so long as they each have the common elements the function expects.
Little John
Addict
Addict
Posts: 4527
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: Small tricks with JSON

Post by Little John »

DebugStructure macro by infratec

see viewtopic.php?f=12&t=73871
Post Reply