点击上方蓝字关注我们
12.5 获取天气预报:解析XML文件 现在很多网站服务器提供了常用API接口,想要实现获取天气预报比较方便。其中主要方法就是使用QNetworkAccessManager类get方法调用网站服务器提供的API函数接口(一般接口都需要收费),来实现想要的功能。一般像获取天气预报这些类似的信息时,服务器返回的都是XML或者JSON格式的数据。
本小节就以天气预报为例子,介绍怎么通过QT获取服务器的天气预报信息,并解析服务器返回的XML格式数据。
12.5.1 XML文件格式介绍 XML是“Extentsible Markup Language”的缩写,是一种可扩展的标记语言,XML的宗旨是传输数据,而与其同属标准通用标记语言的HTML主要用于显示数据。
(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标记都是大小写敏感的。
(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>
|
(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文档根元素范围
1. 返回该元素的标记名称
QString QDomElement::tagName() const
void QDomElement::setTagName(const QString &name) //设置元素标记名称
|
例如:一个XML元素名称为img的结构:
图12-5-3 元素标记名称
2. 获取元素的直接子节点列表
QDomNodeList QDomNode::childNodes() const
|
该函数通常在QDomElement对象中调用。在元素包含范围内:<>...</> 格式表示一个子节点。
例如:
图12-5-4 元素的直接子节点
3. 获取元素包含的文本字符串
QString QDomElement::text() const
|
示例:
图12-5-5 获取包含的文本字符串
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>
|
图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语法是 JavaScript 对象表示语法的子集。
1. 数据在键值对中
2. 数据由逗号分隔
3. 花括号保存对象
4. 方括号保存数组
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是一个C++用来处理JSON数据的开发包。
网址:http://jsoncpp.sourceforge.net/
cJSON是一个超轻巧,携带方便,单文件,简单的可以作为ANSI-C标准的JSON解析器。
网址:http://sourceforge.net/projects/cjson/
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"}
|
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对象格式
在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类封装了一个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类封装了一个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(已满)
我知道了
|