최소한의 RSS 목록 애플리케이션

네트워크 리소스를 가져오고 표시하는 방법에 대한 데모입니다.

이 예에서는 사용자가 요청한 리소스를 가져오고 응답에 포함된 데이터를 표시하는 방법을 RSS 목록 애플리케이션으로 설명합니다. (RDF 사이트 요약 또는 정말 간단한 신디케이션은 웹 사이트에 업데이트를 전달하기 위한 표준 형식입니다. 자세한 내용은 https://www.rssboard.org/rss-specification 참조). 이 예에서는 네트워킹 사용 방법에 중점을 두었기 때문에 그림의 사용자 인터페이스는 간단하지만, 본격적인 RSS 리더라면 당연히 더 정교한 인터페이스가 필요할 것입니다.

이 예는 또한 수신되는 데이터의 비동기 구문 분석을 수행하여 멤버 변수에 상태를 보존함으로써 증분 구문 분석기가 네트워크를 통해 도착하는 데이터 청크를 소비할 수 있도록 하는 방법을 보여줍니다. 구문 분석된 콘텐츠의 구성 요소는 한 데이터 청크에서 시작하지만 이후 청크까지 완료되지 않을 수 있으므로 구문 분석기는 호출 간에 상태를 유지해야 합니다.

기본 프로그램은 매우 간단합니다. QApplication 위젯과 RSSListing 위젯을 인스턴스화하여 후자를 표시하고 전자에게 제어권을 넘겨주기만 하면 됩니다. 예를 들어, 위젯에 리소스 확인을 위한 기본값으로 Qt 블로그의 URL을 제공합니다.

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();
}

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;
};

위젯 자체는 가져올 URL을 지정하고 사용 가능한 업데이트가 표시되면 업데이트된 항목의 다운로드를 제어할 수 있는 간단한 사용자 인터페이스를 제공합니다. QLineEdit 을 통해 URL을 입력하고 QTreeWidget 을 통해 가져온 결과를 표시할 수 있습니다.

위젯은 비동기적으로 RSS(XML의 한 형태)를 다운로드하고 파싱하여 데이터가 도착하면 XML 리더에 데이터를 공급합니다. 따라서 매우 큰 데이터 소스를 읽을 수 있습니다. 데이터가 XML 리더를 통해 네트워크에서 스트리밍되므로 XML의 전체 텍스트를 메모리에 보관할 필요가 없습니다. 다른 맥락에서 유사한 접근 방식을 사용하면 사용자가 이러한 점진적 로딩을 중단할 수 있습니다.

구성
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);
}

생성자는 위젯의 여러 컴포넌트를 설정하고 다양한 신호를 처리하는 데 사용할 슬롯에 연결합니다.

사용자 인터페이스는 줄 편집, 푸시 버튼, 목록 보기 위젯으로 구성됩니다. 줄 편집은 가져올 URL을 입력하는 데 사용되며, 푸시 버튼은 업데이트를 가져오는 프로세스를 시작합니다. 줄 편집은 기본적으로 비어 있지만 main() 에서처럼 생성자의 호출자가 이를 재정의할 수 있습니다. 어떤 경우든 사용자는 기본값을 다른 RSS 피드의 URL로 바꿀 수 있습니다.

목록 보기에는 RSS 피드에 보고된 업데이트된 항목이 표시됩니다. 이 중 하나를 두 번 클릭하면 QDesktopServices::openUrl()를 사용하여 사용자의 브라우저나 다른 사용자 에이전트로 해당 URL이 전송됩니다.

슬롯
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::NetworkError){
    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); }

모든 슬롯은 어려운 작업을 프라이빗 메서드에 위임하여 단순하게 유지합니다.

사용자가 "가져오기" 버튼을 클릭하거나 줄 편집에서 리턴 키를 눌러 URL 입력을 완료하면 fetch() 슬롯은 "가져오기" 버튼을 비활성화하고 줄 편집의 추가 편집을 비활성화합니다. 사용 가능한 업데이트 표시를 지우고 get() 에 HTTP GET 요청 시작을 위임합니다.

데이터가 수신되면 네트워크 응답이 readyRead() 신호를 트리거하고 get()consumeData() 슬롯에 연결합니다. 그러면 응답에 상태 코드가 성공했는지 확인하고, 성공하면 parseXml() 을 호출하여 데이터를 소비합니다.

네트워크 응답에 오류가 발생하면 error() 슬롯으로 전달되어 오류를 보고하고 XML 스트림 리더를 지운 다음 응답과의 연결을 끊고 삭제합니다.

네트워크 응답이 완료되면(성공 여부와 관계없이) finished() 슬롯은 줄 편집 및 '가져오기' 버튼을 다시 활성화하여 새 URL을 가져올 준비가 되도록 UI를 복원합니다.

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.
}

비공개 get() 메서드는 fetch() 슬롯에서 HTTP GET 요청을 시작하는 데 사용됩니다. 먼저 XML 스트림 리더를 지우고 현재 응답이 활성화되어 있는 경우 연결을 끊고 삭제합니다. 전달된 URL이 유효하면 네트워크 액세스 관리자에게 GET을 요청합니다. 관련 슬롯을 결과 회신(있는 경우)의 신호에 연결하고 회신에서 데이터를 읽을 수 있도록 XML 스트림 리더를 설정합니다(네트워크 회신 개체는 QIODevice, 데이터를 읽을 수 있는 곳이기도 합니다).

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();

데이터가 수신되어 XML 스트림 리더가 사용할 수 있게 되면 parseXml() 은 XML 스트림에서 item 요소와 그 안에서 titlelink 요소를 확인하여 읽습니다. 트리 보기의 링크 열에서 itemrss:about 속성을 URL로 사용하며, link 요소의 콘텐츠가 없으면 트리 보기의 제목 열에서 title 요소의 콘텐츠를 사용합니다. 각 item 요소가 닫히면 트리 위젯에서 해당 세부 정보가 새 행으로 바뀌고 제목 및 링크 열에 추출된 제목과 URL이 표시됩니다.

구문 분석 상태를 추적하는 변수인 linkString, titleStringcurrentTagRSSListing 클래스의 멤버 변수로, 이 메서드에서만 액세스되지만 새 데이터가 도착하면 반복적으로 호출될 수 있고 수신된 데이터의 한 청크가 나중에 청크가 도착할 때까지 완료되지 않은 요소를 시작할 수 있기 때문에 이 메서드는 이 클래스의 멤버 변수입니다. 따라서 구문 분석기는 모든 데이터가 도착할 때까지 기다릴 필요 없이 데이터가 도착하는 대로 비동기적으로 작동할 수 있습니다.

예제 프로젝트 @ code.qt.io

QNetworkReplyQXmlStreamReader참조하세요 .

© 2025 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.