5605x
001738
23. März 2022

Tutorial Webservice-API in VBA

Webservice ist eine Kommunikation zwischen Maschinen beziehungsweise Programmen. Diese Kommunikation wird über das Netzwerk bereitgestellt und kann daher von jedem Programm, welches Zeichenketten über das HTTP-Protokoll verschicken und empfangen kann, genutzt werden. RFEM 6 und RSTAB 9 bieten eine Schnittstelle auf Basis dieser plattformübergreifenden Webservices. Dieses Tutorial soll die Grundlagen anhand der Programmiersprache VBA zeigen.

Grundlagen Webservice API am Beispiel von VBA

Für die Formatierung der Zeichenkette wird das XML-Format nach den Spezifikationen des SOAP-Protokolls verwendet. Als Beispiel soll die folgende Abfrage dienen:

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

Ein typisches Element der XML-Formatierung ist der Beginn eines Abschnitts mit dem Zeichen "<". Danach folgt ein Bezeichner und, falls keine weiteren untergeordneten Elemente folgen, wird der Abschnitt mit "/>" beendet. Ein Beispiel ist die dritte Zeile:

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

Wenn Unterelemente vorliegen, wird mit "<", dem Befehl und ">" begonnen und den Abschluss bilden "</", der Befehl und ">". Das passende Beispiel ist der Abschnitt "Body":

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

Die Formatierung mit Leerzeichen und Zeilenumbrüchen dient hier nur der Veranschaulichung. Für die Übertragung ist diese nicht erforderlich. Die Elemente "Body" und "Envelope" sind Standardelemente für die Übertragung und werden für jeden Befehl verwendet.

Alle verfügbaren Befehle können mithilfe der WSDL-Schnittstelle ausgelesen werden. Es gibt Software, mit deren Hilfe daraus Listen erzeugt werden können. Eine solche Software ist beispielsweise SoapUI. Für die API von RFEM 6 gibt es zwei Listen, die Befehle für die Anwendung und die für das Modell. Beide Listen können am Ende dieses Beitrags heruntergeladen werden.

Da Befehle über HTTP gesendet werden, werden zum Ansprechen URL-Adressen benötigt. Die Standardadresse der Anwendungen RSTAB/RFEM ist "http://localhost:8081/" und kann in den Einstellungen im Programm geändert werden. Geöffnete Modelle erhalten aufsteigende Adressen, sodass das erste geöffnete Modell die Adresse "http://localhost:8082/" hat. Um die Adresse des aktiven Modells zu erhalten, wird der Befehl "get_active_model" gesandt. Eine entsprechende Antwort von RFEM 6 sieht so aus:

<?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>

Die zusätzlichen Details des "Envelope"-Abschnitts (deutsch: Umschlag/Briefumschlag) sowie die vorangestellte Zeile "<?xml version="1.0"?>" sollen zunächst die verwendeten Standards aufzeigen und hier nicht weiter erörtert werden. Zu erkennen ist in jedem Falle, dass wieder die Elemente "Envelope" und "Body" verwendet werden. Innerhalb von "Body" steckt die Antwort von RFEM 6 durch den Befehlsnamen "get_active_model" und dem angehängten Wort "Response". Inhalt dieser Antwort ist ein Wert ("value") und zwar die Adresse des aktiven Modells. Zudem wird RFEM jetzt für weitere Zugriffe gesperrt.

Im folgenden Beispiel soll ein Stab mit zwei Knotenlagern und einer Last angelegt werden. Um über VBA mit RFEM kommunizieren zu können, werden die folgenden Objekte benötigt:

request As MSXML2.XMLHTTP60
response As MSXML2.DOMDocument

Das Objekt XMLHTTP60 hat eine integrierte Funktion zum Senden einer HTTP-Anfrage an eine URL und wird daher für die Anfrage verwendet. Die Antwort kann dann mithilfe des DOMDocuments ausgewertet werden. Das folgende Beispiel vereint die zuvor gezeigte Anfrage "get_active_model" mit den unter VBA verwendeten Befehlen:

'   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)

Zuerst wird die Anfrage im XML-Format in der Variable "str_envelope" gespeichert und über die Methode "Open" der Variable "request" die Anfrage an RFEM geöffnet. Über die Methode "Send" kann jetzt der Inhalt der Variable "str_envelope" verschickt werden. Die Antwort kann danach über die Methode "ResponseText" abgerufen werden. Im konkreten Fall wird diese über die Methode "LoadXML" der Variable "response" direkt eingelesen.

