8809x
001738
2025-06-09

Tutorial Webservice API w VBA

Webservice to komunikacja między maszynami lub programami. Ta komunikacja jest udostępniana przez sieć, a zatem może być wykorzystywana przez każdy program, który może wysyłać i odbierać ciągi znaków za pośrednictwem protokołu HTTP. RFEM 6 i RSTAB 9 oferują interfejs oparty na tych wieloplatformowych usługach sieciowych. Ten samouczek ma na celu przedstawienie podstaw na przykładzie języka programowania VBA.

Podstawy Webservice API na przykładzie VBA

Do formatowania ciągu znaków używany jest format XML zgodnie ze specyfikacją protokołu SOAP. Jako przykład, służy temu następujące zapytanie:



    <Body>
        
    </Body>

Typowym elementem formatowania XML jest rozpoczęcie sekcji znakiem "<". Następnie pojawia się identyfikator i, jeśli nie ma dalszych elementów podrzędnych, sekcja jest zakończona przez "/>". Przykładem jest trzecia linia:



Gdy występują elementy podrzędne, rozpoczynane są przez "<", komendę i ">", a kończone przez "</", komendę i ">". Odpowiednim przykładem jest sekcja "Body":


<Body>
    
</Body>

Formatowanie za pomocą spacji i złamań linii służy jedynie ilustracji. Do transmisji nie jest to wymagane. Elementy "Body" i "Envelope" są elementami standardowymi do transmisji i są używane dla każdej komendy.

Wszystkie dostępne polecenia mogą być odczytywane za pomocą interfejsu WSDL. Istnieje oprogramowanie, które pozwala wygenerować z nich listy. Przykładem takiego oprogramowania jest SoapUI. Dla API RFEM 6 istnieją dwie listy, polecenia dla aplikacji i te dla modelu. Obie listy można pobrać na końcu tego wpisu.

Ponieważ polecenia są wysyłane przez HTTP, potrzebne są adresy URL do ich inicjowania. Standardowym adresem aplikacji RSTAB/RFEM jest "localhost:8081" i można go zmienić w ustawieniach programu.

Otwarte modele uzyskują wzrastające adresy, więc pierwszy otwarty model ma adres "localhost:8082". Aby uzyskać adres aktywnego modelu, wysyłana jest komenda "get_active_model". Odpowiedź od RFEM 6 wygląda w następujący sposób:



    
        
            
                http://127.0.0.1:8082/
            
        
    

Dodatkowe szczegóły sekcji "Envelope" (z ang.: koperta) oraz wprowadzająca linia "<?xml version="1.0"?>" mają początkowo za zadanie ukazać używane standardy i nie będą tu dalej omawiane. W każdym razie można zauważyć, że znowu używane są elementy "Envelope" i "Body". Wewnątrz "Body" znajduje się odpowiedź od RFEM 6 przez nazwę polecenia "get_active_model" i dołączone słowo "Response". Zawartością tej odpowiedzi jest wartość ("value"), a mianowicie adres aktywnego modelu. Dodatkowo RFEM jest teraz zablokowany dla dalszych dostępów.

W następnym przykładzie ma zostać utworzony pręt z dwoma podporami węzłowymi i obciążeniem. Aby komunikować się z RFEM za pośrednictwem VBA, potrzebne są następujące obiekty:


request As MSXML2.XMLHTTP60
response As MSXML2.DOMDocument

Obiekt XMLHTTP60 ma wbudowaną funkcję do wysyłania zapytania HTTP do URL, dlatego jest używany do zapytania. Odpowiedź można następnie analizować za pomocą DOMDocument. Poniższy przykład łączy wcześniej pokazane zapytanie "get_active_model" z poleceniami używanymi pod VBA:


'   get active model url with "get_active_model" command
str_envelope =
    "" & _
    "   <Body>" & _
    "       " & _
    "   </Body>" & _
    ""

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

Najpierw zapytanie w formacie XML jest przechowywane w zmiennej "str_envelope" i poprzez metodę "Open" zmiennej "request" zapytanie jest otwierane w RFEM. Za pomocą metody "Send" można teraz wysłać zawartość zmiennej "str_envelope". Odpowiedź można następnie pobrać za pomocą metody "ResponseText". W konkretnym przypadku jest ona bezpośrednio wczytywana za pomocą metody "LoadXML" zmiennej "response".

