Главная > Qt > Парсинг XML через HTTP на C++ с помощью Qt

Парсинг XML через HTTP на C++ с помощью Qt

Не стоит пугаться столь сложного заголовка статьи, состоящего из одних терминов. Задача чтения XML документов по протоколу HTTP встречается довольно часто. Решение, приведенное в данной статье можно использовать при написании ПО, которое активно работает с любым веб-сервисом. Например, такая программа может проводить авторизацию по логину и паролю в веб-сервисе, получение новостей в отдельном окне, возможность оставлять комментарии к записям и т.д..

Но хватит слов, приступим к реализации.

Реализация

Первое что нам понадобится - это подготовить данные к отправке методом POST. Для этого воспользуемся классом QUrl и методом addQueryItem, который формирует запрос по названии параметра и его значении.

QUrl params;
 
params.addQueryItem("e", "dowhile@dowhile.ru");
params.addQueryItem("p", "password");

Однако данные нам нужно подготовить в формате QByteArray (этого требует метод post класса QNetworkAccessManager). Ничего страшно, переведем переменную params в строку с помощью метода toString. Однако нужно будет еще удалить первый символ, так как этот метод вернет нам строку запроса для отправки методом GET, т. е. вначале будет идти символ "?". В методе POST нам этот символ не нужен.

QByteArray data;
 
data.append(params.toString());
data.remove(0, 1);

Для отправки запроса на веб-сервис нам понадобится класс QNetworkAccessManager. С помощью него мы сможем отправлять запросы по HTTP и принимать ответы. Для работы с ним создадим в коде функцию serverRequest().

void serverRequest(QByteArray param)
{
 
}

Не забываем прописать требуемые строчки в заголовочном файле. Для экономии места я на него ссылаться не буду.

После того, как функция создана, необходимо ее вызвать из нашего основного кода, передав соответствующие аргументы.

serverRequest(data);

Теперь в этой функции нам нужно создать объекты классов QNetworkAccessManager и QNetworkRequest.

QNetworkAccessManager *manager = new QNetworkAccessManager(this);
QNetworkRequest request;

Сразу же после объявления объектов необходимо озаботиться о получении ответа. В этом нам поможет сигнал finished, который испускает объект класса QNetworkAccessManager после окончания приема данных, и слот slotServerReply, который мы создадим позже. QNetworkReply, который передается вместе сигнала к слоту - это класс, который содержит в себе ответ и информацию о запросе.

connect(manager, SIGNAL(finished(QNetworkReply*)), this,
    SLOT(slotReply(QNetworkReply*)));

Теперь нужно подготовить запрос на сервер. С помощью метода setUrl устанавливаем адрес для нашего запроса, с помощью setHeader - тип передаваемого контента, с помощью setRawHeader - произвольный (в данном случае User-Agent) элемент в заголовке. Не забудьте вместо domain.ru подставить свой домен, на котором будете производить тест, а вместо api/test_request - адрес к api веб-сервиса.

request.setUrl(QUrl("http://domain.ru/api/test_request"));
request.setHeader(QNetworkRequest::ContentTypeHeader,
    "application/x-www-form-urlencoded");
request.setRawHeader("User-Agent", "XMLParser 0.1");

Ниже мы делаем непосредственно сам запрос, передавая параметры методом POST. Параметры в формате QByteArray получаем в виде аргумента в нашей функции serverRequest.

manager->post(request, param);

После выполнения приведенной выше команды, нашей программе останется только ожидать сигнала finished, который указывает на завершение запроса. За обработку этого сигнала у нас отвечает слот slotServerReply. Им мы сейчас и займемся.

void slotReply(QNetworkReply *reply)
{
 
}

В этом слоте мы прочитаем все данные из объекта класса QNetworkReply в строковую переменную replyString. Поскольку ответы от сервера вряд ли будут большими, то для чтения будет используем функцию readAll.

QString replyString;
replyString = reply->readAll();

Далее остается только обработать пришедший сигнал. Для этого создадим отдельную функцию serverReplyParse.

void serverReplyParse(QString reply)
{
 
}

Чтобы попасть в эту функцию после чтения ответа сервера, в слоте slotServerReply нужно вызвать функцию serverReplyParse.

serverReplyParse(replyString);

В функции serverReplyParse создадим объект QDomDocument. Это позволит нам полностью считывать в память XML данные и без всяких проблем обращаться к ним.

QDomDocument xmlDoc;

С помощью метода setContent класса QDomDocument, загрузим наши XML данные.

xmlDoc.setContent(reply);

Чтобы прочесть данные по тегу, достаточно воспользоваться методом elementsByTagName, который возвращает список элементов, относящихся к этому тегу. После этого из списка выбираем нужный элемент и переводим его в XML элемент с помощью метода toElement, из которого считываем данные с помощью метода text. Все станет понятней после приведенного ниже примера:

int userId = 0;
 
if(xmlDoc.elementsByTagName("userId").count() > 0)
    userId = xmlDoc.elementsByTagName("userId").at(0).toElement().text().toInt();

Пример очень простой. Сначала мы создаем численную переменную целого типа и сразу приравниваем ее к нулю. Затем проверяем с помощью метода count количество элементов под тегом userId в полученном XML документе. Если количество элементов больше ноля (т. е. существует хотя бы один такой элемент), то мы заносим в переменную userId первое (под индексом 0) число, которое хранится под этим тегом в списке.

Categories: Qt Tags: , ,
  1. Пока что нет комментариев.
  1. Пока что нет уведомлений.