Die Variable "response" vom Typ DOMDocuments hat die Methode LoadXML und kann damit die XML-Formatierung erkennen. Der Vorteil besteht darin, dass der Typ DOMDocuments auch die Methode GetElementsByTagName bereitstellt. Damit lassen sich direkt Elemente aus dem Code extrahieren. Im Folgenden wird der vorige Code noch erweitert, sodass die URL-Adresse des Modells zur Verfügung steht:

'   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

Bevor die URL ausgelesen wird, kann noch der Status der Antwort überprüft werden. Es handelt sich um standardisierte HTTP-Statuscodes. Der Status "200" bedeutet, dass die Übertragung "OK" war. Nach dieser Abfrage wird in der Zeichenkette url_model die URL des Modells gespeichert. Dazu wird aus der XML-Antwort das Element "value" gesucht. Wenn eine Antwort mehrere Elemente enthält, werden alle Werte innerhalb des Abschnitts "value" abgelegt, sodass hier keine Auswertung mit dem Bezeichner "value" möglich ist, sondern die Unterelemente von "value" angesprochen werden. Mehr dazu im Praxisbeispiel. Im Fall der Modelladresse ist der einzige zurückgegebene Wert die URL, sodass "value" hier zum Erfolg führt.

Praxisbeispiel in VBA

Da nun alle Basiselemente bekannt sind, folgt ein einfaches Beispiel. Es soll ein Träger auf zwei Stützen erzeugt werden, auf dem eine Stablast aufgebracht werden kann.

Zuerst werden die bereits vorgestellten Variablen definiert und initialisiert:

'    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/"

Neben den Variablen "request" und "response" werden die Zeichenkette "str_envelope" für die Anfrage und "url_app" und "url_model" für die Adressen von Anwendung und Modell angelegt. Bei der Initialisierung können die bekannten Spezifikationen des SOAP-Protokolls zur Auswertung der XML-Formatierung der Antwort übergeben werden. Die Adresse des Modells wird später geholt, aber die Adresse der Anwendung muss angeben werden. Wie bereits zuvor erwähnt ist die Standardadresse "http://localhost:8081/" anzugeben.

Im nächsten Schritt soll die Verbindung zur Anwendung getestet werden. Für diesen Test werden über den Befehl "get_information" die Standardinformationen der Anwendung abgefragt:

'   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"

Wie bereits im ersten Teil beschrieben, wird zuerst die XML-formatierte Anfrage vorbereitet und in "str_envelope" gespeichert. "request.Open" öffnet die Verbindung zur Anwendung. Das Schlüsselwort "Post" steht dabei für das Senden der Anfrage. Der dritte Parameter steht auf "true" und damit wird eine synchrone Übertragung durchgeführt. Im Anschluss sendet "request.Send" die vorbereitete Zeichenkette.

Nach der Übertragung wird die Antwort in "response" gespeichert und mit "request.Status" überprüft, ob die Anfrage erfolgreich war. Der Status wird dabei von RFEM vergeben, sodass dieses bei einer fehlerhaften Anfrage, zum Beispiel einem unbekannten Befehl, einen Fehler zurückgibt. Wenn der Status nicht "200" ist, wird das Programm abgebrochen und der Fehler in einem Fenster (MsgBox) ausgegeben.

Wenn keine Fehler entstanden sind, können jetzt über "GetElementsByTagName" die verschiedenen übertragenen Informationen ausgelesen werden. Im konkreten Beispiel werden die Informationen dann in einem Fenster dargestellt.

Die folgenden Elemente weisen große Ähnlichkeiten auf, daher wird nur auf Besonderheiten eingegangen (der komplette Quellcode steht zum Download zur Verfügung). Für den Aufbau eines Trägers auf zwei Stützen mit einer Stablast werden folgende Funktionen benötigt:

  1. Knoten - set_node
  2. Linie - set_line
  3. Material - set_material
  4. Querschnitt - set_section
  5. Stab - set_member
  6. Knotenlager - set_nodal_support
  7. Berechnungsparameter - set_static_analysis_settings
  8. Lastfall - set_load_case
  9. Stablast - set_member_load

