【Qt】XML


【目的】

  • 讀取 Google Weather。

【原理】

  • Google Weather 提供多樣化的API查詢方式
  • Xml 結點與資料(1)
    • 透過 WMHelp XMLPad Pro EditionXMLmind XML Editor檢視。
      明顯可以看出左邊的圖分類的非常清楚。
      imageimage
    • 同事試過亦可由 FreeMind 讀取XML 資料(透過 PS Pad 整理縮排後)
  • Xml 結點與資料(2),以 2010年 9月 29 日(禮拜三)為例
    • xml_api_reply version=1 (第一層)
      • weather module_id=0 tab_id=0 mobile_row=0 mobile_zipped=1 row=0 section=0
        • forecast_information 預測資料 (第三層)
          • city data=taipei (第四層)
          • postal_code data=taipei
          • latitude_e6 data=
          • forecast_date=2010-09-29
          • current_date_time data=2010-09-29 14:00:00 +0000
          • unit_system data=SI
        • current_conditions 目前狀況 ( 猜測是代表目前時間,比如說 11:00am時的天氣)
          • condition data=多雲
          • temp_f data=79
          • temp_c data=26
          • humidity data=濕度: 86%
          • icon data=/ig/images/weather/cloudy.gif
          • wind_condition data=風向: 公里/小時
        • forecast_conditions 預測狀況(這周的天氣預測)
          • day_of_week data=週三
          • low data=23
          • high data=28
          • icon data=/ig/images/weather/rain.gif
          • condition data=多雲時陰短暫雨
        • forecast_conditions 預測狀況
          • day_of_week data=週四
          • low data=23
          • high data=29
          • icon data=/ig/images/weather/rain.gif
          • condition data=多雲短暫雨
        • forecast_conditions 預測狀況
          • day_of_week data=週五
          • low data=24
          • high data=32
          • icon data=/ig/images/weather/cloudy.gif
          • condition data=多雲
        • forecast_conditions 預測狀況
          • day_of_week data=週六
          • low data=24
          • high data=33
          • icon data=/ig/images/weather/cloudy.gif
          • condition data=多雲
  • Xml 格式資料可透過幾種方式讀取
    • SAX(Simple API for XML)  XML資料唯獨,讀取速度較快
    • DOM(Document Object Model)  可更新 XML 資料
    • Pull Parse(Java推薦方式,目前Qt 不支援)

