En esta página

Una aplicación mínima de listas RSS

Una demostración de cómo obtener y mostrar un recurso de la red.

Este ejemplo muestra cómo obtener un recurso que el usuario ha solicitado y mostrar los datos contenidos en la respuesta, ilustrados por una aplicación de listado RSS. (RDF Site Summary, o Really Simple Syndication, es un formato estándar para comunicar actualizaciones de sitios web. Para más detalles, consulte https://www.rssboard.org/rss-specification). La inferfaz de usuario de la ilustración es sencilla, ya que este ejemplo se centra en cómo utilizar la red, pero naturalmente se desearía una interfaz más sofisticada para un lector RSS serio.

El ejemplo también ilustra cómo realizar un análisis asíncrono de los datos a medida que se reciben, preservando el estado en las variables miembro para que un analizador incremental pueda consumir trozos de datos a medida que llegan a través de la red. Los componentes del contenido analizado pueden comenzar en un trozo de datos pero no completarse hasta un trozo posterior, lo que requiere que el analizador conserve el estado entre llamadas.

La aplicación obtiene información de la URL especificada, en este caso, Qt Blog, y a continuación analiza los datos XML disponibles

El programa principal es bastante sencillo. Se limita a instanciar QApplication y el widget RSSListing, muestra este último y cede el control al primero. A modo de ilustración, da al widget la URL del blog Qt como valor por defecto para el recurso a comprobar.

int main(int argc, char **argv)
{
    QApplication app(argc, argv);
    RSSListing rsslisting(u"https://www.qt.io/blog/rss.xml"_s);
    rsslisting.show();
    return app.exec();
}

La clase RSSListing

class RSSListing : public QWidget
{
    Q_OBJECT
public:
    explicit RSSListing(const QString &url = QString(), QWidget *widget = nullptr);

public slots:
    void fetch();
    void finished(QNetworkReply *reply);
    void consumeData();
    void error(QNetworkReply::NetworkError);

private:
    void parseXml();
    void get(const QUrl &url);

    // Parser state:
    QXmlStreamReader xml;
    QString currentTag;
    QString linkString;
    QString titleString;

    // Network state:
    QNetworkAccessManager manager;
    QNetworkReply *currentReply;

    // UI elements:
    QLineEdit *lineEdit;
    QTreeWidget *treeWidget;
    QPushButton *fetchButton;
};

El propio widget proporciona una interfaz de usuario sencilla para especificar la URL que se desea obtener y, una vez que se muestran las actualizaciones disponibles, controlar la descarga de los elementos actualizados. En QLineEdit se introduce la URL y en QTreeWidget se muestran los resultados una vez obtenidos.

El widget descarga y analiza el RSS (una forma de XML) de forma asíncrona, transmitiendo los datos a un lector XML a medida que llegan. Esto permite leer fuentes de datos muy grandes. Como los datos se transmiten desde la red a través del lector XML, no es necesario conservar el texto completo del XML en la memoria. En otro contexto, un enfoque similar puede permitir al usuario interrumpir esa carga incremental.

Construcción
RSSListing::RSSListing(const QString &url, QWidget *parent)
    : QWidget(parent), currentReply(0)
{
    connect(&manager, &QNetworkAccessManager::finished, this, &RSSListing::finished);

    lineEdit = new QLineEdit(this);
    lineEdit->setText(url);
    connect(lineEdit, &QLineEdit::returnPressed, this, &RSSListing::fetch);

    fetchButton = new QPushButton(tr("Fetch"), this);
    connect(fetchButton, &QPushButton::clicked, this, &RSSListing::fetch);

    treeWidget = new QTreeWidget(this);
    connect(treeWidget, &QTreeWidget::itemActivated,
            // Open the link in the browser:
            this, [](QTreeWidgetItem *item) { QDesktopServices::openUrl(QUrl(item->text(1))); });
    treeWidget->setHeaderLabels(QStringList { tr("Title"), tr("Link") });
    treeWidget->header()->setSectionResizeMode(QHeaderView::ResizeToContents);

    QHBoxLayout *hboxLayout = new QHBoxLayout;
    hboxLayout->addWidget(lineEdit);
    hboxLayout->addWidget(fetchButton);

    QVBoxLayout *layout = new QVBoxLayout(this);
    layout->addLayout(hboxLayout);
    layout->addWidget(treeWidget);

    setWindowTitle(tr("RSS listing example"));
    resize(640, 480);
}

El constructor configura los distintos componentes del widget y conecta sus distintas señales a las ranuras que utilizará para manejarlas.

La interfaz de usuario consiste en un widget de edición de línea, un botón pulsador y una vista de lista. El editor de línea se utiliza para introducir la URL que se desea obtener; el botón pulsador inicia el proceso de obtención de actualizaciones. La línea de edición está vacía por defecto, pero el constructor puede anularla, como ha hecho nuestro main(). En cualquier caso, el usuario puede sustituir el valor por defecto por la URL de otro canal RSS.

La vista de lista muestra los elementos actualizados de los que se informa en el canal RSS. Al hacer doble clic en uno de ellos, se envía su URL al navegador del usuario o a otro agente de usuario mediante QDesktopServices::openUrl().

Las ranuras
void RSSListing::fetch() {  lineEdit->setReadOnly(true);  fetchButton->setEnabled(false);  treeWidget->clear(); get(QUrl(lineEdit->text())); }void RSSListing::consumeData() { int statusCode =  currentReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); if (statusCode >= 200 && statusCode < 300) parseXml(); }void RSSListing::error(QNetworkReply::ErrorDeRed){
    qWarning("error retrieving RSS feed");
    xml.clear();  currentReply->disconnect(this);  currentReply->deleteLater(); currentReply = nullptr; }void RSSListing::finished(QNetworkReply *reply) { Q_UNUSED(reply);  lineEdit->setReadOnly(false);  fetchButton->setEnabled(true); }

