5649x
001738
2022-03-23

Webservice API in VBA Tutorial

Webservice is a communication between machines and programs. This communication is provided via the network and can, therefore, be used by any program that can send and receive strings via the HTTP protocol. RFEM 6 and RSTAB 9 provide an interface based on these cross-platform webservices. This tutorial shows the basics using the VBA programming language.

Basics of Webservice API Using the Example of VBA

For the formatting of the string, the XML format is used according to the specifications of the SOAP protocol. The following query serves as an example:

<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
    <Body>
        <get_active_model xmlns="http://www.dlubal.com/rfem.xsd"/>
    </Body>
</Envelope>

A typical element of XML formatting is the start of a section with the "<" character. Then, an identifier follows and, if no other sub-elements are present, the section is closed with "/>". One example is the third line:

<get_active_model xmlns="http://www.dlubal.com/rfem.xsd"/>

If there are sub-elements, it starts with "<", the command and ">" and ends with "</", the command and ">". The appropriate example is the "Body" section:

<Body>
    <get_active_model xmlns="http://www.dlubal.com/rfem.xsd"/>
</Body>

The formatting with spaces and line breaks is used here for illustrative purposes only. This is not required for the transfer. The "Body" and "Envelope" elements are standard elements for the transfer and are used for each command.

All available commands can be read out using the WSDL interface. Software is available that can be used to create lists. An example for such software is SoapUI. There are two lists for the API of RFEM 6; the commands for the application and those for the model. Both lists can be downloaded at the end of this article.

Since commands are sent via HTTP, URL addresses are required for addressing. The default address of the RSTAB/RFEM applications is "http://localhost:8081/" and can be changed in the settings in the program. Opened models are assigned addresses in ascending order so that the first open model has the address "http://localhost:8082/". To get the address of the active model, the "get_active_model" command is sent. A corresponding response from RFEM 6 looks like this:

<?xml version="1.0"?>
<Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:soap-enc="http://schemas.xmlsoap.org/soap/encoding/"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <soap:Body>
        <n1:get_active_modelResponse
            xmlns:n1="http://www.dlubal.com/rfem.xsd">
            <value>
                http://127.0.0.1:8082/
            </value>
        </n1:get_active_modelResponse>
    </soap:Body>
</soap:Envelope>

The additional details of the "Envelope" section as well as the preceding line "<?xml version="1.0"?>" should first show the standards used and will not be discussed further here. In any case, you can see that the "Envelope" and "Body" elements are used again. The RFEM 6 response is contained within "Body" by the command name "get_active_model" and the appended word "Response". The content of this response is a "value", namely the address of the active model. In addition, RFEM is now locked for further access.

In the following example, we want to create a member with two nodal supports and a load. To be able to communicate with RFEM via VBA, the following objects are required:

request As MSXML2.XMLHTTP60
response As MSXML2.DOMDocument

The XMLHTTP60 object has a built-in function for sending an HTTP request to a URL and is, therefore, used for the request. The response can then be evaluated using the DOMDocument. The following example combines the previously shown "get_active_model" request with the commands used under VBA:

'   get active model url with "get_active_model" command
str_envelope = 
    "<Envelope xmlns=""http://schemas.xmlsoap.org/soap/envelope/"">" & _
    "   <Body>" & _
    "       <get_active_model xmlns=""http://www.dlubal.com/rfem.xsd""/>" & _
    "   </Body>" & _
    "</Envelope>"

'   open request and send it
request.Open "Post", "http://localhost:8081/", False
request.Send (str_envelope)

'   get response and transform it to an xml-object
response.LoadXML (request.responseText)

First, the request is saved in XML format in the "str_envelope" variable and the request is opened in RFEM using the "Open" method of the "request" variable. The content of the "str_envelope" variable can now be sent using the "Send" method. The response can then be accessed using the "ResponseText" method. In this specific case, this is imported directly via the "LoadXML" method of the "response" variable.

The "response" variable of the DOMDocuments type has the LoadXML method and can thus recognize the XML formatting. The advantage is that the DOMDocuments type also provides the GetElementsByTagName method. This allows you to extract elements directly from the code. In the following, the previous code is extended so that the URL address of the model is available:

'   get http-status
status = request.status
If status <> "200" Then
    MsgBox "get_active_model: Sending not successful - " & response.Text
    Exit Sub
End If

url_model = response.GetElementsByTagName("value")(0).Text

Before the URL is read out, the status of the response can be checked. They are standardized HTTP status codes. Status "200" means that the transfer was "OK". After this query, the URL of the model is saved in the url_model string. For this, the "value" element is searched for in the XML response. If an answer contains several elements, all values are saved within the "value" section, so that no evaluation with the "value" identifier is possible, but the sub-elements of "value" are addressed. More information will be provided in the practical example. In the case of the model address, the only returned value is the URL, so "value" is successful here.

