Для работы с web-сервисами традиционно используется SoapUI от SmartBear Software. Отличный инструмент и к тому же бесплатный. Но… это инструмент разработчика, тестировщика, архитектора, но никак не ориентированный на работу конечного пользователя.
Как я уже писал, я не разработчик, а иногда мне надо получать данные из внутрикорпоративных и внешних источников, желательно не привлекая «тяжелую артиллерию», и чтобы результат можно было показать другому не-разработчику. Поэтому пришло время добавить в свои инструменты новый модуль, в котором будем обращаться к web-сервисам, полученные данные парсить и отображать в удобоваримом виде.
Чтобы обратиться к web-сервису существует огромное количество способов. В Python есть requests (статьи на Хабре 1, 2), но я буду использовать средства Qt, отчасти по привычке, отчасти для уменьшения зависимостей, так как PyQt5 уже подключен, отчасти для уменьшения промежуточных преобразований данных. Соответственно, для преобразования полученного xml-ответа использую XPath и XQuery, так же заложенные в Qt.
Подключаться будем к сервису курса валют Банка России. Сервис по ссылке отвечает таким XML:
<?xml version="1.0" encoding="windows-1251" ?>
<ValCurs Date="16.09.2017" name="Foreign Currency Market">
<Valute ID="R01010">
<NumCode>036</NumCode>
<CharCode>AUD</CharCode>
<Nominal>1</Nominal>
<Name>Австралийский доллар</Name>
<Value>46,0614</Value>
</Valute>
...
</ValCurs>
[Input]
; Показать на экране поле ввода даты
Date=Дата,02/03/2017
[WebPage]
; Ссылка на сервис с подставляемым параметром
Url="http://www.cbr.ru/scripts/XML_daily.asp?date_req={Date}"
; Шаблон, которым будет преобразовываться ответ
Transform=valcurs.xq
os.environ.putenv('QT_OPENGL','software') # desktop, software, angle
os.environ.putenv('QT_ANGLE_PLATFORM','warp') # d3d11, d3d9 and warp
QtWebEngineProcess.exe - Системная ошибка
---------------------------
Запуск программы невозможен, так как на компьютере отсутствует VCRUNTIME140.dll. Попробуйте переустановить программу.
# Создадим один раз менеджер
self.man = QNetworkAccessManager(self)
# Кнопка Run
def run(self):
try:
# Считаем введенные параметры
values = { kp[0]:self.inputs[kp[0]].text() for kp in self.params}
url = self.url.format(**values)
req = QNetworkRequest(QUrl(url))
# Вызовем GET
reply = self.man.get(req)
reply.finished.connect(self.replyFinished)
def replyFinished(self):
reply = self.sender()
xquery version "1.0" encoding "utf-8";
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
</head>
<body>
<div>Курсы ЦБ на {string(/ValCurs/@Date)}</div>
<table><tbody>
<tr>
<th>Код валюты</th>
<th>Код валюты</th>
<th>Номинал</th>
<th>Название</th>
<th>Курс</th>
</tr>
{for $i in /ValCurs/Valute
return (
<tr>
<td>{string($i/NumCode)}</td>
<td>{string($i/CharCode)}</td>
<td>{string($i/Nominal)}</td>
<td>{string($i/Name)}</td>
<td>{string($i/Value)}</td>
</tr>
)
}
</tbody></table>
</body>
</html>
# Создаем объект
lang = QXmlQuery.XQuery10
query = QXmlQuery(lang)
query.setMessageHandler(XmlQueryMessageHandler())
query.setFocus(reply)
# Начитываем шаблон из файла
templ = QFile(self.transformTemplate)
templ.open(QIODevice.ReadOnly)
query.setQuery(templ)
# Результат преобразуем в строку и вставим в веб-страницу
out = query.evaluateToString()
self.page.setHtml(out)
lang = QXmlQuery.XSLT20
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*" />
<xsl:output method="html" version="2.0" encoding="UTF-8" indent="no"/>
<xsl:template match="/">
<html>
<head>
<style type="text/css">
.node { font-weight: normal }
.nodeName { font-weight: normal }
.nodeLine { font-weight: bold }
</style>
</head>
<body>
<h2>Transformed XML</h2>
<xsl:apply-templates select="/*"/>
</body>
</html>
</xsl:template>
<xsl:template match="node()">
<xsl:param name="level" select="0"/>
<div>
<xsl:attribute name="style">
<xsl:value-of select="concat('margin-left: ',$level,'em')"/>
</xsl:attribute>
<span class="nodeLine"><<span class="nodeName"><xsl:value-of select="name(.)"/></span>
<xsl:for-each select="@*"><xsl:value-of select="concat(' ',name(.))"/>="<xsl:value-of select="."/>"</xsl:for-each>><xsl:value-of select="text()"/><xsl:apply-templates select="*"><xsl:with-param name="level" select="2"/></xsl:apply-templates><span class="node"></<span class="nodeName"><xsl:value-of select="name(.)"/></span>></span></span>
</div>
</xsl:template>
</xsl:stylesheet>
b = reply.readAll()
self.page.setContent(b, reply.header(QNetworkRequest.ContentTypeHeader), reply.url())
b = reply.readAll()
cth = reply.header(QNetworkRequest.ContentTypeHeader)
if len(cth.split(';')) == 1:
cth = cth + ";charset=windows-1251"
self.page.setContent(b,cth,reply.url())
К сожалению, не доступен сервер mySQL