Home

codesys.com tvm

Version 1.0.0.16
https://www.dropbox.com/scl/fi/16rzprk6dhnr6204ya5vu/PRO_JSON-1.0.0.16.library?rlkey=vohd00hny0uvm9i6a1avf16vq&dl=0
Changes:
1. changes to JSONVAR.FB_Init (Simon Dreyer)
1. line 8: delete all names first before populating the array
2. line 25: when copying the string, ensure that no more than GPL_JSON.MAX_NAME_SIZE are copied, to leave a null character at the end
2. changes from discussion at https://github.com/stefandreyer/JSON-Library/issues/1
1. line 129 (End previous object): added second case for when offset < 0 (struct of struct)
3. (Stefan Dreyer) added GPL_JSON.APPLICATION_NAME for when the Application has another name than ‘Application’
4. STRUCT_TO_JSON:
1. added check for ApplicationLevel = 0, misconfigured application name
2. reconfigured error checking and added ErrorMsg
5. JSON_TO_STRUCT
1. added check for ApplicationLevel = 0, misconfigured application name
2. reconfigured error checking and added ErrorMsg
6. STRUCT_TO_JSON: added error and message if JSONString is too small
7. JSONVAR_FB_Init: New array, added a check for the end of an array on the previous var for the case when two arrays are adjacent to each other in a struct
8. added JSONVARS_TABLE_VISU and JSONVAR_TAVLE_VISU for testing and troubleshooting
9. added some points to JSON_TO_STRUCT_VISU and STRUCT_TO_JSON_VISU
10. (Stefan Dreyer) changed STRUCT_TO_JSON line 132 closeLevel:= MaxLevel (was closeLevel:= 1) to fix bug where closing bracket was not added when MaxLevel was defined
11. changed the ASCII enum to make it a bit more readable when looking at the JSONString arrays
12. Restructuring of JSON_TO_STRUCT.Name and Value methods - some length checks added, more efficient and readable
13. Several minor stylistic changes

Version 1.0.0.15
https://www.dropbox.com/s/9w2p2yrgncalixp/PRO_JSON%201.0.0.15.library?dl=0
Changes:
1. refactoring of JSON_TO_STRUCT
1. added MatchAllLevels method to make the code more understandable
2. moved some variables, changed some names
2. added JSON_TO_STRUCT.ClearAll method which resets the value of all JSONVARS to null
3. added STRUCT_TO_JSON.ClearString method which clears the output string
4. added JSON_TO_STRUCT_VISU - mostly for testing, but I guess you could use it anywhere
5. added STRUCT_TO_JSON_VISU
6. deleted copyright and copying files. I don’t care about licensing. This library is released under the terms of "it's on the internet so people can do whatever the heck they want with it". Use it, modify it, copy it, put it in your own projects, contribute to it, credit me. Or not. Whatever you like. But it's free, so don't cry to me if it breaks something.

I realize I'm bypassing the structure of the Forge platform by simply posting links to the .library files. I don't have time to make this site work with Schneider Machine Expert, which is what I primarily use for development. If you want to contribute, comment below or send me an email.

This as an open source library to compose and parse JSON objects. For more information about JSON, have a look at json.org. It is a popular language used as part of many other protocols, like REST.

Usage

The usage is simple. You can describe a JSON file with a special structure format, which then can be stored or loaded from or to a file. Actually instead of a file, you are also able to use an HTTP Client library or s.th. similar. The example below is in the library, along with several others.

//All variables must be of type JSONVAR.  They can include other structures or put into arrays, as needed.
TYPE EXAMPLEJSONSTRUCT :
STRUCT
    var1:       JSONVAR;
    var2:       JSONVAR;
    var3:       JSONVAR;
    obj:        EXAMPLEJSONSTRUCT_1;
    arrayobj:   ARRAY[1..3] OF JSONVAR;
END_STRUCT
END_TYPE

TYPE EXAMPLEJSONSTRUCT_1 :
STRUCT
    var4:       JSONVAR;
    var5:       JSONVAR;
    var6:       JSONVAR;
    var7:       ARRAY[1..3] OF JSONVAR;
END_STRUCT
END_TYPE
PROGRAM ExampleJSON_PRG
VAR
    ExampleJSONObj:     EXAMPLEJSONSTRUCT;
    ComposeJSON:        STRUCT_TO_JSON;
    JSONString:         STRING(1000);

    NewJSONObj:         EXAMPLEJSONSTRUCT;  
    ParseJSON:          JSON_TO_STRUCT;
    JSONString2:        STRING(1000);