Practical Example in VBA

Now that we know all the basic elements, a simple example follows. We want to create a beam on two columns to which a member load can be applied.

First, the variables described above are defined and initialized:

'    define variables
Dim request As MSXML2.XMLHTTP60
Dim response As MSXML2.DOMDocument60

Dim str_envelope As String
Dim url_app As String
Dim url_model As String

'   init variables
Set request = New MSXML2.XMLHTTP60

Set response = New MSXML2.DOMDocument60
With response
    .async = False
    .preserveWhiteSpace = False
    .validateOnParse = False
    .resolveExternals = False
    '   Use full XPath functionality
    .SetProperty "SelectionLanguage", "XPath"
    '   Add specific Namespaces to work with Paths
    .SetProperty "SelectionNamespaces", "xmlns:soap=""http://www.w3.org/2003/05/soap-envelope"" " & _
                    "xmlns:xsd=""http://www.dlubal.com/rfem.xsd"" " & _
                    "xmlns:n1=""urn:schemas-microsoft-com:rowset"" " & _
                    "xmlns=""http://www.dlubal.com/rfem.xsd"" "
End With

url_app = "http://localhost:8081/"

In addition to the variables "request" and "response", the "str_envelope" string is created for the request and "url_app" and "url_model" for the addresses of the application and model. During the initialization, the known specifications of the SOAP protocol can be transferred to evaluate the XML formatting of the response. The address of the model will be taken later, but the address of the application must be specified. As already mentioned, the default address "http://localhost:8081/" must be entered.

The next step is to test the connection to the application. For this test, the standard information of the application is queried using the "get_information" command:

'   check application url with command "get_information"
str_envelope = "<Envelope xmlns=""http://schemas.xmlsoap.org/soap/envelope/"">" & _
                "   <Body>" & _
                "       <get_information xmlns=""http://www.dlubal.com/rfem.xsd""/>" & _
                "   </Body>" & _
                "</Envelope>"

'   open request and send it
request.Open "Post", url_app, False
request.Send (str_envelope)

'   get response and transform it to an xml-object
response.LoadXML (request.responseText)

'   get http-status
status = request.Status
If status <> "200" Then
    MsgBox "get_information: Sending not successful - " & response.Text
    Exit Sub
End If

'   read application information
Dim str1 As String
str1 = ""
str1 = str1 & response.GetElementsByTagName("name")(0).Text & vbLf
str1 = str1 & response.GetElementsByTagName("type")(0).Text & vbLf
str1 = str1 & response.GetElementsByTagName("version")(0).Text & vbLf
str1 = str1 & response.GetElementsByTagName("language_name")(0).Text & vbLf
str1 = str1 & response.GetElementsByTagName("language_id")(0).Text

MsgBox str1, vbInformation, "Response to ""get_information"" request"

As already described in the first part, the XML-formatted request is prepared and saved in "str_envelope". "request.Open" opens the connection to the application. The keyword "Post" stands for the sending of the request. The third parameter is set to "true" and thus a synchronous transmission is carried out. Finally, "request.Send" sends the prepared string.

After the transfer, the response is saved in "response" and checked with "request.Status" as to whether the request was successful. The status is assigned by RFEM so that it returns an error in the case of an incorrect request; for example, an unknown command. If the status is not "200", the program is aborted and the error is displayed in a window (MsgBox).

If no errors have occurred, the various transferred information can now be read out using "GetElementsByTagName". In the specific example, the information is then displayed in a window.

The following elements are very similar, so only special features are described (the complete source code can be downloaded). To set up a beam on two columns with a member load, the following functions are required:

  1. Node - set_node
  2. Line - set_line
  3. Material - set_material
  4. Cross-section - set_section
  5. Member - set_member
  6. Nodal support - set_nodal_support
  7. Calculation parameters - set_static_analysis_settings
  8. Load case - set_load_case
  9. Member load - set_member_load

Like most others, the "set_node" function has many parameters, but they are usually not required. In the already mentioned command list of the RFEM model, you can see the variety of parameters. Above all, the parameters that are not marked as "optional" are important, as they must be completed in each case. In the example, the following parameters are transferred:

begin_modification (url_model)