Zmiennej "response" typu DOMDocuments ma metodę LoadXML i dzięki temu rozpoznaje formatowanie XML. Zaletą jest to, że typ DOMDocuments udostępnia także metodę GetElementsByTagName. Pozwala to bezpośrednio wyciągać elementy z kodu. Następująco zostanie rozszerzony poprzedni kod, aby adres URL modelu był dostępny:


'   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

Zanim adres URL zostanie odczytany, można jeszcze sprawdzić status odpowiedzi. Chodzi tu o standardowe kody statusu HTTP. Status "200" oznacza, że transmisja była "OK". Po tym zapytaniu, w ciągu znaków url_model przechowywany jest adres URL modelu. W tym celu szuka się elementu "value" w odpowiedzi XML. Gdy odpowiedź zawiera wiele elementów, wszystkie wartości wewnątrz sekcji "value" są przechowywane, więc tutaj nie jest możliwa analiza przy użyciu identyfikatora "value", lecz należy odwołać się do elementów podrzędnych "value". Więcej na ten temat w przykładzie praktycznym. W przypadku adresu modelu jedyną zwracaną wartością jest URL, więc użycie "value" tutaj się sprawdza.

Przykład praktyczny w VBA

Gdy wszystkie elementy podstawowe są znane, przedstawiamy prosty przykład. Ma zostać stworzona belka na dwóch podporach, na której można nałożyć obciążenie liniowe.

Najpierw definiowane i inicjalizowane są już przedstawione zmienne:


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

Oprócz zmiennych "request" i "response", są tworzone ciągi znaków "str_envelope" do zapytania oraz "url_app" i "url_model" dla adresów aplikacji i modelu. Podczas inicjalizacji można przekazać znane specyfikacje protokołu SOAP do analizy formatowania XML odpowiedzi. Adres modelu zostanie później uzyskany, ale adres aplikacji musi być podany. Jak już wcześniej wspomniano, należy podać adres standardowy:

W następnym kroku należy przetestować połączenie z aplikacją. Do tego testu, za pomocą komendy "get_information", pobierane są standardowe informacje aplikacji:


'   check application url with command "get_information"
str_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"

Jak opisano w pierwszej części, najpierw przygotowywane jest zapytanie sformatowane jako XML i przechowywane w "str_envelope". "request.Open" otwiera połączenie z aplikacją. Słowo kluczowe "Post" oznacza wysyłanie zapytania. Trzeci parametr jest ustawiony na "true", co oznacza, że realizowana jest transmisja synchroniczna. Następnie "request.Send" wysyła przygotowany ciąg znaków.

Po przesłaniu odpowiedź jest przechowywana w "response" i sprawdza się, czy zapytanie było udane za pomocą "request.Status". Status jest przyznawany przez RFEM, więc w przypadku błędnego zapytania, na przykład nieznanej komendy, zwracany jest błąd. Jeśli status nie wynosi "200", program jest przerywany, a błąd wyświetlany w oknie (MsgBox).

Jeśli nie wystąpiły błędy, teraz można odczytać różne przesyłane informacje za pomocą "GetElementsByTagName". W konkretnym przykładzie informacje są następnie wyświetlane w oknie.

Następujące elementy mają duże podobieństwa, dlatego skupimy się tylko na szczegółach (pełny kod źródłowy jest dostępny do pobrania). Do stworzenia belki na dwóch podporach z obciążeniem liniowym potrzebne są następujące funkcje:

  1. Węzeł – set_node
  2. Linia – set_line
  3. Materiał – set_material
  4. Przekrój – set_section
  5. Pręt – set_member
  6. Podpora węzłowa – set_nodal_support
  7. Parametry obliczeniowe – set_static_analysis_settings
  8. Przypadek obciążenia – set_load_case
  9. Obciążenie liniowe – set_member_load

Funkcja "set_node" ma, jak wiele innych, wiele parametrów, które jednak zwykle nie są potrzebne. W już wspomnianej liście komend modelu RFEM można zapoznać się z różnorodnością parametrów. Ważne są przede wszystkim parametry, które nie mają adnotacji "opcjonalne", ponieważ muszą być w każdym przypadku wypełnione. W przykładzie przekazywane są następujące parametry:


begin_modification (url_model)

'   set node 1 on [0,0,0] with "set_node" command
str_envelope =
    "" & _
        "<Body>" & _
            "" & _
                "" & _
                    "1" & _
                    "TYPE_STANDARD" & _
                    "0" & _
                    "0" & _
                    "0" & _
                "" & _
            "" & _
        "</Body>>" & _
    ""

