找回密码
 立即注册
Qt开源社区 门户 查看内容

QT软件开发-第十二章 网络编程 12.5~12.7

2019-5-22 19:37| 发布者: admin| 查看: 1077| 评论: 0

摘要: 点击上方蓝字关注我们12.5 获取天气预报:解析XML文件现在很多网站服务器提供了常用API接口,想要实现获取天气预报比较方便。其中主要方法就是使用QNetworkAccessManager类get方法调用网站服务器提供的API函数接口( ...


点击上方蓝字关注我们




12.5 获取天气预报:解析XML文件


现在很多网站服务器提供了常用API接口,想要实现获取天气预报比较方便。其中主要方法就是使用QNetworkAccessManager类get方法调用网站服务器提供的API函数接口(一般接口都需要收费),来实现想要的功能。一般像获取天气预报这些类似的信息时,服务器返回的都是XML或者JSON格式的数据。

本小节就以天气预报为例子,介绍怎么通过QT获取服务器的天气预报信息,并解析服务器返回的XML格式数据。

12.5.1 XML文件格式介绍


XML是“Extentsible Markup Language”的缩写,是一种可扩展的标记语言,XML的宗旨是传输数据,而与其同属标准通用标记语言的HTML主要用于显示数据。

  • XML文档的语法规则

(1)必须有XML声明语句。声明语句是文件的第一句,格式为<?xml version="1.0" standalone="yes/no" encoding="UTF-8"?>。声明的作用是告诉浏览器或者其他处理程序这个文档是XML文档。声明语句中的version表示文档遵守XML规范的版本,standalone表示文档是否附带DTD文件,encoding表示文档所用的语言编码,默认是UTF-8。

(2)在XML文档中,所有的标记必须要有结束标记,包括空标记。

(3)所有的XML文档必须有一个根元素,XML文档中的第一个元素就是根元素。

(4)所有的XML文档都必须包含一个单独的标记来定义,所有的其他元素都必须成对在根元素中嵌套。XML文档有且只有一个根元素。所有的XML标记都必须嵌套合理。

(5)属性值必须使用引号(包括双引号和单引号)。在XML中,元素的属性值没有引号引着是不符合规定的。

(6)使用XML,空白将被保留。在XML文档中,空白部分不会被解析器自动删除。

(7)使用XML,CR/LF被转换为LF。使用XML,新行总是被标识为LF(Line Feed,即换行)。

(8)在XML中注释的语法基本上和HTML中的一样,比如 <!-- 这是一个注释 --> 。

(9)XML标记都是大小写敏感的。

  • XML元素的语法

(1)XML元素是可以扩展的,它们之间有关联。

(2)XML元素有简单的命名规则。

(3)XML元素是可以扩展的,XML元素的可扩展决定了XML文档的可扩展。

(4)XML元素是相互关联的,XML元素之间可以是父子关系和兄弟关系。

(5)XML元素由元素名称和元素内容组成。XML元素可以有不同的内容。

(6)元素可以用来标记XML文件中的区段。XML元素拥有下列的格式:

<ElementName>Content</ElementName>

内容Content部分将会被包含在XML标记中。

(7) 虽然XML标记通常包围住内容部分,但是也可以建立不含内容的元素,称为空(empty elements)元素。在XML中,空元素可以利用下面两种方式来呈现:

<ElementName/>

<ElementName></ElementName>

  • XML元素命名规则

(1)元素的名字可以包含字母、数字和其他字符。

(2)元素的名字只能以字母和“_” (下画线)开头。

(3)元素的名字不能以XML(或者xml、Xml、xMl…)开头。

(4)元素的名字不能包含空格,中间不能包含“:”(冒号)。

  • 属性的语法

(1) XML元素在开始标记处可以有元素属性。

(2) XML元素可以有属性,属性通常包含一些关于元素的额外信息。

(3) 属性值必须用引号引着(单引号、双引号都可以使用,单引号中可以包含双引号)。

(4) 通常可以用子元素代替属性。

XML属性定义格式如下:

<person sex="female">why</person>

代码中person是元素名称,sex是属性名称。

  • 百度天气预报API接口返回的XML格式数据示例:




图12-5-1 XML格式示例

12.5.2 解析XML文件相关类介绍


在QT下解析XML文件需要用到QDomNode 、QDomDocument、QDomElement、QDomNodeList类。这些类不属于QT核心模块,在使用的时候需要在pro工程文件中加上QT+= xml。

其中QDomDocument类代表整个XML文档;从概念上讲,它是文档树的根,并提供主要访问文档的数据接口。QDomElement类代表一个元素的DOM树。QDomNodeList类保存了QDomNode对象的列表。QDomNode类保存了所有节点的DOM树,是前面几个类的基类。

除了以上介绍的类,QT提供QXmlStreamReader类提供了一个快速阅读XML的一系列API接口,读取数据是按照顺序向下读取。QXmlStreamReader属于QT核心类,不属于QtXml模块。

继承关系如下:




  • QDomDocument类解析XML文件常用的函数介绍

    1. 加载XML内容并检测XML文档编码规范要求。

(1) bool setContent(const QByteArray& text, bool namespaceProcessing, QString *errorMsg=Q_NULLPTR, int *errorLine=Q_NULLPTR, int *errorColumn=Q_NULLPTR );

(2)bool setContent(const QString& text, bool namespaceProcessing, QString *errorMsg=Q_NULLPTR, int *errorLine=Q_NULLPTR, int *errorColumn=Q_NULLPTR );

(3)bool setContent(QIODevice* dev, bool namespaceProcessing, QString *errorMsg=Q_NULLPTR, int *errorLine=Q_NULLPTR, int *errorColumn=Q_NULLPTR );

如果加载的XML内容符合规范将返回true。如果加载失败,将会返回失败的信息,保存在errorMsg指针里;同时也返回了错误的行列位置,保存在errorLine 和errorColumn指针里。

示例:

QDomDocument document;

QString error;

int row = 0, column = 0;

QByteArray byte_array;

if(!document.setContent(byte_array, false, &error, &row, &column))

{

    //XML内容加载错误

    return;

}

    2. 检查节点是否为空

bool QDomNode::isNull() const

如果该节点为空(即如果它没有类型或内容)返回true,否则返回false。

    3. 判断节点是否为文本节点

bool QDomNode::isText() const

如果是文本节点,可以通过QDomText QDomNode::toText()函数

    4. 返回文档最外层的根元素

QDomElement QDomDocument::documentElement() const

示例:

/*返回XML文档最外层的 <>...</> 元素*/

QDomElement root = document.documentElement();



 图12-5-2 XML文档根元素范围


  • QdomElement类常用函数介绍

    1. 返回该元素的标记名称

QString QDomElement::tagName() const

void QDomElement::setTagName(const QString &name) //设置元素标记名称

例如:一个XML元素名称为img的结构:

<img src="myimg.png">



图12-5-3 元素标记名称

    2. 获取元素的直接子节点列表

QDomNodeList QDomNode::childNodes() const

该函数通常在QDomElement对象中调用。在元素包含范围内:<>...</> 格式表示一个子节点。

例如:



图12-5-4 元素的直接子节点

    3. 获取元素包含的文本字符串

QString QDomElement::text() const

示例:



图12-5-5 获取包含的文本字符串


  • QdomNode类常用函数介绍

    1. 返回QDomElement元素对象

QDomElement QDomNode::toElement() const

bool QDomNode::isElement() const   //判断节点是否是一个元素

12.5.3 获取天气预报实例


下面代码通过百度提供的API接口获取天气预报信息。通过QT提供的QDomNode 、QDomDocument、QDomElement相关类进行解析。

  • 百度开发者API接口申请:http://lbsyun.baidu.com/apiconsole/key

  • 访问百度天气预报的格式:

http://api.map.baidu.com/telematics/v2/weather?location=城市名称&ak=密匙

城市名称:需要查询的城市拼音。

密匙:在百度开发者栏目进行申请。

返回结果: XML格式文本。

示例结果如下:

<?xml version="1.0" encoding="utf-8" ?>

<CityWeatherResponse>

    <status>success</status>

        <currentCity>shenzhen</currentCity>

        <results>

        <result>

            <date>周日 12月11日 (实时:21℃)</date>

            <dayPictureUrl>http://api.map.baidu.com/images/weather/day/duoyun.png</dayPictureUrl>

            <nightPictureUrl>http://api.map.baidu.com/images/weather/night/duoyun.png</nightPictureUrl>

            <weather>多云</weather>

            <wind>微风</wind>

            <temperature>23 ~ 15℃</temperature>

        </result>

        <result>

            <date>周一</date>

            <dayPictureUrl>http://api.map.baidu.com/images/weather/day/duoyun.png</dayPictureUrl>

            <nightPictureUrl>http://api.map.baidu.com/images/weather/night/duoyun.png</nightPictureUrl>

            <weather>多云</weather>

            <wind>微风</wind>

            <temperature>24 ~ 17℃</temperature>

        </result>

        <result>

            <date>周二</date>

            <dayPictureUrl>http://api.map.baidu.com/images/weather/day/duoyun.png</dayPictureUrl>

            <nightPictureUrl>http://api.map.baidu.com/images/weather/night/duoyun.png</nightPictureUrl>

            <weather>多云</weather>

            <wind>微风</wind>

            <temperature>25 ~ 15℃</temperature>

        </result>

        <result>

            <date>周三</date>

            <dayPictureUrl>http://api.map.baidu.com/images/weather/day/qing.png</dayPictureUrl>

            <nightPictureUrl>http://api.map.baidu.com/images/weather/night/qing.png</nightPictureUrl>

            <weather>晴</weather>

            <wind>东北风3-4级</wind>

            <temperature>21 ~ 13℃</temperature>

        </result>

        </results>

</CityWeatherResponse>

  • 天气预报解析结果如下:(配套代码CH12-9)



 图12-5-6 获取天气预报

    1. “widget.cpp”文件示例

#include "widget.h"

#include "ui_widget.h"

Widget::Widget(QWidget *parent) :QWidget(parent),ui(new Ui::Widget)

{

    ui->setupUi(this);

    /*设置标题*/

    this->setWindowTitle("百度天气预报");

    /*1. 实例化QNetworkAccessManager*/

    manager = new QNetworkAccessManager(this);

    /*2. 关联finished信号*/

    connect(manager, SIGNAL(finished(QNetworkReply*)),this, SLOT(replyFinished(QNetworkReply*)));

    ui->lineEdit->setText("shenzhen");

}

Widget::~Widget()

{

    delete ui;

}

//槽函数

void Widget::replyFinished(QNetworkReply*network)

{

   //无错误返回

    if(network->error() == QNetworkReply::NoError)

    {

        //读取所有数据

        QByteArray byte_array=network->readAll();

        GetXmlWeatherInfo(byte_array);

    }

     else

     {

        QMessageBox::warning(this, tr("错误信息提示"),tr("失败!""检查网络是否正常!"),QMessageBox::Ok);

     }

    //删除reply,不能在repyfinished里直接delete,要调用deletelater;

    network->deleteLater();

}

void Widget::on_pushButton_Get_clicked()

{

    /*接收输入框的数据*/

    QString str=ui->lineEdit->text();

    if(str.isEmpty())

    {

        QMessageBox::warning(this, tr("错误信息提示"),tr("输入数据为空!"),QMessageBox::Ok);

        return;

    }

    /*保存接口地址*/

    QString text="http://api.map.baidu.com/telematics/v2/weather?location=";

    text+=str;

    text+="&ak=vvjkqKyqSFwLgnfg0I0sXzyCDDFWFykb"; //

    ui->plainTextEdit->clear();//清空显示

    /*获取网页数据*/

    manager->get(QNetworkRequest(QUrl(text)));

}

//解析XML格式的天气预报(百度天气接口)

void Widget::GetXmlWeatherInfo(QByteArray &ByteArray)

{

    QDomDocument document;

    QString error;

    int row = 0, column = 0;

    QString Info;

    /*1. 检测XML文件格式*/

    if(!document.setContent(ByteArray, false, &error, &row, &column))

    {

        QMessageBox::information(NULL, QString(tr("错误提示")), QString(tr("XML文件读取错误!")));

        return;

    }

    /*2. 判断是否有节点*/

    if(document.isNull())

    {

        //弹出提示信息

        QMessageBox::information(NULL, QString(tr("错误提示")), QString(tr("XML格式错误!")));

        return;

    }

    /*3. 返回XML文档的根元素。最外层的 <>...</> 元素*/

   QDomElement root = document.documentElement();

   /*4. 获取元素子节点列表*/

    QDomNodeList List=root.childNodes();

    /*5. 判断天气预报是否获取成功*/

    QDomNode DomNode= List.item(0);  //取出存放状态信息子节点

    QDomElement Element = DomNode.toElement();//得到子节点的元素对象

    if(Element.tagName()!="status")

    {

        //弹出提示信息

        QMessageBox::information(NULL, QString(tr("错误提示")), QString(tr("天气预报获取错误!\n"

                                                             "请检查城市名称是否正确")));

        return;

    }

    /*5. 获取城市的名称*/

    DomNode= List.item(1);               //取出存放城市名称子节点

    Element = DomNode.toElement();       //得到子节点的元素对象

    if(Element.text().isEmpty())

    {

        //弹出提示信息

        QMessageBox::information(NULL, QString(tr("错误提示")), QString(tr("天气预报获取错误!\n"

 "请检查城市名称是否正确")));

        return;

    }

    Info+="城市名称:"+Element.text()+"\n";//得到城市名称

    /*5. 循环取出每一个子节点进行解析*/

    DomNode= List.item(2);        //取出存放天气预报信息子节点

    Element = DomNode.toElement();

    List = Element.childNodes();   //得到天气预报列表

    //循环解析子节点

   for(int i=0;i<List.count();i++)

   {

      DomNode= List.item(i);  //取出一个子节点

      Element = DomNode.toElement();//得到子节点的元素对象

      QDomNodeList List1 = Element.childNodes();

      for(int i=0;i<List1.count();i++)

      {

          QDomNode DomNode1= List1.item(i);  //取出一个子节点

          QDomElement Element1 = DomNode1.toElement();//得到子节点的元素对象

          if(Element1.tagName()=="date")

           {

                Info+="日期:"+Element1.text()+"\n";

           }

           else if(Element1.tagName()=="weather")

           {

                Info+="天气:"+Element1.text()+"\n";

           }

           else if(Element1.tagName()=="wind")

           {

                Info+="风量:"+Element1.text()+"\n";

           }

           else if(Element1.tagName()=="temperature")

           {

                Info+="温度:"+Element1.text()+"\n";

           }

      }

   }

    ui->plainTextEdit->appendPlainText(Info);

}

    1. “widget.h”代码示例

#ifndef WIDGET_H

#define WIDGET_H

#include <QWidget>

#include <QNetworkAccessManager>

#include <QNetworkReply>

#include <QNetworkRequest>

#include <QMessageBox>

#include <QFileDialog>

#include <QDomDocument>

#include <QXmlStreamReader>

namespace Ui {

class Widget;

}

class Widget : public QWidget

{

    Q_OBJECT

public:

    explicit Widget(QWidget *parent = 0);

    ~Widget();

    QNetworkAccessManager *manager;

    void GetXmlWeatherInfo(QByteArray &byte_array);

public slots:

    void replyFinished(QNetworkReply* network);

private slots:

    void on_pushButton_Get_clicked();

private:

    Ui::Widget *ui;

};

#endif // WIDGET_H

    2. “widget.ui”文件示例



 图12-5-7 UI设计界面

12.5.4 获取手机归属地信息实例


下面是一个解析XML格式的手机归属地信息,通过QXmlStreamReader类进行解析。(配套代码CH12-10)

XML格式结果如下:

<?xml version="1.0" encoding="UTF-8"?>

<root>

<success>1</success>

<result>

<status>ALREADY_ATT</status>

<phone>13800138000</phone>

<area>010</area>

<postno>100000</postno>

<att>中国,北京</att>

<ctype>中国移动138卡</ctype>

<par>1380013</par>

<prefix>138</prefix>

<operators>中国移动</operators>

<style_simcall>中国,北京</style_simcall>

<style_citynm>中华人民共和国,北京市</style_citynm>

</result>

</root>



 图12-5-8 手机号码归属地解析33

    1.  “widget.ui”文件示例



 图12-5-9 UI设计界面

    2. “widget.cpp”文件示例

#include "widget.h"

#include "ui_widget.h"

Widget::Widget(QWidget *parent) :QWidget(parent),ui(new Ui::Widget)

{

    ui->setupUi(this);

    /*设置标题*/

    this->setWindowTitle("获取手机归属地信息");

    /*1. 实例化QNetworkAccessManager*/

    manager = new QNetworkAccessManager(this);

    /*2. 关联finished信号*/

    connect(manager, SIGNAL(finished(QNetworkReply*)),this, SLOT(replyFinished(QNetworkReply*)));

    ui->lineEdit->setText("13800138000");

}

Widget::~Widget()

{

    delete ui;

}

//槽函数

void Widget::replyFinished(QNetworkReply*network)

{

   //无错误返回

    if(network->error() == QNetworkReply::NoError)

    {

        //读取所有数据

        QByteArray byte_array=network->readAll();

        GetPhoneInfo(byte_array);

    }

     else

     {

        QMessageBox::warning(this, tr("错误信息提示"),tr("失败!""检查网络是否正常!"),QMessageBox::Ok);

     }

    //删除reply,不能在repyfinished里直接delete,要调用deletelater;

    network->deleteLater();

}

void Widget::on_pushButton_Get_clicked()

{

    /*接收输入框的数据*/

    QString str=ui->lineEdit->text();

    if(str.isEmpty())

    {

        QMessageBox::warning(this, tr("错误信息提示"),tr("输入数据为空!"),QMessageBox::Ok);

        return;

    }

    /*保存接口地址*/

    QString text="http://api.k780.com:88/?app=phone.get&phone=";

    text+=str;

    text+="&appkey=10003&sign=b59bc3ef6191eb9f747dd4e83c99f2a4&format=xml";

    ui->plainTextEdit->clear();//清空显示

    /*获取网页数据*/

    manager->get(QNetworkRequest(QUrl(text)));

}

//解析XML格式数据

void Widget::GetPhoneInfo(QByteArray ByteArray)

{

    /*用户存放显示数据*/

    QString text;

    /*1. 载入数据*/

    QXmlStreamReader xml(ByteArray);

    /*2. 循环打印数据*

    /*判断是否到XML文件结尾*/

    while(!xml.atEnd())

    {

        /*判断是否错误*/

        if(xml.hasError())

        {

            qDebug()<<"XML有误";

            QMessageBox::warning(this, tr("错误信息提示"),tr("手机号码信息查询错误!\n"

                                    "请检查号码是否正确\n""网络是否畅通!"),QMessageBox::Ok);

            return;

        }

        else if(xml.isStartElement()) //遇到开始标签,如<city>

        {

            if(xml.name()=="success")

              {

                  if(xml.readElementText()!="1")

                  {

                      qDebug()<<"XML有误";

                      QMessageBox::warning(this, tr("错误信息提示"),

              tr("手机号码信息查询错误!\n请检查号码是否正确\n""网络是否畅通!"),QMessageBox::Ok);

                      return;

                  }

              }

            if(xml.name()=="phone")

              {

                  QString str= xml.readElementText();

                  /*拼接显示的数据*/

                  text+="电话号码:";

                  text+=str;

                  text+="\n";

              }

            if(xml.name()=="area")

              {

                  QString str= xml.readElementText();

                  /*拼接显示的数据*/

                  text+="区号:";

                  text+=str;

                  text+="\n";

              }

            if(xml.name()=="postno")

              {

                  QString str= xml.readElementText();

                  /*拼接显示的数据*/

                  text+="邮编:";

                  text+=str;

                  text+="\n";

              }

            if(xml.name()=="att")

              {

                  QString str= xml.readElementText();

                  /*拼接显示的数据*/

                  text+="归属地:";

                  text+=str;

                  text+="\n";

              }

            if(xml.name()=="ctype")

              {

                  QString str= xml.readElementText();

                  /*拼接显示的数据*/

                  text+="号码卡类型:";

                  text+=str;

                  text+="\n";

              }

            if(xml.name()=="par")

              {

                  QString str= xml.readElementText();

                  /*拼接显示的数据*/

                  text+="所有号码区间:";

                  text+=str;

                  text+="\n";

              }

            if(xml.name()=="prefix")

              {

                  QString str= xml.readElementText();

                  /*拼接显示的数据*/

                  text+="运营商号段:";

                  text+=str;

                  text+="\n";

              }

            if(xml.name()=="operators")

              {

                  QString str= xml.readElementText();

                  /*拼接显示的数据*/

                  text+="运营商:";

                  text+=str;

                  text+="\n";

              }

            if(xml.name()=="style_citynm")

              {

                  QString str= xml.readElementText();

                  /*拼接显示的数据*/

                  text+="完整归属地:";

                  text+=str;

                  text+="\n";

              }

        }

         /*继续读下一个标签*/

         xml.readNext();

    }

    /*显示结果*/

    ui->plainTextEdit->appendPlainText(text);

}

    3. “widget.h”文件示例

#ifndef WIDGET_H

#define WIDGET_H

#include <QWidget>

#include <QNetworkAccessManager>

#include <QNetworkReply>

#include <QNetworkRequest>

#include <QMessageBox>

#include <QFileDialog>

#include <QDomDocument>

#include <QXmlStreamReader>

namespace Ui {

class Widget;

}

class Widget : public QWidget

{

    Q_OBJECT

public:

    explicit Widget(QWidget *parent = 0);

    ~Widget();

    QNetworkAccessManager *manager;

    void GetPhoneInfo(QByteArray ByteArray);

public slots:

    void replyFinished(QNetworkReply* network);

private slots:

    void on_pushButton_Get_clicked();

private:

    Ui::Widget *ui;

};

#endif // WIDGET_H

12.6 获取北京时间:解析JSON文件


JSON(JavaScript Object Notation)是一种轻量级的数据交换格式。它基于JavaScript(Standard ECMA-262 3rd Edition - December 1999)的一个子集。JSON采用完全独立于语言的文本格式,但是也使用了类似于C语言家族的习惯(包括C、C++、C#、Java、JavaScript、Perl、Python等)。这些特性使JSON成为理想的数据交换语言。易于人阅读和编写,同时也易于机器解析和生成。

12.6.1 JSON文件格式介绍


  • JSON语法规则

JSON语法是 JavaScript 对象表示语法的子集。

1. 数据在键值对中

2. 数据由逗号分隔

3. 花括号保存对象

4. 方括号保存数组

  • JSON 的值

1. 数字(整数或浮点数)

2. 字符串(在双引号中)

3. 逻辑值(true 或 false)

4. 数组(在方括号中)

5. 对象(在花括号中)

  • 具体形式

    1. 对象是一个无序的“‘名称/值’对”集合。

(1)一个对象以“{”(左括号)开始,“}”(右括号)结束。

(2)每个“名称”后跟一个“:”(冒号);

(3)“‘名称/值’ 对”之间使用“,”(逗号)分隔。

    2. 数组是值(value)的有序集合。

(1)一个数组以“[”(左中括号)开始,“]”(右中括号)结束。

(2)值之间使用“,”(逗号)分隔

    3. 值(value)可以是双引号括起来的字符串(string)、数值(number)、true、false、 null、对象(object)或者数组(array)。这些结构可以嵌套。

    4. 字符串(string)是由双引号包围的任意数量Unicode字符的集合,使用反斜线转义。一个字符(character)即一个单独的字符串(character string)。字符串(string)与C或者Java的字符串非常相似。

    5. 数值(number)也与C或者Java的数值非常相似。除去未曾使用的八进制与十六进制格式。除去一些编码细节。

12.6.2 常用的Json库


  • JsonCpp

    JsonCpp是一个C++用来处理JSON数据的开发包。

网址:http://jsoncpp.sourceforge.net/

  • cJSON

    cJSON是一个超轻巧,携带方便,单文件,简单的可以作为ANSI-C标准的JSON解析器。

网址:http://sourceforge.net/projects/cjson/

  • QJson

    QJson是一个基于Qt的开发包用来将JSON数据解析成QVariant对象,JSON的数组将被映射为QVariantList实例,而其他对象映射为QVariantMap实例。

网址:http://qjson.sourceforge.net/

关于Qt中对JSON的生成与解析,Qt5以前的版本,需要去进行单独下载、编译,才能使用。到了Qt5,提供了专门的QJsonDocument类来读取和写入JSON文档。

12.6.3 解析JSON文档相关的类介绍


QT提供的QJsonDocument类可以用来读取和写入JSON格式的文档。QJsonDocument类包含了完整的JSON文档操作方法,既可以读取基于UTF-8编码的文本,又可以读取和写入Qt自己的二进制格式数据。利用isNull()函数可以查询解析文档的有效性。

  • 创建json格式文档示例(QJsonObject)

QJsonObject json;

json.insert("name", QString("Qt"));

json.insert("version", 5);

json.insert("windows", true);

json.insert("时间", QString("2016-08-09 23:34"));

QJsonDocument document;

document.setObject(json);

QByteArray byte_array = document.toJson(QJsonDocument::Compact);

byte_array包含的结果:

{"name":"Qt","version":5,"windows":true,"时间":"2016-08-09 23:34"}

  • JsonDocument类常用的函数接口介绍

    1. 载入需要解析的数据

[static]

QJsonDocument QJsonDocument::fromJson(const QByteArray &json, QJsonParseError *error = Q_NULLPTR)  

该函数是一个静态函数,载入的数据格式需要是QByteArray类型。返回值为QJsonDocument对象。

示例:

QJsonParseError json_error

//载入需要解析的数据

QJsonDocument parse_doucment = QJsonDocument::fromJson(byte_array, &json_error);

其中的QJsonParseError 类用于在JSON解析中报告错误。

在进行解析之前需要先判断数据载入的格式是否正确:

if(json_error.error == QJsonParseError::NoError)

{

 ………………………….

}

    2. 获取JSON对象

bool QJsonDocument::isObject() const

QJsonObject QJsonDocument::object() const

示例:

/*如果文档包含一个正确的对象。返回true*/

if(parse_doucment.isObject())

{

   /*获取对象*/

   QJsonObject obj = parse_doucment.object();

}



 图12-6-1 JSON对象

    3. 获取名称对应的数据值

bool QJsonObject::contains(const QString &key) const

示例:

/*如果文档包含一个数组。返回一个空对象*/

QJsonObject obj = parse_doucment.object();

/*如果对象包含指定的标记。返回true*/

if(obj.contains("success"))

{

    /*返回该名称包含值的值*/

    QJsonValue success = obj.take("success");

    /*如果值包含一个字符串返回true。*/

    if(success.isString())

    {

        /*将值转为字符串*/

        QString flag = success.toString();

    }

 }



 图12-6-2 JSON对象包含的名称与值

    4. 值、数组、对象之间的转换

将值转为对象:QJsonObject QJsonValue::toObject() const

将值转为数组:QJsonArray QJsonValue::toArray() const



 图12-6-3 JSON对象格式


  • QJsonValue类常用函数接口介绍

在JSON QJsonValue类里封装了一个用于存放JSON的数据值函数接口。数据值在JSON里可以是以下6种基本类型之一。  

bool QJsonValue::Bool

double QJsonValue::Double

string QJsonValue::String

array QJsonValue::Array

object QJsonValue::Object

null QJsonValue::Null

    1. 构造函数

QJsonValue(Type = Null);

QJsonValue(bool b);

QJsonValue(double n);

QJsonValue(int n);

QJsonValue(qint64 n);

QJsonValue(const QString &s);

QJsonValue(QLatin1String s);

    2. 判断值类型

bool isNull()

bool isBool()

bool isDouble()

bool isString()

bool isArray()

bool isObject()

bool isUndefined()

    3. 将数据值按照指定类型返回

bool toBool(bool defaultValue = false) const;

int toInt(int defaultValue = 0) const;

double toDouble(double defaultValue = 0) const;

QString toString() const;

QJsonArray toArray() const;

QJsonObject toObject() const;

  • QJsonObject 类常用函数接口介绍

QJsonObject类封装了一个JSON对象。JSON对象是一个键值列表,键值的值由QJsonValue类表示。

JSON格式:

{"success":"1","result":"weai"}

1) {}花括号范围里的success称为对象。

2) 逗号表示键值之间的分隔符。

