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
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
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!
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
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:
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:
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.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
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!
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
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.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
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.
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.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
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.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
@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
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hello. I have an error in JSON_TO_STRUCT when trying to get JSON from string: 'Check application name in GPL_JSON.APPLICATION_NAME'. But I didn't change my application name, it's still "Application". What's wrong?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Check any of your JSONVARs. The Names variable contains an array of the variable name divided by level. For example, if the variable path is Application.Test_SingleVar_PRG.colour, then the array will contain [3] 'Application' [2] 'Test_SingleVar_PRG' [1] 'colour'
The ApplicationLevel property should be the array index which contains 'Application', in this case 3. This is all figured out in the JSONVAR.FB_Init method.
The other place to check is JSONVAR.VarName, which is the full instance path of the variable as a string. The string length is set in GPL_JSON.MAX_VAR_NAME, by default 150 characters. Maybe your path is longer than 150 characters and something is getting cut off?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
There is still a bug within the Json_TO_Struct FB. Within the method MatchAllLevels:
The EXIT Statement was in the wrong place within the for loop. As the loop needs to be exited when a match is found. The bug caused the matchalllevels method to always feedback the value false due to the exit statement.
When placing the exit after match is set to true the values are parsed into the struct.
--------------------------------------OLD-----------------------------------------------------------
FOR i:= 1 TO obj_level DO
//Match name and array index. Array index will be 0 if the current name:value is not part of an array
IF MATCH_NAMES(i_JSONVar.Names[i], NameValue[obj_level-(i-1)]) THEN
MatchAllLevels:= TRUE; //name in JSON string matches the local variable name
ELSE
MatchAllLevels:= FALSE; //name in JSON string does not match the local variable name, go to next name
EXIT;
END_IF
END_FOR
--------------------------------------NEW-----------------------------------------------------------
FOR i:= 1 TO obj_level DO
//Match name and array index. Array index will be 0 if the current name:value is not part of an array
IF MATCH_NAMES(i_JSONVar.Names[i], NameValue[obj_level-(i-1)]) THEN
MatchAllLevels:= TRUE; //name in JSON string matches the local variable name
EXIT;
ELSE
MatchAllLevels:= FALSE; //name in JSON string does not match the local variable name, go to next name
END_IF
END_FOR
Last edit: maxkemmeren 2024-05-02
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
The EXIT is in the correct place in the original, this is not a bug. The loop returns FALSE and exits on the first occurrence of a mismatch. If there are any mismatches, there is no point in evaluating the rest of the array. All levels must match for this method to return TRUE.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
OKay but then there must be another error, as after the change the functionblock read all the values into my local struct. Without the fix my local struct stayed empty all the time.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
This is using only your blocks writing the json string and then parsing back the json string to the same struct. Without the exit change the read struct stayed empty
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
It's cleared.
Last edit: svenjotec 2019-12-03
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
I'll see if I can find some time to test this out.
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
good catch, I'll add that to future versions
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!
Hello, have you managed to solve this case? I am struggling with the same issue.
Thanks.
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:
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:
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
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.
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!
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.
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
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.
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.
Hi, I haven't had time to test it, but have you tried recordset :ARRAY [1..1] OF strPGTdataSet;
Will you please rerelease this under MIT or MPL2?
GPL is a cancer.
@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
awesome! thank you sir.
Hello. I have an error in JSON_TO_STRUCT when trying to get JSON from string: 'Check application name in GPL_JSON.APPLICATION_NAME'. But I didn't change my application name, it's still "Application". What's wrong?
Check any of your JSONVARs. The Names variable contains an array of the variable name divided by level. For example, if the variable path is Application.Test_SingleVar_PRG.colour, then the array will contain
[3] 'Application'
[2] 'Test_SingleVar_PRG'
[1] 'colour'
The ApplicationLevel property should be the array index which contains 'Application', in this case 3. This is all figured out in the JSONVAR.FB_Init method.
The other place to check is JSONVAR.VarName, which is the full instance path of the variable as a string. The string length is set in GPL_JSON.MAX_VAR_NAME, by default 150 characters. Maybe your path is longer than 150 characters and something is getting cut off?
SOLVED SEE REPLIES
NOT A BUG, Different thinking approach
Hello,
There is still a bug within the Json_TO_Struct FB. Within the method MatchAllLevels:
The EXIT Statement was in the wrong place within the for loop. As the loop needs to be exited when a match is found. The bug caused the matchalllevels method to always feedback the value false due to the exit statement.
When placing the exit after match is set to true the values are parsed into the struct.
--------------------------------------OLD-----------------------------------------------------------
FOR i:= 1 TO obj_level DO
//Match name and array index. Array index will be 0 if the current name:value is not part of an array
IF MATCH_NAMES(i_JSONVar.Names[i], NameValue[obj_level-(i-1)]) THEN
MatchAllLevels:= TRUE; //name in JSON string matches the local variable name
ELSE
MatchAllLevels:= FALSE; //name in JSON string does not match the local variable name, go to next name
EXIT;
END_IF
END_FOR
--------------------------------------NEW-----------------------------------------------------------
FOR i:= 1 TO obj_level DO
//Match name and array index. Array index will be 0 if the current name:value is not part of an array
IF MATCH_NAMES(i_JSONVar.Names[i], NameValue[obj_level-(i-1)]) THEN
MatchAllLevels:= TRUE; //name in JSON string matches the local variable name
EXIT;
ELSE
MatchAllLevels:= FALSE; //name in JSON string does not match the local variable name, go to next name
END_IF
END_FOR
Last edit: maxkemmeren 2024-05-02
The EXIT is in the correct place in the original, this is not a bug. The loop returns FALSE and exits on the first occurrence of a mismatch. If there are any mismatches, there is no point in evaluating the rest of the array. All levels must match for this method to return TRUE.
OKay but then there must be another error, as after the change the functionblock read all the values into my local struct. Without the fix my local struct stayed empty all the time.
If you can post an example I can test it here.
sFileContentsWrite_Struct : ST_TEST;
sFileContentsWrite_Struct_Json : ST_TEST_Json;
sFileContentsRead_Struct_Json : ST_TEST_Json;
sFileContentsRead_Struct : ST_TEST;
sFileContentsWrite_Struct_Json.fReal.Number := sFileContentsWrite_Struct.fReal;
sFileContentsWrite_Struct_Json.nInteger.Integer := sFileContentsWrite_Struct.nInteger;
sFileContentsWrite_Struct_Json.sText.CharString := sFileContentsWrite_Struct.sText;
sFileContentsWrite_Struct_Json.fLreal.Number :=sFileContentsWrite_Struct.fLreal;
s_fbJsonParser(
Execute := Execute,
Abort := Abort,
JSONString := ADR(JsonString),
JSONStringSize := SIZEOF(JsonString),
JSONVars := ADR(sFileContentsWrite_Struct_Json),
NumberOfVars := SIZEOF(sFileContentsWrite_Struct_Json)/SIZEOF(JSONVAR),
VariableArraySize := TRUE,
Format := false,
Busy => Busy,
Done => Done,
Aborted => Aborted,
Error => Error,
ErrorPosition => ErrorPosition,
ComposeTime => ComposeTime);
s_fbStructParser(
Execute := rExecute,
Abort := rAbort,
JSONString := ADR(JsonString),
JSONStringSize := SIZEOF(JsonString),
JSONVars := ADR(sFileContentsRead_Struct_Json),
NumberOfVars := SIZEOF(sFileContentsRead_Struct_Json)/SIZEOF(JSONVAR),
Busy => rBusy,
Done => rDone,
Aborted => rAborted,
Error => rError,
ErrorPosition => rErrorPosition,
ParseTime => rComposeTime);
sFileContentsRead_Struct.fReal := sFileContentsRead_Struct_Json.fReal.Number;
sFileContentsRead_Struct.nInteger := TO_INT(sFileContentsRead_Struct_Json.nInteger.Integer);
sFileContentsRead_Struct.sText := sFileContentsRead_Struct_Json.sText.CharString;
sFileContentsRead_Struct.fLreal := sFileContentsRead_Struct_Json.fLreal.Number;
TYPE ST_TEST :
STRUCT
END_STRUCT
END_TYPE
TYPE ST_TEST_Json :
STRUCT
thisisnew : JSONVAR;
sText : JSONVAR;
nInteger : JSONVAR;
fReal : JSONVAR;
fLreal :JSONVAR;
END_STRUCT
END_TYPE
This is using only your blocks writing the json string and then parsing back the json string to the same struct. Without the exit change the read struct stayed empty