Jedynym nieopcjonalnym tutaj jest numer węzła, reszta może być nadawana. Na liście komend, poza możliwymi parametrami, znajdują się również listy typów. W tym przypadku możliwych jest obecnie pięć różnych typów. Wybrano standardowy typ "TYPE_STANDARD". Pokazany tutaj pierwszy węzeł jest tworzony w punkcie (0;0;0), drugi węzeł przy (5,5;0;0). Wartości dla liczb dziesiętnych wyglądają w ten sposób:


…
"" & _
        "2" & _
        "TYPE_STANDARD" & _
        "5.5" & _
        "0" & _
        "0" & _
    "" & _
…

Kolejnym szczegółem są listy. Linia potrzebuje dwóch węzłów, których numery przekazywane są jako lista. Elementy listy, jak tutaj "definition_nodes", są oddzielane spacjami:


…
    "" & _
        "" & _
            "1" & _
            "TYPE_POLYLINE" & _
            "1 2" & _
        "" & _
    "" & _
…

Aby można było utworzyć pręt, trzeba jeszcze utworzyć przekrój, który z kolei potrzebuje materiału. Przekroje i materiały mogą być używane z wewnętrznej bazy danych. Dlatego wystarcza podanie znanego identyfikatora. Dla materiału jest to oznaczenie "S235", a przekrój ma nazwę "IPE 300":


…
    "" & _
        "" & _
            "1" & _
            "1" & _
            "TYPE_STANDARDIZED_STEEL" & _
            "IPE 300" & _
        "" & _
    "" & _
…

Aby sprawdzić, czy nazwa taka jak "IPE 300" jest prawidłowa, można skorzystać z wejścia w interfejsie graficznym.

Do wprowadzenia samego pręta nie są potrzebne nowe umiejętności, ale do wprowadzenia podpory stałej musi być zdefiniowana "nieskończona" sztywność sprężyny. Do przekazania używa się słowa kluczowego "INF":


…
    "" & _
        "" & _
            "1" & _
            "1" & _
            "INF" & _
            "INF" & _
            "INF" & _
            "INF" & _
            "0" & _
            "INF" & _
        "" & _
    "" & _
…

Tworzenie przypadku obciążenia i parametrów obliczeniowych nie wymaga dodatkowych umiejętności. Ostatnią wyjątkowość stanowi dodatkowa wartość podczas tworzenia obciążenia, gdyż musi być podana poza obszarem "". W przypadku obciążenia pręta tam musi być przekazany związany z nim przypadek obciążenia:


…
    "" & _
        "1" & _
        "" & _
            "1" & _
            "LOAD_TYPE_FORCE" & _
            "1" & _
            "LOAD_DISTRIBUTION_UNIFORM" & _
            "LOAD_DIRECTION_GLOBAL_Z_OR_USER_DEFINED_W_TRUE" & _
            "1000" & _
        "" & _
    "" & _
…
Dodatkowo należy zauważyć, że kolejność elementów wewnątrz obszaru "value" nie ma znaczenia, ale poza nim ma. Podany przypadek obciążenia musi więc być przed obszarem "value". Oprócz dotychczasowych funkcji do tworzenia i odczytywania danych, istnieją jeszcze dwie szczególne funkcje, które zostaną przedstawione. Gdy program otrzymuje elementy, automatycznie przechodzi w tryb "Modification", czyli tryb edycji. Program sprawdza nowe elementy i wnika w nie. Jeśli chce się utworzyć wiele nowych elementów, warto, aby program przez ten czas pozostał w tym trybie edycji, aby przetwarzanie było szybsze. Do tego celu istnieją funkcje "begin_modification" i "finish_modification". W przykładzie przed utworzeniem pierwszego węzła wywoływane jest "begin_modification", a na końcu, po utworzeniu przypadku obciążenia, "finish_modification". Funkcje te zostały również zaimplementowane jako funkcje VBA. Funkcje są samodzielne, dlatego wewnątrz funkcji ponownie tworzone są zmienne "request" i "response". Ponieważ jednak nie są potrzebne nowe elementy, tutaj nie jest to dalej omawiane. Interesujące jest porównanie z i bez użycia tych funkcji, co zawsze przyniesie różnicę w szybkości. == Podsumowanie == Webservice-API to potężne narzędzie dla RFEM i RSTAB. Prosta transmisja oparta na HTTP umożliwia implementację interfejsu w wielu językach programowania, nie tylko jak pokazano tutaj w VBA, i umożliwia programowanie międzyplatformowe.


Autor

Pan Günthel zapewnia wsparcie techniczne klientom firmy Dlubal Software i zajmuje się ich zapytaniami.

Odnośniki
Pobrane


;