Todos los slots se mantienen simples delegando cualquier trabajo duro a métodos privados.

Cuando el usuario completa la entrada de una URL, ya sea haciendo clic en el botón "Fetch" o pulsando la tecla de retorno en la línea de edición, la ranura fetch() desactiva el botón "Fetch" y desactiva la edición posterior de la línea de edición. Borra la pantalla de actualizaciones disponibles y delega en get() el inicio de una petición HTTP GET.

Cuando se reciben los datos, la respuesta de la red activa su señal readyRead(), que get() conecta a la ranura consumeData(). Éste comprueba si la respuesta obtuvo un código de estado correcto y, en caso afirmativo, llama a parseXml() para consumir los datos.

Si la respuesta de red obtiene un error, éste se envía a la ranura error(), que informa del error, borra el lector de flujo XML y, a continuación, se desconecta de la respuesta y la borra.

Cuando finaliza (con éxito o no) una respuesta de red, el espacio finished() restaura la interfaz de usuario para que esté lista para aceptar una nueva URL que recuperar, volviendo a activar la edición de línea y el botón "Recuperar".

El método get()
void RSSListing::get(const QUrl &url)
{
    if (currentReply) {
        currentReply->disconnect(this);
        currentReply->deleteLater();
    }
    currentReply = url.isValid() ? manager.get(QNetworkRequest(url)) : nullptr;
    if (currentReply) {
        connect(currentReply, &QNetworkReply::readyRead, this, &RSSListing::consumeData);
        connect(currentReply, &QNetworkReply::errorOccurred, this, &RSSListing::error);

    }
    xml.setDevice(currentReply); // Equivalent to clear() if currentReply is null.
}

El método privado get() es utilizado por la ranura fetch() para iniciar una petición HTTP GET. Primero limpia el lector de flujo XML y, si hay una respuesta activa, la desconecta y la borra. Si la URL que se le ha pasado es válida, pide al gestor de acceso a la red que la GET. Conecta sus ranuras pertinentes a las señales de la respuesta resultante (si la hay) y configura su lector de flujo XML para leer datos de la respuesta - un objeto de respuesta de red es también un QIODevice, del que se pueden leer datos.

El método parseXml()
void RSSListing::parseXml() { while (!xml.atEnd()) { xml.readNext(); if (xml.isStartElement()) { if (xml.name() == u"item") { linkString = xml.attributes().value("rss:about").toString(); titleString.clear(); } currentTag = xml.name().toString(); } else if (xml.isEndElement()) { if (xml.name() == u"item") { QTreeWidgetItem * item = new QTreeWidgetItemitem->setText(0, titleString);  item->setText(1, linkString);  treeWidget->addTopLevelItem(item); } } else if (xml.isCharacters() && !xml.isWhitespace()) { if (currentTag == "title") titleString += xml.text(); else if (currentTag == "link") linkString += xml.text(); } } if (xml.error() && xml.error()! = QXmlStreamReader::PrematureEndOfDocumentError)        qWarning() << "XML ERROR:" << xml.lineNumber() << ": " << xml.errorString();
}

Cuando se reciben los datos, y por tanto se ponen a disposición del lector del flujo XML, parseXml() lee del flujo XML, comprobando si hay elementos item y, dentro de ellos, elementos title y link. Utilizará el atributo rss:about de un item como URL en la columna Enlace de la vista en árbol, en su defecto el contenido de su elemento link; y utiliza el contenido del elemento title en la columna Título de la vista en árbol. A medida que se cierra cada elemento item, sus detalles se convierten en una nueva fila en el widget de árbol, con el título y la URL extraídos en las columnas Título y Enlace.

Las variables que llevan la cuenta del estado del análisis - linkString, titleString y currentTag - son variables miembro de la clase RSSListing, aunque sólo se accede a ellas desde este método, porque este método puede ser llamado repetidamente, a medida que llegan nuevos datos, y un trozo de datos recibidos puede iniciar un elemento que no se completa hasta que llega un trozo posterior. Esto permite al analizador operar de forma asíncrona a medida que llegan los datos, en lugar de tener que esperar hasta que todos los datos hayan llegado.

Proyecto de ejemplo @ code.qt.io

Véase también QNetworkReply y QXmlStreamReader.

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.