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

提供: MochiuWiki : SUSE, EC, PCB

20行目: 20行目:
<br>
<br>
==== 要素の取得例 ====
==== 要素の取得例 ====
以下の例では、XMLファイルを読み込み、要素titleの値を抽出してコンソールへ出力している。<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 <QTextStream>
  #include <QDebug>
   
   
  // XMLファイルを開く
  void parseXml(const QString& xmlData)
QFile File("<XMLファイルのパス  例: hoge.xml>");
  {
  if(!File.open(QIODevice::ReadOnly)) {
    QXmlStreamReader xml(xmlData);
     std::cout << QString("ファイルのオープンに失敗 : %1").arg(File.errorString()) << std::endl;
     QString hypocenterAreaName;
     return;
     QString hypocenterAreaCodeType;
}
    QStringList intensityStationNames;
   
   
// XMLファイルを読み込む
    while (!xml.atEnd() && !xml.hasError()) {
QTextStream InStream(&File);
      QXmlStreamReader::TokenType token = xml.readNext();
QString XMLData = InStream.readAll();
File.close();
   
   
// XMLファイルから特定の要素を抽出
      if (token == QXmlStreamReader::StartElement) {
QXmlStreamReader xml(XMLData);
          if (xml.name() == "Hypocenter") {
while (!xml.atEnd() && !xml.hasError()) {
            while (!(xml.tokenType() == QXmlStreamReader::EndElement && xml.name() == "Hypocenter")) {
    QXmlStreamReader::TokenType token = xml.readNext();
                if (xml.tokenType() == QXmlStreamReader::StartElement) {
    if (token == QXmlStreamReader::StartElement) {
                  if (xml.name() == "Area") {
      if (xml.name() == "title") {
                      while (!(xml.tokenType() == QXmlStreamReader::EndElement && xml.name() == "Area")) {
          // 特定の要素が存在する場合は値をコンソールへ出力
                        if (xml.tokenType() == QXmlStreamReader::StartElement) {
          xml.readNext();
                            if (xml.name() == "Name") {
           std::cout << QString("Title : %1").arg(xml.text().toString()).toStdString() << std::endl;
                              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 (xml.hasError()) {
  int main(int argc, char *argv[])
    std::cerr << QString("XML Error : %1").arg(xml.errorString()).toStdString() << std::endl;
{
    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();
 }