mirror of
				https://github.com/eledio-devices/thirdparty-ArduinoJson.git
				synced 2025-10-31 16:14:11 +01:00 
			
		
		
		
	Added "Common pitfall" section
This commit is contained in:
		
							
								
								
									
										423
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										423
									
								
								README.md
									
									
									
									
									
								
							| @@ -1,12 +1,18 @@ | |||||||
| # A malloc-free JSON parser for Arduino | A malloc-free JSON parser for Arduino | ||||||
|  | ===================================== | ||||||
|  |  | ||||||
| The library is an thin C++ wrapper around the *jsmn* tokenizer: http://zserge.com/jsmn.html |  | ||||||
|  | This library is an thin C++ wrapper around the *jsmn* tokenizer: http://zserge.com/jsmn.html | ||||||
|  |  | ||||||
| It's design to be very lightweight, works without any allocation on the heap (no malloc) and supports nested objects. | It's design to be very lightweight, works without any allocation on the heap (no malloc) and supports nested objects. | ||||||
|  |  | ||||||
| It has been written with Arduino in mind, but it isn't linked to Arduino libraries so you can use this library on any other C++ project. | It has been written with Arduino in mind, but it isn't linked to Arduino libraries so you can use this library on any other C++ project. | ||||||
|  |  | ||||||
| ## Example |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | Example | ||||||
|  | ------- | ||||||
|  |  | ||||||
|     char* json = "{\"Name\":\"Blanchon\",\"Skills\":[\"C\",\"C++\",\"C#\"],\"Age\":32,\"Online\":true}"; |     char* json = "{\"Name\":\"Blanchon\",\"Skills\":[\"C\",\"C++\",\"C#\"],\"Age\":32,\"Online\":true}"; | ||||||
|  |  | ||||||
| @@ -27,19 +33,23 @@ It has been written with Arduino in mind, but it isn't linked to Arduino librari | |||||||
|  |  | ||||||
|     bool online = hashTable.getBool("Online"); |     bool online = hashTable.getBool("Online"); | ||||||
|  |  | ||||||
| ## How to  use ? |  | ||||||
|  |  | ||||||
| ### 1. Install the the library |  | ||||||
|  |  | ||||||
|  | How to  use ? | ||||||
|  | ------------- | ||||||
|  |  | ||||||
|  | ### 1. Install the library | ||||||
|  |  | ||||||
| Download the library and extract it to: | Download the library and extract it to: | ||||||
|  |  | ||||||
|     <your Arduino Sketch folder>/libraries/ArduinoJonsParser |     <your Arduino Sketch folder>/libraries/ArduinoJsonParser | ||||||
|  |  | ||||||
| ### 2. Import in your sketch | ### 2. Import in your sketch | ||||||
|  |  | ||||||
| Just add the following line on the to of your `.ino` file: | Just add the following line on the top of your `.ino` file: | ||||||
|  |  | ||||||
|     #include <JonsParser.h> |     #include <JsonParser.h> | ||||||
|      |      | ||||||
| ### 3. Create a parser | ### 3. Create a parser | ||||||
|  |  | ||||||
| @@ -49,20 +59,25 @@ To extract data from the JSON string, you need to create a `JsonParser`, and spe | |||||||
|      |      | ||||||
| > #### How to choose the number of tokens ? | > #### How to choose the number of tokens ? | ||||||
|  |  | ||||||
| > First you need to know exactly what a token is. A token is an element af the JSON object: either a key, a value, an hash-table or an array. | > A token is an element of the JSON object: either a key, a value, an hash-table or an array. | ||||||
| > As an example the `char* json` on the top of this page contains 12 tokens (don't forget to count 1 for the whole object and 1 more for the array itself). | > As an example the `char* json` on the top of this page contains 12 tokens (don't forget to count 1 for the whole object and 1 more for the array itself). | ||||||
|  |  | ||||||
| > The more tokens you allocate, the more complex the JSON can be, but also the more memory will be occupied. | > The more tokens you allocate, the more complex the JSON can be, but also the more memory is occupied. | ||||||
| > Each token takes 8 bytes, so `sizeof(JsonParser<32>)` is 256 bytes which is quite big in an Arduino with only 2KB of RAM. | > Each token takes 8 bytes, so `sizeof(JsonParser<32>)` is 256 bytes which is quite big in an Arduino with only 2KB of RAM. | ||||||
| > Don't forget that you also have to store the JSON string in memory and it's probably big. | > Don't forget that you also have to store the JSON string in RAM and it's probably big. | ||||||
|  |  | ||||||
| > 32 tokens may seem small but it's very descent for an 8-bit processor, you wouldn't get better results with other JSON libraries. | > 32 tokens may seem small but it's very descent for an 8-bit processor, you wouldn't get better results with other JSON libraries. | ||||||
|  |  | ||||||
| ### 4. Extract data | ### 4. Extract data | ||||||
|  |  | ||||||
| To use this library, you need to know beforehand what is the type of data contained in the JSON string, which is extremely likely. | To use this library, you need to know beforehand what is the type of data contained in the JSON string, which is very likely. | ||||||
|  |  | ||||||
| #### Hash table | The root object has to be either a hash-table (like `{"key":"value"}`) or an array (like `[1,2]`).  | ||||||
|  |  | ||||||
|  | The nested objects can be either arrays, booleans, hash-tables, numbers or strings. | ||||||
|  | If you need other type, you can get the string value and parse it yourself. | ||||||
|  |  | ||||||
|  | #### Hash-table | ||||||
|  |  | ||||||
| Consider we have a `char* json` pointing to the following JSON string: | Consider we have a `char* json` pointing to the following JSON string: | ||||||
|  |  | ||||||
| @@ -76,7 +91,7 @@ Consider we have a `char* json` pointing to the following JSON string: | |||||||
|         "Online":true |         "Online":true | ||||||
|     } |     } | ||||||
|  |  | ||||||
| In this case the root object of the JSON string is a hash table, so you need to extract a `JsonHashTable`: | In this case the root object of the JSON string is a hash-table, so you need to extract a `JsonHashTable`: | ||||||
|     |     | ||||||
|     JsonHashTable root = parser.parseHashTable(json); |     JsonHashTable root = parser.parseHashTable(json); | ||||||
|      |      | ||||||
| @@ -125,8 +140,96 @@ And then extract the content by its index in the array: | |||||||
| or simply: | or simply: | ||||||
|  |  | ||||||
|     double a = root.getArray(0).getDouble(0); |     double a = root.getArray(0).getDouble(0); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | Common pitfalls | ||||||
|  | --------------- | ||||||
|  |  | ||||||
|  | ### 1. Not enough tokens | ||||||
|  |  | ||||||
|  | By design, the library has no way to tell you why `JsonParser::parseArray()` or `JsonParser::parseHashTable()` failed. | ||||||
|  |  | ||||||
|  | There are basically two reasons why they may fail: | ||||||
|  |  | ||||||
|  | 1. the JSON string is invalid | ||||||
|  | 2. the JSON string contains more tokens that the parser can store | ||||||
|  |  | ||||||
|  | So, if you are sure the JSON string is correct and you still can't parse it, you should slightly increase the number of token of the parser. | ||||||
|  |  | ||||||
|  | ### 2. Not enough memory | ||||||
|  |  | ||||||
|  | You may go into unpredictable trouble if you allocate more memory than your processor really has. | ||||||
|  | It's a very common issue in embedded development.  | ||||||
|  |  | ||||||
|  | To diagnose this, look at every big objects in you code and sum their size to check that they fit in RAM. | ||||||
|  |  | ||||||
|  | For example, don't do this: | ||||||
|  |  | ||||||
|  |     char json[1024];        // 1 KB | ||||||
|  |     JsonParser<64> parser;    // 512 B | ||||||
|  |  | ||||||
|  | because it may be too big for a processor with only 2 KB: you need free memory to store other variables and the call stack. | ||||||
|  |  | ||||||
|  | That is why an 8-bit processor is not able to parse long and complex JSON strings. | ||||||
|  |  | ||||||
|  | ### 3. JsonParser not in memory | ||||||
|  |  | ||||||
|  | To reduce the memory consumption, `JsonArray` and `JsonHashTable` contains pointer to the token that are inside the `JsonParser`. This can only work if the `JsonParser` is still in memory. | ||||||
|  |  | ||||||
|  | For example, don't do this: | ||||||
|  |  | ||||||
|  |     JsonArray getArray(char* json) | ||||||
|  |     { | ||||||
|  |         JsonParser<16> parser; | ||||||
|  |         return parser.parseArray(parser);  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | because the local variable `parser` will be *removed* from memory when the function `getArray()` returns, and the pointer inside `JsonArray` will point to an invalid location. | ||||||
|  |  | ||||||
|  | ### 4. JSON string is altered | ||||||
|  |  | ||||||
|  | This will probably never be an issue, but you need to be aware of this feature. | ||||||
|  |  | ||||||
|  | When you pass a `char*` to `JsonParser::parseArray()` or `JsonParser::parseHashTable()`, the content of the string will be altered to add `\0` at the end of the tokens. | ||||||
|  |  | ||||||
|  | This is because we want functions like `JsonArray::getString()` to return a null-terminating string without any memory allocation. | ||||||
|     |     | ||||||
| ## Code size |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | Memory usage | ||||||
|  | ------------ | ||||||
|  |  | ||||||
|  | Here are the size of the main classes of the library. | ||||||
|  |  | ||||||
|  | This table is for an 8-bit Arduino, types would be bigger on a 32-bit processor. | ||||||
|  |  | ||||||
|  | <table> | ||||||
|  |     <tr> | ||||||
|  |         <th>Type</th> | ||||||
|  |         <th>Size in bytes</th> | ||||||
|  |     </tr> | ||||||
|  |     <tr> | ||||||
|  |         <td>Parser<N></td> | ||||||
|  |         <td>8 x N</td> | ||||||
|  |     </tr> | ||||||
|  |     <tr> | ||||||
|  |         <td>JsonArray</td> | ||||||
|  |         <td>4</td> | ||||||
|  |     </tr> | ||||||
|  |     <tr> | ||||||
|  |         <td>JsonHashTable</td> | ||||||
|  |         <td>4</td> | ||||||
|  |     </tr> | ||||||
|  | </table>  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | Code size | ||||||
|  | --------- | ||||||
|  |  | ||||||
| Theses tables has been created by analyzing the map file generated by AVR-GCC after adding `-Wl,-Map,foo.map` to the command line. | Theses tables has been created by analyzing the map file generated by AVR-GCC after adding `-Wl,-Map,foo.map` to the command line. | ||||||
|  |  | ||||||
| @@ -135,168 +238,168 @@ As you'll see the code size if between 1680 and 3528 bytes, depending on the fea | |||||||
| ### Minimum setup | ### Minimum setup | ||||||
|  |  | ||||||
| <table> | <table> | ||||||
| 	<tr> |     <tr> | ||||||
| 		<th>Function</th> |         <th>Function</th> | ||||||
| 		<th>Size in bytes</th> |         <th>Size in bytes</th> | ||||||
| 	</tr> |     </tr> | ||||||
| 	<tr> |     <tr> | ||||||
| 		<td>strcmp(char*,char*)</td> |         <td>strcmp(char*,char*)</td> | ||||||
| 		<td>18</td> |         <td>18</td> | ||||||
| 	</tr> |     </tr> | ||||||
| 	<tr> |     <tr> | ||||||
| 		<td>jsmn_init(jsmn_parser*)</td> |         <td>jsmn_init(jsmn_parser*)</td> | ||||||
| 		<td>20</td> |         <td>20</td> | ||||||
| 	</tr> |     </tr> | ||||||
| 	<tr> |     <tr> | ||||||
| 		<td>JsonParser::parse(char*)</td> |         <td>JsonParser::parse(char*)</td> | ||||||
| 		<td>106</td> |         <td>106</td> | ||||||
| 	</tr> |     </tr> | ||||||
| 	<tr> |     <tr> | ||||||
| 		<td>JsonObjectBase::getNestedTokenCount(jsmntok_t*)</td> |         <td>JsonObjectBase::getNestedTokenCount(jsmntok_t*)</td> | ||||||
| 		<td>84</td>		 |         <td>84</td>         | ||||||
| 	</tr> |     </tr> | ||||||
| 	<tr> |     <tr> | ||||||
| 		<td>JsonObjectBase::getStringFromToken(jsmntok_t*)</td> |         <td>JsonObjectBase::getStringFromToken(jsmntok_t*)</td> | ||||||
| 		<td>68</td>		 |         <td>68</td>         | ||||||
| 	</tr> |     </tr> | ||||||
| 	<tr> |     <tr> | ||||||
| 		<td>JsonArray::JsonArray(char*, jsmntok_t*)</td> |         <td>JsonArray::JsonArray(char*, jsmntok_t*)</td> | ||||||
| 		<td>42</td>		 |         <td>42</td>         | ||||||
| 	</tr> |     </tr> | ||||||
| 	<tr> |     <tr> | ||||||
| 		<td>JsonArray::getToken(int)</td> |         <td>JsonArray::getToken(int)</td> | ||||||
| 		<td>112</td>		 |         <td>112</td>         | ||||||
| 	</tr> |     </tr> | ||||||
| 	<tr> |     <tr> | ||||||
| 		<td>JsonArray::getString(int)</td> |         <td>JsonArray::getString(int)</td> | ||||||
| 		<td>18</td> |         <td>18</td> | ||||||
| 	</tr> |     </tr> | ||||||
| 	<tr> |     <tr> | ||||||
| 		<td>JsonHashTable::JsonHashTable(char*, jsmntok_t*)</td> |         <td>JsonHashTable::JsonHashTable(char*, jsmntok_t*)</td> | ||||||
| 		<td>42</td>		 |         <td>42</td>         | ||||||
| 	</tr> |     </tr> | ||||||
| 	<tr> |     <tr> | ||||||
| 		<td>JsonHashTable::getToken(char*)</td> |         <td>JsonHashTable::getToken(char*)</td> | ||||||
| 		<td>180</td>		 |         <td>180</td>         | ||||||
| 	</tr> |     </tr> | ||||||
| 	<tr> |     <tr> | ||||||
| 		<td>JsonHashTable::getString(char*)</td> |         <td>JsonHashTable::getString(char*)</td> | ||||||
| 		<td>18</td> |         <td>18</td> | ||||||
| 	</tr> |     </tr> | ||||||
| 	<tr> |     <tr> | ||||||
| 		<td>TOTAL</td> |         <td>TOTAL</td> | ||||||
| 		<td>1680</td> |         <td>1680</td> | ||||||
| 	</tr> |     </tr> | ||||||
| </table> | </table> | ||||||
|  |  | ||||||
| ### Additional space to parse nested  objects | ### Additional space to parse nested  objects | ||||||
|  |  | ||||||
| <table> | <table> | ||||||
| 	<tr> |     <tr> | ||||||
| 		<th>Function</th> |         <th>Function</th> | ||||||
| 		<th>Size in bytes</th> |         <th>Size in bytes</th> | ||||||
| 	</tr> |     </tr> | ||||||
| 	<tr> |     <tr> | ||||||
| 		<td>JsonArray::getArray(int)</td> |         <td>JsonArray::getArray(int)</td> | ||||||
| 		<td>42</td> |         <td>42</td> | ||||||
| 	</tr>	 |     </tr>     | ||||||
| 	<tr> |     <tr> | ||||||
| 		<td>JsonArray::getHashTable(int)</td> |         <td>JsonArray::getHashTable(int)</td> | ||||||
| 		<td>64</td>		 |         <td>64</td>         | ||||||
| 	</tr> |     </tr> | ||||||
| 	<tr> |     <tr> | ||||||
| 		<td>JsonHashTable::getArray(char*)</td> |         <td>JsonHashTable::getArray(char*)</td> | ||||||
| 		<td>64</td> |         <td>64</td> | ||||||
| 	</tr> |     </tr> | ||||||
| 	<tr> |     <tr> | ||||||
| 		<td>JsonHashTable::getHashTable(char*)</td> |         <td>JsonHashTable::getHashTable(char*)</td> | ||||||
| 		<td>42</td> |         <td>42</td> | ||||||
| 	</tr> |     </tr> | ||||||
| 	<tr> |     <tr> | ||||||
| 		<td>TOTAL</td> |         <td>TOTAL</td> | ||||||
| 		<td>212</td> |         <td>212</td> | ||||||
| 	</tr> |     </tr> | ||||||
| </table> | </table> | ||||||
|  |  | ||||||
| ### Additional space to parse `bool` values | ### Additional space to parse `bool` values | ||||||
|  |  | ||||||
| <table> | <table> | ||||||
| 	<tr> |     <tr> | ||||||
| 		<th>Function</th> |         <th>Function</th> | ||||||
| 		<th>Size in bytes</th> |         <th>Size in bytes</th> | ||||||
| 	</tr> |     </tr> | ||||||
| 	<tr> |     <tr> | ||||||
| 		<td>JsonObjectBase::getBoolFromToken(jsmntok_t*)</td> |         <td>JsonObjectBase::getBoolFromToken(jsmntok_t*)</td> | ||||||
| 		<td>82</td> |         <td>82</td> | ||||||
| 	</tr>	 |     </tr>     | ||||||
| 	<tr> |     <tr> | ||||||
| 		<td>JsonArray::getBool(int)</td> |         <td>JsonArray::getBool(int)</td> | ||||||
| 		<td>18</td>		 |         <td>18</td>         | ||||||
| 	</tr> |     </tr> | ||||||
| 	<tr> |     <tr> | ||||||
| 		<td>JsonHashTable::getBool(char*)</td> |         <td>JsonHashTable::getBool(char*)</td> | ||||||
| 		<td>18</td> |         <td>18</td> | ||||||
| 	</tr> |     </tr> | ||||||
| 	<tr> |     <tr> | ||||||
| 		<td>TOTAL</td> |         <td>TOTAL</td> | ||||||
| 		<td>130</td> |         <td>130</td> | ||||||
| 	</tr> |     </tr> | ||||||
| </table> | </table> | ||||||
|  |  | ||||||
| ### Additional space to parse `double` values | ### Additional space to parse `double` values | ||||||
|  |  | ||||||
| <table> | <table> | ||||||
| 	<tr> |     <tr> | ||||||
| 		<th>Function</th> |         <th>Function</th> | ||||||
| 		<th>Size in bytes</th> |         <th>Size in bytes</th> | ||||||
| 	</tr> |     </tr> | ||||||
| 	<tr> |     <tr> | ||||||
| 		<td>strtod(char*,int)</td> |         <td>strtod(char*,int)</td> | ||||||
| 		<td>704</td> |         <td>704</td> | ||||||
| 	</tr>	 |     </tr>     | ||||||
| 	<tr> |     <tr> | ||||||
| 		<td>JsonObjectBase::getDoubleFromToken(jsmntok_t*)</td> |         <td>JsonObjectBase::getDoubleFromToken(jsmntok_t*)</td> | ||||||
| 		<td>44</td> |         <td>44</td> | ||||||
| 	</tr>	 |     </tr>     | ||||||
| 	<tr> |     <tr> | ||||||
| 		<td>JsonArray::getDouble(int)</td> |         <td>JsonArray::getDouble(int)</td> | ||||||
| 		<td>18</td>		 |         <td>18</td>         | ||||||
| 	</tr> |     </tr> | ||||||
| 	<tr> |     <tr> | ||||||
| 		<td>JsonHashTable::getDouble(char*)</td> |         <td>JsonHashTable::getDouble(char*)</td> | ||||||
| 		<td>18</td> |         <td>18</td> | ||||||
| 	</tr> |     </tr> | ||||||
| 	<tr> |     <tr> | ||||||
| 		<td>TOTAL</td> |         <td>TOTAL</td> | ||||||
| 		<td>796</td> |         <td>796</td> | ||||||
| 	</tr> |     </tr> | ||||||
| </table> | </table> | ||||||
|  |  | ||||||
| ### Additional space to parse `long` values | ### Additional space to parse `long` values | ||||||
|  |  | ||||||
| <table> | <table> | ||||||
| 	<tr> |     <tr> | ||||||
| 		<th>Function</th> |         <th>Function</th> | ||||||
| 		<th>Size in bytes</th> |         <th>Size in bytes</th> | ||||||
| 	</tr> |     </tr> | ||||||
| 	<tr> |     <tr> | ||||||
| 		<td>strtol(char*,char**,int)</td> |         <td>strtol(char*,char**,int)</td> | ||||||
| 		<td>606</td> |         <td>606</td> | ||||||
| 	</tr>	 |     </tr>     | ||||||
| 	<tr> |     <tr> | ||||||
| 		<td>JsonObjectBase::getLongFromToken(jsmntok_t*)</td> |         <td>JsonObjectBase::getLongFromToken(jsmntok_t*)</td> | ||||||
| 		<td>56</td> |         <td>56</td> | ||||||
| 	</tr>	 |     </tr>     | ||||||
| 	<tr> |     <tr> | ||||||
| 		<td>JsonArray::getLong(int)</td> |         <td>JsonArray::getLong(int)</td> | ||||||
| 		<td>18</td>		 |         <td>18</td>         | ||||||
| 	</tr> |     </tr> | ||||||
| 	<tr> |     <tr> | ||||||
| 		<td>JsonHashTable::getLong(char*)</td> |         <td>JsonHashTable::getLong(char*)</td> | ||||||
| 		<td>18</td> |         <td>18</td> | ||||||
| 	</tr> |     </tr> | ||||||
| 	<tr> |     <tr> | ||||||
| 		<td>TOTAL</td> |         <td>TOTAL</td> | ||||||
| 		<td>710</td> |         <td>710</td> | ||||||
| 	</tr> |     </tr> | ||||||
| </table> | </table> | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user