JSON encoder and decoder

Share your advanced PureBasic knowledge/code with the community.
PMV
Enthusiast
Enthusiast
Posts: 727
Joined: Sat Feb 24, 2007 3:15 pm
Location: Germany

Re: JSON encoder and decoder

Post by PMV »

update: 01.08.2013
+ bufix: string creation for unicode escaped characters (tab, linebreak, slash, ...) failed


@Fangbeast
Boolean values are the smalest variant of number-values. :wink:
You can use \i for that. Additional every element will save his
Datatype inside of \type. So you can use that field, too.

Code: Select all

If *out\o("items")\a(0)\o("accessInfo")\o("epub")\o("isAvailable")\type = #JSON_Type_True
  Debug "epub is available:     true"
Else
  Debug "epub is available:     false"
EndIf
I prefer the use of \type because if you are just using \i, you can't
know if it is really just a boolean value.

MFG PMV
User avatar
nblackburn
User
User
Posts: 67
Joined: Mon Aug 19, 2013 1:22 am
Location: United Kingdom
Contact:

Re: JSON encoder and decoder

Post by nblackburn »

Agreed, this would be a very useful thing to have in PB.
Image
rambodash
User
User
Posts: 23
Joined: Thu Jun 13, 2013 1:00 am

Re: JSON encoder and decoder

Post by rambodash »

hey, I was using your library and discovered a small bug with 32bit integers overflowing (only effects 32bit OS)

possible fix:

Code: Select all

Procedure IsLargerThan32bitInteger(string$)
  IF len(string$) > 10 : ProcedureReturn #True : ENDIF
  IF len(string$) < 9   : ProcedureReturn #False : ENDIF
  ;2147483647
  DIM highnum(9)
  highnum(0) = 2
  highnum(1) = 1
  highnum(2) = 4
  highnum(3) = 7
  highnum(4) = 4
  highnum(5) = 8
  highnum(6) = 3
  highnum(7) = 6
  highnum(8) = 4
  highnum(9) = 7
  Define i
  Define spos = 1
  For i = 0 to ArraySize(highnum())
    IF VAL(MID(string$, spos, 1)) > highnum(i) : ProcedureReturn #True : Endif
    spos = spos + 1
  Next
  ProcedureReturn #False
EndProcedure
changes made to this section

Code: Select all


  string = PeekS(*first, (*c - *first) / SizeOf(CHARACTER))
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
    If FindString(string, ".", 1) OR IsLargerThan32bitInteger(string)
  CompilerElseIf #PB_Compiler_Processor = #PB_Processor_x64
    If FindString(string, ".", 1)  
  CompilerEndIf
    *out\s = string  ; used for JSON_encode()
    *out\f = ValD(string)
    *out\i = *out\f
    *out\type = #JSON_Type_Float
    ;Debug "Float: " + StrD(*out\f)
  ElseIf FindString(string, "e", 1)
    *out\s = string  ; used for JSON_encode()
    e = StringField(string, 2, "e")
    string = StringField(string, 1, "e")
    
    *out\f = ValD(string) * Pow(10, Val(e))
    *out\i = *out\f
    *out\type = #JSON_Type_Float
    ;Debug "Float: " + StrD(*out\f)
  Else
    *out\i = Val(string)
    *out\f = *out\i
    *out\type = #JSON_Type_Integer
    ;Debug "Integer: " + Str(*out\i)
  EndIf

User avatar
Kukulkan
Addict
Addict
Posts: 1396
Joined: Mon Jun 06, 2005 2:35 pm
Location: germany
Contact:

Re: JSON encoder and decoder

Post by Kukulkan »

Hello,

quick question about the usage. I have loaded the following JSON (strFileList):

Code: Select all

{
 "/path/to/invoice_678432.pdf" : {
 "upload" : true,
 "meta": [ "bzu54r2bzu", "€99.95" ]
 },
 "/path/to/some/marketing_flyer.pdf" : {   },
 "/path/to/invoice_126742.pdf" : {
 "upload" : true,
 "meta": [ "Invoice#=asd21r2f00", "Total=$23" ] 
 },
 "/path/to/some/special_offer.pdf" : { "upload" : false }
}
Now parsing the content like this:

Code: Select all

*jFiles.jsonObj = JSON_decode(strFileList)
ForEach *jFiles\o()
    Protected SourcePDF.s = MapKey(*jFiles\o())
    ; (Doing some conversion here resulting in a moved file path!)
    ; THEREFORE, I LIKE TO CHANGE THE KEY NAME HERE!!!!!
Next
strFileList.s = JSON_encode(*jFiles)
JSON_free(*jFiles)
As you can see, I need to change the key name. Any idea how to do this preserving the individual content of all the elements below?

Kukulkan
User avatar
Kukulkan
Addict
Addict
Posts: 1396
Joined: Mon Jun 06, 2005 2:35 pm
Location: germany
Contact:

Re: JSON encoder and decoder

Post by Kukulkan »

Found no way to easily solve, but found a workaround by duplicating and swapping pointers:

Code: Select all

Protected *destFiles.jsonObj = JSON_Create() ; json object for destination
JSON_newObject(*destFiles)
*jFiles.jsonObj = JSON_decode(strFileList)
ForEach *jFiles\o()
  Protected SourcePDF.s = MapKey(*jFiles\o())
  Protected DestinationPDF.s = "some new filename"
  ; -----------------------------------
  JSON_newPair(*destFiles, DestinationPDF.s) ; create fake entry
  Copy.i = *destFiles\o(DestinationPDF.s)
  *destFiles\o(DestinationPDF.s) = *jFiles\o() ; swap pointers (real/fake)
  *jFiles\o() = Copy.i
  ; -----------------------------------
Next
strFileList.s = JSON_encode(*destFiles)
JSON_free(*jFiles)
JSON_free(*destFiles)
This did it for me. Maybe someone else can make use of it, too.

Kukulkan
PMV
Enthusiast
Enthusiast
Posts: 727
Joined: Sat Feb 24, 2007 3:15 pm
Location: Germany

Re: JSON encoder and decoder

Post by PMV »

It is just 2 lines of code to change the key. With

Code: Select all

#JSON_UseObjectPointer = #True
PB even doesn't have to copy all elements, just writes the pointer
into the other key and delete the old key.

add this code at the end of the example inside of the JSON_Parser.pbi
file right before the line JSON_Debug(*myJSON, "")

Code: Select all

JSON_newPair(*myJSON, "Original")
*myJSON\o("Original")\s = "key to change"
*myJSON\o("Renamed") = *myJSON\o("Original") ; < create new key and copy original to new
DeleteMapElement(*myJSON\o(), "Original") ; < delete original
Hint:
If you doesn't use the pointer-way, you can remove the first line of
that example. As PB will copy all data inside of the map-element, it
will take some time if its a huge amount. Badly, there is no function to
rename a map-element to another key and preventing that.
feature request: http://www.purebasic.fr/english/viewtop ... =3&t=57600 8)

MFG PMV
User avatar
Kukulkan
Addict
Addict
Posts: 1396
Joined: Mon Jun 06, 2005 2:35 pm
Location: germany
Contact:

Re: JSON encoder and decoder

Post by Kukulkan »

Thanks!
Post Reply