END_VAR

//JSONVAR variable values can be set in a number of different ways
ExampleJSONObj.var1.Boolean:= TRUE;
ExampleJSONObj.var2.Number:= 34.8756;
ExampleJSONObj.var3.CharString:= 'teststring';
ExampleJSONObj.obj.var4.Number:= 22;
ExampleJSONObj.obj.var5.AsString:= 'FALSE'; //JSONVAR will guess at type, in this case, boolean
ExampleJSONObj.obj.var6.CharString:= 'qwer';
//NOTE: AsString will convert the value to/from STRING, and guess at a type, CharString will not convert, but assume it's a JSON string type.
ExampleJSONObj.obj.var7[1].Number:= 123.234;
ExampleJSONObj.obj.var7[2].AsString:= '55.46';  //JSONVAR will guess at type, in this case, a number
ExampleJSONObj.obj.var7[3].Number:= 985;
ExampleJSONObj.arrayobj[1].Number:= 1;
ExampleJSONObj.arrayobj[2].Number:= 2;
ExampleJSONObj.arrayobj[3].Number:= 3;

//create a JSON string from example object
ComposeJSON(
    JSONString:= ADR(JSONString), 
    JSONStringSize:= SIZEOF(JSONString),
    JSONVars:= ADR(ExampleJSONObj),
    NumberOfVars:= SIZEOF(ExampleJSONObj) / SIZEOF(JSONVAR)
);

//fill another example object with values from the created JSON string
ParseJSON(
    JSONString:= ADR(JSONString2), 
    JSONStringSize:= SIZEOF(JSONString2),
    JSONVars:= ADR(NewJSONObj),
    NumberOfVars:= SIZEOF(NewJSONObj) / SIZEOF(JSONVAR)
);

