MochiuWiki : SUSE, EC, PCB
検索
個人用ツール
ログイン
Toggle dark mode
名前空間
ページ
議論
表示
閲覧
ソースを閲覧
履歴を表示
Qtの基礎 - XMLのソースを表示
提供: MochiuWiki : SUSE, EC, PCB
←
Qtの基礎 - XML
あなたには「このページの編集」を行う権限がありません。理由は以下の通りです:
この操作は、次のグループのいずれかに属する利用者のみが実行できます:
管理者
、new-group。
このページのソースの閲覧やコピーができます。
== 概要 == XMLは、データを構造化して記述するためのマークアップ言語である。<br> 1998年にW3Cによって策定されて以来、様々な分野で広く使用されている。<br> <br> XMLの大きな特徴は、その拡張性にある。<br> ユーザが独自のタグを定義できるため、多様なデータ構造を表現することが可能である。<br> また、人間にも機械にも読みやすい形式で記述されるため、データの可読性が高いというメリットがある。<br> <br> XMLドキュメントは、通常、プロローグから始まり、その後にルート要素が続く。<br> ルート要素の中には、階層構造で子要素が配置される。<br> 各要素には属性を付けることができ、要素内にはテキストデータを含めることができる。<br> <br> この構造により、XMLは様々な用途に適している。<br> 例えば、システム間でのデータ交換、アプリケーションの設定ファイル、Webサービスのデータ形式、データベースの保存形式、文書形式としても利用されている。<br> <br> XMLに関連する技術も多く存在しており、DTDやXML Schemaはドキュメントの構造を定義するために使用され、XPathはXML文書内の特定の要素や属性を指定するのに役立つ。<br> また、XSLTを使用すればXML文書を他の形式に変換することができる。<br> <br> XMLの長所としては、その柔軟性の高さや自己記述的な性質、データと表示の分離が可能であること等が挙げられる。<br> 一方で、XMLは冗長になりがちで、ファイルサイズが大きくなる傾向があること、パース処理に時間がかかる場合があること等が短所として指摘されている。<br> <br><br> == QXmlStreamReaderとQt XMLモジュールの違い == QXmlStreamReaderとQt XMLモジュールの主なクラス (例: QDomDocumentクラス等) には、いくつかの違いがある。<br> <br> <code>QXmlStreamReader</code>クラスは現代のXML処理タスクに適しており、大きなファイルを扱う場合やメモリ効率と処理速度が重要な場合に推奨される。<br> 一方、Qt XMLモジュール (QDomDocumentクラス) は小さなXMLドキュメントの簡単な操作やドキュメント全体の構造を変更する必要がある場合に適している。<br> <br> <u>特別な理由がない限り、<code>QXmlStreamReader</code>クラスの使用が推奨されている。</u><br> <br> * パーシング方式 ** QXmlStreamReaderクラス **: プル型パーサー。 **: 開発者が明示的に次の要素を読み取る必要がある。 ** Qt XMLモジュール (QDomDocumentクラス) **: DOM (Document Object Model) ベース。 **: XMLドキュメント全体をメモリに読み込む。 *: <br> * メモリ使用 ** QXmlStreamReaderクラス **: メモリ効率が良く、大きなXMLファイルの処理に適している。 ** Qt XMLモジュール (QDomDocumentクラス) **: 全ドキュメントをメモリに読み込むため、大きなファイルの処理には多くのメモリを必要とする。 *: <br> * 処理速度 ** QXmlStreamReaderクラス **: 高速であり、特に大きなファイルの処理に効率的である。 ** Qt XMLモジュール (QDomDocumentクラス) **: 小さなファイルでは高速であるが、大きなファイルの処理は遅くなる可能性がある。 *: <br> * 使いやすさ ** QXmlStreamReaderクラス **: より低レベルなAPI。 **: XMLの構造に沿って手動でパースする必要がある。 ** Qt XMLモジュール (QDomDocumentクラス) **: より高レベルなAPI。 **: ドキュメント全体を簡単に操作できる。 *: <br> * 機能 ** QXmlStreamReaderクラス **: 読み取り専用。 **: XMLの書き込みには、<code>QXmlStreamWriter</code>クラスが必要である。 ** Qt XMLモジュール (QDomDocumentクラス) **: 読み取りと書き込みの両方が可能である。 **: また、ドキュメントの構造を変更することもできる。 *: <br> * 名前空間サポート ** QXmlStreamReaderクラス **: 名前空間を完全にサポートしている。 ** Qt XMLモジュール (QDomDocumentクラス) **: 名前空間のサポートは限定的である。 *: <br> * バージョン ** QXmlStreamReaderクラス **: Qt 4.3以降で使用可能である。 ** Qt XMLモジュール (QDomDocumentクラス) **: 古いバージョンのQtから使用可能であるが、新しいプロジェクトでは非推奨である。 *: <br> * 標準準拠 ** QXmlStreamReaderクラス **: XML 1.0およびXML 1.1規格に完全準拠している。 ** Qt XMLモジュール (QDomDocumentクラス) **: 完全な準拠ではない。 **: また、一部の高度な機能が欠けている可能性がある。 <br><br> == QXmlStreamReaderクラス == ==== QXmlStreamReaderクラスとは ==== QXmlStreamReaderクラスは、XMLをシンプルなストリーミングAPIで読み込むための高速パーサである。<br> <br> ストリームリーダの基本的なコンセプトは、XMLドキュメントをトークンのストリームとして読み込むことである。<br> QXmlStreamReaderクラスとSAXの主な違いは、これらのXMLトークンの読み込み手順である。<br> <br> * SAXの場合 *: アプリケーションはパーサの都合に合わせてパーサからXMLイベントを受信するハンドラ (コールバック関数) を提供する必要がある。 * QXmlStreamReaderの場合 *: 繰り返し文を使用して、必要なトークンを次々にリーダから取り出すことができる。 *: これは、<code>readNext</code>メソッドを呼び出すことで実行され、リーダは次のトークンを完了するまで入力ストリームから読み取り、<code>tokenType</code>メソッドを返す。 *: その後、<code>isStartElement</code>メソッドや<code>text</code>メソッド等を使用してトークンを確認することにより、読み込まれているタグや要素についての情報を得ることができる。 <br> このプルアプローチのメリットは、再帰降順パーサを構築して、XMLを異なるメソッドやクラスに分割できることである。<br> これにより、XMLの解析を簡単に追跡することができる。<br> <br> ==== 要素の取得例 ==== 以下の例では、XMLファイルを読み込み、以下に示す要素を読み込んでいる。<br> * <Hypocenter> -> <Area> -> <Name>の値 * <Hypocenter> -> <Area> -> <nowiki><Code></nowiki>のtype属性の値 * 全ての<Observation> -> <IntensityStation> -> <Name>の値 <br> 読み込むXMLファイルを以下に示す。<br> <syntaxhighlight lang="xml"> <!-- 使用するXMLファイル --> <Earthquake> <OriginTime>2024-08-23T21:00:00+09:00</OriginTime> <ArrivalTime>2024-08-23T21:01:00+09:00</ArrivalTime> <Hypocenter> <Area> <Name>茨城県南部</Name> <Code type="震央地名">301</Code> </Area> </Hypocenter> <jmx_eb:Magnitude type="Mj" description="M3.8">3.8</jmx_eb:Magnitude> </Earthquake> <Observation> <Pref><Name>茨城県</Name><Code>08</Code><MaxInt>2</MaxInt> <Area><Name>茨城県北部</Name><Code>300</Code><MaxInt>2</MaxInt> <City><Name>小美玉市</Name><Code>0823600</Code><MaxInt>2</MaxInt> <IntensityStation><Name>小美玉市小川*</Name><Code>0823633</Code><Int>2</Int></IntensityStation> <IntensityStation><Name>小美玉市上玉里*</Name><Code>0823635</Code><Int>2</Int></IntensityStation> </City> <City><Name>水戸市</Name><Code>0820100</Code><MaxInt>1</MaxInt> <IntensityStation><Name>水戸市千波町*</Name><Code>0820121</Code><Int>1</Int></IntensityStation> </City> </Area> </Pref> </Observation> </syntaxhighlight> <br> * Qtプロジェクトファイルを使用する場合 <syntaxhighlight lang="make"> # Qtプロジェクトファイル QT += xml </syntaxhighlight> <br> * CMakeLists.txtファイルを使用する場合 <syntaxhighlight lang="cmake"> # CMakeLists.txtファイル # ...略 find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core) # ...略 target_link_libraries(<ターゲット名> PRIVATE Qt${QT_VERSION_MAJOR}::Core ) </syntaxhighlight> <br> <syntaxhighlight lang="c++"> #include <QCoreApplication> #include <QXmlStreamReader> #include <QFile> #include <QDebug> void parseXml(const QString& xmlData) { QXmlStreamReader xml(xmlData); QString hypocenterAreaName; QString hypocenterAreaCodeType; QStringList intensityStationNames; while (!xml.atEnd() && !xml.hasError()) { QXmlStreamReader::TokenType token = xml.readNext(); if (token == QXmlStreamReader::StartElement) { if (xml.name() == "Hypocenter") { while (!(xml.tokenType() == QXmlStreamReader::EndElement && xml.name() == "Hypocenter")) { if (xml.tokenType() == QXmlStreamReader::StartElement) { if (xml.name() == "Area") { while (!(xml.tokenType() == QXmlStreamReader::EndElement && xml.name() == "Area")) { if (xml.tokenType() == QXmlStreamReader::StartElement) { if (xml.name() == "Name") { hypocenterAreaName = xml.readElementText(); } else if (xml.name() == "Code") { hypocenterAreaCodeType = xml.attributes().value("type").toString(); } } xml.readNext(); } } } xml.readNext(); } } else if (xml.name() == "Observation") { while (!(xml.tokenType() == QXmlStreamReader::EndElement && xml.name() == "Observation")) { if (xml.tokenType() == QXmlStreamReader::StartElement && xml.name() == "IntensityStation") { while (!(xml.tokenType() == QXmlStreamReader::EndElement && xml.name() == "IntensityStation")) { if (xml.tokenType() == QXmlStreamReader::StartElement && xml.name() == "Name") { intensityStationNames.append(xml.readElementText()); } xml.readNext(); } } xml.readNext(); } } } } if (xml.hasError()) { qDebug() << "XMLエラー: " << xml.errorString(); } else { qDebug() << "Hypocenter Area Name: " << hypocenterAreaName; qDebug() << "Hypocenter Area Code Type: " << hypocenterAreaCodeType; qDebug() << "Intensity Station Names: "; for (const auto& name : intensityStationNames) { qDebug() << " -" << name; } } } int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); QFile file("sample.xml"); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { qDebug() << "XMLファイルのオープンに失敗"; return -1; } QString xmlData = file.readAll(); file.close(); parseXml(xmlData); return a.exec(); } </syntaxhighlight> <br><br> == QXmlStreamWriterクラス == ==== QXmlStreamWriterクラスとは ==== <code>QXmlStreamWriter</code>クラスは、XMLデータをシンプルなストリーミングAPIで生成するためのクラスである。<br> このクラスは、テキストベースのXMLデータを効率的かつ簡単に書き出すために使用される。<br> <br> <code>QXmlStreamWriter</code>クラスの基本的なコンセプトは、XMLドキュメントを順次書き出すことであり、<br> エレメントの開始や終了、属性の追加、テキストの書き出し等、XMLの様々な部分を逐次的に処理することができる。<br> <br> 主な機能を以下に示す。<br> * エレメントの開始と終了 *: <code>writeStartElement</code>メソッドを使用して、エレメントを開始する。 *: この時点でエレメント名を指定し、そのエレメントが必要とする属性を追加できる。 *: <code>writeEndElement</code>メソッドを呼び出すことにより、そのエレメントの終了タグを自動的に生成する。 <br> * 属性の追加 *: <code>writeAttribute</code>メソッドで、エレメントに属性を追加できる。 *: 属性名と値を指定するだけで簡単に追加が可能である。 <br> * テキストの書き出し *: <code>writeCharacters</code>メソッドを使用して、エレメントの中にテキストデータを書き込むことができる。 <br> * XMLの自動管理 *: <code>QXmlStreamWriter</code>クラスは、開始したエレメントを適切に終了するため、XMLの整合性を保つのに役立つ。 *: また、エンコーディングの指定やXML宣言の追加も簡単に行うことができる。 <br> <code>QXmlStreamWriter</code>クラスの主なメリットは、そのシンプルなインターフェースと効率性にある。<br> ストリーミングAPIのため、大量のデータを1度にメモリに保持することなく、逐次的に処理することができる。<br> これにより、大規模なXMLドキュメントの生成や動的なデータの書き出しが容易になる。<br> <br> ==== XMLファイルの作成 ==== 以下の例では、指定されたXML構造を持つXMLファイルを作成している。<br> <syntaxhighlight lang="xml"> <!-- 作成するXMLファイルの構造 --> <Earthquake> <OriginTime>2024-08-23T21:00:00+09:00</OriginTime> <ArrivalTime>2024-08-23T21:01:00+09:00</ArrivalTime> <Hypocenter> <Area> <Name>茨城県南部</Name> <Code type="震央地名">301</Code> </Area> </Hypocenter> <jmx_eb:Magnitude type="Mj" description="M3.8">3.8</jmx_eb:Magnitude> </Earthquake> <Observation> <Pref><Name>茨城県</Name><Code>08</Code><MaxInt>2</MaxInt> <Area><Name>茨城県北部</Name><Code>300</Code><MaxInt>2</MaxInt> <City><Name>小美玉市</Name><Code>0823600</Code><MaxInt>2</MaxInt> <IntensityStation><Name>小美玉市小川*</Name><Code>0823633</Code><Int>2</Int></IntensityStation> <IntensityStation><Name>小美玉市上玉里*</Name><Code>0823635</Code><Int>2</Int></IntensityStation> </City> <City><Name>水戸市</Name><Code>0820100</Code><MaxInt>1</MaxInt> <IntensityStation><Name>水戸市千波町*</Name><Code>0820121</Code><Int>1</Int></IntensityStation> </City> </Area> </Pref> </Observation> </syntaxhighlight> <br> <syntaxhighlight lang="c++"> #include <QCoreApplication> #include <QXmlStreamWriter> #include <QFile> #include <QDebug> int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); QFile file("sample.xml"); if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { qDebug() << "Failed to open file for writing"; return -1; } QXmlStreamWriter xmlWriter(&file); xmlWriter.setAutoFormatting(true); xmlWriter.writeStartDocument(); xmlWriter.writeStartElement("Earthquake"); xmlWriter.writeTextElement("OriginTime", "2024-08-23T21:00:00+09:00"); xmlWriter.writeTextElement("ArrivalTime", "2024-08-23T21:01:00+09:00"); xmlWriter.writeStartElement("Hypocenter"); xmlWriter.writeStartElement("Area"); xmlWriter.writeTextElement("Name", "茨城県南部"); xmlWriter.writeStartElement("Code"); xmlWriter.writeAttribute("type", "震央地名"); xmlWriter.writeCharacters("301"); xmlWriter.writeEndElement(); // Code xmlWriter.writeEndElement(); // Area xmlWriter.writeEndElement(); // Hypocenter xmlWriter.writeStartElement("jmx_eb:Magnitude"); xmlWriter.writeAttribute("type", "Mj"); xmlWriter.writeAttribute("description", "M3.8"); xmlWriter.writeCharacters("3.8"); xmlWriter.writeEndElement(); // jmx_eb:Magnitude xmlWriter.writeEndElement(); // Earthquake xmlWriter.writeStartElement("Observation"); xmlWriter.writeStartElement("Pref"); xmlWriter.writeTextElement("Name", "茨城県"); xmlWriter.writeTextElement("Code", "08"); xmlWriter.writeTextElement("MaxInt", "2"); xmlWriter.writeStartElement("Area"); xmlWriter.writeTextElement("Name", "茨城県北部"); xmlWriter.writeTextElement("Code", "300"); xmlWriter.writeTextElement("MaxInt", "2"); xmlWriter.writeStartElement("City"); xmlWriter.writeTextElement("Name", "小美玉市"); xmlWriter.writeTextElement("Code", "0823600"); xmlWriter.writeTextElement("MaxInt", "2"); xmlWriter.writeStartElement("IntensityStation"); xmlWriter.writeTextElement("Name", "小美玉市小川*"); xmlWriter.writeTextElement("Code", "0823633"); xmlWriter.writeTextElement("Int", "2"); xmlWriter.writeEndElement(); // IntensityStation xmlWriter.writeStartElement("IntensityStation"); xmlWriter.writeTextElement("Name", "小美玉市上玉里*"); xmlWriter.writeTextElement("Code", "0823635"); xmlWriter.writeTextElement("Int", "2"); xmlWriter.writeEndElement(); // IntensityStation xmlWriter.writeEndElement(); // City xmlWriter.writeStartElement("City"); xmlWriter.writeTextElement("Name", "水戸市"); xmlWriter.writeTextElement("Code", "0820100"); xmlWriter.writeTextElement("MaxInt", "1"); xmlWriter.writeStartElement("IntensityStation"); xmlWriter.writeTextElement("Name", "水戸市千波町*"); xmlWriter.writeTextElement("Code", "0820121"); xmlWriter.writeTextElement("Int", "1"); xmlWriter.writeEndElement(); // IntensityStation xmlWriter.writeEndElement(); // City xmlWriter.writeEndElement(); // Area xmlWriter.writeEndElement(); // Pref xmlWriter.writeEndElement(); // Observation xmlWriter.writeEndDocument(); file.close(); return a.exec(); } </syntaxhighlight> <br><br> == libxml2ライブラリの使用 == 以下の例では、指定されたXML構造を持つXMLファイルを読み込み取得している。<br> <br> * Qtプロジェクトファイル (.pro) を使用する場合 <syntaxhighlight lang="make"> # Qtプロジェクトファイル (.pro) # Pkg-configを使用する場合 CONFIG += link_pkgconfig PKGCONFIG += libxml-2.0 # Pkg-Configを使用しない場合 INCLUDEPATH += /usr/include/libxml2 LIBS += -lxml2 </syntaxhighlight> <br> * CMakeを使用する場合 <syntaxhighlight lang="cmake"> # CMakeLists.txtファイル # ...略 find_package(LibXml2 REQUIRED) # ...略 target_link_libraries(XMLParserProject PRIVATE # ...略 LibXml2::LibXml2 ) </syntaxhighlight> <br> <syntaxhighlight lang="c++"> // XMLParser.hファイル #ifndef XMLPARSER_H #define XMLPARSER_H #include <QString> #include <QVector> #include <libxml/parser.h> #include <libxml/tree.h> class XMLParser { private: static QString getNodeContent(xmlNodePtr node); public: static QString getHypocenterAreaName(const QString& xmlContent); static QString getHypocenterAreaCodeType(const QString& xmlContent); static QVector<QString> getIntensityStationNames(const QString& xmlContent); }; QString XMLParser::getNodeContent(xmlNodePtr node) { if (node && node->children && node->children->content) { return QString::fromUtf8(reinterpret_cast<const char*>(node->children->content)); } return QString(); } QString XMLParser::getHypocenterAreaName(const QString& xmlContent) { xmlDocPtr doc = xmlReadMemory(xmlContent.toUtf8().constData(), xmlContent.toUtf8().size(), NULL, NULL, 0); if (!doc) return QString(); xmlNodePtr root = xmlDocGetRootElement(doc); xmlNodePtr current = root; while (current) { if (QString::fromUtf8(reinterpret_cast<const char*>(current->name)) == "Hypocenter") { xmlNodePtr area = current->children; while (area) { if (QString::fromUtf8(reinterpret_cast<const char*>(area->name)) == "Area") { xmlNodePtr name = area->children; while (name) { if (QString::fromUtf8(reinterpret_cast<const char*>(name->name)) == "Name") { QString result = getNodeContent(name); xmlFreeDoc(doc); return result; } name = name->next; } } area = area->next; } } current = current->next; } xmlFreeDoc(doc); return QString(); } QString XMLParser::getHypocenterAreaCodeType(const QString& xmlContent) { xmlDocPtr doc = xmlReadMemory(xmlContent.toUtf8().constData(), xmlContent.toUtf8().size(), NULL, NULL, 0); if (!doc) return QString(); xmlNodePtr root = xmlDocGetRootElement(doc); xmlNodePtr current = root; while (current) { if (QString::fromUtf8(reinterpret_cast<const char*>(current->name)) == "Hypocenter") { xmlNodePtr area = current->children; while (area) { if (QString::fromUtf8(reinterpret_cast<const char*>(area->name)) == "Area") { xmlNodePtr code = area->children; while (code) { if (QString::fromUtf8(reinterpret_cast<const char*>(code->name)) == "Code") { xmlChar *type = xmlGetProp(code, reinterpret_cast<const xmlChar*>("type")); if (type) { QString result = QString::fromUtf8(reinterpret_cast<const char*>(type)); xmlFree(type); xmlFreeDoc(doc); return result; } } code = code->next; } } area = area->next; } } current = current->next; } xmlFreeDoc(doc); return QString(); } QVector<QString> XMLParser::getIntensityStationNames(const QString& xmlContent) { QVector<QString> results; xmlDocPtr doc = xmlReadMemory(xmlContent.toUtf8().constData(), xmlContent.toUtf8().size(), NULL, NULL, 0); if (!doc) return results; xmlNodePtr root = xmlDocGetRootElement(doc); xmlNodePtr current = root; while (current) { if (QString::fromUtf8(reinterpret_cast<const char*>(current->name)) == "Observation") { xmlNodePtr pref = current->children; while (pref) { if (QString::fromUtf8(reinterpret_cast<const char*>(pref->name)) == "Pref") { xmlNodePtr area = pref->children; while (area) { if (QString::fromUtf8(reinterpret_cast<const char*>(area->name)) == "Area") { xmlNodePtr city = area->children; while (city) { if (QString::fromUtf8(reinterpret_cast<const char*>(city->name)) == "City") { xmlNodePtr station = city->children; while (station) { if (QString::fromUtf8(reinterpret_cast<const char*>(station->name)) == "IntensityStation") { xmlNodePtr name = station->children; while (name) { if (QString::fromUtf8(reinterpret_cast<const char*>(name->name)) == "Name") { results.append(getNodeContent(name)); } name = name->next; } } station = station->next; } } city = city->next; } } area = area->next; } } pref = pref->next; } } current = current->next; } xmlFreeDoc(doc); return results; } #endif // XMLPARSER_H </syntaxhighlight> <br> <syntaxhighlight lang="c++"> #include <QCoreApplication> #include <QFile> #include "xmlparser.h" #include <QDebug> int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); QFile file("earthquake.xml"); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { qDebug() << "Failed to open file"; return -1; } QString xmlContent = file.readAll(); file.close(); QString hypocenterAreaName = XMLParser::getHypocenterAreaName(xmlContent); QString hypocenterAreaCodeType = XMLParser::getHypocenterAreaCodeType(xmlContent); QVector<QString> intensityStationNames = XMLParser::getIntensityStationNames(xmlContent); qDebug() << "Hypocenter Area Name:" << hypocenterAreaName; qDebug() << "Hypocenter Area Code Type:" << hypocenterAreaCodeType; qDebug() << "Intensity Station Names:"; for (const auto& name : intensityStationNames) { qDebug() << " -" << name; } return a.exec(); } </syntaxhighlight> <br><br> __FORCETOC__ [[カテゴリ:Qt]]
Qtの基礎 - XML
に戻る。
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
Collapse