Use complex (structured) data
- Last UpdatedAug 01, 2024
- 3 minute read
The second method (SubmitWorkOrder) is more advanced, accepting a single argument of type WorkOrder and returning a single argument, also of type WorkOrder. In pseudo-syntax:
WorkOrder SubmitWorkOrder(WorkOrder wo)
The WorkOrder type is a fictitious composite structure type defined by the OPC UA server with the following definition:

WorkOrderType contains three primitive type fields (ID, AssetID and StartTime), and a field (StatusComments) that contains an array of WorkOrderStatusType structures.
Declarations
Add the following variable declarations to the script:
dim wOrder as aaMethods.GenericStruct;
dim wOrderIn as aaMethods.GenericStruct;
dim statusComment1 as aaMethods.GenericStruct;
dim statusComment2 as aaMethods.GenericStruct;
Call a method with complex (structured) arguments
In this example, the script calls a method (SubmitWorkOrder) on the OPC UA server, with a single input argument of type WorkOrderType and a single output argument, also of type WorkOrderType. The OPC UA server method implementation adds an additional StatusCommentType to the passed-in WorkOrderType and returns the result to the caller.
The first step is to create the method input argument by creating an empty structure named WorkOrderType:
wOrderIn = methodHelper.CreateStruct("WorkOrderType");
This simply creates a GenericStruct with no fields. As mentioned previously, the script library has no knowledge of the actual WorkOrderType defined in the OPC UA server. As the script developer, it is up to you to ensure that the WorkOrderType structure created in the script library mirrors the actual type defined in the OPC UA server.
Next, start adding the appropriate fields to the WorkOrderType GenericStruct:
wOrderIn.AddField("ID", aaMethods.Value.Create(aaMethods.ValueType.String,
Me.WorkOrderId));
wOrderIn.AddField("AssetID", aaMethods.Value.Create(aaMethods.ValueType.String,
Me.WorkOrderAssetId));
wOrderIn.AddField("StartTime", aaMethods.Value.Create(aaMethods.ValueType.String,
Me.WorkOrderStartTime));
For the sake of simplicity, assume that the Application Object has attributes WorkOrderId, WorkOrderAssetId and StartTime, all of type string. Note that all Application Server attributes types except CustomStruct are supported.
The WorkOrderType contains an array of WorkOrderStatusType structures in a field called StatusComments. Create the WorkOrderStatusType structures as shown below:
statusComment1 = methodHelper.CreateStruct("WorkOrderStatusType");
statusComment1.AddField("Actor", aaMethods.Value.Create(aaMethods.ValueType.String,
Me.WorkOrderHistoryActor[1]));
statusComment1.AddField("TimeStamp",
aaMethods.Value.Create(aaMethods.ValueType.String,
Me.WorkOrderHistoryTime[1]));
statusComment1.AddField("Comment",
aaMethods.Value.Create(aaMethods.ValueType.String,
Me.WorkOrderHistoryComment[1]));
statusComment2 = methodHelper.CreateStruct("WorkOrderStatusType");
statusComment2.AddField("Actor", aaMethods.Value.Create(aaMethods.ValueType.String,
Me.WorkOrderHistoryActor[2]));
statusComment2.AddField("TimeStamp",
aaMethods.Value.Create(aaMethods.ValueType.String,
Me.WorkOrderHistoryTime[2]));
statusComment2.AddField("Comment",
aaMethods.Value.Create(aaMethods.ValueType.String,
Me.WorkOrderHistoryComment[2]));
Add the StatusComments field to the WorkOrderType:
wOrderIn.AddField("StatusComments", statusComment1, statusComment2);
The WorkOrderType GenericStruct now resembles the WorkOrderType defined earlier.
Finally, create the input argument and call the SubmitWorkOrder method:
inputArgs[1] = new aaMethods.MethodArgument("WorkOrder", wOrderIn);
outputArgs = methodHelper.CallMethod(("OPCUA_DeviceGroup",
"OPCUA_DeviceGroup./DemoServer/s=Demo.Method", "SubmitWorkOrder", "Joe Operator", inputArgs);
Process the result
As before, we get the result from the output argument returned by the method call:
wOrder = outputArgs[1][0];
In this case, we know that outputArgs[1] contains a single GenericStruct representing the WorkOrderType structure returned by the OPC UA server.
The individual WorkOrderType fields are accessed as before:
Me.WorkOrderId = wOrder.GetAsString("ID");
Me.WorkOrderAssetId = wOrder.GetAsString("AssetID");
Me.WorkOrderStartTime = wOrder.GetAsString("StartTime");
Me.WorkOrderHistoryActor[1] = wOrder.GetAsString("StatusComments[0].Actor");
Me.WorkOrderHistoryComment[1] = wOrder.GetAsString("StatusComments[0].Comment");
Me.WorkOrderHistoryTime[1] = wOrder.GetAsString("StatusComments[0].TimeStamp");
Me.WorkOrderHistoryActor[2] = wOrder.GetAsString("StatusComments[1].Actor");
Me.WorkOrderHistoryComment[2] = wOrder.GetAsString("StatusComments[1].Comment");
Me.WorkOrderHistoryTime[2] = wOrder.GetAsString("StatusComments[1].TimeStamp");
Me.WorkOrderHistoryActor[3] = wOrder.GetAsString("StatusComments[2].Actor");
Me.WorkOrderHistoryComment[3] = wOrder.GetAsString("StatusComments[2].Comment");
Me.WorkOrderHistoryTime[3] = wOrder.GetAsString("StatusComments[2].TimeStamp");
Note that the fields of the contained structure WorkOrderStatusType are accessed by specifying the index into the StatusComment field of the WorkOrderType structure, for example:
Me.WorkOrderHistoryActor[2] = wOrder.GetAsString("StatusComments[1].Actor");