「Qtの基礎 - XML」の版間の差分
提供: MochiuWiki : SUSE, EC, PCB
| 20行目: | 20行目: | ||
<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="vmake"> | |||
# 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++"> | <syntaxhighlight lang="c++"> | ||
#include <QCoreApplication> | |||
#include <QXmlStreamReader> | #include <QXmlStreamReader> | ||
#include <QFile> | #include <QFile> | ||
#include < | #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; | |||
} | |||
} | } | ||
} | } | ||
if ( | 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> | </syntaxhighlight> | ||
2024年8月24日 (土) 00:28時点における版
概要
QXmlStreamReaderクラス
QXmlStreamReaderクラスとは
QXmlStreamReaderクラスは、XMLをシンプルなストリーミングAPIで読み込むための高速パーサである。
ストリームリーダの基本的なコンセプトは、XMLドキュメントをトークンのストリームとして読み込むことである。
QXmlStreamReaderクラスとSAXの主な違いは、これらのXMLトークンの読み込み手順である。
- SAXの場合
- アプリケーションはパーサの都合に合わせてパーサからXMLイベントを受信するハンドラ (コールバック関数) を提供する必要がある。
- QXmlStreamReaderの場合
- 繰り返し文を使用して、必要なトークンを次々にリーダから取り出すことができる。
- これは、
readNextメソッドを呼び出すことで実行され、リーダは次のトークンを完了するまで入力ストリームから読み取り、tokenTypeメソッドを返す。 - その後、
isStartElementメソッドやtextメソッド等を使用してトークンを確認することにより、読み込まれているタグや要素についての情報を得ることができる。
このプルアプローチのメリットは、再帰降順パーサを構築して、XMLを異なるメソッドやクラスに分割できることである。
これにより、XMLの解析を簡単に追跡することができる。
要素の取得例
以下の例では、XMLファイルを読み込み、以下に示す要素を読み込んでいる。
- <Hypocenter> -> <Area> -> <Name>の値
- <Hypocenter> -> <Area> -> <Code>のtype属性の値
- 全ての<Observation> -> <IntensityStation> -> <Name>の値
読み込む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>
- Qtプロジェクトファイルを使用する場合
# Qtプロジェクトファイル
QT += xml
- CMakeLists.txtファイルを使用する場合
# 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
)
#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();
}