「Qtの基礎 - HTML」の版間の差分

提供: MochiuWiki : SUSE, EC, PCB

📢 Webサイト閉鎖と移転のお知らせ
このWebサイトは2026年9月に閉鎖いたします。
新しい記事は移転先で追加しております。(旧サイトでは記事を追加しておりません)

192行目: 192行目:
  }
  }
  </syntaxhighlight>
  </syntaxhighlight>
<br>
<code>LIBXML_TEST_VERSION</code>マクロは、libxml2ライブラリを使用する場合に、ライブラリのバージョンが使用者のプログラムが期待するものと一致していることを保証するために用いられる。<br>
このマクロは、libxml2のヘッダファイルをインクルードした後に呼び出すことにより、プログラムがリンクされるlibxml2ライブラリのバージョンがヘッダファイルで定義されているバージョンと互換性があるかどうかを確認する。<br>
もし互換性が無ければ、実行時にエラーが発生する。<br>
<br>
<code>LIBXML_TEST_VERSION</code>マクロを使用する主な理由は、APIの非互換性による問題を防ぐことである。<br>
libxml2ライブラリは頻繁に更新されるため、新しいバージョンのライブラリには古いバージョンのコードとは互換性のない新機能や変更が含まれることがある。<br>
<code>LIBXML_TEST_VERSION</code>マクロを使用することにより、開発中にこの種の問題を早期に検出して対処することができる。<br>
<br>
したがって、<code>LIBXML_TEST_VERSION</code>マクロの記述は必須ではないが、<br>
ライブラリのバージョンに依存する可能性のあるプログラムを開発している場合、特にライブラリの更新によって互換性の問題が生じる可能性がある場合には、このマクロを使用することを推奨する。<br>
<br>
これにより、将来的な互換性の問題を防ぐことができ、より安定したソフトウェアの開発が可能になる。<br>
<br><br>
<br><br>



2024年3月22日 (金) 23:35時点における版

概要

Qtでは、HTMLを詳細にパースするライブラリが存在しないため、外部ライブラリを使用する必要がある。

HTMLがパースできるライブラリを、以下に示す。

  • libxml2
    概要
    libxml2は、XML文書を解析し、XPathクエリを実行するための非常に人気があるC言語ライブラリである。
    C++からも使用可能である。

    XPathサポート
    XPath 1.0をサポートしている。

  • TinyXML-2
    概要
    軽量で簡単に使用できるC++のXML解析ライブラリである。
    XPathの直接的なサポートは無いが、XMLノードを簡単に走査して目的のデータを見つけるための機能がある。

    XPathサポート
    直接的なXPathサポートは無いが、独自の検索関数を記述することで類似の機能を実現できる。

  • PugiXML
    概要
    軽量かつ高速なXML解析ライブラリで、C++で開発されている。

    XPathサポート
    XPath 1.0をフルサポートしており、HTMLやXMLファイルからのデータ抽出に適している。

  • Xerces-C++
    概要
    Apache Software Foundationにより開発された高性能なXML解析ライブラリである。
    DOM、SAX、XPath 1.0をサポートしている。

    XPathサポート
    XPath 1.0をサポートしている。



XPath

以下の例では、WebページのHTMLをダウンロードして、<head>タグ内の<title>タグの値を抽出している。

具体的には、まず、QNetworkAccessManagerクラスを使用してHTTPリクエストを送信して、QNetworkReplyクラスを使用してレスポンスを受信する。
次に、libxml2ライブラリを使用して、受信したレスポンスから<head>タグ内の<title>タグの値を抽出する。