3) result表示键值,冒号后面的weai是赋给键值的数据值。

    1. 返回包含键值(名称)的数量

int QJsonObject::count() const

int QJsonObject::size() const

int QJsonObject::length() const

    2. 返回存放键值数据的QJsonValue类

QJsonValue QJsonObject::take(const QString &key)

QJsonValue QJsonObject::value(const QString &key) const

    3. 插入一个新的键值

iterator QJsonObject::insert(const QString &key, const QJsonValue &value)

    4. 删除指定键值

void QJsonObject::remove(const QString &key)

  • QJsonArray类常用函数接口介绍

QJsonArray类封装了一个JSON数组。

    1. 向数组插入数据

void QJsonArray::insert(int i, const QJsonValue &value)

void QJsonArray::append(const QJsonValue &value)  

void QJsonArray::prepend(const QJsonValue &value)

    2. 返回数组指定下标的值

QJsonValue QJsonArray::at(int i) const //直接返回

QJsonValue QJsonArray::takeAt(int i) //删除指定的项目并返回

    3. 删除指定位置的值

void QJsonArray::removeAt(int i)

    4. 数组下标的数量

int QJsonArray::count() const

int QJsonArray::size() const

12.6.4 获取北京时间实例


下面实例中解析的是JSON格式时间信息。北京时间获取地址:http://api.k780.com:88/?app=life.time&appkey=10003&sign=b59bc3ef6191eb9f747dd4e83c99f2a4&format=json

