I'm trying to use a flow to process an XML generated by GXWorks3 for industrial PLCs into some sort of array for use in more complex flows. I've puzzled over it for a couple days, tried ChatGPT, and finally turn to the forum in hopes of help.
Input is a massive XML with a lot of extra nonsense, we chop it down to the bit we need, then operate on that using a function that should output a JSON (or JSObject, I'm not sure, not a JS developer), similar to this format: Desired output format - Pastebin.com.
After much experimentation, I'm trying:
var arr = msg.payload; // get the array
var rv = {};// create a new empty object
for (var i = 0; i < arr.length; ++i) {
let key = msg.payload[i].variable[i].$.name;
rv[key] = {
address: msg.payload[i].variable[i].$.address,
array_data_type_name: "", // empty
fc: '', // empty, change sign?
quantity: 1, // empty
type_name: Object.keys(msg.payload[i].variable[i].type[0]), //object keys
word_length: 1 // empty
}; // replace arr[i] with selected pieces
}
msg.payload = rv;
return msg;
based off examples from elsewhere in the forum, but it chokes at "$", (or elsewhere, if I eliminate that) with "TypeError: Cannot read properties of undefined (reading '$')".
I've done hobby web development and programming at university, but am not a professional JS developer. Can anyone please help me solve this problem?
The variable array are different lengths. so your for loop works for payload but not for the variable array.
also some variable arrays do not contain address.
try this
let arr = msg.payload; // get the array
let rv = {};// create a new empty object
arr.forEach(obj_payload =>{
if(obj_payload.variable){
obj_payload.variable.forEach(obj_variable => {
let key = obj_variable.$.name;
if(obj_variable.$.address){
rv[key] = {
address: obj_variable.$.address,
array_data_type_name: "", // empty
fc: '', // empty, change sign?
quantity: 1, // empty
type_name: Object.keys(obj_variable.type[0]), //object keys
word_length: 1 // empty
}; // replace arr[i] with selected pieces
}
})
}
});
msg.payload = rv;
return msg;
That is awesome and works very well! I experimented with my boss until late yesterday, and we were approaching a solution, but this is beyond what we did and has solved several issues I had yet to solve (e.g. irregularly nested names). Thank you so much!
Once I've figured out how to adjust type_name: Object.keys(obj_variable.type[0]) to return BOOL instead of 0: 'BOOL', I reckon it'll be 100% sorted. Wondering if it is maybe impossible in JS?
Future readers, that's basically what it looks like, and unlike getting the values of the object fields for the rest of the XML, the type_name field is malformed and we use the above methods to get field name "BOOL" or "INT" etc. (array value is always empty)
Would var look_up_table = Object(msg.payload); be enough in the next function node to get a JS object of the correctly generated object from the above? EDIT: after logging to console, yes, it appears it is.
I'm happy, the bit of the program I was working on now seems to be 100% functional.
There are some other flows and stuff connected that still have issues; not sure why, but they're in the general program, not in this section. Odd that it isn't 100% yet, as the generated data from this topic's node looks the same as one of our working installations.
Turns out, there were some undocumented variables that I needed to account for that no-one informed me on. The corrected code:
let arr = msg.payload; // get the array
let rv = {}; // create a new empty object
let fc = [];
arr.forEach(obj_payload => {
if (obj_payload.variable) {
obj_payload.variable.forEach(obj_variable => {
let key = obj_variable.$.name;
if (obj_variable.$.address) {
// assign function code depending on D or M (other) prefix
if (obj_variable.$.address.indexOf('D') > -1) {
fc = 1;
} else {
fc = 3;
}
// strip D/M from head of address
obj_variable.$.address = obj_variable.$.address.substring(1);
// populate the rest of the JSObject
rv[key] = {
address: obj_variable.$.address, // addresses, trimmed of letters
array_data_type_name: "", // empty
fc: fc, // function code
quantity: 1, // empty
type_name: Object.keys(obj_variable.type[0]).toString(), //object keys
word_length: 1, // empty
unitid: 255 // previously added by lvc_labels
}; // replace arr[i] with selected pieces
}
})
}
});
msg.payload = rv;
return msg;