Discussion

  • svenjotec - 2019-12-03

    It's cleared.

     

    Last edit: svenjotec 2019-12-03
  • nothinrandom - 2020-03-06

    Hello Guys,

    I believe there's an issue with nested structs on all verions. For example:

    TYPE stDebugJson :
    STRUCT
    timestamp : JSONVAR;
    messageType : JSONVAR;
    //message : JSONVAR; //works fine with setting MaxLevel to 1
    message : stDebugMessageDetails; // missing end bracket
    END_STRUCT
    END_TYPE

    stDebugMessageDetails is just another type:
    TYPE stDebugMessageDetails :
    STRUCT
    message : JSONVAR;
    END_STRUCT
    END_TYPE

    The output looks like:
    {"debugMessageJson":{"timestamp":"2020-03-06T23:27:22.966Z","messageType":"DEBUG","message":{"message":"test22"}}

     

    Last edit: nothinrandom 2020-03-06
    • tvm - 2020-05-05

      I'll see if I can find some time to test this out.

       
  • schwi - 2020-04-12

    Hi,
    you should add (GPL_JSON.MAX_VALUE_SIZE) on this string.
    Because if bigger value sizes it runs into faulty parse.
    TYPE JSONNAMEVALUE :
    STRUCT
    Value: STRING(GPL_JSON.MAX_VALUE_SIZE); //value of the object at this level
    END_STRUCT
    END_TYPE

    Greetings

     
    • tvm - 2020-05-05

      good catch, I'll add that to future versions

       
  • jumax - 2020-05-05

    Hello, I have a problem parsing a JSON string and I need help.

    The string I receive:
    '[{"device_id":"1","pgt_id":"2","usertag":"3","hgl":"4","ls":"5","rs":"6","erg":"7"}]'

    The struct I devined:
    TYPE strPGTdataSet:
    STRUCT
    device_id :JSONVAR;
    pgt_id :JSONVAR;
    usertag :JSONVAR;
    hgl :JSONVAR;
    ls :JSONVAR;
    rs :JSONVAR;
    erg :JSONVAR;
    END_STRUCT
    END_TYPE

    The FB I call:
    ParseJSON(
    Execute:=xParseJSON,
    JSONString:= ADR(hTTPClient_0.httpResult.sContent),
    JSONStringSize:= SIZEOF(hTTPClient_0.httpResult.sContent),
    JSONVars:= ADR(NewJSONObj),
    NumberOfVars:= SIZEOF(NewJSONObj) / SIZEOF(JSONVAR)
    );

    The NewJSONObj always remains empty. I also tried to define the NewJSONObj as an array of struct like this:
    TYPE strPGToutputSet:
    STRUCT
    recordset :ARRAY [0..0] OF strPGTdataSet;
    END_STRUCT
    END_TYPE

    I don't know if you need more information to help. Also I'm new to CODESYS programming.

    Thank you!

     
    • kamilp-2097 - 2020-07-23

      Hello, have you managed to solve this case? I am struggling with the same issue.

      Thanks.

       
      • manuknecht - 2023-10-19

        I am aware that this thread is three years old, but I ran into the same issue and could not resolve it. Does anyone know what can cause this?

        Thanks in advance!

        Edit:
        After some more tinkering, I found the issue preventing proper parsing of the JSON string. For this the library function JSON_TO_STRUCT (FB) has to be adjusted from row 100. The original implementation is as follows:

        //Match name and array index.  Array index will be 0 if the current name:value is not part of an array
        IF MATCH_NAMES(JSONVars^[jsonvarindex].Names[nameindex], NameValue[obj_level-(nameindex-1)]) THEN   
            foundname:= TRUE;   //name in JSON string matches the local variable name
        ELSE
            foundname:= FALSE;  //name in JSON string does not match the local variable name, go to next name
            EXIT;
        END_IF
        

        This checks if a key in the struct is identical to the key currently being processed. However, as the EXIT statement is set in case of no matching name, the loop continues after a match and in the next cycle, the variable foundname will be overwritten again. Changing the code accordingly did the trick for me:

        //Match name and array index.  Array index will be 0 if the current name:value is not part of an array
        IF MATCH_NAMES(JSONVars^[jsonvarindex].Names[nameindex], NameValue[obj_level-(nameindex-1)]) THEN   
            foundname:= TRUE;   //name in JSON string matches the local variable name
            EXIT;
        ELSE
            foundname:= FALSE;  //name in JSON string does not match the local variable name, go to next name
        END_IF
        

        If this library is still being moderated, it would be interesting to know if this was an error in the code or if I am simply using it wrong?

         

        Last edit: manuknecht 2023-10-19
        • tvm - 2023-10-27

          I haven't had a lot of time to do anything with this for several months, but thanks for the input. It does look like a bug, I'll try to take a closer look at it next week.

           
          • manuknecht - 2023-10-30

            If you will tackle it again, here's another issue I discovered. The JSON string I want to parse contains some nested arrays and objects. It came to my attention, that proper parsing only works when the key-value pairs on the lowest level (inside arrays) are sorted alphabetically. Otherwise, the values can be assigned to the wrong keys. I didn't check the code further to find what causes this, but maybe you will have an idea?
            Otherwise it seems to do what it does, so thanks a lot for sharing!

             
            • tvm - 2023-10-30

              I think I have reproduced something like this, but it would be helpful if you can provide a test program, or at least a JSON string that demonstrates it.

               
              • manuknecht - 2023-10-31

                I'll attach a project to this message. I am using the HTTPClient library to read a JSON string through a HTTP request. I left you a sample string that I want to parse in the code to demonstrate the issue. You can see that the key-value pairs do not match up between the string and the JSON struct.
                Hope that helps.

                 

                Last edit: manuknecht 2023-10-31
                • tvm - 2023-10-31

                  I've released v 1.0.0.15 (link above). I tested your project as well as several of mine, with various different orders of the variables and it's working for me. The code on line 100 was correct, as far as how the FOR loop/EXIT worked, but I refactored some of that to make it easier to understand.

                   
                  • manuknecht - 2023-11-01

                    Thanks a lot for the update! So my project worked with the old version of the library for you? That is very strange. Need to check it from my side then.

                     
  • tvm - 2020-05-05

    Hi, I haven't had time to test it, but have you tried recordset :ARRAY [1..1] OF strPGTdataSet;

     
  • bnewman - 2023-10-27

    Will you please rerelease this under MIT or MPL2?

    GPL is a cancer.

     
    • tvm - 2023-10-27

      @bnewman as far as I'm concerned, it's released under the terms of "it's on the internet so people can do whatever the heck they want with it". I think I had to pick a license when I put it on here, but I don't actually know anything about GPL, nor do I care. Use it, modify it, copy it, put it in your own projects, contribute to it, credit me. Or not. Whatever you like.
      I just changed the licensing to both MIT and Unlicense. I honestly don't know the difference, but I hope that makes it easier for you.

       

      Last edit: tvm 2023-10-27
  • bnewman - 2023-10-27

    awesome! thank you sir.

     

Log in to post a comment.