解析的JSON文本格式如下:

{

"success":"1","result":

{

"timestamp":"1481596461",

"datetime_1":"2016-12-13 10:34:21",

"datetime_2":"2016年12月13日 10时34分21秒",

"week_1":"2",

"week_2":"星期二",

"week_3":"周二",

"week_4":"Tuesday"

}

}

运行效果:(配套代码CH12-11)



 图12-6-4 北京时间获取

    1. “widget.cpp”文件示例

#include "widget.h"

#include "ui_widget.h"

Widget::Widget(QWidget *parent) :QWidget(parent),

    ui(new Ui::Widget)

{

    ui->setupUi(this);

    /*设置标题*/

    this->setWindowTitle("获取北京时间");

    /*1. 实例化QNetworkAccessManager*/

    manager = new QNetworkAccessManager(this);

    /*2. 关联finished信号*/

    connect(manager, SIGNAL(finished(QNetworkReply*)),this, SLOT(replyFinished(QNetworkReply*)));

}

Widget::~Widget()

{

    delete ui;

}

//槽函数

void Widget::replyFinished(QNetworkReply*network)

{

   //无错误返回

    if(network->error() == QNetworkReply::NoError)

    {

        //读取所有数据

        QByteArray byte_array=network->readAll();

        GetInternetTime(byte_array);

    }

     else

     {

        QMessageBox::warning(this, tr("错误信息提示"),tr("失败!""检查网络是否正常!"),QMessageBox::Ok);

     }

    //删除reply,不能在repyfinished里直接delete,要调用deletelater;

    network->deleteLater();

}

