Základy API webové služby na příkladu VBA
Pro formátování řetězce znaků se používá formát XML podle pravidel protokolu SOAP. Jako příklad slouží následující dotaz:
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
<Body>
<get_active_model xmlns="http://www.dlubal.com/rfem.xsd"/>
</Body>
</Envelope>
Typickým prvkem formátování XML je začátek odstavce znakem "<". Za ním následuje identifikátor a, pokud nenásledují vnořené elementy, se odstavec zakončí znakem "/>". Příkladem je třetí řádek:
<get_active_model xmlns="http://www.dlubal.com/rfem.xsd"/>
Pokud existují vnořené prvky, začíná se znakem "<", následuje příkaz a ">" a na konci je "</", příkaz a ">". Vhodným příkladem je odstavec "Body":
<Body>
<get_active_model xmlns="http://www.dlubal.com/rfem.xsd"/>
</Body>
Formátování pomocí mezer a zalomení řádků slouží pouze přehlednosti. Pro přenos není nutné. Prvky "Body" a "Envelope" jsou standardní prvky pro přenos a používají se pro každý příkaz.
Všechny dostupné příkazy lze načíst pomocí rozhraní WSDL. Existují programy, pomocí kterých lze vytvářet seznamy. Jedním z takových programů je například SoapUI. Pro API programu RFEM 6 existují dva seznamy, příkazy pro aplikaci a pro model. Oba seznamy jsou k dispozici ke stažení na konci tohoto článku.
Neboť se příkazy odesílají prostřednictvím protokolu HTTP, jsou pro doručení vyžadovány URL adresy. Přednastavená adresa aplikací RSTAB/RFEM je "http://localhost: 8081/" a lze ji změnit v nastavení programu. Otevřeným modelům jsou přiřazeny adresy ve vzestupném pořadí, takže první otevřený model má adresu "http://localhost: 8082/". Pro získání adresy aktivního modelu se odešle příkaz "get_active_model". Odpověď z programu RFEM 6 vypadá následovně:
<?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>
Další podrobnosti odstavce "Envelope" (česky: obálka) a předchozí řádek "<?xml version="1.0"?>" mají na začátku uvést použité standardy a nebudeme se jimi zde dále zabývat. V každém případě je vidět, že se znovu použijí elementy "Envelope" a "Body". V "Body" je obsažena odpověď programu RFEM 6 pomocí příkazu "get_active_model" a připojeným slovem "Response". Obsahem této odpovědi je hodnota ("value"), a to adresa aktivního modelu. Kromě toho je program RFEM nyní uzamčen pro další přístup.
V následujícím příkladu vytvoříme prut se dvěma uzlovými podporami a zatížením. Aby bylo možné komunikovat s programem RFEM přes VBA, jsou zapotřebí následující objekty:
request As MSXML2.XMLHTTP60
response As MSXML2.DOMDocument
Objekt XMLHTTP60 má integrovanou funkci pro odeslání požadavku HTTP na adresu URL, a proto se používá pro požadavek. Odpověď může být pak vyhodnocena pomocí DOMDocuments. Následující příklad kombinuje dříve zobrazený požadavek "get_active_model" s příkazy používanými ve 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)
Nejdříve se požadavek uloží ve formátu XML do proměnné "str_envelope" a metodou "Open" proměnné "request" se požadavek na program RFEM otevře. Obsah proměnné "str_envelope" lze nyní odeslat pomocí metody "Send". K odpovědi je pak možné přistupovat pomocí metody "ResponseText". V tomto konkrétním případě se importuje přímo pomocí metody "LoadXML" proměnné "response".
Proměnná "response" typu DOMDocuments má metodu LoadXML a může tak rozeznat formátování XML. Výhodou je, že typ DOMDocuments poskytuje také metodu GetElementsByTagName. To umožňuje přímo extrahovat prvky z kódu. V následujícím textu předchozí kód rozšíříme tak, aby byla k dispozici URL adresa modelu:
' 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
Před načtením URL adresy je možné zkontrolovat stav odpovědi. Jedná se o standardizované stavové kódy HTTP. Stav "200" znamená, že přenos proběhl v pořádku. Po tomto dotazu se URL adresa modelu uloží do řetězce url_model. Za tímto účelem se v odpovědi XML hledá element "value". Pokud odpověď obsahuje několik elementů, jsou všechny hodnoty uloženy v odstavci "value", takže není možné vyhodnocení pomocí identifikátoru "value", ale dotazujeme vnořené elementy "value". Více ukážeme na praktickém příkladu. V případě adresy modelu je jedinou vrácenou hodnotou URL, takže "value" je zde úspěšná.
Praktický příklad ve VBA
Nyní, když známe všechny základní elementy, následuje jednoduchý příklad. Na dvou sloupech chceme vytvořit nosník, na který bude působit zatížení na prut.
Nejdříve definujeme a inicializujeme výše popsané proměnné:
' 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/"
Kromě proměnných „request“ a „response“ se vytvoří řetězec "str_envelope" pro požadavek a "url_app" a "url_model" pro adresy aplikace a modelu. Během inicializace lze přenést známá pravidla protokolu SOAP pro vyhodnocení formátování odpovědi XML. Adresa modelu se načte později, ale je třeba zadat adresu aplikace. Jak jsme již zmínili, je třeba zadat přednastavenou adresu "http://localhost:8081/".
Dalším krokem je otestování připojení k aplikaci. Pro otestování se dotazujeme na standardní informace aplikace pomocí příkazu "get_information":
' check application url with command "get_information"
str_envelope = "<Envelope xmlns=""http://schemas.xmlsoap.org/soap/envelope/"">" & _
" " & _
"</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 jsme již zmínili v první části, nejdříve se připraví požadavek ve formátu XML a uloží se v souboru "str_envelope". "request.Open" otevře připojení k aplikaci. Klíčové slovo "Post" slouží pro odeslání požadavku. Třetí parametr se nastaví na "true" a tím proběhne synchronní přenos. Na závěr "request.Send" odešle připravený řetězec.
Po přenosu se odpověď uloží do "response" a pomocí "request.Status" se ověří, zda byl požadavek úspěšný. Status je přitom přiřazen programem RFEM, takže ten v případě neúspěšného požadavku, například neznámého příkazu, vrátí chybu. Pokud stav není "200", program se přeruší a chyba se zobrazí v okně (MsgBox).
Pokud nedošlo k žádným chybám, lze nyní načíst různé přenesené informace pomocí "GetElementsByTagName". V konkrétním příkladu se pak informace zobrazí v okně.
Následující elementy jsou si velmi podobné, proto upozorníme pouze na zvláštnosti (kompletní zdrojový kód je k dispozici ke stažení). Pro vytvoření nosníku na dvou sloupech se zatížením na prut jsou zapotřebí následující funkce:
- Knoten – set_node
- Linie – set_line
- Material – set_material
- Querschnitt – set_section
- Stab – set_member
- Knotenlager – set_nodal_support
- Berechnungsparameter – set_static_analysis_settings
- Lastfall – set_load_case
- Stablast – set_member_load
Stejně jako většina ostatních funkcí má funkce "set_node" mnoho parametrů, které ovšem obvykle nejsou vyžadovány. V již zmíněném seznamu příkazů pro RFEM-model je vidět rozmanitost parametrů. Důležité jsou především parametry, které nejsou označeny jako "volitelné", protože ty je třeba v každém případě vyplnit. V našem příkladu se předávají následující parametry:
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>"
Pouze číslo uzlu není volitelné a zbytek lze zadat. Seznam příkazů obsahuje kromě možných parametrů také seznamy typů. V tomto konkrétním případě je v současnosti k dispozici pět různých typů. Zvolen byl standardní typ "TYPE_STANDARD". První zde zobrazený uzel se vytvoří v místě (0; 0; 0), druhý uzel v (5.5; 0; 0). Hodnoty desetinných čísel vypadají následovně:
...
"<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>" & _
...
Další zvláštnost představují seznamy. Linie potřebuje dva uzly, jejichž čísla lze přenést jako seznam. Prvky seznamu, jako například "definition_nodes", se oddělují mezerami:
...
"<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>" & _
...
Aby mohl být prut vytvořen, musí být ještě vytvořen průřez, který zase potřebuje mít zadaný materiál. Průřezy a materiály lze použít z interní databáze. Proto stačí zadat známý identifikátor. Pro materiál je identifikátor "S235" a průřez má název "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>" & _
...
Chcete-li zkontrolovat, zda je název jako "IPE 300" platný, můžete provést zadání v grafickém uživatelském prostředí.
Pro zadání samotného prutu nejsou zapotřebí žádné další informace, pro zadání pevné podpory je ovšem třeba zadat „nekonečnou“ tuhost. Pro přenos se používá klíčové slovo "INF":
...
"<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>" & _
...
Vytvoření zatěžovacího stavu a parametrů pro výpočet nevyžaduje žádné další informace. Poslední zvláštnost představuje další hodnota při vytváření zatížení, protože musí být zadána mimo oblast "<value>". V případě zatížení na prut je třeba příslušný zatěžovací stav umístit:
...
"<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>" & _
...
Pořadí prvků v oblasti "value" není důležité, mimo ni ale ano. Zadaný zatěžovací stav proto musí být předřazen oblasti "value".
Kromě dosavadních funkcí pro vytváření a načítání dat zde ještě představíme dvě speciální funkce. Pokud jsou prvky přeneseny do programu, program se automaticky přepne do režimu "Modification", tj. do režimu úprav. Program nové prvky zkontroluje a integruje. Pokud se má vytvořit více nových prvků, je vhodné ponechat program na tuto dobu v režimu úprav, aby bylo zpracování rychlejší. Pro tento účel jsou k dispozici funkce "begin_modification" a "finish_modification".
V našem příkladu před vytvořením prvního uzlu zavoláme "begin_modification" a na konci po vytvoření zatěžovacího stavu zavoláme "finish_modification". Obě funkce byly také v programu vytvořeny jako VBA funkce. Funkce jsou na sobě nezávislé, a proto se v rámci funkcí opět vytvoří proměnné "request" und "response". Nicméně vzhledem k tomu, že pro ně nejsou zapotřebí žádné nové elementy, nebudeme je zde dále popisovat. Zajímavé je srovnání rychlosti s těmito funkcemi a bez nich, jehož výsledkem je vždy znatelný rozdíl.
Závěr a výhled
Webová služba API je výkonný nástroj pro RFEM a RSTAB. Jednoduchý přenos pomocí protokolu HTTP umožňuje implementovat rozhraní v mnoha programovacích jazycích, nejen ve zde představeném VBA, a umožňuje programování napříč platformami.