1.前言
????一直以来,博主的事例代码中都一直使用到JSON数据格式。而很多初学者一直对JSON格式有很大疑惑,所以博主特意分出一篇博文来重点讲解Arduino平台下的JSON库——ArduinoJSON。
????读者需要注意一下几点:
- ArduinoJSON的Github地址请参考 wiki。
- ArduinoJSON说明文档可以参考 wiki,博主强烈建议读者可以尝试去阅读这些文档,肯定获益匪浅。
- ArduinoJSON目前分为两个大版本 V5 和 V6版本(估计很多初学者会经常看到Arduino IDE提示自己升级ArduinoJSON库版本),博主也会分别讲解两个版本。
- 下载完库之后,只需要包含以下头文件即可使用
#include <ArduinoJson.h>
????废话少说,请读者认真以下干货内容。
2.JSON基础介绍
2.1 什么是Json?
- Json 指的是JavaScript对象表示法(JavaScript Object Notation)。
- Json 是轻量级的文本数据交换格式,类似于XML,比XML更小、更快,更容易解析。
- Json 独立于语言。
- Json 具有自我描述性,容易理解。
2.2 具体使用例子
2.2.1 JSON对象例子
JSON对象描述:
{
"motor": {
"left": 100,
"right": 20
},
"servo": {
"servo_1": 90
}
}
JSON对象语法说明:
- 这里分别有两个对象(对象是用{}区分),对象分别是motor、servo。
- 对于对象motor来说,有两个字段 left 和 right,它们的值类型是int型,值分别是100和20;
- 对于对象servo来说,有一个字段servo_1,它的值类型是int型,值是90。
2.2.2 JSON对象数组
JSON数组描述:
{
"employees": [
{
"firstName": "Bill",
"lastName": "Gates"
},
{
"firstName": "George",
"lastName": "Bush"
},
{
"firstName": "Thomas",
"lastName": "Carter"
}
]
}
JSON数组语法说明:
- 这里有一个对象数组(数组用[]区分)employees。
- 每个对象里面有两个字段firstName和lastName,它们的值类型都是String。
重点:
- 无论是JSON对象还是JSON数组,它们的核心都是键值对,也就是key-value形式。
3.ArduinoJson库
????上面说到,ArduinoJson库有两个大版本 —— V5 和 V6。
????不管是V5还是V6版本,在编码之前,请到Arduino IDE的管理库去下载:
????请读者按照自己的需求分别去下载不同版本(当然博主建议用新不用旧,毕竟一般新版本都是经过旧版本升级优化)。
????不管是V5 还是 V6版本,对于开发者来说有三个概念是共通的:
- JsonObject —— json对象(存储key-value键值对的集合,每一个key是一个字符串,每一个value是一个JsonVariant)
- JsonArray —— json对象数组(存储一个JsonVariant的数组)
- JsonVariant —— json变体(存储可以放在json文件中的任意类型数据,包括int,float,数组,对象,开发者可以认为它是一个抽象的对象概念,底层内容,读者理解即可)
????除了理解上面的三个概念,博主认为读者还必须注意以下两点:
- 构造json数据,一定是从最外层开始构造,从外到里一层层构造;
- 解析json数据,虽然是交给arduinojson库处理,但是我们获取数据也是从最外层开始获取,从外到里一层层获取;
????记住上面的黑体内容,接下来,我们针对不同版本的ArduinoJson库来讲解使用以及注意事项。
3.1 ArduinoJson V5版本
????假设读者下载的V5版本的,那么可以参考 这里 的API说明。读者需要注意一下jsonBuffer,因为V5版本的json操作都是在它上面。
????对于开发者来说,使用JSON无非就是编码或者解码,所以博主也会分出两种情况来讲解。
????首先我们来看看V5版本常用的百度脑图:
????可以看出,方法主要分为三大类:
- JsonBuffer相关,这是整个json库的入口,它负责高效管理内存以及调用json解析器;
- JsonObject相关;
- JsonArray相关;
3.1.1 JsonBuffer
????JsonBuffer作为整个V5版本ArduinoJson库的入口,负责处理整个json数据的内存管理以及构造解析工作,这是我们需要首先重点关注的内容。
????它包括两个实现类:
- DynamicJsonBuffer,内存分配在heap区,无固定大小,可以自动增长所需空间,方法调用完自动回收;
- StaticJsonBuffer,内存分配在stack区,有固定大小,大小值由开发者定义,方法调用完自动回收;
????对于一些内存使用比较紧缺的机器,博主建议尽量用固定大小的StaticJsonBuffer(这个需要提前预知内容的大小,而这个内容大小可以通过计算得来,请点 wiki 参考)。
????那么,我们开发者可能会关心以下几个常见问题:
1. 问题1,如何去确定buffer的大小?
- 假设整个json数据结构是固定的,开发者可以使用StaticJsonBuffer。举个例子:
{"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}
????那么通过JSON_OBJECT_SIZE(n)和JSON_ARRAY_SIZE(n)可以计算出内存大小:
const int BUFFER_SIZE = JSON_OBJECT_SIZE(3) + JSON_ARRAY_SIZE(2);
StaticJsonBuffer<BUFFER_SIZE> jsonBuffer;
????当然我们可以借助工具来帮我们计算内存大小,具体可以参考 ArduinoJson Assistant。
- 假设整个json数据结构是非固定的,开发者可以使用DynamicJsonBuffer,可以动态增长(动态增长就意味着可能会内存溢出,整个是需要开发者去考虑的),当然尽量给DynamicJsonBuffer一个足够大的初始值,可以减少调用malloc()方法去分配内存。
- json解析器根据输入的内容会有不同的策略字符串。如果输入的内容是可写内容,比如 char* 或者 char[],解析器不会申请额外的内存空间,也就是“zero-copy”模式。如果输入的内容是自读内容,比如 const char* 或者 字符串 或者steam流,解析器会重新拷贝一份该字符串作为可写操作,这样就意味着JsonBuffer大小可能和我们预想的不一样。所以,博主建议开发者尽量是char* 或者 char[]。
2. StaticJsonBuffer 和 DynamicJsonBuffer的区别?
- 具体参考 wiki
3. 如何去重用一个JsonBuffer?
- 要重用JsonBuffer,开发者的版本必须大于5.11.0,并且使用clear方法去重用,当然json库的开发者建议不要去重用jsonbuffer,容易出问题。直接看个例子:
// STEP1: parse input
StaticJsonBuffer<200> jsonBuffer;
JsonObject& inputObject = jsonBuffer.parseObject(inputJson);
...etc...
// STEP2: generate output
jsonBuffer.clear();
JsonObject& outputObject = jsonBuffer.createObject();
outputObject["hello"] = inputObject["world"];
????看起来没有什么问题,但实际上有访问错误,请看分析:
- inputObject是一个json对象的指针,由JsonBuffer管理内存;
- clear方法重置了jsonbuffer内存池,运行重新使用inputObject的内存空间;
- outputObject对象被创建,其地址和inputObject一样;
- 到这一步大家应该知道会发生什么问题了吧,inputObject变成了一个危险指针,其内容是无法预知的;
????那么要怎么解决这个问题呢?有两种解决方案:
- 使用更大的JsonBuffer
// STEP1: parse input
StaticJsonBuffer<400> jsonBuffer;
JsonObject& inputObject = jsonBuffer.parseObject(inputJson);
...etc...
// STEP2: generate output
JsonObject& outputObject = jsonBuffer.createObject();
outputObject["hello"] = inputObject["world"];
- 使用第二个JsonBuffer:
// STEP1: parse input
StaticJsonBuffer<200> jsonBuffer1;
JsonObject& inputObject = jsonBuffer1.parseObject(inputJson);
...etc...
// STEP2: generate output
StaticJsonBuffer<200> jsonBuffer2;
JsonObject& outputObject = jsonBuffer2.createObject();
outputObject["hello"] = inputObject["world"];
4. 为什么不要去用一个全局的JsonBuffer?
- 具体可以参考 wiki。
- 博主认为最重要的原因还是一般我们用完json就应该释放掉它,全局jsonbuffer会一直占用着内存空间。
????接下来,看看JsonBuffer的一些常用方法:
3.1.1.1 clear —— 重置内存指针,复用内存空间,慎用
函数说明:
/**
* 重置内存指针,复用内存空间,慎用
*/
void clear();
例子说明:
StaticJsonBuffer<200> jb;
JsonObject& obj1 = jb.parseObject(json1);
// we can use obj1 here...
jb.clear();
// now obj1 is dangling!!!
// ...but we can reuse the JsonBuffer
JsonObject& obj2 = jb.parseObject(json2);
注意:
- 重要说三遍,慎用,慎用,慎用;
- 一旦你调用 JsonBuffer::clear(),所有之前分配的jsonobject或者jsonbuffer都会变成无效;
3.1.1.2 createArray —— 创建空json数组,并为它分配内存空间
函数说明:
/**
* 创建空json数组,并为它分配内存空间
* @return json数组地址
* @Note 如果分配失败,会提示分配失败
*/
JsonArray& createArray();
例子说明:
StaticJsonBuffer<200> jsonBuffer;
JsonArray& array = jsonBuffer.createArray();
array.add("hello");
array.add("world");
3.1.1.3 createObject —— 创建空json对象,并为它分配内存空间
函数说明:
/**
* 创建空json对象,并为它分配内存空间
* @return json对象地址
* @Note 如果分配失败,会提示分配失败
*/
JsonObject createObject();
例子说明:
StaticJsonBuffer<200> jsonBuffer;
JsonObject& object = jsonBuffer.createObject();
object["hello"] = "world";
3.1.1.4 parse —— 解析json(数组或者对象)字符串
函数说明:
/**
* 解析json(数组或者对象)字符串
* @param json json字符串
* @param nestingLimit json深度限制
* @return jsonVariant对象
* @Note 此方法用于不可预知json格式的前提下使用的
*/
// The first overload, which accepts a modifiable array of chars, is the most efficient
// since it allows the zero-copy feature.
JsonVariant parse(char* json, uint8_t nestingLimit=10);
// The following overloads, which accept read-only strings, require a bigger JsonBuffer
// because parts of the JSON input has to be copied.
JsonVariant parse(const char* json, uint8_t nestingLimit=10);
JsonVariant parse(const String& json, uint8_t nestingLimit=10);
JsonVariant parse(const std::string& json, uint8_t nestingLimit=10);
JsonVariant parse(const __FlashStringHelper* json, uint8_t nestingLimit=10);
// The two last overloads, which accept input streams, make copy of the input too.
JsonVariant parse(Stream& json, uint8_t nestingLimit=10);
JsonVariant parse(std::istream& json, uint8_t nestingLimit=10);
例子说明:
char json[] = "[\"hello\",\"world\"]";
StaticJsonBuffer<200> jsonBuffer;
JsonVariant variant = jsonBuffer.parse(json);
if (variant.is<JsonArray>()) // true in this example
{
JsonArray& array = variant;
const char* hello = array[0];
const char* world = array[1];
}
3.1.1.5 parseArray —— 解析json数组字符串
函数说明:
/**
* 解析json数组字符串
* @param json json字符串
* @param nestingLimit json深度限制
* @return jsonArray对象
* @Note 此方法用于预知json格式是jsonArray的前提下使用的
*/
// The first overload, which accepts a modifiable array of chars, is the most efficient
// since it allows the zero-copy feature.
JsonArray& parseArray(char* json, uint8_t nestingLimit=10);
// The following overloads, which accept read-only strings, require a bigger JsonBuffer
// because parts of the JSON input has to be copied.
JsonArray& parseArray(const char* json, uint8_t nestingLimit=10);
JsonArray& parseArray(const String& json, uint8_t nestingLimit=10);
JsonArray& parseArray(const std::string& json, uint8_t nestingLimit=10);
JsonArray& parseArray(const __FlashStringHelper* json, uint8_t nestingLimit=10);
// The two last overloads, which accept input streams, make copy of the input too.
JsonArray& parseArray(Stream& json, uint8_t nestingLimit=10);
JsonArray& parseArray(std::istream& json, uint8_t nestingLimit=10);
例子说明:
char json[] = "[\"hello\",\"world\"]";
StaticJsonBuffer<200> jsonBuffer;
JsonArray& array = jsonBuffer.parseArray(json);
const char* hello = array[0];
const char* world = array[1];
3.1.1.6 parseObject —— 解析json对象字符串
函数说明:
/**
* 解析json对象字符串
* @param json json字符串
* @param nestingLimit json深度限制
* @return json对象
* @Note 此方法用于预知json格式是jsonObject的前提下使用的
*/
// The first overload, which accepts a modifiable array of chars, is the most efficient
// since it allows the zero-copy feature.
JsonObject& parseObject(char* json, uint8_t nestingLimit=10);
// The following overloads, which accept read-only strings, require a bigger JsonBuffer
// because parts of the JSON input has to be copied.
JsonObject& parseObject(const char* json, uint8_t nestingLimit=10);
JsonObject& parseObject(const String& json, uint8_t nestingLimit=10);
JsonObject& parseObject(const std::string& json, uint8_t nestingLimit=10);
JsonObject& parseObject(const __FlashStringHelper* json, uint8_t nestingLimit=10);
// The two last overloads, which accept input streams, make copy of the input too.
JsonObject& parseObject(Stream& json, uint8_t nestingLimit=10);
JsonObject& parseObject(std::istream& json, uint8_t nestingLimit=10);
例子说明:
char json[] = "{\"hello\":\"world\"}";
StaticJsonBuffer<200> jsonBuffer;
JsonObject& object = jsonBuffer.parseObject(json);
const char* world = object["hello"];
3.1.1.7 size —— JsonBuffer当前已用大小
函数说明:
/**
* JsonBuffer当前已用大小
* @return 当前已用大小
*/
size_t size() const;
例子说明:
StaticJsonBuffer<200> jsonBuffer;
Serial.println(jsonBuffer.size());
jsonBuffer.createObject();
Serial.println(jsonBuffer.size());
jsonBuffer.createArray();
Serial.println(jsonBuffer.size());
在8位单片机中会打印:
0
4
8
3.1.2 JsonObject
????在JsonBuffer所构造出来的内存空间中,Json对象的入口就是JsonObject。
????让我们看看它的常用操作方法:
3.1.2.1 begin / end —— 返回一个迭代器,可用于对象中的所有键值对
函数说明:
/**
* 返回一个迭代器,可用于对象中的所有键值对
* @return iterator iterator包括key和value
*/
JsonObject::iterator begin();
JsonObject::iterator end();
JsonObject::const_iterator begin() const;
JsonObject::const_iterator end() const;
例子说明:
char json[] = "{\"first\":\"hello\",\"second\":\"world\"}";
DynamicJsonBuffer jsonBuffer;
JsonObject& root = jsonBuffer.parseObject(json);
// using C++11 syntax (preferred):
for (auto kv : root) {
Serial.println(kv.key);
Serial.println(kv.value.as<char*>());
}
// using C++98 syntax (for older compilers):
for (JsonObject::iterator it=root.begin(); it!=root.end(); ++it) {
Serial.println(it->key);
Serial.println(it->value.as<char*>());
}
测试结果:
first
hello
second
world
3.1.2.2 containsKey —— 判断对象是否包含某一个key
函数说明:
/**
* 判断对象是否包含某一个key
* @param key key名字
* @return bool
*/
bool containsKey(const char* key) const;
bool containsKey(const String& key) const;
bool containsKey(const std::string& key) const;
bool containsKey(const __FlashStringHelper& key) const;
例子说明:
StaticJsonBuffer<256> jsonBuffer;
JsonObject& root = jsonBuffer.createObject();
root["city"] = "Paris";
bool hasCity = root.containsKey("city"); // true
bool hasCountry = root.containsKey("country"); // false
注意:
- json库的开发者不建议使用该方法,因为就算没有值也会返回一个空值。库开发者给了例子建议:
if (root.containsKey("error"))
{
const char* error = root["error"]
Serial.println(error);
return;
}
可以改成:
JsonVariant error = root["error"];
if (error.success())
{
Serial.println(error.as<char*>());
return;
}
或者更加简单快速的方法:
const char* error = root["error"];
if (error)
{
Serial.println(error);
return;
}
3.1.2.3 createNestedArray —— 在当前对象中添加子key,子value为json数组
函数说明:
/**
* 在当前对象中添加子key,子value为json数组
* @param key key名字
* @return JsonArray
*/
JsonArray& createNestedArray(const char* key) const;
JsonArray& createNestedArray(char* key) const; // see Remarks
JsonArray& createNestedArray(const String& key) const; // see Remarks
JsonArray& createNestedArray(const std::string& key) const; // see Remarks
JsonArray& createNestedArray(const __FlashStringHelper* key) const; // see Remarks
例子说明:
StaticJsonBuffer<256> jsonBuffer;
JsonObject& root = jsonBuffer.createObject();
root["status"] = "on";
JsonArray& levels = root.createNestedArray("levels");
levels.add(10);
levels.add(30);
root.prettyPrintTo(Serial);
打印结果:
{
"status": "on",
"levels": [
10,
20
]
}
3.1.2.4 createNestedObject —— 在当前对象中添加子key,子value为json对象
函数说明:
/**
* 在当前对象中添加子key,子value为json对象
* @param key key名字
* @return JsonObject对象
*/
JsonObject& createNestedObject(const char* key) const;
JsonObject& createNestedObject(char* key) const; // see Remarks
JsonObject& createNestedObject(const String& key) const; // see Remarks
JsonObject& createNestedObject(const std::string& key) const; // see Remarks
JsonObject& createNestedObject(const __FlashStringHelper* key) const; // see Remarks
例子说明:
StaticJsonBuffer<256> jsonBuffer;
JsonObject& root = jsonBuffer.createObject();
root["city"] = "Paris";
JsonObject& weather = root.createNestedObject("weather");
weather["temp"] = 14.2;
weather["cond"] = "cloudy";
root.prettyPrintTo(Serial);
打印结果:
{
"city": "Paris",
"weather": {
"temp": 14.20,
"cond": "cloudy"
}
}
3.1.2.5 get —— 获取某一个key的值,T表示值类型
函数说明:
/**
* 获取某一个key的值,T表示值类型
* @param key key名字
* @return 值
*/
bool get<bool> (TString key) const;
const char* get<const char*> (TString key) const;
double get<double> (TString key) const;
float get<float> (TString key) const;
JsonVariant get<JsonVariant> (TString key) const;
signed char get<signed char> (TString key) const;
signed int get<signed int> (TString key) const;
signed long get<signed long> (TString key) const;
signed short get<signed short> (TString key) const;
std::string get<std::string> (TString key) const;
String get<String> (TString key) const;
unsigned char get<unsigned char> (TString key) const;
unsigned int get<unsigned int> (TString key) const;
unsigned long get<unsigned long> (TString key) const;
unsigned short get<unsigned short> (TString key) const;
例子说明:
char json[] = "{\"pi\":3.14}";
StaticJsonBuffer<256> jsonBuffer;
JsonObject& object = jsonBuffer.parseObject(json);
float pi = object.get<float>("pi"); // template version of get()
const char* value2 = object.get<const char*>("toto"); // returns NULL
3.1.2.6 is —— 判断某一个key的值是否是T类型
函数说明:
/**
* 判断某一个key的值是否是T类型
* @param key key名字
* @return bool
* true 为T类型
* false 不是T类型
*/
bool is<bool> (TString key) const;
bool is<const char*> (TString key) const;
bool is<char*> (TString key) const;
bool is<double> (TString key) const;
bool is<float> (TString key) const;
bool is<signed char> (TString key) const;
bool is<signed int> (TString key) const;
bool is<signed long> (TString key) const;
bool is<signed short> (TString key) const;
bool is<unsigned char> (TString key) const;
bool is<unsigned int> (TString key) const;
bool is<unsigned long> (TString key) const;
bool is<unsigned short> (TString key) const;
bool is<signed long long> (TString key) const; // <- may require ARDUINOJSON_USE_LONG_LONG
bool is<unsigned long long>(TString key) const; // <- may require ARDUINOJSON_USE_LONG_LONG
bool is<JsonArray> (TString key) const;
bool is<JsonObject> (TString key) const;
例子说明:
char json[] = "{\"name\":\"toto\",\"pi\":3.14}";
StaticJsonBuffer<256> jsonBuffer;
JsonObject& obj = jsonBuffer.parseObject(json);
bool nameIsString = obj.is<char*>("name"); // <- true
bool piIsFloat = obj.is<float>("pi"); // <- true
// but we could also use JsonVariant.is<T>(), like that:
nameIsString = obj["name"].is<char*>(); // <- true
piIsFloat = obj["pi"].is<float>(); // <- true
3.1.2.7 measureLength —— 计算当前对象通过printTo打印出来的长度
函数说明:
/**
* 计算当前对象通过printTo打印出来的长度
* @return size_t 长度值
* @Note 跟 JsonObject::printTo() 关联,此方法通常用于http协议中的 Content-Length头
*/
size_t measureLength() const
例子说明:
// Send headers
client.println("Content-Type: application/json");
client.print("Content-Length: ");
client.println(root.measureLength());
// Terminate headers
client.println();
// Send body
root.printTo(client);
3.1.2.8 measurePrettyLength —— 计算当前对象通过prettyPrintTo打印出来的长度
函数说明:
/**
* 计算当前对象通过prettyPrintTo打印出来的长度
* @return size_t 长度值
* @Note 跟 JsonObject::prettyPrintTo() 关联,此方法通常用于http协议中的 Content-Length头
*/
size_t measurePrettyLength() const
例子说明:
// Send headers
client.println("Content-Type: application/json");
client.print("Content-Length: ");
client.println(root.measurePrettyLength());
// Terminate headers
client.println();
// Send body
root.prettyPrintTo(client);
3.1.2.9 prettyPrintTo —— 格式化输出json字符串
函数说明:
/**
* 格式化输出json字符串
* @param buffer 内容输出到内存区
* @param size 内存区的大小
* @param Print 打印流 比如 Serial
* @param String 打印到字符串
* @return 返回已写大小
*/
size_t prettyPrintTo(char* buffer, size_t size) const;
size_t prettyPrintTo(char buffer[size]) const;
size_t prettyPrintTo(Print &) const;
size_t prettyPrintTo(String &) const;
size_t prettyPrintTo(std::string &) const;
例子说明:
StaticJsonBuffer<200> jsonBuffer;
JsonObject& object = jsonBuffer.createObject();
object["hello"] = "world";
object.prettyPrintTo(Serial);
打印结果:
{
"hello": "world"
}
3.1.2.10 printTo —— 压缩式输出json字符串
函数说明:
/**
* 压缩式输出json字符串
* @param buffer 内容输出到内存区
* @param size 内存区的大小
* @param Print 打印流 比如 Serial
* @param String 打印到字符串
* @return 返回已写大小
*/
size_t printTo(char* buffer, size_t size) const;
size_t printTo(char buffer[size]) const;
size_t printTo(Print &) const;
size_t printTo(String &) const;
size_t printTo(std::string &) const;
例子说明:
StaticJsonBuffer<200> jsonBuffer;
JsonObject& object = jsonBuffer.createObject();
object["hello"] = "world";
object.printTo(Serial);
打印结果:
{"hello":"world"}
注意:
- 该方法属于压缩式输出,可以节省空间;
3.1.2.11 remove —— 移除特定key和value
函数说明:
/**
* 移除特定key和value
* @param key key名
*/
void remove(const char* key);
void remove(const String& key);
void remove(const std::string& key);
void remove(const __FlashStringHelper* key);
例子说明:
JsonObject& object = jsonBuffer.createObject();
object["A"] = 1;
object["B"] = 2;
object["C"] = 3;
object.remove("B");
object.printTo(Serial);
打印结果:
{"A":1,"C":3}
注意:
- 该方法只会移除key-value,但是并不会释放key-value对应的jsonbuffer空间,也不建议在循环中同时add和remove key-value;
3.1.2.12 set —— 设置特定key的值
函数说明:
/**
* 设置特定key的值
* @param key key名
* @param value 值
* @return bool 是否设置成功
*/
bool set(TString key, bool value);
bool set(TString key, float value);
bool set(TString key, double value);
bool set(TString key, signed char value);
bool set(TString key, signed long value);
bool set(TString key, signed int value);
bool set(TString key, signed short value);
bool set(TString key, unsigned char value);
bool set(TString key, unsigned long value);
bool set(TString key, unsigned int value);
bool set(TString key, unsigned short value);
bool set(TString key, const char *value);
bool set(TString key, char *value); // see Remarks
bool set(TString key, const String &value); // see Remarks
bool set(TString key, const std::string &value); // see Remarks
bool set(TString key, const __FlashStringHelper* value); // see Remarks
bool set(TString key, JsonArray &array);
bool set(TString key, JsonObject &object);
bool set(TString key, const JsonVariant &value);
例子说明:
StaticJsonBuffer<200> jsonBuffer;
JsonObject& object = jsonBuffer.createObject();
object.set("hello","world");
object.printTo(Serial);
打印结果:
{"hello":"world"}
3.1.2.13 size —— 返回对象键值对的个数
函数说明:
/**
* 返回对象键值对的个数
* @return size_t 个数
*/
size_t size() const;
例子说明:
JsonObject& object = jsonBuffer.createObject();
object["hello"] = "world";
Serial.println(object.size()); // 1
3.1.2.14 operator[] —— get/set的快捷方式
函数说明:
/**
* get/set的快捷方式
*/
JsonVariant& operator[](const char* key);
JsonVariant& operator[](char* key); // see Remarks
JsonVariant& operator[](const String& key); // see Remarks
JsonVariant& operator[](const std::string& key); // see Remarks
JsonVariant& operator[](const __FlashStringHelper* key); // see Remarks
const JsonVariant& operator[](const char* key) const;
const JsonVariant& operator[](const String& key) const;
const JsonVariant& operator[](const std::string& key) const;
const JsonVariant& operator[](const __FlashStringHelper* key) const;
例子说明:
JsonObject& object = jsonBuffer.createObject();
object["hello"] = "world";
const char* world = object["hello"];
3.1.2.15 success —— 判断对象是否是有效
函数说明:
/**
* 判断对象是否是有效(解析或者分配内存)
* @return bool
*/
bool success() const;
例子说明:
//Example 1: parsing success:
StaticJsonBuffer<200> jsonBuffer;
JsonObject& object = jsonBuffer.parseObject("{\"hello\":\"world\"}");
Serial.println(object.success()); // true
//Example 2: parsing failure:
StaticJsonBuffer<200> jsonBuffer;
JsonObject& object = jsonBuffer.parseObject("[\"hello\",\"world\"]");
Serial.println(object.success()); // false
//Example 3: allocation success:
StaticJsonBuffer<200> jsonBuffer;
JsonObject& object = jsonBuffer.createObject();
Serial.println(object.success()); // true
//Example 4: allocation failure:
StaticJsonBuffer<1> jsonBuffer;
JsonObject& object = jsonBuffer.createObject();
Serial.println(object.success()); // false
3.1.3 JsonArray
????在JsonBuffer所构造出来的内存空间中,Json数组的入口就是JsonArray。
????让我们看看它的常用操作方法:
3.1.3.1 add —— 往数组中加入value
函数说明:
/**
* 往数组中加入value
* @param value 值
* @return bool 是否添加成功,如果返回false一般都是jsonbuffer没有足够的空间
*/
bool add(bool value);
bool add(float value);
bool add(double value);
bool add(signed char value);
bool add(signed long value);
bool add(signed int value);
bool add(signed short value);
bool add(unsigned char value);
bool add(unsigned long value);
bool add(unsigned int value);
bool add(unsigned short value);
bool add(const char *value);
bool add(char *value); // see Remarks
bool add(const String &value); // see Remarks
bool add(const std::string &value); // see Remarks
bool add(const __FlashStringHelper *value); // see Remarks
bool add(JsonArray &array);
bool add(JsonObject &object);
bool add(const JsonVariant &variant);
例子说明:
StaticJsonBuffer<200> jsonBuffer;
JsonArray& array = jsonBuffer.createArray();
array.add("hello");
array.add(3.14156);
array.printTo(Serial);
打印结果:
["hello",3.14156]
3.1.3.2 begin/end —— 返回一个迭代器,可用于数组中的所有对象
函数说明:
/**
* 返回一个迭代器,可用于数组中的所有对象
* @return iterator
*/
JsonObject::iterator begin();
JsonObject::iterator end();
JsonObject::const_iterator begin() const;
JsonObject::const_iterator end() const;
例子说明:
char json[] = "[\"one\",\"two\",\"three\"]";
DynamicJsonBuffer jsonBuffer;
JsonArray& arr = jsonBuffer.parseArray(json);
// using C++11 syntax (preferred):
for (auto value : arr) {
Serial.println(value.as<char*>());
}
// using C++98 syntax (for older compilers):
for (JsonArray::iterator it=arr.begin(); it!=arr.end(); ++it) {
Serial.println(it->as<char*>());
}
打印结果:
one
two
three
3.1.3.3 copyFrom —— 把c数组转成json数组
函数说明:
/**
* 把c数组转成json数组
* @param array 数组
* @param len 数组大小
*/
// 1D arrays
JsonArray::copyFrom(T array[len]);
JsonArray::copyFrom(T* array, size_t len);
// 2D arrays
JsonArray::copyFrom(T array[][]);
例子说明:
int values[] = {1, 2, 3};
StaticJsonBuffer<200> jsonBuffer;
JsonArray& array = jsonBuffer.createArray();
array.copyFrom(values);
array.printTo(Serial);
打印结果:
[1,2,3]
3.1.3.4 copyTo —— 把json数组转成c数组
函数说明:
/**
* 把json数组转成c数组
* @param array 数组
*/
JsonArray::copyTo(int array[]);
JsonArray::copyTo(double array[]);
JsonArray::copyTo(const char* array[]);
例子说明:
int values[3];
StaticJsonBuffer<200> jsonBuffer;
JsonArray& array = jsonBuffer.parseArray("[1,2,3]");
array.copyTo(values);//现在values变成1,2,3
3.1.3.5 createNestedArray —— 添加json数组
函数说明:
/**
* 添加json数组
* @return JsonArray json数组
*/
JsonArray& createNestedArray();
例子说明:
StaticJsonBuffer<200> jsonBuffer;
JsonArray& array = jsonBuffer.createArray();
array.add("hello");
JsonArray& nested = array.createNestedArray();
nested.add("world");
array.printTo(Serial);
打印结果:
["hello",["world"]]
3.1.3.6 createNestedObject —— 添加json对象
函数说明:
/**
* 添加json对象
* @return JsonObject json对象
*/
JsonObject& createNestedObject();
例子说明:
StaticJsonBuffer<200> jsonBuffer;
JsonArray& array = jsonBuffer.createArray();
JsonObject& nested = array.createNestedObject();
nested["hello"] = "world";
array.printTo(Serial);
打印结果:
[{"hello":"world"}]
3.1.3.7 get —— 获取具体index的值
函数说明:
/**
* 获取具体index的值
* @param index 索引
* @return T 返回索引对应的值
*/
bool get<bool> (size_t index) const;
const char* get<const char*> (size_t index) const;
const char* get<char*> (size_t index) const;
double get<double> (size_t index) const;
float get<float> (size_t index) const;
signed char get<signed char> (size_t index) const;
signed int get<signed int> (size_t index) const;
signed long get<signed long> (size_t index) const;
signed short get<signed short> (size_t index) const;
unsigned char get<unsigned char> (size_t index) const;
unsigned int get<unsigned int> (size_t index) const;
unsigned long get<unsigned long> (size_t index) const;
unsigned short get<unsigned short> (size_t index) const;
JsonVariant get<JsonVariant> (size_t index) const;
std::string get<std::string> (size_t index) const;
String get<String> (size_t index) const;
例子说明:
char json[] = "[1,3.14]";
StaticJsonBuffer<256> jsonBuffer;
JsonArray& array = jsonBuffer.parseArray(json);
int value0 = array.get(0); // implicit cast of the JsonVariant
float value1 = array.get<float>(1); // template version of get()
const char* value2 = array.get(2); // returns NULL
注意:
- integer默认值是0
- double默认值是0.0
- char* 默认是是NULL
3.1.3.8 is —— 判断具体index的值是否为T类型
函数说明:
/**
* 判断具体index的值是否为T类型
* @return bool 是否是目标类型
*/
bool is<bool> (size_t index) const;
bool is<const char*> (size_t index) const;
bool is<char*> (size_t index) const;
bool is<double> (size_t index) const;
bool is<float> (size_t index) const;
bool is<signed char> (size_t index) const;
bool is<signed int> (size_t index) const;
bool is<signed long> (size_t index) const;
bool is<signed short> (size_t index) const;
bool is<unsigned char> (size_t index) const;
bool is<unsigned int> (size_t index) const;
bool is<unsigned long> (size_t index) const;
bool is<unsigned short> (size_t index) const;
bool is<signed long long> (size_t index) const; // <- may require ARDUINOJSON_USE_LONG_LONG
bool is<unsigned long long>(size_t index) const; // <- may require ARDUINOJSON_USE_LONG_LONG
bool is<JsonArray> (size_t index) const;
bool is<JsonObject> (size_t index) const;
例子说明:
char json[] = "[\"pi\",3.14]";
StaticJsonBuffer<256> jsonBuffer;
JsonArray& array = jsonBuffer.parseArray(json);
bool firstIsString = array.is<char*>(0); // <- true
bool secondIsFloat = array.is<float>(1); // <- true
// but we could also use JsonVariant.is<T>(), like that:
firstIsString = array[0].is<char*>(); // <- true
secondIsFloat = array[1].is<float>(); // <- true
3.1.3.9 measureLength —— 计算当前json数组通过printTo打印出来的长度
函数说明:
/**
* 计算当前json数组通过printTo打印出来的长度
* @return size_t 长度值
* @Note 跟 JsonArray::printTo() 关联,此方法通常用于http协议中的 Content-Length头
*/
size_t measureLength() const
例子说明:
// Send headers
client.println("Content-Type: application/json");
client.print("Content-Length: ");
client.println(root.measureLength());
// Terminate headers
client.println();
// Send body
root.printTo(client);
3.1.3.10 measurePrettyLength —— 计算当前json数组通过prettyPrintTo打印出来的长度
函数说明:
/**
* 计算当前json数组通过prettyPrintTo打印出来的长度
* @return size_t 长度值
* @Note 跟 JsonArray::prettyPrintTo() 关联,此方法通常用于http协议中的 Content-Length头
*/
size_t measurePrettyLength() const
例子说明:
// Send headers
client.println("Content-Type: application/json");
client.print("Content-Length: ");
client.println(root.measurePrettyLength());
// Terminate headers
client.println();
// Send body
root.prettyPrintTo(client);
3.1.3.11 prettyPrintTo —— 格式化输出json数组字符串
函数说明:
/**
* 格式化输出json数组字符串
* @param buffer 内容输出到内存区
* @param size 内存区的大小
* @param Print 打印流 比如 Serial
* @param String 打印到字符串
* @return 返回已写大小
*/
size_t prettyPrintTo(char* buffer, size_t size) const;
size_t prettyPrintTo(char buffer[size]) const;
size_t prettyPrintTo(Print &) const;
size_t prettyPrintTo(String &) const;
size_t prettyPrintTo(std::string &) const;
例子说明:
StaticJsonBuffer<200> jsonBuffer;
JsonArray& array = jsonBuffer.createArray();
array.add("hello");
array.add("world");
array.prettyPrintTo(Serial);
打印结果:
[
"hello",
"world"
]
3.1.3.12 printTo —— 压缩式输出json数组字符串
函数说明:
/**
* 压缩式输出json数组字符串
* @param buffer 内容输出到内存区
* @param size 内存区的大小
* @param Print 打印流 比如 Serial
* @param String 打印到字符串
* @return 返回已写大小
*/
size_t printTo(char* buffer, size_t size) const;
size_t printTo(char buffer[size]) const;
size_t printTo(Print &) const;
size_t printTo(String &) const;
size_t printTo(std::string &) const;
例子说明:
StaticJsonBuffer<200> jsonBuffer;
JsonArray& array = jsonBuffer.createArray();
array.add("hello");
array.add("world");
array.printTo(Serial);
打印结果:
["hello","world"]
注意:
- 该方法属于压缩式输出,可以节省空间;
3.1.3.13 remove —— 移除某一个index位置的元素
函数说明:
/**
* 移除某一个index位置的元素
* @param index 索引
*/
void remove(size_t index);
例子说明:
JsonArray& array = jsonBuffer.createArray();
array.add("A");
array.add("B");
array.add("C");
array.remove(1);
array.printTo(Serial);
打印结果:
["A","C"]
注意:
- 该方法只会移除索引对应的value,但是并不会释放对应的jsonbuffer空间,也不建议在循环中同时add和remove;
3.1.3.14 set —— 设置某一个index位置的值
函数说明:
/**
* 设置某一个index位置的值
* @param index 索引位置
* @param value 值
* @return bool 是否设置成功
*/
bool set(size_t index, bool value);
bool set(size_t index, double value);
bool set(size_t index, float value);
bool set(size_t index, signed char value);
bool set(size_t index, signed int value);
bool set(size_t index, signed long value);
bool set(size_t index, signed short value);
bool set(size_t index, unsigned char value);
bool set(size_t index, unsigned int value);
bool set(size_t index, unsigned long value);
bool set(size_t index, unsigned short value);
bool set(size_t index, const char *value);
bool set(size_t index, char *value); // see Remarks
bool set(size_t index, const std::string &value); // see Remarks
bool set(size_t index, const String &value); // see Remarks
bool set(size_t index, const __FlashStringHelper *value); // see Remarks
bool set(size_t index, JsonArray &array);
bool set(size_t index, JsonObject &object);
bool set(size_t index, const JsonVariant &value);
例子说明:
StaticJsonBuffer<200> jsonBuffer;
JsonArray& array = jsonBuffer.createArray();
// increase the size of the array
array.add(666);
array.add(666);
// replace the values
array.set(0, "hello");
array.add(1, 3.14156);
// serialize
array.printTo(Serial);
打印结果:
["hello",3.14156]
3.1.3.15 size —— 返回json数组元素的个数
函数说明:
/**
* 返回json数组元素的个数
* @return size_t 个数
*/
size_t size() const;
例子说明:
JsonArray& array = jsonBuffer.createArray();
array.add("hello");
array.add("world");
Serial.println(array.size()); // 2
3.1.3.16 operator[] —— get/set 快捷快捷方式
函数说明:
/**
* get/set的快捷方式
*/
JsonVariant& operator[](size_t index);
const JsonVariant& operator[](size_t index) const;
例子说明:
JsonArray& array = jsonBuffer.createArray();
array.add(42);
int value = array[0];
array[0] = 666;
3.1.3.17 success —— 判断json数组是否成功分配内存或者解析
函数说明:
/**
* 判断json数组是否成功分配内存或者解析
* @return bool
*/
bool success() const;
例子说明:
//Example 1: parsing success:
StaticJsonBuffer<200> jsonBuffer;
JsonArray& array = jsonBuffer.parseArray("[1,2]");
Serial.println(array.success()); // true
//Example 2: parsing failure:
StaticJsonBuffer<200> jsonBuffer;
JsonArray& array = jsonBuffer.parseArray("{1,2}");
Serial.println(array.success()); // false
//Example 3: allocation success:
StaticJsonBuffer<200> jsonBuffer;
JsonArray& array = jsonBuffer.createArray();
Serial.println(array.success()); // true
//Example 4: allocation failure:
StaticJsonBuffer<1> jsonBuffer;
JsonArray& array = jsonBuffer.createArray();
Serial.println(array.success()); // false
3.1.4 编码Json字符串
????讲完理论知识,我们开始用具体例子来验证。
实验材料:
- Arduino板子,博主这里用Mega2560
例子代码:
/**
* 构造json例子
* @author 单片机菜鸟
* @date 2019/06/01
*/
#include <ArduinoJson.h>
void setup() {
Serial.begin(115200);
while (!Serial) continue;
// Json对象对象树的内存工具 静态buffer
// 200 是大小 如果这个Json对象更加复杂,那么就需要根据需要去增加这个值.
StaticJsonBuffer<200> jsonBuffer;
// StaticJsonBuffer 在栈区分配内存 它也可以被 DynamicJsonBuffer(内存在堆区分配) 代替
// DynamicJsonBuffer jsonBuffer;
//创建最外层的json对象 —— root对象,顶节点
JsonObject& root = jsonBuffer.createObject();
//给最外层json对象添加属性
root["sensor"] = "gps";
root["time"] = 1351824120;
//在root对象中加入data数组
JsonArray& data = root.createNestedArray("data");
data.add(48.756080);
data.add(2.302038);
//在串口中打印,printTo方法不会格式化json
root.printTo(Serial);
// This prints:
// {"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}
Serial.println();
//在串口中打印,prettyPrintTo方法会格式化json
root.prettyPrintTo(Serial);
// This prints:
// {
// "sensor": "gps",
// "time": 1351824120,
// "data": [
// 48.756080,
// 2.302038
// ]
// }
}
void loop() {
// not used in this example
}
运行结果:
3.1.5 解码Json字符串
实验材料:
- Arduino板子,博主这里用Mega2560
例子代码:
/**
* 解码Json字符串
* @author 单片机菜鸟
* @date 2019/06/02
*/
#include <ArduinoJson.h>
void setup() {
Serial.begin(115200);
while (!Serial) continue;
// Json对象对象树的内存工具 静态buffer
// 200 是大小 如果这个Json对象更加复杂,那么就需要根据需要去增加这个值.
StaticJsonBuffer<200> jsonBuffer;
// StaticJsonBuffer 在栈区分配内存 它也可以被 DynamicJsonBuffer(内存在堆区分配) 代替
// DynamicJsonBuffer jsonBuffer;
char json[] =
"{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}";
JsonObject& root = jsonBuffer.parseObject(json);
// Test if parsing succeeds.
if (!root.success()) {
Serial.println("parseObject() failed");
return;
}
// Fetch values.
//
// Most of the time, you can rely on the implicit casts.
// In other case, you can do root["time"].as<long>();
const char* sensor = root["sensor"];
long time = root["time"];
double latitude = root["data"][0];
double longitude = root["data"][1];
// Print values.
Serial.println(sensor);
Serial.println(time);
Serial.println(latitude, 6);
Serial.println(longitude, 6);
}
void loop() {
// not used in this example
}
注意:
- 解析失败通常有如下三个原因:
- Json字符串非法(格式不对)
- Json字符串产生对象
- JsonBuffer太小
3.2 ArduinoJson V5版本编译配置
3.2.1 ARDUINOJSON_VERSION —— 当前ArduinoJson库的具体版本
比如,如果开发者当前版本为 5.13.2,那么就会有:
#define ARDUINOJSON_VERSION "5.13.2" //完整版本号
#define ARDUINOJSON_VERSION_MAJOR 5 //大版本
#define ARDUINOJSON_VERSION_MINOR 13 //小版本
#define ARDUINOJSON_VERSION_REVISION 2 //小小版本
我们可以通过Serial打印版本号:
Serial.print("Using ArduinoJson version ");
Serial.println(ARDUINOJSON_VERSION);
通过它,我们可以做一些事情,比如:
- 判断是否安装了ArduinoJson库
#ifndef ARDUINOJSON_VERSION
#error ArduinoJson not found, please include ArduinoJson.h in your .ino file
#endif
- 判断某一个版本
#if ARDUINOJSON_VERSION_MAJOR!=5 || ARDUINOJSON_VERSION_MINOR<13
#error ArduinoJson 5.13+ is required
#endif
3.2.2 ARDUINOJSON_DEFAULT_NESTING_LIMIT —— Json数据的嵌套层数
- 该选项用来配置 JsonBuffer::parseArray() 和 JsonBuffer::parseObject()的最大解析层数
- ARDUINO 上默认是10层,一般来说不用改
3.2.3 ARDUINOJSON_ENABLE_ARDUINO_STRING —— 是否使能Arduino字符串功能
- 默认true,建议不要动它
3.2.4 ARDUINOJSON_ENABLE_PROGMEM —— 是否使能Arduino F函数功能
- 默认true,建议不要动它
3.2.5 ARDUINOJSON_ENABLE_PROGMEM —— 是否使能Arduino F函数功能
- 默认true,建议不要动它
4.总结
????总体上,Json属于一种数据交换格式,不会说太难。本篇属于简单介绍了ArduinoJson V5库的使用,更加复杂的使用请直接去到ArduinoJson的主页去查阅。
原文地址:https://www.cnblogs.com/danpianjicainiao/p/11048675.html