玩转ArduinoJson库 V5版本

Posted danpianjicainiao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了玩转ArduinoJson库 V5版本相关的知识,希望对你有一定的参考价值。

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的区别?

技术图片

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"];

????看起来没有什么问题,但实际上有访问错误,请看分析:

  1. inputObject是一个json对象的指针,由JsonBuffer管理内存;
  2. clear方法重置了jsonbuffer内存池,运行重新使用inputObject的内存空间;
  3. outputObject对象被创建,其地址和inputObject一样;
  4. 到这一步大家应该知道会发生什么问题了吧,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

注意

  • 解析失败通常有如下三个原因:
  1. Json字符串非法(格式不对)
  2. Json字符串产生对象
  3. 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的主页去查阅。

以上是关于玩转ArduinoJson库 V5版本的主要内容,如果未能解决你的问题,请参考以下文章

ArduinoJson从版本5迁移到版本6对比差异

Arduino ESP8266利用HTTPClient库 获取心知天气请求实例

ESP8266在Arduinojson获取网络数据时防止数据为空

ESP32上手笔记 | 03 -通过HTTP获取天气信息(WiFi+HTTPClient+ArduinoJson)

版本管理·玩转git(日志查看与版本切换)

Arduino ESP8266获取心知天气平台的实时天气数据