It is currently Sat Dec 14, 2019 10:14 pm

All times are UTC + 1 hour




Post new topic Reply to topic  [ 16 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: Save JSON data with object members well-arranged
PostPosted: Tue Sep 05, 2017 7:49 pm 
Offline
Addict
Addict
User avatar

Joined: Thu Jun 07, 2007 3:25 pm
Posts: 3717
Location: Berlin, Germany
Hi,

one key point of the JSON data format is, that the data are both machine readable and human readable.
However, there is a serious problem:
A JSON object by definition is an unordered collection of name/value pairs. And PureBasic's built-in function SaveJSON() saves the members of objects in an unpredictable way, it's not possible to control their order. This can make the generated JSON files hard to read for humans. I, for instance, not seldom want to compare 2 JSON files visually, using a program such as the built-in file compare tool. This only makes sense, if the "fields" in both files are in the same order.

This "JSave" module solves the problem. It works on all platforms supported by PureBasic (thanks to davido for testing on Mac!). It can be easily used in a simple or in a more advanced way.

In the simplest case, just write
Code:
JSave::Save(jsonId, outFile$)
to save all member names of all objects sorted ascending, without taking upper and lower case into account.

Or use
Code:
JSave::Save(jsonId, "")
for displaying the sorted JSON data in the Debug window.

The code
Code:
InitUnknown(#PB_Sort_Descending)
JSave::Save(jsonId, outFile$)
will save all member names of all objects sorted descending.

Using InitObject() or InitObjectStr(), you can for each object define the names of known members. This defines the order in which these members will be saved (see demo code of the module). All unknown members will still be sorted according to the sorting mode applied to that object. You can even choose to ignore unknown members.

Any constructive feedback will be appreciated.
Enjoy!

Code:
; -- Save (or show with Debug) JSON data pretty-printed, with object
;    members individually arranged or sorted according to their names
;    (array elements are not affected).
;    ==> can replace the built-in function SaveJSON()
; <http://www.purebasic.fr/english/viewtopic.php?f=12&t=69100>
; Version 1.20, 2019-03-11, by Little John
;
; tested with PB 5.70 LTS x86 and x64 on Windows 10,
;             PB 5.45 LTS x86 on Linux Mint 18.2 Cinnamon,
;             PB 5.50 on Mac OS X (thanks to davido)

CompilerIf #PB_Compiler_Version < 540
   CompilerError "PureBasic version 5.40 or newer required"
CompilerEndIf


DeclareModule JSave
   ; -- optional procedures
   Declare.i InitObject (objectName$, List memberName$(), sortUnknown.i=#PB_Sort_Ascending|#PB_Sort_NoCase)
   Declare.i InitObjectStr (objectName$, memberList$, sortUnknown.i=#PB_Sort_Ascending|#PB_Sort_NoCase)
   Declare   InitUnknown (sortUnknown.i)
   Declare   InitClear()
   Declare.i StoreOrder (prefFile$, comment$="")
   Declare.i LoadOrder  (prefFile$)
   
   ; -- main procedure
   Declare.i Save (json.i, dataFile$)
EndDeclareModule


Module JSave
   EnableExplicit
   
   Structure Object
      SortUnknownMembers.i
      Map KnownMember.i()
      List *pKnownMember.String()
   EndStructure
   
   NewMap s_KnownObject.Object()
   Define s_SortUnknownObjects = #PB_Sort_Ascending|#PB_Sort_NoCase
   Define s_Ofn.i
   
   
   Procedure.i InitObject (objectName$, List memberName$(), sortUnknown.i=#PB_Sort_Ascending|#PB_Sort_NoCase)
      ; -- For each wanted object, define the order in which its members should be saved to a JSON file
      ;    (optional function).
      ; in : objectName$  : name of regarding object
      ;                     ("" refers to members at the basic level)
      ;      memberName$(): list of names of known members for this object;
      ;                     This list defines the order of the members.
      ;                     Can be empty, if only 'sortUnknown' is to be changed.
      ;      sortUnknown  : object specific setting for sorting unknown members
      ;                     (any PureBasic sort options for strings,
      ;                      or -1 for ignoring unknown members)
      ; out: return value : 1 on success,
      ;                     0 on error
      Shared s_KnownObject()
     
      If FindMapElement(s_KnownObject(), objectName$)
         ProcedureReturn 0        ; error
      EndIf
     
      AddMapElement(s_KnownObject(), objectName$, #PB_Map_NoElementCheck)
     
      With s_KnownObject()
         ForEach memberName$()
            AddElement(\pKnownMember())                                                       ; Add an element to the list of the new object,
            \pKnownMember() = AddMapElement(\KnownMember(), memberName$()) - SizeOf(Integer)  ; and store the pointer to the new mapkey there.
         Next
         \SortUnknownMembers = sortUnknown
      EndWith
     
      ProcedureReturn 1           ; success
   EndProcedure
   
   
   Procedure.i InitObjectStr (objectName$, memberList$, sortUnknown.i=#PB_Sort_Ascending|#PB_Sort_NoCase)
      ; -- Wrapper for function InitObject(), for convenience
      ;    (optional function).
      ; in : objectName$ : name of regarding object
      ;                    ("" refers to members at the basic level)
      ;      memberList$ : list of names of known members for this object, separated by ',' ;
      ;                    This list defines the order of the members.
      ;                    Can be "", if only 'sortUnknown' is to be changed.
      ;      sortUnknown : object specific setting for sorting unknown members
      ;                    (any PureBasic sort options for strings,
      ;                     or -1 for ignoring unknown members)
      ; out: return value: 1 on success,
      ;                    0 on error
      Protected numFields.i, i.i
      Protected NewList memberName$()
     
      If Asc(Trim(memberList$)) <> ''
         numFields = CountString(memberList$, ",") + 1
         For i = 1 To numFields
            AddElement(memberName$())
            memberName$() = Trim(StringField(memberList$, i, ","))
         Next
      EndIf
     
      ProcedureReturn InitObject(objectName$, memberName$(), sortUnknown)
   EndProcedure
   
   
   Procedure InitUnknown (sortUnknown.i)
      ; -- Change how members of unknown objects are sorted
      ;    (optional function).
      ; in: sortUnknown: setting for sorting the members of unknown objects
      ;                  (any PureBasic sort options for strings,
      ;                  or -1 for ignoring unknown objects)
      Shared s_SortUnknownObjects
     
      s_SortUnknownObjects = sortUnknown
   EndProcedure
   
   
   Procedure InitClear()
      ; -- Reset all settings (optional function).
      Shared s_SortUnknownObjects, s_KnownObject()
     
      s_SortUnknownObjects = #PB_Sort_Ascending|#PB_Sort_NoCase
      ClearMap(s_KnownObject())
   EndProcedure
   
   ;------------------------------------------------------------------------
   
   #Group_General$ = "General"
   #KeyName_Signature$ = "Signature"
   #KeyValue_Signature$ = "-- Order of JSON object members --"
   #KeyName_UnknownObjects$ = "Sort unknown objects"
   #Group_KnownObjects$ = "Sort known objects"
   
   
   Macro WritePreferenceGroup (_name_)
      WriteStringN(ofn, "[" + _name_ + "]")
   EndMacro
   
   Macro WritePreferenceKey (_name_, _value_)
      WriteStringN(ofn, _name_ + " = " + _value_)
   EndMacro
   
   
   Procedure.i StoreOrder (prefFile$, comment$="")
      ; -- Write wanted order of object members to a preference file
      ; in : prefFile$: name of file for writing the order information
      ;      comment$ : comment that will be written as first line of the file
      ; out: return value: 1 on success, 0 on error
      Shared s_SortUnknownObjects, s_KnownObject()
      Protected memberList$, ofn.i, numMembers.i, i.i
     
      ofn = CreateFile(#PB_Any, prefFile$, #PB_UTF8)
      If ofn = 0
         ProcedureReturn 0               ; error
      EndIf
     
      WriteStringFormat(ofn, #PB_UTF8)
      If Asc(comment$) <> ''
         WriteStringN(ofn, "; " + comment$)
         WriteStringN(ofn, "")
      EndIf
      WritePreferenceGroup(#Group_General$)
      WritePreferenceKey(#KeyName_Signature$, #KeyValue_Signature$)
      WritePreferenceKey(#KeyName_UnknownObjects$, s_SortUnknownObjects)
      WriteStringN(ofn, "")
     
      WritePreferenceGroup(#Group_KnownObjects$)
      ForEach s_KnownObject()
         memberList$ = ""
         numMembers = ListSize(s_KnownObject()\pKnownMember())
         i = 1
         ForEach s_KnownObject()\pKnownMember()
            memberList$ + s_KnownObject()\pKnownMember()\s
            If i < numMembers
               memberList$ + ", "
            EndIf
            i + 1
         Next
         
         WritePreferenceKey(MapKey(s_KnownObject()) + "_Known", memberList$)
         WritePreferenceKey(MapKey(s_KnownObject()) + "_Unknown", s_KnownObject()\SortUnknownMembers)
      Next
     
      CloseFile(ofn)
      ProcedureReturn 1                  ; success
   EndProcedure
   
   
   Procedure.i LoadOrder (prefFile$)
      ; -- Read wanted order of object members from a preference file
      ; in : prefFile$: name of file for reading the order information
      ; out: return value: 1 on success, 0 on error
      Shared s_SortUnknownObjects, s_KnownObject()
      Protected keyName$, objectName$, memberList$, f.i, sortUnknown.i
     
      If OpenPreferences(prefFile$) = 0
         ProcedureReturn 0               ; error
      EndIf
     
      PreferenceGroup(#Group_General$)
      If ReadPreferenceString(#KeyName_Signature$, "") <> #KeyValue_Signature$
         ClosePreferences()
         ProcedureReturn 0               ; error
      EndIf
     
      s_SortUnknownObjects = ReadPreferenceInteger(#KeyName_UnknownObjects$, #PB_Sort_Ascending|#PB_Sort_NoCase)
      ClearMap(s_KnownObject())
     
      If PreferenceGroup(#Group_KnownObjects$) = 0 Or ExaminePreferenceKeys() = 0
         ClosePreferences()
         ProcedureReturn 0               ; error
      EndIf
     
      While NextPreferenceKey()
         keyName$ = PreferenceKeyName()
         f = FindString(keyName$, "_")
         If f = 0
            ClosePreferences()
            ProcedureReturn 0            ; error
         EndIf
         
         Select Mid(keyName$, f+1)
            Case "Known"
               objectName$ = Left(keyName$, f-1)
               memberList$ = PreferenceKeyValue()
            Case "Unknown"
               If objectName$ <> Left(keyName$, f-1)
                  ClosePreferences()
                  ProcedureReturn 0      ; error
               EndIf
               sortUnknown = Val(PreferenceKeyValue())
               If InitObjectStr(objectName$, memberList$, sortUnknown) = 0
                  ClosePreferences()
                  ProcedureReturn 0      ; error
               EndIf
            Default   
               ClosePreferences()
               ProcedureReturn 0         ; error
         EndSelect
      Wend
     
      ClosePreferences()
      ProcedureReturn 1                  ; success
   EndProcedure
   
   ;------------------------------------------------------------------------
   
   Macro _WriteLine (_key_, _right_)
      If Asc(_key_) = ''
         line$ = pre$ + _right_
      Else
         line$ = pre$ + LSet(#DQUOTE$ + _key_ + #DQUOTE$, keyWidth) + ": " + _right_
      EndIf
     
      If s_Ofn
         WriteStringN(s_Ofn, line$)
      Else
         Debug line$
      EndIf
   EndMacro
   
   Procedure _TraverseJSON (v.i, level.i, prevKey$="", key$="", keyWidth.i=0, comma$="")
      ; in: v       : JSON value
      ;     level   : level of the given JSON value
      ;     prevKey$: JSON member key of previous level (can be "")
      ;     key$    : JSON member key of current  level (can be "")
      ;     keyWidth: number of characters of a field for 'key$'
      ;     comma$  : "," or ""
      Shared s_Ofn, s_SortUnknownObjects, s_KnownObject()
      Protected NewList unknownMember$()
      Protected.i i, last, pad, validMembers, knownObject
      Protected tmp$, line$, pre$ = Space(3 * level)
     
      Select JSONType(v)
         Case #PB_JSON_Object
            If JSONObjectSize(v) = 0
               _WriteLine(key$, "{}" + comma$)
               
            Else
               ; -- initially examine all members of this object
               If ExamineJSONMembers(v)
                  If Asc(key$) <> ''
                     prevKey$ = key$
                  EndIf
                  knownObject = FindMapElement(s_KnownObject(), prevKey$)
                  pad = 0
                  validMembers = 0
                  If knownObject
                     While NextJSONMember(v)
                        If FindMapElement(s_KnownObject()\KnownMember(), JSONMemberKey(v))
                           If pad < Len(JSONMemberKey(v))
                              pad = Len(JSONMemberKey(v))
                           EndIf
                           validMembers + 1
                        ElseIf s_KnownObject()\SortUnknownMembers > -1
                           If pad < Len(JSONMemberKey(v))
                              pad = Len(JSONMemberKey(v))
                           EndIf
                           validMembers + 1
                           AddElement(unknownMember$()) : unknownMember$() = JSONMemberKey(v)
                        EndIf
                     Wend
                  ElseIf s_SortUnknownObjects > -1
                     While NextJSONMember(v)
                        If pad < Len(JSONMemberKey(v))
                           pad = Len(JSONMemberKey(v))
                        EndIf
                        validMembers + 1
                        AddElement(unknownMember$()) : unknownMember$() = JSONMemberKey(v)
                     Wend
                  EndIf
                  pad + 2
               EndIf
               
               _WriteLine(key$, "{")
               i = 1
               
               ; -- write known members
               If knownObject
                  ResetList(s_KnownObject()\pKnownMember())
                  While (i <= validMembers) And NextElement(s_KnownObject()\pKnownMember())
                     If GetJSONMember(v, s_KnownObject()\pKnownMember()\s)
                        If i < validMembers : tmp$ = "," : Else : tmp$ = "" : EndIf
                        PushListPosition(s_KnownObject()\pKnownMember())
                        PushMapPosition(s_KnownObject())
                        _TraverseJSON(JSONMemberValue(v), level+1, "", JSONMemberKey(v), pad, tmp$)
                        PopMapPosition(s_KnownObject())
                        PopListPosition(s_KnownObject()\pKnownMember())
                        i + 1
                     EndIf
                  Wend
               EndIf
               
               ; -- write unknown members
               If ListSize(unknownMember$()) > 0
                  If knownObject
                     SortList(unknownMember$(), s_KnownObject()\SortUnknownMembers)
                  Else
                     SortList(unknownMember$(), s_SortUnknownObjects)
                  EndIf
                  ForEach unknownMember$()
                     GetJSONMember(v, unknownMember$())
                     If i < validMembers : tmp$ = "," : Else : tmp$ = "" : EndIf
                     _TraverseJSON(JSONMemberValue(v), level+1, "", JSONMemberKey(v), pad, tmp$)
                     i + 1
                  Next
               EndIf
               
               _WriteLine("", "}" + comma$)
            EndIf
           
         Case #PB_JSON_Array
            last = JSONArraySize(v) - 1
            If last < 0
               _WriteLine(key$, "[]" + comma$)
            Else
               _WriteLine(key$, "[")
               For i = 0 To last-1
                  _TraverseJSON(GetJSONElement(v, i), level+1, key$, "", 0, ",")
               Next
               _TraverseJSON(GetJSONElement(v, last), level+1, key$)
               _WriteLine("", "]" + comma$)
            EndIf
           
         Case #PB_JSON_String
            _WriteLine(key$, #DQUOTE$ + EscapeString(GetJSONString(v)) + #DQUOTE$ + comma$)
           
         Case #PB_JSON_Number
            _WriteLine(key$, GetJSONDouble(v) + comma$)
           
         Case #PB_JSON_Boolean
            If GetJSONBoolean(v) : tmp$ = "true" : Else : tmp$ = "false" : EndIf
            _WriteLine(key$, tmp$ + comma$)
           
         Case #PB_JSON_Null
            _WriteLine(key$, "null" + comma$)
      EndSelect
   EndProcedure
   
   
   Procedure.i Save (json.i, dataFile$)
      ; -- Save JSON data to a file in the proper format (UTF-8 without BOM);
      ;    pretty-printed, with object members individually arranged or sorted
      ;    according to their names
      ; in : json     : ID of JSON data
      ;      dataFile$: name of destination file,
      ;                 or "" for output with Debug
      ; out: return value: 1: file successfully saved,
      ;                    0: dataFile$ = "", or error
      Shared s_Ofn
     
      If IsJSON(json)
         If Asc(dataFile$) <> ''
            s_Ofn = CreateFile(#PB_Any, dataFile$, #PB_UTF8)
            If s_Ofn
               _TraverseJSON(JSONValue(json), 0)
               CloseFile(s_Ofn)
               ProcedureReturn 1
            EndIf
         Else
            CompilerIf #PB_Compiler_Debugger = #False
               CompilerWarning "Enable the Debugger, in order to see the output"
            CompilerEndIf
            s_Ofn = 0
            _TraverseJSON(JSONValue(json), 0)
         EndIf
      EndIf
     
      ProcedureReturn 0
   EndProcedure
EndModule


CompilerIf #PB_Compiler_IsMainFile
   ; -- Module demo
   
   EnableExplicit
   
   Define.i jn, i, last=5
   Dim input$(last)
   
   input$(0) = "'Hello \'world\''"
   input$(1) = "null"
   input$(2) = "2.7"
   input$(3) = "true"
   input$(4) = "[[4, 3], [1, 2], [5, 6]]"
   input$(5) = "{" +
               "'Given name': 'Mary'," +
               "'Family name': 'Smith'," +
               "'Age': 30," +
               "'Children': {" +
               "'Peter': 6," +
               "'Tom': 2," +
               "'Laura': 5" +
               "}," +
               "'Address': {" +
               "'Country': 'Germany'," +
               "'City': 'Berlin'," +
               "'E-mail': 'mary@smith.de'" +
               "}" +
               "}"
   
   For i = 0 To last
      ReplaceString(input$(i), "'", #DQUOTE$, #PB_String_InPlace)
      jn = ParseJSON(#PB_Any, input$(i))
      If IsJSON(jn) = #False
         Debug "Error, invalid JSON data: " + input$(i)
         End
      EndIf
     
      Debug ComposeJSON(jn, #PB_JSON_PrettyPrint)
      If i = last
         Debug ~"---------  For each object, all member keys sorted ascending  ---------"
      EndIf
      JSave::Save(jn, "")
      Debug ""
     
      If i < last
         FreeJSON(jn)
      EndIf
   Next
   
   Debug "---------  All member keys at basic level individually arranged  ---------"
   JSave::InitObjectStr("", "Given name, Family name, Age, Children, Address")
   JSave::Save(jn, "")
   
   Debug ~"---------  Additionally all member keys of objects \"Children\" and \"Address\" individually arranged  ---------"
   JSave::InitObjectStr("Children", "Laura, Tom, Peter")
   JSave::InitObjectStr("Address", "Country, City, E-mail")
   JSave::Save(jn, "")
CompilerEndIf

_________________
Please excuse my flawed English. My native language is PureBasic.
Search
RSBasic's backups


Last edited by Little John on Mon Mar 11, 2019 7:30 am, edited 7 times in total.

Top
 Profile  
Reply with quote  
 Post subject: Re: Save JSON data with object members well-arranged (Module
PostPosted: Tue Sep 05, 2017 9:25 pm 
Offline
Addict
Addict

Joined: Fri Nov 09, 2012 11:04 pm
Posts: 1715
Location: Uttoxeter, UK
HI Little John,

This is the debug output when run on Mac OS X. Pure Basic 5.50:


Code:
"Hello \"world\""
"Hello \"world\""

null
null

2.7
2.7

true
true

[
  [
    4,
    3
  ],
  [
    1,
    2
  ],
  [
    5,
    6
  ]
]
[
   [
      4,
      3
   ],
   [
      1,
      2
   ],
   [
      5,
      6
   ]
]

{
  "Family name": "Smith",
  "Given name" : "Mary",
  "Address"    : {
      "Country": "Germany",
      "E-mail" : "mary@smith.de",
      "City"   : "Berlin"
    },
  "Children"   : {
      "Laura": 5,
      "Tom"  : 2,
      "Peter": 6
    },
  "Age"        : 30
}
--------------------------------
{
   "Address"    : {
      "City"   : "Berlin",
      "Country": "Germany",
      "E-mail" : "mary@smith.de"
   },
   "Age"        : 30,
   "Children"   : {
      "Laura": 5,
      "Peter": 6,
      "Tom"  : 2
   },
   "Family name": "Smith",
   "Given name" : "Mary"
}

--------------------------------
{
   "Given name" : "Mary",
   "Family name": "Smith",
   "Age"        : 30,
   "Children"   : {
      "Laura": 5,
      "Peter": 6,
      "Tom"  : 2
   },
   "Address"    : {
      "City"   : "Berlin",
      "Country": "Germany",
      "E-mail" : "mary@smith.de"
   }
}
--------------------------------
{
   "Given name" : "Mary",
   "Family name": "Smith",
   "Age"        : 30,
   "Children"   : {
      "Laura": 5,
      "Peter": 6,
      "Tom"  : 2
   },
   "Address"    : {
      "Country": "Germany",
      "City"   : "Berlin",
      "E-mail" : "mary@smith.de"
   }
}


__________________________________________________
Code tags added
06.09.2017
RSBasic

_________________
DE AA EB


Top
 Profile  
Reply with quote  
 Post subject: Re: Save JSON data with object members well-arranged (Module
PostPosted: Wed Sep 06, 2017 10:46 am 
Offline
Addict
Addict
User avatar

Joined: Thu Jun 07, 2007 3:25 pm
Posts: 3717
Location: Berlin, Germany
Hi davido,

this is the correct output. :-)
Thank you very much for testing on Mac!
I have uptaded the text in the first post accordingly.

_________________
Please excuse my flawed English. My native language is PureBasic.
Search
RSBasic's backups


Top
 Profile  
Reply with quote  
 Post subject: Re: Save JSON data with object members well-arranged (Module
PostPosted: Wed Sep 06, 2017 7:59 pm 
Offline
Addict
Addict

Joined: Fri Nov 09, 2012 11:04 pm
Posts: 1715
Location: Uttoxeter, UK
Hi Little John,

Thank you for confirming; I wasn't sure.

I always use JSON because it is so easy to save data.
I had noticed that there was something amiss but I don't compare the saved data just read it. Anyway I couldn't do anything about it. :)
I shall in future use your module.
Thank you for taking the time to compose it and share it. :D

@RSBasic: Sorry for omitting the code tags. Thank you for correcting it - much appreciated.

_________________
DE AA EB


Top
 Profile  
Reply with quote  
 Post subject: Re: Save JSON data with object members well-arranged (Module
PostPosted: Tue Feb 13, 2018 1:47 pm 
Offline
User
User

Joined: Thu Aug 10, 2017 7:35 am
Posts: 78
Thanks for this module, Little John!

Saves a lot of hassle when visually comparing different .jsons
and it makes manual editing also a bit more "foreseeable" :oops:

One thing, though...

As far as I understand you can use JSave::InitObjectStr() multiple
times before you do the save, correct?

If this is true, shouldn't this work:
Code:
  hJSON = CreateJSON(#PB_Any)
  If hJSON
    InsertJSONList(JSONValue(hJSON), Profile())
    JSave::InitObjectStr("", "ID, Position, Enabled, Name, ProfileItems")
    JSave::InitObjectStr("ProfileItems", "Script, Name, Enabled, Position")
    JSave::Save(hJSON, "_converted.json")
    FreeJSON(hJSON)
  EndIf


What I would expect is this:
Code:
[
   {
      "ID"               : "x20160901000000007",
      "Position"         : 7,
      "Enabled"          : 1,
      "Name"             : "Bookmark management",
      "ProfileItems"     : [
         {
            "Script"   : "#ID_4001;",
            "Name"     : "Bookmark item(s)",
            "Enabled"  : 1,
            "Position" : 1
         }
      ]
   },
   {
      "ID"               : "x20160901000000008",
      "Position"         : 8,
      "Enabled"          : 0,
      "Name"             : "Firewall management",
      "ProfileItems"     : [
         {
            "Script"   : "#ID_2001;",
            "Name"     : "Add firewall rule",
            "Enabled"  : 1,
            "Position" : 1
         }
      ]
   }
]


but I get that:
Code:
[
   {
      "ID"               : "x20160901000000007",
      "Position"         : 7,
      "Enabled"          : 1,
      "Name"             : "Bookmark management",
      "ProfileItems"     : [
         {
            "Position" : 1,
            "Enabled"  : 1,
            "Name"     : "Bookmark item(s)",
            "Script"   : "#ID_4001;"
         }
      ]
   },
   {
      "ID"               : "x20160901000000008",
      "Position"         : 8,
      "Enabled"          : 0,
      "Name"             : "Firewall management",
      "ProfileItems"     : [
         {
            "Position" : 1,
            "Enabled"  : 1,
            "Name"     : "Add firewall rule",
            "Script"   : "#ID_2001;"
         }
      ]
   }
]


Top
 Profile  
Reply with quote  
 Post subject: Re: Save JSON data with object members well-arranged (Module
PostPosted: Thu Feb 15, 2018 6:12 am 
Offline
Addict
Addict
User avatar

Joined: Thu Jun 07, 2007 3:25 pm
Posts: 3717
Location: Berlin, Germany
Hi oO0XX0Oo,

thanks for your report!
That was a bug. Please see the first post for the new code.
Can you please tell me whether it works now for you?

_________________
Please excuse my flawed English. My native language is PureBasic.
Search
RSBasic's backups


Top
 Profile  
Reply with quote  
 Post subject: Re: Save JSON data with object members well-arranged (Module
PostPosted: Thu Feb 15, 2018 9:37 am 
Offline
User
User

Joined: Thu Aug 10, 2017 7:35 am
Posts: 78
Thanks for the bugfix, Little John!

The updated code works perfectly fine, the sorting works exactly as expected now :D


Top
 Profile  
Reply with quote  
 Post subject: Re: Save JSON data with object members well-arranged (Module
PostPosted: Thu Feb 15, 2018 1:01 pm 
Offline
Addict
Addict
User avatar

Joined: Sun Nov 05, 2006 11:42 pm
Posts: 4548
Location: Lyon - France
That's works here W7 x86 v5.61 x86
I have apparently the same result than DAVIDO
Thanks for sharing 8)

_________________
ImageThe happiness is a road...
Not a destination


Top
 Profile  
Reply with quote  
 Post subject: Re: Save JSON data with object members well-arranged (Module
PostPosted: Thu Feb 15, 2018 3:22 pm 
Offline
Addict
Addict
User avatar

Joined: Thu Jun 07, 2007 3:25 pm
Posts: 3717
Location: Berlin, Germany
You are welcome!
I am happy that it works fine now.

_________________
Please excuse my flawed English. My native language is PureBasic.
Search
RSBasic's backups


Top
 Profile  
Reply with quote  
 Post subject: Re: Save JSON data with object members well-arranged (Module
PostPosted: Thu Mar 07, 2019 7:11 am 
Offline
User
User

Joined: Thu Aug 10, 2017 7:35 am
Posts: 78
@Little John

I've noticed a small quirk...

Code:
  hJSON = CreateJSON(#PB_Any)
  If hJSON
    InsertJSONList(JSONValue(hJSON), Profile())
    JSave::InitObjectStr("", "ID, Position, Enabled, Name, ClickType, Control, Description, MatchOn, MatchType, Modifier, MouseButton, SkipOn, SkipType, Items")
    JSave::InitObjectStr("Items", "Position, Enabled, Name, Script, DisableOn, Icon, HideOn")
    JSave::Save(hJSON, "_converted.json")
    FreeJSON(hJSON)
  EndIf


As you can see I'm very specific on the sort order, it is exactly defined for all root level elements and for all elements in the "Items" list

Test data:
Code:
[
   {
      "Name"             : "Demo",
      "ID"               : "x001",
      "ClickType"        : 1,
      "Control"          : 6,
      "MatchOn": "",
      "Items"            : [
         {
            "Icon"     : "icon",
            "HideOn"   : "<it is a folder>",
            "Enabled"  : 0,
            "Name"     : "Open here",
            "DisableOn": "never",
            "Script"   : "text \"huhu\";",
            "Position" : 1
         },
         {
            "Icon"     : "",
            "HideOn"   : "<it is a file>",
            "Enabled"  : 1,
            "Name"     : "Open in elsewhere",
            "DisableOn": "",
            "Script"   : "text \"haha\";",
            "Position" : 2
         }
      ],
      "MatchType"        : 3,
      "Modifier"         : 0,
      "Position"         : 1,
      "MouseButton"      : 2,
      "SkipOn" : "",
      "SkipType"         : 1,
      "Description"      : "Some stuff",
      "Enabled"          : 1
   }
]


The result:
Code:
[
   {
      "ID"         : "x001",
      "Position"   : 1,
      "Enabled"    : 1,
      "Name"       : "Demo",
      "ClickType"  : 1,
      "Control"    : 6,
      "Description": "Some stuff",
      "MatchOn"    : "",
      "MatchType"  : 3,
      "Modifier"   : 0,
      "MouseButton": 2,
      "SkipOn"     : "",
      "SkipType"   : 1,
      "Items"      : [
         {
            "Position" : 1,
            "Enabled"  : 0,
            "Name"     : "Open here",
            "Script"   : "text \"huhu\";",
            "DisableOn": "never",
            "Icon"     : "icon",
            "HideOn"   : "<it is a folder>"
         },
         {
            "Position" : 2,
            "Enabled"  : 1,
            "Name"     : "Open in elsewhere",
            "DisableOn": "",
            "HideOn"   : "<it is a file>",
            "Icon"     : "",
            "Script"   : "text \"haha\";"
         }
      ]
   }
]

The entries in the Items list are not sorted identically.
The first entry follows the definition, but the second does not.
E.g. "Script" is now the last element, instead of the 4th

Root level elements are always fine, even if the example has plenty of them
(I reduced the test data ofc)...

Can you take a look at it (again), please?


Top
 Profile  
Reply with quote  
 Post subject: Re: Save JSON data with object members well-arranged (Module
PostPosted: Thu Mar 07, 2019 7:37 pm 
Offline
Addict
Addict
User avatar

Joined: Thu Jun 07, 2007 3:25 pm
Posts: 3717
Location: Berlin, Germany
Hi!

That looks like a bug.
Please give me some time to understand the code that I wrote more than one year ago. :-)

_________________
Please excuse my flawed English. My native language is PureBasic.
Search
RSBasic's backups


Top
 Profile  
Reply with quote  
 Post subject: Re: Save JSON data with object members well-arranged (Module
PostPosted: Thu Mar 07, 2019 10:30 pm 
Offline
PureBasic Team
PureBasic Team
User avatar

Joined: Fri Apr 25, 2003 6:14 pm
Posts: 1704
Location: Germany (Saxony, Deutscheinsiedel)
Could become useful, good work & thanks for sharing! :D

_________________
Bye,
...André
(PureBasicTeam::Docs & Support - PureArea.net | Order:: PureBasic | PureVisionXP)


Top
 Profile  
Reply with quote  
 Post subject: Re: Save JSON data with object members well-arranged
PostPosted: Sat Mar 09, 2019 1:50 pm 
Offline
Addict
Addict
User avatar

Joined: Thu Jun 07, 2007 3:25 pm
Posts: 3717
Location: Berlin, Germany
Thanks, Andre! :-)

Changes on 2019-03-09:
  • Fixed a bug
  • Demo code slightly extended
  • Some cosmetic changes

@oO0XX0Oo:
I'm sorry for the inconveniences.
Please test whether the corrected code works for you as expected.

_________________
Please excuse my flawed English. My native language is PureBasic.
Search
RSBasic's backups


Top
 Profile  
Reply with quote  
 Post subject: Re: Save JSON data with object members well-arranged
PostPosted: Sat Mar 09, 2019 2:46 pm 
Offline
User
User

Joined: Thu Aug 10, 2017 7:35 am
Posts: 78
Quote:
I'm sorry for the inconveniences.

No need to be sorry!

The new version looks fine currently, test data with about 65kb is sorted as expected
(one sort order on root level + 2 additional sort orders for the arrays). Different
structure as in my example ofc^^

Many thanks for fixing the bug!


Top
 Profile  
Reply with quote  
 Post subject: Re: Save JSON data with object members well-arranged
PostPosted: Sun Mar 10, 2019 1:04 pm 
Offline
Addict
Addict
User avatar

Joined: Thu Jun 07, 2007 3:25 pm
Posts: 3717
Location: Berlin, Germany
Hi oO0XX0Oo,

thanks for your feedback! I'm glad that the bug seems to be fixed now. :-)


I just posted a new version with some small changes:

Changed
  • Public procedure Save():
    optional parameter 'sortUnknown' removed;
    This setting is now done by the new public procedure InitUnknown().
  • Public procedure Clear()
    • renamed to InitClear()
    • extended, so that it now also resets the mode for sorting members of unknown objects to its default value
  • Default mode for sorting unknown object members changed from #PB_Sort_Ascending to #PB_Sort_Ascending|#PB_Sort_NoCase.

New
  • Optional public procedure InitUnknown():
    Change how members of unknown objects are sorted.

_________________
Please excuse my flawed English. My native language is PureBasic.
Search
RSBasic's backups


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 16 posts ]  Go to page 1, 2  Next

All times are UTC + 1 hour


Who is online

Users browsing this forum: No registered users and 11 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
Jump to:  

 


Powered by phpBB © 2008 phpBB Group
subSilver+ theme by Canver Software, sponsor Sanal Modifiye