diff --git a/Bag-of-Tricks.md b/Bag-of-Tricks.md deleted file mode 100644 index 8c474e6..0000000 --- a/Bag-of-Tricks.md +++ /dev/null @@ -1,435 +0,0 @@ -Here are helper class that can help you add missing features. - -## Look for a nested key - -Suppose we've got this json: - -```json -{"key1":1,"key2":{"subkey1":3,"subkey2":4}} -``` - -And we want to check presence of **subkey1** (or **subkey2**). Using **containsKey** method will not work, since **subkey1** and **subkey2** are nested keys inside **key2** value. This function allows to find key presence even if they are nested inside any key value: - -```c++ -bool containsNestedKey(const JsonObject& obj, const char* key) { - for (const JsonPair& pair : obj) { - if (!strcmp(pair.key, key)) - return true; - - if (containsNestedKey(pair.value.as(), key)) - return true; - } - - return false; -} -``` - -See issue [#322](https://github.com/bblanchon/ArduinoJson/issues/322) - -## Extract an array of integer - -Suppose we have an input like this: - -```json -{"leds":[56,60,46]} -``` - -And we want to get a `int[]` out of it: - -```c++ -#define MAX_LED_COUNT 10 - -int leds[MAX_LED_COUNT]; -int ledCount = root["leds"].asArray().copyTo(leds); -``` - -See issue [#246](https://github.com/bblanchon/ArduinoJson/issues/246) - -## Nested array in a nested array - -Imagine you need to generate the following JSON: - -```json -{ - "value1": "x", - "value2": [ - [ - "Yes", - "No" - ], - [ - "Maybe" - ] - ] -} -``` - -The canonical way to do this is: - -```c++ -JsonObject& root = jsonBuffer.createObject(); - -root["value1"] = "x"; -JsonArray& value2 = root.createNestedArray("value2"); - -JsonArray& yesno = value2.createNestedArray(); -yesno.add("Yes"); -yesno.add("No"); - -JsonArray& maybe = value2.createNestedArray(); -maybe.add("Maybe"); -``` - -It's also possible to create the arrays and then put them in the object: - -```c++ -JsonObject& root = jsonBuffer.createObject(); -JsonObject& value2 = jsonBuffer.createArray(); -JsonObject& yesno = jsonBuffer.createArray(); -JsonObject& maybe = jsonBuffer.createArray(); - -root["value1"] = "x"; -root["value2"] = value2; -value2.add(yesno); -yesno.add("Yes"); -yesno.add("No"); -value2.add(maybe); -maybe.add("Maybe"); -``` - -But it's a little less efficient in term of CPU and memory. - -Lastly, it's possible to manually encode the nested array with an undocumented feature: - -```c++ -JsonObject& root = jsonBuffer.createObject(); -root["value1"] = "x"; -root["value2"] = RawJson("[[\"Yes\",\"No\"],[\"Maybe\"]"); -``` - -See issue [#252](https://github.com/bblanchon/ArduinoJson/issues/252) - -## Merging JSON objects - -Suppose we have three JSON objects like these: - -```c++ -char json1[] = R"({ - "fingerprint": "1234" - })"; - -char json2[] = R"({ - "Trait1":{ - "someValue": "4321" - } - })"; - -char json3[] = R"({ - "Trait2":{ - "anotherValue": "5555" - } - })"; - -JsonObject& jsonObjectRoot = jsonBuffer1.parseObject(json1); -JsonObject& jsonObjectOne = jsonBuffer2.parseObject(json2); -JsonObject& jsonObjectTwo = jsonBuffer3.parseObject(json3); -``` -And we want a JSON that looks like this: - -```json -{ - "fingerprint": "1234", - "SetOfObjects" : { - "Trait1":{ - "someValue": "4321" - }, - "Trait2":{ - "anotherValue": "5555" - } - } -} -``` - -This function allows to merge the JSON objects: - -```c++ -void merge(JsonObject& dest, JsonObject& src) { - for (auto kvp : src) { - dest[kvp.key] = kvp.value; - } -} -``` -Usage: -```c++ -JsonObject& nestedObject = jsonObjectRoot.createNestedObject("SetOfObjects"); -merge(nestedObject, jsonObjectOne); -merge(nestedObject, jsonObjectTwo); -``` - -See issue [#332](https://github.com/bblanchon/ArduinoJson/issues/332) - -## Buffered output - -Here is a proxy that will put bytes in a buffer before actually writing them to the destination: - -```c++ -template -class BufferedPrint : public Print { - public: - BufferedPrint(Print& destination) : _destination(destination), _size(0) {} - - ~BufferedPrint() { flush(); } - - virtual size_t write(uint8_t c) { - _buffer[_size++] = c; - - if (_size + 1 == CAPACITY) { - flush(); - } - } - - void flush() { - _buffer[_size] = '\0'; - _destination.print(_buffer); - _size = 0; - } - - private: - Print& _destination; - size_t _size; - char _buffer[CAPACITY]; -}; -``` - -To use this in your code: - -```c++ -BufferedPrint<256> bufferedPrint(Serial) -root.printTo(bufferedPrint); -``` - -See issue [#166](https://github.com/bblanchon/ArduinoJson/issues/166). - -## Chunked output - -Here is a proxy that allow to get only part of the output: - -```c++ -class ChunkPrint : public Print { - public: - ChunkPrint(Print& destination, size_t from, size_t to) - : _destination(destination), _to_skip(from), _to_write(to - from) {} - - virtual size_t write(uint8_t c) { - if (_to_skip > 0) { - _to_skip--; - } else if (_to_write > 0) { - _to_write--; - return _destination.write(c); - } - return 0; - } - - private: - Print& _destination; - size_t _to_skip; - size_t _to_write; -}; -``` - -To use this in your code: - -```c++ -// print only range [10,20[ -ChunkPrint chunkPrint(Serial,10,20); -root.printTo(chunkPrint); -``` - -See issue [#206](https://github.com/bblanchon/ArduinoJson/issues/206). - -## Render to ESP8266 WiFiClient - -When used on [ESP8266 Arduino](https://github.com/esp8266/Arduino), there is currently not a direct way to render the JSON to WiFiClient, since it does not implement required Print interface. -This utility class serves as an adapter between `Print` and `WiFiClient` classes. Internal buffer is required, otherwise rendering will take several seconds (every byte will be sent as a separate packet). Increase buffer for faster send, if you have spare memory. - -Create this as separate header file `WiFiClientPrint.h` or just include class in your program. - -_Note: You need to call either `flush()` or `stop()` manually after printTo._ - -```c++ -#pragma once - -#include -#include - -template -class WiFiClientPrint : public Print -{ - public: - WiFiClientPrint(WiFiClient client) - : _client(client), - _length(0) - { - } - - ~WiFiClientPrint() - { -#ifdef DEBUG_ESP_PORT - // Note: This is manual expansion of assertion macro - if (_length != 0) { - DEBUG_ESP_PORT.printf("\nassertion failed at " __FILE__ ":%d: " "_length == 0" "\n", __LINE__); - // Note: abort() causes stack dump and restart of the ESP - abort(); - } -#endif - } - - virtual size_t write(uint8_t c) override - { - _buffer[_length++] = c; - if (_length == BUFFER_SIZE) { - flush(); - } - } - - void flush() - { - if (_length != 0) { - _client.write((const uint8_t*)_buffer, _length); - _length = 0; - } - } - - void stop() - { - flush(); - _client.stop(); - } - - private: - WiFiClient _client; - uint8_t _buffer[BUFFER_SIZE]; - size_t _length; -}; -``` - -Usage (typically inside `ESP8266WebServer` handler): -```c++ -// #include "WiFiClientPrint.h" - -// ESP8266WebServer _server; -// JsonObject json; -_server.setContentLength(json.measureLength()); -_server.send(200, "application/json", ""); - -WiFiClientPrint<> p(_server.client()); -json.printTo(p); -p.stop(); // Calls p.flush() and WifiClient.stop() -``` - -See issue [#166](https://github.com/bblanchon/ArduinoJson/issues/166). - -## Compute hash of JSON output - -Here is how you can compute the CRC32 hash of the JSON output without consuming a lot of memory. - -This can be very handy to compare two JSON trees. - -```c++ -#include // https://github.com/FrankBoesing/FastCRC - -class HashPrint : public Print { -public: - HashPrint() - { - _hash = _hasher.crc32(NULL, 0); - } - - virtual size_t write(uint8_t c) - { - _hash = _hasher.crc32_upd(&c, 1); - } - - uint32_t hash() const - { - return _hash; - } - -private: - FastCRC32 _hasher; - uint32_t _hash; -}; -``` - -To use this in your code: - -```c++ -HashPrint hashPrint; -root.printTo(hashPrint); -Serial.println(hashPrint.hash()); -``` - -See issue [#390](https://github.com/bblanchon/ArduinoJson/issues/390). - - -## Throw exception when JsonBuffer is too small - -Here is a static decorator that will behave as the decorated `JsonBuffer`, except that it will throw an exception if the allocation fails: - -```c++ -#include - -template -struct Throwing : TJsonBuffer { - virtual void *alloc(size_t bytes) { - void *ptr = TJsonBuffer::alloc(bytes); - if (ptr) - return ptr; - else - throw std::runtime_error("allocation failed"); - } -}; -``` - -To use this in your code: - -```c++ -Throwing > jsonBuffer; -// or -Throwing jsonBuffer; -``` - -See issue [#205](https://github.com/bblanchon/ArduinoJson/issues/205). - -## Clone an object or an array - -```c++ -JsonVariant clone(JsonBuffer& jb, JsonVariant prototype) -{ - if (prototype.is()) { - const JsonObject& protoObj = prototype; - JsonObject& newObj = jb.createObject(); - for (const auto& kvp : protoObj) { - newObj[clone(jb, kvp.key)] = clone(jb, kvp.value); - } - return newObj; - } - - if (prototype.is()) { - const JsonArray& protoArr = prototype; - JsonArray& newArr = jb.createArray(); - for (const auto& elem : protoArr) { - newArr.add(clone(jb, elem)); - } - return newArr; - } - - if (prototype.is()) { - return jb.strdup(prototype.as()); - } - - return prototype; -} -``` - -See issue [#533](https://github.com/bblanchon/ArduinoJson/issues/533) \ No newline at end of file