libxml2ライブラリは、C言語で記述されたライブラリであるため、メモリ管理には特に注意が必要である。
例えば、xmlFreeDoc関数、xmlXPathFreeContext関数、xmlFree関数等を適切に使用すること。

 # QMakeを使用する場合
 LIBS += -lxml2
 INCLUDEPATH += /<libxml2のインストールディレクトリ>/include/libxml2


 # CMakeを使用する場合
 
 # pkg-configを使うための準備
 find_package(PkgConfig REQUIRED)
 
 # pkg-configを使用してlibxml2ライブラリを検索
 pkg_search_module(LIBXML2 REQUIRED libxml-2.0)
 
 # ライブラリのインクルードディレクトリをターゲットに追加
 include_directories(${LIBXML2_INCLUDE_DIRS})
 
 # ライブラリのリンクディレクトリをターゲットに追加
 link_directories(${LIBXML2_LIBRARY_DIRS})
 
 target_include_directories(<プロジェクト名> PRIVATE
     # ...略
     ${LIBXML2_INCLUDE_DIRS}
 )
 
 target_link_libraries(<プロジェクト名>
     # ...略
     ${LIBXML2_LIBRARIES}
 )
 
 # libxml2のコンパイルオプション
 add_definitions(
     # ...略
     ${LIBXML2_CFLAGS_OTHER}
 )


 // main.h
 
 #ifndef MAIN_H
 #define MAIN_H
 
 #include <QCoreApplication>
 #include <QNetworkAccessManager>
 #include <QNetworkReply>
 
 class HtmlTitleFetcher : public QObject {
    Q_OBJECT
 
 private:
    QNetworkAccessManager *m_pManager;
    QNetworkReply         *m_pReply;
    QUrl url;
 
 private:
     void parseHtml(const QByteArray &htmlData);
 
 public:
    HtmlTitleFetcher(const QUrl &url, QObject *parent = nullptr);
 
 private slots:
    void onFinished();
 };
 
 #endif // MAIN_H


 // main.cpp
 
 #include <libxml/HTMLparser.h>
 #include <libxml/xpath.h>
 #include "main.h"
 
 HtmlTitleFetcher::HtmlTitleFetcher(const QUrl &url, QObject *parent) : QObject(parent), url(url)
 {
    m_pManager = new QNetworkAccessManager(this);
    QNetworkRequest request(url);
    m_pReply = manager->get(request);
    connect(m_pReply, SIGNAL(finished()), this, SLOT(onFinished()));
 }
 
 void HtmlTitleFetcher::onFinished()
 {
    if (m_pReply->error() == QNetworkReply::NoError) {
       QByteArray htmlData = m_pReply->readAll();
       parseHtml(htmlData);
    }
    else {
       std::cerr << QString("エラー : %1").arg(m_pReply->errorString()).toStdString() << std::endl;
    }
 
    reply->deleteLater();
 }
 
 void HtmlTitleFetcher::parseHtml(const QByteArray &htmlData)
 {
    htmlDocPtr doc = htmlReadMemory(htmlData.data(), htmlData.size(), nullptr, "UTF-8", HTML_PARSE_RECOVER | HTML_PARSE_NOERROR | HTML_PARSE_NOWARNING);
    if (doc == nullptr) {
       std::cerr << QString("HTMLデータのパースに失敗").toStdString() << std::endl;
       return;
    }
 
    xmlXPathContextPtr context = xmlXPathNewContext(doc);
    if (context == nullptr) {
       xmlFreeDoc(doc);
       std::cerr << QString("XPathの生成に失敗").toStdString() << std::endl;
       return;
    }
 
    xmlXPathObjectPtr result = xmlXPathEvalExpression((const xmlChar*)"//title", context);
    if (result == nullptr) {
       xmlXPathFreeContext(context);
       xmlFreeDoc(doc);
       std::cerr << QString("XPath式の評価に失敗").toStdString() << std::endl;
       return;
    }
 
    xmlNodeSetPtr nodeset = result->nodesetval;
    if (xmlXPathNodeSetIsEmpty(nodeset)) {
       std::cerr << QString("<title>タグが存在しません").toStdString() << std::endl;
    }
    else {
       xmlNodePtr cur = nodeset->nodeTab[0];
       if (cur != nullptr && cur->children != nullptr) {
          xmlChar *content = xmlNodeGetContent(cur);
          std::cerr << QString("<title>タグの値 : %1").arg(QString((char *)content)).toStdString() << std::endl;
          xmlFree(content);
       }
    }
 
    xmlXPathFreeObject(result);
    xmlXPathFreeContext(context);
    xmlFreeDoc(doc);
 }
 
 int main(int argc, char *argv[])
 {
    QCoreApplication app(argc, argv);
 
    QUrl url("https://www.example.com");
    HtmlTitleFetcher fetcher(url);
 
    return app.exec();
 }


LIBXML_TEST_VERSIONマクロは、libxml2ライブラリを使用する場合に、ライブラリのバージョンが使用者のプログラムが期待するものと一致していることを保証するために用いられる。
このマクロは、libxml2のヘッダファイルをインクルードした後に呼び出すことにより、プログラムがリンクされるlibxml2ライブラリのバージョンがヘッダファイルで定義されているバージョンと互換性があるかどうかを確認する。
もし互換性が無ければ、実行時にエラーが発生する。

LIBXML_TEST_VERSIONマクロを使用する主な理由は、APIの非互換性による問題を防ぐことである。
libxml2ライブラリは頻繁に更新されるため、新しいバージョンのライブラリには古いバージョンのコードとは互換性のない新機能や変更が含まれることがある。
LIBXML_TEST_VERSIONマクロを使用することにより、開発中にこの種の問題を早期に検出して対処することができる。

したがって、LIBXML_TEST_VERSIONマクロの記述は必須ではないが、
ライブラリのバージョンに依存する可能性のあるプログラムを開発している場合、特にライブラリの更新によって互換性の問題が生じる可能性がある場合には、このマクロを使用することを推奨する。

これにより、将来的な互換性の問題を防ぐことができ、より安定したソフトウェアの開発が可能になる。