5559x
001738
2022-03-23

Учебное пособие веб-службы API в VBA

Веб-сервис - это связь между оборудованием или программами. Эта связь обеспечивается через сеть и, следовательно, может использоваться любой программой, которая может отправлять и получать строки по протоколу HTTP. Программы RFEM 6 и RSTAB 9 предоставляют интерфейс, основанный на этих кросс-платформенных веб-сервисах. В данном учебном пособии показаны основы использования языка программирования VBA.

Основы API веб-сервисов на примере VBA

Для форматирования строки используется формат XML в соответствии со спецификациями протокола SOAP. Примером может служить следующий запрос:

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

Типичный элемент форматирования XML - это начало раздела с символа «<». Затем следует идентификатор, и, если больше нет подчиненных элементов, раздел заканчивается знаком «/>». Примером может служить третья строка:

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

Если присутствуют субэлементы, то они начинаются с «<», команды и «>», а заканчиваются «</», командой и «>». Подходящим примером является раздел «Body»:

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

Форматирование с помощью пробелов и разрывов строк применено исключительно для наглядности. Этого не требуется для передачи. Элементы «Body» и «Envelope» являются стандартными элементами для передачи и используются для каждой команды.

Все доступные команды можно считать с помощью интерфейса WSDL. Существуют программы, которые можно применить для создания списков. Одной из таких программ является SoapUI. Для API программы RFEM 6 имеются два списка; команды для приложения и для модели. Оба списка можно скачать в конце данной статьи.

Поскольку команды передаются по протоколу HTTP, для адресации требуются URL-адреса. Адрес приложений RSTAB/RFEM по умолчанию - «http://localhost: 8081/», его можно изменить в настройках программы. Открытым моделям присваиваются адреса в порядке возрастания, таким образом, первая открытая модель имеет адрес «http://localhost: 8082/». Для получения адреса активной модели отправляется команда «get_active_model». Соответствующий ответ от RFEM 6 выглядит следующим образом:

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

Дополнительные данные раздела «Envelope», а также предыдущая строка "<?xml version="1.0"?>" сначала должны указать используемые нормы, и они не будут обсуждаться далее. В любом случае, мы видим, что элементы «Envelope» и «Body» применяются снова. В «Body» содержится ответ RFEM 6 через команду «get_active_model» и добавленное слово «Response». Содержание этого ответа - это значение "value", а именно адрес активной модели. Кроме того, теперь программа RFEM заблокирована от дальнейшего доступа.

В последующем примере создадим стержень с двумя узловыми опорами и нагрузкой. Для связи с RFEM через VBA требуются следующие объекты:

request As MSXML2.XMLHTTP60
response As MSXML2.DOMDocument

Объект XMLHTTP60 имеет встроенную функцию для отправки HTTP-запроса на URL-адрес и поэтому используется для запроса. Затем можно оценить ответ с помощью DOMDocument. Следующий пример объединяет ранее показанный запрос «get_active_model» с командами, используемыми в 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)

Сначала запрос сохраняется в формате XML в переменной «str_envelope», запрос открывается в RFEM с помощью метода «Open» переменной «request». Содержание переменной «str_envelope» теперь можно отправить с помощью метода «Send». К ответу затем можно получить доступ с помощью метода «ResponseText». В данном конкретном случае он импортируется напрямую с помощью метода «LoadXML» переменной «response».

Переменная «response» с типом DOMDocuments содержит метод LoadXML и, таким образом, может распознавать форматирование XML. Преимущество заключается в том, что тип DOMDocuments также предоставляет метод GetElementsByTagName. Это позволяет извлекать элементы прямо из кода. Далее предыдущий код будет расширен так, чтобы был доступен URL-адрес модели:

'   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

Перед считыванием URL-адреса можно проверить статус ответа. Это стандартизированные коды состояния HTTP. Статус «200» означает, что передача выполнена успешно. После этого запроса URL-адрес модели сохраняется в строке url_model. Для этого в XML-ответе производится поиск элемента "value". Если ответ содержит несколько элементов, то все значения сохраняются в разделе «value», поэтому оценка с идентификатором «value» невозможна, а адресуются подэлементы «value». Представим это более подробно на практическом примере. В случае с адресом модели, единственным возвращаемым значением является URL-адрес, поэтому «value» здесь применяется успешно.

Практический пример в VBA

Теперь, когда мы знаем все основные элементы, рассмотрим простой пример. Необходимо создать балку на двух колоннах, к которой можно приложить нагрузку на стержень.

Сначала задаются и инициализируются описанные выше переменные:

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

В дополнение к переменным «request» и «response», создается строка «str_envelope» для запроса, а также «url_app» и «url_model» для адресов приложения и модели. Во время инициализации можно выполнить переду известных спецификаций протокола SOAP для оценки XML форматирования ответа. Адрес модели будет считан позже, но указать адрес приложения необходимо. Как уже упоминалось, необходимо ввести адрес по умолчанию «http://localhost:8081/».