'   set node 1 on [0,0,0] with "set_node" command
str_envelope =
    "<Envelope xmlns=""http://schemas.xmlsoap.org/soap/envelope/"">" & _
        "<Body>" & _
            "<set_node xmlns=""http://www.dlubal.com/rfem.xsd"">" & _
                "<value xmlns="""">" & _
                    "<no>1</no>" & _
                    "<type>TYPE_STANDARD</type>" & _
                    "<coordinate_1>0</coordinate_1>" & _
                    "<coordinate_2>0</coordinate_2>" & _
                    "<coordinate_3>0</coordinate_3>" & _
                "</value>" & _
            "</set_node>" & _
        "</Body>" & _
    "</Envelope>"

Only the node number is not optional; the rest can be assigned, but does not have to be. In addition to the possible parameters, the command list also shows type listings. In this specific case, five different types are currently possible. The default type "TYPE_STANDARD" has been selected. The first node shown here is created at the location (0; 0; 0), the second node at (5.5; 0; 0). The values for decimal numbers are as follows:

...
    "<value xmlns="""">" & _
        "<no>2</no>" & _
        "<type>TYPE_STANDARD</type>" & _
        "<coordinate_1>5.5</coordinate_1>" & _
        "<coordinate_2>0</coordinate_2>" & _
        "<coordinate_3>0</coordinate_3>" & _
    "</value>" & _
...

Lists are another special feature. The line needs two nodes of which the numbers can be transferred as a list. The elements of a list, such as "definition_nodes", are separated by spaces:

...
    "<set_line xmlns=""http://www.dlubal.com/rfem.xsd"">" & _
        "<value xmlns="""">" & _
            "<no>1</no>" & _
            "<type>TYPE_POLYLINE</type>" & _
            "<definition_nodes>1 2</definition_nodes>" & _
        "</value>" & _
    "</set_line>" & _
...

To be able to create the member, a cross-section must be created, which in turn requires a material. Cross-sections and materials can be used from the internal database. Therefore, it is sufficient to specify a known identifier. For the material, the identifier is "S235" and the cross-section has the name "IPE 300":

...
    "<set_section xmlns=""http://www.dlubal.com/rfem.xsd"">" & _
        "<value xmlns="""">" & _
            "<no>1</no>" & _
            "<material>1</material>" & _
            "<type>TYPE_STANDARDIZED_STEEL</type>" & _
            "<name>IPE 300</name>" & _
        "</value>" & _
    "</set_section>" & _
...

To check whether a name such as "IPE 300" is valid, you can use the entry in the graphical user interface.

To enter the member itself, no further knowledge is required, but to enter a fixed support, you have to define an "infinite" spring stiffness. The keyword "INF" is used for the transfer:

...
    "<set_nodal_support xmlns=""http://www.dlubal.com/rfem.xsd"">" & _
        "<value xmlns="""">" & _
            "<no>1</no>" & _
            "<nodes>1</nodes>" & _
            "<spring_x>INF</spring_x>" & _
            "<spring_y>INF</spring_y>" & _
            "<spring_z>INF</spring_z>" & _
            "<rotational_restraint_x>INF</rotational_restraint_x>" & _
            "<rotational_restraint_y>0</rotational_restraint_y>" & _
            "<rotational_restraint_z>INF</rotational_restraint_z>" & _
        "</value>" & _
    "</set_nodal_support>" & _
...

Creating the load case and the calculation parameters does not require any additional knowledge. The last peculiarity is an additional value when creating the load, because it must be specified outside the "<value>" area. In the case of a member load, the corresponding load case must be transferred there:

...
    "<set_member_load xmlns=""http://www.dlubal.com/rfem.xsd"">" & _
        "<load_case_no xmlns="""">1</load_case_no>" & _
        "<value xmlns="""">" & _
            "<no>1</no>" & _
            "<load_type>LOAD_TYPE_FORCE</load_type>" & _
            "<members>1</members>" & _
            "<load_distribution>LOAD_DISTRIBUTION_UNIFORM</load_distribution>" & _
            "<load_direction>LOAD_DIRECTION_GLOBAL_Z_OR_USER_DEFINED_W_TRUE</load_direction>" & _
            "<magnitude>1000</magnitude>" & _
        "</value>" & _
    "</set_member_load>" & _
...

In addition, it should be mentioned that the order of the elements within the "value" area is irrelevant, but outside it is not. The specified load case must, therefore, come before the "value" area.

In addition to the previous functions for creating and exporting data, there are two special functions that will be shown here. If elements are transferred to the program, the program automatically goes into a "Modification" mode. The program checks the new elements and integrates them. If several new elements are to be created, it is, therefore, useful to leave the program in this editing mode for this time, so that the processing is faster. The "begin_modification" and "finish_modification" functions are available for this purpose. In the example, "begin_modification" is called before creating the first node and "finish_modification" is called at the end after creating the load case. Both functions were also created as VBA functions in the program. The functions are independent, and therefore the variables "request" and "response" are created again within the functions. However, since no new elements are required for this, they will not be described further here. An interesting comparison is the one with and without the use of these functions, which will always result in a speed difference.

Summary

The Webservice API is a powerful tool for RFEM and RSTAB. The simple HTTP-based transfer allows the interface to be implemented in many programming languages, not only in VBA as shown here, and cross-platform programming is possible.


Author

Mr. Günthel provides technical support for our customers.

Links
Downloads