Die Funktion "set_node" hat, wie die meisten anderen, viele Parameter, welche aber im Normalfall nicht benötigt werden. In der bereits erwähnten Befehlsliste des RFEM-Modells kann die Vielfalt der Parameter eingesehen werden. Wichtig sind vor allem die Parameter, welche nicht den Vermerk "optional" haben, da diese in jedem Fall ausgefüllt werden müssen. Im Beispiel werden folgende Parameter übergeben:

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>"

Einzig die Knotennummer ist hier nicht optional und der Rest kann vergeben werden. In der Befehlsliste werden neben den möglichen Parametern auch Auflistungen für Typen aufgezeigt. Im konkreten Fall sind derzeit fünf verschiedene Typen möglich. Es wurde der Standardtyp "TYPE_STANDARD" gewählt. Der hier gezeigte erste Knoten wird an der Stelle (0;0;0) erstellt, der zweite Knoten bei (5,5;0;0). Die Werte bei Kommazahlen sehen dann wie folgt aus:

...
    "<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>" & _
...

Eine weitere Besonderheit stellen Listen dar. Die Linie braucht zwei Knoten, deren Nummern als Liste übergeben werden können. Die Elemente einer Liste, wie hier "definition_nodes", werden durch Leerzeichen getrennt:

...
    "<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>" & _
...

Um den Stab anlegen zu können, muss noch ein Querschnitt angelegt werden, welcher wiederum ein Material benötigt. Querschnitte und Materialien können aus der internen Datenbank genutzt werden. Darum genügt die Angabe eines bekannten Bezeichners. Für das Material ist der Bezeichner "S235" und der Querschnitt hat den Namen "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>" & _
...

Zur Überprüfung, ob ein Name wie "IPE 300" gültig ist, kann die Eingabe in der grafischen Oberfläche genutzt werden.

Für die Eingabe des Stabes an sich werden keine weiteren Kenntnisse benötigt, für die Eingabe eines festen Lagers muss aber eine "unendliche" Federsteifigkeit definiert werden. Für die Übergabe wird das Schlüsselwort "INF" verwendet:

...
    "<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>" & _
...

Das Anlegen des Lastfalls und der Berechnungsparameter benötigt keine zusätzlichen Kenntnisse. Die letzte Besonderheit stellt ein zusätzlicher Wert beim Anlegen der Last dar, da er außerhalb des Bereichs "<value>" angegeben werden muss. Im Falle der Stablast muss der zugehörige Lastfall dort übergeben werden:

...
    "<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>" & _
...

Ergänzend dazu sei erwähnt, dass die Reihenfolge der Elemente innerhalb des Bereichs "value" keine Rolle spielt, außerhalb aber schon. Der angegebene Lastfall muss also vor dem Bereich "value" stehen.

Neben den bisherigen Funktionen zum Anlegen und Auslesen von Daten gibt es noch zwei besondere Funktionen, die vorgestellt werden. Wenn dem Programm Elemente übergeben werden, geht das Programm automatisch in einen "Modification"-Modus, also Bearbeitungsmodus. Das Programm überprüft die neuen Elemente und arbeitet diese ein. Wenn mehrere neue Elemente angelegt werden sollen, ist es daher sinnvoll, das Programm für diese Zeit in diesem Bearbeitungsmodus zu lassen, damit die Abarbeitung schneller ist. Zu diesem Zweck gibt es die Funktionen "begin_modification" und "finish_modification". Im Beispiel wird daher vor dem Anlegen des ersten Knotens "begin_modification" aufgerufen und am Ende, nach dem Anlegen des Lastfalls, "finish_modification". Die beiden Funktionen wurden im Programm auch als VBA-Funktionen angelegt. Die Funktionen sind eigenständig und daher werden innerhalb der Funktionen erneut die Variablen "request" und "response" angelegt. Da aber keine neuen Elemente dafür benötigt werden, wird hier nicht weiter darauf eingegangen. Interessant ist der Vergleich mit und ohne die Nutzung dieser Funktionen, welcher immer einen Geschwindigkeitsunterschied bringen wird.

Zusammenfassung

Die Webservice-API ist ein mächtiges Werkzeug für RFEM und RSTAB. Die simple HTTP-basierte Übertragung ermöglicht die Implementierung der Schnittstelle in viele Programmiersprachen, nicht nur wie hier dargestellt in VBA, und eine plattformübergreifende Programmierung wird möglich.


Autor

Herr Günthel kümmert sich im Kundensupport um die Anliegen unserer Anwender.

Links
Downloads