【程式】

  1. main.c  一樣用之前的 QHttp 範例,main.c 中有兩個地方需特別注意
    1. 抓取資料的網址改成由原本的zh_tw以us顯示,方便處理
      http://www.google.com/ig/api?hl=us&weather=taipei
    2. 抓取網頁成功之後的callback function binding 到 show_weather
      int main(int argc, char *argv[])
      {
        QApplication a(argc, argv);
        Dialog w;
        w.show();
      
        HttpGet getter;
        QUrl url("http://www.google.com/ig/api?hl=us&weather=taipei");
        getter.downloadFile(QUrl(url));
        QObject::connect(&getter, SIGNAL(finished()), &w, SLOT(show_weather()));
      
          return a.exec();
      }
  2. 由於我們不需更改資料,所以以 SAX 先作實驗
    (tbd)

  3. 透過 DOM 的方式 (通常可用 QTreeWidgetItem搭配遞迴方式載入,此處使用苦工方式一個一個讀出)

    1. dialog.h

      #ifndef DIALOG_H
      #define DIALOG_H
      
      #include <QDialog>
      #include <QUrl>
      #include "HttpGet.h"
      #include <iostream>
      #include <QtXml>
      #include <QFile>
      
      namespace Ui {
          class Dialog;
      }
      class Dialog : public QDialog {
          Q_OBJECT
      public:
          Dialog(QWidget *parent = 0);
          ~Dialog();
      protected:
          void changeEvent(QEvent *e);
      private:
          Ui::Dialog *ui;
      private slots:
          void show_weather();
          void show_forecast_information(const QDomNode node3);
          void show_current_conditions(const QDomNode node3);
          void show_forecast_conditions(const QDomNode node3);
      };
      
      #endif // DIALOG_H
    2. dialog.cpp

      void Dialog::show_weather()
      {
          QDomDocument doc;
          QFile file("api");
          QString errorStr;
          int errorLine;
          int errorCol;
          if(!doc.setContent(&file,true,&errorStr,&errorLine,&errorCol)){
              qDebug() << "Unable to open the file";
              return;
          }
          file.close();
      
          QDomElement root = doc.documentElement();
          if (root.tagName() != "xml_api_reply")
              return;
      
          QDomNode node2 = root.firstChild();
          if(node2.toElement().tagName() == "weather")
          {
              QDomNode node3 = node2.firstChild();
                 while (!node3.isNull()){
                  qDebug() << "-" << node3.toElement().tagName();
                  if(node3.toElement().tagName() == "forecast_information")
                      show_forecast_information(node3);
                  else if (node3.toElement().tagName() == "current_conditions")
                      show_current_conditions(node3);
                  else if (node3.toElement().tagName() == "forecast_conditions")
                      show_forecast_conditions(node3);
                  node3 = node3.nextSibling();
                 }
              }
      }
      void Dialog::show_forecast_information(const QDomNode node3)
      {
          QDomNode node4 = node3.firstChild();
          while (!node4.isNull()){
              if(node4.toElement().tagName() == "city")
                  qDebug() << "    +city:" << node4.toElement().attribute("data");
              else if(node4.toElement().tagName() == "postal_code")
                  qDebug() << "    +postal_code:" << node4.toElement().attribute("data");
              else if(node4.toElement().tagName() == "latitude_e6")
                  qDebug() << "    +latitude_e6:" << node4.toElement().attribute("data");
              else if(node4.toElement().tagName() == "forecast_date")
                  qDebug() << "    +forecast_date:" << node4.toElement().attribute("humidity");
              else if(node4.toElement().tagName() == "current_date_time")
                  qDebug() << "    +current_date_time:" << node4.toElement().attribute("data");
              else if(node4.toElement().tagName() == "unit_system")
                  qDebug() << "    +unit_system:" << node4.toElement().attribute("data");
              node4 = node4.nextSibling();
          }
      }
      void Dialog::show_current_conditions(const QDomNode node3)
      {  
          QDomNode node4 = node3.firstChild();
          while (!node4.isNull()){
              if(node4.toElement().tagName() == "condition")
                  qDebug() << "    +condition:" << node4.toElement().attribute("data");
              else if(node4.toElement().tagName() == "temp_f")
                  qDebug() << "    +temp_f:" << node4.toElement().attribute("data");
              else if(node4.toElement().tagName() == "temp_c")
                  qDebug() << "    +temp_c:" << node4.toElement().attribute("data");
              else if(node4.toElement().tagName() == "humidity")
                  qDebug() << "    +humidity:" << node4.toElement().attribute("humidity");
              else if(node4.toElement().tagName() == "icon")
                  qDebug() << "    +icon:" << node4.toElement().attribute("data");
              else if(node4.toElement().tagName() == "wind_condition")
                  qDebug() << "    +wind_condition:" << node4.toElement().attribute("data");
              node4 = node4.nextSibling();
          }
      }
      void Dialog::show_forecast_conditions(const QDomNode node3)
      {
          QDomNode node4 = node3.firstChild();
          while (!node4.isNull()){
              if(node4.toElement().tagName() == "day_of_week")
                  qDebug() << "    +day_of_week:" << node4.toElement().attribute("data");
              else if(node4.toElement().tagName() == "low")
                  qDebug() << "    +low:" << node4.toElement().attribute("data");
              else if(node4.toElement().tagName() == "high")
                  qDebug() << "    +high:" << node4.toElement().attribute("data");
              else if(node4.toElement().tagName() == "icon")
                  qDebug() << "    +icon:" << node4.toElement().attribute("data");
              else if(node4.toElement().tagName() == "condition")
                  qDebug() << "    +condition:" << node4.toElement().attribute("data");
              node4 = node4.nextSibling();
          }
      }
    3. 結果
      - "forecast_information" 
          +city: "taipei" 
          +postal_code: "taipei" 
          +latitude_e6: "" 
          +forecast_date: "" 
          +current_date_time: "2010-09-29 23:00:00 +0000" 
          +unit_system: "US" 
      - "current_conditions" 
          +condition: "Clear" 
          +temp_f: "82" 
          +temp_c: "28" 
          +humidity: "" 
          +icon: "/ig/images/weather/sunny.gif" 
          +wind_condition: "Wind:  mph" 
      - "forecast_conditions" 
          +day_of_week: "Thu" 
          +low: "75" 
          +high: "87" 
          +icon: "/ig/images/weather/rain.gif" 
          +condition: "Rain" 
      - "forecast_conditions" 
          +day_of_week: "Fri" 
          +low: "77" 
          +high: "89" 
          +icon: "/ig/images/weather/cloudy.gif" 
          +condition: "Cloudy" 
      - "forecast_conditions" 
          +day_of_week: "Sat" 
          +low: "77" 
          +high: "91" 
          +icon: "/ig/images/weather/cloudy.gif" 
          +condition: "Cloudy" 
      - "forecast_conditions" 
          +day_of_week: "Sun" 
          +low: "73" 
          +high: "86" 
          +icon: "/ig/images/weather/rain.gif" 
          +condition: "Rain" 

【其它】

【參考】

 

Ed32. Copyright 2008 All Rights Reserved Revolution Two Church theme by Brian Gardner Converted into Blogger Template by Bloganol dot com