Следующим шагом будет проверка связи с приложением. Для этого теста стандартная информация приложения запрашивается с помощью команды «get_information»:

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

Как уже было упомянуто в первой части, сначала подготавливается запрос в формате XML  и сохраняется в «str_envelope». «request.Open» открывает соединение с приложением. Ключевое слово «Post» означает отправку запроса. Третий параметр устанавливается на «true», и таким образом выполняется синхронная передача. Наконец, «request.Send» отправит подготовленную строку.

После передачи ответ сохраняется в «response» и проверяется с помощью «request.Status» на предмет того, был ли запрос успешным. Статус присваивается программой RFEM так, что она возвращает ошибку в случае неправильного запроса, например, неизвестная команда. Если нет статуса «200», программа прерывается и ошибка отображается в окне (MsgBox).

Если ошибок нет, то теперь можно считать различную переданную информацию с помощью GetElementsByTagName. В конкретном примере информация затем отображается в окне.

Следующие элементы очень похожи, поэтому упомянем только специальные функции (полный исходный код можно скачать). Чтобы создать балку на двух колоннах с нагрузкой на стержень, требуются следующие функции:

  1. Узел - set_node
  2. Линия - set_line
  3. Материал - set_material
  4. Сечение - set_section
  5. Стержень - set_member
  6. Узловая опора - set_nodal_support
  7. Параметры расчета - set_static_analysis_settings
  8. Загружение - set_load_case
  9. Нагрузка на стержень - set_member_load

Как и большинство других функций, опция «set_node» имеет множество параметров, но обычно их ввод не требуется. В упомянутом списке команд модели в RFEM вы можете просмотреть все параметры. Прежде всего значение имеют параметры, которые не отмечены как «выборочные», поскольку они должны быть заданы в любом случае. В данном примере передаются следующие параметры:

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

Только номер узла не является выборочным, остальные параметры можно задать, но это не обязательно. В дополнение к возможным параметрам в списке команд также отображаются списки типов. В данном конкретном случае в данное время возможны пять различных типов. Выбран тип по умолчанию «TYPE_STANDARD». Первый показанный здесь узел создается в точке (0; 0; 0), второй узел в (5,5; 0; 0). Значения десятичных чисел следующие:

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

Еще одной особенностью являются списки. Для линии требуются два узла, номера которых можно передать в виде списка. Элементы списка, такие как «definition_nodes», разделяются пробелами:

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

Чтобы создать стержень, необходимо создать сечение, для которого, в свою очередь, требуется ввод материала. Можно применить сечения и материалы из внутренней базы данных. Поэтому достаточно указать известный идентификатор. Для материала используется идентификатор «S235», а для сечения «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>" & _
...

Для того, чтобы проверить, действителен ли идентификатор «IPE 300», можно использовать ввод в графическом интерфейсе пользователя.

Чтобы задать сам стержень, никакой дополнительной информации не требуется, но чтобы задать неподвижную опору, необходимо задать «бесконечную» жесткость пружины. Для передачи используется ключевое слово «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>" & _
...

Ввод загружения и параметров расчета не требует дополнительной информации. Последняя особенность - это дополнительная величина при создании нагрузки, поскольку она должна быть указана вне области «<value>». В случае нагрузки на стержень, необходимо передать соответствующее загружение:

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

Кроме того, следует отметить, что порядок элементов в области «value» не имеет значения, а за ее пределами имеет. Таким образом, заданное загружение должно быть перед областью «value».

В дополнение к предыдущим функциям для создания и экспорта данных, здесь мы представим две специальные функции. Если в программу передаются элементы, она автоматически переходит в режим «Modification». Программа проверяет новые элементы и интегрирует их. Поэтому, если необходимо создать несколько новых элементов, лучше оставить программу в этом режиме редактирования на данное время, чтобы обработка проходила быстрее. Для этого существуют функции «begin_modification» и «finish_modification». В нашем примере «begin_modification» вызывается перед созданием первого узла, а «finish_modification» вызывается в конце после создания загружения. Обе функции были созданы в программе в качестве функций VBA. Функции независимы, поэтому в рамках функций снова создаются переменные «request» и «response». Поскольку для этого не требуется никаких новых элементов, мы не будем их описывать более подробно. Интересным является сравнение скорости с применением этих функций и без них, которое показывает значительное различие.

Заключение

Веб-служба API - это мощный инструмент для RFEM и RSTAB. Простая передача на основе HTTP позволяет реализовать интерфейс в многих языках программирования, не только в VBA, как было показано здесь, поэтому возможно кросс-платформенное программирование.


Автор

Г-н Гюнтель осуществляет техническую поддержку пользователей Dlubal Software.

Ссылки
Скачивания