void Widget::on_pushButton_Get_clicked()

{

    //获取北京时间接口

    QString text="http://api.k780.com:88/?app=life.time&appkey=10003&sign=b59bc3ef6191eb9f747dd4e83c99f2a4&format=json";

    manager->get(QNetworkRequest(QUrl(text)));

}

//解析时间

void Widget::GetInternetTime(QByteArray &byte_array)

{

    /*解析数据*/

    QString time;

    QJsonParseError json_error;

    QJsonDocument parse_doucment = QJsonDocument::fromJson(byte_array, &json_error);

    if(json_error.error != QJsonParseError::NoError)

    {

        return;

    }

      /*1.  解析状态,判断是否解析成功*/

     /*如果文档包含一个正确的对象。返回true*/

      if(parse_doucment.isObject())

      {

        /*QJsonObject包含在文档中,返回QJsonObject。如果文档包含一个数组。返回一个空对象*/

        QJsonObject obj = parse_doucment.object();

        /*如果对象包含指定的标记。返回true*/

        if(obj.contains("success"))

        {

            /*返回一个包含值引用键QJsonValue*/

            QJsonValue success = obj.take("success");

            /*如果值包含一个字符串返回true。*/

            if(success.isString())

            {

                /*将值转为字符串*/

                QString flag = success.toString();

                /*判断返回的状态值*/

                if(flag!="1")

                {

                    QMessageBox::warning(this, tr("错误信息提示"),tr("时间获取错误!\n"

                                             "请检查网络是否畅通!"),QMessageBox::Ok);

                                return;

                }

            }

         }

      /*2. 解析结果 */

        /*如果对象包含指定的标记。返回true*/

        if(obj.contains("result"))

        {

            /*返回一个包含值引用键QJsonValue*/

            QJsonValue datetime = obj.take("result");

            /*如果值包含一个对象返回true*/

            if(datetime.isObject())

            {

                /*将值转为QJ

鲜花

握手

雷人

路过

鸡蛋

公告
可以关注我们的微信公众号yafeilinux_friends获取最新动态,或者加入QQ会员群进行交流:190741849、186601429(已满) 我知道了